]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
1353. [contrib] sdb/ldap to version 0.9.
authorMark Andrews <marka@isc.org>
Mon, 5 Aug 2002 04:45:21 +0000 (04:45 +0000)
committerMark Andrews <marka@isc.org>
Mon, 5 Aug 2002 04:45:21 +0000 (04:45 +0000)
CHANGES
contrib/sdb/ldap/INSTALL.ldap
contrib/sdb/ldap/README.ldap
contrib/sdb/ldap/ldapdb.c

diff --git a/CHANGES b/CHANGES
index 3e9a8c1b00324236f2f4d4a01eb2785879d26ad6..389c1ee5d73282d6d3b0ba88d80fd51e8891efa9 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -1,3 +1,5 @@
+1353.  [contrib]       sdb/ldap to version 0.9.
+
 1350.  [bug]           dns_name_fromtext() failed to handle too many labels
                        gracefully.
 
index e54b5001579e28f51b14edf4f0241d588b25a99c..e3801ed2585200acb0791109b47732aec4745ff9 100644 (file)
@@ -1,4 +1,4 @@
-This is the INSTALL file for 0.4. See
+This is the INSTALL file for 0.9. See
 http://www.venaas.no/ldap/bind-sdb/ for updates or other information.
 
 BUILDING
@@ -22,7 +22,10 @@ Finally you need to edit bin/named/main.c. Below where it says
 it says "xxdb_init();" add the line "ldapdb_init();", and finally
 below where it says "xxdb_clear();", add "ldapdb_clear();".
 
-Now you should hopefully be able to build it.
+Now you should hopefully be able to build it. If you get an error
+message about ldap_memfree() not being defined, you're probably
+using an LDAP library with the interface defined in RFC 1823. To
+build, uncomment the #define RFC1823API line near the top of ldapdb.c.
 
 
 CONFIGURING
