Example #1
0
        def test_json_matching_entries(self):
            """
            The ``--json`` variants must contain the same keys as their
            respective plain counterpart.

            Does not check nested dictionaries (e. g. the ``Flags`` value of
            ``net ads lookup``..
            """
            argv = "%s %s" % (COMMAND, self.subcmd)
            try:
                out_plain = get_string(self.check_output(argv))
            except samba.tests.BlackboxProcessError as e:
                self.fail("Error calling [%s]: %s" % (argv, e))

            argv = "%s %s --json" % (COMMAND, self.subcmd)
            try:
                out_jsobj = self.check_output(argv)
            except samba.tests.BlackboxProcessError as e:
                self.fail("Error calling [%s]: %s" % (argv, e))

            parsed = json.loads(get_string(out_jsobj))

            for key in [
                    re.match(PLAIN_KEY_REGEX, line).group(1)
                    for line in out_plain.split("\n")
                    if line != "" and line[0] not in " \t:"
            ]:
                self.assertTrue(parsed.get(key) is not None)
                del parsed[key]

            self.assertTrue(len(parsed) == 0)  # tolerate no leftovers
Example #2
0
    def check_domain_server_authentication(self, pipe, logon_id, description):

        messages = os.read(pipe, 8192)
        messages = get_string(messages)
        if len(messages) == 0 or messages == "None":
            self.fail("No Domain server authentication message")

        #
        # Look for the SamLogon request matching logon_id
        msg = None
        for message in messages.split("\n"):
            msg = json.loads(get_string(message))
            if logon_id == msg["Authentication"]["logonId"]:
                break
            msg = None

        if msg is None:
            self.fail("No Domain server authentication message")

        #
        # Validate that message contains the expected data
        #
        self.assertEquals("Authentication", msg["type"])
        self.assertEquals(logon_id, msg["Authentication"]["logonId"])
        self.assertEquals("SamLogon",
                          msg["Authentication"]["serviceDescription"])
        self.assertEquals(description,
                          msg["Authentication"]["authDescription"])
Example #3
0
    def test_samba_tool_showrepl_summary_forced_failure(self):
        """Tests 'samba-tool drs showrepl --summary' command when we break the
        network on purpose.
        """
        self.addCleanup(self._enable_all_repl, self.dc1)
        self._disable_all_repl(self.dc1)

        samdb1 = self.getSamDB("-H", "ldap://%s" % self.dc1, "-U",
                               self.cmdline_creds)
        samdb2 = self.getSamDB("-H", "ldap://%s" % self.dc2, "-U",
                               self.cmdline_creds)
        domain_dn = samdb1.domain_dn()

        # Add some things to NOT replicate
        ou1 = "OU=dc1.%x,%s" % (random.randrange(1 << 64), domain_dn)
        ou2 = "OU=dc2.%x,%s" % (random.randrange(1 << 64), domain_dn)
        samdb1.add({"dn": ou1, "objectclass": "organizationalUnit"})
        self.addCleanup(samdb1.delete, ou1, ['tree_delete:1'])
        samdb2.add({"dn": ou2, "objectclass": "organizationalUnit"})
        self.addCleanup(samdb2.delete, ou2, ['tree_delete:1'])

        dn1 = 'cn=u1.%%d,%s' % (ou1)
        dn2 = 'cn=u2.%%d,%s' % (ou2)

        try:
            for i in range(100):
                samdb1.add({"dn": dn1 % i, "objectclass": "user"})
                samdb2.add({"dn": dn2 % i, "objectclass": "user"})
                out = self.check_output("samba-tool drs showrepl --summary -v "
                                        "%s %s" %
                                        (self.dc1, self.cmdline_creds))
                out = get_string(out)
                self.assertStringsEqual('[ALL GOOD]', out, strip=True)
                out = self.check_output("samba-tool drs showrepl --summary -v "
                                        "--color=yes %s %s" %
                                        (self.dc2, self.cmdline_creds))
                out = get_string(out)
                self.assertIn('[ALL GOOD]', out)

        except samba.tests.BlackboxProcessError as e:
            e_stdout = get_string(e.stdout)
            e_stderr = get_string(e.stderr)
            print("Good, failed as expected after %d rounds: %r" % (i, e.cmd))
            self.assertIn('There are failing connections',
                          e_stdout,
                          msg=('stdout: %r\nstderr: %r\nretcode: %s'
                               '\nmessage: %r\ncmd: %r') %
                          (e_stdout, e_stderr, e.returncode, e.msg, e.cmd))
            self.assertRegexpMatches(
                e_stdout, r'result 845[67] '
                r'\(WERR_DS_DRA_(SINK|SOURCE)_DISABLED\)',
                msg=("The process should have failed "
                     "because replication was forced off, "
                     "but it failed for some other reason."))
            self.assertIn('consecutive failure(s).', e_stdout)
        else:
            self.fail("No DRS failure noticed after 100 rounds of trying")
