Example #1
0
class LDAPBase(object):
    def __init__(self,
                 host,
                 creds,
                 lp,
                 two=False,
                 quiet=False,
                 descriptor=False,
                 sort_aces=False,
                 verbose=False,
                 view="section",
                 base="",
                 scope="SUB",
                 outf=sys.stdout,
                 errf=sys.stderr,
                 skip_missing_dn=True):
        ldb_options = []
        samdb_url = host
        if not "://" in host:
            if os.path.isfile(host):
                samdb_url = "tdb://%s" % host
            else:
                samdb_url = "ldap://%s" % host
        # use 'paged_search' module when connecting remotely
        if samdb_url.lower().startswith("ldap://"):
            ldb_options = ["modules:paged_searches"]
        self.outf = outf
        self.errf = errf
        self.ldb = Ldb(url=samdb_url,
                       credentials=creds,
                       lp=lp,
                       options=ldb_options)
        self.search_base = base
        self.search_scope = scope
        self.two_domains = two
        self.quiet = quiet
        self.descriptor = descriptor
        self.sort_aces = sort_aces
        self.view = view
        self.verbose = verbose
        self.host = host
        self.skip_missing_dn = skip_missing_dn
        self.base_dn = str(self.ldb.get_default_basedn())
        self.root_dn = str(self.ldb.get_root_basedn())
        self.config_dn = str(self.ldb.get_config_basedn())
        self.schema_dn = str(self.ldb.get_schema_basedn())
        self.domain_netbios = self.find_netbios()
        self.server_names = self.find_servers()
        self.domain_name = re.sub("[Dd][Cc]=", "",
                                  self.base_dn).replace(",", ".")
        self.domain_sid = self.find_domain_sid()
        self.get_sid_map()
        #
        # Log some domain controller specific place-holers that are being used
        # when compare content of two DCs. Uncomment for DEBUG purposes.
        if self.two_domains and not self.quiet:
            self.outf.write("\n* Place-holders for %s:\n" % self.host)
            self.outf.write(4 * " " +
                            "${DOMAIN_DN}      => %s\n" % self.base_dn)
            self.outf.write(4 * " " +
                            "${DOMAIN_NETBIOS} => %s\n" % self.domain_netbios)
            self.outf.write(4 * " " +
                            "${SERVER_NAME}     => %s\n" % self.server_names)
            self.outf.write(4 * " " +
                            "${DOMAIN_NAME}    => %s\n" % self.domain_name)

    def find_domain_sid(self):
        res = self.ldb.search(base=self.base_dn,
                              expression="(objectClass=*)",
                              scope=SCOPE_BASE)
        return ndr_unpack(security.dom_sid, res[0]["objectSid"][0])

    def find_servers(self):
        """
        """
        res = self.ldb.search(base="OU=Domain Controllers,%s" % self.base_dn,
                              scope=SCOPE_SUBTREE,
                              expression="(objectClass=computer)",
                              attrs=["cn"])
        assert len(res) > 0
        srv = []
        for x in res:
            srv.append(x["cn"][0])
        return srv

    def find_netbios(self):
        res = self.ldb.search(base="CN=Partitions,%s" % self.config_dn,
                              scope=SCOPE_SUBTREE,
                              attrs=["nETBIOSName"])
        assert len(res) > 0
        for x in res:
            if "nETBIOSName" in x.keys():
                return x["nETBIOSName"][0]

    def object_exists(self, object_dn):
        res = None
        try:
            res = self.ldb.search(base=object_dn, scope=SCOPE_BASE)
        except LdbError, (enum, estr):
            if enum == ERR_NO_SUCH_OBJECT:
                return False
            raise
        return len(res) == 1