@@ -50,6 +53,7 @@ zone "venaas.com" {
 
 When doing lookups BIND will do a sub-tree search below the base in the
 URL. The number 172800 is the TTL which will be used for all entries that
-haven't got the dNSTTL attribute.
+haven't got the dNSTTL attribute. It is also possible to add an filter to
+the URL, say ldap://host/base???(o=internal)
 
-Stig Venaas <venaas@uninett.no> 2001-04-12
+Stig Venaas <venaas@uninett.no> 2002-04-17
index 102d0ac969d4ee6c5d456fe353e8cf765d5ebc03..10d6587255727a3e822d137b063a8f1a81ed6605 100644 (file)
@@ -1,18 +1,40 @@
 This is an attempt at an LDAP back-end for BIND 9 using the new simplified
-database interface "sdb". This is the fifth release (0.5) and is not ready
-for production use yet. Note that this version (and  0.4) uses a new schema
-and is not backwards compatible with versions before 0.4. The big changes in
-0.5 are thread support and improved connection handling. Multiple threads
-can now access the back-end simultaneously, and rather than having one
-connection per zone, there is now one connection per thread per LDAP server.
-This should help people with multiple CPUs and people with a huge number of
-zones. One final change is support for literal IPv6 addresses in LDAP URLs.
-At least OpenLDAP 2 has IPv6 support, so if you use OpenLDAP 2 libraries and
-server, you got all you need.
+database interface "sdb". This is the nineth release (0.9) and seems to
+be pretty stable. Note that since version 0.4 a new schema is used.
+It is not backwards compatible with versions before 0.4.
+
+In 0.9 the code has been cleaned up a bit and should be slightly faster
+than previous versions. It also fixes an error with zone transfers (AXFR)
+and entries with multiple relativeDomainName values. The problem was
+that it would only use the first value in the result. There's no need
+to upgrade unless you use such entries.
+
+0.8 uses asynchronous LDAP search which should give better performance.
+Thanks to Ashley Burston for providing patch. Another new feature is
+allowing filters in URLs. The syntax is as in RFC 2255. Few people will
+need this, but if you have say an internal and external version of the
+same zone, you could stick say o=internal and o=external into different
+entries, and specify for instance ldap://host/base???(o=internal)
+Some error logging has also been added.
+
+0.7 allows space and other characters to be used in URLs by use of %-quoting.
+For instance space can be written as %20. It also fixes a problem with some
+servers and/or APIs that do not preserve attribute casing.
+
+0.6 fixes some memory leaks present in older versions unless compiled with
+the RFC 1823 API.
+
+The big changes in 0.5 are thread support and improved connection handling.
+Multiple threads can now access the back-end simultaneously, and rather than
+having one connection per zone, there is now one connection per thread per
+LDAP server. This should help people with multiple CPUs and people with a
+huge number of zones. One final change is support for literal IPv6 addresses
+in LDAP URLs. At least OpenLDAP 2 has IPv6 support, so if you use OpenLDAP 2
+libraries and server, you got all you need.
 
 If you have bug reports, fixes, comments, questions or whatever, please
 contact me. See also http://www.venaas.no/ldap/bind-sdb/ for information.
 
 See INSTALL for how to build, install and use.
 
-Stig Venaas <venaas@uninett.no> 2001-05-06
+Stig Venaas <venaas@uninett.no> 2001-12-29
index 0b6e88b48de1a2e6215d42f2f7b2f3583f7f85f8..47612dce3ea0baf75b60ec7f212675e9bf28bb83 100644 (file)
@@ -1,11 +1,19 @@
 /*
- * Copyright (C) 2001 Stig Venaas
+ * ldapdb.c version 0.9
+ *
+ * Copyright (C) 2002 Stig Venaas
  *
  * Permission to use, copy, modify, and distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
  * copyright notice and this permission notice appear in all copies.
  */
 
+/*
+ * If you are using an old LDAP API uncomment the define below. Only do this
+ * if you know what you're doing or get compilation errors on ldap_memfree().
+ */
+/* #define RFC1823API */
+
 #include <config.h>
 
 #include <string.h>
 #include <dns/sdb.h>
 
 #include <named/globals.h>
+#include <named/log.h>
 
 #include <ldap.h>
 #include "ldapdb.h"
 
 /*
- * A simple database driver for LDAP. Not production quality yet
+ * A simple database driver for LDAP
  */ 
 
+/* enough for name with 8 labels of max length */
+#define MAXNAMELEN 519
+
 static dns_sdbimplementation_t *ldapdb = NULL;
 
 struct ldapdb_data {
@@ -38,6 +50,11 @@ struct ldapdb_data {
        int portno;
        char *base;
        int defaultttl;
+       char *filterall;
+       int filteralllen;
+       char *filterone;
+       int filteronelen;
+       char *filtername;
 };
 
 /* used by ldapdb_getconn */
@@ -153,79 +170,6 @@ ldapdb_getconn(struct ldapdb_data *data)
        return (LDAP **)&conndata->data;
 }
 
-/* callback routines */
-static isc_result_t
-ldapdb_create(const char *zone, int argc, char **argv,
-             void *driverdata, void **dbdata)
-{
-       struct ldapdb_data *data;
-       char *s;
-       int defaultttl;
-
-       UNUSED(zone);
-       UNUSED(driverdata);
-
-       /* we assume that only one thread will call create at a time */
-       /* want to do this only once for all instances */
-
-       if ((argc < 2)
-           || (argv[0] != strstr( argv[0], "ldap://"))
-           || ((defaultttl = atoi(argv[1])) < 1))
-                return (ISC_R_FAILURE);
-        data = isc_mem_get(ns_g_mctx, sizeof(struct ldapdb_data));
-        if (data == NULL)
-                return (ISC_R_NOMEMORY);
-       data->hostport = isc_mem_strdup(ns_g_mctx, argv[0] + strlen("ldap://"));
-       if (data->hostport == NULL) {
-               isc_mem_put(ns_g_mctx, data, sizeof(struct ldapdb_data));
-               return (ISC_R_NOMEMORY);
-       }
-       data->defaultttl = defaultttl;
-       s = strchr(data->hostport, '/');
-       if (s != NULL) {
-               *s++ = '\0';
-               data->base = *s != '\0' ? s : NULL;
-       }
-
-       /* support URLs with literal IPv6 addresses */
-       data->hostname = isc_mem_strdup(ns_g_mctx, data->hostport +
-                                       (*data->hostport == '[' ? 1 : 0));
-       if (data->hostname == NULL) {
-               isc_mem_free(ns_g_mctx, data->hostport);
-               isc_mem_put(ns_g_mctx, data, sizeof(struct ldapdb_data));
-               return (ISC_R_NOMEMORY);
-       }
-
-       if (*data->hostport == '[' &&
-           (s = strchr(data->hostname, ']')) != NULL )
-               *s++ = '\0';
-       else
-               s = data->hostname;
-       s = strchr(s, ':');
-       if (s != NULL) {
-               *s++ = '\0';
-               data->portno = atoi(s);
-       } else
-               data->portno = LDAP_PORT;
-
-       *dbdata = data;
-       return (ISC_R_SUCCESS);
-}
-
-static void
-ldapdb_destroy(const char *zone, void *driverdata, void **dbdata) {
-       struct ldapdb_data *data = *dbdata;
-       
-        UNUSED(zone);
-        UNUSED(driverdata);
-
-       if (data->hostport != NULL)
-               isc_mem_free(ns_g_mctx, data->hostport);
-       if (data->hostname != NULL)
-               isc_mem_free(ns_g_mctx, data->hostname);
-        isc_mem_put(ns_g_mctx, data, sizeof(struct ldapdb_data));
-}
-
 static void
 ldapdb_bind(struct ldapdb_data *data, LDAP **ldp)
 {
@@ -241,197 +185,339 @@ ldapdb_bind(struct ldapdb_data *data, LDAP **ldp)
 }
 
 static isc_result_t
-ldapdb_lookup(const char *zone, const char *name, void *dbdata,
-             dns_sdblookup_t *lookup)
+ldapdb_search(const char *zone, const char *name, void *dbdata, void *retdata)
 {
-        isc_result_t result = ISC_R_NOTFOUND;
        struct ldapdb_data *data = dbdata;
+       isc_result_t result = ISC_R_NOTFOUND;
        LDAP **ldp;
        LDAPMessage *res, *e;
-       char *fltr, *a, **vals;
+       char *fltr, *a, **vals, **names;
        char type[64];
+#ifdef RFC1823API
+       void *ptr;
+#else
        BerElement *ptr;
-       int i;
+#endif
+       int i, j, errno, msgid;
 
        ldp = ldapdb_getconn(data);
        if (ldp == NULL)
                return (ISC_R_FAILURE);
        if (*ldp == NULL) {
                ldapdb_bind(data, ldp);
-               if (*ldp == NULL)
+               if (*ldp == NULL) {
+                       isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER, ISC_LOG_ERROR,    
+                                     "LDAP sdb zone '%s': bind failed", zone);
                        return (ISC_R_FAILURE);
+               }
        }
-       fltr = isc_mem_get(ns_g_mctx, strlen(zone) + strlen(name) +
-                          strlen("(&(zoneName=)(relativeDomainName=))") + 1);
-        if (fltr == NULL)
-                return (ISC_R_NOMEMORY);
 
-       strcpy(fltr, "(&(zoneName=");
-       strcat(fltr, zone);
-       strcat(fltr, ")(relativeDomainName=");
-       strcat(fltr, name);
-       strcat(fltr, "))");
+       if (name == NULL) {
+               fltr = data->filterall;
+       } else {
+               if (strlen(name) > MAXNAMELEN) {
+                       isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
+                                      "LDAP sdb zone '%s': name %s too long", zone, name);
+                       return (ISC_R_FAILURE);
+               }
+               sprintf(data->filtername, "%s))", name);
+               fltr = data->filterone;
+       }
 