Example #4
0
 def set_kdc_tdb(self, val):
     old_val = self.gp_db.gpostore.get(self.attribute)
     self.logger.info('%s was changed from %s to %s' %
                      (self.attribute, old_val, val))
     if val is not None:
         self.gp_db.gpostore.store(self.attribute, get_string(val))
         self.gp_db.store(str(self), self.attribute,
                          get_string(old_val) if old_val else None)
     else:
         self.gp_db.gpostore.delete(self.attribute)
         self.gp_db.delete(str(self), self.attribute)
    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,{0}'.format(
                self.samdb.get_config_basedn()))
        m['siteList'] = ldb.MessageElement(
            "CN={0},CN=Sites,{1}".format(site_name,
                                         self.samdb.get_config_basedn()),
            ldb.FLAG_MOD_ADD, "siteList")

        dns_c = "samba_dnsupdate --verbose --use-file={0}".format(tmp_uc)
        out = get_string(self.check_output(dns_c))
        self.assertFalse(site_name.lower() in out, out)

        self.samdb.modify(m)

        shutil.copyfile(uc_fn, tmp_uc)
        out = get_string(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")
Example #6
0
    def test_help_tree(self):
        # we call actual subprocesses, because we are probing the
        # actual help output where there is no sub-command. Don't copy
        # this if you have an actual command: for that use
        # self.runcmd() or self.runsubcmd().
        known_commands = [[]]
        failed_commands = []

        for i in range(4):
            new_commands = []
            for c in known_commands:
                line = ' '.join(['samba-tool'] + c + ['--help'])
                try:
                    output = self.check_output(line)
                except BlackboxProcessError as e:
                    output = e.stdout
                    failed_commands.append(c)
                output = get_string(output)
                tail = output.partition('Available subcommands:')[2]
                subcommands = re.findall(r'^\s*([\w-]+)\s+-', tail,
                                         re.MULTILINE)
                for s in subcommands:
                    new_commands.append(c + [s])

                # check that `samba-tool help X Y` == `samba-tool X Y --help`
                line = ' '.join(['samba-tool', 'help'] + c)
                try:
                    output2 = self.check_output(line)
                except BlackboxProcessError as e:
                    output2 = e.stdout
                    failed_commands.append(c)

                output2 = get_string(output2)
                self.assertEqual(output, output2)

                err = check_help_consistency(
                    output,
                    options_start='Options:',
                    options_end='Available subcommands:')
                if err is not None:
                    self.fail("consistency error with %s:\n%s" % (line, err))

            if not new_commands:
                break

            known_commands = new_commands

        self.assertEqual(failed_commands, [])
Example #7
0
    def test_samba_tool_showrepl_json(self):
        """Tests 'samba-tool drs showrepl --json' command.
        """
        out = self.check_output("samba-tool drs showrepl %s %s --json" %
                                (self.dc1, self.cmdline_creds))
        d = json.loads(get_string(out))
        self.assertEqual(set(d),
                         set(['repsFrom', 'repsTo', "NTDSConnections", "dsa"]))

        # dsa
        for k in ["objectGUID", "invocationId"]:
            self.assertRegexpMatches(d['dsa'][k], '^%s$' % GUID_RE)
        self.assertTrue(isinstance(d['dsa']["options"], int))

        # repsfrom and repsto
        for reps in (d['repsFrom'], d['repsTo']):
            for r in reps:
                for k in ('NC dn', "NTDS DN"):
                    self.assertRegexpMatches(r[k], '^%s$' % DN_RE)
                for k in ("last attempt time", "last attempt message",
                          "last success"):
                    self.assertTrue(isinstance(r[k], str))
                self.assertRegexpMatches(r["DSA objectGUID"], '^%s$' % GUID_RE)
                self.assertTrue(isinstance(r["consecutive failures"], int))

        # ntdsconnection
        for n in d["NTDSConnections"]:
            self.assertRegexpMatches(n["dns name"],
                                     r'^[\w]+\.samba\.example\.com$')
            self.assertRegexpMatches(n["name"], "^%s$" % GUID_RE)
            self.assertTrue(isinstance(n['enabled'], bool))
            self.assertTrue(isinstance(n['options'], int))
            self.assertTrue(isinstance(n['replicates NC'], list))
            self.assertRegexpMatches(n["remote DN"], "^%s$" % DN_RE)
    def setUp(self):
        super(AuthLogTestsNetLogonBadCreds, 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 = "NetLogonBad"
        self.machinepass = "******"
        self.remoteAddress = AS_SYSTEM_MAGIC_PATH_TOKEN
        self.base_dn = self.ldb.domain_dn()
        self.dn = ("cn=%s,cn=users,%s" % (self.netbios_name, self.base_dn))

        utf16pw = get_string('"' + self.machinepass + '"').encode('utf-16-le')
        self.ldb.add({
            "dn":
            self.dn,
            "objectclass":
            "computer",
            "sAMAccountName":
            "%s$" % self.netbios_name,
            "userAccountControl":
            str(UF_WORKSTATION_TRUST_ACCOUNT | UF_PASSWD_NOTREQD),
            "unicodePwd":
            utf16pw
        })
Example #9
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 = ('"%s"' % get_string(self.machine_pass)).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)
Example #10
0
 def string_to_key(cls, string, salt, params):
     utf8string = get_string(string)
     tmp = Credentials()
     tmp.set_anonymous()
     tmp.set_password(utf8string)
     nthash = tmp.get_nt_hash()
     return Key(cls.enctype, nthash)
Example #11
0
def run(cmd):
    """
    Run a cmd, return bytes str for py2 and unicode str for py3.

    NOTE: subprocess api always return bytes, in both py2 and py3.
    """
    output = subprocess.check_output(cmd).strip()
    return get_string(output)
Example #12
0
 def test_json_wellformed(self):
     """The output of ``--json`` commands must parse as JSON."""
     argv = "%s %s --json" % (COMMAND, self.subcmd)
     try:
         out = self.check_output(argv)
         json.loads(get_string(out))
     except samba.tests.BlackboxProcessError as e:
         self.fail("Error calling [%s]: %s" % (argv, e))
Example #13
0
    def _create_ou(self, samdb, name):
        ldif = """
dn: %s,%s
objectClass: organizationalUnit
""" % (name, self.domain_dn)
        samdb.add_ldif(ldif)
        res = samdb.search(base="%s,%s" % (name, self.domain_dn),
                           scope=SCOPE_BASE, attrs=["objectGUID"])
        return get_string(self._GUID_string(res[0]["objectGUID"][0]))
Example #14
0
 def setUp(self):
     super(NTLMAuthHelpersTests, self).setUp()
     self.username = os.environ["DC_USERNAME"]
     self.password = os.environ["DC_PASSWORD"]
     self.domain = os.environ["DOMAIN"]
     out = get_string(self.check_output("wbinfo -n %s" % self.username))
     self.group_sid = out.split(" ")[0]
     self.assertTrue(self.group_sid.startswith("S-1-5-21-"))
     self.bad_group_sid = self.group_sid[:-2]
Example #15
0
    def test_samba_tool_showrepl_pull_summary_all_good(self):
        """Tests 'samba-tool drs showrepl --pull-summary' command."""
        # To be sure that all is good we need to force replication
        # with everyone (because others might have it turned off), and
        # turn replication on for them in case they suddenly decide to
        # try again.
        #
        # We don't restore them to the non-auto-replication state.
        samdb1 = self.getSamDB("-H", "ldap://%s" % self.dc1, "-U",
                               self.cmdline_creds)
        self._enable_all_repl(self.dc1)
        self._force_all_reps(samdb1, self.dc1, 'inbound')
        self._force_all_reps(samdb1, self.dc1, 'outbound')
        try:
            out = self.check_output(
                "samba-tool drs showrepl --pull-summary %s %s" %
                (self.dc1, self.cmdline_creds))
            out = get_string(out)
            self.assertStringsEqual(out, "[ALL GOOD]\n")
            out = get_string(out)

            out = self.check_output("samba-tool drs showrepl --pull-summary "
                                    "--color=yes %s %s" %
                                    (self.dc1, self.cmdline_creds))
            out = get_string(out)
            self.assertStringsEqual(out, "\033[1;32m[ALL GOOD]\033[0m\n")

            # --verbose output is still quiet when all is good.
            out = self.check_output(
                "samba-tool drs showrepl --pull-summary -v %s %s" %
                (self.dc1, self.cmdline_creds))
            out = get_string(out)
            self.assertStringsEqual(out, "[ALL GOOD]\n")
            out = self.check_output(
                "samba-tool drs showrepl --pull-summary -v "
                "--color=yes %s %s" % (self.dc1, self.cmdline_creds))
            out = get_string(out)

        except samba.tests.BlackboxProcessError as e:
            self.fail(str(e))

        self.assertStringsEqual(out, "\033[1;32m[ALL GOOD]\033[0m\n")
Example #16
0
def encode_vlv_control(critical=1,
                       before=0,
                       after=0,
                       offset=None,
                       gte=None,
                       n=0,
                       cookie=None):

    s = "vlv:%d:%d:%d:" % (critical, before, after)

    if offset is not None:
        m = "%d:%d" % (offset, n)
    elif b':' in gte or b'\x00' in gte:
        gte = get_string(base64.b64encode(gte))
        m = "base64>=%s" % gte
    else:
        m = ">=%s" % get_string(gte)

    if cookie is None:
        return s + m

    return s + m + ':' + cookie
Example #17
0
    def netlogon(self):
        server = os.environ["SERVER"]
        host = os.environ["SERVER_IP"]
        lp = self.get_loadparm()

        credentials = self.get_credentials()

        session = system_session()
        ldb = SamDB(url="ldap://%s" % host,
                    session_info=session,
                    credentials=credentials,
                    lp=lp)
        machine_pass = samba.generate_random_password(32, 32)
        machine_name = MACHINE_NAME
        machine_dn = "cn=%s,%s" % (machine_name, ldb.domain_dn())

        delete_force(ldb, machine_dn)

        utf16pw = ('"%s"' % get_string(machine_pass)).encode('utf-16-le')
        ldb.add({
            "dn":
            machine_dn,
            "objectclass":
            "computer",
            "sAMAccountName":
            "%s$" % machine_name,
            "userAccountControl":
            str(UF_WORKSTATION_TRUST_ACCOUNT | UF_PASSWD_NOTREQD),
            "unicodePwd":
            utf16pw
        })

        machine_creds = Credentials()
        machine_creds.guess(lp)
        machine_creds.set_secure_channel_type(SEC_CHAN_WKSTA)
        machine_creds.set_kerberos_state(DONT_USE_KERBEROS)
        machine_creds.set_password(machine_pass)
        machine_creds.set_username(machine_name + "$")
        machine_creds.set_workstation(machine_name)

        netlogon.netlogon("ncacn_ip_tcp:%s[schannel,seal]" % server, lp,
                          machine_creds)

        delete_force(ldb, machine_dn)
Example #18
0
    def create_user_account(self):
        self.user_pass = self.random_password()
        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 = ('"%s"' % get_string(self.user_pass)).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.server)