Example #2
0
class LDAPBase(object):

    def __init__(self, host, creds, lp,
                 two=False, quiet=False, descriptor=False, sort_aces=False, verbose=False,
                 view="section", base="", scope="SUB"):
        ldb_options = []
        samdb_url = host
        if not "://" in host:
            if os.path.isfile(host):
                samdb_url = "tdb://%s" % host
            else:
                samdb_url = "ldap://%s" % host
        # use 'paged_search' module when connecting remotely
        if samdb_url.lower().startswith("ldap://"):
            ldb_options = ["modules:paged_searches"]
        self.ldb = Ldb(url=samdb_url,
                       credentials=creds,
                       lp=lp,
                       options=ldb_options)
        self.search_base = base
        self.search_scope = scope
        self.two_domains = two
        self.quiet = quiet
        self.descriptor = descriptor
        self.sort_aces = sort_aces
        self.view = view
        self.verbose = verbose
        self.host = host
        self.base_dn = str(self.ldb.get_default_basedn())
        self.root_dn = str(self.ldb.get_root_basedn())
        self.config_dn = str(self.ldb.get_config_basedn())
        self.schema_dn = str(self.ldb.get_schema_basedn())
        self.domain_netbios = self.find_netbios()
        self.server_names = self.find_servers()
        self.domain_name = re.sub("[Dd][Cc]=", "", self.base_dn).replace(",", ".")
        self.domain_sid = self.find_domain_sid()
        self.get_guid_map()
        self.get_sid_map()
        #
        # Log some domain controller specific place-holers that are being used
        # when compare content of two DCs. Uncomment for DEBUG purposes.
        if self.two_domains and not self.quiet:
            self.outf.write("\n* Place-holders for %s:\n" % self.host)
            self.outf.write(4*" " + "${DOMAIN_DN}      => %s\n" %
                self.base_dn)
            self.outf.write(4*" " + "${DOMAIN_NETBIOS} => %s\n" %
                self.domain_netbios)
            self.outf.write(4*" " + "${SERVER_NAME}     => %s\n" %
                self.server_names)
            self.outf.write(4*" " + "${DOMAIN_NAME}    => %s\n" %
                self.domain_name)

    def find_domain_sid(self):
        res = self.ldb.search(base=self.base_dn, expression="(objectClass=*)", scope=SCOPE_BASE)
        return ndr_unpack(security.dom_sid,res[0]["objectSid"][0])

    def find_servers(self):
        """
        """
        res = self.ldb.search(base="OU=Domain Controllers,%s" % self.base_dn, \
                scope=SCOPE_SUBTREE, expression="(objectClass=computer)", attrs=["cn"])
        assert len(res) > 0
        srv = []
        for x in res:
            srv.append(x["cn"][0])
        return srv

    def find_netbios(self):
        res = self.ldb.search(base="CN=Partitions,%s" % self.config_dn, \
                scope=SCOPE_SUBTREE, attrs=["nETBIOSName"])
        assert len(res) > 0
        for x in res:
            if "nETBIOSName" in x.keys():
                return x["nETBIOSName"][0]

    def object_exists(self, object_dn):
        res = None
        try:
            res = self.ldb.search(base=object_dn, scope=SCOPE_BASE)
        except LdbError, (enum, estr):
            if enum == ERR_NO_SUCH_OBJECT:
                return False
            raise
        return len(res) == 1
