def join_finalise(ctx): '''finalise the join, mark us synchronised and setup secrets db''' print "Sending DsReplicateUpdateRefs for all the partitions" ctx.send_DsReplicaUpdateRefs(ctx.schema_dn) ctx.send_DsReplicaUpdateRefs(ctx.config_dn) ctx.send_DsReplicaUpdateRefs(ctx.base_dn) print "Setting isSynchronized and dsServiceName" m = ldb.Message() m.dn = ldb.Dn(ctx.local_samdb, '@ROOTDSE') m["isSynchronized"] = ldb.MessageElement("TRUE", ldb.FLAG_MOD_REPLACE, "isSynchronized") m["dsServiceName"] = ldb.MessageElement( "<GUID=%s>" % str(ctx.ntds_guid), ldb.FLAG_MOD_REPLACE, "dsServiceName") ctx.local_samdb.modify(m) if ctx.subdomain: return secrets_ldb = Ldb(ctx.paths.secrets, session_info=system_session(), lp=ctx.lp) print "Setting up secrets database" secretsdb_self_join(secrets_ldb, domain=ctx.domain_name, realm=ctx.realm, dnsdomain=ctx.dnsdomain, netbiosname=ctx.myname, domainsid=security.dom_sid(ctx.domsid), machinepass=ctx.acct_pass, secure_channel_type=ctx.secure_channel_type, key_version_number=ctx.key_version_number)
def join_finalise(ctx): """finalise the join, mark us synchronised and setup secrets db""" print "Sending DsReplicateUpdateRefs for all the partitions" ctx.send_DsReplicaUpdateRefs(ctx.schema_dn) ctx.send_DsReplicaUpdateRefs(ctx.config_dn) ctx.send_DsReplicaUpdateRefs(ctx.base_dn) print "Setting isSynchronized and dsServiceName" m = ldb.Message() m.dn = ldb.Dn(ctx.local_samdb, "@ROOTDSE") m["isSynchronized"] = ldb.MessageElement("TRUE", ldb.FLAG_MOD_REPLACE, "isSynchronized") m["dsServiceName"] = ldb.MessageElement("<GUID=%s>" % str(ctx.ntds_guid), ldb.FLAG_MOD_REPLACE, "dsServiceName") ctx.local_samdb.modify(m) if ctx.subdomain: return secrets_ldb = Ldb(ctx.paths.secrets, session_info=system_session(), lp=ctx.lp) print "Setting up secrets database" secretsdb_self_join( secrets_ldb, domain=ctx.domain_name, realm=ctx.realm, dnsdomain=ctx.dnsdomain, netbiosname=ctx.myname, domainsid=security.dom_sid(ctx.domsid), machinepass=ctx.acct_pass, secure_channel_type=ctx.secure_channel_type, key_version_number=ctx.key_version_number, )
def update_machine_account_password(samdb, secrets_ldb, names): """Update (change) the password of the current DC both in the SAM db and in secret one :param samdb: An LDB object related to the sam.ldb file of a given provision :param secrets_ldb: An LDB object related to the secrets.ldb file of a given provision :param names: List of key provision parameters""" expression = "samAccountName=%s$" % names.netbiosname secrets_msg = secrets_ldb.search(expression=expression, attrs=["secureChannelType"]) if int(secrets_msg[0]["secureChannelType"][0]) == SEC_CHAN_BDC: res = samdb.search(expression=expression, attrs=[]) assert (len(res) == 1) msg = ldb.Message(res[0].dn) machinepass = samba.generate_random_machine_password(128, 255) mputf16 = machinepass.encode('utf-16-le') msg["clearTextPassword"] = ldb.MessageElement(mputf16, ldb.FLAG_MOD_REPLACE, "clearTextPassword") samdb.modify(msg) res = samdb.search(expression=("samAccountName=%s$" % names.netbiosname), attrs=["msDs-keyVersionNumber"]) assert (len(res) == 1) kvno = int(str(res[0]["msDs-keyVersionNumber"])) secChanType = int(secrets_msg[0]["secureChannelType"][0]) secretsdb_self_join(secrets_ldb, domain=names.domain, realm=names.realm, domainsid=names.domainsid, dnsdomain=names.dnsdomain, netbiosname=names.netbiosname, machinepass=machinepass, key_version_number=kvno, secure_channel_type=secChanType) else: raise ProvisioningError("Unable to find a Secure Channel" "of type SEC_CHAN_BDC")
def join_finalise(ctx): '''finalise the join, mark us synchronised and setup secrets db''' print "Setting isSynchronized" m = ldb.Message() m.dn = ldb.Dn(ctx.samdb, '@ROOTDSE') m["isSynchronized"] = ldb.MessageElement("TRUE", ldb.FLAG_MOD_REPLACE, "isSynchronized") ctx.samdb.modify(m) secrets_ldb = Ldb(ctx.paths.secrets, session_info=system_session(), lp=ctx.lp) print "Setting up secrets database" secretsdb_self_join(secrets_ldb, domain=ctx.domain_name, realm=ctx.realm, dnsdomain=ctx.dnsdomain, netbiosname=ctx.myname, domainsid=security.dom_sid(ctx.domsid), machinepass=ctx.acct_pass, secure_channel_type=ctx.secure_channel_type, key_version_number=ctx.key_version_number)
def update_machine_account_password(samdb, secrets_ldb, names): """Update (change) the password of the current DC both in the SAM db and in secret one :param samdb: An LDB object related to the sam.ldb file of a given provision :param secrets_ldb: An LDB object related to the secrets.ldb file of a given provision :param names: List of key provision parameters""" expression = "samAccountName=%s$" % names.netbiosname secrets_msg = secrets_ldb.search(expression=expression, attrs=["secureChannelType"]) if int(secrets_msg[0]["secureChannelType"][0]) == SEC_CHAN_BDC: res = samdb.search(expression=expression, attrs=[]) assert(len(res) == 1) msg = ldb.Message(res[0].dn) machinepass = samba.generate_random_password(128, 255) mputf16 = machinepass.encode('utf-16-le') msg["clearTextPassword"] = ldb.MessageElement(mputf16, ldb.FLAG_MOD_REPLACE, "clearTextPassword") samdb.modify(msg) res = samdb.search(expression=("samAccountName=%s$" % names.netbiosname), attrs=["msDs-keyVersionNumber"]) assert(len(res) == 1) kvno = int(str(res[0]["msDs-keyVersionNumber"])) secChanType = int(secrets_msg[0]["secureChannelType"][0]) secretsdb_self_join(secrets_ldb, domain=names.domain, realm=names.realm, domainsid=names.domainsid, dnsdomain=names.dnsdomain, netbiosname=names.netbiosname, machinepass=machinepass, key_version_number=kvno, secure_channel_type=secChanType) else: raise ProvisioningError("Unable to find a Secure Channel" "of type SEC_CHAN_BDC")
def run(self, sambaopts=None, credopts=None, backup_file=None, targetdir=None, newservername=None, host_ip=None, host_ip6=None): if not (backup_file and os.path.exists(backup_file)): raise CommandError('Backup file not found.') if targetdir is None: raise CommandError('Please specify a target directory') # allow restoredc to install into a directory prepopulated by selftest if (os.path.exists(targetdir) and os.listdir(targetdir) and os.environ.get('SAMBA_SELFTEST') != '1'): raise CommandError('Target directory is not empty') if not newservername: raise CommandError('Server name required') logger = logging.getLogger() logger.setLevel(logging.DEBUG) logger.addHandler(logging.StreamHandler(sys.stdout)) # ldapcmp prefers the server's netBIOS name in upper-case newservername = newservername.upper() # extract the backup .tar to a temp directory targetdir = os.path.abspath(targetdir) tf = tarfile.open(backup_file) tf.extractall(targetdir) tf.close() # use the smb.conf that got backed up, by default (save what was # actually backed up, before we mess with it) smbconf = os.path.join(targetdir, 'etc', 'smb.conf') shutil.copyfile(smbconf, smbconf + ".orig") # if a smb.conf was specified on the cmd line, then use that instead cli_smbconf = sambaopts.get_loadparm_path() if cli_smbconf: logger.info("Using %s as restored domain's smb.conf" % cli_smbconf) shutil.copyfile(cli_smbconf, smbconf) lp = samba.param.LoadParm() lp.load(smbconf) # open a DB connection to the restored DB private_dir = os.path.join(targetdir, 'private') samdb_path = os.path.join(private_dir, 'sam.ldb') samdb = SamDB(url=samdb_path, session_info=system_session(), lp=lp) # Create account using the join_add_objects function in the join object # We need namingContexts, account control flags, and the sid saved by # the backup process. res = samdb.search(base="", scope=ldb.SCOPE_BASE, attrs=['namingContexts']) ncs = [str(r) for r in res[0].get('namingContexts')] creds = credopts.get_credentials(lp) ctx = DCJoinContext(logger, creds=creds, lp=lp, forced_local_samdb=samdb, netbios_name=newservername) ctx.nc_list = ncs ctx.full_nc_list = ncs ctx.userAccountControl = (samba.dsdb.UF_SERVER_TRUST_ACCOUNT | samba.dsdb.UF_TRUSTED_FOR_DELEGATION) # rewrite the smb.conf to make sure it uses the new targetdir settings. # (This doesn't update all filepaths in a customized config, but it # corrects the same paths that get set by a new provision) logger.info('Updating basic smb.conf settings...') make_smbconf(smbconf, newservername, ctx.domain_name, ctx.realm, targetdir, lp=lp, serverrole="active directory domain controller") # Get the SID saved by the backup process and create account res = samdb.search(base=ldb.Dn(samdb, "@SAMBA_DSDB"), scope=ldb.SCOPE_BASE, attrs=['sidForRestore', 'backupRename']) is_rename = True if 'backupRename' in res[0] else False sid = res[0].get('sidForRestore')[0] logger.info('Creating account with SID: ' + str(sid)) ctx.join_add_objects(specified_sid=dom_sid(sid)) m = ldb.Message() m.dn = ldb.Dn(samdb, '@ROOTDSE') ntds_guid = str(ctx.ntds_guid) m["dsServiceName"] = ldb.MessageElement("<GUID=%s>" % ntds_guid, ldb.FLAG_MOD_REPLACE, "dsServiceName") samdb.modify(m) # if we renamed the backed-up domain, then we need to add the DNS # objects for the new realm (we do this in the restore, now that we # know the new DC's IP address) if is_rename: self.register_dns_zone(logger, samdb, lp, ctx.ntds_guid, host_ip, host_ip6) secrets_path = os.path.join(private_dir, 'secrets.ldb') secrets_ldb = Ldb(secrets_path, session_info=system_session(), lp=lp) secretsdb_self_join(secrets_ldb, domain=ctx.domain_name, realm=ctx.realm, dnsdomain=ctx.dnsdomain, netbiosname=ctx.myname, domainsid=ctx.domsid, machinepass=ctx.acct_pass, key_version_number=ctx.key_version_number, secure_channel_type=misc.SEC_CHAN_BDC) # Seize DNS roles domain_dn = samdb.domain_dn() forest_dn = samba.dn_from_dns_name(samdb.forest_dns_name()) domaindns_dn = ("CN=Infrastructure,DC=DomainDnsZones,", domain_dn) forestdns_dn = ("CN=Infrastructure,DC=ForestDnsZones,", forest_dn) for dn_prefix, dns_dn in [forestdns_dn, domaindns_dn]: if dns_dn not in ncs: continue full_dn = dn_prefix + dns_dn m = ldb.Message() m.dn = ldb.Dn(samdb, full_dn) m["fSMORoleOwner"] = ldb.MessageElement(samdb.get_dsServiceName(), ldb.FLAG_MOD_REPLACE, "fSMORoleOwner") samdb.modify(m) # Seize other roles for role in ['rid', 'pdc', 'naming', 'infrastructure', 'schema']: self.seize_role(role, samdb, force=True) # Get all DCs and remove them (this ensures these DCs cannot # replicate because they will not have a password) search_expr = "(&(objectClass=Server)(serverReference=*))" res = samdb.search(samdb.get_config_basedn(), scope=ldb.SCOPE_SUBTREE, expression=search_expr) for m in res: cn = m.get('cn')[0] if cn != newservername: remove_dc(samdb, logger, cn) # Remove the repsFrom and repsTo from each NC to ensure we do # not try (and fail) to talk to the old DCs for nc in ncs: msg = ldb.Message() msg.dn = ldb.Dn(samdb, nc) msg["repsFrom"] = ldb.MessageElement([], ldb.FLAG_MOD_REPLACE, "repsFrom") msg["repsTo"] = ldb.MessageElement([], ldb.FLAG_MOD_REPLACE, "repsTo") samdb.modify(msg) # Update the krbtgt passwords twice, ensuring no tickets from # the old domain are valid update_krbtgt_account_password(samdb) update_krbtgt_account_password(samdb) # restore the sysvol directory from the backup tar file, including the # original NTACLs. Note that the backup_restore() will fail if not root sysvol_tar = os.path.join(targetdir, 'sysvol.tar.gz') dest_sysvol_dir = lp.get('path', 'sysvol') if not os.path.exists(dest_sysvol_dir): os.makedirs(dest_sysvol_dir) backup_restore(sysvol_tar, dest_sysvol_dir, samdb, smbconf) os.remove(sysvol_tar) # fix up any stale links to the old DCs we just removed logger.info("Fixing up any remaining references to the old DCs...") self.fix_old_dc_references(samdb) # Remove DB markers added by the backup process m = ldb.Message() m.dn = ldb.Dn(samdb, "@SAMBA_DSDB") m["backupDate"] = ldb.MessageElement([], ldb.FLAG_MOD_DELETE, "backupDate") m["sidForRestore"] = ldb.MessageElement([], ldb.FLAG_MOD_DELETE, "sidForRestore") if is_rename: m["backupRename"] = ldb.MessageElement([], ldb.FLAG_MOD_DELETE, "backupRename") samdb.modify(m) logger.info("Backup file successfully restored to %s" % targetdir) logger.info("Please check the smb.conf settings are correct before " "starting samba.")
def join_finalise(ctx): """Finalise the join, mark us synchronised and setup secrets db.""" logger = logging.getLogger("provision") logger.addHandler(logging.StreamHandler(sys.stdout)) # FIXME we shouldn't do this in all cases # If for some reasons we joined in another site than the one of # DC we just replicated from then we don't need to send the updatereplicateref # as replication between sites is time based and on the initiative of the # requesting DC print "Sending DsReplicateUpdateRefs for all the replicated partitions" for nc in ctx.full_nc_list: ctx.send_DsReplicaUpdateRefs(nc) if ctx.RODC: print "Setting RODC invocationId" ctx.local_samdb.set_invocation_id(str(ctx.invocation_id)) ctx.local_samdb.set_opaque_integer("domainFunctionality", ctx.behavior_version) m = ldb.Message() m.dn = ldb.Dn(ctx.local_samdb, "%s" % ctx.ntds_dn) m["invocationId"] = ldb.MessageElement(ndr_pack(ctx.invocation_id), ldb.FLAG_MOD_REPLACE, "invocationId") ctx.local_samdb.modify(m) # Note: as RODC the invocationId is only stored # on the RODC itself, the other DCs never see it. # # Thats is why we fix up the replPropertyMetaData stamp # for the 'invocationId' attribute, we need to change # the 'version' to '0', this is what windows 2008r2 does as RODC # # This means if the object on a RWDC ever gets a invocationId # attribute, it will have version '1' (or higher), which will # will overwrite the RODC local value. ctx.local_samdb.set_attribute_replmetadata_version(m.dn, "invocationId", 0) print "Setting isSynchronized and dsServiceName" m = ldb.Message() m.dn = ldb.Dn(ctx.local_samdb, '@ROOTDSE') m["isSynchronized"] = ldb.MessageElement("TRUE", ldb.FLAG_MOD_REPLACE, "isSynchronized") m["dsServiceName"] = ldb.MessageElement("<GUID=%s>" % str(ctx.ntds_guid), ldb.FLAG_MOD_REPLACE, "dsServiceName") ctx.local_samdb.modify(m) if ctx.subdomain: return secrets_ldb = Ldb(ctx.paths.secrets, session_info=system_session(), lp=ctx.lp) print "Setting up secrets database" secretsdb_self_join(secrets_ldb, domain=ctx.domain_name, realm=ctx.realm, dnsdomain=ctx.dnsdomain, netbiosname=ctx.myname, domainsid=security.dom_sid(ctx.domsid), machinepass=ctx.acct_pass, secure_channel_type=ctx.secure_channel_type, key_version_number=ctx.key_version_number) if ctx.dns_backend.startswith("BIND9_"): dnspass = samba.generate_random_password(128, 255) setup_bind9_dns(ctx.local_samdb, secrets_ldb, security.dom_sid(ctx.domsid), ctx.names, ctx.paths, ctx.lp, logger, dns_backend=ctx.dns_backend, dnspass=dnspass, os_level=ctx.behavior_version, targetdir=ctx.targetdir)