Exemple #1
0
    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())
Exemple #3
0
 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)
Exemple #7
0
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
Exemple #8
0
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
Exemple #9
0
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))
Exemple #10
0
    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)
Exemple #11
0
 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, "")
Exemple #12
0
    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()
Exemple #13
0
    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")
Exemple #14
0
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
Exemple #15
0
    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)
Exemple #16
0
 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()
Exemple #17
0
    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)
Exemple #18
0
    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
Exemple #19
0
 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"])
Exemple #20
0
 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()
Exemple #21
0
    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)
Exemple #23
0
    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)
Exemple #24
0
 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)
Exemple #25
0
	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()
Exemple #26
0
 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)
Exemple #27
0
    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()
Exemple #28
0
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")
Exemple #29
0
    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")
Exemple #30
0
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
Exemple #31
0
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
Exemple #32
0
    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"
            )
Exemple #33
0
    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))
Exemple #34
0
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
Exemple #35
0
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)
Exemple #36
0
    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)
Exemple #37
0
    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)
Exemple #39
0
    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")
Exemple #40
0
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
Exemple #41
0
    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)
Exemple #42
0
    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)
Exemple #43
0
 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
Exemple #44
0
    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)
Exemple #45
0
    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)
Exemple #46
0
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()
Exemple #47
0
    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)
Exemple #48
0
    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
Exemple #49
0
 def get_anon_creds(self):
     c = Credentials()
     c.set_anonymous()
     return c
Exemple #50
0
 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
Exemple #51
0
 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
Exemple #52
0
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)
Exemple #53
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)
Exemple #54
0
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)
Exemple #55
0
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])
Exemple #56
0
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")
Exemple #57
0
 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)
Exemple #60
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")