Example #19
0
    def __init__(self,
                 domain_sid,
                 invocationid=None,
                 schemadn=None,
                 files=None,
                 override_prefixmap=None,
                 additional_prefixmap=None,
                 base_schema=None):
        from samba.provision import setup_path
        """Load schema for the SamDB from the AD schema files and
        samba4_schema.ldif

        :param samdb: Load a schema into a SamDB.
        :param schemadn: DN of the schema

        Returns the schema data loaded, to avoid double-parsing when then
        needing to add it to the db
        """

        if base_schema is None:
            base_schema = Schema.default_base_schema()

        self.base_schema = base_schema

        self.schemadn = schemadn
        # We need to have the am_rodc=False just to keep some warnings quiet -
        # this isn't a real SAM, so it's meaningless.
        self.ldb = SamDB(global_schema=False, am_rodc=False)
        if invocationid is not None:
            self.ldb.set_invocation_id(invocationid)

        self.schema_data = read_ms_schema(
            setup_path('ad-schema/%s' % Schema.base_schemas[base_schema][0]),
            setup_path('ad-schema/%s' % Schema.base_schemas[base_schema][1]))

        if files is not None:
            for file in files:
                data = get_string(open(file, 'rb').read())
                self.schema_data += data

        self.schema_data = substitute_var(self.schema_data,
                                          {"SCHEMADN": schemadn})
        check_all_substituted(self.schema_data)

        schema_version = str(Schema.get_version(base_schema))
        self.schema_dn_modify = read_and_sub_file(
            setup_path("provision_schema_basedn_modify.ldif"), {
                "SCHEMADN": schemadn,
                "OBJVERSION": schema_version
            })

        descr = b64encode(get_schema_descriptor(domain_sid)).decode('utf8')
        self.schema_dn_add = read_and_sub_file(
            setup_path("provision_schema_basedn.ldif"), {
                "SCHEMADN": schemadn,
                "DESCRIPTOR": descr
            })

        if override_prefixmap is not None:
            self.prefixmap_data = override_prefixmap
        else:
            self.prefixmap_data = open(setup_path("prefixMap.txt"),
                                       'rb').read()

        if additional_prefixmap is not None:
            for map in additional_prefixmap:
                self.prefixmap_data += "%s\n" % map

        self.prefixmap_data = b64encode(self.prefixmap_data).decode('utf8')

        # We don't actually add this ldif, just parse it
        prefixmap_ldif = "dn: %s\nprefixMap:: %s\n\n" % (self.schemadn,
                                                         self.prefixmap_data)
        self.set_from_ldif(prefixmap_ldif, self.schema_data, self.schemadn)