Example #3
0
class LDAPBase(object):

    def __init__(self, host, creds, lp,
                 two=False, quiet=False, descriptor=False, sort_aces=False, verbose=False,
                 view="section", base="", scope="SUB",
                 outf=sys.stdout, errf=sys.stderr, skip_missing_dn=True):
        ldb_options = []
        samdb_url = host
        if "://" not in host:
            if os.path.isfile(host):
                samdb_url = "tdb://%s" % host
            else:
                samdb_url = "ldap://%s" % host
        # use 'paged_search' module when connecting remotely
        if samdb_url.lower().startswith("ldap://"):
            ldb_options = ["modules:paged_searches"]
        self.outf = outf
        self.errf = errf
        self.ldb = Ldb(url=samdb_url,
                       credentials=creds,
                       lp=lp,
                       options=ldb_options)
        self.search_base = base
        self.search_scope = scope
        self.two_domains = two
        self.quiet = quiet
        self.descriptor = descriptor
        self.sort_aces = sort_aces
        self.view = view
        self.verbose = verbose
        self.host = host
        self.skip_missing_dn = skip_missing_dn
        self.base_dn = str(self.ldb.get_default_basedn())
        self.root_dn = str(self.ldb.get_root_basedn())
        self.config_dn = str(self.ldb.get_config_basedn())
        self.schema_dn = str(self.ldb.get_schema_basedn())
        self.domain_netbios = self.find_netbios()
        self.server_names = self.find_servers()
        self.domain_name = re.sub("[Dd][Cc]=", "", self.base_dn).replace(",", ".")
        self.domain_sid = self.find_domain_sid()
        self.get_sid_map()
        #
        # Log some domain controller specific place-holers that are being used
        # when compare content of two DCs. Uncomment for DEBUG purposes.
        if self.two_domains and not self.quiet:
            self.outf.write("\n* Place-holders for %s:\n" % self.host)
            self.outf.write(4 * " " + "${DOMAIN_DN}      => %s\n" %
                            self.base_dn)
            self.outf.write(4 * " " + "${DOMAIN_NETBIOS} => %s\n" %
                            self.domain_netbios)
            self.outf.write(4 * " " + "${SERVER_NAME}     => %s\n" %
                            self.server_names)
            self.outf.write(4 * " " + "${DOMAIN_NAME}    => %s\n" %
                            self.domain_name)

    def find_domain_sid(self):
        res = self.ldb.search(base=self.base_dn, expression="(objectClass=*)", scope=SCOPE_BASE)
        return ndr_unpack(security.dom_sid, res[0]["objectSid"][0])

    def find_servers(self):
        """
        """
        res = self.ldb.search(base="OU=Domain Controllers,%s" % self.base_dn,
                              scope=SCOPE_SUBTREE, expression="(objectClass=computer)", attrs=["cn"])
        assert len(res) > 0
        return [str(x["cn"][0]) for x in res]

    def find_netbios(self):
        res = self.ldb.search(base="CN=Partitions,%s" % self.config_dn,
                              scope=SCOPE_SUBTREE, attrs=["nETBIOSName"])
        assert len(res) > 0
        for x in res:
            if "nETBIOSName" in x:
                return x["nETBIOSName"][0]

    def object_exists(self, object_dn):
        res = None
        try:
            res = self.ldb.search(base=object_dn, scope=SCOPE_BASE)
        except LdbError as e2:
            (enum, estr) = e2.args
            if enum == ERR_NO_SUCH_OBJECT:
                return False
            raise
        return len(res) == 1

    def delete_force(self, object_dn):
        try:
            self.ldb.delete(object_dn)
        except Ldb.LdbError as e:
            assert "No such object" in str(e)

    def get_attribute_name(self, key):
        """ Returns the real attribute name
            It resolved ranged results e.g. member;range=0-1499
        """

        m = RE_RANGED_RESULT.match(key)
        if m is None:
            return key

        return m.group(1)

    def get_attribute_values(self, object_dn, key, vals):
        """ Returns list with all attribute values
            It resolved ranged results e.g. member;range=0-1499
        """

        m = RE_RANGED_RESULT.match(key)
        if m is None:
            # no range, just return the values
            return vals

        attr = m.group(1)
        hi = int(m.group(3))

        # get additional values in a loop
        # until we get a response with '*' at the end
        while True:

            n = "%s;range=%d-*" % (attr, hi + 1)
            res = self.ldb.search(base=object_dn, scope=SCOPE_BASE, attrs=[n])
            assert len(res) == 1
            res = dict(res[0])
            del res["dn"]

            fm = None
            fvals = None

            for key in res:
                m = RE_RANGED_RESULT.match(key)

                if m is None:
                    continue

                if m.group(1) != attr:
                    continue

                fm = m
                fvals = list(res[key])
                break

            if fm is None:
                break

            vals.extend(fvals)
            if fm.group(3) == "*":
                # if we got "*" we're done
                break

            assert int(fm.group(2)) == hi + 1
            hi = int(fm.group(3))

        return vals

    def get_attributes(self, object_dn):
        """ Returns dict with all default visible attributes
        """
        res = self.ldb.search(base=object_dn, scope=SCOPE_BASE, attrs=["*"])
        assert len(res) == 1
        res = dict(res[0])
        # 'Dn' element is not iterable and we have it as 'distinguishedName'
        del res["dn"]

        attributes = {}
        for key, vals in res.items():
            name = self.get_attribute_name(key)
            # sort vals and return a list, help to compare
            vals = sorted(vals)
            attributes[name] = self.get_attribute_values(object_dn, key, vals)

        return attributes

    def get_descriptor_sddl(self, object_dn):
        res = self.ldb.search(base=object_dn, scope=SCOPE_BASE, attrs=["nTSecurityDescriptor"])
        desc = res[0]["nTSecurityDescriptor"][0]
        desc = ndr_unpack(security.descriptor, desc)
        return desc.as_sddl(self.domain_sid)

    def guid_as_string(self, guid_blob):
        """ Translate binary representation of schemaIDGUID to standard string representation.
            @gid_blob: binary schemaIDGUID
        """
        blob = "%s" % guid_blob
        stops = [4, 2, 2, 2, 6]
        index = 0
        res = ""
        x = 0
        while x < len(stops):
            tmp = ""
            y = 0
            while y < stops[x]:
                c = hex(ord(blob[index])).replace("0x", "")
                c = [None, "0" + c, c][len(c)]
                if 2 * index < len(blob):
                    tmp = c + tmp
                else:
                    tmp += c
                index += 1
                y += 1
            res += tmp + " "
            x += 1
        assert index == len(blob)
        return res.strip().replace(" ", "-")

    def get_sid_map(self):
        """ Build dictionary that maps GUID to 'name' attribute found in Schema or Extended-Rights.
        """
        self.sid_map = {}
        res = self.ldb.search(base=self.base_dn,
                              expression="(objectSid=*)", scope=SCOPE_SUBTREE, attrs=["objectSid", "sAMAccountName"])
        for item in res:
            try:
                self.sid_map["%s" % ndr_unpack(security.dom_sid, item["objectSid"][0])] = str(item["sAMAccountName"][0])
            except KeyError:
                pass
