1 diff -urN bind-9.2.3-orig/bin/named/Makefile.in bind-9.2.3/bin/named/Makefile.in
2 --- bind-9.2.3-orig/bin/named/Makefile.in 2001-05-31 18:45:00.000000000 -0600
3 +++ bind-9.2.3/bin/named/Makefile.in 2003-11-16 14:52:51.000000000 -0700
6 # Add database drivers here.
10 +DBDRIVER_OBJS = ldapdb.@O@
11 +DBDRIVER_SRCS = ldapdb.c
14 +DBDRIVER_LIBS = -lldap -llber -lresolv
16 CINCLUDES = -I${srcdir}/include -I${srcdir}/unix/include \
17 ${LWRES_INCLUDES} ${DNS_INCLUDES} \
18 diff -urN bind-9.2.3-orig/bin/named/include/ldapdb.h bind-9.2.3/bin/named/include/ldapdb.h
19 --- bind-9.2.3-orig/bin/named/include/ldapdb.h 1969-12-31 17:00:00.000000000 -0700
20 +++ bind-9.2.3/bin/named/include/ldapdb.h 2003-11-16 14:52:51.000000000 -0700
22 +#include <isc/types.h>
24 +isc_result_t ldapdb_init(void);
26 +void ldapdb_clear(void);
28 diff -urN bind-9.2.3-orig/bin/named/ldapdb.c bind-9.2.3/bin/named/ldapdb.c
29 --- bind-9.2.3-orig/bin/named/ldapdb.c 1969-12-31 17:00:00.000000000 -0700
30 +++ bind-9.2.3/bin/named/ldapdb.c 2003-11-16 14:52:51.000000000 -0700
33 + * ldapdb.c version 1.0-beta
35 + * Copyright (C) 2002, 2004 Stig Venaas
37 + * Permission to use, copy, modify, and distribute this software for any
38 + * purpose with or without fee is hereby granted, provided that the above
39 + * copyright notice and this permission notice appear in all copies.
41 + * Contributors: Jeremy C. McDermond
45 + * If you want to use TLS, uncomment the define below
47 +/* #define LDAPDB_TLS */
50 + * If you are using an old LDAP API uncomment the define below. Only do this
51 + * if you know what you're doing or get compilation errors on ldap_memfree().
52 + * This also forces LDAPv2.
54 +/* #define LDAPDB_RFC1823API */
56 +/* Using LDAPv3 by default, change this if you want v2 */
57 +#ifndef LDAPDB_LDAP_VERSION
58 +#define LDAPDB_LDAP_VERSION 3
69 +#include <isc/print.h>
70 +#include <isc/result.h>
71 +#include <isc/util.h>
72 +#include <isc/thread.h>
76 +#include <named/globals.h>
77 +#include <named/log.h>
83 + * A simple database driver for LDAP
86 +/* enough for name with 8 labels of max length */
87 +#define MAXNAMELEN 519
89 +static dns_sdbimplementation_t *ldapdb = NULL;
109 +/* used by ldapdb_getconn */
111 +struct ldapdb_entry {
115 + struct ldapdb_entry *next;
118 +static struct ldapdb_entry *ldapdb_find(struct ldapdb_entry *stack,
119 + const void *index, size_t size) {
120 + while (stack != NULL) {
121 + if (stack->size == size && !memcmp(stack->index, index, size))
123 + stack = stack->next;
128 +static void ldapdb_insert(struct ldapdb_entry **stack,
129 + struct ldapdb_entry *item) {
130 + item->next = *stack;
134 +static void ldapdb_lock(int what) {
135 + static isc_mutex_t lock;
139 + isc_mutex_init(&lock);
150 +/* data == NULL means cleanup */
152 +ldapdb_getconn(struct ldapdb_data *data)
154 + static struct ldapdb_entry *allthreadsdata = NULL;
155 + struct ldapdb_entry *threaddata, *conndata;
156 + unsigned long threadid;
158 + if (data == NULL) {
160 + /* lock out other threads */
162 + while (allthreadsdata != NULL) {
163 + threaddata = allthreadsdata;
164 + free(threaddata->index);
165 + while (threaddata->data != NULL) {
166 + conndata = threaddata->data;
167 + free(conndata->index);
168 + if (conndata->data != NULL)
169 + ldap_unbind((LDAP *)conndata->data);
170 + threaddata->data = conndata->next;
173 + allthreadsdata = threaddata->next;
180 + /* look for connection data for current thread */
181 + threadid = isc_thread_self();
182 + threaddata = ldapdb_find(allthreadsdata, &threadid, sizeof(threadid));
183 + if (threaddata == NULL) {
184 + /* no data for this thread, create empty connection list */
185 + threaddata = malloc(sizeof(*threaddata));
186 + if (threaddata == NULL)
188 + threaddata->index = malloc(sizeof(threadid));
189 + if (threaddata->index == NULL) {
193 + *(unsigned long *)threaddata->index = threadid;
194 + threaddata->size = sizeof(threadid);
195 + threaddata->data = NULL;
197 + /* need to lock out other threads here */
199 + ldapdb_insert(&allthreadsdata, threaddata);
203 + /* threaddata points at the connection list for current thread */
204 + /* look for existing connection to our server */
205 + conndata = ldapdb_find((struct ldapdb_entry *)threaddata->data,
206 + data->hostport, strlen(data->hostport));
207 + if (conndata == NULL) {
208 + /* no connection data structure for this server, create one */
209 + conndata = malloc(sizeof(*conndata));
210 + if (conndata == NULL)
212 + conndata->index = data->hostport;
213 + conndata->size = strlen(data->hostport);
214 + conndata->data = NULL;
215 + ldapdb_insert((struct ldapdb_entry **)&threaddata->data,
219 + return (LDAP **)&conndata->data;
223 +ldapdb_bind(struct ldapdb_data *data, LDAP **ldp)
225 +#ifndef LDAPDB_RFC1823API
226 + const int ver = LDAPDB_LDAP_VERSION;
231 + *ldp = ldap_open(data->hostname, data->portno);
235 +#ifndef LDAPDB_RFC1823API
236 + ldap_set_option(*ldp, LDAP_OPT_PROTOCOL_VERSION, &ver);
241 + ldap_start_tls_s(*ldp, NULL, NULL);
245 + if (ldap_simple_bind_s(*ldp, data->bindname, data->bindpw) != LDAP_SUCCESS) {
252 +ldapdb_search(const char *zone, const char *name, void *dbdata, void *retdata)
254 + struct ldapdb_data *data = dbdata;
255 + isc_result_t result = ISC_R_NOTFOUND;
257 + LDAPMessage *res, *e;
258 + char *fltr, *a, **vals = NULL, **names = NULL;
260 +#ifdef LDAPDB_RFC1823API
265 + int i, j, errno, msgid;
267 + ldp = ldapdb_getconn(data);
269 + return (ISC_R_FAILURE);
270 + if (*ldp == NULL) {
271 + ldapdb_bind(data, ldp);
272 + if (*ldp == NULL) {
273 + isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
274 + "LDAP sdb zone '%s': bind failed", zone);
275 + return (ISC_R_FAILURE);
279 + if (name == NULL) {
280 + fltr = data->filterall;
282 + if (strlen(name) > MAXNAMELEN) {
283 + isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
284 + "LDAP sdb zone '%s': name %s too long", zone, name);
285 + return (ISC_R_FAILURE);
287 + sprintf(data->filtername, "%s))", name);
288 + fltr = data->filterone;
291 + msgid = ldap_search(*ldp, data->base, LDAP_SCOPE_SUBTREE, fltr, NULL, 0);
293 + ldapdb_bind(data, ldp);
295 + msgid = ldap_search(*ldp, data->base, LDAP_SCOPE_SUBTREE, fltr, NULL, 0);
298 + if (*ldp == NULL || msgid == -1) {
299 + isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
300 + "LDAP sdb zone '%s': search failed, filter %s", zone, fltr);
301 + return (ISC_R_FAILURE);
304 + /* Get the records one by one as they arrive and return them to bind */
305 + while ((errno = ldap_result(*ldp, msgid, 0, NULL, &res)) != LDAP_RES_SEARCH_RESULT ) {
307 + int ttl = data->defaultttl;
309 + /* not supporting continuation references at present */
310 + if (errno != LDAP_RES_SEARCH_ENTRY) {
311 + isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
312 + "LDAP sdb zone '%s': ldap_result returned %d", zone, errno);
314 + return (ISC_R_FAILURE);
317 + /* only one entry per result message */
318 + e = ldap_first_entry(ld, res);
321 + isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
322 + "LDAP sdb zone '%s': ldap_first_entry failed", zone);
323 + return (ISC_R_FAILURE);
326 + if (name == NULL) {
327 + names = ldap_get_values(ld, e, "relativeDomainName");
332 + vals = ldap_get_values(ld, e, "dNSTTL");
333 + if (vals != NULL) {
334 + ttl = atoi(vals[0]);
335 + ldap_value_free(vals);
338 + for (a = ldap_first_attribute(ld, e, &ptr); a != NULL; a = ldap_next_attribute(ld, e, ptr)) {
341 + for (s = a; *s; s++)
343 + s = strstr(a, "RECORD");
344 + if ((s == NULL) || (s == a) || (s - a >= (signed int)sizeof(type))) {
345 +#ifndef LDAPDB_RFC1823API
351 + strncpy(type, a, s - a);
352 + type[s - a] = '\0';
353 + vals = ldap_get_values(ld, e, a);
354 + if (vals != NULL) {
355 + for (i = 0; vals[i] != NULL; i++) {
356 + if (name != NULL) {
357 + result = dns_sdb_putrr(retdata, type, ttl, vals[i]);
359 + for (j = 0; names[j] != NULL; j++) {
360 + result = dns_sdb_putnamedrr(retdata, names[j], type, ttl, vals[i]);
361 + if (result != ISC_R_SUCCESS)
365 +; if (result != ISC_R_SUCCESS) {
366 + isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
367 + "LDAP sdb zone '%s': dns_sdb_put... failed for %s", zone, vals[i]);
368 + ldap_value_free(vals);
369 +#ifndef LDAPDB_RFC1823API
375 + ldap_value_free(names);
377 + return (ISC_R_FAILURE);
380 + ldap_value_free(vals);
382 +#ifndef LDAPDB_RFC1823API
386 +#ifndef LDAPDB_RFC1823API
391 + ldap_value_free(names);
393 + /* free this result */
397 + /* free final result */
403 +/* callback routines */
405 +ldapdb_lookup(const char *zone, const char *name, void *dbdata,
406 + dns_sdblookup_t *lookup)
408 + return ldapdb_search(zone, name, dbdata, lookup);
412 +ldapdb_allnodes(const char *zone, void *dbdata,
413 + dns_sdballnodes_t *allnodes)
415 + return ldapdb_search(zone, NULL, dbdata, allnodes);
421 + static const char hexdigits[] = "0123456789abcdef";
425 + while ((s = strchr(s, '%'))) {
426 + if (!(s[1] && s[2]))
428 + if ((p = strchr(hexdigits, tolower(s[1]))) == NULL)
430 + d1 = p - hexdigits;
431 + if ((p = strchr(hexdigits, tolower(s[2]))) == NULL)
433 + d2 = p - hexdigits;
434 + *s++ = d1 << 4 | d2;
435 + memmove(s, s + 2, strlen(s) - 1);
440 +/* returns 0 for ok, -1 for bad syntax, -2 for unknown critical extension */
442 +parseextensions(char *extensions, struct ldapdb_data *data)
444 + char *s, *next, *name, *value;
447 + while (extensions != NULL) {
448 + s = strchr(extensions, ',');
456 + if (*extensions != '\0') {
457 + s = strchr(extensions, '=');
460 + value = *s != '\0' ? s : NULL;
466 + critical = *name == '!';
470 + if (*name == '\0') {
474 + if (!strcasecmp(name, "bindname")) {
475 + data->bindname = value;
476 + } else if (!strcasecmp(name, "x-bindpw")) {
477 + data->bindpw = value;
479 + } else if (!strcasecmp(name, "x-tls")) {
480 + data->tls = value == NULL || !strcasecmp(value, "true");
482 + } else if (critical) {
492 +free_data(struct ldapdb_data *data)
494 + if (data->hostport != NULL)
495 + isc_mem_free(ns_g_mctx, data->hostport);
496 + if (data->hostname != NULL)
497 + isc_mem_free(ns_g_mctx, data->hostname);
498 + if (data->filterall != NULL)
499 + isc_mem_put(ns_g_mctx, data->filterall, data->filteralllen);
500 + if (data->filterone != NULL)
501 + isc_mem_put(ns_g_mctx, data->filterone, data->filteronelen);
502 + isc_mem_put(ns_g_mctx, data, sizeof(struct ldapdb_data));
507 +ldapdb_create(const char *zone, int argc, char **argv,
508 + void *driverdata, void **dbdata)
510 + struct ldapdb_data *data;
511 + char *s, *filter = NULL, *extensions = NULL;
514 + UNUSED(driverdata);
516 + /* we assume that only one thread will call create at a time */
517 + /* want to do this only once for all instances */
520 + || (argv[0] != strstr( argv[0], "ldap://"))
521 + || ((defaultttl = atoi(argv[1])) < 1))
522 + return (ISC_R_FAILURE);
523 + data = isc_mem_get(ns_g_mctx, sizeof(struct ldapdb_data));
525 + return (ISC_R_NOMEMORY);
527 + memset(data, 0, sizeof(struct ldapdb_data));
528 + data->hostport = isc_mem_strdup(ns_g_mctx, argv[0] + strlen("ldap://"));
529 + if (data->hostport == NULL) {
531 + return (ISC_R_NOMEMORY);
534 + data->defaultttl = defaultttl;
536 + s = strchr(data->hostport, '/');
540 + /* attrs, scope, filter etc? */
541 + s = strchr(s, '?');
544 + /* ignore attributes */
545 + s = strchr(s, '?');
549 + s = strchr(s, '?');
554 + s = strchr(s, '?');
559 + s = strchr(s, '?');
563 + if (*extensions == '\0') {
567 + if (*filter == '\0') {
573 + if (*data->base == '\0') {
578 + /* parse extensions */
579 + if (extensions != NULL) {
582 + err = parseextensions(extensions, data);
584 + /* err should be -1 or -2 */
587 + isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
588 + "LDAP sdb zone '%s': URL: extension syntax error", zone);
589 + } else if (err == -2) {
590 + isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
591 + "LDAP sdb zone '%s': URL: unknown critical extension", zone);
593 + return (ISC_R_FAILURE);
597 + if ((data->base != NULL && unhex(data->base) == NULL) ||
598 + (filter != NULL && unhex(filter) == NULL) ||
599 + (data->bindname != NULL && unhex(data->bindname) == NULL) ||
600 + (data->bindpw != NULL && unhex(data->bindpw) == NULL)) {
602 + isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
603 + "LDAP sdb zone '%s': URL: bad hex values", zone);
604 + return (ISC_R_FAILURE);
607 + /* compute filterall and filterone once and for all */
608 + if (filter == NULL) {
609 + data->filteralllen = strlen(zone) + strlen("(zoneName=)") + 1;
610 + data->filteronelen = strlen(zone) + strlen("(&(zoneName=)(relativeDomainName=))") + MAXNAMELEN + 1;
612 + data->filteralllen = strlen(filter) + strlen(zone) + strlen("(&(zoneName=))") + 1;
613 + data->filteronelen = strlen(filter) + strlen(zone) + strlen("(&(zoneName=)(relativeDomainName=))") + MAXNAMELEN + 1;
616 + data->filterall = isc_mem_get(ns_g_mctx, data->filteralllen);
617 + if (data->filterall == NULL) {
619 + return (ISC_R_NOMEMORY);
621 + data->filterone = isc_mem_get(ns_g_mctx, data->filteronelen);
622 + if (data->filterone == NULL) {
624 + return (ISC_R_NOMEMORY);
627 + if (filter == NULL) {
628 + sprintf(data->filterall, "(zoneName=%s)", zone);
629 + sprintf(data->filterone, "(&(zoneName=%s)(relativeDomainName=", zone);
631 + sprintf(data->filterall, "(&%s(zoneName=%s))", filter, zone);
632 + sprintf(data->filterone, "(&%s(zoneName=%s)(relativeDomainName=", filter, zone);
634 + data->filtername = data->filterone + strlen(data->filterone);
636 + /* support URLs with literal IPv6 addresses */
637 + data->hostname = isc_mem_strdup(ns_g_mctx, data->hostport + (*data->hostport == '[' ? 1 : 0));
638 + if (data->hostname == NULL) {
640 + return (ISC_R_NOMEMORY);
643 + if (*data->hostport == '[' &&
644 + (s = strchr(data->hostname, ']')) != NULL )
647 + s = data->hostname;
648 + s = strchr(s, ':');
651 + data->portno = atoi(s);
653 + data->portno = LDAP_PORT;
656 + return (ISC_R_SUCCESS);
660 +ldapdb_destroy(const char *zone, void *driverdata, void **dbdata) {
661 + struct ldapdb_data *data = *dbdata;
664 + UNUSED(driverdata);
669 +static dns_sdbmethods_t ldapdb_methods = {
671 + NULL, /* authority */
677 +/* Wrapper around dns_sdb_register() */
680 + unsigned int flags =
681 + DNS_SDBFLAG_RELATIVEOWNER |
682 + DNS_SDBFLAG_RELATIVERDATA |
683 + DNS_SDBFLAG_THREADSAFE;
686 + return (dns_sdb_register("ldap", &ldapdb_methods, NULL, flags,
687 + ns_g_mctx, &ldapdb));
690 +/* Wrapper around dns_sdb_unregister() */
692 +ldapdb_clear(void) {
693 + if (ldapdb != NULL) {
694 + /* clean up thread data */
695 + ldapdb_getconn(NULL);
696 + dns_sdb_unregister(&ldapdb);
699 diff -urN bind-9.2.3-orig/bin/named/main.c bind-9.2.3/bin/named/main.c
700 --- bind-9.2.3-orig/bin/named/main.c 2003-10-09 01:32:33.000000000 -0600
701 +++ bind-9.2.3/bin/named/main.c 2003-11-16 14:52:51.000000000 -0700
703 * Include header files for database drivers here.
705 /* #include "xxdb.h" */
708 static isc_boolean_t want_stats = ISC_FALSE;
709 static char program_name[ISC_DIR_NAMEMAX] = "named";
711 * Add calls to register sdb drivers here.
716 ns_server_create(ns_g_mctx, &ns_g_server);
719 * Add calls to unregister sdb drivers here.
724 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_MAIN,
725 ISC_LOG_NOTICE, "exiting");
726 diff -urN bind-9.2.3-orig/doc/INSTALL.sdb-ldap bind-9.2.3/doc/INSTALL.sdb-ldap
727 --- bind-9.2.3-orig/doc/INSTALL.sdb-ldap 1969-12-31 17:00:00.000000000 -0700
728 +++ bind-9.2.3/doc/INSTALL.sdb-ldap 2003-11-16 14:53:32.000000000 -0700
730 +This is the INSTALL file for 0.9. See
731 +http://www.venaas.no/ldap/bind-sdb/ for updates or other information.
735 +You need the source for BIND 9.1.0 or newer (for zone transfers you
736 +will need at least 9.1.1rc3 due to a bug). Basically you need to follow
737 +the instructions in doc/misc/sdb, if my instructions doesn't make sense,
738 +please have a look at that as well.
740 +Copy ldapdb.c to bin/named and ldapdb.h to bin/named/include in the
743 +Next alter bin/named/Makefile.in. Add ldapdb.@O@ to DBDRIVER_OBJS and
744 +ldapdb.c to DBDRIVER_SRCS. You also need to add something like
745 +-I/usr/local/include to DBDRIVER_INCLUDES and
746 +-L/usr/local/lib -lldap -llber -lresolv to DBDRIVER_LIBS
747 +depending on what LDAP library you have and where you installed it.
749 +Finally you need to edit bin/named/main.c. Below where it says
750 +"#include "xxdb.h"", add the line "#include <ldapdb.h>". Below where
751 +it says "xxdb_init();" add the line "ldapdb_init();", and finally
752 +below where it says "xxdb_clear();", add "ldapdb_clear();".
754 +Now you should hopefully be able to build it. If you get an error
755 +message about ldap_memfree() not being defined, you're probably
756 +using an LDAP library with the interface defined in RFC 1823. To
757 +build, uncomment the #define RFC1823API line near the top of ldapdb.c.
762 +Before you do any configuring of LDAP stuff, please try to configure
763 +and start bind as usual to see if things work.
765 +To do anything useful, you need to store a zone in some LDAP server.
766 +From this release on, you must use a schema called dNSZone. Note that
767 +it relies on some attribute definitions in the Cosine schema, so that
768 +must be included as well. The Cosine schema probably comes with your
769 +LDAP server. You can find dNSZone and further details on how to store
770 +the data in your LDAP server at
771 +http://www.venaas.no/ldap/bind-sdb/
773 +For an example, have a look at my venaas.com zone. Try a subtree search
774 +for objectClass=* at
775 +ldap ldap://129.241.20.67/dc=venaas,dc=com,o=DNS,dc=venaas,dc=no
777 +To use it with BIND, I've added the following to named.conf:
780 + database "ldap ldap://129.241.20.67/dc=venaas,dc=com,o=DNS,dc=venaas,dc=no 172800";
783 +When doing lookups BIND will do a sub-tree search below the base in the
784 +URL. The number 172800 is the TTL which will be used for all entries that
785 +haven't got the dNSTTL attribute. It is also possible to add an filter to
786 +the URL, say ldap://host/base???(o=internal)
788 +Stig Venaas <venaas@uninett.no> 2002-04-17
789 diff -urN bind-9.2.3-orig/doc/README.sdb-ldap bind-9.2.3/doc/README.sdb-ldap
790 --- bind-9.2.3-orig/doc/README.sdb-ldap 1969-12-31 17:00:00.000000000 -0700
791 +++ bind-9.2.3/doc/README.sdb-ldap 2003-11-16 14:53:18.000000000 -0700
793 +This is an attempt at an LDAP back-end for BIND 9 using the new simplified
794 +database interface "sdb". This is the nineth release (0.9) and seems to
795 +be pretty stable. Note that since version 0.4 a new schema is used.
796 +It is not backwards compatible with versions before 0.4.
798 +In 0.9 the code has been cleaned up a bit and should be slightly faster
799 +than previous versions. It also fixes an error with zone transfers (AXFR)
800 +and entries with multiple relativeDomainName values. The problem was
801 +that it would only use the first value in the result. There's no need
802 +to upgrade unless you use such entries.
804 +0.8 uses asynchronous LDAP search which should give better performance.
805 +Thanks to Ashley Burston for providing patch. Another new feature is
806 +allowing filters in URLs. The syntax is as in RFC 2255. Few people will
807 +need this, but if you have say an internal and external version of the
808 +same zone, you could stick say o=internal and o=external into different
809 +entries, and specify for instance ldap://host/base???(o=internal)
810 +Some error logging has also been added.
812 +0.7 allows space and other characters to be used in URLs by use of %-quoting.
813 +For instance space can be written as %20. It also fixes a problem with some
814 +servers and/or APIs that do not preserve attribute casing.
816 +0.6 fixes some memory leaks present in older versions unless compiled with
819 +The big changes in 0.5 are thread support and improved connection handling.
820 +Multiple threads can now access the back-end simultaneously, and rather than
821 +having one connection per zone, there is now one connection per thread per
822 +LDAP server. This should help people with multiple CPUs and people with a
823 +huge number of zones. One final change is support for literal IPv6 addresses
824 +in LDAP URLs. At least OpenLDAP 2 has IPv6 support, so if you use OpenLDAP 2
825 +libraries and server, you got all you need.
827 +If you have bug reports, fixes, comments, questions or whatever, please
828 +contact me. See also http://www.venaas.no/ldap/bind-sdb/ for information.
830 +See INSTALL for how to build, install and use.
832 +Stig Venaas <venaas@uninett.no> 2001-12-29