Example #20
0
 def GUID_string(self, guid):
     return get_string(self.samdb.schema_format_value("objectGUID", guid))
Example #21
0
    def test_setpassword(self):
        for user in self.users:
            newpasswd = self.random_password(16)
            (result, out, err) = self.runsubcmd("user", "setpassword",
                                                user["name"],
                                                "--newpassword=%s" % newpasswd,
                                                "-H", "ldap://%s" % os.environ["DC_SERVER"],
                                                "-U%s%%%s" % (os.environ["DC_USERNAME"], os.environ["DC_PASSWORD"]))
            self.assertCmdSuccess(result, out, err, "Ensure setpassword runs")
            self.assertEquals(err, "", "setpassword with url")
            self.assertMatch(out, "Changed password OK", "setpassword with url")

        attributes = "sAMAccountName,unicodePwd,supplementalCredentials,virtualClearTextUTF8,virtualClearTextUTF16,virtualSSHA,virtualSambaGPG"
        (result, out, err) = self.runsubcmd("user", "syncpasswords",
                                            "--cache-ldb-initialize",
                                            "--attributes=%s" % attributes,
                                            "--decrypt-samba-gpg")
        self.assertCmdSuccess(result, out, err, "Ensure syncpasswords --cache-ldb-initialize runs")
        self.assertEqual(err, "", "getpassword without url")
        cache_attrs = {
            "objectClass": {"value": "userSyncPasswords"},
            "samdbUrl": {},
            "dirsyncFilter": {},
            "dirsyncAttribute": {},
            "dirsyncControl": {"value": "dirsync:1:0:0"},
            "passwordAttribute": {},
            "decryptSambaGPG": {},
            "currentTime": {},
        }
        for a in cache_attrs.keys():
            v = cache_attrs[a].get("value", "")
            self.assertMatch(out, "%s: %s" % (a, v),
                             "syncpasswords --cache-ldb-initialize: %s: %s out[%s]" % (a, v, out))

        (result, out, err) = self.runsubcmd("user", "syncpasswords", "--no-wait")
        self.assertCmdSuccess(result, out, err, "Ensure syncpasswords --no-wait runs")
        self.assertEqual(err, "", "syncpasswords --no-wait")
        self.assertMatch(out, "dirsync_loop(): results 0",
                         "syncpasswords --no-wait: 'dirsync_loop(): results 0': out[%s]" % (out))
        for user in self.users:
            self.assertMatch(out, "sAMAccountName: %s" % (user["name"]),
                             "syncpasswords --no-wait: 'sAMAccountName': %s out[%s]" % (user["name"], out))

        for user in self.users:
            newpasswd = self.random_password(16)
            creds = credentials.Credentials()
            creds.set_anonymous()
            creds.set_password(newpasswd)
            nthash = creds.get_nt_hash()
            unicodePwd = base64.b64encode(creds.get_nt_hash()).decode('utf8')
            virtualClearTextUTF8 = base64.b64encode(get_bytes(newpasswd)).decode('utf8')
            virtualClearTextUTF16 = base64.b64encode(get_string(newpasswd).encode('utf-16-le')).decode('utf8')

            (result, out, err) = self.runsubcmd("user", "setpassword",
                                                user["name"],
                                                "--newpassword=%s" % newpasswd)
            self.assertCmdSuccess(result, out, err, "Ensure setpassword runs")
            self.assertEquals(err, "", "setpassword without url")
            self.assertMatch(out, "Changed password OK", "setpassword without url")

            (result, out, err) = self.runsubcmd("user", "syncpasswords", "--no-wait")
            self.assertCmdSuccess(result, out, err, "Ensure syncpasswords --no-wait runs")
            self.assertEqual(err, "", "syncpasswords --no-wait")
            self.assertMatch(out, "dirsync_loop(): results 0",
                             "syncpasswords --no-wait: 'dirsync_loop(): results 0': out[%s]" % (out))
            self.assertMatch(out, "sAMAccountName: %s" % (user["name"]),
                             "syncpasswords --no-wait: 'sAMAccountName': %s out[%s]" % (user["name"], out))
            self.assertMatch(out, "# unicodePwd::: REDACTED SECRET ATTRIBUTE",
                             "getpassword '# unicodePwd::: REDACTED SECRET ATTRIBUTE': out[%s]" % out)
            self.assertMatch(out, "unicodePwd:: %s" % unicodePwd,
                             "getpassword unicodePwd: out[%s]" % out)
            self.assertMatch(out, "# supplementalCredentials::: REDACTED SECRET ATTRIBUTE",
                             "getpassword '# supplementalCredentials::: REDACTED SECRET ATTRIBUTE': out[%s]" % out)
            self.assertMatch(out, "supplementalCredentials:: ",
                             "getpassword supplementalCredentials: out[%s]" % out)
            if "virtualSambaGPG:: " in out:
                self.assertMatch(out, "virtualClearTextUTF8:: %s" % virtualClearTextUTF8,
                                 "getpassword virtualClearTextUTF8: out[%s]" % out)
                self.assertMatch(out, "virtualClearTextUTF16:: %s" % virtualClearTextUTF16,
                                 "getpassword virtualClearTextUTF16: out[%s]" % out)
                self.assertMatch(out, "virtualSSHA: ",
                                 "getpassword virtualSSHA: out[%s]" % out)

            (result, out, err) = self.runsubcmd("user", "getpassword",
                                                user["name"],
                                                "--attributes=%s" % attributes,
                                                "--decrypt-samba-gpg")
            self.assertCmdSuccess(result, out, err, "Ensure getpassword runs")
            self.assertEqual(err, "", "getpassword without url")
            self.assertMatch(out, "Got password OK", "getpassword without url")
            self.assertMatch(out, "sAMAccountName: %s" % (user["name"]),
                             "getpassword: '******': %s out[%s]" % (user["name"], out))
            self.assertMatch(out, "unicodePwd:: %s" % unicodePwd,
                             "getpassword unicodePwd: out[%s]" % out)
            self.assertMatch(out, "supplementalCredentials:: ",
                             "getpassword supplementalCredentials: out[%s]" % out)
            self._verify_supplementalCredentials(out.replace("\nGot password OK\n", ""))
            if "virtualSambaGPG:: " in out:
                self.assertMatch(out, "virtualClearTextUTF8:: %s" % virtualClearTextUTF8,
                                 "getpassword virtualClearTextUTF8: out[%s]" % out)
                self.assertMatch(out, "virtualClearTextUTF16:: %s" % virtualClearTextUTF16,
                                 "getpassword virtualClearTextUTF16: out[%s]" % out)
                self.assertMatch(out, "virtualSSHA: ",
                                 "getpassword virtualSSHA: out[%s]" % out)

        for user in self.users:
            newpasswd = self.random_password(16)
            (result, out, err) = self.runsubcmd("user", "setpassword",
                                                user["name"],
                                                "--newpassword=%s" % newpasswd,
                                                "--must-change-at-next-login",
                                                "-H", "ldap://%s" % os.environ["DC_SERVER"],
                                                "-U%s%%%s" % (os.environ["DC_USERNAME"], os.environ["DC_PASSWORD"]))
            self.assertCmdSuccess(result, out, err, "Ensure setpassword runs")
            self.assertEquals(err, "", "setpassword with forced change")
            self.assertMatch(out, "Changed password OK", "setpassword with forced change")