Example #4
0
class LDAPBase(object):

    def __init__(self, host, creds, lp,
                 two=False, quiet=False, descriptor=False, sort_aces=False, verbose=False,
                 view="section", base="", scope="SUB",
                 outf=sys.stdout, errf=sys.stderr, skip_missing_dn=True):
        ldb_options = []
        samdb_url = host
        if not "://" in host:
            if os.path.isfile(host):
                samdb_url = "tdb://%s" % host
            else:
                samdb_url = "ldap://%s" % host
        # use 'paged_search' module when connecting remotely
        if samdb_url.lower().startswith("ldap://"):
            ldb_options = ["modules:paged_searches"]
        self.outf = outf
        self.errf = errf
        self.ldb = Ldb(url=samdb_url,
                       credentials=creds,
                       lp=lp,
                       options=ldb_options)
        self.search_base = base
        self.search_scope = scope
        self.two_domains = two
        self.quiet = quiet
        self.descriptor = descriptor
        self.sort_aces = sort_aces
        self.view = view
        self.verbose = verbose
        self.host = host
        self.skip_missing_dn = skip_missing_dn
        self.base_dn = str(self.ldb.get_default_basedn())
        self.root_dn = str(self.ldb.get_root_basedn())
        self.config_dn = str(self.ldb.get_config_basedn())
        self.schema_dn = str(self.ldb.get_schema_basedn())
        self.domain_netbios = self.find_netbios()
        self.server_names = self.find_servers()
        self.domain_name = re.sub("[Dd][Cc]=", "", self.base_dn).replace(",", ".")
        self.domain_sid = self.find_domain_sid()
        self.get_sid_map()
        #
        # Log some domain controller specific place-holers that are being used
        # when compare content of two DCs. Uncomment for DEBUG purposes.
        if self.two_domains and not self.quiet:
            self.outf.write("\n* Place-holders for %s:\n" % self.host)
            self.outf.write(4*" " + "${DOMAIN_DN}      => %s\n" %
                self.base_dn)
            self.outf.write(4*" " + "${DOMAIN_NETBIOS} => %s\n" %
                self.domain_netbios)
            self.outf.write(4*" " + "${SERVER_NAME}     => %s\n" %
                self.server_names)
            self.outf.write(4*" " + "${DOMAIN_NAME}    => %s\n" %
                self.domain_name)

    def find_domain_sid(self):
        res = self.ldb.search(base=self.base_dn, expression="(objectClass=*)", scope=SCOPE_BASE)
        return ndr_unpack(security.dom_sid,res[0]["objectSid"][0])

    def find_servers(self):
        """
        """
        res = self.ldb.search(base="OU=Domain Controllers,%s" % self.base_dn,
                scope=SCOPE_SUBTREE, expression="(objectClass=computer)", attrs=["cn"])
        assert len(res) > 0
        srv = []
        for x in res:
            srv.append(x["cn"][0])
        return srv

    def find_netbios(self):
        res = self.ldb.search(base="CN=Partitions,%s" % self.config_dn,
                scope=SCOPE_SUBTREE, attrs=["nETBIOSName"])
        assert len(res) > 0
        for x in res:
            if "nETBIOSName" in x.keys():
                return x["nETBIOSName"][0]

    def object_exists(self, object_dn):
        res = None
        try:
            res = self.ldb.search(base=object_dn, scope=SCOPE_BASE)
        except LdbError as e:
            (enum, estr) = e.args
            if enum == ERR_NO_SUCH_OBJECT:
                return False
            raise
        return len(res) == 1

    def delete_force(self, object_dn):
        try:
            self.ldb.delete(object_dn)
        except Ldb.LdbError as e:
            assert "No such object" in str(e)

    def get_attribute_name(self, key):
        """ Returns the real attribute name
            It resolved ranged results e.g. member;range=0-1499
        """

        r = re.compile("^([^;]+);range=(\d+)-(\d+|\*)$")

        m = r.match(key)
        if m is None:
            return key

        return m.group(1)

    def get_attribute_values(self, object_dn, key, vals):
        """ Returns list with all attribute values
            It resolved ranged results e.g. member;range=0-1499
        """

        r = re.compile("^([^;]+);range=(\d+)-(\d+|\*)$")

        m = r.match(key)
        if m is None:
            # no range, just return the values
            return vals

        attr = m.group(1)
        hi = int(m.group(3))

        # get additional values in a loop
        # until we get a response with '*' at the end
        while True:

            n = "%s;range=%d-*" % (attr, hi + 1)
            res = self.ldb.search(base=object_dn, scope=SCOPE_BASE, attrs=[n])
            assert len(res) == 1
            res = dict(res[0])
            del res["dn"]

            fm = None
            fvals = None

            for key in res.keys():
                m = r.match(key)

                if m is None:
                    continue

                if m.group(1) != attr:
                    continue

                fm = m
                fvals = list(res[key])
                break

            if fm is None:
                break

            vals.extend(fvals)
            if fm.group(3) == "*":
                # if we got "*" we're done
                break

            assert int(fm.group(2)) == hi + 1
            hi = int(fm.group(3))

        return vals

    def get_attributes(self, object_dn):
        """ Returns dict with all default visible attributes
        """
        res = self.ldb.search(base=object_dn, scope=SCOPE_BASE, attrs=["*"])
        assert len(res) == 1
        res = dict(res[0])
        # 'Dn' element is not iterable and we have it as 'distinguishedName'
        del res["dn"]
        for key in res.keys():
            vals = list(res[key])
            del res[key]
            name = self.get_attribute_name(key)
            res[name] = self.get_attribute_values(object_dn, key, vals)

        return res

    def get_descriptor_sddl(self, object_dn):
        res = self.ldb.search(base=object_dn, scope=SCOPE_BASE, attrs=["nTSecurityDescriptor"])
        desc = res[0]["nTSecurityDescriptor"][0]
        desc = ndr_unpack(security.descriptor, desc)
        return desc.as_sddl(self.domain_sid)

    def guid_as_string(self, guid_blob):
        """ Translate binary representation of schemaIDGUID to standard string representation.
            @gid_blob: binary schemaIDGUID
        """
        blob = "%s" % guid_blob
        stops = [4, 2, 2, 2, 6]
        index = 0
        res = ""
        x = 0
        while x < len(stops):
            tmp = ""
            y = 0
            while y < stops[x]:
                c = hex(ord(blob[index])).replace("0x", "")
                c = [None, "0" + c, c][len(c)]
                if 2 * index < len(blob):
                    tmp = c + tmp
                else:
                    tmp += c
                index += 1
                y += 1
            res += tmp + " "
            x += 1
        assert index == len(blob)
        return res.strip().replace(" ", "-")

    def get_sid_map(self):
        """ Build dictionary that maps GUID to 'name' attribute found in Schema or Extended-Rights.
        """
        self.sid_map = {}
        res = self.ldb.search(base=self.base_dn,
                              expression="(objectSid=*)", scope=SCOPE_SUBTREE, attrs=["objectSid", "sAMAccountName"])
        for item in res:
            try:
                self.sid_map["%s" % ndr_unpack(security.dom_sid, item["objectSid"][0])] = item["sAMAccountName"][0]
            except KeyError:
                pass