summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source4/scripting/python/samba/join.py150
-rw-r--r--source4/scripting/python/samba/provision/__init__.py137
2 files changed, 154 insertions, 133 deletions
diff --git a/source4/scripting/python/samba/join.py b/source4/scripting/python/samba/join.py
index ccb9f06f28..195dfc2312 100644
--- a/source4/scripting/python/samba/join.py
+++ b/source4/scripting/python/samba/join.py
@@ -304,40 +304,47 @@ class dc_join(object):
r.value_ctr = 1
- def DsAddEntry(ctx, rec):
+ def DsAddEntry(ctx, recs):
'''add a record via the DRSUAPI DsAddEntry call'''
if ctx.drsuapi is None:
ctx.drsuapi_connect()
if ctx.tmp_samdb is None:
ctx.create_tmp_samdb()
- id = drsuapi.DsReplicaObjectIdentifier()
- id.dn = rec['dn']
-
- attrs = []
- for a in rec:
- if a == 'dn':
- continue
- if not isinstance(rec[a], list):
- v = [rec[a]]
- else:
- v = rec[a]
- rattr = ctx.tmp_samdb.dsdb_DsReplicaAttribute(ctx.tmp_samdb, a, v)
- attrs.append(rattr)
-
- attribute_ctr = drsuapi.DsReplicaAttributeCtr()
- attribute_ctr.num_attributes = len(attrs)
- attribute_ctr.attributes = attrs
-
- object = drsuapi.DsReplicaObject()
- object.identifier = id
- object.attribute_ctr = attribute_ctr
-
- first_object = drsuapi.DsReplicaObjectListItem()
- first_object.object = object
+ objects = []
+ for rec in recs:
+ id = drsuapi.DsReplicaObjectIdentifier()
+ id.dn = rec['dn']
+
+ attrs = []
+ for a in rec:
+ if a == 'dn':
+ continue
+ if not isinstance(rec[a], list):
+ v = [rec[a]]
+ else:
+ v = rec[a]
+ rattr = ctx.tmp_samdb.dsdb_DsReplicaAttribute(ctx.tmp_samdb, a, v)
+ attrs.append(rattr)
+
+ attribute_ctr = drsuapi.DsReplicaAttributeCtr()
+ attribute_ctr.num_attributes = len(attrs)
+ attribute_ctr.attributes = attrs
+
+ object = drsuapi.DsReplicaObject()
+ object.identifier = id
+ object.attribute_ctr = attribute_ctr
+
+ list_object = drsuapi.DsReplicaObjectListItem()
+ list_object.object = object
+ objects.append(list_object)
req2 = drsuapi.DsAddEntryRequest2()
- req2.first_object = first_object
+ req2.first_object = objects[0]
+ prev = req2.first_object
+ for o in objects[1:]:
+ prev.next_object = o
+ prev = o
(level, ctr) = ctx.drsuapi.DsAddEntry(ctx.drsuapi_handle, 2, req2)
if ctr.err_ver != 1:
@@ -349,6 +356,7 @@ class dc_join(object):
if ctr.err_data.dir_err != drsuapi.DRSUAPI_DIRERR_OK:
print("DsAddEntry failed with dir_err %u" % ctr.err_data.dir_err)
raise RuntimeError("DsAddEntry failed")
+ return ctr.objects
def join_add_ntdsdsa(ctx):
@@ -361,17 +369,12 @@ class dc_join(object):
"systemFlags" : str(samba.dsdb.SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE),
"dMDLocation" : ctx.schema_dn}
- if ctx.subdomain:
- # the local subdomain NC doesn't exist at this time
- # so we have to add the base_dn NC later
- nc_list = [ ctx.config_dn, ctx.schema_dn ]
- else:
- nc_list = [ ctx.base_dn, ctx.config_dn, ctx.schema_dn ]
+ nc_list = [ ctx.base_dn, ctx.config_dn, ctx.schema_dn ]
if ctx.behavior_version >= samba.dsdb.DS_DOMAIN_FUNCTION_2003:
rec["msDS-Behavior-Version"] = str(ctx.behavior_version)
- if ctx.behavior_version >= samba.dsdb.DS_DOMAIN_FUNCTION_2003 and not ctx.subdomain:
+ if ctx.behavior_version >= samba.dsdb.DS_DOMAIN_FUNCTION_2003:
rec["msDS-HasDomainNCs"] = ctx.base_dn
if ctx.RODC:
@@ -386,32 +389,13 @@ class dc_join(object):
rec["msDS-HasMasterNCs"] = nc_list
rec["options"] = "1"
rec["invocationId"] = ndr_pack(ctx.invocation_id)
- if ctx.subdomain:
- ctx.samdb.add(rec, ['relax:0'])
- else:
- ctx.DsAddEntry(rec)
+ ctx.DsAddEntry([rec])
# find the GUID of our NTDS DN
res = ctx.samdb.search(base=ctx.ntds_dn, scope=ldb.SCOPE_BASE, attrs=["objectGUID"])
ctx.ntds_guid = misc.GUID(ctx.samdb.schema_format_value("objectGUID", res[0]["objectGUID"][0]))
- def join_modify_ntdsdsa(ctx):
- '''modify the ntdsdsa object to add local partitions'''
- print "Modifying %s using system privileges" % ctx.ntds_dn
-
- # this works around the Enterprise Admins ACL on the NTDSDSA object
- system_session_info = system_session()
- ctx.samdb.set_session_info(system_session_info)
-
- m = ldb.Message()
- m.dn = ldb.Dn(ctx.samdb, ctx.ntds_dn)
- m["HasMasterNCs"] = ldb.MessageElement(ctx.base_dn, ldb.FLAG_MOD_ADD, "HasMasterNCs")
- if ctx.behavior_version >= samba.dsdb.DS_DOMAIN_FUNCTION_2003:
- m["msDS-HasDomainNCs"] = ldb.MessageElement(ctx.base_dn, ldb.FLAG_MOD_ADD, "msDS-HasDomainNCs")
- m["msDS-HasMasterNCs"] = ldb.MessageElement(ctx.base_dn, ldb.FLAG_MOD_ADD, "msDS-HasMasterNCs")
- ctx.samdb.modify(m, controls=['relax:0'])
-
def join_add_objects(ctx):
'''add the various objects needed for the join'''
if ctx.acct_dn:
@@ -440,9 +424,11 @@ class dc_join(object):
rec = {
"dn": ctx.server_dn,
"objectclass" : "server",
+ # windows uses 50000000 decimal for systemFlags. A windows hex/decimal mixup bug?
"systemFlags" : str(samba.dsdb.SYSTEM_FLAG_CONFIG_ALLOW_RENAME |
samba.dsdb.SYSTEM_FLAG_CONFIG_ALLOW_LIMITED_MOVE |
samba.dsdb.SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE),
+ # windows seems to add the dnsHostName later
"dnsHostName" : ctx.dnshostname}
if ctx.acct_dn:
@@ -507,9 +493,6 @@ class dc_join(object):
def join_add_objects2(ctx):
'''add the various objects needed for the join, for subdomains post replication'''
- if not ctx.subdomain:
- return
-
print "Adding %s" % ctx.partition_dn
# NOTE: windows sends a ntSecurityDescriptor here, we
# let it default
@@ -524,8 +507,47 @@ class dc_join(object):
"systemFlags" : str(samba.dsdb.SYSTEM_FLAG_CR_NTDS_NC|samba.dsdb.SYSTEM_FLAG_CR_NTDS_DOMAIN)}
if ctx.behavior_version >= samba.dsdb.DS_DOMAIN_FUNCTION_2003:
rec["msDS-Behavior-Version"] = str(ctx.behavior_version)
- ctx.DsAddEntry(rec)
+ rec2 = {
+ "dn" : ctx.ntds_dn,
+ "objectclass" : "nTDSDSA",
+ "systemFlags" : str(samba.dsdb.SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE),
+ "dMDLocation" : ctx.schema_dn}
+
+ nc_list = [ ctx.base_dn, ctx.config_dn, ctx.schema_dn ]
+
+ if ctx.behavior_version >= samba.dsdb.DS_DOMAIN_FUNCTION_2003:
+ rec2["msDS-Behavior-Version"] = str(ctx.behavior_version)
+
+ if ctx.behavior_version >= samba.dsdb.DS_DOMAIN_FUNCTION_2003:
+ rec2["msDS-HasDomainNCs"] = ctx.base_dn
+
+ rec2["objectCategory"] = "CN=NTDS-DSA,%s" % ctx.schema_dn
+ rec2["HasMasterNCs"] = nc_list
+ if ctx.behavior_version >= samba.dsdb.DS_DOMAIN_FUNCTION_2003:
+ rec2["msDS-HasMasterNCs"] = nc_list
+ rec2["options"] = "1"
+ rec2["invocationId"] = ndr_pack(ctx.invocation_id)
+
+ objects = ctx.DsAddEntry([rec, rec2])
+ if len(objects) != 2:
+ raise DCJoinException("Expected 2 objects from DsAddEntry")
+
+ ctx.ntds_guid = objects[1].guid
+
+ print("Replicating partition DN")
+ ctx.repl.replicate(ctx.partition_dn,
+ misc.GUID("00000000-0000-0000-0000-000000000000"),
+ ctx.ntds_guid,
+ exop=drsuapi.DRSUAPI_EXOP_REPL_OBJ,
+ replica_flags=drsuapi.DRSUAPI_DRS_WRIT_REP)
+
+ print("Replicating NTDS DN")
+ ctx.repl.replicate(ctx.ntds_dn,
+ misc.GUID("00000000-0000-0000-0000-000000000000"),
+ ctx.ntds_guid,
+ exop=drsuapi.DRSUAPI_EXOP_REPL_OBJ,
+ replica_flags=drsuapi.DRSUAPI_DRS_WRIT_REP)
def join_provision(ctx):
'''provision the local SAM'''
@@ -565,14 +587,11 @@ class dc_join(object):
ctx.local_samdb = ctx.samdb
print("Finding domain GUID from ncName")
- res = ctx.samdb.search(base=ctx.partition_dn, scope=ldb.SCOPE_BASE, attrs=['ncName'],
- controls=["extended_dn:1:1"])
+ res = ctx.local_samdb.search(base=ctx.partition_dn, scope=ldb.SCOPE_BASE, attrs=['ncName'],
+ controls=["extended_dn:1:1"])
domguid = str(misc.GUID(ldb.Dn(ctx.samdb, res[0]['ncName'][0]).get_extended_component('GUID')))
print("Got domain GUID %s" % domguid)
-
- ctx.join_add_ntdsdsa()
-
print("Calling own domain provision")
logger = logging.getLogger("provision")
@@ -597,6 +616,7 @@ class dc_join(object):
try:
source_dsa_invocation_id = misc.GUID(ctx.samdb.get_invocation_id())
if ctx.ntds_guid is None:
+ print("Using DS_BIND_GUID_W2K3")
destination_dsa_guid = misc.GUID(drsuapi.DRSUAPI_DS_BIND_GUID_W2K3)
else:
destination_dsa_guid = ctx.ntds_guid
@@ -634,6 +654,9 @@ class dc_join(object):
repl.replicate(ctx.new_krbtgt_dn, source_dsa_invocation_id,
destination_dsa_guid,
exop=drsuapi.DRSUAPI_EXOP_REPL_SECRET, rodc=True)
+ ctx.repl = repl
+ ctx.source_dsa_invocation_id = source_dsa_invocation_id
+ ctx.destination_dsa_guid = destination_dsa_guid
print "Committing SAM database"
except:
@@ -787,12 +810,11 @@ class dc_join(object):
try:
ctx.join_add_objects()
ctx.join_provision()
- ctx.join_add_objects2()
ctx.join_replicate()
if ctx.subdomain:
+ ctx.join_add_objects2()
ctx.join_provision_own_domain()
ctx.join_setup_trusts()
- ctx.join_modify_ntdsdsa()
ctx.join_finalise()
except Exception:
print "Join failed - cleaning up"
diff --git a/source4/scripting/python/samba/provision/__init__.py b/source4/scripting/python/samba/provision/__init__.py
index 0b39167df4..a3633ab128 100644
--- a/source4/scripting/python/samba/provision/__init__.py
+++ b/source4/scripting/python/samba/provision/__init__.py
@@ -995,11 +995,11 @@ def setup_secretsdb(paths, session_info, backend_credentials, lp):
"LDAPADMINREALM": backend_credentials.get_realm(),
"LDAPADMINPASS_B64": b64encode(backend_credentials.get_password())
})
-
- return secrets_ldb
except Exception:
secrets_ldb.transaction_cancel()
raise
+ return secrets_ldb
+
def setup_privileges(path, session_info, lp):
@@ -1597,10 +1597,6 @@ def provision_fill(samdb, secrets_ldb, logger, names, paths,
setsysvolacl(samdb, paths.netlogon, paths.sysvol, paths.wheel_gid,
domainsid, names.dnsdomain, names.domaindn, lp)
- logger.info("Setting up sam.ldb rootDSE marking as synchronized")
- setup_modify_ldif(samdb, setup_path("provision_rootdse_modify.ldif"),
- { 'NTDSGUID' : names.ntdsguid })
-
secretsdb_self_join(secrets_ldb, domain=names.domain,
realm=names.realm, dnsdomain=names.dnsdomain,
netbiosname=names.netbiosname, domainsid=domainsid,
@@ -1624,69 +1620,72 @@ def provision_fill(samdb, secrets_ldb, logger, names, paths,
# It might be that this attribute does not exist in this schema
raise
- if serverrole == "domain controller":
- secretsdb_setup_dns(secrets_ldb, names,
- paths.private_dir, realm=names.realm,
- dnsdomain=names.dnsdomain,
- dns_keytab_path=paths.dns_keytab, dnspass=dnspass)
-
- # Default DNS backend is BIND9 using txt files for zone information
- if not dns_backend:
- dns_backend = "BIND9"
-
- setup_ad_dns(samdb, names, logger, hostip=hostip, hostip6=hostip6,
- dns_backend=dns_backend, os_level=dom_for_fun_level)
-
- domainguid = samdb.searchone(basedn=samdb.get_default_basedn(),
- attribute="objectGUID")
- assert isinstance(domainguid, str)
-
- create_dns_dir(logger, paths)
-
- # Only make a zone file on the first DC, it should be
- # replicated with DNS replication
- if dns_backend == "BIND9":
- create_zone_file(lp, logger, paths, targetdir,
- dnsdomain=names.dnsdomain, hostip=hostip, hostip6=hostip6,
- hostname=names.hostname, realm=names.realm,
- domainguid=domainguid, ntdsguid=names.ntdsguid)
-
- create_named_conf(paths, realm=names.realm,
- dnsdomain=names.dnsdomain, dns_backend=dns_backend)
-
- create_named_txt(paths.namedtxt,
- realm=names.realm, dnsdomain=names.dnsdomain,
- dnsname = "%s.%s" % (names.hostname, names.dnsdomain),
- private_dir=paths.private_dir,
- keytab_name=paths.dns_keytab)
- logger.info("See %s for an example configuration include file for BIND", paths.namedconf)
- logger.info("and %s for further documentation required for secure DNS "
- "updates", paths.namedtxt)
-
- lastProvisionUSNs = get_last_provision_usn(samdb)
- maxUSN = get_max_usn(samdb, str(names.rootdn))
- if lastProvisionUSNs is not None:
- update_provision_usn(samdb, 0, maxUSN, invocationid, 1)
- else:
- set_provision_usn(samdb, 0, maxUSN, invocationid)
-
- # fix any dangling GUIDs from the provision
- logger.info("Fixing provision GUIDs")
- chk = dbcheck(samdb, samdb_schema=samdb, verbose=False, fix=True, yes=True, quiet=True)
- samdb.transaction_start()
- # a small number of GUIDs are missing because of ordering issues in the
- # provision code
- for schema_obj in ['CN=Domain', 'CN=Organizational-Person', 'CN=Contact', 'CN=inetOrgPerson']:
- chk.check_database(DN="%s,%s" % (schema_obj, names.schemadn),
- scope=ldb.SCOPE_BASE, attrs=['defaultObjectCategory'])
- chk.check_database(DN="CN=IP Security,CN=System,%s" % names.domaindn,
- scope=ldb.SCOPE_ONELEVEL,
- attrs=['ipsecOwnersReference',
- 'ipsecFilterReference',
- 'ipsecISAKMPReference',
- 'ipsecNegotiationPolicyReference',
- 'ipsecNFAReference'])
- samdb.transaction_commit()
+ secretsdb_setup_dns(secrets_ldb, names,
+ paths.private_dir, realm=names.realm,
+ dnsdomain=names.dnsdomain,
+ dns_keytab_path=paths.dns_keytab, dnspass=dnspass)
+
+ # Default DNS backend is BIND9 using txt files for zone information
+ if not dns_backend:
+ dns_backend = "BIND9"
+
+ setup_ad_dns(samdb, names, logger, hostip=hostip, hostip6=hostip6,
+ dns_backend=dns_backend, os_level=dom_for_fun_level)
+
+ domainguid = samdb.searchone(basedn=samdb.get_default_basedn(),
+ attribute="objectGUID")
+ assert isinstance(domainguid, str)
+
+ create_dns_dir(logger, paths)
+
+ # Only make a zone file on the first DC, it should be
+ # replicated with DNS replication
+ if dns_backend == "BIND9":
+ create_zone_file(lp, logger, paths, targetdir,
+ dnsdomain=names.dnsdomain, hostip=hostip, hostip6=hostip6,
+ hostname=names.hostname, realm=names.realm,
+ domainguid=domainguid, ntdsguid=names.ntdsguid)
+
+ create_named_conf(paths, realm=names.realm,
+ dnsdomain=names.dnsdomain, dns_backend=dns_backend)
+
+ create_named_txt(paths.namedtxt,
+ realm=names.realm, dnsdomain=names.dnsdomain,
+ dnsname = "%s.%s" % (names.hostname, names.dnsdomain),
+ private_dir=paths.private_dir,
+ keytab_name=paths.dns_keytab)
+ logger.info("See %s for an example configuration include file for BIND", paths.namedconf)
+ logger.info("and %s for further documentation required for secure DNS "
+ "updates", paths.namedtxt)
+
+ lastProvisionUSNs = get_last_provision_usn(samdb)
+ maxUSN = get_max_usn(samdb, str(names.rootdn))
+ if lastProvisionUSNs is not None:
+ update_provision_usn(samdb, 0, maxUSN, invocationid, 1)
+ else:
+ set_provision_usn(samdb, 0, maxUSN, invocationid)
+
+ logger.info("Setting up sam.ldb rootDSE marking as synchronized")
+ setup_modify_ldif(samdb, setup_path("provision_rootdse_modify.ldif"),
+ { 'NTDSGUID' : names.ntdsguid })
+
+ # fix any dangling GUIDs from the provision
+ logger.info("Fixing provision GUIDs")
+ chk = dbcheck(samdb, samdb_schema=samdb, verbose=False, fix=True, yes=True, quiet=True)
+ samdb.transaction_start()
+ # a small number of GUIDs are missing because of ordering issues in the
+ # provision code
+ for schema_obj in ['CN=Domain', 'CN=Organizational-Person', 'CN=Contact', 'CN=inetOrgPerson']:
+ chk.check_database(DN="%s,%s" % (schema_obj, names.schemadn),
+ scope=ldb.SCOPE_BASE, attrs=['defaultObjectCategory'])
+ chk.check_database(DN="CN=IP Security,CN=System,%s" % names.domaindn,
+ scope=ldb.SCOPE_ONELEVEL,
+ attrs=['ipsecOwnersReference',
+ 'ipsecFilterReference',
+ 'ipsecISAKMPReference',
+ 'ipsecNegotiationPolicyReference',
+ 'ipsecNFAReference'])
+ samdb.transaction_commit()
def provision(logger, session_info, credentials, smbconf=None,