def main(): lp = LoadParm() lp.load_default() print("\nLoaded loadparm:") print(" samdb_url: ", lp.samdb_url()) print(" server_role: ", lp.server_role()) creds = Credentials() creds.guess(lp) print("\nCredentials:") creds.set_kerberos_state(MUST_USE_KERBEROS) # If MUST_USE_KERBEROS and we have no ticket, yields this error: # "Failed to connect to 'ldap://dc1' with backend 'ldap': LDAP client internal error: NT_STATUS_INVALID_PARAMETER" # Local #samdb = SamDB(lp=lp) # Remote samdb = SamDB(lp=lp, url='ldap://dc1', credentials=creds) print("\nOpened SAM DB:") print(" domain_dn: ", samdb.domain_dn()) print(" domain_dns_name:", samdb.domain_dns_name()) for q in sys.argv[1:]: query(samdb, q)
def run(self, sambaopts=None, credopts=None, server=None, targetdir=None, no_secrets=False, backend_store=None): logger = self.get_logger() logger.setLevel(logging.DEBUG) lp = sambaopts.get_loadparm() creds = credopts.get_credentials(lp) # Make sure we have all the required args. if server is None: raise CommandError('Server required') check_targetdir(logger, targetdir) tmpdir = tempfile.mkdtemp(dir=targetdir) # Run a clone join on the remote include_secrets = not no_secrets ctx = join_clone(logger=logger, creds=creds, lp=lp, include_secrets=include_secrets, server=server, dns_backend='SAMBA_INTERNAL', targetdir=tmpdir, backend_store=backend_store) # get the paths used for the clone, then drop the old samdb connection paths = ctx.paths del ctx # Get a free RID to use as the new DC's SID (when it gets restored) remote_sam = SamDB(url='ldap://' + server, credentials=creds, session_info=system_session(), lp=lp) new_sid = get_sid_for_restore(remote_sam, logger) realm = remote_sam.domain_dns_name() # Grab the remote DC's sysvol files and bundle them into a tar file sysvol_tar = os.path.join(tmpdir, 'sysvol.tar.gz') smb_conn = smb_sysvol_conn(server, lp, creds) backup_online(smb_conn, sysvol_tar, remote_sam.get_domain_sid()) # remove the default sysvol files created by the clone (we want to # make sure we restore the sysvol.tar.gz files instead) shutil.rmtree(paths.sysvol) # Edit the downloaded sam.ldb to mark it as a backup samdb = SamDB(url=paths.samdb, session_info=system_session(), lp=lp) time_str = get_timestamp() add_backup_marker(samdb, "backupDate", time_str) add_backup_marker(samdb, "sidForRestore", new_sid) add_backup_marker(samdb, "backupType", "online") # ensure the admin user always has a password set (same as provision) if no_secrets: set_admin_password(logger, samdb) # Add everything in the tmpdir to the backup tar file backup_file = backup_filepath(targetdir, realm, time_str) create_log_file(tmpdir, lp, "online", server, include_secrets) create_backup_tar(logger, tmpdir, backup_file) shutil.rmtree(tmpdir)
def run(self, sambaopts=None, credopts=None, server=None, targetdir=None): logger = self.get_logger() logger.setLevel(logging.DEBUG) # Make sure we have all the required args. check_online_backup_args(logger, credopts, server, targetdir) lp = sambaopts.get_loadparm() creds = credopts.get_credentials(lp) if not os.path.exists(targetdir): logger.info('Creating targetdir %s...' % targetdir) os.makedirs(targetdir) tmpdir = tempfile.mkdtemp(dir=targetdir) # Run a clone join on the remote ctx = join_clone(logger=logger, creds=creds, lp=lp, include_secrets=True, dns_backend='SAMBA_INTERNAL', server=server, targetdir=tmpdir) # get the paths used for the clone, then drop the old samdb connection paths = ctx.paths del ctx # Get a free RID to use as the new DC's SID (when it gets restored) remote_sam = SamDB(url='ldap://' + server, credentials=creds, session_info=system_session(), lp=lp) new_sid = get_sid_for_restore(remote_sam) realm = remote_sam.domain_dns_name() # Grab the remote DC's sysvol files and bundle them into a tar file sysvol_tar = os.path.join(tmpdir, 'sysvol.tar.gz') smb_conn = smb.SMB(server, "sysvol", lp=lp, creds=creds) backup_online(smb_conn, sysvol_tar, remote_sam.get_domain_sid()) # remove the default sysvol files created by the clone (we want to # make sure we restore the sysvol.tar.gz files instead) shutil.rmtree(paths.sysvol) # Edit the downloaded sam.ldb to mark it as a backup samdb = SamDB(url=paths.samdb, session_info=system_session(), lp=lp) time_str = get_timestamp() add_backup_marker(samdb, "backupDate", time_str) add_backup_marker(samdb, "sidForRestore", new_sid) # Add everything in the tmpdir to the backup tar file backup_file = backup_filepath(targetdir, realm, time_str) create_backup_tar(logger, tmpdir, backup_file) shutil.rmtree(tmpdir)
def main(): args = parse_args() logging.basicConfig(level=logging.DEBUG if args.debug else logging.WARNING) inpipe = sys.stdin outpipe = sys.stdout if args.unix: import socket try: os.remove(args.unix) except OSError: pass sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) sock.bind(args.unix) os.chmod(args.unix, 0o777) logger.debug("Bound unix socket: {}".format(args.unix)) logger.info("Waiting for connection at {}".format(args.unix)) sock.listen(1) csock, client_address = sock.accept() logger.info("Accepted connection from {}".format(client_address)) inpipe = outpipe = csock.makefile() lp = LoadParm() lp.load_default() creds = Credentials() creds.guess(lp) creds.set_kerberos_state(MUST_USE_KERBEROS) # If MUST_USE_KERBEROS and we have no ticket, yields this error: # "Failed to connect to 'ldap://dc1' with backend 'ldap': LDAP client # internal error: NT_STATUS_INVALID_PARAMETER" # lp is required by ldap_connect_send() -> lpcfg_resolve_context() samdb = SamDB(lp=lp, url=args.url, credentials=creds) logger.debug("Opened SAM DB:") logger.debug(" domain_dn: {}".format(samdb.domain_dn())) logger.debug(" domain_dns_name: {}".format(samdb.domain_dns_name())) try: r = SambaResponder(samdb, inpipe, outpipe) r.run() finally: if args.unix: try: os.remove(args.unix) except OSError: pass
class PassWordHashTests(TestCase): def setUp(self): self.lp = samba.tests.env_loadparm() super(PassWordHashTests, self).setUp() def set_store_cleartext(self, cleartext): # get the current pwdProperties pwdProperties = self.ldb.get_pwdProperties() # update the clear-text properties flag props = int(pwdProperties) if cleartext: props |= DOMAIN_PASSWORD_STORE_CLEARTEXT else: props &= ~DOMAIN_PASSWORD_STORE_CLEARTEXT self.ldb.set_pwdProperties(str(props)) # Add a user to ldb, this will exercise the password_hash code # and calculate the appropriate supplemental credentials def add_user(self, options=None, clear_text=False, ldb=None): # set any needed options if options is not None: for (option, value) in options: self.lp.set(option, value) if ldb is None: self.creds = Credentials() self.session = system_session() self.creds.guess(self.lp) self.session = system_session() self.ldb = SamDB(session_info=self.session, credentials=self.creds, lp=self.lp) else: self.ldb = ldb res = self.ldb.search(base=self.ldb.get_config_basedn(), expression="ncName=%s" % self.ldb.get_default_basedn(), attrs=["nETBIOSName"]) self.netbios_domain = str(res[0]["nETBIOSName"][0]) self.dns_domain = self.ldb.domain_dns_name() # Gets back the basedn base_dn = self.ldb.domain_dn() # Gets back the configuration basedn configuration_dn = self.ldb.get_config_basedn().get_linearized() # permit password changes during this test PasswordCommon.allow_password_changes(self, self.ldb) self.base_dn = self.ldb.domain_dn() account_control = 0 if clear_text: # Restore the current domain setting on exit. pwdProperties = self.ldb.get_pwdProperties() self.addCleanup(self.ldb.set_pwdProperties, pwdProperties) # Update the domain setting self.set_store_cleartext(clear_text) account_control |= UF_ENCRYPTED_TEXT_PASSWORD_ALLOWED # (Re)adds the test user USER_NAME with password USER_PASS # and userPrincipalName UPN delete_force(self.ldb, "cn=" + USER_NAME + ",cn=users," + self.base_dn) self.ldb.add({ "dn": "cn=" + USER_NAME + ",cn=users," + self.base_dn, "objectclass": "user", "sAMAccountName": USER_NAME, "userPassword": USER_PASS, "userPrincipalName": UPN, "userAccountControl": str(account_control) }) # Get the supplemental credentials for the user under test def get_supplemental_creds(self): base = "cn=" + USER_NAME + ",cn=users," + self.base_dn res = self.ldb.search(scope=ldb.SCOPE_BASE, base=base, attrs=["supplementalCredentials"]) self.assertIs(True, len(res) > 0) obj = res[0] sc_blob = obj["supplementalCredentials"][0] sc = ndr_unpack(drsblobs.supplementalCredentialsBlob, sc_blob) return sc # Calculate and validate a Wdigest value def check_digest(self, user, realm, password, digest): expected = calc_digest(user, realm, password) actual = binascii.hexlify(bytearray(digest)).decode('utf8') error = "Digest expected[%s], actual[%s], " \ "user[%s], realm[%s], pass[%s]" % \ (expected, actual, user, realm, password) self.assertEquals(expected, actual, error) # Check all of the 29 expected WDigest values # def check_wdigests(self, digests): self.assertEquals(29, digests.num_hashes) # Using the n-1 pattern in the array indexes to make it easier # to check the tests against the spec and the samba-tool user tests. self.check_digest(USER_NAME, self.netbios_domain, USER_PASS, digests.hashes[1 - 1].hash) self.check_digest(USER_NAME.lower(), self.netbios_domain.lower(), USER_PASS, digests.hashes[2 - 1].hash) self.check_digest(USER_NAME.upper(), self.netbios_domain.upper(), USER_PASS, digests.hashes[3 - 1].hash) self.check_digest(USER_NAME, self.netbios_domain.upper(), USER_PASS, digests.hashes[4 - 1].hash) self.check_digest(USER_NAME, self.netbios_domain.lower(), USER_PASS, digests.hashes[5 - 1].hash) self.check_digest(USER_NAME.upper(), self.netbios_domain.lower(), USER_PASS, digests.hashes[6 - 1].hash) self.check_digest(USER_NAME.lower(), self.netbios_domain.upper(), USER_PASS, digests.hashes[7 - 1].hash) self.check_digest(USER_NAME, self.dns_domain, USER_PASS, digests.hashes[8 - 1].hash) self.check_digest(USER_NAME.lower(), self.dns_domain.lower(), USER_PASS, digests.hashes[9 - 1].hash) self.check_digest(USER_NAME.upper(), self.dns_domain.upper(), USER_PASS, digests.hashes[10 - 1].hash) self.check_digest(USER_NAME, self.dns_domain.upper(), USER_PASS, digests.hashes[11 - 1].hash) self.check_digest(USER_NAME, self.dns_domain.lower(), USER_PASS, digests.hashes[12 - 1].hash) self.check_digest(USER_NAME.upper(), self.dns_domain.lower(), USER_PASS, digests.hashes[13 - 1].hash) self.check_digest(USER_NAME.lower(), self.dns_domain.upper(), USER_PASS, digests.hashes[14 - 1].hash) self.check_digest(UPN, "", USER_PASS, digests.hashes[15 - 1].hash) self.check_digest(UPN.lower(), "", USER_PASS, digests.hashes[16 - 1].hash) self.check_digest(UPN.upper(), "", USER_PASS, digests.hashes[17 - 1].hash) name = "%s\\%s" % (self.netbios_domain, USER_NAME) self.check_digest(name, "", USER_PASS, digests.hashes[18 - 1].hash) name = "%s\\%s" % (self.netbios_domain.lower(), USER_NAME.lower()) self.check_digest(name, "", USER_PASS, digests.hashes[19 - 1].hash) name = "%s\\%s" % (self.netbios_domain.upper(), USER_NAME.upper()) self.check_digest(name, "", USER_PASS, digests.hashes[20 - 1].hash) self.check_digest(USER_NAME, "Digest", USER_PASS, digests.hashes[21 - 1].hash) self.check_digest(USER_NAME.lower(), "Digest", USER_PASS, digests.hashes[22 - 1].hash) self.check_digest(USER_NAME.upper(), "Digest", USER_PASS, digests.hashes[23 - 1].hash) self.check_digest(UPN, "Digest", USER_PASS, digests.hashes[24 - 1].hash) self.check_digest(UPN.lower(), "Digest", USER_PASS, digests.hashes[25 - 1].hash) self.check_digest(UPN.upper(), "Digest", USER_PASS, digests.hashes[26 - 1].hash) name = "%s\\%s" % (self.netbios_domain, USER_NAME) self.check_digest(name, "Digest", USER_PASS, digests.hashes[27 - 1].hash) name = "%s\\%s" % (self.netbios_domain.lower(), USER_NAME.lower()) self.check_digest(name, "Digest", USER_PASS, digests.hashes[28 - 1].hash) name = "%s\\%s" % (self.netbios_domain.upper(), USER_NAME.upper()) self.check_digest(name, "Digest", USER_PASS, digests.hashes[29 - 1].hash) def checkUserPassword(self, up, expected): # Check we've received the correct number of hashes self.assertEquals(len(expected), up.num_hashes) i = 0 for (tag, alg, rounds) in expected: self.assertEquals(tag, up.hashes[i].scheme) data = up.hashes[i].value.decode('utf8').split("$") # Check we got the expected crypt algorithm self.assertEquals(alg, data[1]) if rounds is None: cmd = "$%s$%s" % (alg, data[2]) else: cmd = "$%s$rounds=%d$%s" % (alg, rounds, data[3]) # Calculate the expected hash value expected = crypt.crypt(USER_PASS, cmd) self.assertEquals(expected, up.hashes[i].value.decode('utf8')) i += 1 # Check that the correct nt_hash was stored for userPassword def checkNtHash(self, password, nt_hash): creds = Credentials() creds.set_anonymous() creds.set_password(password) expected = creds.get_nt_hash() actual = bytearray(nt_hash) self.assertEquals(expected, actual)
class RodcTests(samba.tests.TestCase): def setUp(self): super(RodcTests, self).setUp() self.samdb = SamDB(HOST, credentials=CREDS, session_info=system_session(LP), lp=LP) self.base_dn = self.samdb.domain_dn() root = self.samdb.search(base='', scope=ldb.SCOPE_BASE, attrs=['dsServiceName']) self.service = root[0]['dsServiceName'][0] self.tag = uuid.uuid4().hex def test_add_replicated_objects(self): for o in ( { 'dn': "ou=%s1,%s" % (self.tag, self.base_dn), "objectclass": "organizationalUnit" }, { 'dn': "cn=%s2,%s" % (self.tag, self.base_dn), "objectclass": "user" }, { 'dn': "cn=%s3,%s" % (self.tag, self.base_dn), "objectclass": "group" }, { 'dn': "cn=%s4,%s" % (self.tag, self.service), "objectclass": "NTDSConnection", 'enabledConnection': 'TRUE', 'fromServer': self.base_dn, 'options': '0' }, ): try: self.samdb.add(o) self.fail("Failed to fail to add %s" % o['dn']) except ldb.LdbError as e: (ecode, emsg) = e.args if ecode != ldb.ERR_REFERRAL: print(emsg) self.fail("Adding %s: ldb error: %s %s, wanted referral" % (o['dn'], ecode, emsg)) else: m = re.search(r'(ldap://[^>]+)>', emsg) if m is None: self.fail("referral seems not to refer to anything") address = m.group(1) try: tmpdb = SamDB(address, credentials=CREDS, session_info=system_session(LP), lp=LP) tmpdb.add(o) tmpdb.delete(o['dn']) except ldb.LdbError as e: self.fail("couldn't modify referred location %s" % address) if address.lower().startswith( self.samdb.domain_dns_name()): self.fail( "referral address did not give a specific DC") def test_modify_replicated_attributes(self): # some timestamp ones dn = 'CN=Guest,CN=Users,' + self.base_dn value = 'hallooo' for attr in ['carLicense', 'middleName']: msg = ldb.Message() msg.dn = ldb.Dn(self.samdb, dn) msg[attr] = ldb.MessageElement(value, ldb.FLAG_MOD_REPLACE, attr) try: self.samdb.modify(msg) self.fail("Failed to fail to modify %s %s" % (dn, attr)) except ldb.LdbError as e1: (ecode, emsg) = e1.args if ecode != ldb.ERR_REFERRAL: self.fail("Failed to REFER when trying to modify %s %s" % (dn, attr)) else: m = re.search(r'(ldap://[^>]+)>', emsg) if m is None: self.fail("referral seems not to refer to anything") address = m.group(1) try: tmpdb = SamDB(address, credentials=CREDS, session_info=system_session(LP), lp=LP) tmpdb.modify(msg) except ldb.LdbError as e: self.fail("couldn't modify referred location %s" % address) if address.lower().startswith( self.samdb.domain_dns_name()): self.fail( "referral address did not give a specific DC") def test_modify_nonreplicated_attributes(self): # some timestamp ones dn = 'CN=Guest,CN=Users,' + self.base_dn value = '123456789' for attr in ['badPwdCount', 'lastLogon', 'lastLogoff']: m = ldb.Message() m.dn = ldb.Dn(self.samdb, dn) m[attr] = ldb.MessageElement(value, ldb.FLAG_MOD_REPLACE, attr) # Windows refers these ones even though they are non-replicated try: self.samdb.modify(m) self.fail("Failed to fail to modify %s %s" % (dn, attr)) except ldb.LdbError as e2: (ecode, emsg) = e2.args if ecode != ldb.ERR_REFERRAL: self.fail("Failed to REFER when trying to modify %s %s" % (dn, attr)) else: m = re.search(r'(ldap://[^>]+)>', emsg) if m is None: self.fail("referral seems not to refer to anything") address = m.group(1) if address.lower().startswith( self.samdb.domain_dns_name()): self.fail( "referral address did not give a specific DC") def test_modify_nonreplicated_reps_attributes(self): # some timestamp ones dn = self.base_dn m = ldb.Message() m.dn = ldb.Dn(self.samdb, dn) attr = 'repsFrom' res = self.samdb.search(dn, scope=ldb.SCOPE_BASE, attrs=['repsFrom']) rep = ndr_unpack(drsblobs.repsFromToBlob, res[0]['repsFrom'][0], allow_remaining=True) rep.ctr.result_last_attempt = -1 value = ndr_pack(rep) m[attr] = ldb.MessageElement(value, ldb.FLAG_MOD_REPLACE, attr) try: self.samdb.modify(m) self.fail("Failed to fail to modify %s %s" % (dn, attr)) except ldb.LdbError as e3: (ecode, emsg) = e3.args if ecode != ldb.ERR_REFERRAL: self.fail("Failed to REFER when trying to modify %s %s" % (dn, attr)) else: m = re.search(r'(ldap://[^>]+)>', emsg) if m is None: self.fail("referral seems not to refer to anything") address = m.group(1) if address.lower().startswith(self.samdb.domain_dns_name()): self.fail("referral address did not give a specific DC") def test_delete_special_objects(self): dn = 'CN=Guest,CN=Users,' + self.base_dn try: self.samdb.delete(dn) self.fail("Failed to fail to delete %s" % (dn)) except ldb.LdbError as e4: (ecode, emsg) = e4.args if ecode != ldb.ERR_REFERRAL: print(ecode, emsg) self.fail("Failed to REFER when trying to delete %s" % dn) else: m = re.search(r'(ldap://[^>]+)>', emsg) if m is None: self.fail("referral seems not to refer to anything") address = m.group(1) if address.lower().startswith(self.samdb.domain_dns_name()): self.fail("referral address did not give a specific DC") def test_no_delete_nonexistent_objects(self): dn = 'CN=does-not-exist-%s,CN=Users,%s' % (self.tag, self.base_dn) try: self.samdb.delete(dn) self.fail("Failed to fail to delete %s" % (dn)) except ldb.LdbError as e5: (ecode, emsg) = e5.args if ecode != ldb.ERR_NO_SUCH_OBJECT: print(ecode, emsg) self.fail("Failed to NO_SUCH_OBJECT when trying to delete " "%s (which does not exist)" % dn)
class RodcTests(samba.tests.TestCase): def setUp(self): super(RodcTests, self).setUp() self.samdb = SamDB(HOST, credentials=CREDS, session_info=system_session(LP), lp=LP) self.base_dn = self.samdb.domain_dn() root = self.samdb.search(base='', scope=ldb.SCOPE_BASE, attrs=['dsServiceName']) self.service = root[0]['dsServiceName'][0] self.tag = uuid.uuid4().hex def test_add_replicated_objects(self): for o in ( { 'dn': "ou=%s1,%s" % (self.tag, self.base_dn), "objectclass": "organizationalUnit" }, { 'dn': "cn=%s2,%s" % (self.tag, self.base_dn), "objectclass": "user" }, { 'dn': "cn=%s3,%s" % (self.tag, self.base_dn), "objectclass": "group" }, { 'dn': "cn=%s4,%s" % (self.tag, self.service), "objectclass": "NTDSConnection", 'enabledConnection': 'TRUE', 'fromServer': self.base_dn, 'options': '0' }, ): try: self.samdb.add(o) self.fail("Failed to fail to add %s" % o['dn']) except ldb.LdbError as (ecode, emsg): if ecode != ldb.ERR_REFERRAL: print emsg self.fail("Adding %s: ldb error: %s %s, wanted referral" % (o['dn'], ecode, emsg)) else: m = re.search(r'(ldap://[^>]+)>', emsg) if m is None: self.fail("referral seems not to refer to anything") address = m.group(1) try: tmpdb = SamDB(address, credentials=CREDS, session_info=system_session(LP), lp=LP) tmpdb.add(o) tmpdb.delete(o['dn']) except ldb.LdbError, e: self.fail("couldn't modify referred location %s" % address) if address.lower().startswith( self.samdb.domain_dns_name()): self.fail( "referral address did not give a specific DC")
def run(self, new_domain_name, new_dns_realm, sambaopts=None, credopts=None, server=None, targetdir=None, keep_dns_realm=False): logger = self.get_logger() logger.setLevel(logging.INFO) # Make sure we have all the required args. check_online_backup_args(logger, credopts, server, targetdir) delete_old_dns = not keep_dns_realm new_dns_realm = new_dns_realm.lower() new_domain_name = new_domain_name.upper() new_base_dn = samba.dn_from_dns_name(new_dns_realm) logger.info("New realm for backed up domain: %s" % new_dns_realm) logger.info("New base DN for backed up domain: %s" % new_base_dn) logger.info("New domain NetBIOS name: %s" % new_domain_name) tmpdir = tempfile.mkdtemp(dir=targetdir) # Clone and rename the remote server lp = sambaopts.get_loadparm() creds = credopts.get_credentials(lp) ctx = DCCloneAndRenameContext(new_base_dn, new_domain_name, new_dns_realm, logger=logger, creds=creds, lp=lp, include_secrets=True, dns_backend='SAMBA_INTERNAL', server=server, targetdir=tmpdir) ctx.do_join() # get the paths used for the clone, then drop the old samdb connection del ctx.local_samdb paths = ctx.paths # get a free RID to use as the new DC's SID (when it gets restored) remote_sam = SamDB(url='ldap://' + server, credentials=creds, session_info=system_session(), lp=lp) new_sid = get_sid_for_restore(remote_sam) old_realm = remote_sam.domain_dns_name() # Grab the remote DC's sysvol files and bundle them into a tar file. # Note we end up with 2 sysvol dirs - the original domain's files (that # use the old realm) backed here, as well as default files generated # for the new realm as part of the clone/join. sysvol_tar = os.path.join(tmpdir, 'sysvol.tar.gz') smb_conn = smb.SMB(server, "sysvol", lp=lp, creds=creds) backup_online(smb_conn, sysvol_tar, remote_sam.get_domain_sid()) # connect to the local DB (making sure we use the new/renamed config) lp.load(paths.smbconf) samdb = SamDB(url=paths.samdb, session_info=system_session(), lp=lp) # Edit the cloned sam.ldb to mark it as a backup time_str = get_timestamp() add_backup_marker(samdb, "backupDate", time_str) add_backup_marker(samdb, "sidForRestore", new_sid) add_backup_marker(samdb, "backupRename", old_realm) # fix up the DNS objects that are using the old dnsRoot value self.update_dns_root(logger, samdb, old_realm, delete_old_dns) # update the netBIOS name and the Partition object for the domain self.rename_domain_partition(logger, samdb, new_domain_name) if delete_old_dns: self.delete_old_dns_zones(logger, samdb, old_realm) logger.info("Fixing DN attributes after rename...") self.fix_old_dn_attributes(samdb) # Add everything in the tmpdir to the backup tar file backup_file = backup_filepath(targetdir, new_dns_realm, time_str) create_backup_tar(logger, tmpdir, backup_file) shutil.rmtree(tmpdir)
class PassWordHashTests(TestCase): def setUp(self): self.lp = samba.tests.env_loadparm() super(PassWordHashTests, self).setUp() def set_store_cleartext(self, cleartext): # get the current pwdProperties pwdProperties = self.ldb.get_pwdProperties() # update the clear-text properties flag props = int(pwdProperties) if cleartext: props |= DOMAIN_PASSWORD_STORE_CLEARTEXT else: props &= ~DOMAIN_PASSWORD_STORE_CLEARTEXT self.ldb.set_pwdProperties(str(props)) # Add a user to ldb, this will exercise the password_hash code # and calculate the appropriate supplemental credentials def add_user(self, options=None, clear_text=False, ldb=None): # set any needed options if options is not None: for (option, value) in options: self.lp.set(option, value) if ldb is None: self.creds = Credentials() self.session = system_session() self.creds.guess(self.lp) self.session = system_session() self.ldb = SamDB(session_info=self.session, credentials=self.creds, lp=self.lp) else: self.ldb = ldb res = self.ldb.search(base=self.ldb.get_config_basedn(), expression="ncName=%s" % self.ldb.get_default_basedn(), attrs=["nETBIOSName"]) self.netbios_domain = res[0]["nETBIOSName"][0] self.dns_domain = self.ldb.domain_dns_name() # Gets back the basedn base_dn = self.ldb.domain_dn() # Gets back the configuration basedn configuration_dn = self.ldb.get_config_basedn().get_linearized() # permit password changes during this test PasswordCommon.allow_password_changes(self, self.ldb) self.base_dn = self.ldb.domain_dn() account_control = 0 if clear_text: # Restore the current domain setting on exit. pwdProperties = self.ldb.get_pwdProperties() self.addCleanup(self.ldb.set_pwdProperties, pwdProperties) # Update the domain setting self.set_store_cleartext(clear_text) account_control |= UF_ENCRYPTED_TEXT_PASSWORD_ALLOWED # (Re)adds the test user USER_NAME with password USER_PASS # and userPrincipalName UPN delete_force(self.ldb, "cn=" + USER_NAME + ",cn=users," + self.base_dn) self.ldb.add({ "dn": "cn=" + USER_NAME + ",cn=users," + self.base_dn, "objectclass": "user", "sAMAccountName": USER_NAME, "userPassword": USER_PASS, "userPrincipalName": UPN, "userAccountControl": str(account_control) }) # Get the supplemental credentials for the user under test def get_supplemental_creds(self): base = "cn=" + USER_NAME + ",cn=users," + self.base_dn res = self.ldb.search(scope=ldb.SCOPE_BASE, base=base, attrs=["supplementalCredentials"]) self.assertIs(True, len(res) > 0) obj = res[0] sc_blob = obj["supplementalCredentials"][0] sc = ndr_unpack(drsblobs.supplementalCredentialsBlob, sc_blob) return sc # Calculate and validate a Wdigest value def check_digest(self, user, realm, password, digest): expected = calc_digest(user, realm, password) actual = binascii.hexlify(bytearray(digest)) error = "Digest expected[%s], actual[%s], " \ "user[%s], realm[%s], pass[%s]" % \ (expected, actual, user, realm, password) self.assertEquals(expected, actual, error) # Check all of the 29 expected WDigest values # def check_wdigests(self, digests): self.assertEquals(29, digests.num_hashes) # Using the n-1 pattern in the array indexes to make it easier # to check the tests against the spec and the samba-tool user tests. self.check_digest(USER_NAME, self.netbios_domain, USER_PASS, digests.hashes[1-1].hash) self.check_digest(USER_NAME.lower(), self.netbios_domain.lower(), USER_PASS, digests.hashes[2-1].hash) self.check_digest(USER_NAME.upper(), self.netbios_domain.upper(), USER_PASS, digests.hashes[3-1].hash) self.check_digest(USER_NAME, self.netbios_domain.upper(), USER_PASS, digests.hashes[4-1].hash) self.check_digest(USER_NAME, self.netbios_domain.lower(), USER_PASS, digests.hashes[5-1].hash) self.check_digest(USER_NAME.upper(), self.netbios_domain.lower(), USER_PASS, digests.hashes[6-1].hash) self.check_digest(USER_NAME.lower(), self.netbios_domain.upper(), USER_PASS, digests.hashes[7-1].hash) self.check_digest(USER_NAME, self.dns_domain, USER_PASS, digests.hashes[8-1].hash) self.check_digest(USER_NAME.lower(), self.dns_domain.lower(), USER_PASS, digests.hashes[9-1].hash) self.check_digest(USER_NAME.upper(), self.dns_domain.upper(), USER_PASS, digests.hashes[10-1].hash) self.check_digest(USER_NAME, self.dns_domain.upper(), USER_PASS, digests.hashes[11-1].hash) self.check_digest(USER_NAME, self.dns_domain.lower(), USER_PASS, digests.hashes[12-1].hash) self.check_digest(USER_NAME.upper(), self.dns_domain.lower(), USER_PASS, digests.hashes[13-1].hash) self.check_digest(USER_NAME.lower(), self.dns_domain.upper(), USER_PASS, digests.hashes[14-1].hash) self.check_digest(UPN, "", USER_PASS, digests.hashes[15-1].hash) self.check_digest(UPN.lower(), "", USER_PASS, digests.hashes[16-1].hash) self.check_digest(UPN.upper(), "", USER_PASS, digests.hashes[17-1].hash) name = "%s\\%s" % (self.netbios_domain, USER_NAME) self.check_digest(name, "", USER_PASS, digests.hashes[18-1].hash) name = "%s\\%s" % (self.netbios_domain.lower(), USER_NAME.lower()) self.check_digest(name, "", USER_PASS, digests.hashes[19-1].hash) name = "%s\\%s" % (self.netbios_domain.upper(), USER_NAME.upper()) self.check_digest(name, "", USER_PASS, digests.hashes[20-1].hash) self.check_digest(USER_NAME, "Digest", USER_PASS, digests.hashes[21-1].hash) self.check_digest(USER_NAME.lower(), "Digest", USER_PASS, digests.hashes[22-1].hash) self.check_digest(USER_NAME.upper(), "Digest", USER_PASS, digests.hashes[23-1].hash) self.check_digest(UPN, "Digest", USER_PASS, digests.hashes[24-1].hash) self.check_digest(UPN.lower(), "Digest", USER_PASS, digests.hashes[25-1].hash) self.check_digest(UPN.upper(), "Digest", USER_PASS, digests.hashes[26-1].hash) name = "%s\\%s" % (self.netbios_domain, USER_NAME) self.check_digest(name, "Digest", USER_PASS, digests.hashes[27-1].hash) name = "%s\\%s" % (self.netbios_domain.lower(), USER_NAME.lower()) self.check_digest(name, "Digest", USER_PASS, digests.hashes[28-1].hash) name = "%s\\%s" % (self.netbios_domain.upper(), USER_NAME.upper()) self.check_digest(name, "Digest", USER_PASS, digests.hashes[29-1].hash) def checkUserPassword(self, up, expected): # Check we've received the correct number of hashes self.assertEquals(len(expected), up.num_hashes) i = 0 for (tag, alg, rounds) in expected: self.assertEquals(tag, up.hashes[i].scheme) data = up.hashes[i].value.split("$") # Check we got the expected crypt algorithm self.assertEquals(alg, data[1]) if rounds is None: cmd = "$%s$%s" % (alg, data[2]) else: cmd = "$%s$rounds=%d$%s" % (alg, rounds, data[3]) # Calculate the expected hash value expected = crypt.crypt(USER_PASS, cmd) self.assertEquals(expected, up.hashes[i].value) i += 1 # Check that the correct nt_hash was stored for userPassword def checkNtHash(self, password, nt_hash): creds = Credentials() creds.set_anonymous() creds.set_password(password) expected = creds.get_nt_hash() actual = bytearray(nt_hash) self.assertEquals(expected, actual)
class RodcTests(samba.tests.TestCase): def setUp(self): super(RodcTests, self).setUp() self.samdb = SamDB(HOST, credentials=CREDS, session_info=system_session(LP), lp=LP) self.base_dn = self.samdb.domain_dn() root = self.samdb.search(base='', scope=ldb.SCOPE_BASE, attrs=['dsServiceName']) self.service = root[0]['dsServiceName'][0] self.tag = uuid.uuid4().hex def test_add_replicated_objects(self): for o in ( { 'dn': "ou=%s1,%s" % (self.tag, self.base_dn), "objectclass": "organizationalUnit" }, { 'dn': "cn=%s2,%s" % (self.tag, self.base_dn), "objectclass": "user" }, { 'dn': "cn=%s3,%s" % (self.tag, self.base_dn), "objectclass": "group" }, { 'dn': "cn=%s4,%s" % (self.tag, self.service), "objectclass": "NTDSConnection", 'enabledConnection': 'TRUE', 'fromServer': self.base_dn, 'options': '0' }, ): try: self.samdb.add(o) self.fail("Failed to fail to add %s" % o['dn']) except ldb.LdbError as e: (ecode, emsg) = e.args if ecode != ldb.ERR_REFERRAL: print(emsg) self.fail("Adding %s: ldb error: %s %s, wanted referral" % (o['dn'], ecode, emsg)) else: m = re.search(r'(ldap://[^>]+)>', emsg) if m is None: self.fail("referral seems not to refer to anything") address = m.group(1) try: tmpdb = SamDB(address, credentials=CREDS, session_info=system_session(LP), lp=LP) tmpdb.add(o) tmpdb.delete(o['dn']) except ldb.LdbError as e: self.fail("couldn't modify referred location %s" % address) if address.lower().startswith(self.samdb.domain_dns_name()): self.fail("referral address did not give a specific DC") def test_modify_replicated_attributes(self): # some timestamp ones dn = 'CN=Guest,CN=Users,' + self.base_dn value = 'hallooo' for attr in ['carLicense', 'middleName']: msg = ldb.Message() msg.dn = ldb.Dn(self.samdb, dn) msg[attr] = ldb.MessageElement(value, ldb.FLAG_MOD_REPLACE, attr) try: self.samdb.modify(msg) self.fail("Failed to fail to modify %s %s" % (dn, attr)) except ldb.LdbError as e1: (ecode, emsg) = e1.args if ecode != ldb.ERR_REFERRAL: self.fail("Failed to REFER when trying to modify %s %s" % (dn, attr)) else: m = re.search(r'(ldap://[^>]+)>', emsg) if m is None: self.fail("referral seems not to refer to anything") address = m.group(1) try: tmpdb = SamDB(address, credentials=CREDS, session_info=system_session(LP), lp=LP) tmpdb.modify(msg) except ldb.LdbError as e: self.fail("couldn't modify referred location %s" % address) if address.lower().startswith(self.samdb.domain_dns_name()): self.fail("referral address did not give a specific DC") def test_modify_nonreplicated_attributes(self): # some timestamp ones dn = 'CN=Guest,CN=Users,' + self.base_dn value = '123456789' for attr in ['badPwdCount', 'lastLogon', 'lastLogoff']: m = ldb.Message() m.dn = ldb.Dn(self.samdb, dn) m[attr] = ldb.MessageElement(value, ldb.FLAG_MOD_REPLACE, attr) # Windows refers these ones even though they are non-replicated try: self.samdb.modify(m) self.fail("Failed to fail to modify %s %s" % (dn, attr)) except ldb.LdbError as e2: (ecode, emsg) = e2.args if ecode != ldb.ERR_REFERRAL: self.fail("Failed to REFER when trying to modify %s %s" % (dn, attr)) else: m = re.search(r'(ldap://[^>]+)>', emsg) if m is None: self.fail("referral seems not to refer to anything") address = m.group(1) if address.lower().startswith(self.samdb.domain_dns_name()): self.fail("referral address did not give a specific DC") def test_modify_nonreplicated_reps_attributes(self): # some timestamp ones dn = self.base_dn m = ldb.Message() m.dn = ldb.Dn(self.samdb, dn) attr = 'repsFrom' res = self.samdb.search(dn, scope=ldb.SCOPE_BASE, attrs=['repsFrom']) rep = ndr_unpack(drsblobs.repsFromToBlob, res[0]['repsFrom'][0], allow_remaining=True) rep.ctr.result_last_attempt = -1 value = ndr_pack(rep) m[attr] = ldb.MessageElement(value, ldb.FLAG_MOD_REPLACE, attr) try: self.samdb.modify(m) self.fail("Failed to fail to modify %s %s" % (dn, attr)) except ldb.LdbError as e3: (ecode, emsg) = e3.args if ecode != ldb.ERR_REFERRAL: self.fail("Failed to REFER when trying to modify %s %s" % (dn, attr)) else: m = re.search(r'(ldap://[^>]+)>', emsg) if m is None: self.fail("referral seems not to refer to anything") address = m.group(1) if address.lower().startswith(self.samdb.domain_dns_name()): self.fail("referral address did not give a specific DC") def test_delete_special_objects(self): dn = 'CN=Guest,CN=Users,' + self.base_dn try: self.samdb.delete(dn) self.fail("Failed to fail to delete %s" % (dn)) except ldb.LdbError as e4: (ecode, emsg) = e4.args if ecode != ldb.ERR_REFERRAL: print(ecode, emsg) self.fail("Failed to REFER when trying to delete %s" % dn) else: m = re.search(r'(ldap://[^>]+)>', emsg) if m is None: self.fail("referral seems not to refer to anything") address = m.group(1) if address.lower().startswith(self.samdb.domain_dns_name()): self.fail("referral address did not give a specific DC") def test_no_delete_nonexistent_objects(self): dn = 'CN=does-not-exist-%s,CN=Users,%s' % (self.tag, self.base_dn) try: self.samdb.delete(dn) self.fail("Failed to fail to delete %s" % (dn)) except ldb.LdbError as e5: (ecode, emsg) = e5.args if ecode != ldb.ERR_NO_SUCH_OBJECT: print(ecode, emsg) self.fail("Failed to NO_SUCH_OBJECT when trying to delete " "%s (which does not exist)" % dn)