Example #22
0
def read_ms_markdown(in_file, out_folder=None, out_dict={}):
    """
    Read Github documentation to produce forest wide udpates
    :param in_file: Forest-Wide-Updates.md
    :param out_folder: output folder
    :param out_dict: output dictionary
    """

    with open(in_file) as update_file:
        # There is a hidden ClaimPossibleValues in this md file
        html = markdown.markdown(re.sub(r'CN=<forest root domain.*?>',
                                        '${FOREST_ROOT_DOMAIN}',
                                        update_file.read()),
                                 output_format='xhtml')

    html = html.replace('CN=Schema,%ws', '${SCHEMA_DN}')

    tree = ET.fromstring('<root>' + html + '</root>')

    for node in tree:
        if node.text and node.text.startswith('|Operation'):
            # Strip first and last |
            updates = [
                x[1:len(x) - 1].split('|') for x in get_string(
                    ET.tostring(node, method='text')).splitlines()
            ]
            for update in updates[2:]:
                output = re.match('Operation (\d+): {(.*)}', update[0])
                if output:
                    # print output.group(1), output.group(2)
                    guid = output.group(2)
                    filename = "%s-{%s}.ldif" % (output.group(1).zfill(4),
                                                 guid)

                found = False

                if update[3].startswith('Created') or update[1].startswith(
                        'Added ACE'):
                    # Trigger the security descriptor code
                    # Reduce info to just the security descriptor
                    update[3] = update[3].split(':')[-1]

                    result = parse_ace(update[1], update[2], update[3])

                    if filename and out_folder is not None:
                        save_ldif(filename, result, out_folder)
                    else:
                        save_array(guid, result, out_dict)

                    continue

                for operation in operation_map:
                    if update[1].startswith(operation):
                        found = True

                        result = operation_map[operation](update[1], update[2],
                                                          update[3])

                        if filename and out_folder is not None:
                            save_ldif(filename, [result], out_folder)
                        else:
                            save_array(guid, [result], out_dict)

                        break

                if not found:
                    raise Exception(update)
