def _search(self, searchfilter, attrs, basedn):
        """Generic search"""
        if attrs == NO_ATTR:
            attrlist = []
        elif attrs == DISPLAYED_ATTRS:
            # fix me later (to much attributes)
            attrlist = self.attrlist
        elif attrs == LISTED_ATTRS:
            attrlist = self.attrlist
        elif attrs == ALL_ATTRS:
            attrlist = None
        else:
            attrlist = None

        self._logger(
            severity=logging.DEBUG,
            msg="%(backend)s: executing search "
                "with filter '%(filter)s' in DN '%(dn)s'" % {
                    'backend': self.backend_name,
                    'dn': basedn,
                    'filter': self._uni(searchfilter)
                }
        )

        # bind and search the ldap
        ldap_client = self._bind()
        try:
            r = ldap_client.search_s(
                basedn,
                ldap.SCOPE_SUBTREE,
                searchfilter,
                attrlist=attrlist
                )
        except Exception as e:
            ldap_client.unbind_s()
            self._exception_handler(e)

        ldap_client.unbind_s()

        # python-ldap doesn't know utf-8,
        # it treates everything as bytes.
        # So it's necessary to reencode
        # it's output in utf-8.
        ret = []
        for entry in r:
            uni_dn = self._uni(entry[0])
            uni_attrs = {}
            for attr in entry[1]:
                if type(entry[1][attr]) is list:
                    tmp = []
                    for value in entry[1][attr]:
                        tmp.append(self._uni(value))
                else:
                    tmp = self._uni(entry[1][attr])
                uni_attrs[self._uni(attr)] = tmp
            ret.append((uni_dn, uni_attrs))
        return ret