class ActiveDirectory(object):
    class ActiveDirectoryHandle(object):
        def __init__(self, host, binddn, bindpw):
            self.__host = host
            self.__binddn = binddn
            self.__bindpw = bindpw
            self.__dchandle = self.get_dc_handle()
            self.__gchandle = self.get_gc_handle()

        def get_connection_handle(self, host, port, binddn, bindpw):
            server = ldap3.Server(host, port=port, get_info=ldap3.ALL)
            conn = ldap3.Connection(server, user=binddn, password=bindpw,
                authentication=ldap3.AUTH_SIMPLE, auto_bind=True)
            return conn

        @property
        def dchandle(self):
            return self.__dchandle

        def get_dc_handle(self):
            return self.get_connection_handle(
                self.__host,
                389,
                self.__binddn,
                self.__bindpw
            )

        @property
        def gchandle(self):
            return self.__gchandle

        def get_gc_handle(self):
            return self.get_connection_handle(
                self.__host,
                3268,
                self.__binddn,
                self.__bindpw
            )

    def __init__(self, *args,  **kwargs):
        self.dispatcher = kwargs.get('dispatcher')
        self.datastore = kwargs.get('datastore')

        sys.path.extend(['/usr/local/lib/dsd/modules/'])
        from dsdns import DSDNS

        self.dsdns = DSDNS(
            dispatcher=self.dispatcher,
            datastore=self.datastore,
        )

    def get_directory_type(self):
        return "activedirectory"

    def get_connection_handle(self, host, binddn, bindpw):
        return self.ActiveDirectoryHandle(host, binddn, bindpw)

    def get_ldap_servers(self, domain, site=None):
        dcs = []
        if not domain:
            return dcs

        host = "_ldap._tcp.%s" % domain
        if site:
            host = "_ldap._tcp.%s._sites.%s" % (site, domain)

        logger.debug("get_ldap_servers: host = %s", host)
        dcs = self.dsdns.get_SRV_records(host)

        for dc in dcs:
            logger.debug("get_ldap_servers: found %s", dc)

        return dcs

    def get_domain_controllers(self, domain, site=None):
        dcs = []
        if not domain:
            return dcs

        host = "_ldap._tcp.dc._msdcs.%s" % domain
        if site:
            host = "_ldap._tcp.%s._sites.dc._msdcs.%s" % (site, domain)

        logger.debug("get_domain_controllers: host = %s", host)
        dcs = self.dsdns.get_SRV_records(host)

        for dc in dcs:
            logger.debug("get_domain_controllers: found %s", dc)

        return dcs

    def get_primary_domain_controllers(self, domain):
        pdcs = []
        if not domain:
            return pdcs

        host = "_ldap._tcp.pdc._msdcs.%s"

        logger.debug("get_primary_domain_controllers: host = %s", host)
        pdcs = self.dsdns.get_SRV_records(host)

        for pdc in pdcs:
            logger.debug("get_primary_domain_controllers: found %s", pdc)

        return pdcs

    def get_global_catalog_servers(self, domain, site=None):
        gcs = []
        if not domain:
            return gcs

        host = "_gc._tcp.%s" % domain
        if site:
            host = "_gc._tcp.%s._sites.%s" % (site, domain)

        logger.debug("get_global_catalog_servers: host = %s", host)
        gcs = self.dsdns.get_SRV_records(host)

        for gc in gcs:
            logger.debug("get_global_catalog_servers: found %s", gc)

        return gcs

    def get_forest_global_catalog_servers(self, forest, site=None):
        fgcs = []
        if not forest:
            return fgcs

        host = "_ldap._tcp.gc._msdcs.%s" % forest
        if site:
            host = "_ldap._tcp.%s._sites.gc._msdcs.%s" % (site, forest)

        logger.debug("get_forest_global_catalog_servers: host = %s", host)
        fgcs = self.dsdns.get_SRV_records(host)

        for fgc in fgcs:
            logger.debug("get_forest_global_catalog_servers: found %s", fgc)

        return fgcs

    def get_kerberos_servers(self, domain, site=None):
        kdcs = []
        if not domain:
            return kdcs

        host = "_kerberos._tcp.%s" % domain
        if site:
            host = "_kerberos._tcp.%s._sites.%s" % (site, domain)

        logger.debug("get_kerberos_servers: host = %s", host)
        kdcs = self.dsdns.get_SRV_records(host)

        for kdc in kdcs:
            logger.debug("get_kerberos_servers: found %s", kdc)

        return kdcs

    def get_kerberos_domain_controllers(self, domain, site=None):
        kdcs = []
        if not domain:
            return kdcs

        host = "_kerberos._tcp.dc._msdcs.%s" % domain
        if site:
            host = "_kerberos._tcp.%s._sites.dc._msdcs.%s" % (site, domain)

        logger.debug("get_kerberos_domain_controllers: host = %s", host)
        kdcs = self.dsdns.get_SRV_records(host)

        for kdc in kdcs:
            logger.debug("get_kerberos_domain_controllers: found %s", kdc)

        return kdcs

    def get_kpasswd_servers(self, domain):
        kpws = []
        if not domain:
            return kpws

        host = "_kpasswd._tcp.%s" % domain
        logger.debug("get_kpasswd_servers: host = %s", host)

        kpws = self.dsdns.get_SRV_records(host)

        for kpw in kpws:
            logger.debug("get_kpasswd_servers: found %s", kpwd)

        return kpws

    def get_rootDSE(self, handle):
        dchandle = handle.dchandle

        dchandle.search('',
            '(objectclass=*)',
            search_scope=ldap3.BASE,
            attributes=ldap3.ALL_ATTRIBUTES,
        )

        if not dchandle.result:
            return None

        if not dchandle.response:
            return None

        results = dchandle.response[0]
        if not results:
            return None

        attributes = results.get('attributes', None)
        if not attributes:
            return None

        return attributes

    def get_rootDN(self, handle):
        rootDSE = self.get_rootDSE(handle)
        if not rootDSE:
            return None

        rootDN = rootDSE.get('rootDomainNamingContext', None)
        if not rootDN:
            return None

        rootDN = rootDN[0].strip()
        logger.debug("get_rootDN: rootDN = %s", rootDN)

        return rootDN
        
    def get_baseDN(self, handle):
        rootDSE = self.get_rootDSE(handle)
        if not rootDSE:
            return None

        baseDN = rootDSE.get('defaultNamingContext', None)
        if not baseDN:
            return None

        baseDN = baseDN[0].strip()
        logger.debug("get_baseDN: baseDN = %s", baseDN)

        return baseDN

    def get_configurationDN(self, handle):
        rootDSE = self.get_rootDSE(handle)
        if not rootDSE:
            return None

        configurationDN = rootDSE.get('configurationNamingContext', None)
        if not configurationDN:
            return None

        configurationDN = configurationDN[0].strip()
        logger.debug("get_configurationDN: configurationDN = %s", configurationDN)

        return configurationDN

    def get_forest_functionality(self, handle):
        rootDSE = self.get_rootDSE(handle)
        if not rootDSE:
            return None

        forest_functionality = rootDSE.get('forestFunctionality', None)
        if not forest_functionality:
            return None

        forest_functionality = int(forest_functionality[0].strip())
        logger.debug("get_forest_functionality: forest_functionality = %d", forest_functionality)

        return forest_functionality

    def get_domain_functionality(self, handle):
        rootDSE = self.get_rootDSE(handle)
        if not rootDSE:
            return None

        domain_functionality = rootDSE.get('domainFunctionality', None)
        if not domain_functionality:
            return None

        domain_functionality = int(domain_functionality[0].strip())
        logger.debug("get_domain_functionality: domain_functionality = %d", domain_functionality)

        return domain_functionality

    def get_domain_controller_functionality(self, handle):
        rootDSE = self.get_rootDSE(handle)
        if not rootDSE:
            return None

        domain_controller_functionality = rootDSE.get('domainControllerFunctionality', None)
        if not domain_controller_functionality:
            return None

        domain_controller_functionality = int(domain_controller_functionality[0].strip())
        logger.debug("get_domain_controller_functionality: domain_controller_functionality = %d", domain_controller_functionality)

        return domain_controller_functionality

    def get_domain_netbiosname(self, handle):
        dchandle = handle.dchandle

        baseDN = self.get_baseDN(handle)
        configurationDN = self.get_configurationDN(handle)

        filter = "(&(objectcategory=crossref)(nCName=%s))" % baseDN
        logger.debug("get_domain_netbiosname: filter = %s", filter)

        dchandle.search(configurationDN,
            filter,
            search_scope=ldap3.SUBTREE,
            attributes=ldap3.ALL_ATTRIBUTES
        )

        if not dchandle.result:
            return None

        if not dchandle.response:
            return None

        attributes = dchandle.response[0].get('attributes', None)
        if not attributes:
            return None

        netbiosname = attributes.get('nETBIOSName', None)
        if not netbiosname:
            return None

        netbiosname = netbiosname.strip()
        logger.debug("get_domain_netbiosname: netbiosname = %s", netbiosname)

        return netbiosname

    def get_partitions(self, handle, **kwargs):
        dchandle = handle.dchandle

        configurationDN = self.get_configurationDN(handle)
        baseDN = "CN=Partitions,%s" % configurationDN

        filter = None
        keys = ['netbiosname', 'name', 'cn', 'dn', 'distinguishedname', 'ncname']
        for k in keys:
            if kwargs.has_key(k) and kwargs[k]:
                filter = "(%s=%s)" % (k, kwargs[k])
                break

        if filter is None:
            filter = "(cn=*)"

        logger.debug("get_partitions: filter = %s", filter)

        dchandle.search(baseDN,
            filter, 
            search_scope=ldap3.SUBTREE,
            attributes=ldap3.ALL_ATTRIBUTES,
        )

        if not dchandle.result:
            return None

        partitions = []
        for result in dchandle.response:
            attributes = result.get('attributes', None)
            if not attributes: 
                continue
            partitions.append(attributes)

        return partitions

    def get_root_domain(self, handle):
        rootDN = self.get_rootDN(handle)
        partitions = self.get_partitions(handle, ncname=rootDN)
        if not partitions:
            return None

        domain = None
        try: 
            domain = partitions[0]['dnsRoot'][0]

        except: 
            return None

        domain = domain.strip()
        logger.debug("get_root_domain: domain = %s", domain)

        return domain

    def get_domain(self, handle, **kwargs):
        partitions = self.get_partitions(handle, **kwargs)
        if not partitions:
            return None 

        domain = None
        try:
            domain = partitions[0]['dnsRoot'][0]

        except:
            return None

        domain = domain.strip()
        logger.debug("get_domain: domain = %s", domain)

        return domain

    def get_domains(self, handle, **kwargs):
        dchandle = handle.dchandle
        gchandle = handle.gchandle

        gchandle.search('',
            '(objectclass=domain)',
            search_scope=ldap3.SUBTREE,
            attributes=ldap3.ALL_ATTRIBUTES
        )

        if not gchandle.result:
            return None

        domains = []
        for result in gchandle.response:
            attributes = result.get('attributes', None)
            if not attributes: 
                continue
 
            domains.append(attributes)

        configurationDN = self.get_configurationDN(handle)
        results = []

        haskey = False
        keys = ['netbiosname', 'name', 'cn', 'dn', 'distinguishedname', 'ncname']
        for domain in domains:
            dn = domain.get('distinguishedName', None)
            if not dn:
                continue
            dn = dn.strip()

            filter = None
            if len(kwargs) > 0:
                haskey = True
                for k in keys: 
                    if kwargs.has_key(k) and kwargs[k]:
                        filter = "(&(objectcategory=crossref)(%s=%s))" % (k, kwargs[k])
                        break

            if filter is None:
                filter = "(&(objectcategory=crossref)(nCName=%s))" % dn

            logger.debug("get_domains: filter = %s", filter)

            dchandle.search(
                configurationDN,
                filter,
                search_scope=ldap3.SUBTREE,
                attributes=ldap3.ALL_ATTRIBUTES
            )

            if not dchandle.result:
                continue

            for result in dchandle.response:
                attributes = result.get('attributes', None)
                if not attributes: 
                    continue

                results.append(attributes)

            if haskey:
                break 

        return results

    def get_subnets(self, handle, **kwargs):
        dchandle = handle.dchandle

        configurationDN = self.get_configurationDN(handle)
        baseDN = "CN=Subnets,CN=Sites,%s" % configurationDN
        filter = '(objectClass=subnet)'

        keys = ['distinguishedname', 'cn', 'name', 'siteobjectbl']
        for k in keys:
            if kwargs.has_key(k) and kwargs[k]:
                filter = "(&%s(%s=%s))" % (filter, k, kwargs[k])

        subnets = []
        logger.debug("get_subnets: filter = %s", filter)

        dchandle.search(
            configurationDN,
            filter,
            search_scope=ldap3.SUBTREE,
            attributes=ldap3.ALL_ATTRIBUTES
        )

        if not dchandle.result:
            return subnets

        for result in dchandle.response:
            attributes = result.get('attributes', None)
            if not attributes: 
                return subnets

            subnets.append(attributes)

        return subnets

    def get_sites(self, handle, **kwargs):
        dchandle = handle.dchandle

        configurationDN = self.get_configurationDN(handle)
        baseDN = "CN=Sites,%s" % configurationDN
        filter = '(objectClass=site)'

        keys = ['distinguishedname', 'cn', 'name', 'siteobjectbl']
        for k in keys:
            if kwargs.has_key(k) and kwargs[k]:
                filter = "(&%s(%s=%s))" % (filter, k, kwargs[k])

        sites = []
        logger.debug("get_sites: filter = %s", filter)

        dchandle.search(
            configurationDN,
            filter,
            search_scope=ldap3.SUBTREE,
            attributes=ldap3.ALL_ATTRIBUTES
        )

        if not dchandle.result:
            return sites

        for result in dchandle.response:
            attributes = result.get('attributes', None)
            if not attributes: 
                return sites

            sites.append(attributes)

        return sites

    def get_machine_account(self, handle, hostname):
        dchandle = handle.dchandle

        hostname = hostname.split('.')[0]
        baseDN = self.get_baseDN(handle) 

        filter = '(&(objectClass=computer)(sAMAccountName=%s$))' % hostname
        logger.debug("get_machine_account: filter = %s", filter)

        dchandle.search(
            baseDN,
            filter,
            search_scope=ldap3.SUBTREE,
            attributes=ldap3.ALL_ATTRIBUTES
        )

        if not dchandle.result:
            return None

        if not dchandle.response:
            return None

        attributes = dchandle.response[0].get('attributes', None)
        if not attributes: 
            return None

        return attributes

    def get_users(self, handle, **kwargs):
        dchandle = handle.dchandle

        baseDN = self.get_baseDN(handle) 
        filter = '(&(|(objectclass=user)(objectclass=person))(sAMAccountName=*))'
        logger.debug("get_users: filter = %s", filter)

        dchandle.search(
            baseDN,
            filter,
            search_scope=ldap3.SUBTREE,
            attributes=ldap3.ALL_ATTRIBUTES
        )
         
        users = []
        if not dchandle.result:
            return users

        filter_func = lambda x: 'sAMAccountType' in x and \
            (long(x['sAMAccountType']) != SAM_USER_OBJECT)

        if 'filter' in kwargs and kwargs['filter']:
            filter_func = kwargs['filter']

        for result in dchandle.response:
            attributes = result.get('attributes', None)
            if not attributes: 
                continue

            if filter_func:
                if filter_func(attributes):
                    continue

            users.append(attributes)
 
        return users
         
    def get_groups(self, handle, **kwargs):
        dchandle = handle.dchandle

        baseDN = self.get_baseDN(handle) 
        filter = '(&(objectclass=group)(sAMAccountName=*))'
        logger.debug("get_groups: filter = %s", filter)

        dchandle.search(
            baseDN,
            filter,
            search_scope=ldap3.SUBTREE,
            attributes=ldap3.ALL_ATTRIBUTES
        )
         
        groups = []
        if not dchandle.result:
            return groups

        filter_func = lambda x: 'groupType' in x and \
            (long(x['groupType']) & GROUP_TYPE_BUILTIN_LOCAL_GROUP)

        if 'filter' in kwargs and kwargs['filter']:
            filter_func = kwargs['filter']

        for result in dchandle.response:
            attributes = result.get('attributes', None)
            if not attributes: 
                continue

            if filter_func:
                if filter_func(attributes):
                    continue

            groups.append(attributes)

        return groups

    def get_user(self, handle, user):
        dchandle = handle.dchandle

        baseDN = self.get_baseDN(handle)
        filter = '(&(|(objectclass=user)(objectclass=person))' \
            '(sAMAccountName=%s))' % user
        logger.debug("get_user: filter = %s", filter)

        dchandle.search(
            baseDN,
            filter,
            search_scope=ldap3.SUBTREE,
            attributes=ldap3.ALL_ATTRIBUTES
        )

        if not dchandle.result:
            return []

        if not dchandle.response:
            return []

        attributes = dchandle.response[0].get('attributes', None)
        if not attributes: 
            return []

        return attributes  

    def get_group(self, handle, group):
        dchandle = handle.dchandle

        baseDN = self.get_baseDN(handle)
        filter = '(&(objectclass=group)(sAMAccountName=%s))' % group
        logger.debug("get_group: filter = %s", filter)

        dchandle.search(
            baseDN,
            filter,
            search_scope=ldap3.SUBTREE,
            attributes=ldap3.ALL_ATTRIBUTES
        )

        if not dchandle.result:
            return []

        if not dchandle.response:
            return []

        attributes = dchandle.response[0].get('attributes', None)
        if not attributes: 
            return []

        return attributes  

    def get_userDN(self, handle, user):
        user = self.get_user(handle, user)
        if not user: 
            return None

        userDN = user['distinguishedName'].strip()
        logger.debug("get_userDN: userDN = %s", userDN)

        return userDN

    def get_groupDN(self, handle, group):
        group = self.get_group(handle, group)
        if not group: 
            return None

        groupDN = group['distinguishedName'].strip()
        logger.debug("get_groupDN: groupDN = %s", groupDN)

        return groupDN