Example #23
0
    def get_local_repl_data(self):
        drsuapi_connect(self)
        samdb_connect(self)

        # show domain information
        ntds_dn = self.samdb.get_dsServiceName()

        (site, server) = drs_parse_ntds_dn(ntds_dn)
        try:
            ntds = self.samdb.search(base=ntds_dn, scope=ldb.SCOPE_BASE, attrs=['options', 'objectGUID', 'invocationId'])
        except Exception as e:
            raise CommandError("Failed to search NTDS DN %s" % ntds_dn)

        dsa_details = {
            "options": int(attr_default(ntds[0], "options", 0)),
            "objectGUID": get_string(self.samdb.schema_format_value(
                "objectGUID", ntds[0]["objectGUID"][0])),
            "invocationId": get_string(self.samdb.schema_format_value(
                "objectGUID", ntds[0]["invocationId"][0]))
        }

        conn = self.samdb.search(base=ntds_dn, expression="(objectClass=nTDSConnection)")
        repsfrom = self.get_neighbours(drsuapi.DRSUAPI_DS_REPLICA_INFO_NEIGHBORS)
        repsto = self.get_neighbours(drsuapi.DRSUAPI_DS_REPLICA_INFO_REPSTO)

        conn_details = []
        for c in conn:
            c_rdn, sep, c_server_dn = str(c['fromServer'][0]).partition(',')
            d = {
                'name': str(c['name']),
                'remote DN': str(c['fromServer'][0]),
                'options': int(attr_default(c, 'options', 0)),
                'enabled': (get_string(attr_default(c, 'enabledConnection',
                                         'TRUE')).upper() == 'TRUE')
            }

            conn_details.append(d)
            try:
                c_server_res = self.samdb.search(base=c_server_dn,
                                                 scope=ldb.SCOPE_BASE,
                                                 attrs=["dnsHostName"])
                d['dns name'] = str(c_server_res[0]["dnsHostName"][0])
            except ldb.LdbError as e:
                (errno, _) = e.args
                if errno == ldb.ERR_NO_SUCH_OBJECT:
                    d['is deleted'] = True
            except (KeyError, IndexError):
                pass

            d['replicates NC'] = []
            for r in c.get('mS-DS-ReplicatesNCReason', []):
                a = str(r).split(':')
                d['replicates NC'].append((a[3], int(a[2])))

        return {
            'dsa': dsa_details,
            'repsFrom': repsfrom,
            'repsTo': repsto,
            'NTDSConnections': conn_details,
            'site': site,
            'server': server
        }
