ctx.schema_dn = str(ctx.samdb.get_schema_basedn())
ctx.config_dn = str(ctx.samdb.get_config_basedn())
ctx.domsid = security.dom_sid(ctx.samdb.get_domain_sid())
- ctx.forestsid = ctx.domsid
ctx.domain_name = ctx.get_domain_name()
ctx.forest_domain_name = ctx.get_forest_domain_name()
+ ctx.forest_dnsdomain = ctx.get_forest_dns_domain()
+ ctx.forestsid = ctx.get_forest_domain_sid()
+ ctx.forest_domain_guid = ctx.get_forest_domain_guid()
ctx.invocation_id = misc.GUID(str(uuid.uuid4()))
ctx.dc_ntds_dn = ctx.samdb.get_dsServiceName()
expression='ncName=%s' % ldb.binary_encode(str(ctx.samdb.get_root_basedn())))
return str(res[0]["nETBIOSName"][0])
- def get_parent_partition_dn(ctx):
- '''get the parent domain partition DN from parent DNS name'''
- res = ctx.samdb.search(base=ctx.config_dn, attrs=[],
+ def get_forest_dns_domain(ctx):
+ '''get dns name of the domain from the partitions record'''
+ partitions_dn = ctx.samdb.get_partitions_dn()
+ res = ctx.samdb.search(base=partitions_dn, scope=ldb.SCOPE_ONELEVEL, attrs=["dnsRoot"],
+ expression='ncName=%s' % ldb.binary_encode(str(ctx.samdb.get_root_basedn())))
+ return res[0]["dnsRoot"][0]
+
+ def get_forest_domain_sid(ctx):
+ '''get netbios name of the domain from the partitions record'''
+ partitions_dn = ctx.samdb.get_partitions_dn()
+ res = ctx.samdb.search(base=partitions_dn, scope=ldb.SCOPE_ONELEVEL,
+ attrs=["ncName"], controls=["extended_dn:1:1"]
+ expression='ncName=%s' % ldb.binary_encode(str(ctx.samdb.get_root_basedn())))
+ return str(security.dom_sid(ldb.Dn(ctx.samdb, res[0]['ncName'][0]).get_extended_component('SID')))
+
+ def get_forest_domain_guid(ctx):
+ '''get netbios name of the domain from the partitions record'''
+ partitions_dn = ctx.samdb.get_partitions_dn()
+ res = ctx.samdb.search(base=partitions_dn, scope=ldb.SCOPE_ONELEVEL,
+ attrs=["ncName"], controls=["extended_dn:1:1"]
+ expression='ncName=%s' % ldb.binary_encode(str(ctx.samdb.get_root_basedn())))
+ return str(misc.GUID(ldb.Dn(ctx.samdb, res[0]['ncName'][0]).get_extended_component('GUID')))
+
+ def get_crossref_dn_from_dnsdomain(ctx, dnsdomain):
+ '''get the domain partition DN from DNS name'''
+ partitions_dn = ctx.samdb.get_partitions_dn()
+ res = ctx.samdb.search(base=partitions_dn, scope=ldb.SCOPE_ONELEVEL, attrs=[],
expression='(&(objectclass=crossRef)(dnsRoot=%s)(systemFlags:%s:=%u))' %
- (ldb.binary_encode(ctx.parent_dnsdomain),
+ (ldb.binary_encode(dnsdomain),
ldb.OID_COMPARATOR_AND, samba.dsdb.SYSTEM_FLAG_CR_NTDS_DOMAIN))
+ if len(res) == 0:
+ return None
return str(res[0].dn)
+ def get_netbios_name_from_crossref_dn(ctx, crossref_dn):
+ '''get the netbios name for the partition crossRef DN'''
+ res = ctx.samdb.search(base=crossref_dn, scope=ldb.SCOPE_BASE, attrs=["nETBIOSName"])
+ return res[0]["nETBIOSName"][0]
+
+ def get_dns_name_from_crossref_dn(ctx, crossref_dn):
+ '''get the dns name for the partition crossRef DN'''
+ res = ctx.samdb.search(base=crossref_dn, scope=ldb.SCOPE_BASE, attrs=["dnsRoot"])
+ return res[0]["dnsRoot"][0]
+
+ def get_domain_sid_from_crossref_dn(ctx, crossref_dn):
+ '''get the domain sid for the partition crossRef DN'''
+ res = ctx.samdb.search(base=crossref_dn, scope=ldb.SCOPE_BASE, attrs=['ncName'],
+ controls=["extended_dn:1:1")
+ return str(security.dom_sid(ldb.Dn(ctx.samdb, res[0]['ncName'][0]).get_extended_component('SID')))
+
+ def get_domain_guid_from_crossref_dn(ctx, crossref_dn):
+ '''get the domain guid for the partition crossRef DN'''
+ res = ctx.samdb.search(base=crossref_dn, scope=ldb.SCOPE_BASE, attrs=['ncName'],
+ controls=["extended_dn:1:1")
+ return str(misc.GUID(ldb.Dn(ctx.samdb, res[0]['ncName'][0]).get_extended_component('GUID')))
+
def get_naming_master(ctx):
'''get the parent domain partition DN from parent DNS name'''
res = ctx.samdb.search(base='CN=Partitions,%s' % ctx.config_dn, attrs=['fSMORoleOwner'],
"nCName": ctx.base_dn,
"nETBIOSName": ctx.domain_name,
"dnsRoot": ctx.dnsdomain,
- "trustParent": ctx.parent_partition_dn,
"systemFlags": str(samba.dsdb.SYSTEM_FLAG_CR_NTDS_NC |samba.dsdb.SYSTEM_FLAG_CR_NTDS_DOMAIN),
"ntSecurityDescriptor": sd_binary,
}
+ if ctx.trust_partition_dn == ctx.parent_crossref_dn:
+ rec["trustParent"] = ctx.trust_partition_dn
+ else:
+ rec["rootTrust"] = ctx.trust_partition_dn
+
if ctx.behavior_version >= samba.dsdb.DS_DOMAIN_FUNCTION_2003:
rec["msDS-Behavior-Version"] = str(ctx.behavior_version)
auth_info = lsa.TrustDomainInfoAuthInfoInternal()
auth_info.auth_blob = auth_blob
- trustdom_handle = lsaconn.CreateTrustedDomainEx2(pol_handle,
- info,
- auth_info,
- security.SEC_STD_DELETE)
+ create_handle = lsaconn.CreateTrustedDomainEx2(pol_handle,
+ info,
+ auth_info,
+ security.SEC_STD_DELETE)
- rec = {
- "dn": "cn=%s,cn=system,%s" % (ctx.dnsforest, ctx.base_dn),
- "objectclass": "trustedDomain",
- "trustType": str(info.trust_type),
- "trustAttributes": str(info.trust_attributes),
- "trustDirection": str(info.trust_direction),
- "flatname": ctx.forest_domain_name,
- "trustPartner": ctx.dnsforest,
- "trustAuthIncoming": ndr_pack(outgoing),
- "trustAuthOutgoing": ndr_pack(outgoing),
- "securityIdentifier": ndr_pack(ctx.forestsid)
- }
- ctx.local_samdb.add(rec)
+ modify_handle = lsaconn.OpenTrustedDomainByName(pol_handle,
+ ctx.domain_name,
+ security.SEC_FLAG_MAXIMUM_ALLOWED)
+ try:
+ infoclass = lsa.TrustDomainInfoSupportedEncTypes()
+ infoclass.enc_types = security.KERB_ENCTYPE_RC4_HMAC_MD5
+ infoclass.enc_types |= security.KERB_ENCTYPE_AES128_CTS_HMAC_SHA1_96
+ infoclass.enc_types |= security.KERB_ENCTYPE_AES256_CTS_HMAC_SHA1_96
+ lsaconn.SetInformationTrustedDomain(modify_handle,
+ lsa.LSA_TRUSTED_DOMAIN_SUPPORTED_ENCRYPTION_TYPES,
+ infoclass)
+ except RuntimeError:
+ # We can ignore the error here -- changing enctypes is for
+ # improved security but the trust will work with default values as
+ # well. In particular, the call may fail against Windows 2003
+ # server as that one doesn't support AES encryption types
+ pass
+ lsaconn.Close(modify_handle)
- rec = {
- "dn": "cn=%s$,cn=users,%s" % (ctx.forest_domain_name, ctx.base_dn),
- "objectclass": "user",
- "userAccountControl": str(samba.dsdb.UF_INTERDOMAIN_TRUST_ACCOUNT),
- "clearTextPassword": ctx.trustdom_pass.encode('utf-16-le'),
- "samAccountName": "%s$" % ctx.forest_domain_name
- }
- ctx.local_samdb.add(rec)
+ try:
+ rec = {
+ "dn": "cn=%s,cn=system,%s" % (ctx.dnsforest, ctx.base_dn),
+ "objectclass": "trustedDomain",
+ "trustType": str(info.trust_type),
+ "trustAttributes": str(info.trust_attributes),
+ "trustDirection": str(info.trust_direction),
+ "flatname": ctx.forest_domain_name,
+ "trustPartner": ctx.dnsforest,
+ "trustAuthIncoming": ndr_pack(outgoing),
+ "trustAuthOutgoing": ndr_pack(outgoing),
+ "securityIdentifier": ndr_pack(ctx.forestsid)
+ }
+ ctx.local_samdb.add(rec)
+
+ rec = {
+ "dn": "cn=%s$,cn=users,%s" % (ctx.forest_domain_name, ctx.base_dn),
+ "objectclass": "user",
+ "userAccountControl": str(samba.dsdb.UF_INTERDOMAIN_TRUST_ACCOUNT),
+ "clearTextPassword": ctx.trustdom_pass.encode('utf-16-le'),
+ "samAccountName": "%s$" % ctx.forest_domain_name
+ }
+ ctx.local_samdb.add(rec)
+
+ except RuntimeError:
+ lsaconn.DeleteObject(create_handle)
+ create_handle = None
+ if create_handle is not None:
+ lsaconn.Close(create_handle)
def build_nc_lists(ctx):
# nc_list is the list of naming context (NC) for which we will
return ctx
-def join_subdomain(logger=None, server=None, creds=None, lp=None, site=None,
- netbios_name=None, targetdir=None, parent_domain=None, dnsdomain=None,
+def join_newdomain(logger=None, server=None, creds=None, lp=None, site=None,
+ netbios_name=None, targetdir=None, reference_dnsdomain=None, dnsdomain=None,
netbios_domain=None, machinepass=None, adminpass=None, use_ntvfs=False,
dns_backend=None, plaintext_secrets=False,
backend_store=None, backend_store_size=None):
- """Join as a DC."""
+ """Join as a NEW domain into the existing forest."""
+ if reference_dnsdomain is None:
+ parent_dnsdomain = ".".join(dnsdomain.split(".")[1:])
+ reference_dnsdomain = parent_dnsdomain
+
ctx = DCJoinContext(logger, server, creds, lp, site, netbios_name,
- targetdir, parent_domain, machinepass, use_ntvfs,
+ targetdir, reference_dnsdomain, machinepass, use_ntvfs,
dns_backend, plaintext_secrets,
backend_store=backend_store,
backend_store_size=backend_store_size)
ctx.server = res[0]["dnsHostName"]
logger.info("DNS name of new naming master is %s" % ctx.server)
- ctx.base_dn = samba.dn_from_dns_name(dnsdomain)
- ctx.forestsid = ctx.domsid
+ def is_dns_child(parent_dnsdomain, child_dnsdomain):
+ parent = parent_dnsdomain.lower.split(".")
+ child = child_dnsdomain.lower.split(".")
+
+ if len(parent) >= len(child):
+ return 0
+
+ for i in range(len(parent)):
+ ir = -i
+ il = ir - 1
+ if ir == 0:
+ ir = None
+ pp = parent[il:ir]
+ cp = child[il:ir]
+ if pp != cp:
+ return 0
+
+ return len(child) - len(parent)
+
+ ctx.parent_crossref_dn = ctx.get_crossref_dn_from_dnsdomain(parent_dnsdomain)
+ if ctx.parent_crossref_dn is not None:
+ ctx.trust_dnsdomain = parent_dnsdomain
+ ctx.trust_sid = ctx.domsid
+ ctx.trust_domain_name = ctx.domain_name
+ ctx.trust_partition_dn = ctx.parent_crossref_dn
+ else:
+ if is_dns_child(reference_domain, domain) > 0:
+ raise DCJoinException("""Unsupported dnsdomain[%s] parent_domain[%s]
+ reference_domain[%s]""" % (domain, parent_domain, reference_domain)
+
+ ctx.trust_dnsdomain = ctx.forest_dnsdomain
+ ctx.trust_sid = ctx.forestsid
+ ctx.trust_domain_name = ctx.forest_domain_name
+ ctx.trust_crossref_dn = ctx.get_crossref_dn_from_dnsdomain(ctx.trust_dnsdomain)
+
+ ctx.subdomain = True
+ if adminpass is None:
+ ctx.adminpass = samba.generate_random_password(12, 32)
+ else:
+ ctx.adminpass = adminpass
+ # Windows uses 240 bytes as UTF16 so we do
+ ctx.trustdom_pass = samba.generate_random_machine_password(120, 120)
+
ctx.domsid = security.random_sid()
+ ctx.domain_name = netbios_domain
+ ctx.realm = dnsdomain
+ ctx.dnsdomain = dnsdomain
+ ctx.partition_dn = "CN=%s,CN=Partitions,%s" % (ctx.domain_name, ctx.config_dn)
+ ctx.base_dn = samba.dn_from_dns_name(dnsdomain)
+
ctx.acct_dn = None
ctx.dnshostname = "%s.%s" % (ctx.myname.lower(), ctx.dnsdomain)
- # Windows uses 240 bytes as UTF16 so we do
- ctx.trustdom_pass = samba.generate_random_machine_password(120, 120)
ctx.userAccountControl = samba.dsdb.UF_SERVER_TRUST_ACCOUNT | samba.dsdb.UF_TRUSTED_FOR_DELEGATION
-
- ctx.SPNs.append('E3514235-4B06-11D1-AB04-00C04FC2DCD2/$NTDSGUID/%s' % ctx.dnsdomain)
+ ctx.SPNs = [
+ "HOST/%s" % ctx.myname,
+ "HOST/%s" % ctx.dnshostname,
+ "GC/%s/%s" % (ctx.dnshostname, ctx.dnsforest),
+ "E3514235-4B06-11D1-AB04-00C04FC2DCD2/$NTDSGUID/%s" % ctx.dnsdomain)
+ ]
ctx.secure_channel_type = misc.SEC_CHAN_BDC
ctx.replica_flags |= (drsuapi.DRSUAPI_DRS_WRIT_REP |