class Kerberos(object):
    def __init__(self, *args,  **kwargs):
        self.dispatcher = kwargs.get('dispatcher')
        self.datastore = kwargs.get('datastore')

        sys.path.extend(['/usr/local/lib/dsd/modules/'])
        from dsdns import DSDNS

        self.dsdns = DSDNS(
            dispatcher=self.dispatcher,
            datastore=self.datastore,
        )

    def get_directory_type(self):
        return "kerberos"

    def get_kerberos_servers(self, domain, proto='tcp'):
        kerberos_servers = []

        if not domain:
            return kerberos_servers
        if proto is None:
            proto = ['tcp', 'udp']
            
        if 'tcp' in proto:
            tcp_host = "_kerberos._tcp.%s" % domain
            
            logger.debug("get_kerberos_servers: tcp_host = %s", tcp_host)
            tcp_kerberos_servers = self.dsdns.get_SRV_records(tcp_host)
            if tcp_kerberos_servers:
                kerberos_servers += tcp_kerberos_servers

        if 'udp' in proto:
            udp_host = "_kerberos._tcp.%s" % domain

            logger.debug("get_kerberos_servers: udp_host = %s", udp_host)
            udp_kerberos_servers = self.dsdns.get_SRV_records(tcp_host)
            if udp_kerberos_servers:
                kerberos_servers += udp_kerberos_servers

        for ks in kerberos_servers:
            logger.debug("get_kerberos_servers: found %s", ks)

        return kerberos_servers

    def get_kpasswd_servers(self, domain, proto='tcp'):
        kpasswd_servers = []

        if not domain:
            return kpasswd_servers
        if proto is None:
            proto = ['tcp', 'udp']

        if 'tcp' in proto:
            tcp_host = "_kpasswd._tcp.%s" % domain

            logger.debug("get_kpasswd_servers: tcp_host = %s", tcp_host)
            tcp_kpasswd_servers = self.dsdns.get_SRV_records(tcp_host)
            if tcp_kpasswd_servers:
                kpasswd_servers += tcp_kpasswd_servers

        if 'udp' in proto:
            udp_host = "_kpasswd._udp.%s" % domain

            logger.debug("get_kpasswd_servers: udp_host = %s", udp_host)
            udp_kpasswd_servers = self.dsdns.get_SRV_records(udp_host)
            if udp_kpasswd_servers:
                kpasswd_servers += udp_kpasswd_servers

        for kpws in kpasswd_servers:
            logger.debug("get_kpasswd_servers: found %s", kpws)

        return kpasswd_servers

    def get_kerberos_master_servers(self, domain, proto='tcp'):
        kerberos_master_servers = []

        if not domain:
            return kerberos_master_servers
        if proto is None:
            proto = ['tcp', 'udp']

        if 'tcp' in proto:
            tcp_host = "_kerberos-master._tcp.%s" % domain

            logger.debug("get_kerberos_master_servers: tcp_host = %s", tcp_host)
            tcp_kerberos_master_servers = self.dsdns.get_SRV_records(tcp_host)
            if tcp_kerberos_master_servers:
                kerberos_master_servers += tcp_kerberos_master_servers

        if 'udp' in proto:
            udp_host = "_kerberos-master._tcp.%s" % domain

            logger.debug("get_kerberos_master_servers: udp_host = %s", udp_host)
            udp_kerberos_master_servers = self.dsdns.get_SRV_records(tcp_host)
            if udp_kerberos_master_servers:
                kerberos_master_servers += udp_kerberos_master_servers

        for kms in kerberos_master_servers:
            logger.debug("get_kerberos_master_servers: found %s", kms)

        return kerberos_master_servers

    def get_kerberos_admin_servers(self, domain, proto='tcp'):
        kerberos_admin_servers = []

        if not domain:
            return kerberos_admin_servers
        if proto is None:
            proto = ['tcp', 'udp']

        if 'tcp' in proto:
            tcp_host = "_kerberos-adm._tcp.%s" % domain

            logger.debug("get_kerberos_admin_servers: tcp_host = %s", tcp_host)
            tcp_kerberos_admin_servers = self.dsdns.get_SRV_records(tcp_host)
            if tcp_kerberos_admin_servers:
                kerberos_admin_servers += tcp_kerberos_admin_servers

        if 'udp' in proto:
            udp_host = "_kerberos-adm._tcp.%s" % domain

            logger.debug("get_kerberos_admin_servers: udp_host = %s", udp_host)
            udp_kerberos_admin_servers = self.dsdns.get_SRV_records(tcp_host)
            if udp_kerberos_admin_servers:
                kerberos_admin_servers += udp_kerberos_admin_servers

        for kms in kerberos_admin_servers:
            logger.debug("get_kerberos_admin_servers: found %s", kms)

        return kerberos_admin_servers

    def cache_has_ticket(self):
        res = False

        p = pipeopen("/usr/bin/klist -t")
        p.communicate()
        if p.returncode == 0:
            res = True

        return res

    def get_principal_from_cache(self):
        principal = None

        p = pipeopen("klist")
        klist_out = p.communicate()
        if p.returncode != 0:
            return None

        klist_out = klist_out[0]
        lines = klist_out.splitlines()
        for line in lines:
            line = line.strip()
            if line.startswith(bytes("Principal", "UTF-8")):
                parts = line.split(bytes(":", "UTF-8"))
                if len(parts) > 1:
                    principal = parts[1].strip()

        return principal

    def get_ticket(self, realm, binddn, bindpw):
        krb_principal = self.get_principal_from_cache()
        principal = "%s@%s" % (binddn, realm)

        res = kinit = False

        if krb_principal and krb_principal.upper() == principal.upper():
            return True

        (fd, tmpfile) = tempfile.mkstemp(dir="/tmp")
        os.fchmod(fd, 600)
        os.write(fd, bytes(bindpw, "UTF-8"))
        os.close(fd)

        args = [
            "/usr/bin/kinit",
            "--renewable",
            "--password-file=%s" % tmpfile,
            "%s" % principal
        ]

        # XXX this needs to be configurable
        timeout = 30

        (returncode, stdout, stderr) = run(' '.join(args), timeout=timeout)
        if returncode == 0:
            res = True

        if res != False:
            kinit = True

        os.unlink(tmpfile)

        if kinit:
            i = 0
            while i < timeout:
                if self.cache_has_ticket():
                    res = True
                    break

                time.sleep(1)
                i += 1

        return res