Example #24
0
    def _test_samba_tool_replicate_local_no_dns(self):
        """Check we can provision a database without DNS partitions
        (and then add them afterwards)."""

        server_rootdse, _ = self._get_rootDSE(self.dc1)
        nc_name = server_rootdse["defaultNamingContext"]
        server_ldap_service_name = str(server_rootdse["ldapServiceName"][0])
        server_realm = server_ldap_service_name.split(":")[0]
        creds = self.get_credentials()

        # We have to give it a different netbiosname every time
        # it runs, otherwise the collision causes strange issues
        # to happen. This should be different on different environments.
        netbiosname = "dns" + self.backend + self.dc1
        if len(netbiosname) > 15:
            netbiosname = netbiosname[:15]

        out = self.check_output(
            "samba-tool domain join %s dc --server=%s %s --targetdir=%s --option=netbiosname=%s %s --backend-store=%s"
            % (server_realm, self.dc1, self.cmdline_creds, self.tempdir,
               netbiosname, "--dns-backend=NONE", self.backend))

        new_dc_config_file = os.path.join(self.tempdir, "etc", "smb.conf")
        new_dc_sam = os.path.join(self.tempdir, "private", "sam.ldb")

        forestdns_dn = ldb.binary_encode('DC=ForestDNSZones,' + str(nc_name))
        domaindns_dn = ldb.binary_encode('DC=DomainDNSZones,' + str(nc_name))

        self.check_output(
            "samba-tool drs replicate --local %s %s %s %s -s %s --full-sync" %
            ("invalid", self.dc1, forestdns_dn, self.cmdline_creds,
             new_dc_config_file))

        self.check_output(
            "samba-tool drs replicate --local %s %s %s %s -s %s --full-sync" %
            ("invalid", self.dc1, domaindns_dn, self.cmdline_creds,
             new_dc_config_file))

        server_rootdse, samdb = self._get_rootDSE("ldb://" + new_dc_sam,
                                                  ldap_only=False)
        server_ds_name = ldb.binary_encode(
            server_rootdse["dsServiceName"][0].decode('utf-8'))

        # Show that Has-Master-NCs is fixed by samba_upgradedns
        res = samdb.search(base=server_ds_name,
                           expression="(msds-hasmasterncs=%s)" % forestdns_dn)
        self.assertEquals(len(res), 0)
        res = samdb.search(base=server_ds_name,
                           expression="(msds-hasmasterncs=%s)" % domaindns_dn)
        self.assertEquals(len(res), 0)

        self.check_output("samba_upgradedns -s %s" % (new_dc_config_file))

        res = samdb.search(base=server_ds_name,
                           expression="(msds-hasmasterncs=%s)" % forestdns_dn)
        self.assertEquals(len(res), 1)
        res = samdb.search(base=server_ds_name,
                           expression="(msds-hasmasterncs=%s)" % domaindns_dn)
        self.assertEquals(len(res), 1)

        # Show that replica locations is fixed by dbcheck
        res = samdb.search(
            controls=["search_options:1:2"],
            expression="(&(msds-nc-replica-locations=%s)(ncname=%s))" %
            (server_ds_name, forestdns_dn))
        self.assertEquals(len(res), 0)
        res = samdb.search(
            controls=["search_options:1:2"],
            expression="(&(msds-nc-replica-locations=%s)(ncname=%s))" %
            (server_ds_name, domaindns_dn))
        self.assertEquals(len(res), 0)

        try:
            # This fixes any forward-link-backward-link issues with the tools
            self.check_output(
                "samba-tool dbcheck -s %s --cross-ncs --fix --yes" %
                (new_dc_config_file))
        except BlackboxProcessError as e:
            self.assertTrue("Checked " in get_string(e.stdout))

        self.check_output("samba-tool dbcheck -s %s --cross-ncs" %
                          (new_dc_config_file))

        # Compare the two directories
        self.check_output(
            "samba-tool ldapcmp ldap://%s ldb://%s %s --filter=%s" %
            (self.dc1, new_dc_sam, self.cmdline_creds,
             "msDs-masteredBy,msDS-NC-Replica-Locations,msDS-hasMasterNCs"))

        # Check all ForestDNS connections and backlinks
        res = samdb.search(base=server_ds_name,
                           expression="(msds-hasmasterncs=%s)" % forestdns_dn)
        self.assertEquals(len(res), 1)
        res = samdb.search(base=forestdns_dn,
                           expression="(msds-masteredby=%s)" % server_ds_name)
        self.assertEquals(len(res), 1)
        res = samdb.search(
            controls=["search_options:1:2"],
            expression="(&(msds-nc-replica-locations=%s)(ncname=%s))" %
            (server_ds_name, forestdns_dn))
        self.assertEquals(len(res), 1)

        # Check all DomainDNS connections and backlinks
        res = samdb.search(base=server_ds_name,
                           expression="(msds-hasmasterncs=%s)" % domaindns_dn)
        self.assertEquals(len(res), 1)
        res = samdb.search(base=domaindns_dn,
                           expression="(msds-masteredby=%s)" % server_ds_name)
        self.assertEquals(len(res), 1)
        res = samdb.search(
            controls=["search_options:1:2"],
            expression="(&(msds-nc-replica-locations=%s)(ncname=%s))" %
            (server_ds_name, domaindns_dn))
        self.assertEquals(len(res), 1)

        # Demote the DC we created in the test
        self.check_output(
            "samba-tool domain demote --remove-other-dead-server=%s -H ldap://%s %s -s %s"
            % (netbiosname, self.dc1, self.cmdline_creds, new_dc_config_file))
