def run(self, account, sambaopts=None, credopts=None, versionopts=None, server=None): if server is None: raise Exception("You must supply a server") lp = sambaopts.get_loadparm() creds = credopts.get_credentials(lp, fallback_machine=True) # connect to the remote and local SAMs samdb = SamDB(url="ldap://%s" % server, session_info=system_session(), credentials=creds, lp=lp) local_samdb = SamDB(url=None, session_info=system_session(), credentials=creds, lp=lp) # work out the source and destination GUIDs dc_ntds_dn = samdb.get_dsServiceName() res = samdb.search(base=dc_ntds_dn, scope=ldb.SCOPE_BASE, attrs=["invocationId"]) source_dsa_invocation_id = misc.GUID(local_samdb.schema_format_value("objectGUID", res[0]["invocationId"][0])) dn = self.get_dn(samdb, account) self.outf.write("Replicating DN %s\n" % dn) destination_dsa_guid = misc.GUID(local_samdb.get_ntds_GUID()) local_samdb.transaction_start() repl = drs_Replicate("ncacn_ip_tcp:%s[seal,print]" % server, lp, creds, local_samdb) try: repl.replicate(dn, source_dsa_invocation_id, destination_dsa_guid, exop=drsuapi.DRSUAPI_EXOP_REPL_SECRET, rodc=True) except Exception, e: raise CommandError("Error replicating DN %s" % dn, e)
def test_offline_manual_seized_ridalloc_add_user(self): """Peform the same actions as test_offline_samba_tool_seized_ridalloc, but do not create the RID set. Confirm that user-add correctly creates the RID Set.""" fsmo_dn = ldb.Dn( self.ldb_dc1, "CN=RID Manager$,CN=System," + self.ldb_dc1.domain_dn()) (fsmo_owner, fsmo_not_owner) = self._determine_fSMORoleOwner(fsmo_dn) targetdir = self._test_join(fsmo_not_owner['dns_name'], "RIDALLOCTEST3") try: # Connect to the database ldb_url = "tdb://%s" % os.path.join(targetdir, "private/sam.ldb") lp = self.get_loadparm() new_ldb = SamDB(ldb_url, credentials=self.get_credentials(), session_info=system_session(lp), lp=lp) serviceName = new_ldb.get_dsServiceName() m = ldb.Message() m.dn = fsmo_dn m["fSMORoleOwner"] = ldb.MessageElement(serviceName, ldb.FLAG_MOD_REPLACE, "fSMORoleOwner") new_ldb.modify(m) # 1. Get server name res = new_ldb.search(base=ldb.Dn(new_ldb, new_ldb.get_serverName()), scope=ldb.SCOPE_BASE, attrs=["serverReference"]) # 2. Get server reference server_ref_dn = ldb.Dn(new_ldb, res[0]['serverReference'][0].decode('utf8')) # Assert that no RID Set has been set res = new_ldb.search(base=server_ref_dn, scope=ldb.SCOPE_BASE, attrs=['rIDSetReferences']) self.assertFalse("rIDSetReferences" in res[0]) smbconf = os.path.join(targetdir, "etc/smb.conf") new_ldb.newuser("ridalloctestuser", "P@ssword!") # 3. Assert we get the RID Set res = new_ldb.search(base=server_ref_dn, scope=ldb.SCOPE_BASE, attrs=['rIDSetReferences']) self.assertTrue("rIDSetReferences" in res[0]) finally: self._test_force_demote(fsmo_not_owner['dns_name'], "RIDALLOCTEST3") shutil.rmtree(targetdir, ignore_errors=True)
def test_offline_manual_seized_ridalloc_with_dbcheck(self): """Peform the same actions as test_offline_samba_tool_seized_ridalloc, but do not create the RID set. Confirm that dbcheck correctly creates the RID Set. Also check """ fsmo_dn = ldb.Dn(self.ldb_dc1, "CN=RID Manager$,CN=System," + self.ldb_dc1.domain_dn()) (fsmo_owner, fsmo_not_owner) = self._determine_fSMORoleOwner(fsmo_dn) targetdir = self._test_join(fsmo_not_owner['dns_name'], "RIDALLOCTEST2") try: # Connect to the database ldb_url = "tdb://%s" % os.path.join(targetdir, "private/sam.ldb") lp = self.get_loadparm() new_ldb = SamDB(ldb_url, credentials=self.get_credentials(), session_info=system_session(lp), lp=lp) serviceName = new_ldb.get_dsServiceName() m = ldb.Message() m.dn = fsmo_dn m["fSMORoleOwner"] = ldb.MessageElement(serviceName, ldb.FLAG_MOD_REPLACE, "fSMORoleOwner") new_ldb.modify(m) # 1. Get server name res = new_ldb.search(base=ldb.Dn(new_ldb, new_ldb.get_serverName()), scope=ldb.SCOPE_BASE, attrs=["serverReference"]) # 2. Get server reference server_ref_dn = ldb.Dn(new_ldb, res[0]['serverReference'][0]) # Assert that no RID Set has been set res = new_ldb.search(base=server_ref_dn, scope=ldb.SCOPE_BASE, attrs=['rIDSetReferences']) self.assertFalse("rIDSetReferences" in res[0]) smbconf = os.path.join(targetdir, "etc/smb.conf") chk = dbcheck(new_ldb, verbose=False, fix=True, yes=True, quiet=True) self.assertEqual(chk.check_database(DN=server_ref_dn, scope=ldb.SCOPE_BASE), 1, "Should have fixed one error (missing RID Set)") # 3. Assert we get the RID Set res = new_ldb.search(base=server_ref_dn, scope=ldb.SCOPE_BASE, attrs=['rIDSetReferences']) self.assertTrue("rIDSetReferences" in res[0]) finally: self._test_force_demote(fsmo_not_owner['dns_name'], "RIDALLOCTEST2") shutil.rmtree(targetdir, ignore_errors=True)
def run(self, *accounts, **kwargs): sambaopts = kwargs.get("sambaopts") credopts = kwargs.get("credopts") versionpts = kwargs.get("versionopts") server = kwargs.get("server") accounts_file = kwargs.get("file") if server is None: raise Exception("You must supply a server") if accounts_file is not None: accounts = [] if accounts_file == "-": for line in sys.stdin: accounts.append(line.strip()) else: for line in open(accounts_file, 'r'): accounts.append(line.strip()) lp = sambaopts.get_loadparm() creds = credopts.get_credentials(lp, fallback_machine=True) # connect to the remote and local SAMs samdb = SamDB(url="ldap://%s" % server, session_info=system_session(), credentials=creds, lp=lp) local_samdb = SamDB(url=None, session_info=system_session(), credentials=creds, lp=lp) destination_dsa_guid = misc.GUID(local_samdb.get_ntds_GUID()) repl = drs_Replicate("ncacn_ip_tcp:%s[seal,print]" % server, lp, creds, local_samdb, destination_dsa_guid) for account in accounts: # work out the source and destination GUIDs dc_ntds_dn = samdb.get_dsServiceName() res = samdb.search(base=dc_ntds_dn, scope=ldb.SCOPE_BASE, attrs=["invocationId"]) source_dsa_invocation_id = misc.GUID(local_samdb.schema_format_value("objectGUID", res[0]["invocationId"][0])) dn = self.get_dn(samdb, account) self.outf.write("Replicating DN %s\n" % dn) local_samdb.transaction_start() try: repl.replicate(dn, source_dsa_invocation_id, destination_dsa_guid, exop=drsuapi.DRSUAPI_EXOP_REPL_SECRET, rodc=True) except Exception, e: local_samdb.transaction_cancel() raise CommandError("Error replicating DN %s" % dn, e) local_samdb.transaction_commit()
def run(self, account, sambaopts=None, credopts=None, versionopts=None, server=None): if server is None: raise Exception("You must supply a server") lp = sambaopts.get_loadparm() creds = credopts.get_credentials(lp, fallback_machine=True) # connect to the remote and local SAMs samdb = SamDB(url="ldap://%s" % server, session_info=system_session(), credentials=creds, lp=lp) local_samdb = SamDB(url=None, session_info=system_session(), credentials=creds, lp=lp) # work out the source and destination GUIDs dc_ntds_dn = samdb.get_dsServiceName() res = samdb.search(base=dc_ntds_dn, scope=ldb.SCOPE_BASE, attrs=["invocationId"]) source_dsa_invocation_id = misc.GUID( local_samdb.schema_format_value("objectGUID", res[0]["invocationId"][0])) dn = self.get_dn(samdb, account) self.outf.write("Replicating DN %s\n" % dn) destination_dsa_guid = misc.GUID(local_samdb.get_ntds_GUID()) local_samdb.transaction_start() repl = drs_Replicate("ncacn_ip_tcp:%s[seal,print]" % server, lp, creds, local_samdb, destination_dsa_guid) try: repl.replicate(dn, source_dsa_invocation_id, destination_dsa_guid, exop=drsuapi.DRSUAPI_EXOP_REPL_SECRET, rodc=True) except Exception, e: local_samdb.transaction_cancel() raise CommandError("Error replicating DN %s" % dn, e)
def test_offline_manual_seized_ridalloc_add_user_as_admin(self): """Peform the same actions as test_offline_samba_tool_seized_ridalloc, but do not create the RID set. Confirm that user-add correctly creates the RID Set.""" fsmo_dn = ldb.Dn(self.ldb_dc1, "CN=RID Manager$,CN=System," + self.ldb_dc1.domain_dn()) (fsmo_owner, fsmo_not_owner) = self._determine_fSMORoleOwner(fsmo_dn) targetdir = self._test_join(fsmo_not_owner['dns_name'], "RIDALLOCTEST4") try: # Connect to the database ldb_url = "tdb://%s" % os.path.join(targetdir, "private/sam.ldb") lp = self.get_loadparm() new_ldb = SamDB(ldb_url, credentials=self.get_credentials(), session_info=admin_session(lp, self.ldb_dc1.get_domain_sid()), lp=lp) serviceName = new_ldb.get_dsServiceName() m = ldb.Message() m.dn = fsmo_dn m["fSMORoleOwner"] = ldb.MessageElement(serviceName, ldb.FLAG_MOD_REPLACE, "fSMORoleOwner") new_ldb.modify(m) # 1. Get server name res = new_ldb.search(base=ldb.Dn(new_ldb, new_ldb.get_serverName()), scope=ldb.SCOPE_BASE, attrs=["serverReference"]) # 2. Get server reference server_ref_dn = ldb.Dn(new_ldb, res[0]['serverReference'][0]) # Assert that no RID Set has been set res = new_ldb.search(base=server_ref_dn, scope=ldb.SCOPE_BASE, attrs=['rIDSetReferences']) self.assertFalse("rIDSetReferences" in res[0]) smbconf = os.path.join(targetdir, "etc/smb.conf") # Create a user to allocate a RID Set for itself (the RID master) new_ldb.newuser("ridalloctestuser", "P@ssword!") # 3. Assert we get the RID Set res = new_ldb.search(base=server_ref_dn, scope=ldb.SCOPE_BASE, attrs=['rIDSetReferences']) self.assertTrue("rIDSetReferences" in res[0]) finally: self._test_force_demote(fsmo_not_owner['dns_name'], "RIDALLOCTEST4") shutil.rmtree(targetdir, ignore_errors=True)
def run(self, *accounts, **kwargs): sambaopts = kwargs.get("sambaopts") credopts = kwargs.get("credopts") server = kwargs.get("server") accounts_file = kwargs.get("file") ignore_errors = kwargs.get("ignore_errors") if server is None: raise Exception("You must supply a server") if accounts_file is not None: accounts = [] if accounts_file == "-": for line in sys.stdin: accounts.append(line.strip()) else: for line in open(accounts_file, 'r'): accounts.append(line.strip()) lp = sambaopts.get_loadparm() creds = credopts.get_credentials(lp, fallback_machine=True) # connect to the remote and local SAMs samdb = SamDB(url="ldap://%s" % server, session_info=system_session(), credentials=creds, lp=lp) local_samdb = SamDB(url=None, session_info=system_session(), credentials=creds, lp=lp) destination_dsa_guid = misc.GUID(local_samdb.get_ntds_GUID()) binding_options = "seal" if lp.log_level() >= 9: binding_options += ",print" repl = drs_Replicate("ncacn_ip_tcp:%s[%s]" % (server, binding_options), lp, creds, local_samdb, destination_dsa_guid) errors = [] for account in accounts: # work out the source and destination GUIDs dc_ntds_dn = samdb.get_dsServiceName() res = samdb.search(base=dc_ntds_dn, scope=ldb.SCOPE_BASE, attrs=["invocationId"]) source_dsa_invocation_id = misc.GUID( local_samdb.schema_format_value("objectGUID", res[0]["invocationId"][0])) try: dn = self.get_dn(samdb, account) except RODCException as e: if not ignore_errors: raise CommandError(str(e)) errors.append(e) continue self.outf.write("Replicating DN %s\n" % dn) local_samdb.transaction_start() try: repl.replicate(dn, source_dsa_invocation_id, destination_dsa_guid, exop=drsuapi.DRSUAPI_EXOP_REPL_SECRET, rodc=True) except Exception as e: local_samdb.transaction_cancel() if not ignore_errors: raise CommandError("Error replicating DN %s" % dn) errors.append(ReplicationError("Error replicating DN %s" % dn)) continue local_samdb.transaction_commit() if len(errors) > 0: self.message("\nPreload encountered problematic users:") for error in errors: self.message(" %s" % error)
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.")