示例#3
0
class LDAP(object):
    class LDAPHandle(object):
        def __init__(self, host, binddn, bindpw):
            self.__host = host
            self.__binddn = binddn
            self.__bindpw = bindpw
            self.__ldap_handle = self.get_ldap_handle()

        def get_connection_handle(self, host, port, binddn, bindpw):
            server = ldap3.Server(host, port=port, get_info=ldap3.ALL)
            conn = ldap3.Connection(server, user=binddn, password=bindpw,
                authentication=ldap3.AUTH_SIMPLE, auto_bind=True)
            return conn

        @property
        def ldap_handle(self):
            return self.__ldap_handle

        def get_ldap_handle(self):
            return self.get_connection_handle(
                self.__host,
                389,
                self.__binddn,
                self.__bindpw
            )

    def __init__(self, *args,  **kwargs):
        self.dispatcher = kwargs.get('dispatcher')
        self.datastore = kwargs.get('datastore')

        sys.path.extend(['/usr/local/lib/dsd/modules/'])
        from dsdns import DSDNS

        self.dsdns = DSDNS(
            dispatcher=self.dispatcher,
            datastore=self.datastore,
        )

    def get_directory_type(self):
        return "ldap"

    def get_connection_handle(self, host, binddn, bindpw):
        return self.LDAPHandle(host, binddn, bindpw)

    def get_ldap_servers(self, domain):
        ldap_servers = []
        if not domain:
            return dcs

        host = "_ldap._tcp.%s" % domain

        logger.debug("get_ldap_servers: host = %s", host)
        ldap_servers = self.dsdns.get_SRV_records(host)

        for lds in ldap_servers:
            logger.debug("get_ldap_servers: found %s", lds)

        return ldap_servers

    def get_rootDSE(self, handle):
        ldap_handle = handle.ldap_handle

        ldap_handle.search('',
            '(objectclass=*)',
            search_scope=ldap3.BASE,
            attributes=ldap3.ALL_ATTRIBUTES,
        )

        if not ldap_handle.result:
            return None

        if not ldap_handle.response:
            return None

        results = ldap_handle.response[0]
        if not results:
            return None

        attributes = results.get('attributes', None)
        if not attributes:
            return None

        return attributes

    def get_baseDN(self, handle):
        rootDSE = self.get_rootDSE(handle)
        if not rootDSE:
            return None

        baseDN = rootDSE.get('defaultNamingContext', None)
        if not baseDN:
            return None

        baseDN = baseDN[0].strip()
        logger.debug("get_baseDN: baseDN = %s", baseDN)

        return baseDN

    def get_users(self, handle, **kwargs):
        ldap_handle = handle.ldap_handle

        baseDN = self.get_baseDN(handle)
        filter = '(&(|(objectclass=person)' \
            '(objectclass=posixaccount)' \
            '(objectclass=account))(uid=*))'
        logger.debug("get_users: filter = %s", filter)

        ldap_handle.search(
            baseDN,
            filter,
            search_scope=ldap3.SUBTREE,
            attributes=ldap3.ALL_ATTRIBUTES
        )

        users = []
        if not ldap_handle.result:
            return users

        filter_func = None
        if 'filter' in kwargs and kwargs['filter']:
            filter_func = kwargs['filter']

        for result in ldap_handle.response:
            attributes = result.get('attributes', None)
            if not attributes:
                continue

            attributes['dn'] = result.get('dn')
            if filter_func:
                if filter_func(attributes):
                    continue

            users.append(attributes)

        return users

    def get_groups(self, handle, **kwargs):
        ldap_handle = handle.ldap_handle

        baseDN = self.get_baseDN(handle)
        filter = '(&(|(objectclass=posixgroup)' \
            '(objectclass=group))' \
            '(gidnumber=*))'
        logger.debug("get_groups: filter = %s", filter)

        ldap_handle.search(
            baseDN,
            filter,
            search_scope=ldap3.SUBTREE,
            attributes=ldap3.ALL_ATTRIBUTES
        )

        groups = []
        if not ldap_handle.result:
            return groups

        filter_func = None
        if 'filter' in kwargs and kwargs['filter']:
            filter_func = kwargs['filter']

        for result in ldap_handle.response:
            attributes = result.get('attributes', None)
            if not attributes:
                continue

            attributes['dn'] = result.get('dn')
            if filter_func:
                if filter_func(attributes):
                    continue

            groups.append(attributes)

        return groups

    def get_user(self, handle, user):
        ldap_handle = handle.ldap_handle

        baseDN = self.get_baseDN(handle)
        if user.isdigit():
            filter = '(&(|(objectclass=person)' \
                '(objectclass=posixaccount)' \
                '(objectclass=account))' \
                '(uidnumber=%s))' % user
        else:
            filter = '(&(|(objectclass=person)' \
                '(objectclass=posixaccount)' \
                '(objectclass=account))' \
                '(|(uid=%s)(cn=%s)))' % (user, user)
        logger.debug("get_user: filter = %s", filter)

        ldap_handle.search(
            baseDN,
            filter,
            search_scope=ldap3.SUBTREE,
            attributes=ldap3.ALL_ATTRIBUTES
        )

        if not ldap_handle.result:
            return []

        if not ldap_handle.response:
            return []

        results = ldap_handle.response[0]
        if not results:
            return []

        attributes = results.get('attributes', None)
        if not attributes:
            return []

        if 'dn' in results:
            attributes['dn'] = results['dn']

        return attributes

    def get_group(self, handle, group):
        ldap_handle = handle.ldap_handle

        baseDN = self.get_baseDN(handle)
        if group.isdigit():
            filter = '(&(|(objectclass=posixgroup)' \
                '(objectclass=group))' \
                '(gidnumber=%s))' % group
        else:
            filter = '(&(|(objectclass=posixgroup)' \
                '(objectclass=group))' \
                '(cn=%s))' % group
        logger.debug("get_group: filter = %s", filter)

        ldap_handle.search(
            baseDN,
            filter,
            search_scope=ldap3.SUBTREE,
            attributes=ldap3.ALL_ATTRIBUTES
        )

        if not ldap_handle.result:
            return []

        if not ldap_handle.response:
            return []

        results = ldap_handle.response[0]
        if not results:
            return []

        attributes = results.get('attributes', None)
        if not attributes:
            return []

        if 'dn' in results:
            attributes['dn'] = results['dn']

        return attributes

    def get_userDN(self, handle, user):
        user = self.get_user(handle, user)
        if not user:
            return None

        userDN = user['dn'].strip()
        logger.debug("get_userDN: userDN = %s", userDN)

        return userDN

    def get_groupDN(self, handle, group):
        group = self.get_group(handle, group)
        if not group:
            return None


        groupDN = group['dn'].strip()
        logger.debug("get_groupDN: groupDN = %s", groupDN)

        return groupDN