Example #25
0
 def _GUID_string(self, guid):
     return get_string(
         self.test_ldb_dc.schema_format_value("objectGUID", guid))
Example #26
0
    def test_samba_tool_showrepl(self):
        """Tests 'samba-tool drs showrepl' command.
        """
        # Output should be like:
        #      <site-name>/<domain-name>
        #      DSA Options: <hex-options>
        #      DSA object GUID: <DSA-object-GUID>
        #      DSA invocationId: <DSA-invocationId>
        #      <Inbound-connections-list>
        #      <Outbound-connections-list>
        #      <KCC-objects>
        #      ...
        #   TODO: Perhaps we should check at least for
        #         DSA's objectGUDI and invocationId
        out = self.check_output("samba-tool drs showrepl "
                                "%s %s" % (self.dc1, self.cmdline_creds))

        out = get_string(out)
        # We want to assert that we are getting the same results, but
        # dates and GUIDs change randomly.
        #
        # There are sections with headers like ==== THIS ===="
        (header, _inbound, inbound, _outbound, outbound, _conn,
         conn) = out.split("====")

        self.assertEqual(_inbound, ' INBOUND NEIGHBORS ')
        self.assertEqual(_outbound, ' OUTBOUND NEIGHBORS ')
        self.assertEqual(_conn, ' KCC CONNECTION OBJECTS ')

        self.assertRegexpMatches(
            header, r'^Default-First-Site-Name\\LOCALDC\s+'
            r"DSA Options: %s\s+"
            r"DSA object GUID: %s\s+"
            r"DSA invocationId: %s" % (HEX8_RE, GUID_RE, GUID_RE))

        # We don't assert the DomainDnsZones and ForestDnsZones are
        # there because we don't know that they have been set up yet.

        for p in [
                'CN=Configuration,DC=samba,DC=example,DC=com',
                'DC=samba,DC=example,DC=com',
                'CN=Schema,CN=Configuration,DC=samba,DC=example,DC=com'
        ]:
            self.assertRegexpMatches(
                inbound,
                r'%s\n'
                r'\tDefault-First-Site-Name\\[A-Z]+ via RPC\n'
                r'\t\tDSA object GUID: %s\n'
                r'\t\tLast attempt @ [^\n]+\n'
                r'\t\t\d+ consecutive failure\(s\).\n'
                r'\t\tLast success @ [^\n]+\n'
                r'\n' % (p, GUID_RE),
                msg="%s inbound missing" % p)

            self.assertRegexpMatches(
                outbound,
                r'%s\n'
                r'\tDefault-First-Site-Name\\[A-Z]+ via RPC\n'
                r'\t\tDSA object GUID: %s\n'
                r'\t\tLast attempt @ [^\n]+\n'
                r'\t\t\d+ consecutive failure\(s\).\n'
                r'\t\tLast success @ [^\n]+\n'
                r'\n' % (p, GUID_RE),
                msg="%s outbound missing" % p)

        self.assertRegexpMatches(
            conn, r'Connection --\n'
            r'\tConnection name: %s\n'
            r'\tEnabled        : TRUE\n'
            r'\tServer DNS name : \w+.samba.example.com\n'
            r'\tServer DN name  : %s'
            r'\n' % (GUID_RE, DN_RE))