-       if (ldap_search_s(*ldp, data->base, LDAP_SCOPE_SUBTREE, fltr, NULL, 0,
-                         &res) != LDAP_SUCCESS) {
+       msgid = ldap_search(*ldp, data->base, LDAP_SCOPE_SUBTREE, fltr, NULL, 0);
+       if (msgid == -1) {
                ldapdb_bind(data, ldp);
                if (*ldp != NULL)
-                       ldap_search_s(*ldp, data->base, LDAP_SCOPE_SUBTREE,
-                                     fltr, NULL, 0, &res);
+                       msgid = ldap_search(*ldp, data->base, LDAP_SCOPE_SUBTREE, fltr, NULL, 0);
        }
 
-       isc_mem_put(ns_g_mctx, fltr, strlen(fltr) + 1);
+       if (*ldp == NULL || msgid == -1) {
+               isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER, ISC_LOG_ERROR,    
+                             "LDAP sdb zone '%s': search failed, filter %s", zone, fltr);
+               return (ISC_R_FAILURE);
+       }
 
-       if (*ldp == NULL)
-               goto exit;
-       
-       for (e = ldap_first_entry(*ldp, res); e != NULL;
-            e = ldap_next_entry(*ldp, e)) {
+       /* Get the records one by one as they arrive and return them to bind */
+       while ((errno = ldap_result(*ldp, msgid, 0, NULL, &res)) != LDAP_RES_SEARCH_RESULT ) {
                LDAP *ld = *ldp;
                int ttl = data->defaultttl;
-               
-               for (a = ldap_first_attribute(ld, e, &ptr); a != NULL;
-                    a = ldap_next_attribute(ld, e, ptr)) {
-                       if (!strcmp(a, "dNSTTL")) {
-                               vals = ldap_get_values(ld, e, a);
-                               ttl = atoi(vals[0]);
-                               ldap_value_free(vals);
-                               ldap_memfree(a);
-                               break;
-                       }
-                       ldap_memfree(a);
+
+               /* not supporting continuation references at present */
+               if (errno != LDAP_RES_SEARCH_ENTRY) {
+                       isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER, ISC_LOG_ERROR,    
+                                     "LDAP sdb zone '%s': ldap_result returned %d", zone, errno);
+                       ldap_msgfree(res);
+                       return (ISC_R_FAILURE);
+                }
+
+               /* only one entry per result message */
+               e = ldap_first_entry(ld, res);
+               if (e == NULL) {
+                       ldap_msgfree(res);
+                       isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER, ISC_LOG_ERROR,    
+                                     "LDAP sdb zone '%s': ldap_first_entry failed", zone);
+                       return (ISC_R_FAILURE);
+                }
+
+               if (name == NULL) {
+                       names = ldap_get_values(ld, e, "relativeDomainName");
+                       if (names == NULL)
+                               continue;
                }
-               for (a = ldap_first_attribute(ld, e, &ptr); a != NULL;
-                    a = ldap_next_attribute(ld, e, ptr)) {
+
+               vals = ldap_get_values(ld, e, "dNSTTL");
+               if (vals != NULL) {
+                       ttl = atoi(vals[0]);
+                       ldap_value_free(vals);
+               }
+
+               for (a = ldap_first_attribute(ld, e, &ptr); a != NULL; a = ldap_next_attribute(ld, e, ptr)) {
                        char *s;
-                       
+
                        for (s = a; *s; s++)
                                *s = toupper(*s);
                        s = strstr(a, "RECORD");
-                       if ((s == NULL) || (s == a)
-                           || (s - a >= (signed int)sizeof(type))) {
+                       if ((s == NULL) || (s == a) || (s - a >= (signed int)sizeof(type))) {
+#ifndef RFC1823API
                                ldap_memfree(a);
+#endif
                                continue;
                        }
+
                        strncpy(type, a, s - a);
                        type[s - a] = '\0';
                        vals = ldap_get_values(ld, e, a);
-                       for (i=0; vals[i] != NULL; i++) {
-                               result = dns_sdb_putrr(lookup, type, ttl,
-                                                      vals[i]);
-                               if (result != ISC_R_SUCCESS) {
-                                       ldap_value_free(vals);
-                                       ldap_memfree(a);
-                                       result = ISC_R_FAILURE;
-                                       goto exit;
+                       if (vals != NULL) {
+                               for (i = 0; vals[i] != NULL; i++) {
+                                       if (name != NULL) {
+                                               result = dns_sdb_putrr(retdata, type, ttl, vals[i]);
+                                       } else {
+                                               for (j = 0; names[j] != NULL; j++) {
+                                                       result = dns_sdb_putnamedrr(retdata, names[j], type, ttl, vals[i]);
+                                                       if (result != ISC_R_SUCCESS)
+                                                               break;
+                                               }
+                                       }
+;                                      if (result != ISC_R_SUCCESS) {
+                                               isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER, ISC_LOG_ERROR,    
+                                                             "LDAP sdb zone '%s': dns_sdb_put... failed for %s", zone, vals[i]);
+                                               ldap_value_free(vals);
+#ifndef RFC1823API
+                                               ldap_memfree(a);
+                                               if (ptr != NULL)
+                                                       ber_free(ptr, 0);
+#endif
+                                               if (name == NULL)
+                                                       ldap_value_free(names);
+                                               ldap_msgfree(res);
+                                               return (ISC_R_FAILURE);
+                                       }
                                }
+                               ldap_value_free(vals);
                        }
-                       ldap_value_free(vals);
+#ifndef RFC1823API
                        ldap_memfree(a);
+#endif
                }
+#ifndef RFC1823API
+               if (ptr != NULL)
+                       ber_free(ptr, 0);
+#endif
+               if (name == NULL)
+                       ldap_value_free(names);
+
+               /* cleanup this result */
+               ldap_msgfree(res);
        }
- exit:
-       ldap_msgfree(res);
-       return (result);
+
+        return (result);
+}
+
+
+/* callback routines */
+static isc_result_t
+ldapdb_lookup(const char *zone, const char *name, void *dbdata,
+             dns_sdblookup_t *lookup)
+{
+       return ldapdb_search(zone, name, dbdata, lookup);
 }
 
 static isc_result_t
 ldapdb_allnodes(const char *zone, void *dbdata,
-               dns_sdballnodes_t *allnodes) {
-        isc_result_t result = ISC_R_NOTFOUND;
-       struct ldapdb_data *data = dbdata;
-       LDAP **ldp;
-       LDAPMessage     *res, *e;
-       char type[64];
-       char *fltr, *a, **vals;
-       BerElement *ptr;
-       int i;
+               dns_sdballnodes_t *allnodes)
+{
+       return ldapdb_search(zone, NULL, dbdata, allnodes);
+}
 
-       ldp = ldapdb_getconn(data);
-       if (ldp == NULL)
-               return (ISC_R_FAILURE);
-       if (*ldp == NULL) {
-               ldapdb_bind(data, ldp);
-               if (*ldp == NULL)
-                       return (ISC_R_FAILURE);
+static char *
+unhex(char *in)
+{
+       static const char hexdigits[] = "0123456789abcdef";
+       char *p, *s = in;
+       int d1, d2;
+
+       while ((s = strchr(s, '%'))) {
+               if (!(s[1] && s[2]))
+                       return NULL;
+               if ((p = strchr(hexdigits, tolower(s[1]))) == NULL)
+                       return NULL;
+               d1 = p - hexdigits;
+               if ((p = strchr(hexdigits, tolower(s[2]))) == NULL)
+                       return NULL;
+               d2 = p - hexdigits;
+               *s++ = d1 << 4 | d2;
+               memmove(s, s + 2, strlen(s) - 1);
        }
+       return in;
+}
 
-       fltr = isc_mem_get(ns_g_mctx, strlen(zone) + strlen("(zoneName=)") + 1);
-        if (fltr == NULL)
-                return (ISC_R_NOMEMORY);
 
-       strcpy(fltr, "(zoneName=");
-       strcat(fltr, zone);
-       strcat(fltr, ")");
 
-       if (ldap_search_s(*ldp, data->base, LDAP_SCOPE_SUBTREE, fltr, NULL, 0,
-                         &res) != LDAP_SUCCESS) {
-               ldapdb_bind(data, ldp);
-               if (*ldp != NULL)
-                       ldap_search_s(*ldp, data->base, LDAP_SCOPE_SUBTREE,
-                                     fltr, NULL, 0, &res);
+static void
+free_data(struct ldapdb_data *data)
+{
+       if (data->hostport != NULL)
+               isc_mem_free(ns_g_mctx, data->hostport);
+       if (data->hostname != NULL)
+               isc_mem_free(ns_g_mctx, data->hostname);
+       if (data->filterall != NULL)
+               isc_mem_put(ns_g_mctx, data->filterall, data->filteralllen);
+       if (data->filterone != NULL)
+               isc_mem_put(ns_g_mctx, data->filterone, data->filteronelen);
+        isc_mem_put(ns_g_mctx, data, sizeof(struct ldapdb_data));
+}
+
+
+static isc_result_t
+ldapdb_create(const char *zone, int argc, char **argv,
+             void *driverdata, void **dbdata)
+{
+       struct ldapdb_data *data;
+       char *s, *filter = NULL;
+       int defaultttl;
+
+       UNUSED(driverdata);
+
+       /* we assume that only one thread will call create at a time */
+       /* want to do this only once for all instances */
+
+       if ((argc < 2)
+           || (argv[0] != strstr( argv[0], "ldap://"))
+           || ((defaultttl = atoi(argv[1])) < 1))
+                return (ISC_R_FAILURE);
+        data = isc_mem_get(ns_g_mctx, sizeof(struct ldapdb_data));
+        if (data == NULL)
+                return (ISC_R_NOMEMORY);
+
+       memset(data, 0, sizeof(struct ldapdb_data));
+       data->hostport = isc_mem_strdup(ns_g_mctx, argv[0] + strlen("ldap://"));
+       if (data->hostport == NULL) {
+               free_data(data);
+               return (ISC_R_NOMEMORY);
        }
 
-       isc_mem_put(ns_g_mctx, fltr, strlen(fltr) + 1);
+       data->defaultttl = defaultttl;
 
-       for (e = ldap_first_entry(*ldp, res); e != NULL;
-            e = ldap_next_entry(*ldp, e)) {
-               LDAP *ld = *ldp;
-               char *name = NULL;
-               int ttl = data->defaultttl;
-               
-               for (a = ldap_first_attribute(ld, e, &ptr); a != NULL;
-                    a = ldap_next_attribute(ld, e, ptr)) {
-                       if (!strcmp(a, "dNSTTL")) {
-                               vals = ldap_get_values(ld, e, a);
-                               ttl = atoi(vals[0]);
-                               ldap_value_free(vals);
-                       } else if (!strcmp(a, "relativeDomainName")) {
-                               vals = ldap_get_values(ld, e, a);
-                               name = isc_mem_strdup(ns_g_mctx, vals[0]);
-                               ldap_value_free(vals);
+       s = strchr(data->hostport, '/');
+       if (s != NULL) {
+               *s++ = '\0';
+               data->base = s;
+               /* attrs, scope, filter etc? */
+               s = strchr(s, '?');
+               if (s != NULL) {
+                       *s++ = '\0';
+                       /* ignore attributes */
+                       s = strchr(s, '?');
+                       if (s != NULL) {
+                               *s++ = '\0';
+                               /* ignore scope */
+                               s = strchr(s, '?');
+                               if (s != NULL) {
+                                       *s++ = '\0';
+                                       /* filter */
+                                       filter = s;
+                                       s = strchr(s, '?');
+                                       if (s != NULL) {
+                                               *s++ = '\0';
+                                       }
+                                       if (*filter == '\0') {
+                                               filter = NULL;
+                                       }
+                               }
                        }
-                       ldap_memfree(a);
                }
-               
-               if (name == NULL)
-                       continue;
-               
-               for (a = ldap_first_attribute(ld, e, &ptr); a != NULL;
-                    a = ldap_next_attribute(ld, e, ptr)) {
-                       char *s;
+               if (*data->base == '\0') {
+                       data->base = NULL;
+               }
 
-                       for (s = a; *s; s++)
-                               *s = toupper(*s);
-                       s = strstr(a, "RECORD");
-                       if ((s == NULL) || (s == a)
-                           || (s - a >= (signed int)sizeof(type))) {
-                               ldap_memfree(a);
-                               continue;
-                       }
-                       strncpy(type, a, s - a);
-                       type[s - a] = '\0';
-                       vals = ldap_get_values(ld, e, a);
-                       for (i=0; vals[i] != NULL; i++) {
-                               result = dns_sdb_putnamedrr(allnodes, name,
-                                                           type, ttl, vals[i]);
-                               if (result != ISC_R_SUCCESS) {
-                                       ldap_value_free(vals);
-                                       ldap_memfree(a);
-                                       isc_mem_free(ns_g_mctx, name);
-                                       result = ISC_R_FAILURE;
-                                       goto exit;
-                               }
-                       }
-                       ldap_value_free(vals);
-                       ldap_memfree(a);
+               if ((data->base != NULL && unhex(data->base) == NULL) || (filter != NULL && unhex(filter) == NULL)) {
+                       free_data(data);
+                       isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER, ISC_LOG_ERROR,    
+                                     "LDAP sdb zone '%s': bad hex values", zone);
+                       return (ISC_R_FAILURE);
                }
-               isc_mem_free(ns_g_mctx, name);
        }
 
- exit:
-       ldap_msgfree(res);
-       return (result);
+       /* compute filterall and filterone once and for all */
+       if (filter == NULL) {
+               data->filteralllen = strlen(zone) + strlen("(zoneName=)") + 1;
+               data->filteronelen = strlen(zone) + strlen("(&(zoneName=)(relativeDomainName=))") + MAXNAMELEN + 1;
+       } else {
+               data->filteralllen = strlen(filter) + strlen(zone) + strlen("(&(zoneName=))") + 1;
+               data->filteronelen = strlen(filter) + strlen(zone) + strlen("(&(zoneName=)(relativeDomainName=))") + MAXNAMELEN + 1;
+       }
+
+       data->filterall = isc_mem_get(ns_g_mctx, data->filteralllen);
+       if (data->filterall == NULL) {
+               free_data(data);
+               return (ISC_R_NOMEMORY);
+       }
+       data->filterone = isc_mem_get(ns_g_mctx, data->filteronelen);
+       if (data->filterone == NULL) {
+               free_data(data);
+               return (ISC_R_NOMEMORY);
+       }
+
+       if (filter == NULL) {
+               sprintf(data->filterall, "(zoneName=%s)", zone);
+               sprintf(data->filterone, "(&(zoneName=%s)(relativeDomainName=", zone); 
+       } else {
+               sprintf(data->filterall, "(&%s(zoneName=%s))", filter, zone);
+               sprintf(data->filterone, "(&%s(zoneName=%s)(relativeDomainName=", filter, zone);
+       }
+       data->filtername = data->filterone + strlen(data->filterone);
+
+       /* support URLs with literal IPv6 addresses */
+       data->hostname = isc_mem_strdup(ns_g_mctx, data->hostport + (*data->hostport == '[' ? 1 : 0));
+       if (data->hostname == NULL) {
+               free_data(data);
+               return (ISC_R_NOMEMORY);
+       }
+
+       if (*data->hostport == '[' &&
+           (s = strchr(data->hostname, ']')) != NULL )
+               *s++ = '\0';
+       else
+               s = data->hostname;
+       s = strchr(s, ':');
+       if (s != NULL) {
+               *s++ = '\0';
+               data->portno = atoi(s);
+       } else
+               data->portno = LDAP_PORT;
+
+       *dbdata = data;
+       return (ISC_R_SUCCESS);
+}
+
+static void
+ldapdb_destroy(const char *zone, void *driverdata, void **dbdata) {
+       struct ldapdb_data *data = *dbdata;
+       
+        UNUSED(zone);
+        UNUSED(driverdata);
+
+       free_data(data);
 }
 
 static dns_sdbmethods_t ldapdb_methods = {