def test_join_records_can_update(self): dc_creds = Credentials() dc_creds.guess(self.join_ctx.lp) dc_creds.set_machine_account(self.join_ctx.lp) self.tkey_trans(creds=dc_creds) p = self.make_name_packet(dns.DNS_OPCODE_UPDATE) q = self.make_name_question(self.join_ctx.dnsdomain, dns.DNS_QTYPE_SOA, dns.DNS_QCLASS_IN) questions = [] questions.append(q) self.finish_name_packet(p, questions) updates = [] # Delete the old expected IPs IPs = samba.interface_ips(self.lp) for IP in IPs[1:]: if ":" in IP: r = dns.res_rec() r.name = self.join_ctx.dnshostname r.rr_type = dns.DNS_QTYPE_AAAA r.rr_class = dns.DNS_QCLASS_NONE r.ttl = 0 r.length = 0xffff rdata = IP else: r = dns.res_rec() r.name = self.join_ctx.dnshostname r.rr_type = dns.DNS_QTYPE_A r.rr_class = dns.DNS_QCLASS_NONE r.ttl = 0 r.length = 0xffff rdata = IP r.rdata = rdata updates.append(r) p.nscount = len(updates) p.nsrecs = updates mac = self.sign_packet(p, self.key_name) (response, response_p) = self.dns_transaction_udp(p, self.server_ip) self.assert_dns_rcode_equals(response, dns.DNS_RCODE_OK) self.verify_packet(response, response_p, mac) p = self.make_name_packet(dns.DNS_OPCODE_QUERY) questions = [] name = self.join_ctx.dnshostname q = self.make_name_question(name, dns.DNS_QTYPE_A, dns.DNS_QCLASS_IN) questions.append(q) self.finish_name_packet(p, questions) (response, response_packet) = self.dns_transaction_tcp(p, host=self.server_ip) self.assert_dns_rcode_equals(response, dns.DNS_RCODE_OK) self.assert_dns_opcode_equals(response, dns.DNS_OPCODE_QUERY) self.assertEquals(response.ancount, 1)
def test_set_named_ccache(self): ccache = self.machine_creds.get_named_ccache(self.lp) creds = Credentials() creds.set_named_ccache(ccache.get_name()) ccache2 = creds.get_named_ccache(self.lp) self.assertEqual(ccache.get_name(), ccache2.get_name())
def _get_smb_connection(self, service='SysVol'): # Connect to SMB using kerberos parm = param.LoadParm() creds = Credentials() creds.set_kerberos_state(MUST_USE_KERBEROS) creds.guess(parm) conn = smb.SMB(self._get_server_name(), service, lp=parm, creds=creds) return conn
def test_install_schemas(self): def setup_path(relpath): return os.path.join(find_setup_dir(), relpath) names = guess_names_from_smbconf(self.lp) creds = Credentials() creds.set_anonymous() self.lp.set("sam database", os.path.join(self.tempdir, "samdb.ldb")) install_schemas(setup_path, names, self.lp, creds)
def _test_netlogon(self, binding, checkFunction): def isLastExpectedMessage(msg): return ( msg["type"] == "Authorization" and msg["Authorization"]["serviceDescription"] == "DCE/RPC" and msg["Authorization"]["authType"] == "schannel" and msg["Authorization"]["transportProtection"] == "SEAL") if binding: binding = "[schannel,%s]" % binding else: binding = "[schannel]" machine_creds = Credentials() machine_creds.guess(self.get_loadparm()) machine_creds.set_secure_channel_type(SEC_CHAN_WKSTA) machine_creds.set_password(self.machinepass) machine_creds.set_username(self.netbios_name + "$") netlogon_conn = netlogon.netlogon("ncalrpc:%s" % binding, self.get_loadparm(), machine_creds) messages = self.waitForMessages(isLastExpectedMessage, netlogon_conn) checkFunction(messages)
def _test_netlogon(self, name, pwd, status, checkFunction): def isLastExpectedMessage(msg): return ( msg["type"] == "Authentication" and msg["Authentication"]["serviceDescription"] == "NETLOGON" and msg["Authentication"]["authDescription"] == "ServerAuthenticate" and msg["Authentication"]["status"] == status) machine_creds = Credentials() machine_creds.guess(self.get_loadparm()) machine_creds.set_secure_channel_type(SEC_CHAN_WKSTA) machine_creds.set_password(pwd) machine_creds.set_username(name + "$") try: netlogon.netlogon("ncalrpc:[schannel]", self.get_loadparm(), machine_creds) self.fail("NTSTATUSError not raised") except NTSTATUSError: pass messages = self.waitForMessages(isLastExpectedMessage) checkFunction(messages)
class LdifImportExportTests(samba.tests.TestCaseInTempDir): def setUp(self): super(LdifImportExportTests, self).setUp() self.lp = LoadParm() self.creds = Credentials() self.creds.guess(self.lp) def remove_files(self, *files): for f in files: assert f.startswith(self.tempdir) os.unlink(f) def test_write_search_url(self): pass def test_ldif_to_samdb(self): dburl = os.path.join(self.tempdir, "ldap") samdb = ldif_import_export.ldif_to_samdb(dburl, self.lp, MULTISITE_LDIF) self.assertIsInstance(samdb, SamDB) dsa = ( "CN=WIN01,CN=Servers,CN=Default-First-Site-Name,CN=Sites," "CN=Configuration,DC=ad,DC=samba,DC=example,DC=com" ) res = samdb.search(ldb.Dn(samdb, "CN=NTDS Settings," + dsa), scope=ldb.SCOPE_BASE, attrs=["objectGUID"]) ntds_guid = misc.GUID(samdb.get_ntds_GUID()) self.assertEqual(misc.GUID(res[0]["objectGUID"][0]), ntds_guid) service_name_res = samdb.search(base="", scope=ldb.SCOPE_BASE, attrs=["dsServiceName"]) dn = ldb.Dn(samdb, service_name_res[0]["dsServiceName"][0]) self.assertEqual(dn, ldb.Dn(samdb, "CN=NTDS Settings," + dsa)) self.remove_files(dburl) def test_ldif_to_samdb_forced_local_dsa(self): for dsa, site in MULTISITE_LDIF_DSAS: dburl = os.path.join(self.tempdir, "ldif-to-samba-forced-local-dsa" "-%s" % dsa) samdb = ldif_import_export.ldif_to_samdb(dburl, self.lp, MULTISITE_LDIF, forced_local_dsa=dsa) self.assertIsInstance(samdb, SamDB) self.assertEqual(samdb.server_site_name(), site) res = samdb.search(ldb.Dn(samdb, "CN=NTDS Settings," + dsa), scope=ldb.SCOPE_BASE, attrs=["objectGUID"]) ntds_guid = misc.GUID(samdb.get_ntds_GUID()) self.assertEqual(misc.GUID(res[0]["objectGUID"][0]), ntds_guid) service_name_res = samdb.search(base="", scope=ldb.SCOPE_BASE, attrs=["dsServiceName"]) dn = ldb.Dn(samdb, service_name_res[0]["dsServiceName"][0]) self.assertEqual(dn, ldb.Dn(samdb, "CN=NTDS Settings," + dsa)) self.remove_files(dburl) def samdb_to_ldif_file(self): # samdb_to_ldif_file(samdb, dburl, lp, creds, ldif_file): pass
def _load_samba_environment(): """Load the samba configuration vars from smb.conf and the sam.db.""" params = samba.param.LoadParm() params.load_default() netbiosname = params.get("netbios name") hostname = netbiosname.lower() dnsdomain = params.get("realm") dnsdomain = dnsdomain.lower() creds = Credentials() creds.guess(params) creds.set_machine_account(params) samdb_url = params.get('dcerpc_mapiproxy:samdb_url') if samdb_url is None: samdb_url = params.samdb_url() samdb_ldb = SamDBWrapper(url=samdb_url, session_info=system_session(), credentials=creds, lp=params) domaindn = samdb_ldb.domain_dn() rootdn = domaindn configdn = "CN=Configuration," + rootdn # FIXME: Hardcoded strings, those should be queried to LDB, just like # openchange.provision.guess_names_from_smbconf does. firstorg = FIRST_ORGANIZATION firstou = FIRST_ORGANIZATION_UNIT username_mail = False if params.get("auth:usernames are emails") == 'yes': username_mail = True sam_environ = {"samdb_ldb": samdb_ldb, "private_dir": params.get("private dir"), "domaindn": domaindn, "oc_user_basedn": "CN=%s,CN=%s,CN=%s,%s" \ % (firstou, firstorg, netbiosname, domaindn), "firstorgdn": ("CN=%s,CN=Microsoft Exchange,CN=Services,%s" % (firstorg, configdn)), "legacyserverdn": ("/o=%s/ou=%s/cn=Configuration/cn=Servers" "/cn=%s" % (firstorg, firstou, netbiosname)), "hostname": hostname, "dnsdomain": dnsdomain, 'username_mail': username_mail, } # OpenChange dispatcher DB names return sam_environ
def run(): param_samba = { 'basedn' : config.get('samba', 'path'), 'pathsamdb':'%s/sam.ldb' % config.get('samba', 'private'), 'adbase': config.get('samba', 'base') } # SAMDB lp = LoadParm() creds = Credentials() creds.guess(lp) samdb_loc = SamDB(url=param_samba['pathsamdb'], session_info=system_session(),credentials=creds, lp=lp) testpawd = GetPasswordCommand() testpawd.lp = lp passwordattr = config.get('common', 'attr_password') allmail = {} # Search all users for user in samdb_loc.search(base=param_samba['adbase'], expression="(&(objectClass=user)(mail=*))", attrs=["mail","sAMAccountName","pwdLastSet"]): mail = str(user["mail"]) #replace mail if replace_domain in config if config.getboolean('common', 'replace_domain'): mail = mail.split('@')[0] + '@' + config.get('common', 'domain') pwdlastset = user.get('pwdLastSet','') #add mail in all mail allmail[mail] = None if str(pwdlastset) != dict_mail_pwdlastset.get(mail,''): Random.atfork() # Update if password different in dict mail pwdlastset password = testpawd.get_account_attributes(samdb_loc,None,param_samba['basedn'],filter="(sAMAccountName=%s)" % (str(user["sAMAccountName"])),scope=ldb.SCOPE_SUBTREE,attrs=[passwordattr],decrypt=False) if not passwordattr in password: continue password = str(password[passwordattr]) update_password(mail, password, pwdlastset) #delete user found in dict mail pwdlastset but not found in samba listdelete = [] for user in dict_mail_pwdlastset : if not user in allmail: listdelete.append(user) for user in listdelete: del dict_mail_pwdlastset[user] #write new json dict mail password if listdelete: open(filename,'w').write(json.dumps(dict_mail_pwdlastset))
def test_max_update_size(self): """Test GENSEC by doing an exchange with ourselves using GSSAPI against a KDC""" """Start up a client and server GENSEC instance to test things with""" self.gensec_client = gensec.Security.start_client(self.settings) self.gensec_client.set_credentials(self.get_credentials()) self.gensec_client.want_feature(gensec.FEATURE_SIGN) self.gensec_client.set_max_update_size(5) self.gensec_client.start_mech_by_name("spnego") self.gensec_server = gensec.Security.start_server( settings=self.settings, auth_context=auth.AuthContext(lp_ctx=self.lp_ctx) ) creds = Credentials() creds.guess(self.lp_ctx) creds.set_machine_account(self.lp_ctx) self.gensec_server.set_credentials(creds) self.gensec_server.want_feature(gensec.FEATURE_SIGN) self.gensec_server.set_max_update_size(5) self.gensec_server.start_mech_by_name("spnego") client_finished = False server_finished = False server_to_client = "" """Run the actual call loop""" i = 0 while not client_finished or not server_finished: i += 1 if not client_finished: print("running client gensec_update: %d: %r" % (len(server_to_client), server_to_client)) (client_finished, client_to_server) = self.gensec_client.update(server_to_client) if not server_finished: print("running server gensec_update: %d: %r" % (len(client_to_server), client_to_server)) (server_finished, server_to_client) = self.gensec_server.update(client_to_server) """Here we expect a lot more than the typical 1 or 2 roundtrips""" self.assertTrue(i > 10) session_info = self.gensec_server.session_info() test_string = "Hello Server" test_wrapped = self.gensec_client.wrap(test_string) test_unwrapped = self.gensec_server.unwrap(test_wrapped) self.assertEqual(test_string, test_unwrapped) test_string = "Hello Client" test_wrapped = self.gensec_server.wrap(test_string) test_unwrapped = self.gensec_client.unwrap(test_wrapped) self.assertEqual(test_string, test_unwrapped) client_session_key = self.gensec_client.session_key() server_session_key = self.gensec_server.session_key() self.assertEqual(client_session_key, server_session_key)
def test_find_key_param(self): paths = get_paths(param, None, smb_conf_path) creds = Credentials() lp = env_loadparm() creds.guess(lp) rootdn = "dc=samba,dc=example,dc=com" ldbs = get_ldbs(paths, creds, system_session(), lp) names = find_provision_key_parameters(ldbs.sam, ldbs.secrets, ldbs.idmap, paths, smb_conf_path, lp) self.assertEquals(names.realm, "SAMBA.EXAMPLE.COM") self.assertEquals(str(names.rootdn).lower(), rootdn.lower()) self.assertNotEquals(names.policyid_dc, None) self.assertNotEquals(names.ntdsguid, "")
def join_replicate(ctx): '''replicate the SAM''' print "Starting replication" ctx.local_samdb.transaction_start() 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 if ctx.RODC: repl_creds = Credentials() repl_creds.guess(ctx.lp) repl_creds.set_kerberos_state(DONT_USE_KERBEROS) repl_creds.set_username(ctx.samname) repl_creds.set_password(ctx.acct_pass) else: repl_creds = ctx.creds binding_options = "seal" if int(ctx.lp.get("log level")) >= 5: binding_options += ",print" repl = drs_utils.drs_Replicate( "ncacn_ip_tcp:%s[%s]" % (ctx.server, binding_options), ctx.lp, repl_creds, ctx.local_samdb) repl.replicate(ctx.schema_dn, source_dsa_invocation_id, destination_dsa_guid, schema=True, rodc=ctx.RODC, replica_flags=ctx.replica_flags) repl.replicate(ctx.config_dn, source_dsa_invocation_id, destination_dsa_guid, rodc=ctx.RODC, replica_flags=ctx.replica_flags) if not ctx.subdomain: repl.replicate(ctx.base_dn, source_dsa_invocation_id, destination_dsa_guid, rodc=ctx.RODC, replica_flags=ctx.domain_replica_flags) if ctx.RODC: repl.replicate(ctx.acct_dn, source_dsa_invocation_id, destination_dsa_guid, exop=drsuapi.DRSUAPI_EXOP_REPL_SECRET, rodc=True) 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: ctx.local_samdb.transaction_cancel() raise else: ctx.local_samdb.transaction_commit()
def test_pac_groups(self): if creds.get_kerberos_state() == DONT_USE_KERBEROS: self.skipTest("Kerberos disabled, skipping PAC test") settings = {} settings["lp_ctx"] = lp settings["target_hostname"] = lp.get("netbios name") gensec_client = gensec.Security.start_client(settings) gensec_client.set_credentials(creds) gensec_client.want_feature(gensec.FEATURE_SEAL) gensec_client.start_mech_by_sasl_name("GSSAPI") auth_context = AuthContext(lp_ctx=lp, ldb=self.ldb, methods=[]) gensec_server = gensec.Security.start_server(settings, auth_context) machine_creds = Credentials() machine_creds.guess(lp) machine_creds.set_machine_account(lp) gensec_server.set_credentials(machine_creds) gensec_server.want_feature(gensec.FEATURE_SEAL) gensec_server.start_mech_by_sasl_name("GSSAPI") client_finished = False server_finished = False server_to_client = "" # Run the actual call loop. while client_finished == False and server_finished == False: if not client_finished: print "running client gensec_update" (client_finished, client_to_server) = gensec_client.update(server_to_client) if not server_finished: print "running server gensec_update" (server_finished, server_to_client) = gensec_server.update(client_to_server) session = gensec_server.session_info() token = session.security_token pac_sids = [] for s in token.sids: pac_sids.append(str(s)) sidset1 = set(pac_sids) sidset2 = set(self.user_sids) if len(sidset1.difference(sidset2)): print("token sids don't match") print("difference : %s" % sidset1.difference(sidset2)) self.fail(msg="calculated groups don't match against user PAC tokenGroups")
def samdb_connect(): """ Open and return a SamDB connection """ with root(): lp = samba.param.LoadParm() lp.load("/etc/samba/smb.conf") creds = Credentials() creds.guess(lp) session = system_session() samdb = SamDB("/var/lib/samba/private/sam.ldb", session_info=session, credentials=creds, lp=lp) return samdb
def setUp(self): super(RodcCmdTestCase, self).setUp() self.lp = samba.param.LoadParm() self.lp.load(os.environ["SMB_CONF_PATH"]) self.creds = Credentials() self.creds.set_username(os.environ["DC_USERNAME"]) self.creds.set_password(os.environ["DC_PASSWORD"]) self.creds.guess(self.lp) self.session = system_session() self.ldb = SamDB("ldap://" + os.environ["DC_SERVER"], session_info=self.session, credentials=self.creds,lp=self.lp) self.base_dn = self.ldb.domain_dn() self.ldb.newuser("sambatool1", "1qazXSW@") self.ldb.newuser("sambatool2", "2wsxCDE#") self.ldb.newuser("sambatool3", "3edcVFR$") self.ldb.newuser("sambatool4", "4rfvBGT%") self.ldb.newuser("sambatool5", "5tjbNHY*") self.ldb.newuser("sambatool6", "6yknMJU*") self.ldb.add_remove_group_members("Allowed RODC Password Replication Group", ["sambatool1", "sambatool2", "sambatool3", "sambatool4", "sambatool5"], add_members_operation=True)
def __init__(self, parser): self.ask_for_password = True self.ipaddress = None self.machine_pass = False optparse.OptionGroup.__init__(self, parser, "Credentials Options") self.add_option("--simple-bind-dn", metavar="DN", action="callback", callback=self._set_simple_bind_dn, type=str, help="DN to use for a simple bind") self.add_option("--password", metavar="PASSWORD", action="callback", help="Password", type=str, callback=self._set_password) self.add_option("-U", "--username", metavar="USERNAME", action="callback", type=str, help="Username", callback=self._parse_username) self.add_option("-W", "--workgroup", metavar="WORKGROUP", action="callback", type=str, help="Workgroup", callback=self._parse_workgroup) self.add_option("-N", "--no-pass", action="callback", help="Don't ask for a password", callback=self._set_no_password) self.add_option("-k", "--kerberos", metavar="KERBEROS", action="callback", type=str, help="Use Kerberos", callback=self._set_kerberos) self.add_option("", "--ipaddress", metavar="IPADDRESS", action="callback", type=str, help="IP address of server", callback=self._set_ipaddress) self.add_option("-P", "--machine-pass", action="callback", help="Use stored machine account password", callback=self._set_machine_pass) self.creds = Credentials()
def create_machine_account(self): self.machine_pass = samba.generate_random_password(32, 32) self.machine_name = MACHINE_NAME self.machine_dn = "cn=%s,%s" % (self.machine_name, self.ldb.domain_dn()) # remove the account if it exists, this will happen if a previous test # run failed delete_force(self.ldb, self.machine_dn) utf16pw = unicode( '"' + self.machine_pass.encode('utf-8') + '"', 'utf-8' ).encode('utf-16-le') self.ldb.add({ "dn": self.machine_dn, "objectclass": "computer", "sAMAccountName": "%s$" % self.machine_name, "userAccountControl": str(UF_WORKSTATION_TRUST_ACCOUNT | UF_PASSWD_NOTREQD), "unicodePwd": utf16pw}) self.machine_creds = Credentials() self.machine_creds.guess(self.get_loadparm()) self.machine_creds.set_secure_channel_type(SEC_CHAN_WKSTA) self.machine_creds.set_kerberos_state(DONT_USE_KERBEROS) self.machine_creds.set_password(self.machine_pass) self.machine_creds.set_username(self.machine_name + "$") self.machine_creds.set_workstation(self.machine_name)
def create_user_account(self): self.user_pass = samba.generate_random_password(32, 32) self.user_name = USER_NAME self.user_dn = "cn=%s,%s" % (self.user_name, self.ldb.domain_dn()) # remove the account if it exists, this will happen if a previous test # run failed delete_force(self.ldb, self.user_dn) utf16pw = unicode( '"' + self.user_pass.encode('utf-8') + '"', 'utf-8' ).encode('utf-16-le') self.ldb.add({ "dn": self.user_dn, "objectclass": "user", "sAMAccountName": "%s" % self.user_name, "userAccountControl": str(UF_NORMAL_ACCOUNT), "unicodePwd": utf16pw}) self.user_creds = Credentials() self.user_creds.guess(self.get_loadparm()) self.user_creds.set_password(self.user_pass) self.user_creds.set_username(self.user_name) self.user_creds.set_workstation(self.machine_name) pass
def setUp(self): super(KCCTests, self).setUp() self.lp = LoadParm() self.creds = Credentials() self.creds.guess(self.lp) self.creds.set_username(os.environ["USERNAME"]) self.creds.set_password(os.environ["PASSWORD"])
def setUp(self): super(LdifUtilTests, self).setUp() self.lp = LoadParm() self.creds = Credentials() self.creds.guess(self.lp) #self.creds.set_machine_account(self.lp) self.tmpdir = mkdtemp()
def test_update(self): """Test GENSEC by doing an exchange with ourselves using GSSAPI against a KDC""" """Start up a client and server GENSEC instance to test things with""" self.gensec_client = gensec.Security.start_client(self.settings) self.gensec_client.set_credentials(self.get_credentials()) self.gensec_client.want_feature(gensec.FEATURE_SEAL) self.gensec_client.start_mech_by_sasl_name("GSSAPI") self.gensec_server = gensec.Security.start_server( settings=self.settings, auth_context=auth.AuthContext(lp_ctx=self.lp_ctx) ) creds = Credentials() creds.guess(self.lp_ctx) creds.set_machine_account(self.lp_ctx) self.gensec_server.set_credentials(creds) self.gensec_server.want_feature(gensec.FEATURE_SEAL) self.gensec_server.start_mech_by_sasl_name("GSSAPI") client_finished = False server_finished = False server_to_client = "" """Run the actual call loop""" while not client_finished and not server_finished: if not client_finished: print("running client gensec_update") (client_finished, client_to_server) = self.gensec_client.update(server_to_client) if not server_finished: print("running server gensec_update") (server_finished, server_to_client) = self.gensec_server.update(client_to_server) session_info = self.gensec_server.session_info() test_string = "Hello Server" test_wrapped = self.gensec_client.wrap(test_string) test_unwrapped = self.gensec_server.unwrap(test_wrapped) self.assertEqual(test_string, test_unwrapped) test_string = "Hello Client" test_wrapped = self.gensec_server.wrap(test_string) test_unwrapped = self.gensec_client.unwrap(test_wrapped) self.assertEqual(test_string, test_unwrapped) client_session_key = self.gensec_client.session_key() server_session_key = self.gensec_server.session_key() self.assertEqual(client_session_key, server_session_key)
class EncryptedSecretsTests(TestCase): def setUp(self): super(EncryptedSecretsTests, self).setUp() self.lp = samba.tests.env_loadparm() 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) def test_encrypted_secrets(self): """Test that secret attributes are stored encrypted on disk""" basedn = self.ldb.domain_dn() backend_filename = "%s.ldb" % basedn.upper() backend_subpath = os.path.join("sam.ldb.d", backend_filename) backend_path = self.lp.private_path(backend_subpath) backenddb = ldb.Ldb("ldb://" + backend_path, flags=ldb.FLG_DONT_CREATE_DB) dn = "CN=Administrator,CN=Users,%s" % basedn res = backenddb.search(scope=ldb.SCOPE_BASE, base=dn, attrs=["unicodePwd"]) self.assertIs(True, len(res) > 0) obj = res[0] blob = obj["unicodePwd"][0] self.assertTrue(len(blob) > 30) # Now verify that the header contains the correct magic value. encrypted = ndr_unpack(drsblobs.EncryptedSecret, blob) magic = 0xca5caded self.assertEquals(magic, encrypted.header.magic) def test_required_features(self): """Test that databases are provisioned with encryptedSecrets as a required feature """ res = self.ldb.search(scope=ldb.SCOPE_BASE, base="@SAMBA_DSDB", attrs=["requiredFeatures"]) self.assertTrue(len(res) > 0) self.assertTrue("requiredFeatures" in res[0]) required_features = res[0]["requiredFeatures"] self.assertTrue("encryptedSecrets" in required_features)
def setUp(self): super(DrsRodcTestCase, self).setUp() self.base_dn = self.ldb_dc1.get_default_basedn() rand = random.randint(1, 10000000) self.ou = "OU=test_drs_rodc%s,%s" % (rand, self.base_dn) self.ldb_dc1.add({ "dn": self.ou, "objectclass": "organizationalUnit" }) self.allowed_group = "CN=Allowed RODC Password Replication Group,CN=Users,%s" % self.base_dn self.site = self.ldb_dc1.server_site_name() self.rodc_name = "TESTRODCDRS%s" % rand self.rodc_pass = "******" self.computer_dn = "CN=%s,OU=Domain Controllers,%s" % (self.rodc_name, self.base_dn) self.rodc_ctx = dc_join(server=self.ldb_dc1.host_dns_name(), creds=self.get_credentials(), lp=self.get_loadparm(), site=self.site, netbios_name=self.rodc_name, targetdir=None, domain=None, machinepass=self.rodc_pass) self._create_rodc(self.rodc_ctx) self.rodc_ctx.create_tmp_samdb() self.tmp_samdb = self.rodc_ctx.tmp_samdb rodc_creds = Credentials() rodc_creds.guess(self.rodc_ctx.lp) rodc_creds.set_username(self.rodc_name+'$') rodc_creds.set_password(self.rodc_pass) self.rodc_creds = rodc_creds (self.drs, self.drs_handle) = self._ds_bind(self.dnsname_dc1) (self.rodc_drs, self.rodc_drs_handle) = self._ds_bind(self.dnsname_dc1, rodc_creds)
def setUp(self): super(DsdbTests, self).setUp() self.lp = samba.param.LoadParm() self.lp.load(os.path.join(os.path.join(self.baseprovpath(), "etc"), "smb.conf")) self.creds = Credentials() self.creds.guess(self.lp) self.session = system_session() self.samdb = SamDB(os.path.join(self.baseprovpath(), "private", "sam.ldb"), session_info=self.session, credentials=self.creds,lp=self.lp)
def __init__(self,username,password): BaseModel.__init__(self,username,password); #if self.isAuthenticate(): self.opts = Options(); #self.creds = self.opts.get_credentials(self.opts.lp) self.creds = Credentials() self.creds.guess(self.opts.lp) self.creds.set_kerberos_state(DONT_USE_KERBEROS) self.session = system_session()
def setUp(self): super(DsdbTests, self).setUp() self.lp = samba.tests.env_loadparm() self.creds = Credentials() self.creds.guess(self.lp) self.session = system_session() self.samdb = SamDB(session_info=self.session, credentials=self.creds, lp=self.lp)
def init(self): from samba.provision import ProvisioningError # we will shortly start slapd with ldapi for final provisioning. first # check with ldapsearch -> rootDSE via self.ldap_uri if another # instance of slapd is already running try: ldapi_db = Ldb(self.ldap_uri) ldapi_db.search(base="", scope=SCOPE_BASE, expression="(objectClass=OpenLDAProotDSE)") try: f = open(self.slapd_pid, "r") except IOError as err: if err != errno.ENOENT: raise else: try: p = f.read() finally: f.close() self.logger.info("Check for slapd process with PID: %s and terminate it manually." % p) raise SlapdAlreadyRunning(self.ldap_uri) except LdbError: # XXX: We should never be catching all Ldb errors pass # Try to print helpful messages when the user has not specified the # path to slapd if self.slapd_path is None: raise ProvisioningError("Warning: LDAP-Backend must be setup with path to slapd, e.g. --slapd-path=\"/usr/local/libexec/slapd\"!") if not os.path.exists(self.slapd_path): self.logger.warning("Path (%s) to slapd does not exist!", self.slapd_path) if not os.path.isdir(self.ldapdir): os.makedirs(self.ldapdir, 0o700) # Put the LDIF of the schema into a database so we can search on # it to generate schema-dependent configurations in Fedora DS and # OpenLDAP schemadb_path = os.path.join(self.ldapdir, "schema-tmp.ldb") try: os.unlink(schemadb_path) except OSError: pass self.schema.write_to_tmp_ldb(schemadb_path) self.credentials = Credentials() self.credentials.guess(self.lp) # Kerberos to an ldapi:// backend makes no sense (we also force EXTERNAL) self.credentials.set_kerberos_state(DONT_USE_KERBEROS) self.credentials.set_username("samba-admin") self.credentials.set_password(self.ldapadminpass) self.credentials.set_forced_sasl_mech("EXTERNAL") self.provision()
class DsdbFullScanTests(TestCase): def setUp(self): super(DsdbFullScanTests, self).setUp() self.lp = samba.tests.env_loadparm() self.creds = Credentials() self.creds.guess(self.lp) self.session = system_session() def test_sam_ldb_open_no_full_scan(self): try: self.samdb = SamDB(session_info=self.session, credentials=self.creds, lp=self.lp, options=["disable_full_db_scan_for_self_test:1"]) except LdbError as err: estr = err.args[1] self.fail("sam.ldb required a full scan to start up")
def setUp(self): super(SamDBTestCase, self).setUp() invocationid = str(uuid.uuid4()) domaindn = "DC=COM,DC=EXAMPLE" self.domaindn = domaindn configdn = "CN=Configuration," + domaindn schemadn = "CN=Schema," + configdn domainguid = str(uuid.uuid4()) policyguid = str(uuid.uuid4()) creds = Credentials() creds.set_anonymous() domainsid = security.random_sid() hostguid = str(uuid.uuid4()) path = os.path.join(self.tempdir, "samdb.ldb") session_info = system_session() hostname="foo" domain="EXAMPLE" dnsdomain="example.com" serverrole="domain controller" smbconf = os.path.join(self.tempdir, "smb.conf") make_smbconf(smbconf, self.setup_path, hostname, domain, dnsdomain, serverrole, self.tempdir) self.lp = param.LoadParm() self.lp.load(smbconf) names = guess_names(lp=self.lp, hostname=hostname, domain=domain, dnsdomain=dnsdomain, serverrole=serverrole, domaindn=self.domaindn, configdn=configdn, schemadn=schemadn) setup_templatesdb(os.path.join(self.tempdir, "templates.ldb"), self.setup_path, session_info=session_info, credentials=creds, lp=self.lp) self.samdb = setup_samdb(path, self.setup_path, session_info, creds, self.lp, names, lambda x: None, domainsid, "# no aci", domainguid, policyguid, False, "secret", "secret", "secret", invocationid, "secret", "domain controller")
def credenciales(username, password, parametros): """ Más que nada, encapsulo un par de líneas sobre el trabajo con Credentials() Rompe un poco la idea de inyección, pero así las cosas """ cred = Credentials() dominio = parametros.get('workgroup') cred.set_username(username) cred.set_password(password) cred.set_domain(dominio) # TODO: ¿Este tiene algún efecto? cred.set_workstation("") return cred
def test_pac_groups(self): if creds.get_kerberos_state() == DONT_USE_KERBEROS: self.skipTest("Kerberos disabled, skipping PAC test") settings = {} settings["lp_ctx"] = lp settings["target_hostname"] = lp.get("netbios name") gensec_client = gensec.Security.start_client(settings) gensec_client.set_credentials(creds) gensec_client.want_feature(gensec.FEATURE_SEAL) gensec_client.start_mech_by_sasl_name("GSSAPI") auth_context = AuthContext(lp_ctx=lp, ldb=self.ldb, methods=[]) gensec_server = gensec.Security.start_server(settings, auth_context) machine_creds = Credentials() machine_creds.guess(lp) machine_creds.set_machine_account(lp) gensec_server.set_credentials(machine_creds) gensec_server.want_feature(gensec.FEATURE_SEAL) gensec_server.start_mech_by_sasl_name("GSSAPI") client_finished = False server_finished = False server_to_client = "" # Run the actual call loop. while client_finished == False and server_finished == False: if not client_finished: print("running client gensec_update") (client_finished, client_to_server) = gensec_client.update(server_to_client) if not server_finished: print("running server gensec_update") (server_finished, server_to_client) = gensec_server.update(client_to_server) session = gensec_server.session_info() token = session.security_token pac_sids = [] for s in token.sids: pac_sids.append(str(s)) sidset1 = set(pac_sids) sidset2 = set(self.user_sids) if len(sidset1.difference(sidset2)): print("token sids don't match") print("difference : %s" % sidset1.difference(sidset2)) self.fail( msg="calculated groups don't match against user PAC tokenGroups" )
def setUp(self): super(AuthLogTestsSamLogon, self).setUp() self.lp = samba.tests.env_loadparm() self.creds = Credentials() self.session = system_session() self.ldb = SamDB(session_info=self.session, credentials=self.creds, lp=self.lp) self.domain = os.environ["DOMAIN"] self.netbios_name = "SamLogonTest" self.machinepass = "******" self.remoteAddress = "/root/ncalrpc_as_system" self.base_dn = self.ldb.domain_dn() self.samlogon_dn = ("cn=%s,cn=users,%s" % (self.netbios_name, self.base_dn))
def get_ad_binddn_from_name(base, server, username, password): lp = LoadParm() creds = Credentials() creds.guess(lp) creds.set_username(username) creds.set_password(password) binddn = 'cn=%s,cn=users,%s' % (ldap.dn.escape_dn_chars(username), base) try: samdb = SamDB(url='ldap://%s' % server, session_info=system_session(), credentials=creds, lp=lp) res = samdb.search( base, scope=ldb.SCOPE_SUBTREE, expression=ldap.filter.filter_format('(samAccountName=%s)', [username, ]), attrs=['samaccountname']) if res.count == 1: binddn = res.msgs[0].get('dn', idx=0).extended_str() except ldb.LdbError as ex: MODULE.warn('get_dn_from_name() could not get binddn for user %s: %s' % (username, ex)) return binddn
def get_dns_zones(): request_filter = dnsserver.DNS_ZONE_REQUEST_PRIMARY server = '127.0.0.1' binding_str = 'ncacn_ip_tcp:%s[sign]' % server cred_data = open('/vapour/dnsquery').read().split(':') creds = Credentials() creds.guess(lp) creds.set_username(cred_data[0]) creds.set_password(cred_data[1].rstrip()) dns_conn = dnsserver.dnsserver(binding_str, lp, creds) client_version = dnsserver.DNS_CLIENT_VERSION_LONGHORN typeid, res = dns_conn.DnssrvComplexOperation2( client_version, 0, server, None, 'EnumZones', dnsserver.DNSSRV_TYPEID_DWORD, request_filter) return dict(res)
def test_max_update_size(self): """Test GENSEC by doing an exchange with ourselves using GSSAPI against a KDC""" """Start up a client and server GENSEC instance to test things with""" self.gensec_client = gensec.Security.start_client(self.settings) self.gensec_client.set_credentials(self.get_credentials()) self.gensec_client.want_feature(gensec.FEATURE_SIGN) self.gensec_client.set_max_update_size(5) self.gensec_client.start_mech_by_name("spnego") self.gensec_server = gensec.Security.start_server(settings=self.settings, auth_context=auth.AuthContext(lp_ctx=self.lp_ctx)) creds = Credentials() creds.guess(self.lp_ctx) creds.set_machine_account(self.lp_ctx) self.gensec_server.set_credentials(creds) self.gensec_server.want_feature(gensec.FEATURE_SIGN) self.gensec_server.set_max_update_size(5) self.gensec_server.start_mech_by_name("spnego") client_finished = False server_finished = False server_to_client = b"" """Run the actual call loop""" i = 0 while not client_finished or not server_finished: i += 1 if not client_finished: print("running client gensec_update: %d: %r" % (len(server_to_client), server_to_client)) (client_finished, client_to_server) = self.gensec_client.update(server_to_client) if not server_finished: print("running server gensec_update: %d: %r" % (len(client_to_server), client_to_server)) (server_finished, server_to_client) = self.gensec_server.update(client_to_server) """Here we expect a lot more than the typical 1 or 2 roundtrips""" self.assertTrue(i > 10) session_info = self.gensec_server.session_info() test_bytes = b"Hello Server" test_wrapped = self.gensec_client.wrap(test_bytes) test_unwrapped = self.gensec_server.unwrap(test_wrapped) self.assertEqual(test_bytes, test_unwrapped) test_bytes = b"Hello Client" test_wrapped = self.gensec_server.wrap(test_bytes) test_unwrapped = self.gensec_client.unwrap(test_wrapped) self.assertEqual(test_bytes, test_unwrapped) client_session_key = self.gensec_client.session_key() server_session_key = self.gensec_server.session_key() self.assertEqual(client_session_key, server_session_key)
def test_lsa_LookupNames4_multiple_conns(self): """ Test by going back and forward between real DB lookups name->sid->name to ensure the sam.ldb handle is fine once shared """ machine_creds = Credentials() machine_creds.guess(self.lp) machine_creds.set_machine_account() c_normal = lsa.lsarpc( "ncacn_np:%s[seal]" % self.server, self.lp, machine_creds) username, domain = c_normal.GetUserName(None, None, None) c = lsa.lsarpc( "ncacn_ip_tcp:%s[schannel,seal]" % self.server, self.lp, machine_creds) sids = lsa.TransSidArray3() names = [username] level = lsa.LSA_LOOKUP_NAMES_ALL count = 0 lookup_options = lsa.LSA_LOOKUP_OPTION_SEARCH_ISOLATED_NAMES client_revision = lsa.LSA_CLIENT_REVISION_2 (domains, sids, count) = c.LookupNames4(names, sids, level, count, lookup_options, client_revision) c = lsa.lsarpc( "ncacn_ip_tcp:%s[schannel,seal]" % self.server, self.lp, machine_creds) sids = lsa.TransSidArray3() names = [username] level = lsa.LSA_LOOKUP_NAMES_ALL count = 0 lookup_options = lsa.LSA_LOOKUP_OPTION_SEARCH_ISOLATED_NAMES client_revision = lsa.LSA_CLIENT_REVISION_2 (domains, sids, count) = c.LookupNames4(names, sids, level, count, lookup_options, client_revision)
def add_user(self, hashes=""): self.lp = samba.tests.env_loadparm() # set the extra hashes to be calculated self.lp.set(HASH_OPTION, hashes) self.creds = Credentials() self.session = system_session() self.ldb = SamDB( session_info=self.session, credentials=self.creds, lp=self.lp) password = self.random_password() self.runsubcmd("user", "create", USER_NAME, password)
def test_lsa_LookupSids3_multiple_conns(self): machine_creds = Credentials() machine_creds.guess(self.lp) machine_creds.set_machine_account() c = lsa.lsarpc( "ncacn_ip_tcp:%s[schannel,seal]" % self.server, self.lp, machine_creds) sids = lsa.SidArray() sid = lsa.SidPtr() # Need a set x = dom_sid("S-1-5-7") sid.sid = x sids.sids = [sid] sids.num_sids = 1 names = lsa.TransNameArray2() level = lsa.LSA_LOOKUP_NAMES_ALL count = 0 lookup_options = lsa.LSA_LOOKUP_OPTION_SEARCH_ISOLATED_NAMES client_revision = lsa.LSA_CLIENT_REVISION_2 # We want to run LookupSids3, and then again on a new # connection to show that we don't have an issue with the DB # being tied to the wrong connection. (domains, names, count) = c.LookupSids3(sids, names, level, count, lookup_options, client_revision) self.assertEqual(count, 1) self.assertEqual(names.count, 1) self.assertEqual(names.names[0].name.string, "ANONYMOUS LOGON") c = lsa.lsarpc( "ncacn_ip_tcp:%s[schannel,seal]" % self.server, self.lp, machine_creds) (domains, names, count) = c.LookupSids3(sids, names, level, count, lookup_options, client_revision) self.assertEqual(count, 1) self.assertEqual(names.count, 1) self.assertEqual(names.names[0].name.string, "ANONYMOUS LOGON")
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
def test_gp_daily_scripts(self): local_path = self.lp.cache_path('gpo_cache') guid = '{31B2F340-016D-11D2-945F-00C04FB984F9}' reg_pol = os.path.join(local_path, policies, guid, 'MACHINE/REGISTRY.POL') logger = logging.getLogger('gpo_tests') cache_dir = self.lp.get('cache directory') store = GPOStorage(os.path.join(cache_dir, 'gpo.tdb')) machine_creds = Credentials() machine_creds.guess(self.lp) machine_creds.set_machine_account() # Initialize the group policy extension ext = gp_scripts_ext(logger, self.lp, machine_creds, store) ads = gpo.ADS_STRUCT(self.server, self.lp, machine_creds) if ads.connect(): gpos = ads.get_gpo_list(machine_creds.get_username()) # Stage the Registry.pol file with test data stage = preg.file() e = preg.entry() e.keyname = b'Software\\Policies\\Samba\\Unix Settings\\Daily Scripts' e.valuename = b'Software\\Policies\\Samba\\Unix Settings' e.type = 1 e.data = b'echo hello world' stage.num_entries = 1 stage.entries = [e] ret = stage_file(reg_pol, ndr_pack(stage)) self.assertTrue(ret, 'Could not create the target %s' % reg_pol) # Process all gpos, with temp output directory with TemporaryDirectory() as dname: ext.process_group_policy([], gpos, dname) scripts = os.listdir(dname) self.assertEquals(len(scripts), 1, 'The daily script was not created') out, _ = Popen([os.path.join(dname, scripts[0])], stdout=PIPE).communicate() self.assertIn(b'hello world', out, 'Daily script execution failed') # Unstage the Registry.pol file unstage_file(reg_pol)
def test_gp_sudoers(self): local_path = self.lp.cache_path('gpo_cache') guid = '{31B2F340-016D-11D2-945F-00C04FB984F9}' reg_pol = os.path.join(local_path, policies, guid, 'MACHINE/REGISTRY.POL') logger = logging.getLogger('gpo_tests') cache_dir = self.lp.get('cache directory') store = GPOStorage(os.path.join(cache_dir, 'gpo.tdb')) machine_creds = Credentials() machine_creds.guess(self.lp) machine_creds.set_machine_account() # Initialize the group policy extension ext = gp_sudoers_ext(logger, self.lp, machine_creds, store) ads = gpo.ADS_STRUCT(self.server, self.lp, machine_creds) if ads.connect(): gpos = ads.get_gpo_list(machine_creds.get_username()) # Stage the Registry.pol file with test data stage = preg.file() e = preg.entry() e.keyname = b'Software\\Policies\\Samba\\Unix Settings\\Sudo Rights' e.valuename = b'Software\\Policies\\Samba\\Unix Settings' e.type = 1 e.data = b'fakeu ALL=(ALL) NOPASSWD: ALL' stage.num_entries = 1 stage.entries = [e] ret = stage_file(reg_pol, ndr_pack(stage)) self.assertTrue(ret, 'Could not create the target %s' % reg_pol) # Process all gpos, with temp output directory with TemporaryDirectory() as dname: ext.process_group_policy([], gpos, dname) sudoers = os.listdir(dname) self.assertEquals(len(sudoers), 1, 'The sudoer file was not created') self.assertIn(e.data, open(os.path.join(dname, sudoers[0]), 'r').read(), 'The sudoers entry was not applied') # Unstage the Registry.pol file unstage_file(reg_pol)
def _get_smb_connection(self, service='SysVol'): # Create options like if we were using command line parser = optparse.OptionParser() sambaopts = options.SambaOptions(parser) # Samba options parm = sambaopts.get_loadparm() s3_lp = s3param.get_context() s3_lp.load(parm.configfile) # Build credentials from credential options creds = Credentials() # Credentials need username and realm to be not empty strings to work creds.set_username('NOTEMPTY') creds.set_realm('NOTEMPTY') # Connect to SMB using kerberos creds.set_kerberos_state(MUST_USE_KERBEROS) # Create connection conn = libsmb.Conn(self._get_server_name(), service, lp=parm, creds=creds, sign=False) return conn
def setUp(self): super(DrsRodcTestCase, self).setUp() self.base_dn = self.ldb_dc1.get_default_basedn() rand = random.randint(1, 10000000) self.ou = "OU=test_drs_rodc%s,%s" % (rand, self.base_dn) self.ldb_dc1.add({"dn": self.ou, "objectclass": "organizationalUnit"}) self.allowed_group = "CN=Allowed RODC Password Replication Group,CN=Users,%s" % self.base_dn self.site = self.ldb_dc1.server_site_name() self.rodc_name = "TESTRODCDRS%s" % rand self.rodc_pass = "******" self.computer_dn = "CN=%s,OU=Domain Controllers,%s" % (self.rodc_name, self.base_dn) self.rodc_ctx = dc_join(server=self.ldb_dc1.host_dns_name(), creds=self.get_credentials(), lp=self.get_loadparm(), site=self.site, netbios_name=self.rodc_name, targetdir=None, domain=None, machinepass=self.rodc_pass) self._create_rodc(self.rodc_ctx) self.rodc_ctx.create_tmp_samdb() self.tmp_samdb = self.rodc_ctx.tmp_samdb rodc_creds = Credentials() rodc_creds.guess(self.rodc_ctx.lp) rodc_creds.set_username(self.rodc_name + '$') rodc_creds.set_password(self.rodc_pass) self.rodc_creds = rodc_creds (self.drs, self.drs_handle) = self._ds_bind(self.dnsname_dc1) (self.rodc_drs, self.rodc_drs_handle) = self._ds_bind(self.dnsname_dc1, rodc_creds)
def test_update(self): """Test GENSEC by doing an exchange with ourselves using GSSAPI against a KDC""" """Start up a client and server GENSEC instance to test things with""" self.gensec_client = gensec.Security.start_client(self.settings) self.gensec_client.set_credentials(self.get_credentials()) self.gensec_client.want_feature(gensec.FEATURE_SEAL) self.gensec_client.start_mech_by_sasl_name("GSSAPI") self.gensec_server = gensec.Security.start_server( settings=self.settings, auth_context=auth.AuthContext(lp_ctx=self.lp_ctx)) creds = Credentials() creds.guess(self.lp_ctx) creds.set_machine_account(self.lp_ctx) self.gensec_server.set_credentials(creds) self.gensec_server.want_feature(gensec.FEATURE_SEAL) self.gensec_server.start_mech_by_sasl_name("GSSAPI") client_finished = False server_finished = False server_to_client = b"" """Run the actual call loop""" while not client_finished and not server_finished: if not client_finished: print("running client gensec_update") (client_finished, client_to_server ) = self.gensec_client.update(server_to_client) if not server_finished: print("running server gensec_update") (server_finished, server_to_client ) = self.gensec_server.update(client_to_server) session_info = self.gensec_server.session_info() test_bytes = b"Hello Server" test_wrapped = self.gensec_client.wrap(test_bytes) test_unwrapped = self.gensec_server.unwrap(test_wrapped) self.assertEqual(test_bytes, test_unwrapped) test_bytes = b"Hello Client" test_wrapped = self.gensec_server.wrap(test_bytes) test_unwrapped = self.gensec_client.unwrap(test_wrapped) self.assertEqual(test_bytes, test_unwrapped) client_session_key = self.gensec_client.session_key() server_session_key = self.gensec_server.session_key() self.assertEqual(client_session_key, server_session_key)
class KCCTests(samba.tests.TestCase): def setUp(self): super(KCCTests, self).setUp() self.lp = LoadParm() self.creds = Credentials() self.creds.guess(self.lp) self.creds.set_username(os.environ["USERNAME"]) self.creds.set_password(os.environ["PASSWORD"]) def test_list_dsas(self): my_kcc = kcc.KCC(unix_now, False, False, False, False) my_kcc.load_samdb("ldap://%s" % os.environ["SERVER"], self.lp, self.creds) try: dsas = my_kcc.list_dsas() except kcc.KCCError as e: self.fail("kcc.list_dsas failed with %s" % e) env = os.environ['TEST_ENV'] for expected_dsa in ENV_DSAS[env]: self.assertIn(expected_dsa, dsas) def test_verify(self): """check that the KCC generates graphs that pass its own verify option. This is not a spectacular achievement when there are only a couple of nodes to connect, but it shows something. """ my_kcc = kcc.KCC(unix_now, readonly=True, verify=True, debug=False, dot_file_dir=None) # As this is flapping with errors under python3, we catch # exceptions and turn them into failures.. try: my_kcc.run("ldap://%s" % os.environ["SERVER"], self.lp, self.creds, attempt_live_connections=False) except (samba.kcc.graph_utils.GraphError, kcc.KCCError): import traceback traceback.print_exc() self.fail()
def test_lsa_LookupSids3_multiple(self): machine_creds = Credentials() machine_creds.guess(self.lp) machine_creds.set_machine_account() c = lsa.lsarpc( "ncacn_ip_tcp:%s[schannel,seal]" % self.server, self.lp, machine_creds) sids = lsa.SidArray() sid = lsa.SidPtr() # Need a set x = dom_sid("S-1-5-7") sid.sid = x sids.sids = [sid] sids.num_sids = 1 names = lsa.TransNameArray2() level = lsa.LSA_LOOKUP_NAMES_ALL count = 0 lookup_options = lsa.LSA_LOOKUP_OPTION_SEARCH_ISOLATED_NAMES client_revision = lsa.LSA_CLIENT_REVISION_2 # We want to run LookupSids3 multiple times on the same # connection as we have code to re-use the sam.ldb and we need # to check things work for the second request. (domains, names, count) = c.LookupSids3(sids, names, level, count, lookup_options, client_revision) self.assertEqual(count, 1) self.assertEqual(names.count, 1) self.assertEqual(names.names[0].name.string, "ANONYMOUS LOGON") (domains2, names2, count2) = c.LookupSids3(sids, names, level, count, lookup_options, client_revision) self.assertEqual(count2, 1) self.assertEqual(names2.count, 1) self.assertEqual(names2.names[0].name.string, "ANONYMOUS LOGON") # Just looking for any exceptions in the last couple of loops c.LookupSids3(sids, names, level, count, lookup_options, client_revision) c.LookupSids3(sids, names, level, count, lookup_options, client_revision)
def insta_creds(self, template=None, username=None, userpass=None, kerberos_state=None): if template is None: raise ValueError("you need to supply a Credentials template") if username is not None and userpass is None: raise ValueError( "you cannot set creds username without setting a password") if username is None: assert userpass is None username = template.get_username() userpass = template.get_password() if kerberos_state is None: kerberos_state = template.get_kerberos_state() # get a copy of the global creds or a the passed in creds c = Credentials() c.set_username(username) c.set_password(userpass) c.set_domain(template.get_domain()) c.set_realm(template.get_realm()) c.set_workstation(template.get_workstation()) c.set_gensec_features(c.get_gensec_features() | gensec.FEATURE_SEAL) c.set_kerberos_state(kerberos_state) return c
def get_anon_creds(self): c = Credentials() c.set_anonymous() return c
def get_service_creds(self, allow_missing_password=False): c = Credentials() c.guess() domain = samba.tests.env_get_var_value('DOMAIN') realm = samba.tests.env_get_var_value('REALM') username = samba.tests.env_get_var_value('SERVICE_USERNAME') password = samba.tests.env_get_var_value( 'SERVICE_PASSWORD', allow_missing=allow_missing_password) c.set_domain(domain) c.set_realm(realm) c.set_username(username) if password is not None: c.set_password(password) return c
def get_user_creds(self): c = Credentials() c.guess() domain = samba.tests.env_get_var_value('DOMAIN') realm = samba.tests.env_get_var_value('REALM') username = samba.tests.env_get_var_value('USERNAME') password = samba.tests.env_get_var_value('PASSWORD') c.set_domain(domain) c.set_realm(realm) c.set_username(username) c.set_password(password) return c
from samba import dsdb from samba.samdb import SamDB from samba.param import LoadParm from samba.auth import system_session from samba.credentials import Credentials if __name__ == '__main__': parser = OptionParser(usage='DN2base64Guid.py dn') (options, args) = parser.parse_args() if len(args) != 1: parser.print_help() sys.exit(2) dn = args[0] lp = LoadParm() creds = Credentials() creds.guess(lp) samdb = SamDB(url='/var/lib/samba/private/sam.ldb', session_info=system_session(), credentials=creds, lp=lp) domain_dn = samdb.domain_dn() res = samdb.search(dn, scope=ldb.SCOPE_BASE, attrs=["objectGuid"]) for msg in res: guid = msg.get("objectGuid", idx=0) print base64.encodestring(guid), sys.exit(0)
class SamrTests(RpcInterfaceTestCase): def setUp(self): super(SamrTests, self).setUp() self.conn = samr.samr("ncalrpc:", self.get_loadparm()) self.open_samdb() self.open_domain_handle() # # Open the samba database # def open_samdb(self): self.lp = env_loadparm() self.domain = os.environ["DOMAIN"] self.creds = Credentials() self.creds.guess(self.lp) self.session = system_session() self.samdb = SamDB( session_info=self.session, credentials=self.creds, lp=self.lp) # # Open a SAMR Domain handle def open_domain_handle(self): self.handle = self.conn.Connect2( None, security.SEC_FLAG_MAXIMUM_ALLOWED) self.domain_sid = self.conn.LookupDomain( self.handle, lsa.String(self.domain)) self.domain_handle = self.conn.OpenDomain( self.handle, security.SEC_FLAG_MAXIMUM_ALLOWED, self.domain_sid) # Filter a list of records, removing those that are not part of the # current domain. # def filter_domain(self, unfiltered): def sid(msg): sid = ndr_unpack(security.dom_sid, msg["objectSID"][0]) (x, _) = sid.split() return x dom_sid = security.dom_sid(self.samdb.get_domain_sid()) return [x for x in unfiltered if sid(x) == dom_sid] def test_connect5(self): (level, info, handle) =\ self.conn.Connect5(None, 0, 1, samr.ConnectInfo1()) def test_connect2(self): handle = self.conn.Connect2(None, security.SEC_FLAG_MAXIMUM_ALLOWED) self.assertTrue(handle is not None) def test_EnumDomains(self): handle = self.conn.Connect2(None, security.SEC_FLAG_MAXIMUM_ALLOWED) toArray(*self.conn.EnumDomains(handle, 0, 4294967295)) self.conn.Close(handle) # Create groups based on the id list supplied, the id is used to # form a unique name and description. # # returns a list of the created dn's, which can be passed to delete_dns # to clean up after the test has run. def create_groups(self, ids): dns = [] for i in ids: name = "SAMR_GRP%d" % i dn = "cn=%s,cn=Users,%s" % (name, self.samdb.domain_dn()) delete_force(self.samdb, dn) self.samdb.newgroup(name) dns.append(dn) return dns # Create user accounts based on the id list supplied, the id is used to # form a unique name and description. # # returns a list of the created dn's, which can be passed to delete_dns # to clean up after the test has run. def create_users(self, ids): dns = [] for i in ids: name = "SAMR_USER%d" % i dn = "cn=%s,CN=USERS,%s" % (name, self.samdb.domain_dn()) delete_force(self.samdb, dn) # We only need the user to exist, we don't need a password self.samdb.newuser( name, password=None, setpassword=False, description="Description for " + name, givenname="given%dname" % i, surname="surname%d" % i) dns.append(dn) return dns # Create computer accounts based on the id list supplied, the id is used to # form a unique name and description. # # returns a list of the created dn's, which can be passed to delete_dns # to clean up after the test has run. def create_computers(self, ids): dns = [] for i in ids: name = "SAMR_CMP%d" % i dn = "cn=%s,cn=COMPUTERS,%s" % (name, self.samdb.domain_dn()) delete_force(self.samdb, dn) self.samdb.newcomputer(name, description="Description of " + name) dns.append(dn) return dns # Delete the specified dn's. # # Used to clean up entries created by individual tests. # def delete_dns(self, dns): for dn in dns: delete_force(self.samdb, dn) # Common tests for QueryDisplayInfo # def _test_QueryDisplayInfo( self, level, check_results, select, attributes, add_elements): # # Get the expected results by querying the samdb database directly. # We do this rather than use a list of expected results as this runs # with other tests so we do not have a known fixed list of elements expected = self.samdb.search(expression=select, attrs=attributes) self.assertTrue(len(expected) > 0) # # Perform QueryDisplayInfo with max results greater than the expected # number of results. (ts, rs, actual) = self.conn.QueryDisplayInfo( self.domain_handle, level, 0, 1024, 4294967295) self.assertEquals(len(expected), ts) self.assertEquals(len(expected), rs) check_results(expected, actual.entries) # # Perform QueryDisplayInfo with max results set to the number of # results returned from the first query, should return the same results (ts1, rs1, actual1) = self.conn.QueryDisplayInfo( self.domain_handle, level, 0, rs, 4294967295) self.assertEquals(ts, ts1) self.assertEquals(rs, rs1) check_results(expected, actual1.entries) # # Perform QueryDisplayInfo and get the last two results. # Note: We are assuming there are at least three entries self.assertTrue(ts > 2) (ts2, rs2, actual2) = self.conn.QueryDisplayInfo( self.domain_handle, level, (ts - 2), 2, 4294967295) self.assertEquals(ts, ts2) self.assertEquals(2, rs2) check_results(list(expected)[-2:], actual2.entries) # # Perform QueryDisplayInfo and get the first two results. # Note: We are assuming there are at least three entries self.assertTrue(ts > 2) (ts2, rs2, actual2) = self.conn.QueryDisplayInfo( self.domain_handle, level, 0, 2, 4294967295) self.assertEquals(ts, ts2) self.assertEquals(2, rs2) check_results(list(expected)[:2], actual2.entries) # # Perform QueryDisplayInfo and get two results in the middle of the # list i.e. not the first or the last entry. # Note: We are assuming there are at least four entries self.assertTrue(ts > 3) (ts2, rs2, actual2) = self.conn.QueryDisplayInfo( self.domain_handle, level, 1, 2, 4294967295) self.assertEquals(ts, ts2) self.assertEquals(2, rs2) check_results(list(expected)[1:2], actual2.entries) # # To check that cached values are being returned rather than the # results being re-read from disk we add elements, and request all # but the first result. # dns = add_elements([1000, 1002, 1003, 1004]) # # Perform QueryDisplayInfo and get all but the first result. # We should be using the cached results so the entries we just added # should not be present (ts3, rs3, actual3) = self.conn.QueryDisplayInfo( self.domain_handle, level, 1, 1024, 4294967295) self.assertEquals(ts, ts3) self.assertEquals(len(expected) - 1, rs3) check_results(list(expected)[1:], actual3.entries) # # Perform QueryDisplayInfo and get all the results. # As the start index is zero we should reread the data from disk and # the added entries should be there new = self.samdb.search(expression=select, attrs=attributes) (ts4, rs4, actual4) = self.conn.QueryDisplayInfo( self.domain_handle, level, 0, 1024, 4294967295) self.assertEquals(len(expected) + len(dns), ts4) self.assertEquals(len(expected) + len(dns), rs4) check_results(new, actual4.entries) # Delete the added DN's and query all but the first entry. # This should ensure the cached results are used and that the # missing entry code is triggered. self.delete_dns(dns) (ts5, rs5, actual5) = self.conn.QueryDisplayInfo( self.domain_handle, level, 1, 1024, 4294967295) self.assertEquals(len(expected) + len(dns), ts5) # The deleted results will be filtered from the result set so should # be missing from the returned results. # Note: depending on the GUID order, the first result in the cache may # be a deleted entry, in which case the results will contain all # the expected elements, otherwise the first expected result will # be missing. if rs5 == len(expected): check_results(expected, actual5.entries) elif rs5 == (len(expected) - 1): check_results(list(expected)[1:], actual5.entries) else: self.fail("Incorrect number of entries {0}".format(rs5)) # # Perform QueryDisplayInfo specifying an index past the end of the # available data. # Should return no data. (ts6, rs6, actual6) = self.conn.QueryDisplayInfo( self.domain_handle, level, ts5, 1, 4294967295) self.assertEquals(ts5, ts6) self.assertEquals(0, rs6) self.conn.Close(self.handle) # Test for QueryDisplayInfo, Level 1 # Returns the sAMAccountName, displayName and description for all # the user accounts. # def test_QueryDisplayInfo_level_1(self): def check_results(expected, actual): # Assume the QueryDisplayInfo and ldb.search return their results # in the same order for (e, a) in zip(expected, actual): self.assertTrue(isinstance(a, samr.DispEntryGeneral)) self.assertEquals(str(e["sAMAccountName"]), str(a.account_name)) # The displayName and description are optional. # In the expected results they will be missing, in # samr.DispEntryGeneral the corresponding attribute will have a # length of zero. # if a.full_name.length == 0: self.assertFalse("displayName" in e) else: self.assertEquals(str(e["displayName"]), str(a.full_name)) if a.description.length == 0: self.assertFalse("description" in e) else: self.assertEquals(str(e["description"]), str(a.description)) # Create four user accounts # to ensure that we have the minimum needed for the tests. dns = self.create_users([1, 2, 3, 4]) select = "(&(objectclass=user)(sAMAccountType={0}))".format( ATYPE_NORMAL_ACCOUNT) attributes = ["sAMAccountName", "displayName", "description"] self._test_QueryDisplayInfo( 1, check_results, select, attributes, self.create_users) self.delete_dns(dns) # Test for QueryDisplayInfo, Level 2 # Returns the sAMAccountName and description for all # the computer accounts. # def test_QueryDisplayInfo_level_2(self): def check_results(expected, actual): # Assume the QueryDisplayInfo and ldb.search return their results # in the same order for (e, a) in zip(expected, actual): self.assertTrue(isinstance(a, samr.DispEntryFull)) self.assertEquals(str(e["sAMAccountName"]), str(a.account_name)) # The description is optional. # In the expected results they will be missing, in # samr.DispEntryGeneral the corresponding attribute will have a # length of zero. # if a.description.length == 0: self.assertFalse("description" in e) else: self.assertEquals(str(e["description"]), str(a.description)) # Create four computer accounts # to ensure that we have the minimum needed for the tests. dns = self.create_computers([1, 2, 3, 4]) select = "(&(objectclass=user)(sAMAccountType={0}))".format( ATYPE_WORKSTATION_TRUST) attributes = ["sAMAccountName", "description"] self._test_QueryDisplayInfo( 2, check_results, select, attributes, self.create_computers) self.delete_dns(dns) # Test for QueryDisplayInfo, Level 3 # Returns the sAMAccountName and description for all # the groups. # def test_QueryDisplayInfo_level_3(self): def check_results(expected, actual): # Assume the QueryDisplayInfo and ldb.search return their results # in the same order for (e, a) in zip(expected, actual): self.assertTrue(isinstance(a, samr.DispEntryFullGroup)) self.assertEquals(str(e["sAMAccountName"]), str(a.account_name)) # The description is optional. # In the expected results they will be missing, in # samr.DispEntryGeneral the corresponding attribute will have a # length of zero. # if a.description.length == 0: self.assertFalse("description" in e) else: self.assertEquals(str(e["description"]), str(a.description)) # Create four groups # to ensure that we have the minimum needed for the tests. dns = self.create_groups([1, 2, 3, 4]) select = "(&(|(groupType=%d)(groupType=%d))(objectClass=group))" % ( GTYPE_SECURITY_UNIVERSAL_GROUP, GTYPE_SECURITY_GLOBAL_GROUP) attributes = ["sAMAccountName", "description"] self._test_QueryDisplayInfo( 3, check_results, select, attributes, self.create_groups) self.delete_dns(dns) # Test for QueryDisplayInfo, Level 4 # Returns the sAMAccountName (as an ASCII string) # for all the user accounts. # def test_QueryDisplayInfo_level_4(self): def check_results(expected, actual): # Assume the QueryDisplayInfo and ldb.search return their results # in the same order for (e, a) in zip(expected, actual): self.assertTrue(isinstance(a, samr.DispEntryAscii)) self.assertTrue( isinstance(a.account_name, lsa.AsciiStringLarge)) self.assertEquals( str(e["sAMAccountName"]), str(a.account_name.string)) # Create four user accounts # to ensure that we have the minimum needed for the tests. dns = self.create_users([1, 2, 3, 4]) select = "(&(objectclass=user)(sAMAccountType={0}))".format( ATYPE_NORMAL_ACCOUNT) attributes = ["sAMAccountName", "displayName", "description"] self._test_QueryDisplayInfo( 4, check_results, select, attributes, self.create_users) self.delete_dns(dns) # Test for QueryDisplayInfo, Level 5 # Returns the sAMAccountName (as an ASCII string) # for all the groups. # def test_QueryDisplayInfo_level_5(self): def check_results(expected, actual): # Assume the QueryDisplayInfo and ldb.search return their results # in the same order for (e, a) in zip(expected, actual): self.assertTrue(isinstance(a, samr.DispEntryAscii)) self.assertTrue( isinstance(a.account_name, lsa.AsciiStringLarge)) self.assertEquals( str(e["sAMAccountName"]), str(a.account_name.string)) # Create four groups # to ensure that we have the minimum needed for the tests. dns = self.create_groups([1, 2, 3, 4]) select = "(&(|(groupType=%d)(groupType=%d))(objectClass=group))" % ( GTYPE_SECURITY_UNIVERSAL_GROUP, GTYPE_SECURITY_GLOBAL_GROUP) attributes = ["sAMAccountName", "description"] self._test_QueryDisplayInfo( 5, check_results, select, attributes, self.create_groups) self.delete_dns(dns) def test_EnumDomainGroups(self): def check_results(expected, actual): for (e, a) in zip(expected, actual): self.assertTrue(isinstance(a, samr.SamEntry)) self.assertEquals( str(e["sAMAccountName"]), str(a.name.string)) # Create four groups # to ensure that we have the minimum needed for the tests. dns = self.create_groups([1, 2, 3, 4]) # # Get the expected results by querying the samdb database directly. # We do this rather than use a list of expected results as this runs # with other tests so we do not have a known fixed list of elements select = "(&(|(groupType=%d)(groupType=%d))(objectClass=group))" % ( GTYPE_SECURITY_UNIVERSAL_GROUP, GTYPE_SECURITY_GLOBAL_GROUP) attributes = ["sAMAccountName", "objectSID"] unfiltered = self.samdb.search(expression=select, attrs=attributes) filtered = self.filter_domain(unfiltered) self.assertTrue(len(filtered) > 4) # Sort the expected results by rid expected = sorted(list(filtered), key=rid) # # Perform EnumDomainGroups with max size greater than the expected # number of results. Allow for an extra 10 entries # max_size = calc_max_size(len(expected) + 10) (resume_handle, actual, num_entries) = self.conn.EnumDomainGroups( self.domain_handle, 0, max_size) self.assertEquals(len(expected), num_entries) check_results(expected, actual.entries) # # Perform EnumDomainGroups with size set to so that it contains # 4 entries. # max_size = calc_max_size(4) (resume_handle, actual, num_entries) = self.conn.EnumDomainGroups( self.domain_handle, 0, max_size) self.assertEquals(4, num_entries) check_results(expected[:4], actual.entries) # # Try calling with resume_handle greater than number of entries # Should return no results and a resume handle of 0 max_size = calc_max_size(1) rh = len(expected) self.conn.Close(self.handle) (resume_handle, a, num_entries) = self.conn.EnumDomainGroups( self.domain_handle, rh, max_size) self.assertEquals(0, num_entries) self.assertEquals(0, resume_handle) # # Enumerate through the domain groups one element at a time. # max_size = calc_max_size(1) actual = [] (resume_handle, a, num_entries) = self.conn.EnumDomainGroups( self.domain_handle, 0, max_size) while resume_handle: self.assertEquals(1, num_entries) actual.append(a.entries[0]) (resume_handle, a, num_entries) = self.conn.EnumDomainGroups( self.domain_handle, resume_handle, max_size) if num_entries: actual.append(a.entries[0]) # # Check that the cached results are being returned. # Obtain a new resume_handle and insert new entries into the # into the DB # actual = [] max_size = calc_max_size(1) (resume_handle, a, num_entries) = self.conn.EnumDomainGroups( self.domain_handle, 0, max_size) extra_dns = self.create_groups([1000, 1002, 1003, 1004]) while resume_handle: self.assertEquals(1, num_entries) actual.append(a.entries[0]) (resume_handle, a, num_entries) = self.conn.EnumDomainGroups( self.domain_handle, resume_handle, max_size) if num_entries: actual.append(a.entries[0]) self.assertEquals(len(expected), len(actual)) check_results(expected, actual) # # Perform EnumDomainGroups, we should read the newly added domains # max_size = calc_max_size(len(expected) + len(extra_dns) + 10) (resume_handle, actual, num_entries) = self.conn.EnumDomainGroups( self.domain_handle, 0, max_size) self.assertEquals(len(expected) + len(extra_dns), num_entries) # # Get a new expected result set by querying the database directly unfiltered01 = self.samdb.search(expression=select, attrs=attributes) filtered01 = self.filter_domain(unfiltered01) self.assertTrue(len(filtered01) > len(expected)) # Sort the expected results by rid expected01 = sorted(list(filtered01), key=rid) # # Now check that we read the new entries. # check_results(expected01, actual.entries) # # Check that deleted results are handled correctly. # Obtain a new resume_handle and delete entries from the DB. # actual = [] max_size = calc_max_size(1) (resume_handle, a, num_entries) = self.conn.EnumDomainGroups( self.domain_handle, 0, max_size) self.delete_dns(extra_dns) while resume_handle and num_entries: self.assertEquals(1, num_entries) actual.append(a.entries[0]) (resume_handle, a, num_entries) = self.conn.EnumDomainGroups( self.domain_handle, resume_handle, max_size) if num_entries: actual.append(a.entries[0]) self.assertEquals(len(expected), len(actual)) check_results(expected, actual) self.delete_dns(dns) def test_EnumDomainUsers(self): def check_results(expected, actual): for (e, a) in zip(expected, actual): self.assertTrue(isinstance(a, samr.SamEntry)) self.assertEquals( str(e["sAMAccountName"]), str(a.name.string)) # Create four users # to ensure that we have the minimum needed for the tests. dns = self.create_users([1, 2, 3, 4]) # # Get the expected results by querying the samdb database directly. # We do this rather than use a list of expected results as this runs # with other tests so we do not have a known fixed list of elements select = "(objectClass=user)" attributes = ["sAMAccountName", "objectSID", "userAccountConrol"] unfiltered = self.samdb.search(expression=select, attrs=attributes) filtered = self.filter_domain(unfiltered) self.assertTrue(len(filtered) > 4) # Sort the expected results by rid expected = sorted(list(filtered), key=rid) # # Perform EnumDomainUsers with max_size greater than required for the # expected number of results. We should get all the results. # max_size = calc_max_size(len(expected) + 10) (resume_handle, actual, num_entries) = self.conn.EnumDomainUsers( self.domain_handle, 0, 0, max_size) self.assertEquals(len(expected), num_entries) check_results(expected, actual.entries) # # Perform EnumDomainUsers with size set to so that it contains # 4 entries. max_size = calc_max_size(4) (resume_handle, actual, num_entries) = self.conn.EnumDomainUsers( self.domain_handle, 0, 0, max_size) self.assertEquals(4, num_entries) check_results(expected[:4], actual.entries) # # Try calling with resume_handle greater than number of entries # Should return no results and a resume handle of 0 rh = len(expected) max_size = calc_max_size(1) self.conn.Close(self.handle) (resume_handle, a, num_entries) = self.conn.EnumDomainUsers( self.domain_handle, rh, 0, max_size) self.assertEquals(0, num_entries) self.assertEquals(0, resume_handle) # # Enumerate through the domain users one element at a time. # We should get all the results. # actual = [] max_size = calc_max_size(1) (resume_handle, a, num_entries) = self.conn.EnumDomainUsers( self.domain_handle, 0, 0, max_size) while resume_handle: self.assertEquals(1, num_entries) actual.append(a.entries[0]) (resume_handle, a, num_entries) = self.conn.EnumDomainUsers( self.domain_handle, resume_handle, 0, max_size) if num_entries: actual.append(a.entries[0]) self.assertEquals(len(expected), len(actual)) check_results(expected, actual) # # Check that the cached results are being returned. # Obtain a new resume_handle and insert new entries into the # into the DB. As the entries were added after the results were cached # they should not show up in the returned results. # actual = [] max_size = calc_max_size(1) (resume_handle, a, num_entries) = self.conn.EnumDomainUsers( self.domain_handle, 0, 0, max_size) extra_dns = self.create_users([1000, 1002, 1003, 1004]) while resume_handle: self.assertEquals(1, num_entries) actual.append(a.entries[0]) (resume_handle, a, num_entries) = self.conn.EnumDomainUsers( self.domain_handle, resume_handle, 0, max_size) if num_entries: actual.append(a.entries[0]) self.assertEquals(len(expected), len(actual)) check_results(expected, actual) # # Perform EnumDomainUsers, we should read the newly added groups # As resume_handle is zero, the results will be read from disk. # max_size = calc_max_size(len(expected) + len(extra_dns) + 10) (resume_handle, actual, num_entries) = self.conn.EnumDomainUsers( self.domain_handle, 0, 0, max_size) self.assertEquals(len(expected) + len(extra_dns), num_entries) # # Get a new expected result set by querying the database directly unfiltered01 = self.samdb.search(expression=select, attrs=attributes) filtered01 = self.filter_domain(unfiltered01) self.assertTrue(len(filtered01) > len(expected)) # Sort the expected results by rid expected01 = sorted(list(filtered01), key=rid) # # Now check that we read the new entries. # self.assertEquals(len(expected01), num_entries) check_results(expected01, actual.entries) # # Check that deleted results are handled correctly. # Obtain a new resume_handle and delete entries from the DB. # We will not see the deleted entries in the result set, as details # need to be read from disk. Only the object GUID's are cached. # actual = [] max_size = calc_max_size(1) (resume_handle, a, num_entries) = self.conn.EnumDomainUsers( self.domain_handle, 0, 0, max_size) self.delete_dns(extra_dns) while resume_handle and num_entries: self.assertEquals(1, num_entries) actual.append(a.entries[0]) (resume_handle, a, num_entries) = self.conn.EnumDomainUsers( self.domain_handle, resume_handle, 0, max_size) if num_entries: actual.append(a.entries[0]) self.assertEquals(len(expected), len(actual)) check_results(expected, actual) self.delete_dns(dns) def test_DomGeneralInformation_num_users(self): info = self.conn.QueryDomainInfo( self.domain_handle, DomainGeneralInformation) # # Enumerate through all the domain users and compare the number # returned against QueryDomainInfo they should be the same max_size = calc_max_size(1) (resume_handle, a, num_entries) = self.conn.EnumDomainUsers( self.domain_handle, 0, 0, max_size) count = num_entries while resume_handle: self.assertEquals(1, num_entries) (resume_handle, a, num_entries) = self.conn.EnumDomainUsers( self.domain_handle, resume_handle, 0, max_size) count += num_entries self.assertEquals(count, info.num_users) def test_DomGeneralInformation_num_groups(self): info = self.conn.QueryDomainInfo( self.domain_handle, DomainGeneralInformation) # # Enumerate through all the domain groups and compare the number # returned against QueryDomainInfo they should be the same max_size = calc_max_size(1) (resume_handle, a, num_entries) = self.conn.EnumDomainGroups( self.domain_handle, 0, max_size) count = num_entries while resume_handle: self.assertEquals(1, num_entries) (resume_handle, a, num_entries) = self.conn.EnumDomainGroups( self.domain_handle, resume_handle, max_size) count += num_entries self.assertEquals(count, info.num_groups) def test_DomGeneralInformation_num_aliases(self): info = self.conn.QueryDomainInfo( self.domain_handle, DomainGeneralInformation) # # Enumerate through all the domain aliases and compare the number # returned against QueryDomainInfo they should be the same max_size = calc_max_size(1) (resume_handle, a, num_entries) = self.conn.EnumDomainAliases( self.domain_handle, 0, max_size) count = num_entries while resume_handle: self.assertEquals(1, num_entries) (resume_handle, a, num_entries) = self.conn.EnumDomainAliases( self.domain_handle, resume_handle, max_size) count += num_entries self.assertEquals(count, info.num_aliases)
class PyCredentialsTests(TestCase): def setUp(self): super(PyCredentialsTests, self).setUp() self.server = os.environ["SERVER"] self.domain = os.environ["DOMAIN"] self.host = os.environ["SERVER_IP"] self.lp = self.get_loadparm() self.credentials = self.get_credentials() self.session = system_session() self.ldb = SamDB(url="ldap://%s" % self.host, session_info=self.session, credentials=self.credentials, lp=self.lp) self.create_machine_account() self.create_user_account() def tearDown(self): super(PyCredentialsTests, self).tearDown() delete_force(self.ldb, self.machine_dn) delete_force(self.ldb, self.user_dn) # Until a successful netlogon connection has been established there will # not be a valid authenticator associated with the credentials # and new_client_authenticator should throw a ValueError def test_no_netlogon_connection(self): self.assertRaises(ValueError, self.machine_creds.new_client_authenticator) # Once a netlogon connection has been established, # new_client_authenticator should return a value # def test_have_netlogon_connection(self): c = self.get_netlogon_connection() a = self.machine_creds.new_client_authenticator() self.assertIsNotNone(a) # Get an authenticator and use it on a sequence of operations requiring # an authenticator def test_client_authenticator(self): c = self.get_netlogon_connection() (authenticator, subsequent) = self.get_authenticator(c) self.do_NetrLogonSamLogonWithFlags(c, authenticator, subsequent) (authenticator, subsequent) = self.get_authenticator(c) self.do_NetrLogonGetDomainInfo(c, authenticator, subsequent) (authenticator, subsequent) = self.get_authenticator(c) self.do_NetrLogonGetDomainInfo(c, authenticator, subsequent) (authenticator, subsequent) = self.get_authenticator(c) self.do_NetrLogonGetDomainInfo(c, authenticator, subsequent) # Test Credentials.encrypt_netr_crypt_password # By performing a NetrServerPasswordSet2 # And the logging on using the new password. def test_encrypt_netr_password(self): # Change the password self.do_Netr_ServerPasswordSet2() # Now use the new password to perform an operation self.do_DsrEnumerateDomainTrusts() # Change the current machine account pazssword with a # netr_ServerPasswordSet2 call. def do_Netr_ServerPasswordSet2(self): c = self.get_netlogon_connection() (authenticator, subsequent) = self.get_authenticator(c) PWD_LEN = 32 DATA_LEN = 512 newpass = samba.generate_random_password(PWD_LEN, PWD_LEN) filler = [ord(x) for x in os.urandom(DATA_LEN - PWD_LEN)] pwd = netlogon.netr_CryptPassword() pwd.length = PWD_LEN pwd.data = filler + [ord(x) for x in newpass] self.machine_creds.encrypt_netr_crypt_password(pwd) c.netr_ServerPasswordSet2(self.server, self.machine_creds.get_workstation(), SEC_CHAN_WKSTA, self.machine_name, authenticator, pwd) self.machine_pass = newpass self.machine_creds.set_password(newpass) # Perform a DsrEnumerateDomainTrusts, this provides confirmation that # a netlogon connection has been correctly established def do_DsrEnumerateDomainTrusts(self): c = self.get_netlogon_connection() trusts = c.netr_DsrEnumerateDomainTrusts( self.server, netlogon.NETR_TRUST_FLAG_IN_FOREST | netlogon.NETR_TRUST_FLAG_OUTBOUND | netlogon.NETR_TRUST_FLAG_INBOUND) # Establish sealed schannel netlogon connection over TCP/IP # def get_netlogon_connection(self): return netlogon.netlogon( "ncacn_ip_tcp:%s[schannel,seal]" % self.server, self.lp, self.machine_creds) # # Create the machine account def create_machine_account(self): self.machine_pass = samba.generate_random_password(32, 32) self.machine_name = MACHINE_NAME self.machine_dn = "cn=%s,%s" % (self.machine_name, self.ldb.domain_dn()) # remove the account if it exists, this will happen if a previous test # run failed delete_force(self.ldb, self.machine_dn) utf16pw = unicode('"' + self.machine_pass.encode('utf-8') + '"', 'utf-8').encode('utf-16-le') self.ldb.add({ "dn": self.machine_dn, "objectclass": "computer", "sAMAccountName": "%s$" % self.machine_name, "userAccountControl": str(UF_WORKSTATION_TRUST_ACCOUNT | UF_PASSWD_NOTREQD), "unicodePwd": utf16pw }) self.machine_creds = Credentials() self.machine_creds.guess(self.get_loadparm()) self.machine_creds.set_secure_channel_type(SEC_CHAN_WKSTA) self.machine_creds.set_password(self.machine_pass) self.machine_creds.set_username(self.machine_name + "$") self.machine_creds.set_workstation(self.machine_name) # # Create a test user account def create_user_account(self): self.user_pass = samba.generate_random_password(32, 32) self.user_name = USER_NAME self.user_dn = "cn=%s,%s" % (self.user_name, self.ldb.domain_dn()) # remove the account if it exists, this will happen if a previous test # run failed delete_force(self.ldb, self.user_dn) utf16pw = unicode('"' + self.user_pass.encode('utf-8') + '"', 'utf-8').encode('utf-16-le') self.ldb.add({ "dn": self.user_dn, "objectclass": "user", "sAMAccountName": "%s" % self.user_name, "userAccountControl": str(UF_NORMAL_ACCOUNT), "unicodePwd": utf16pw }) self.user_creds = Credentials() self.user_creds.guess(self.get_loadparm()) self.user_creds.set_password(self.user_pass) self.user_creds.set_username(self.user_name) self.user_creds.set_workstation(self.machine_name) pass # # Get the authenticator from the machine creds. def get_authenticator(self, c): auth = self.machine_creds.new_client_authenticator() current = netr_Authenticator() current.cred.data = [ord(x) for x in auth["credential"]] current.timestamp = auth["timestamp"] subsequent = netr_Authenticator() return (current, subsequent) def do_NetrLogonSamLogonWithFlags(self, c, current, subsequent): logon = samlogon_logon_info(self.domain, self.machine_name, self.user_creds) logon_level = netlogon.NetlogonNetworkTransitiveInformation validation_level = netlogon.NetlogonValidationSamInfo4 netr_flags = 0 c.netr_LogonSamLogonWithFlags(self.server, self.user_creds.get_workstation(), current, subsequent, logon_level, logon, validation_level, netr_flags) def do_NetrLogonGetDomainInfo(self, c, current, subsequent): query = netr_WorkstationInformation() c.netr_LogonGetDomainInfo(self.server, self.user_creds.get_workstation(), current, subsequent, 2, query)
class DsdbTests(TestCase): def setUp(self): super(DsdbTests, self).setUp() self.lp = samba.tests.env_loadparm() self.creds = Credentials() self.creds.guess(self.lp) self.session = system_session() self.samdb = SamDB(session_info=self.session, credentials=self.creds, lp=self.lp) def test_get_oid_from_attrid(self): oid = self.samdb.get_oid_from_attid(591614) self.assertEquals(oid, "1.2.840.113556.1.4.1790") def test_error_replpropertymetadata(self): res = self.samdb.search(expression="cn=Administrator", scope=ldb.SCOPE_SUBTREE, attrs=["replPropertyMetaData"]) repl = ndr_unpack(drsblobs.replPropertyMetaDataBlob, str(res[0]["replPropertyMetaData"])) ctr = repl.ctr for o in ctr.array: # Search for Description if o.attid == 13: old_version = o.version o.version = o.version + 1 replBlob = ndr_pack(repl) msg = ldb.Message() msg.dn = res[0].dn msg["replPropertyMetaData"] = ldb.MessageElement( replBlob, ldb.FLAG_MOD_REPLACE, "replPropertyMetaData") self.assertRaises(ldb.LdbError, self.samdb.modify, msg, ["local_oid:1.3.6.1.4.1.7165.4.3.14:0"]) def test_error_replpropertymetadata_nochange(self): res = self.samdb.search(expression="cn=Administrator", scope=ldb.SCOPE_SUBTREE, attrs=["replPropertyMetaData"]) repl = ndr_unpack(drsblobs.replPropertyMetaDataBlob, str(res[0]["replPropertyMetaData"])) replBlob = ndr_pack(repl) msg = ldb.Message() msg.dn = res[0].dn msg["replPropertyMetaData"] = ldb.MessageElement( replBlob, ldb.FLAG_MOD_REPLACE, "replPropertyMetaData") self.assertRaises(ldb.LdbError, self.samdb.modify, msg, ["local_oid:1.3.6.1.4.1.7165.4.3.14:0"]) def test_error_replpropertymetadata_allow_sort(self): res = self.samdb.search(expression="cn=Administrator", scope=ldb.SCOPE_SUBTREE, attrs=["replPropertyMetaData"]) repl = ndr_unpack(drsblobs.replPropertyMetaDataBlob, str(res[0]["replPropertyMetaData"])) replBlob = ndr_pack(repl) msg = ldb.Message() msg.dn = res[0].dn msg["replPropertyMetaData"] = ldb.MessageElement( replBlob, ldb.FLAG_MOD_REPLACE, "replPropertyMetaData") self.samdb.modify(msg, [ "local_oid:1.3.6.1.4.1.7165.4.3.14:0", "local_oid:1.3.6.1.4.1.7165.4.3.25:0" ]) def test_twoatt_replpropertymetadata(self): res = self.samdb.search(expression="cn=Administrator", scope=ldb.SCOPE_SUBTREE, attrs=["replPropertyMetaData", "uSNChanged"]) repl = ndr_unpack(drsblobs.replPropertyMetaDataBlob, str(res[0]["replPropertyMetaData"])) ctr = repl.ctr for o in ctr.array: # Search for Description if o.attid == 13: old_version = o.version o.version = o.version + 1 o.local_usn = long(str(res[0]["uSNChanged"])) + 1 replBlob = ndr_pack(repl) msg = ldb.Message() msg.dn = res[0].dn msg["replPropertyMetaData"] = ldb.MessageElement( replBlob, ldb.FLAG_MOD_REPLACE, "replPropertyMetaData") msg["description"] = ldb.MessageElement("new val", ldb.FLAG_MOD_REPLACE, "description") self.assertRaises(ldb.LdbError, self.samdb.modify, msg, ["local_oid:1.3.6.1.4.1.7165.4.3.14:0"]) def test_set_replpropertymetadata(self): res = self.samdb.search(expression="cn=Administrator", scope=ldb.SCOPE_SUBTREE, attrs=["replPropertyMetaData", "uSNChanged"]) repl = ndr_unpack(drsblobs.replPropertyMetaDataBlob, str(res[0]["replPropertyMetaData"])) ctr = repl.ctr for o in ctr.array: # Search for Description if o.attid == 13: old_version = o.version o.version = o.version + 1 o.local_usn = long(str(res[0]["uSNChanged"])) + 1 o.originating_usn = long(str(res[0]["uSNChanged"])) + 1 replBlob = ndr_pack(repl) msg = ldb.Message() msg.dn = res[0].dn msg["replPropertyMetaData"] = ldb.MessageElement( replBlob, ldb.FLAG_MOD_REPLACE, "replPropertyMetaData") self.samdb.modify(msg, ["local_oid:1.3.6.1.4.1.7165.4.3.14:0"]) def test_ok_get_attribute_from_attid(self): self.assertEquals(self.samdb.get_attribute_from_attid(13), "description") def test_ko_get_attribute_from_attid(self): self.assertEquals(self.samdb.get_attribute_from_attid(11979), None) def test_get_attribute_replmetadata_version(self): res = self.samdb.search(expression="cn=Administrator", scope=ldb.SCOPE_SUBTREE, attrs=["dn"]) self.assertEquals(len(res), 1) dn = str(res[0].dn) self.assertEqual( self.samdb.get_attribute_replmetadata_version(dn, "unicodePwd"), 1) def test_set_attribute_replmetadata_version(self): res = self.samdb.search(expression="cn=Administrator", scope=ldb.SCOPE_SUBTREE, attrs=["dn"]) self.assertEquals(len(res), 1) dn = str(res[0].dn) version = self.samdb.get_attribute_replmetadata_version( dn, "description") self.samdb.set_attribute_replmetadata_version(dn, "description", version + 2) self.assertEqual( self.samdb.get_attribute_replmetadata_version(dn, "description"), version + 2) def test_db_lock1(self): basedn = self.samdb.get_default_basedn() (r1, w1) = os.pipe() pid = os.fork() if pid == 0: # In the child, close the main DB, re-open just one DB del (self.samdb) gc.collect() self.samdb = SamDB(session_info=self.session, credentials=self.creds, lp=self.lp) self.samdb.transaction_start() dn = "cn=test_db_lock_user,cn=users," + str(basedn) self.samdb.add({ "dn": dn, "objectclass": "user", }) self.samdb.delete(dn) # Obtain a write lock self.samdb.transaction_prepare_commit() os.write(w1, b"prepared") time.sleep(2) # Drop the write lock self.samdb.transaction_cancel() os._exit(0) self.assertEqual(os.read(r1, 8), b"prepared") start = time.time() # We need to hold this iterator open to hold the all-record lock. res = self.samdb.search_iterator() # This should take at least 2 seconds because the transaction # has a write lock on one backend db open # Release the locks for l in res: pass end = time.time() self.assertGreater(end - start, 1.9) (got_pid, status) = os.waitpid(pid, 0) self.assertEqual(got_pid, pid) self.assertTrue(os.WIFEXITED(status)) self.assertEqual(os.WEXITSTATUS(status), 0) def test_db_lock2(self): basedn = self.samdb.get_default_basedn() (r1, w1) = os.pipe() (r2, w2) = os.pipe() pid = os.fork() if pid == 0: # In the child, close the main DB, re-open del (self.samdb) gc.collect() self.samdb = SamDB(session_info=self.session, credentials=self.creds, lp=self.lp) # We need to hold this iterator open to hold the all-record lock. res = self.samdb.search_iterator() os.write(w2, b"start") if (os.read(r1, 7) != b"started"): os._exit(1) os.write(w2, b"add") if (os.read(r1, 5) != b"added"): os._exit(2) # Wait 2 seconds to block prepare_commit() in the child. os.write(w2, b"prepare") time.sleep(2) # Release the locks for l in res: pass if (os.read(r1, 8) != b"prepared"): os._exit(3) os._exit(0) # We can start the transaction during the search # because both just grab the all-record read lock. self.assertEqual(os.read(r2, 5), b"start") self.samdb.transaction_start() os.write(w1, b"started") self.assertEqual(os.read(r2, 3), b"add") dn = "cn=test_db_lock_user,cn=users," + str(basedn) self.samdb.add({ "dn": dn, "objectclass": "user", }) self.samdb.delete(dn) os.write(w1, b"added") # Obtain a write lock, this will block until # the parent releases the read lock. self.assertEqual(os.read(r2, 7), b"prepare") start = time.time() self.samdb.transaction_prepare_commit() end = time.time() try: self.assertGreater(end - start, 1.9) except: raise finally: os.write(w1, b"prepared") # Drop the write lock self.samdb.transaction_cancel() (got_pid, status) = os.waitpid(pid, 0) self.assertEqual(got_pid, pid) self.assertTrue(os.WIFEXITED(status)) self.assertEqual(os.WEXITSTATUS(status), 0) def test_db_lock3(self): basedn = self.samdb.get_default_basedn() (r1, w1) = os.pipe() (r2, w2) = os.pipe() pid = os.fork() if pid == 0: # In the child, close the main DB, re-open del (self.samdb) gc.collect() self.samdb = SamDB(session_info=self.session, credentials=self.creds, lp=self.lp) # We need to hold this iterator open to hold the all-record lock. res = self.samdb.search_iterator() os.write(w2, b"start") if (os.read(r1, 7) != b"started"): os._exit(1) os.write(w2, b"add") if (os.read(r1, 5) != b"added"): os._exit(2) # Wait 2 seconds to block prepare_commit() in the child. os.write(w2, b"prepare") time.sleep(2) # Release the locks for l in res: pass if (os.read(r1, 8) != b"prepared"): os._exit(3) os._exit(0) # We can start the transaction during the search # because both just grab the all-record read lock. self.assertEqual(os.read(r2, 5), b"start") self.samdb.transaction_start() os.write(w1, b"started") self.assertEqual(os.read(r2, 3), b"add") # This will end up in the top level db dn = "@DSDB_LOCK_TEST" self.samdb.add({"dn": dn}) self.samdb.delete(dn) os.write(w1, b"added") # Obtain a write lock, this will block until # the child releases the read lock. self.assertEqual(os.read(r2, 7), b"prepare") start = time.time() self.samdb.transaction_prepare_commit() end = time.time() self.assertGreater(end - start, 1.9) os.write(w1, b"prepared") # Drop the write lock self.samdb.transaction_cancel() (got_pid, status) = os.waitpid(pid, 0) self.assertTrue(os.WIFEXITED(status)) self.assertEqual(os.WEXITSTATUS(status), 0) self.assertEqual(got_pid, pid) def _test_full_db_lock1(self, backend_path): (r1, w1) = os.pipe() pid = os.fork() if pid == 0: # In the child, close the main DB, re-open just one DB del (self.samdb) gc.collect() backenddb = ldb.Ldb(backend_path) backenddb.transaction_start() backenddb.add({"dn": "@DSDB_LOCK_TEST"}) backenddb.delete("@DSDB_LOCK_TEST") # Obtain a write lock backenddb.transaction_prepare_commit() os.write(w1, b"prepared") time.sleep(2) # Drop the write lock backenddb.transaction_cancel() os._exit(0) self.assertEqual(os.read(r1, 8), b"prepared") start = time.time() # We need to hold this iterator open to hold the all-record lock. res = self.samdb.search_iterator() # This should take at least 2 seconds because the transaction # has a write lock on one backend db open end = time.time() self.assertGreater(end - start, 1.9) # Release the locks for l in res: pass (got_pid, status) = os.waitpid(pid, 0) self.assertEqual(got_pid, pid) self.assertTrue(os.WIFEXITED(status)) self.assertEqual(os.WEXITSTATUS(status), 0) def test_full_db_lock1(self): basedn = self.samdb.get_default_basedn() backend_filename = "%s.ldb" % basedn.get_casefold() backend_subpath = os.path.join("sam.ldb.d", backend_filename) backend_path = self.lp.private_path(backend_subpath) self._test_full_db_lock1(backend_path) def test_full_db_lock1_config(self): basedn = self.samdb.get_config_basedn() backend_filename = "%s.ldb" % basedn.get_casefold() backend_subpath = os.path.join("sam.ldb.d", backend_filename) backend_path = self.lp.private_path(backend_subpath) self._test_full_db_lock1(backend_path) def _test_full_db_lock2(self, backend_path): (r1, w1) = os.pipe() (r2, w2) = os.pipe() pid = os.fork() if pid == 0: # In the child, close the main DB, re-open del (self.samdb) gc.collect() self.samdb = SamDB(session_info=self.session, credentials=self.creds, lp=self.lp) # We need to hold this iterator open to hold the all-record lock. res = self.samdb.search_iterator() os.write(w2, b"start") if (os.read(r1, 7) != b"started"): os._exit(1) os.write(w2, b"add") if (os.read(r1, 5) != b"added"): os._exit(2) # Wait 2 seconds to block prepare_commit() in the child. os.write(w2, b"prepare") time.sleep(2) # Release the locks for l in res: pass if (os.read(r1, 8) != b"prepared"): os._exit(3) os._exit(0) # In the parent, close the main DB, re-open just one DB del (self.samdb) gc.collect() backenddb = ldb.Ldb(backend_path) # We can start the transaction during the search # because both just grab the all-record read lock. self.assertEqual(os.read(r2, 5), b"start") backenddb.transaction_start() os.write(w1, b"started") self.assertEqual(os.read(r2, 3), b"add") backenddb.add({"dn": "@DSDB_LOCK_TEST"}) backenddb.delete("@DSDB_LOCK_TEST") os.write(w1, b"added") # Obtain a write lock, this will block until # the child releases the read lock. self.assertEqual(os.read(r2, 7), b"prepare") start = time.time() backenddb.transaction_prepare_commit() end = time.time() try: self.assertGreater(end - start, 1.9) except: raise finally: os.write(w1, b"prepared") # Drop the write lock backenddb.transaction_cancel() (got_pid, status) = os.waitpid(pid, 0) self.assertEqual(got_pid, pid) self.assertTrue(os.WIFEXITED(status)) self.assertEqual(os.WEXITSTATUS(status), 0) def test_full_db_lock2(self): basedn = self.samdb.get_default_basedn() backend_filename = "%s.ldb" % basedn.get_casefold() backend_subpath = os.path.join("sam.ldb.d", backend_filename) backend_path = self.lp.private_path(backend_subpath) self._test_full_db_lock2(backend_path) def test_full_db_lock2_config(self): basedn = self.samdb.get_config_basedn() backend_filename = "%s.ldb" % basedn.get_casefold() backend_subpath = os.path.join("sam.ldb.d", backend_filename) backend_path = self.lp.private_path(backend_subpath) self._test_full_db_lock2(backend_path) def test_no_error_on_invalid_control(self): try: res = self.samdb.search( expression="cn=Administrator", scope=ldb.SCOPE_SUBTREE, attrs=["replPropertyMetaData"], controls=[ "local_oid:%s:0" % dsdb.DSDB_CONTROL_INVALID_NOT_IMPLEMENTED ]) except ldb.LdbError as e: self.fail("Should have not raised an exception") def test_error_on_invalid_critical_control(self): try: res = self.samdb.search( expression="cn=Administrator", scope=ldb.SCOPE_SUBTREE, attrs=["replPropertyMetaData"], controls=[ "local_oid:%s:1" % dsdb.DSDB_CONTROL_INVALID_NOT_IMPLEMENTED ]) except ldb.LdbError as e: if e[0] != ldb.ERR_UNSUPPORTED_CRITICAL_EXTENSION: self.fail( "Got %s should have got ERR_UNSUPPORTED_CRITICAL_EXTENSION" % e[1])
class SambaDnsUpdateTests(samba.tests.BlackboxTestCase): """Blackbox test case for samba_dnsupdate.""" def setUp(self): self.server_ip = samba.tests.env_get_var_value("DNS_SERVER_IP") super(SambaDnsUpdateTests, self).setUp() try: out = self.check_output("samba_dnsupdate --verbose") self.assertTrue("Looking for DNS entry" in out, out) except samba.tests.BlackboxProcessError: pass def test_samba_dnsupate_no_change(self): try: out = self.check_output("samba_dnsupdate --verbose") except samba.tests.BlackboxProcessError as e: self.fail("Error calling samba_dnsupdate: %s" % e) self.assertTrue("No DNS updates needed" in out, out) def test_samba_dnsupate_set_ip(self): try: out = self.check_output("samba_dnsupdate --verbose --current-ip=10.0.0.1") self.assertTrue(" DNS updates and" in out, out) self.assertTrue(" DNS deletes needed" in out, out) except samba.tests.BlackboxProcessError: pass try: out = self.check_output("samba_dnsupdate --verbose --use-nsupdate --current-ip=10.0.0.1") except samba.tests.BlackboxProcessError as e: self.fail("Error calling samba_dnsupdate: %s" % e) self.assertTrue("No DNS updates needed" in out, out) try: rpc_out = self.check_output("samba_dnsupdate --verbose --use-samba-tool --rpc-server-ip=%s" % self.server_ip) except samba.tests.BlackboxProcessError as e: self.fail("Error calling samba_dnsupdate: %s" % e) self.assertTrue(" DNS updates and" in rpc_out, rpc_out) self.assertTrue(" DNS deletes needed" in rpc_out, rpc_out) out = self.check_output("samba_dnsupdate --verbose") self.assertTrue("No DNS updates needed" in out, out + rpc_out) def test_add_new_uncovered_site(self): name = 'sites' cmd = cmd_sambatool.subcommands[name] cmd.outf = StringIO() cmd.errf = StringIO() site_name = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' # Clear out any existing site cmd._run("samba-tool %s" % name, 'remove', site_name) result = cmd._run("samba-tool %s" % name, 'create', site_name) if result is not None: self.fail("Error creating new site") self.lp = samba.tests.env_loadparm() self.creds = Credentials() self.creds.guess(self.lp) self.session = system_session() uc_fn = self.lp.private_path('dns_update_cache') tmp_uc = uc_fn + '_tmp' shutil.copyfile(uc_fn, tmp_uc) self.samdb = SamDB(session_info=self.session, credentials=self.creds, lp=self.lp) m = ldb.Message() m.dn = ldb.Dn(self.samdb, 'CN=DEFAULTIPSITELINK,CN=IP,' 'CN=Inter-Site Transports,CN=Sites,{}'.format( self.samdb.get_config_basedn())) m['siteList'] = ldb.MessageElement("CN={},CN=Sites,{}".format( site_name, self.samdb.get_config_basedn()), ldb.FLAG_MOD_ADD, "siteList") dns_c = "samba_dnsupdate --verbose --use-file={}".format(tmp_uc) out = self.check_output(dns_c) self.assertFalse(site_name.lower() in out, out) self.samdb.modify(m) shutil.copyfile(uc_fn, tmp_uc) out = self.check_output(dns_c) self.assertFalse("No DNS updates needed" in out, out) self.assertTrue(site_name.lower() in out, out) result = cmd._run("samba-tool %s" % name, 'remove', site_name) if result is not None: self.fail("Error deleting site")
def get_ldb_connection(self, target_username, target_password): creds_tmp = Credentials() creds_tmp.set_username(target_username) creds_tmp.set_password(target_password) creds_tmp.set_domain(creds.get_domain()) creds_tmp.set_realm(creds.get_realm()) creds_tmp.set_workstation(creds.get_workstation()) creds_tmp.set_gensec_features(creds_tmp.get_gensec_features() | gensec.FEATURE_SEAL) creds_tmp.set_kerberos_state( DONT_USE_KERBEROS) # kinit is too expensive to use in a tight loop ldb_target = SamDB(url=ldaphost, credentials=creds_tmp, lp=lp) return ldb_target
def setUp(self): super(BasePasswordTestCase, self).setUp() self.global_creds.set_gensec_features( self.global_creds.get_gensec_features() | gensec.FEATURE_SEAL) self.template_creds = Credentials() self.template_creds.set_username("testuser") self.template_creds.set_password("thatsAcomplPASS1") self.template_creds.set_domain(self.global_creds.get_domain()) self.template_creds.set_realm(self.global_creds.get_realm()) self.template_creds.set_workstation( self.global_creds.get_workstation()) self.template_creds.set_gensec_features( self.global_creds.get_gensec_features()) self.template_creds.set_kerberos_state( self.global_creds.get_kerberos_state()) # Gets back the basedn base_dn = self.ldb.domain_dn() # Gets back the configuration basedn configuration_dn = self.ldb.get_config_basedn().get_linearized() res = self.ldb.search(base_dn, scope=SCOPE_BASE, attrs=[ "lockoutDuration", "lockOutObservationWindow", "lockoutThreshold" ]) if "lockoutDuration" in res[0]: lockoutDuration = res[0]["lockoutDuration"][0] else: lockoutDuration = 0 if "lockoutObservationWindow" in res[0]: lockoutObservationWindow = res[0]["lockoutObservationWindow"][0] else: lockoutObservationWindow = 0 if "lockoutThreshold" in res[0]: lockoutThreshold = res[0]["lockoutThreshold"][0] else: lockoutTreshold = 0 self.addCleanup( self.ldb.modify_ldif, """ dn: """ + base_dn + """ changetype: modify replace: lockoutDuration lockoutDuration: """ + str(lockoutDuration) + """ replace: lockoutObservationWindow lockoutObservationWindow: """ + str(lockoutObservationWindow) + """ replace: lockoutThreshold lockoutThreshold: """ + str(lockoutThreshold) + """ """) self.base_dn = self.ldb.domain_dn() # # Some test cases sleep() for self.account_lockout_duration # so allow it to be controlled via the subclass # if not hasattr(self, 'account_lockout_duration'): self.account_lockout_duration = 3 if not hasattr(self, 'lockout_observation_window'): self.lockout_observation_window = 3 self.update_lockout_settings( threshold=3, duration=self.account_lockout_duration, observation_window=self.lockout_observation_window) # update DC to allow password changes for the duration of this test self.allow_password_changes() self.domain_sid = security.dom_sid(self.ldb.get_domain_sid()) self.samr = samr.samr("ncacn_ip_tcp:%s[seal]" % self.host, self.lp, self.global_creds) self.samr_handle = self.samr.Connect2( None, security.SEC_FLAG_MAXIMUM_ALLOWED) self.samr_domain = self.samr.OpenDomain( self.samr_handle, security.SEC_FLAG_MAXIMUM_ALLOWED, self.domain_sid) self.addCleanup(self.delete_ldb_connections) # (Re)adds the test user accounts self.lockout1krb5_creds = self.insta_creds( self.template_creds, username="******", userpass="******", kerberos_state=MUST_USE_KERBEROS) self.lockout1krb5_ldb = self._readd_user(self.lockout1krb5_creds) self.lockout1ntlm_creds = self.insta_creds( self.template_creds, username="******", userpass="******", kerberos_state=DONT_USE_KERBEROS) self.lockout1ntlm_ldb = self._readd_user(self.lockout1ntlm_creds)
class BasePasswordTestCase(PasswordTestCase): def _open_samr_user(self, res): self.assertTrue("objectSid" in res[0]) (domain_sid, rid) = ndr_unpack(security.dom_sid, res[0]["objectSid"][0]).split() self.assertEquals(self.domain_sid, domain_sid) return self.samr.OpenUser(self.samr_domain, security.SEC_FLAG_MAXIMUM_ALLOWED, rid) def _check_attribute(self, res, name, value): if value is None: self.assertTrue(name not in res[0], msg="attr[%s]=%r on dn[%s]" % (name, res[0], res[0].dn)) return if isinstance(value, tuple): (mode, value) = value else: mode = "equal" if mode == "ignore": return if mode == "absent": self.assertFalse(name in res[0], msg="attr[%s] not missing on dn[%s]" % (name, res[0].dn)) return self.assertTrue(name in res[0], msg="attr[%s] missing on dn[%s]" % (name, res[0].dn)) self.assertTrue(len(res[0][name]) == 1, msg="attr[%s]=%r on dn[%s]" % (name, res[0][name], res[0].dn)) print("%s = '%s'" % (name, res[0][name][0])) if mode == "present": return if mode == "equal": v = int(res[0][name][0]) value = int(value) msg = ("attr[%s]=[%s] != [%s] on dn[%s]\n" "(diff %d; actual value is %s than expected)" % (name, v, value, res[0].dn, v - value, ('less' if v < value else 'greater'))) self.assertTrue(v == value, msg) return if mode == "greater": v = int(res[0][name][0]) self.assertTrue(v > int(value), msg="attr[%s]=[%s] <= [%s] on dn[%s] (diff %d)" % (name, v, int(value), res[0].dn, v - int(value))) return if mode == "less": v = int(res[0][name][0]) self.assertTrue(v < int(value), msg="attr[%s]=[%s] >= [%s] on dn[%s] (diff %d)" % (name, v, int(value), res[0].dn, v - int(value))) return self.assertEqual(mode, not mode, "Invalid Mode[%s]" % mode) def _check_account_initial(self, userdn): self._check_account(userdn, badPwdCount=0, badPasswordTime=0, logonCount=0, lastLogon=0, lastLogonTimestamp=("absent", None), userAccountControl=dsdb.UF_NORMAL_ACCOUNT, msDSUserAccountControlComputed=0) def _check_account(self, dn, badPwdCount=None, badPasswordTime=None, logonCount=None, lastLogon=None, lastLogonTimestamp=None, lockoutTime=None, userAccountControl=None, msDSUserAccountControlComputed=None, effective_bad_password_count=None, msg=None, badPwdCountOnly=False): print('-=' * 36) if msg is not None: print("\033[01;32m %s \033[00m\n" % msg) attrs = [ "objectSid", "badPwdCount", "badPasswordTime", "lastLogon", "lastLogonTimestamp", "logonCount", "lockoutTime", "userAccountControl", "msDS-User-Account-Control-Computed" ] # in order to prevent some time resolution problems we sleep for # 10 micro second time.sleep(0.01) res = self.ldb.search(dn, scope=SCOPE_BASE, attrs=attrs) self.assertTrue(len(res) == 1) self._check_attribute(res, "badPwdCount", badPwdCount) self._check_attribute(res, "lockoutTime", lockoutTime) self._check_attribute(res, "badPasswordTime", badPasswordTime) if not badPwdCountOnly: self._check_attribute(res, "logonCount", logonCount) self._check_attribute(res, "lastLogon", lastLogon) self._check_attribute(res, "lastLogonTimestamp", lastLogonTimestamp) self._check_attribute(res, "userAccountControl", userAccountControl) self._check_attribute(res, "msDS-User-Account-Control-Computed", msDSUserAccountControlComputed) lastLogon = int(res[0]["lastLogon"][0]) logonCount = int(res[0]["logonCount"][0]) samr_user = self._open_samr_user(res) uinfo3 = self.samr.QueryUserInfo(samr_user, 3) uinfo5 = self.samr.QueryUserInfo(samr_user, 5) uinfo16 = self.samr.QueryUserInfo(samr_user, 16) uinfo21 = self.samr.QueryUserInfo(samr_user, 21) self.samr.Close(samr_user) expected_acb_info = 0 if not badPwdCountOnly: if userAccountControl & dsdb.UF_NORMAL_ACCOUNT: expected_acb_info |= samr.ACB_NORMAL if userAccountControl & dsdb.UF_ACCOUNTDISABLE: expected_acb_info |= samr.ACB_DISABLED if userAccountControl & dsdb.UF_PASSWD_NOTREQD: expected_acb_info |= samr.ACB_PWNOTREQ if msDSUserAccountControlComputed & dsdb.UF_LOCKOUT: expected_acb_info |= samr.ACB_AUTOLOCK if msDSUserAccountControlComputed & dsdb.UF_PASSWORD_EXPIRED: expected_acb_info |= samr.ACB_PW_EXPIRED self.assertEquals(uinfo3.acct_flags, expected_acb_info) self.assertEquals(uinfo3.last_logon, lastLogon) self.assertEquals(uinfo3.logon_count, logonCount) expected_bad_password_count = 0 if badPwdCount is not None: expected_bad_password_count = badPwdCount if effective_bad_password_count is None: effective_bad_password_count = expected_bad_password_count self.assertEquals(uinfo3.bad_password_count, expected_bad_password_count) if not badPwdCountOnly: self.assertEquals(uinfo5.acct_flags, expected_acb_info) self.assertEquals(uinfo5.bad_password_count, effective_bad_password_count) self.assertEquals(uinfo5.last_logon, lastLogon) self.assertEquals(uinfo5.logon_count, logonCount) self.assertEquals(uinfo16.acct_flags, expected_acb_info) self.assertEquals(uinfo21.acct_flags, expected_acb_info) self.assertEquals(uinfo21.bad_password_count, effective_bad_password_count) self.assertEquals(uinfo21.last_logon, lastLogon) self.assertEquals(uinfo21.logon_count, logonCount) # check LDAP again and make sure the samr.QueryUserInfo # doesn't have any impact. res2 = self.ldb.search(dn, scope=SCOPE_BASE, attrs=attrs) self.assertEquals(res[0], res2[0]) # in order to prevent some time resolution problems we sleep for # 10 micro second time.sleep(0.01) return res def update_lockout_settings(self, threshold, duration, observation_window): """Updates the global user lockout settings""" m = Message() m.dn = Dn(self.ldb, self.base_dn) account_lockout_duration_ticks = -int(duration * (1e7)) m["lockoutDuration"] = MessageElement( str(account_lockout_duration_ticks), FLAG_MOD_REPLACE, "lockoutDuration") m["lockoutThreshold"] = MessageElement(str(threshold), FLAG_MOD_REPLACE, "lockoutThreshold") lockout_observation_window_ticks = -int(observation_window * (1e7)) m["lockOutObservationWindow"] = MessageElement( str(lockout_observation_window_ticks), FLAG_MOD_REPLACE, "lockOutObservationWindow") self.ldb.modify(m) def _readd_user(self, creds, lockOutObservationWindow=0): username = creds.get_username() userpass = creds.get_password() userdn = "cn=%s,cn=users,%s" % (username, self.base_dn) delete_force(self.ldb, userdn) self.ldb.add({ "dn": userdn, "objectclass": "user", "sAMAccountName": username }) self.addCleanup(delete_force, self.ldb, userdn) # Sets the initial user password with a "special" password change # I think that this internally is a password set operation and it can # only be performed by someone which has password set privileges on the # account (at least in s4 we do handle it like that). self.ldb.modify_ldif(""" dn: """ + userdn + """ changetype: modify delete: userPassword add: userPassword userPassword: """ + userpass + """ """) # Enables the user account self.ldb.enable_account("(sAMAccountName=%s)" % username) use_kerberos = creds.get_kerberos_state() fail_creds = self.insta_creds(self.template_creds, username=username, userpass=userpass + "X", kerberos_state=use_kerberos) self._check_account_initial(userdn) # Fail once to get a badPasswordTime try: ldb = SamDB(url=self.host_url, credentials=fail_creds, lp=self.lp) self.fail() except LdbError as e: (num, msg) = e.args self.assertEquals(num, ERR_INVALID_CREDENTIALS) # Succeed to reset everything to 0 ldb = SamDB(url=self.host_url, credentials=creds, lp=self.lp) return ldb def assertLoginFailure(self, url, creds, lp, errno=ERR_INVALID_CREDENTIALS): try: ldb = SamDB(url=url, credentials=creds, lp=lp) self.fail("Login unexpectedly succeeded") except LdbError as e1: (num, msg) = e1.args if errno is not None: self.assertEquals(num, errno, ("Login failed in the wrong way" "(got err %d, expected %d)" % (num, errno))) def setUp(self): super(BasePasswordTestCase, self).setUp() self.global_creds.set_gensec_features( self.global_creds.get_gensec_features() | gensec.FEATURE_SEAL) self.template_creds = Credentials() self.template_creds.set_username("testuser") self.template_creds.set_password("thatsAcomplPASS1") self.template_creds.set_domain(self.global_creds.get_domain()) self.template_creds.set_realm(self.global_creds.get_realm()) self.template_creds.set_workstation( self.global_creds.get_workstation()) self.template_creds.set_gensec_features( self.global_creds.get_gensec_features()) self.template_creds.set_kerberos_state( self.global_creds.get_kerberos_state()) # Gets back the basedn base_dn = self.ldb.domain_dn() # Gets back the configuration basedn configuration_dn = self.ldb.get_config_basedn().get_linearized() res = self.ldb.search(base_dn, scope=SCOPE_BASE, attrs=[ "lockoutDuration", "lockOutObservationWindow", "lockoutThreshold" ]) if "lockoutDuration" in res[0]: lockoutDuration = res[0]["lockoutDuration"][0] else: lockoutDuration = 0 if "lockoutObservationWindow" in res[0]: lockoutObservationWindow = res[0]["lockoutObservationWindow"][0] else: lockoutObservationWindow = 0 if "lockoutThreshold" in res[0]: lockoutThreshold = res[0]["lockoutThreshold"][0] else: lockoutTreshold = 0 self.addCleanup( self.ldb.modify_ldif, """ dn: """ + base_dn + """ changetype: modify replace: lockoutDuration lockoutDuration: """ + str(lockoutDuration) + """ replace: lockoutObservationWindow lockoutObservationWindow: """ + str(lockoutObservationWindow) + """ replace: lockoutThreshold lockoutThreshold: """ + str(lockoutThreshold) + """ """) self.base_dn = self.ldb.domain_dn() # # Some test cases sleep() for self.account_lockout_duration # so allow it to be controlled via the subclass # if not hasattr(self, 'account_lockout_duration'): self.account_lockout_duration = 3 if not hasattr(self, 'lockout_observation_window'): self.lockout_observation_window = 3 self.update_lockout_settings( threshold=3, duration=self.account_lockout_duration, observation_window=self.lockout_observation_window) # update DC to allow password changes for the duration of this test self.allow_password_changes() self.domain_sid = security.dom_sid(self.ldb.get_domain_sid()) self.samr = samr.samr("ncacn_ip_tcp:%s[seal]" % self.host, self.lp, self.global_creds) self.samr_handle = self.samr.Connect2( None, security.SEC_FLAG_MAXIMUM_ALLOWED) self.samr_domain = self.samr.OpenDomain( self.samr_handle, security.SEC_FLAG_MAXIMUM_ALLOWED, self.domain_sid) self.addCleanup(self.delete_ldb_connections) # (Re)adds the test user accounts self.lockout1krb5_creds = self.insta_creds( self.template_creds, username="******", userpass="******", kerberos_state=MUST_USE_KERBEROS) self.lockout1krb5_ldb = self._readd_user(self.lockout1krb5_creds) self.lockout1ntlm_creds = self.insta_creds( self.template_creds, username="******", userpass="******", kerberos_state=DONT_USE_KERBEROS) self.lockout1ntlm_ldb = self._readd_user(self.lockout1ntlm_creds) def delete_ldb_connections(self): del self.lockout1krb5_ldb del self.lockout1ntlm_ldb del self.ldb def tearDown(self): super(BasePasswordTestCase, self).tearDown() def _test_login_lockout(self, creds): username = creds.get_username() userpass = creds.get_password() userdn = "cn=%s,cn=users,%s" % (username, self.base_dn) use_kerberos = creds.get_kerberos_state() # This unlocks by waiting for account_lockout_duration if use_kerberos == MUST_USE_KERBEROS: logoncount_relation = 'greater' lastlogon_relation = 'greater' print("Performs a lockout attempt against LDAP using Kerberos") else: logoncount_relation = 'equal' lastlogon_relation = 'equal' print("Performs a lockout attempt against LDAP using NTLM") # Change password on a connection as another user res = self._check_account(userdn, badPwdCount=0, badPasswordTime=("greater", 0), logonCount=(logoncount_relation, 0), lastLogon=("greater", 0), lastLogonTimestamp=("greater", 0), userAccountControl=dsdb.UF_NORMAL_ACCOUNT, msDSUserAccountControlComputed=0) badPasswordTime = int(res[0]["badPasswordTime"][0]) logonCount = int(res[0]["logonCount"][0]) lastLogon = int(res[0]["lastLogon"][0]) firstLogon = lastLogon lastLogonTimestamp = int(res[0]["lastLogonTimestamp"][0]) print(firstLogon) print(lastLogonTimestamp) self.assertGreater(lastLogon, badPasswordTime) self.assertGreaterEqual(lastLogon, lastLogonTimestamp) # Open a second LDB connection with the user credentials. Use the # command line credentials for informations like the domain, the realm # and the workstation. creds_lockout = self.insta_creds(creds) # The wrong password creds_lockout.set_password("thatsAcomplPASS1x") self.assertLoginFailure(self.host_url, creds_lockout, self.lp) res = self._check_account(userdn, badPwdCount=1, badPasswordTime=("greater", badPasswordTime), logonCount=logonCount, lastLogon=lastLogon, lastLogonTimestamp=lastLogonTimestamp, userAccountControl=dsdb.UF_NORMAL_ACCOUNT, msDSUserAccountControlComputed=0, msg='lastlogontimestamp with wrong password') badPasswordTime = int(res[0]["badPasswordTime"][0]) # Correct old password creds_lockout.set_password(userpass) ldb_lockout = SamDB(url=self.host_url, credentials=creds_lockout, lp=self.lp) # lastLogonTimestamp should not change # lastLogon increases if badPwdCount is non-zero (!) res = self._check_account(userdn, badPwdCount=0, badPasswordTime=badPasswordTime, logonCount=(logoncount_relation, logonCount), lastLogon=('greater', lastLogon), lastLogonTimestamp=lastLogonTimestamp, userAccountControl=dsdb.UF_NORMAL_ACCOUNT, msDSUserAccountControlComputed=0, msg='LLTimestamp is updated to lastlogon') logonCount = int(res[0]["logonCount"][0]) lastLogon = int(res[0]["lastLogon"][0]) self.assertGreater(lastLogon, badPasswordTime) self.assertGreaterEqual(lastLogon, lastLogonTimestamp) # The wrong password creds_lockout.set_password("thatsAcomplPASS1x") self.assertLoginFailure(self.host_url, creds_lockout, self.lp) res = self._check_account(userdn, badPwdCount=1, badPasswordTime=("greater", badPasswordTime), logonCount=logonCount, lastLogon=lastLogon, lastLogonTimestamp=lastLogonTimestamp, userAccountControl=dsdb.UF_NORMAL_ACCOUNT, msDSUserAccountControlComputed=0) badPasswordTime = int(res[0]["badPasswordTime"][0]) # The wrong password creds_lockout.set_password("thatsAcomplPASS1x") try: ldb_lockout = SamDB(url=self.host_url, credentials=creds_lockout, lp=self.lp) self.fail() except LdbError as e2: (num, msg) = e2.args self.assertEquals(num, ERR_INVALID_CREDENTIALS) res = self._check_account(userdn, badPwdCount=2, badPasswordTime=("greater", badPasswordTime), logonCount=logonCount, lastLogon=lastLogon, lastLogonTimestamp=lastLogonTimestamp, userAccountControl=dsdb.UF_NORMAL_ACCOUNT, msDSUserAccountControlComputed=0) badPasswordTime = int(res[0]["badPasswordTime"][0]) print("two failed password change") # The wrong password creds_lockout.set_password("thatsAcomplPASS1x") try: ldb_lockout = SamDB(url=self.host_url, credentials=creds_lockout, lp=self.lp) self.fail() except LdbError as e3: (num, msg) = e3.args self.assertEquals(num, ERR_INVALID_CREDENTIALS) res = self._check_account( userdn, badPwdCount=3, badPasswordTime=("greater", badPasswordTime), logonCount=logonCount, lastLogon=lastLogon, lastLogonTimestamp=lastLogonTimestamp, lockoutTime=("greater", badPasswordTime), userAccountControl=dsdb.UF_NORMAL_ACCOUNT, msDSUserAccountControlComputed=dsdb.UF_LOCKOUT) badPasswordTime = int(res[0]["badPasswordTime"][0]) lockoutTime = int(res[0]["lockoutTime"][0]) # The wrong password creds_lockout.set_password("thatsAcomplPASS1x") try: ldb_lockout = SamDB(url=self.host_url, credentials=creds_lockout, lp=self.lp) self.fail() except LdbError as e4: (num, msg) = e4.args self.assertEquals(num, ERR_INVALID_CREDENTIALS) res = self._check_account( userdn, badPwdCount=3, badPasswordTime=badPasswordTime, logonCount=logonCount, lastLogon=lastLogon, lastLogonTimestamp=lastLogonTimestamp, lockoutTime=lockoutTime, userAccountControl=dsdb.UF_NORMAL_ACCOUNT, msDSUserAccountControlComputed=dsdb.UF_LOCKOUT) # The wrong password creds_lockout.set_password("thatsAcomplPASS1x") try: ldb_lockout = SamDB(url=self.host_url, credentials=creds_lockout, lp=self.lp) self.fail() except LdbError as e5: (num, msg) = e5.args self.assertEquals(num, ERR_INVALID_CREDENTIALS) res = self._check_account( userdn, badPwdCount=3, badPasswordTime=badPasswordTime, logonCount=logonCount, lastLogon=lastLogon, lastLogonTimestamp=lastLogonTimestamp, lockoutTime=lockoutTime, userAccountControl=dsdb.UF_NORMAL_ACCOUNT, msDSUserAccountControlComputed=dsdb.UF_LOCKOUT) # The correct password, but we are locked out creds_lockout.set_password(userpass) try: ldb_lockout = SamDB(url=self.host_url, credentials=creds_lockout, lp=self.lp) self.fail() except LdbError as e6: (num, msg) = e6.args self.assertEquals(num, ERR_INVALID_CREDENTIALS) res = self._check_account( userdn, badPwdCount=3, badPasswordTime=badPasswordTime, logonCount=logonCount, lastLogon=lastLogon, lastLogonTimestamp=lastLogonTimestamp, lockoutTime=lockoutTime, userAccountControl=dsdb.UF_NORMAL_ACCOUNT, msDSUserAccountControlComputed=dsdb.UF_LOCKOUT) # wait for the lockout to end time.sleep(self.account_lockout_duration + 1) print(self.account_lockout_duration + 1) res = self._check_account(userdn, badPwdCount=3, effective_bad_password_count=0, badPasswordTime=badPasswordTime, logonCount=logonCount, lockoutTime=lockoutTime, lastLogon=lastLogon, lastLogonTimestamp=lastLogonTimestamp, userAccountControl=dsdb.UF_NORMAL_ACCOUNT, msDSUserAccountControlComputed=0) # The correct password after letting the timeout expire creds_lockout.set_password(userpass) creds_lockout2 = self.insta_creds(creds_lockout) ldb_lockout = SamDB(url=self.host_url, credentials=creds_lockout2, lp=self.lp) time.sleep(3) res = self._check_account(userdn, badPwdCount=0, badPasswordTime=badPasswordTime, logonCount=(logoncount_relation, logonCount), lastLogon=(lastlogon_relation, lastLogon), lastLogonTimestamp=lastLogonTimestamp, lockoutTime=0, userAccountControl=dsdb.UF_NORMAL_ACCOUNT, msDSUserAccountControlComputed=0, msg="lastLogon is way off") logonCount = int(res[0]["logonCount"][0]) lastLogon = int(res[0]["lastLogon"][0]) # The wrong password creds_lockout.set_password("thatsAcomplPASS1x") try: ldb_lockout = SamDB(url=self.host_url, credentials=creds_lockout, lp=self.lp) self.fail() except LdbError as e7: (num, msg) = e7.args self.assertEquals(num, ERR_INVALID_CREDENTIALS) res = self._check_account(userdn, badPwdCount=1, badPasswordTime=("greater", badPasswordTime), logonCount=logonCount, lockoutTime=0, lastLogon=lastLogon, lastLogonTimestamp=lastLogonTimestamp, userAccountControl=dsdb.UF_NORMAL_ACCOUNT, msDSUserAccountControlComputed=0) badPasswordTime = int(res[0]["badPasswordTime"][0]) # The wrong password creds_lockout.set_password("thatsAcomplPASS1x") try: ldb_lockout = SamDB(url=self.host_url, credentials=creds_lockout, lp=self.lp) self.fail() except LdbError as e8: (num, msg) = e8.args self.assertEquals(num, ERR_INVALID_CREDENTIALS) res = self._check_account(userdn, badPwdCount=2, badPasswordTime=("greater", badPasswordTime), logonCount=logonCount, lockoutTime=0, lastLogon=lastLogon, lastLogonTimestamp=lastLogonTimestamp, userAccountControl=dsdb.UF_NORMAL_ACCOUNT, msDSUserAccountControlComputed=0) badPasswordTime = int(res[0]["badPasswordTime"][0]) time.sleep(self.lockout_observation_window + 1) res = self._check_account(userdn, badPwdCount=2, effective_bad_password_count=0, badPasswordTime=badPasswordTime, logonCount=logonCount, lockoutTime=0, lastLogon=lastLogon, lastLogonTimestamp=lastLogonTimestamp, userAccountControl=dsdb.UF_NORMAL_ACCOUNT, msDSUserAccountControlComputed=0) # The wrong password creds_lockout.set_password("thatsAcomplPASS1x") try: ldb_lockout = SamDB(url=self.host_url, credentials=creds_lockout, lp=self.lp) self.fail() except LdbError as e9: (num, msg) = e9.args self.assertEquals(num, ERR_INVALID_CREDENTIALS) res = self._check_account(userdn, badPwdCount=1, badPasswordTime=("greater", badPasswordTime), logonCount=logonCount, lockoutTime=0, lastLogon=lastLogon, lastLogonTimestamp=lastLogonTimestamp, userAccountControl=dsdb.UF_NORMAL_ACCOUNT, msDSUserAccountControlComputed=0) badPasswordTime = int(res[0]["badPasswordTime"][0]) # The correct password without letting the timeout expire creds_lockout.set_password(userpass) ldb_lockout = SamDB(url=self.host_url, credentials=creds_lockout, lp=self.lp) res = self._check_account(userdn, badPwdCount=0, badPasswordTime=badPasswordTime, logonCount=(logoncount_relation, logonCount), lockoutTime=0, lastLogon=("greater", lastLogon), lastLogonTimestamp=lastLogonTimestamp, userAccountControl=dsdb.UF_NORMAL_ACCOUNT, msDSUserAccountControlComputed=0) def _test_multiple_logon(self, creds): # Test the happy case in which a user logs on correctly, then # logs on correctly again, so that the bad password and # lockout times are both zero the second time. The lastlogon # time should increase. # Open a second LDB connection with the user credentials. Use the # command line credentials for informations like the domain, the realm # and the workstation. username = creds.get_username() userdn = "cn=%s,cn=users,%s" % (username, self.base_dn) use_kerberos = creds.get_kerberos_state() if use_kerberos == MUST_USE_KERBEROS: print("Testing multiple logon with Kerberos") logoncount_relation = 'greater' lastlogon_relation = 'greater' else: print("Testing multiple logon with NTLM") logoncount_relation = 'equal' lastlogon_relation = 'equal' SamDB(url=self.host_url, credentials=self.insta_creds(creds), lp=self.lp) res = self._check_account(userdn, badPwdCount=0, badPasswordTime=("greater", 0), logonCount=(logoncount_relation, 0), lastLogon=("greater", 0), lastLogonTimestamp=("greater", 0), userAccountControl=dsdb.UF_NORMAL_ACCOUNT, msDSUserAccountControlComputed=0) badPasswordTime = int(res[0]["badPasswordTime"][0]) logonCount = int(res[0]["logonCount"][0]) lastLogon = int(res[0]["lastLogon"][0]) lastLogonTimestamp = int(res[0]["lastLogonTimestamp"][0]) firstLogon = lastLogon print("last logon is %d" % lastLogon) self.assertGreater(lastLogon, badPasswordTime) self.assertGreaterEqual(lastLogon, lastLogonTimestamp) time.sleep(1) SamDB(url=self.host_url, credentials=self.insta_creds(creds), lp=self.lp) res = self._check_account(userdn, badPwdCount=0, badPasswordTime=badPasswordTime, logonCount=(logoncount_relation, logonCount), lastLogon=(lastlogon_relation, lastLogon), lastLogonTimestamp=lastLogonTimestamp, userAccountControl=dsdb.UF_NORMAL_ACCOUNT, msDSUserAccountControlComputed=0, msg=("second logon, firstlogon was %s" % firstLogon)) lastLogon = int(res[0]["lastLogon"][0]) time.sleep(1) SamDB(url=self.host_url, credentials=self.insta_creds(creds), lp=self.lp) res = self._check_account(userdn, badPwdCount=0, badPasswordTime=badPasswordTime, logonCount=(logoncount_relation, logonCount), lastLogon=(lastlogon_relation, lastLogon), lastLogonTimestamp=lastLogonTimestamp, userAccountControl=dsdb.UF_NORMAL_ACCOUNT, msDSUserAccountControlComputed=0)
class RodcCmdTestCase(SambaToolCmdTest): def setUp(self): super(RodcCmdTestCase, self).setUp() self.lp = samba.param.LoadParm() self.lp.load(os.environ["SMB_CONF_PATH"]) self.creds = Credentials() self.creds.set_username(os.environ["DC_USERNAME"]) self.creds.set_password(os.environ["DC_PASSWORD"]) self.creds.guess(self.lp) self.session = system_session() self.ldb = SamDB("ldap://" + os.environ["DC_SERVER"], session_info=self.session, credentials=self.creds,lp=self.lp) self.base_dn = self.ldb.domain_dn() self.ldb.newuser("sambatool1", "1qazXSW@") self.ldb.newuser("sambatool2", "2wsxCDE#") self.ldb.newuser("sambatool3", "3edcVFR$") self.ldb.newuser("sambatool4", "4rfvBGT%") self.ldb.newuser("sambatool5", "5tjbNHY*") self.ldb.newuser("sambatool6", "6yknMJU*") self.ldb.add_remove_group_members("Allowed RODC Password Replication Group", ["sambatool1", "sambatool2", "sambatool3", "sambatool4", "sambatool5"], add_members_operation=True) def tearDown(self): super(RodcCmdTestCase, self).tearDown() self.ldb.deleteuser("sambatool1") self.ldb.deleteuser("sambatool2") self.ldb.deleteuser("sambatool3") self.ldb.deleteuser("sambatool4") self.ldb.deleteuser("sambatool5") self.ldb.deleteuser("sambatool6") (result, out, err) = self.runsubcmd("drs", "replicate", "--local", "unused", os.environ["DC_SERVER"], self.base_dn) def test_single_by_account_name(self): (result, out, err) = self.runsubcmd("rodc", "preload", "sambatool1", "--server", os.environ["DC_SERVER"]) self.assertCmdSuccess(result, out, err, "ensuring rodc prefetch ran successfully") self.assertEqual(out, "Replicating DN CN=sambatool1,CN=Users,%s\n" % self.base_dn) self.assertEqual(err, "") def test_single_by_dn(self): (result, out, err) = self.runsubcmd("rodc", "preload", "cn=sambatool2,cn=users,%s" % self.base_dn, "--server", os.environ["DC_SERVER"]) self.assertCmdSuccess(result, out, err, "ensuring rodc prefetch ran successfully") self.assertEqual(out, "Replicating DN CN=sambatool2,CN=Users,%s\n" % self.base_dn) def test_multi_by_account_name(self): (result, out, err) = self.runsubcmd("rodc", "preload", "sambatool1", "sambatool2", "--server", os.environ["DC_SERVER"]) self.assertCmdSuccess(result, out, err, "ensuring rodc prefetch ran successfully") self.assertEqual(out, "Replicating DN CN=sambatool1,CN=Users,%s\nReplicating DN CN=sambatool2,CN=Users,%s\n" % (self.base_dn, self.base_dn)) def test_multi_by_dn(self): (result, out, err) = self.runsubcmd("rodc", "preload", "cn=sambatool3,cn=users,%s" % self.base_dn, "cn=sambatool4,cn=users,%s" % self.base_dn, "--server", os.environ["DC_SERVER"]) self.assertCmdSuccess(result, out, err, "ensuring rodc prefetch ran successfully") self.assertEqual(out, "Replicating DN CN=sambatool3,CN=Users,%s\nReplicating DN CN=sambatool4,CN=Users,%s\n" % (self.base_dn, self.base_dn)) def test_multi_in_file(self): tempf = os.path.join(self.tempdir, "accountlist") open(tempf, 'w').write("sambatool1\nsambatool2") (result, out, err) = self.runsubcmd("rodc", "preload", "--file", tempf, "--server", os.environ["DC_SERVER"]) self.assertCmdSuccess(result, out, err, "ensuring rodc prefetch ran successfully") self.assertEqual(out, "Replicating DN CN=sambatool1,CN=Users,%s\nReplicating DN CN=sambatool2,CN=Users,%s\n" % (self.base_dn, self.base_dn)) os.unlink(tempf) def test_multi_with_missing_name_success(self): (result, out, err) = self.runsubcmd("rodc", "preload", "nonexistentuser1", "sambatool5", "nonexistentuser2", "--server", os.environ["DC_SERVER"], "--ignore-errors") self.assertCmdSuccess(result, out, err, "ensuring rodc prefetch ran successfully") self.assertTrue(out.startswith("Replicating DN CN=sambatool5,CN=Users,%s\n" % self.base_dn)) def test_multi_with_missing_name_failure(self): (result, out, err) = self.runsubcmd("rodc", "preload", "nonexistentuser1", "sambatool5", "nonexistentuser2", "--server", os.environ["DC_SERVER"]) self.assertCmdFail(result, "ensuring rodc prefetch quit on missing user") def test_multi_without_group_success(self): (result, out, err) = self.runsubcmd("rodc", "preload", "sambatool6", "sambatool5", "--server", os.environ["DC_SERVER"], "--ignore-errors") self.assertCmdSuccess(result, out, err, "ensuring rodc prefetch ran successfully") self.assertTrue(out.startswith("Replicating DN CN=sambatool6,CN=Users,%s\n" "Replicating DN CN=sambatool5,CN=Users,%s\n" % (self.base_dn, self.base_dn))) def test_multi_without_group_failure(self): (result, out, err) = self.runsubcmd("rodc", "preload", "sambatool6", "sambatool5", "--server", os.environ["DC_SERVER"]) self.assertCmdFail(result, "ensuring rodc prefetch quit on non-replicated user")