You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
calculate-overlay/net-dns/bind/files/bind-9.14.8-sdb-ldap.patch

2467 lines
68 KiB

diff --git a/bin/named/Makefile.in b/bin/named/Makefile.in
index 40f506c..697059f 100644
--- a/bin/named/Makefile.in
+++ b/bin/named/Makefile.in
@@ -30,10 +30,10 @@ VERSION=@BIND9_VERSION@
#
# Add database drivers here.
#
-DBDRIVER_OBJS =
-DBDRIVER_SRCS =
+DBDRIVER_OBJS = ldapdb.@O@
+DBDRIVER_SRCS = ldapdb.c
DBDRIVER_INCLUDES =
-DBDRIVER_LIBS =
+DBDRIVER_LIBS = -lldap -llber -ldb
DLZ_DRIVER_DIR = ${top_srcdir}/contrib/dlz/drivers
diff --git a/bin/named/main.c b/bin/named/main.c
index 15dbce2..ec96f14 100644
--- a/bin/named/main.c
+++ b/bin/named/main.c
@@ -90,6 +90,7 @@
* Include header files for database drivers here.
*/
/* #include "xxdb.h" */
+#include "ldapdb.h"
#ifdef CONTRIB_DLZ
/*
@@ -921,6 +922,8 @@ dump_symboltable(void) {
if (!isc_log_wouldlog(named_g_lctx, ISC_LOG_DEBUG(99)))
return;
+ ldapdb_clear();
+
isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
NAMED_LOGMODULE_MAIN, ISC_LOG_DEBUG(99),
"Symbol table:");
@@ -1213,6 +1216,24 @@ setup(void) {
isc_result_totext(result));
#endif
+ result = ldapdb_init();
+ if (result != ISC_R_SUCCESS)
+ {
+ isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, NAMED_LOGMODULE_MAIN,
+ ISC_LOG_ERROR,
+ "SDB ldap module initialisation failed: %s.",
+ isc_result_totext(result)
+ );
+ isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, NAMED_LOGMODULE_MAIN,
+ ISC_LOG_ERROR,
+ "SDB ldap zone database will be unavailable."
+ );
+ }else
+ isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, NAMED_LOGMODULE_MAIN,
+ ISC_LOG_NOTICE, "SDB ldap zone database module loaded."
+ );
+
+
named_server_create(named_g_mctx, &named_g_server);
sctx = named_g_server->sctx;
@@ -1282,6 +1303,8 @@ cleanup(void) {
dns_name_destroy();
+ ldapdb_clear();
+
isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
NAMED_LOGMODULE_MAIN,
ISC_LOG_NOTICE, "exiting");
diff --git a/bin/tools/Makefile.in b/bin/tools/Makefile.in
index d153097..4de6ce3 100644
--- a/bin/tools/Makefile.in
+++ b/bin/tools/Makefile.in
@@ -19,7 +19,7 @@ CINCLUDES = ${DNS_INCLUDES} ${ISC_INCLUDES} ${ISCCFG_INCLUDES} \
${BIND9_INCLUDES} ${MAXMINDDB_CFLAGS} \
@OPENSSL_INCLUDES@
-CDEFINES = -DVERSION=\"${VERSION}\"
+CDEFINES = -DVERSION=\"${VERSION}\" -DBIND9
CWARNINGS =
DNSLIBS = ../../lib/dns/libdns.@A@ ${MAXMINDDB_LIBS} @DNS_CRYPTO_LIBS@
@@ -27,13 +27,18 @@ BIND9LIBS = ../../lib/bind9/libbind9.@A@
ISCLIBS = ../../lib/isc/libisc.@A@ @OPENSSL_LIBS@
ISCNOSYMLIBS = ../../lib/isc/libisc-nosymtbl.@A@ @OPENSSL_LIBS@
ISCCFGLIBS = ../../lib/isccfg/libisccfg.@A@
+ISCCCLIBS = ../../lib/isccc/libisccc.@A@
DNSDEPLIBS = ../../lib/dns/libdns.@A@
BIND9DEPLIBS = ../../lib/bind9/libbind9.@A@
ISCDEPLIBS = ../../lib/isc/libisc.@A@
ISCCFGDEPLIBS = ../../lib/isccfg/libisccfg.@A@
+ISCCCDEPLIBS = ../../lib/isccc/libisccc.@A@
-LIBS = ${ISCLIBS} @LIBS@
+DEPLIBS = ${LWRESDEPLIBS} ${DNSDEPLIBS} ${BIND9DEPLIBS} \
+ ${ISCCFGDEPLIBS} ${ISCCCDEPLIBS} ${ISCDEPLIBS}
+LIBS = ${LWRESLIBS} ${DNSLIBS} ${BIND9LIBS} \
+ ${ISCCFGLIBS} ${ISCCCLIBS} ${ISCLIBS} ${DBDRIVER_LIBS} @LIBS@
NOSYMLIBS = ${ISCNOSYMLIBS} @LIBS@
SUBDIRS =
@@ -43,17 +48,19 @@ NZDTARGETS = named-nzd2nzf@EXEEXT@
TARGETS = arpaname@EXEEXT@ named-journalprint@EXEEXT@ \
named-rrchecker@EXEEXT@ nsec3hash@EXEEXT@ \
mdig@EXEEXT@ \
- @DNSTAPTARGETS@ @NZDTARGETS@
+ @DNSTAPTARGETS@ @NZDTARGETS@ ldap2zone@EXEEXT@ \
+ zone2ldap@EXEEXT@
DNSTAPSRCS = dnstap-read.c
NZDSRCS = named-nzd2nzf.c
SRCS = arpaname.c named-journalprint.c named-rrchecker.c \
nsec3hash.c mdig.c \
- @DNSTAPSRCS@ @NZDSRCS@
+ @DNSTAPSRCS@ @NZDSRCS@ ldap2zone.c zone2ldap.c
MANPAGES = arpaname.1 dnstap-read.1 \
mdig.1 named-journalprint.8 \
- named-nzd2nzf.8 named-rrchecker.1 nsec3hash.8
+ named-nzd2nzf.8 named-rrchecker.1 nsec3hash.8 \
+ ldap2zone.1 zone2ldap.1
HTMLPAGES = arpaname.html dnstap-read.html \
mdig.html named-journalprint.html \
@@ -97,6 +104,12 @@ named-nzd2nzf@EXEEXT@: named-nzd2nzf.@O@ ${NZDDEPLIBS}
export LIBS0="${ISCCFGLIBS} ${ISCCCLIBS} ${BIND9LIBS} ${DNSLIBS}"; \
${FINALBUILDCMD}
+ldap2zone@EXEEXT@: ldap2zone.@O@ ${DEPLIBS}
+ ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ ldap2zone.@O@ -lldap -llber ${LIBS}
+
+zone2ldap@EXEEXT@: zone2ldap.@O@ ${DEPLIBS}
+ ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ zone2ldap.@O@ -lldap -llber ${LIBS}
+
doc man:: ${MANOBJS}
docclean manclean maintainer-clean::
@@ -129,7 +142,11 @@ install:: ${TARGETS} installdirs @DNSTAP@ @NZD_TOOLS@
${DESTDIR}${sbindir}
${LIBTOOL_MODE_INSTALL} ${INSTALL_PROGRAM} mdig@EXEEXT@ \
${DESTDIR}${bindir}
+ ${LIBTOOL_MODE_INSTALL} ${INSTALL_PROGRAM} zone2ldap@EXEEXT@ ${DESTDIR}${sbindir}
+ ${LIBTOOL_MODE_INSTALL} ${INSTALL_PROGRAM} ldap2zone@EXEEXT@ ${DESTDIR}${sbindir}
${INSTALL_DATA} ${srcdir}/arpaname.1 ${DESTDIR}${mandir}/man1
+ ${INSTALL_DATA} ${srcdir}/zone2ldap.1 ${DESTDIR}${mandir}/man1
+ ${INSTALL_DATA} ${srcdir}/ldap2zone.1 ${DESTDIR}${mandir}/man1
${INSTALL_DATA} ${srcdir}/named-journalprint.8 ${DESTDIR}${mandir}/man8
${INSTALL_DATA} ${srcdir}/named-rrchecker.1 ${DESTDIR}${mandir}/man1
${INSTALL_DATA} ${srcdir}/nsec3hash.8 ${DESTDIR}${mandir}/man8
diff --git a/contrib/sdb/ldap/INSTALL.ldap b/contrib/sdb/ldap/INSTALL.ldap
new file mode 100644
index 0000000..9151129
--- /dev/null
+++ b/contrib/sdb/ldap/INSTALL.ldap
@@ -0,0 +1,83 @@
+This is the INSTALL file for 1.0-beta. See
+http://www.venaas.no/ldap/bind-sdb/ for updates or other information.
+
+BUILDING
+
+You need the source for BIND 9.1.0 or newer (for zone transfers you
+will need at least 9.1.1rc3 due to a bug). Basically you need to follow
+the instructions in doc/misc/sdb, if my instructions don't make sense,
+please have a look at those as well.
+
+Copy ldapdb.c to bin/named and ldapdb.h to bin/named/include in the
+source tree.
+
+Next alter bin/named/Makefile.in. Add ldapdb.@O@ to DBDRIVER_OBJS and
+ldapdb.c to DBDRIVER_SRCS. You also need to add something like
+-I/usr/local/include to DBDRIVER_INCLUDES and
+-L/usr/local/lib -lldap -llber -lresolv to DBDRIVER_LIBS
+depending on what LDAP library you have and where you installed it.
+
+Finally you need to edit bin/named/main.c. Below where it says
+"#include "xxdb.h"", add the line "#include <ldapdb.h>". Below where
+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 as usual; first configure
+and then make. 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
+LDAPDB_RFC1823API" line near the top of ldapdb.c.
+
+Also, if you're using an LDAPv2 only server, you need to change
+the line "#define LDAPDB_LDAP_VERSION 3" in ldapdb.c. Simply
+replace 3 with 2. Instead of editing the file, you may define
+LDAPDB_LDAP_VERSION yourself.
+
+If you want to use TLS, you need to uncommed the #define LDAPDB_TLS"
+line near the top of ldapdb.c.
+
+CONFIGURING
+
+Before you do any configuring of LDAP stuff, please try to configure
+and start bind as usual to see if things work.
+
+To do anything useful, you need to store a zone in some LDAP server.
+You must use a schema called dNSZone. Note that it relies on some
+attribute definitions in the Cosine schema, so that must be included
+as well. The Cosine schema probably comes with your LDAP server. You
+can find dNSZone and further details on how to store the data in your
+LDAP server at http://www.venaas.no/ldap/bind-sdb/
+
+To make BIND use a zone stored in LDAP, you will have to put something
+like this in named.conf:
+
+zone "venaas.com" {
+ type master;
+ database "ldap ldap://158.38.160.245/dc=venaas,dc=com,o=DNS,dc=venaas,dc=no 172800";
+};
+
+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. It is also possible to add a filter to
+the URL, say "ldap://host/base???(o=internal)".
+
+Version 1.0 also has support for simple LDAP bind, that is, binding to
+LDAP using plain text authentication. The bind dn and password is coded
+into the URL as extensions, according to RFC 2255. If you want simple
+bind with say dn "cn=Manager,dc=venaas,dc=no" and password "secret", the
+URL will be something like this:
+
+ldap://158.38.160.245/dc=venaas,dc=com,o=DNS,dc=venaas,dc=no????!bindname=cn=Manager%2cdc=venaas%2cdc=no,!x-bindpw=secret
+
+This URL may also include a filter part if you need it. Note that in
+the bind dn, "," is hex-escaped as "%2c". This is necessary since ","
+is the separator between the extension elements. The "!" in front of
+"bindname" and "x-bindpw" can be omitted if you prefer. "x-bindpw" is
+not standardized, but it's used by several other LDAP applications. See
+RFC 2255 for details.
+
+Finally, if you enabled TLS when compiling, you can also use TLS if
+you like. To do this you use the extension "x-tls", e.g.
+ldap://158.38.160.245/dc=venaas,dc=com,o=DNS,dc=venaas,dc=no????!bindname=cn=Manager%2cdc=venaas%2cdc=no,!x-bindpw=secret,x-tls
+
+Stig Venaas <venaas@uninett.no> 2004-08-15
diff --git a/contrib/sdb/ldap/README.ldap b/contrib/sdb/ldap/README.ldap
new file mode 100644
index 0000000..b4ea18a
--- /dev/null
+++ b/contrib/sdb/ldap/README.ldap
@@ -0,0 +1,48 @@
+This is an attempt at an LDAP back-end for BIND 9 using the new simplified
+database interface "sdb". This is release 1.0-beta and should be pretty
+stable. Note that since version 0.4 a new schema is used. It is not
+backwards compatible with versions before 0.4.
+
+1.0-beta fixes a large memory leak. An extension x-tls for enabling TLS
+has been added.
+
+1.0-alpha uses LDAPv3 by default and also supports LDAP simple bind. That
+is, one can use plain text password for authentication. The bind dn and
+password is coded into the URL using extensions bindname and x-bindpw
+per RFC 2255.
+
+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> 2004-08-15
diff --git a/contrib/sdb/ldap/README.zone2ldap b/contrib/sdb/ldap/README.zone2ldap
new file mode 100644
index 0000000..dacb56b
--- /dev/null
+++ b/contrib/sdb/ldap/README.zone2ldap
@@ -0,0 +1,17 @@
+INSTALLATION
+
+To Compile zone2ldap from contrib/sdb directory:
+
+ gcc -g `../../../isc-config.sh --cflags isc dns` -c zone2ldap.c
+ gcc -g -o zone2ldap zone2ldap.o `../../../isc-config.sh --libs isc dns` -lldap -llber -lresolv
+
+USAGE:
+
+See zone2ldap.1
+
+BUGS:
+
+Jeff McNeil <jeff@snapcase.g-rock.net>
+
+
+
diff --git a/contrib/sdb/ldap/ldap2zone.1 b/contrib/sdb/ldap/ldap2zone.1
new file mode 100644
index 0000000..a48c69f
--- /dev/null
+++ b/contrib/sdb/ldap/ldap2zone.1
@@ -0,0 +1,41 @@
+.\" Copyright (C) 2004, 2005 Stig Venaas <venaas@uninett.no>
+.\"
+.\" 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.
+.\" Manpage written by Jan Gorig
+.TH ldap2zone 1 "15 March 2010" "BIND9"
+.SH NAME
+ldap2zone - Creates zone file from LDAP dnszone information
+.SH SYNOPSIS
+.B ldap2zone zone-name LDAP-URL default-ttl [serial]
+.SH DESCRIPTION
+ldap2zone is a tool that reads info for a zone from LDAP and constructs a standard plain ascii zone file that is written to the standard output. The LDAP information has to be stored using the dnszone schema. The schema is used by BIND with LDAP back-end.
+
+\fBzone-name\fR
+.RS 4
+Name of the zone, eg "mydomain.net."
+.RE
+.PP
+\fBLDAP-URL\fR
+.RS 4
+LDAP URL to dnszone information
+.RE
+.PP
+\fBdefault-ttl\fR
+.RS 4
+Default TTL value to be used in zone
+.RE
+.PP
+\fBserial\fR
+.RS 4
+(optional) Program checks this number to be different than SOA serial number.
+.RE
+
+.SH "EXIT STATUS"
+Exits with 0 on success or 1 on failure.
+.SH "SEE ALSO"
+named(8) ldap(3)
+http://www.venaas.no/dns/ldap2zone/
+.SH "COPYRIGHT"
+Copyright (C) 2004, 2005 Stig Venaas
diff --git a/contrib/sdb/ldap/ldap2zone.c b/contrib/sdb/ldap/ldap2zone.c
new file mode 100644
index 0000000..80e7919
--- /dev/null
+++ b/contrib/sdb/ldap/ldap2zone.c
@@ -0,0 +1,411 @@
+/*
+ * Copyright (C) 2004, 2005 Stig Venaas <venaas@uninett.no>
+ * $Id: ldap2zone.c,v 1.1 2007/07/24 15:18:00 atkac Exp $
+ *
+ * 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.
+ */
+
+#define LDAP_DEPRECATED 1
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+
+#include <ldap.h>
+
+struct string {
+ void *data;
+ size_t len;
+};
+
+struct assstack_entry {
+ struct string key;
+ struct string val;
+ struct assstack_entry *next;
+};
+
+struct assstack_entry *assstack_find(struct assstack_entry *stack, struct string *key);
+void assstack_push(struct assstack_entry **stack, struct assstack_entry *item);
+void assstack_insertbottom(struct assstack_entry **stack, struct assstack_entry *item);
+void printsoa(struct string *soa);
+void printrrs(char *defaultttl, struct assstack_entry *item);
+void print_zone(char *defaultttl, struct assstack_entry *stack);
+void usage(char *name);
+void err(char *name, const char *msg);
+int putrr(struct assstack_entry **stack, struct berval *name, char *type, char *ttl, struct berval *val);
+
+struct assstack_entry *assstack_find(struct assstack_entry *stack, struct string *key) {
+ for (; stack; stack = stack->next)
+ if (stack->key.len == key->len && !memcmp(stack->key.data, key->data, key->len))
+ return stack;
+ return NULL;
+}
+
+void assstack_push(struct assstack_entry **stack, struct assstack_entry *item) {
+ item->next = *stack;
+ *stack = item;
+}
+
+void assstack_insertbottom(struct assstack_entry **stack, struct assstack_entry *item) {
+ struct assstack_entry *p;
+
+ item->next = NULL;
+ if (!*stack) {
+ *stack = item;
+ return;
+ }
+ /* find end, should keep track of end somewhere */
+ /* really a queue, not a stack */
+ p = *stack;
+ while (p->next)
+ p = p->next;
+ p->next = item;
+}
+
+void printsoa(struct string *soa) {
+ char *s;
+ size_t i;
+
+ s = (char *)soa->data;
+ i = 0;
+ while (i < soa->len) {
+ putchar(s[i]);
+ if (s[i++] == ' ')
+ break;
+ }
+ while (i < soa->len) {
+ putchar(s[i]);
+ if (s[i++] == ' ')
+ break;
+ }
+ printf("(\n\t\t\t\t");
+ while (i < soa->len) {
+ putchar(s[i]);
+ if (s[i++] == ' ')
+ break;
+ }
+ printf("; Serialnumber\n\t\t\t\t");
+ while (i < soa->len) {
+ if (s[i] == ' ')
+ break;
+ putchar(s[i++]);
+ }
+ i++;
+ printf("\t; Refresh\n\t\t\t\t");
+ while (i < soa->len) {
+ if (s[i] == ' ')
+ break;
+ putchar(s[i++]);
+ }
+ i++;
+ printf("\t; Retry\n\t\t\t\t");
+ while (i < soa->len) {
+ if (s[i] == ' ')
+ break;
+ putchar(s[i++]);
+ }
+ i++;
+ printf("\t; Expire\n\t\t\t\t");
+ while (i < soa->len) {
+ putchar(s[i++]);
+ }
+ printf(" )\t; Minimum TTL\n");
+}
+
+void printrrs(char *defaultttl, struct assstack_entry *item) {
+ struct assstack_entry *stack;
+ char *s;
+ int first;
+ size_t i;
+ char *ttl, *type;
+ int top;
+
+ s = (char *)item->key.data;
+
+ if (item->key.len == 1 && *s == '@') {
+ top = 1;
+ printf("@\t");
+ } else {
+ top = 0;
+ for (i = 0; i < item->key.len; i++)
+ putchar(s[i]);
+ if (item->key.len < 8)
+ putchar('\t');
+ putchar('\t');
+ }
+
+ first = 1;
+ for (stack = (struct assstack_entry *) item->val.data; stack; stack = stack->next) {
+ ttl = (char *)stack->key.data;
+ s = strchr(ttl, ' ');
+ *s++ = '\0';
+ type = s;
+
+ if (first)
+ first = 0;
+ else
+ printf("\t\t");
+
+ if (strcmp(defaultttl, ttl))
+ printf("%s", ttl);
+ putchar('\t');
+
+ if (top) {
+ top = 0;
+ printf("IN\t%s\t", type);
+ /* Should always be SOA here */
+ if (!strcmp(type, "SOA")) {
+ printsoa(&stack->val);
+ continue;
+ }
+ } else
+ printf("%s\t", type);
+
+ s = (char *)stack->val.data;
+ for (i = 0; i < stack->val.len; i++)
+ putchar(s[i]);
+ putchar('\n');
+ }
+}
+
+void print_zone(char *defaultttl, struct assstack_entry *stack) {
+ printf("$TTL %s\n", defaultttl);
+ for (; stack; stack = stack->next)
+ printrrs(defaultttl, stack);
+};
+
+void usage(char *name) {
+ fprintf(stderr, "Usage:%s zone-name LDAP-URL default-ttl [serial]\n", name);
+ exit(1);
+};
+
+void err(char *name, const char *msg) {
+ fprintf(stderr, "%s: %s\n", name, msg);
+ exit(1);
+};
+
+int putrr(struct assstack_entry **stack, struct berval *name, char *type, char *ttl, struct berval *val) {
+ struct string key;
+ struct assstack_entry *rr, *rrdata;
+
+ /* Do nothing if name or value have 0 length */
+ if (!name->bv_len || !val->bv_len)
+ return 0;
+
+ /* see if already have an entry for this name */
+ key.len = name->bv_len;
+ key.data = name->bv_val;
+
+ rr = assstack_find(*stack, &key);
+ if (!rr) {
+ /* Not found, create and push new entry */
+ rr = (struct assstack_entry *) malloc(sizeof(struct assstack_entry));
+ if (!rr)
+ return -1;
+ rr->key.len = name->bv_len;
+ rr->key.data = (void *) malloc(rr->key.len);
+ if (!rr->key.data) {
+ free(rr);
+ return -1;
+ }
+ memcpy(rr->key.data, name->bv_val, name->bv_len);
+ rr->val.len = sizeof(void *);
+ rr->val.data = NULL;
+ if (name->bv_len == 1 && *(char *)name->bv_val == '@')
+ assstack_push(stack, rr);
+ else
+ assstack_insertbottom(stack, rr);
+ }
+
+ rrdata = (struct assstack_entry *) malloc(sizeof(struct assstack_entry));
+ if (!rrdata) {
+ free(rr->key.data);
+ free(rr);
+ return -1;
+ }
+ rrdata->key.len = strlen(type) + strlen(ttl) + 1;
+ rrdata->key.data = (void *) malloc(rrdata->key.len);
+ if (!rrdata->key.data) {
+ free(rrdata);
+ free(rr->key.data);
+ free(rr);
+ return -1;
+ }
+ sprintf((char *)rrdata->key.data, "%s %s", ttl, type);
+
+ rrdata->val.len = val->bv_len;
+ rrdata->val.data = (void *) malloc(val->bv_len);
+ if (!rrdata->val.data) {
+ free(rrdata->key.data);
+ free(rrdata);
+ free(rr->key.data);
+ free(rr);
+ return -1;
+ }
+ memcpy(rrdata->val.data, val->bv_val, val->bv_len);
+
+ if (!strcmp(type, "SOA"))
+ assstack_push((struct assstack_entry **) &(rr->val.data), rrdata);
+ else
+ assstack_insertbottom((struct assstack_entry **) &(rr->val.data), rrdata);
+ return 0;
+}
+
+int main(int argc, char **argv) {
+ char *s, *hostporturl, *base = NULL;
+ char *ttl, *defaultttl;
+ LDAP *ld;
+ char *fltr = NULL;
+ LDAPMessage *res, *e;
+ char *a, **ttlvals, **soavals, *serial;
+ struct berval **vals, **names;
+ char type[64];
+ BerElement *ptr;
+ int i, j, rc, msgid;
+ struct assstack_entry *zone = NULL;
+
+ if (argc < 4 || argc > 5)
+ usage(argv[0]);
+
+ hostporturl = argv[2];
+
+ if (hostporturl != strstr( hostporturl, "ldap"))
+ err(argv[0], "Not an LDAP URL");
+
+ s = strchr(hostporturl, ':');
+
+ if (!s || strlen(s) < 3 || s[1] != '/' || s[2] != '/')
+ err(argv[0], "Not an LDAP URL");
+
+ s = strchr(s+3, '/');
+ if (s) {
+ *s++ = '\0';
+ base = s;
+ s = strchr(base, '?');
+ if (s)
+ err(argv[0], "LDAP URL can only contain host, port and base");
+ }
+
+ defaultttl = argv[3];
+
+ rc = ldap_initialize(&ld, hostporturl);
+ if (rc != LDAP_SUCCESS)
+ err(argv[0], "ldap_initialize() failed");
+
+ if (argc == 5) {
+ /* serial number specified, check if different from one in SOA */
+ fltr = (char *)malloc(strlen(argv[1]) + strlen("(&(relativeDomainName=@)(zoneName=))") + 1);
+ sprintf(fltr, "(&(relativeDomainName=@)(zoneName=%s))", argv[1]);
+ msgid = ldap_search(ld, base, LDAP_SCOPE_SUBTREE, fltr, NULL, 0);
+ if (msgid == -1)
+ err(argv[0], "ldap_search() failed");
+
+ while ((rc = ldap_result(ld, msgid, 0, NULL, &res)) != LDAP_RES_SEARCH_RESULT ) {
+ /* not supporting continuation references at present */
+ if (rc != LDAP_RES_SEARCH_ENTRY)
+ err(argv[0], "ldap_result() returned cont.ref? Exiting");
+
+ /* only one entry per result message */
+ e = ldap_first_entry(ld, res);
+ if (e == NULL) {
+ ldap_msgfree(res);
+ err(argv[0], "ldap_first_entry() failed");
+ }
+
+ soavals = ldap_get_values(ld, e, "SOARecord");
+ if (soavals)
+ break;
+ }
+
+ ldap_msgfree(res);
+ if (!soavals) {
+ err(argv[0], "No SOA Record found");
+ }
+
+ /* We have a SOA, compare serial numbers */
+ /* Only checkinf first value, should be only one */
+ s = strchr(soavals[0], ' ');
+ s++;
+ s = strchr(s, ' ');
+ s++;
+ serial = s;
+ s = strchr(s, ' ');
+ *s = '\0';
+ if (!strcmp(serial, argv[4])) {
+ ldap_value_free(soavals);
+ err(argv[0], "serial numbers match");
+ }
+ ldap_value_free(soavals);
+ }
+
+ if (!fltr)
+ fltr = (char *)malloc(strlen(argv[1]) + strlen("(zoneName=)") + 1);
+ if (!fltr)
+ err(argv[0], "Malloc failed");
+ sprintf(fltr, "(zoneName=%s)", argv[1]);
+
+ msgid = ldap_search(ld, base, LDAP_SCOPE_SUBTREE, fltr, NULL, 0);
+ if (msgid == -1)
+ err(argv[0], "ldap_search() failed");
+
+ while ((rc = ldap_result(ld, msgid, 0, NULL, &res)) != LDAP_RES_SEARCH_RESULT ) {
+ /* not supporting continuation references at present */
+ if (rc != LDAP_RES_SEARCH_ENTRY)
+ err(argv[0], "ldap_result() returned cont.ref? Exiting");
+
+ /* only one entry per result message */
+ e = ldap_first_entry(ld, res);
+ if (e == NULL) {
+ ldap_msgfree(res);
+ err(argv[0], "ldap_first_entry() failed");
+ }
+
+ names = ldap_get_values_len(ld, e, "relativeDomainName");
+ if (!names)
+ continue;
+
+ ttlvals = ldap_get_values(ld, e, "dNSTTL");
+ ttl = ttlvals ? ttlvals[0] : defaultttl;
+
+ 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))) {
+ ldap_memfree(a);
+ continue;
+ }
+
+ strncpy(type, a, s - a);
+ type[s - a] = '\0';
+ vals = ldap_get_values_len(ld, e, a);
+ if (vals) {
+ for (i = 0; vals[i]; i++)
+ for (j = 0; names[j]; j++)
+ if (putrr(&zone, names[j], type, ttl, vals[i]))
+ err(argv[0], "malloc failed");
+ ldap_value_free_len(vals);
+ }
+ ldap_memfree(a);
+ }
+
+ if (ptr)
+ ber_free(ptr, 0);
+ if (ttlvals)
+ ldap_value_free(ttlvals);
+ ldap_value_free_len(names);
+ /* free this result */
+ ldap_msgfree(res);
+ }
+
+ /* free final result */
+ ldap_msgfree(res);
+
+ print_zone(defaultttl, zone);
+ return 0;
+}
diff --git a/contrib/sdb/ldap/ldapdb.c b/contrib/sdb/ldap/ldapdb.c
new file mode 100644
index 0000000..4c1e90c
--- /dev/null
+++ b/contrib/sdb/ldap/ldapdb.c
@@ -0,0 +1,691 @@
+/*
+ * ldapdb.c version 1.0-beta
+ *
+ * Copyright (C) 2002, 2004 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.
+ *
+ * Contributors: Jeremy C. McDermond
+ */
+
+/*
+ * If you want to use TLS, uncomment the define below
+ */
+/* #define LDAPDB_TLS */
+
+/*
+ * 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().
+ * This also forces LDAPv2.
+ */
+/* #define LDAPDB_RFC1823API */
+
+/* Using LDAPv3 by default, change this if you want v2 */
+#ifndef LDAPDB_LDAP_VERSION
+#define LDAPDB_LDAP_VERSION 3
+#define LDAP_DEPRECATED 1
+#endif
+
+#include <config.h>
+
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+
+#include <isc/mem.h>
+#include <isc/print.h>
+#include <isc/result.h>
+#include <isc/util.h>
+#include <isc/thread.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
+ */
+
+/* enough for name with 8 labels of max length */
+#define MAXNAMELEN 519
+
+static dns_sdbimplementation_t *ldapdb = NULL;
+
+struct ldapdb_data {
+ char *hostport;
+ char *hostname;
+ int portno;
+ char *base;
+ int defaultttl;
+ char *filterall;
+ int filteralllen;
+ char *filterone;
+ int filteronelen;
+ char *filtername;
+ char *bindname;
+ char *bindpw;
+#ifdef LDAPDB_TLS
+ int tls;
+#endif
+};
+
+/* used by ldapdb_getconn */
+
+struct ldapdb_entry {
+ void *index;
+ size_t size;
+ void *data;
+ struct ldapdb_entry *next;
+};
+
+static struct ldapdb_entry *ldapdb_find(struct ldapdb_entry *stack,
+ const void *index, size_t size) {
+ while (stack != NULL) {
+ if (stack->size == size && !memcmp(stack->index, index, size))
+ return stack;
+ stack = stack->next;
+ }
+ return NULL;
+}
+
+static void ldapdb_insert(struct ldapdb_entry **stack,
+ struct ldapdb_entry *item) {
+ item->next = *stack;
+ *stack = item;
+}
+
+static void ldapdb_lock(int what) {
+ static isc_mutex_t lock;
+
+ switch (what) {
+ case 0:
+ isc_mutex_init(&lock);
+ break;
+ case 1:
+ LOCK(&lock);
+ break;
+ case -1:
+ UNLOCK(&lock);
+ break;
+ }
+}
+
+/* data == NULL means cleanup */
+static LDAP **
+ldapdb_getconn(struct ldapdb_data *data)
+{
+ static struct ldapdb_entry *allthreadsdata = NULL;
+ struct ldapdb_entry *threaddata, *conndata;
+ unsigned long threadid;
+
+ if (data == NULL) {
+ /* cleanup */
+ /* lock out other threads */
+ ldapdb_lock(1);
+ while (allthreadsdata != NULL) {
+ threaddata = allthreadsdata;
+ free(threaddata->index);
+ while (threaddata->data != NULL) {
+ conndata = threaddata->data;
+ if (conndata->data != NULL)
+ ldap_unbind((LDAP *)conndata->data);
+ threaddata->data = conndata->next;
+ free(conndata);
+ }
+ allthreadsdata = threaddata->next;
+ free(threaddata);
+ }
+ ldapdb_lock(-1);
+ return (NULL);
+ }
+
+ /* look for connection data for current thread */
+ threadid = isc_thread_self();
+ threaddata = ldapdb_find(allthreadsdata, &threadid, sizeof(threadid));
+ if (threaddata == NULL) {
+ /* no data for this thread, create empty connection list */
+ threaddata = malloc(sizeof(*threaddata));
+ if (threaddata == NULL)
+ return (NULL);
+ threaddata->index = malloc(sizeof(threadid));
+ if (threaddata->index == NULL) {
+ free(threaddata);
+ return (NULL);
+ }
+ *(unsigned long *)threaddata->index = threadid;
+ threaddata->size = sizeof(threadid);
+ threaddata->data = NULL;
+
+ /* need to lock out other threads here */
+ ldapdb_lock(1);
+ ldapdb_insert(&allthreadsdata, threaddata);
+ ldapdb_lock(-1);
+ }
+
+ /* threaddata points at the connection list for current thread */
+ /* look for existing connection to our server */
+ conndata = ldapdb_find((struct ldapdb_entry *)threaddata->data,
+ data->hostport, strlen(data->hostport));
+ if (conndata == NULL) {
+ /* no connection data structure for this server, create one */
+ conndata = malloc(sizeof(*conndata));
+ if (conndata == NULL)
+ return (NULL);
+ conndata->index = data->hostport;
+ conndata->size = strlen(data->hostport);
+ conndata->data = NULL;
+ ldapdb_insert((struct ldapdb_entry **)&threaddata->data,
+ conndata);
+ }
+
+ return (LDAP **)&conndata->data;
+}
+
+static void
+ldapdb_bind(struct ldapdb_data *data, LDAP **ldp)
+{
+#ifndef LDAPDB_RFC1823API
+ const int ver = LDAPDB_LDAP_VERSION;
+#endif
+
+ if (*ldp != NULL)
+ ldap_unbind(*ldp);
+ *ldp = ldap_open(data->hostname, data->portno);
+ if (*ldp == NULL)
+ return;
+
+#ifndef LDAPDB_RFC1823API
+ ldap_set_option(*ldp, LDAP_OPT_PROTOCOL_VERSION, &ver);
+#endif
+
+#ifdef LDAPDB_TLS
+ if (data->tls) {
+ ldap_start_tls_s(*ldp, NULL, NULL);
+ }
+#endif
+
+ if (ldap_simple_bind_s(*ldp, data->bindname, data->bindpw) != LDAP_SUCCESS) {
+ ldap_unbind(*ldp);
+ *ldp = NULL;
+ }
+}
+
+#ifdef DNS_CLIENTINFO_VERSION
+static isc_result_t
+ldapdb_search(const char *zone, const char *name, void *dbdata, void *retdata,
+ dns_clientinfomethods_t *methods, dns_clientinfo_t *clientinfo)
+#else
+static isc_result_t
+ldapdb_search(const char *zone, const char *name, void *dbdata, void *retdata,
+ void *methods, void *clientinfo)
+#endif /* DNS_CLIENTINFO_VERSION */
+{
+ struct ldapdb_data *data = dbdata;
+ isc_result_t result = ISC_R_NOTFOUND;
+ LDAP **ldp;
+ LDAPMessage *res, *e;
+ char *fltr, *a, **vals = NULL, **names = NULL;
+ char type[64];
+#ifdef LDAPDB_RFC1823API
+ void *ptr;
+#else
+ BerElement *ptr;
+#endif
+ int i, j, errno, msgid;
+
+ UNUSED(methods);
+ UNUSED(clientinfo);
+
+ ldp = ldapdb_getconn(data);
+ if (ldp == NULL)
+ return (ISC_R_FAILURE);
+ if (*ldp == NULL) {
+ ldapdb_bind(data, ldp);
+ if (*ldp == NULL) {
+ isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
+ "LDAP sdb zone '%s': bind failed", zone);
+ return (ISC_R_FAILURE);
+ }
+ }
+
+ if (name == NULL) {
+ fltr = data->filterall;
+ } else {
+ if (strlen(name) > MAXNAMELEN) {
+ isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, NAMED_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;
+ }
+
+ msgid = ldap_search(*ldp, data->base, LDAP_SCOPE_SUBTREE, fltr, NULL, 0);
+ if (msgid == -1) {
+ ldapdb_bind(data, ldp);
+ if (*ldp != NULL)
+ msgid = ldap_search(*ldp, data->base, LDAP_SCOPE_SUBTREE, fltr, NULL, 0);
+ }
+
+ if (*ldp == NULL || msgid == -1) {
+ isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
+ "LDAP sdb zone '%s': search failed, filter %s", zone, fltr);
+ return (ISC_R_FAILURE);
+ }
+
+ /* 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;
+
+ /* not supporting continuation references at present */
+ if (errno != LDAP_RES_SEARCH_ENTRY) {
+ isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, NAMED_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(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, NAMED_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;
+ }
+
+ 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))) {
+#ifndef LDAPDB_RFC1823API
+ ldap_memfree(a);
+#endif
+ continue;
+ }
+
+ strncpy(type, a, s - a);
+ type[s - a] = '\0';
+ vals = ldap_get_values(ld, e, a);
+ 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(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
+ "LDAP sdb zone '%s': dns_sdb_put... failed for %s", zone, vals[i]);
+ ldap_value_free(vals);
+#ifndef LDAPDB_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);
+ }
+#ifndef LDAPDB_RFC1823API
+ ldap_memfree(a);
+#endif
+ }
+#ifndef LDAPDB_RFC1823API
+ if (ptr != NULL)
+ ber_free(ptr, 0);
+#endif
+ if (name == NULL)
+ ldap_value_free(names);
+
+ /* free this result */
+ ldap_msgfree(res);
+ }
+
+ /* free final result */
+ ldap_msgfree(res);
+ return (result);
+}
+
+
+/* callback routines */
+#ifdef DNS_CLIENTINFO_VERSION
+static isc_result_t
+ldapdb_lookup(const char *zone, const char *name, void *dbdata,
+ dns_sdblookup_t *lookup, dns_clientinfomethods_t *methods,
+ dns_clientinfo_t *clientinfo)
+{
+ UNUSED(methods);
+ UNUSED(clientinfo);
+ return (ldapdb_search(zone, name, dbdata, lookup, NULL, NULL));
+}
+#else
+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, methods,
+ clientinfo));
+}
+#endif /* DNS_CLIENTINFO_VERSION */
+
+static isc_result_t
+ldapdb_allnodes(const char *zone, void *dbdata,
+ dns_sdballnodes_t *allnodes)
+{
+ return (ldapdb_search(zone, NULL, dbdata, allnodes, NULL, NULL));
+}
+
+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;
+}
+
+/* returns 0 for ok, -1 for bad syntax, -2 for unknown critical extension */
+static int
+parseextensions(char *extensions, struct ldapdb_data *data)
+{
+ char *s, *next, *name, *value;
+ int critical;
+
+ while (extensions != NULL) {
+ s = strchr(extensions, ',');
+ if (s != NULL) {
+ *s++ = '\0';
+ next = s;
+ } else {
+ next = NULL;
+ }
+
+ if (*extensions != '\0') {
+ s = strchr(extensions, '=');
+ if (s != NULL) {
+ *s++ = '\0';
+ value = *s != '\0' ? s : NULL;
+ } else {
+ value = NULL;
+ }
+ name = extensions;
+
+ critical = *name == '!';
+ if (critical) {
+ name++;
+ }
+ if (*name == '\0') {
+ return -1;
+ }
+
+ if (!strcasecmp(name, "bindname")) {
+ data->bindname = value;
+ } else if (!strcasecmp(name, "x-bindpw")) {
+ data->bindpw = value;
+#ifdef LDAPDB_TLS
+ } else if (!strcasecmp(name, "x-tls")) {
+ data->tls = value == NULL || !strcasecmp(value, "true");
+#endif
+ } else if (critical) {
+ return -2;
+ }
+ }
+ extensions = next;
+ }
+ return 0;
+}
+
+static void
+free_data(struct ldapdb_data *data)
+{
+ if (data->hostport != NULL)
+ isc_mem_free(named_g_mctx, data->hostport);
+ if (data->hostname != NULL)
+ isc_mem_free(named_g_mctx, data->hostname);
+ if (data->filterall != NULL)
+ isc_mem_put(named_g_mctx, data->filterall, data->filteralllen);
+ if (data->filterone != NULL)
+ isc_mem_put(named_g_mctx, data->filterone, data->filteronelen);
+ isc_mem_put(named_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, *extensions = 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(named_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(named_g_mctx, argv[0] + strlen("ldap://"));
+ if (data->hostport == NULL) {
+ free_data(data);
+ return (ISC_R_NOMEMORY);
+ }
+
+ data->defaultttl = defaultttl;
+
+ 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';
+ /* extensions */
+ extensions = s;
+ s = strchr(s, '?');
+ if (s != NULL) {
+ *s++ = '\0';
+ }
+ if (*extensions == '\0') {
+ extensions = NULL;
+ }
+ }
+ if (*filter == '\0') {
+ filter = NULL;
+ }
+ }
+ }
+ }
+ if (*data->base == '\0') {
+ data->base = NULL;
+ }
+ }
+
+ /* parse extensions */
+ if (extensions != NULL) {
+ int err;
+
+ err = parseextensions(extensions, data);
+ if (err < 0) {
+ /* err should be -1 or -2 */
+ free_data(data);
+ if (err == -1) {
+ isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
+ "LDAP sdb zone '%s': URL: extension syntax error", zone);
+ } else if (err == -2) {
+ isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
+ "LDAP sdb zone '%s': URL: unknown critical extension", zone);
+ }
+ return (ISC_R_FAILURE);
+ }
+ }
+
+ if ((data->base != NULL && unhex(data->base) == NULL) ||
+ (filter != NULL && unhex(filter) == NULL) ||
+ (data->bindname != NULL && unhex(data->bindname) == NULL) ||
+ (data->bindpw != NULL && unhex(data->bindpw) == NULL)) {
+ free_data(data);
+ isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
+ "LDAP sdb zone '%s': URL: bad hex values", zone);
+ return (ISC_R_FAILURE);
+ }
+
+ /* 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(named_g_mctx, data->filteralllen);
+ if (data->filterall == NULL) {
+ free_data(data);
+ return (ISC_R_NOMEMORY);
+ }
+ data->filterone = isc_mem_get(named_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(named_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 = {
+ ldapdb_lookup,
+ NULL, /* authority */
+ ldapdb_allnodes,
+ ldapdb_create,
+ ldapdb_destroy,
+ NULL /* lookup2 */
+};
+
+/* Wrapper around dns_sdb_register() */
+isc_result_t
+ldapdb_init(void) {
+ unsigned int flags =
+ DNS_SDBFLAG_RELATIVEOWNER |
+ DNS_SDBFLAG_RELATIVERDATA |
+ DNS_SDBFLAG_THREADSAFE;
+
+ ldapdb_lock(0);
+ return (dns_sdb_register("ldap", &ldapdb_methods, NULL, flags,
+ named_g_mctx, &ldapdb));
+}
+
+/* Wrapper around dns_sdb_unregister() */
+void
+ldapdb_clear(void) {
+ if (ldapdb != NULL) {
+ /* clean up thread data */
+ ldapdb_getconn(NULL);
+ dns_sdb_unregister(&ldapdb);
+ }
+}
diff --git a/contrib/sdb/ldap/ldapdb.h b/contrib/sdb/ldap/ldapdb.h
new file mode 100644
index 0000000..a08eb20
--- /dev/null
+++ b/contrib/sdb/ldap/ldapdb.h
@@ -0,0 +1,6 @@
+#include <isc/types.h>
+
+isc_result_t ldapdb_init(void);
+
+void ldapdb_clear(void);
+
diff --git a/contrib/sdb/ldap/zone2ldap.1 b/contrib/sdb/ldap/zone2ldap.1
new file mode 100644
index 0000000..781114b
--- /dev/null
+++ b/contrib/sdb/ldap/zone2ldap.1
@@ -0,0 +1,64 @@
+.TH zone2ldap 1 "8 March 2001"
+.SH NAME
+zone2ldap /- Load BIND 9 Zone files into LDAP Directory
+.SH SYNOPSIS
+zone2ldap [-D Bind DN] [-w Bind Password] [-b Base DN] [-z Zone] [-f Zone File ] [-h Ldap Host] [-cd] [-v]
+.SH DESCRIPTION
+zone2ldap will parse a complete BIND 9 format DNS zone file, and load
+the contents into an LDAP directory, for use with the LDAP sdb back-end.
+
+If the zone already exists, zone2ldap will exit succesfully. If the zone does not exists, or
+partially exists, zone2ldap will attempt to add all/missing zone data.
+
+.SS Options
+.TP
+-b
+LDAP Base DN. LDAP systems require a "base dn", which is generally considered the LDAP Directory root.
+If the zone you are loading is different from the base, then you will need to tell zone2ldap what your LDAP
+base is.
+.TP
+-v
+Print version information, and immediatly exit.
+.TP
+-f
+Zone file. Bind 9.1 compatible zone file, from which zone information will be read.
+.TP
+-d
+Dump debug information to standard out.
+.TP
+-w
+LDAP Bind password, corresponding the the value of "-b".
+.TP
+-h
+LDAP Directory host. This is the hostname of the LDAP system you wish to store zone information on.
+An LDAP server should be listening on port 389 of the target system. This may be ommited, and will default
+to "localhost".
+.TP
+-c
+This will create the zone portion of the DN you are importing. For instance, if you are creating a domain.com zone,
+zone2ldap should first create "dc=domain,dc=com". This is useful if you are creating multiple domains.
+.TP
+-z
+This is the name of the zone specified in the SOA record.
+.SH EXAMPLES
+Following are brief examples of how to import a zone file into your LDAP DIT.
+.SS Loading zone domain.com, with an LDAP Base DN of dc=domain,dc=com
+zone2ldap -D dc=root -w secret -h localhost -z domain.com -f domain.com.zone
+
+This will add Resource Records into an ALREADY EXISTING dc=domain,dc=com. The final SOA DN in this case, will be
+dc=@,dc=domain,dc=com
+
+.SS Loading customer.com, if your LDAP Base DN is dc=provider,dc=net.
+zone2ldap -D dc=root -w secret -h localhost -z customer.com -b dc=provider,dc=net -f customer.com.zone -c
+
+This will create dc=customer,dc=com under dc=provider,dc=net, and add all necessary Resource Records. The final
+root DN to the SOA will be dc=@,dc=customer,dc=com,dc=provider,dc=net.
+
+.SH "SEE ALSO"
+named(8) ldap(3)
+http://www.venaas.no/ldap/bind-sdb/
+.SH "BUGS"
+Send all bug reports to Jeff McNeil <jeff@snapcase.g-rock.net>
+.SH AUTHOR
+Jeff McNeil <jeff@snapcase.g-rock.net>
+
diff --git a/contrib/sdb/ldap/zone2ldap.c b/contrib/sdb/ldap/zone2ldap.c
new file mode 100644
index 0000000..83e88fb
--- /dev/null
+++ b/contrib/sdb/ldap/zone2ldap.c
@@ -0,0 +1,897 @@
+/*
+ * Copyright (C) 2001 Jeff McNeil <jeff@snapcase.g-rock.net>
+ *
+ * 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.
+ *
+ * Change Log
+ *
+ * Tue May 1 19:19:54 EDT 2001 - Jeff McNeil
+ * Update to objectClass code, and add_to_rr_list function
+ * (I need to rename that) to support the dNSZone schema,
+ * ditched dNSDomain2 schema support. Version 0.3-ALPHA
+ */
+
+
+#define LDAP_DEPRECATED 1
+
+#include <errno.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <getopt.h>
+
+#include <isc/buffer.h>
+//#include "entropy_private.h"
+#include <isc/hash.h>
+#include <isc/mem.h>
+#include <isc/print.h>
+#include <isc/hash.h>
+#include <isc/result.h>
+#include <isc/string.h>
+
+#include <dns/db.h>
+#include <dns/dbiterator.h>
+#include <dns/fixedname.h>
+#include <dns/name.h>
+#include <dns/rdata.h>
+#include <dns/rdataset.h>
+#include <dns/rdatasetiter.h>
+#include <dns/result.h>
+#include <dns/rdatatype.h>
+
+#define LDAP_DEPRECATED 1
+
+#include <ldap.h>
+
+#define DNS_OBJECT 6
+#define DNS_TOP 2
+
+#define VERSION "0.4-ALPHA"
+
+#define NO_SPEC 0
+#define WI_SPEC 1
+
+/* Global Zone Pointer */
+char *gbl_zone = NULL;
+
+typedef struct LDAP_INFO
+{
+ char *dn;
+ LDAPMod **attrs;
+ struct LDAP_INFO *next;
+ int attrcnt;
+}
+ldap_info;
+
+/* usage Info */
+void usage (void);
+
+/* Check for existence of (and possibly add) containing dNSZone objects */
+int lookup_dns_zones( ldap_info *ldinfo);
+
+/* Add to the ldap dit */
+void add_ldap_values (ldap_info * ldinfo);
+
+/* Init an ldap connection */
+void init_ldap_conn (void);
+
+/* Ldap error checking */
+void ldap_result_check (const char *msg, char *dn, int err);
+
+/* Put a hostname into a char ** array */
+char **hostname_to_dn_list (char *hostname, char *zone, unsigned int flags);
+
+/* Find out how many items are in a char ** array */
+int get_attr_list_size (char **tmp);
+
+/* Get a DN */
+char *build_dn_from_dc_list (char **dc_list, unsigned int ttl, int flag, char *zone);
+
+/* Add to RR list */
+void add_to_rr_list (char *dn, char *name, char *type, char *data,
+ unsigned int ttl, unsigned int flags);
+
+/* Error checking */
+void isc_result_check (isc_result_t res, const char *errorstr);
+
+/* Generate LDIF Format files */
+void generate_ldap (dns_name_t * dnsname, dns_rdata_t * rdata,
+ unsigned int ttl);
+
+/* head pointer to the list */
+ldap_info *ldap_info_base = NULL;
+
+ldap_info *
+locate_by_dn (char *dn);
+void
+init_ldap_conn ();
+void usage();
+
+static char *argzone, *ldapbase, *binddn, *bindpw = NULL;
+
+/* these are needed to placate gcc4's const-ness const-ernations : */
+static char localhost[] = "localhost";
+static char *ldapsystem=&(localhost[0]);
+/* dnszone schema class names: */
+static char topClass [] ="top";
+static char dNSZoneClass[] ="dNSZone";
+static char objectClass [] ="objectClass";
+static char dcObjectClass[]="dcObject";
+/* dnszone schema attribute names: */
+static char relativeDomainName[]="relativeDomainName";
+static char dNSTTL []="dNSTTL";
+static char zoneName []="zoneName";
+static char dc []="dc";
+static char sameZone []="@";
+/* LDAPMod mod_values: */
+static char *objectClasses []= { &(topClass[0]), &(dNSZoneClass[0]), NULL };
+static char *topObjectClasses []= { &(topClass[0]), &(dcObjectClass[0]), &(dNSZoneClass[0]), NULL };
+static char *dn_buffer [64]={NULL};
+
+LDAP *conn;
+unsigned int debug = 0;
+
+#ifdef DEBUG
+debug = 1;
+#endif
+
+static void
+fatal(const char *msg) {
+ perror(msg);
+ if (conn != NULL)
+ ldap_unbind_s(conn);
+ exit(1);
+}
+
+int
+main (int argc, char **argv)
+{
+ isc_mem_t *mctx = NULL;
+ //isc_entropy_t *ectx = NULL;
+ isc_result_t result;
+ char *basedn;
+ ldap_info *tmp;
+ LDAPMod *base_attrs[5];
+ LDAPMod base, dcBase, znBase, rdnBase;
+ isc_buffer_t buff;
+ char *zonefile=0L;
+ char fullbasedn[1024];
+ char *ctmp, *zn, *dcp[2], *znp[2], *rdn[2];
+ dns_fixedname_t fixedzone, fixedname;
+ dns_rdataset_t rdataset;
+ char **dc_list;
+ dns_rdata_t rdata = DNS_RDATA_INIT;
+ dns_rdatasetiter_t *riter;
+ dns_name_t *zone, *name;
+ dns_db_t *db = NULL;
+ dns_dbiterator_t *dbit = NULL;
+ dns_dbnode_t *node;
+ extern char *optarg;
+ extern int optind, opterr, optopt;
+ int create_base = 0;
+ int topt, dcn, zdn, znlen;
+
+ if (argc < 2)
+ {
+ usage ();
+ exit (-1);
+ }
+
+ while ((topt = getopt ((int) argc, argv, "D:Ww:b:z:f:h:?dcv")) != -1)
+ {
+ switch (topt)
+ {
+ case 'v':
+ printf("%s\n", VERSION);
+ exit(0);
+ case 'c':
+ create_base++;
+ break;
+ case 'd':
+ debug++;
+ break;
+ case 'D':
+ binddn = strdup (optarg);
+ if (binddn == NULL)
+ fatal("strdup");
+ break;
+ case 'w':
+ bindpw = strdup (optarg);
+ if (bindpw == NULL)
+ fatal("strdup");
+ break;
+ case 'W':
+ bindpw = getpass("Enter LDAP Password: ");
+ break;
+ case 'b':
+ ldapbase = strdup (optarg);
+ if (ldapbase == NULL)
+ fatal("strdup");
+ break;
+ case 'z':
+ argzone = strdup (optarg);
+ // We wipe argzone all to hell when we parse it for the DN */
+ gbl_zone = strdup(argzone);
+ if (argzone == NULL || gbl_zone == NULL)
+ fatal("strdup");
+ break;
+ case 'f':
+ zonefile = strdup (optarg);
+ if (zonefile == NULL)
+ fatal("strdup");
+ break;
+ case 'h':
+ ldapsystem = strdup (optarg);
+ if (ldapsystem == NULL)
+ fatal("strdup");
+ break;
+ case '?':
+ default:
+ usage ();
+ exit (0);
+ }
+ }
+
+ if ((argzone == NULL) || (zonefile == NULL))
+ {
+ usage ();
+ exit (-1);
+ }
+
+ if (debug)
+ printf ("Initializing ISC Routines, parsing zone file\n");
+
+ result = isc_mem_create (0, 0, &mctx);
+ isc_result_check (result, "isc_mem_create");
+
+ //result = isc_entropy_create(mctx, &ectx);
+ //isc_result_check (result, "isc_entropy_create");
+
+ //result = isc_hash_create(mctx, ectx, DNS_NAME_MAXWIRE);
+ //isc_result_check (result, "isc_hash_create");
+
+ isc_buffer_init (&buff, argzone, strlen (argzone));
+ isc_buffer_add (&buff, strlen (argzone));
+ dns_fixedname_init (&fixedzone);
+ zone = dns_fixedname_name (&fixedzone);
+ result = dns_name_fromtext (zone, &buff, dns_rootname, 0, NULL);
+ isc_result_check (result, "dns_name_fromtext");
+
+ result = dns_db_create (mctx, "rbt", zone, dns_dbtype_zone,
+ dns_rdataclass_in, 0, NULL, &db);
+ isc_result_check (result, "dns_db_create");
+
+ result = dns_db_load (db, zonefile, dns_masterformat_text, 0);
+ isc_result_check (result, "Check Zone Syntax: dns_db_load");
+
+ result = dns_db_createiterator (db, 0, &dbit);
+ isc_result_check (result, "dns_db_createiterator");
+
+ result = dns_dbiterator_first (dbit);
+ isc_result_check (result, "dns_dbiterator_first");
+
+ dns_fixedname_init (&fixedname);
+ name = dns_fixedname_name (&fixedname);
+ dns_rdataset_init (&rdataset);
+ dns_rdata_init (&rdata);
+
+ while (result == ISC_R_SUCCESS)
+ {
+ node = NULL;
+ result = dns_dbiterator_current (dbit, &node, name);
+
+ if (result == ISC_R_NOMORE)
+ break;
+
+ isc_result_check (result, "dns_dbiterator_current");
+
+ riter = NULL;
+ result = dns_db_allrdatasets (db, node, NULL, 0, &riter);
+ isc_result_check (result, "dns_db_allrdatasets");
+
+ result = dns_rdatasetiter_first (riter);
+ //isc_result_check(result, "dns_rdatasetiter_first");
+
+ while (result == ISC_R_SUCCESS)
+ {
+ dns_rdatasetiter_current (riter, &rdataset);
+ result = dns_rdataset_first (&rdataset);
+ isc_result_check (result, "dns_rdatasetiter_current");
+
+ while (result == ISC_R_SUCCESS)
+ {
+ dns_rdataset_current (&rdataset, &rdata);
+ generate_ldap (name, &rdata, rdataset.ttl);
+ dns_rdata_reset (&rdata);
+ result = dns_rdataset_next (&rdataset);
+ }
+ dns_rdataset_disassociate (&rdataset);
+ result = dns_rdatasetiter_next (riter);
+
+ }
+ dns_rdatasetiter_destroy (&riter);
+ result = dns_dbiterator_next (dbit);
+
+ }
+
+ /* Initialize the LDAP Connection */
+ if (debug)
+ printf ("Initializing LDAP Connection to %s as %s\n", ldapsystem, binddn);
+
+ init_ldap_conn ();
+
+ if (create_base)
+ {
+ if (debug)
+ printf ("Creating base zone DN %s\n", argzone);
+
+ dc_list = hostname_to_dn_list (argzone, argzone, DNS_TOP);
+
+ basedn = build_dn_from_dc_list (dc_list, 0, NO_SPEC, argzone);
+ if (debug)
+ printf ("base DN %s\n", basedn);
+
+ for (ctmp = &basedn[strlen (basedn)], dcn=0; ctmp >= &basedn[0]; ctmp--)
+ {
+ if ((*ctmp == ',') || (ctmp == &basedn[0]))
+ {
+ base.mod_op = LDAP_MOD_ADD;
+ base.mod_type = objectClass;
+ base.mod_values = topObjectClasses;
+
+ base_attrs[0] = (void*)&base;
+
+ dcBase.mod_op = LDAP_MOD_ADD;
+ dcBase.mod_type = dc;
+ dcp[0]=dc_list[dcn];
+ dcp[1]=0L;
+ dcBase.mod_values=dcp;
+ base_attrs[1] = (void*)&dcBase;
+
+ znBase.mod_op = LDAP_MOD_ADD;
+ znBase.mod_type = zoneName;
+ for( zdn = dcn, znlen = 0; zdn >= 0; zdn-- )
+ znlen += strlen(dc_list[zdn])+1;
+ znp[0] = (char*)malloc(znlen+1);
+ znp[1] = 0L;
+ for( zdn = dcn, zn=znp[0]; zdn >= 0; zdn-- )
+ zn+=sprintf(zn,"%s%s",dc_list[zdn],
+ ((zdn > 0) && (*(dc_list[zdn-1])!='.')) ? "." : ""
+ );
+
+ znBase.mod_values = znp;
+ base_attrs[2] = (void*)&znBase;
+
+ rdnBase.mod_op = LDAP_MOD_ADD;
+ rdnBase.mod_type = relativeDomainName;
+ rdn[0] = strdup(sameZone);
+ rdn[1] = 0L;
+ rdnBase.mod_values = rdn;
+ base_attrs[3] = (void*)&rdnBase;
+
+ dcn++;
+
+ base.mod_values = topObjectClasses;
+ base_attrs[4] = NULL;
+
+ if (ldapbase)
+ {
+ if (ctmp != &basedn[0])
+ sprintf (fullbasedn, "%s,%s", ctmp + 1, ldapbase);
+ else
+ sprintf (fullbasedn, "%s,%s", ctmp, ldapbase);
+
+ }
+ else
+ {
+ if (ctmp != &basedn[0])
+ sprintf (fullbasedn, "%s", ctmp + 1);
+ else
+ sprintf (fullbasedn, "%s", ctmp);
+ }
+
+ if( debug )
+ printf("Full base dn: %s\n", fullbasedn);
+
+ result = ldap_add_s (conn, fullbasedn, base_attrs);
+ ldap_result_check ("intial ldap_add_s", fullbasedn, result);
+ }
+
+ }
+ }
+ else
+ {
+ if (debug)
+ printf ("Skipping zone base dn creation for %s\n", argzone);
+ }
+
+ for (tmp = ldap_info_base; tmp != NULL; tmp = tmp->next)
+ {
+
+ if (debug)
+ printf ("Adding DN: %s\n", tmp->dn);
+
+ add_ldap_values (tmp);
+ }
+
+ if (debug)
+ printf("Operation Complete.\n");
+
+ /* Cleanup */
+ //isc_hash_destroy();
+ //isc_entropy_detach(&ectx);
+ isc_mem_destroy(&mctx);
+ if (zonefile)
+ free(zonefile);
+
+ return 0;
+}
+
+
+/* Check the status of an isc_result_t after any isc routines.
+ * I should probably rename this function, as not to cause any
+ * confusion with the isc* routines. Will exit on error. */
+void
+isc_result_check (isc_result_t res, const char *errorstr)
+{
+ if (res != ISC_R_SUCCESS)
+ {
+ fprintf (stderr, " %s: %s\n", errorstr, isc_result_totext (res));
+ exit (-1);
+ }
+}
+
+
+/* Takes DNS information, in bind data structure format, and adds textual
+ * zone information to the LDAP run queue. */
+void
+generate_ldap (dns_name_t * dnsname, dns_rdata_t * rdata, unsigned int ttl)
+{
+ char name[DNS_NAME_MAXTEXT + 1];
+ unsigned int len;
+ char type[20];
+ char data[2048];
+ char **dc_list;
+ char *dn;
+
+ isc_buffer_t buff;
+ isc_result_t result;
+
+ isc_buffer_init (&buff, name, sizeof (name));
+ result = dns_name_totext (dnsname, true, &buff);
+ isc_result_check (result, "dns_name_totext");
+ name[isc_buffer_usedlength (&buff)] = 0;
+
+ isc_buffer_init (&buff, type, sizeof (type));
+ result = dns_rdatatype_totext (rdata->type, &buff);
+ isc_result_check (result, "dns_rdatatype_totext");
+ type[isc_buffer_usedlength (&buff)] = 0;
+
+ isc_buffer_init (&buff, data, sizeof (data));
+ result = dns_rdata_totext (rdata, NULL, &buff);
+ isc_result_check (result, "dns_rdata_totext");
+ data[isc_buffer_usedlength (&buff)] = 0;
+
+ dc_list = hostname_to_dn_list ((char*)name, argzone, DNS_OBJECT);
+ len = (get_attr_list_size (dc_list) - 2);
+ dn = build_dn_from_dc_list (dc_list, ttl, WI_SPEC, argzone);
+
+ if (debug)
+ printf ("Adding %s (%s %s) to run queue list.\n", dn, type, data);
+
+ add_to_rr_list (dn, dc_list[len], (char*)type, (char*)data, ttl, DNS_OBJECT);
+}
+
+
+/* Locate an item in the Run queue linked list, by DN. Used by functions
+ * which add items to the run queue.
+ */
+ldap_info *
+locate_by_dn (char *dn)
+{
+ ldap_info *tmp;
+ for (tmp = ldap_info_base; tmp != (ldap_info *) NULL; tmp = tmp->next)
+ {
+ if (!strncmp (tmp->dn, dn, strlen (dn)))
+ return tmp;
+ }
+ return (ldap_info *) NULL;
+}
+
+
+
+/* Take textual zone data, and add to the LDAP Run queue. This works like so:
+ * If locate_by_dn does not return, alloc a new ldap_info structure, and then
+ * calloc a LDAPMod array, fill in the default "everyone needs this" information,
+ * including object classes and dc's. If it locate_by_dn does return, then we'll
+ * realloc for more LDAPMod structs, and appened the new data. If an LDAPMod exists
+ * for the parameter we're adding, then we'll realloc the mod_values array, and
+ * add the new value to the existing LDAPMod. Finnaly, it assures linkage exists
+ * within the Run queue linked ilst*/
+
+void
+add_to_rr_list (char *dn, char *name, char *type,
+ char *data, unsigned int ttl, unsigned int flags)
+{
+ int i;
+ int x;
+ ldap_info *tmp;
+ int attrlist;
+ char ldap_type_buffer[128];
+ char charttl[64];
+
+ char *zn;
+ int znlen;
+
+ if ((tmp = locate_by_dn (dn)) == NULL)
+ {
+
+ /* There wasn't one already there, so we need to allocate a new one,
+ * and stick it on the list */
+
+ tmp = (ldap_info *) malloc (sizeof (ldap_info));
+ if (tmp == (ldap_info *) NULL)
+ fatal("malloc");
+
+ tmp->dn = strdup (dn);
+ if (tmp->dn == NULL)
+ fatal("strdup");
+
+ tmp->attrs = (LDAPMod **) calloc (sizeof (LDAPMod *), flags);
+ if (tmp->attrs == (LDAPMod **) NULL)
+ fatal("calloc");
+
+ for (i = 0; i < (int)flags; i++)
+ {
+ tmp->attrs[i] = (LDAPMod *) malloc (sizeof (LDAPMod));
+ if (tmp->attrs[i] == (LDAPMod *) NULL)
+ fatal("malloc");
+ }
+ tmp->attrs[0]->mod_op = LDAP_MOD_ADD;
+ tmp->attrs[0]->mod_type = objectClass;
+
+ if (flags == DNS_OBJECT)
+ tmp->attrs[0]->mod_values = objectClasses;
+ else
+ {
+ tmp->attrs[0]->mod_values = topObjectClasses;
+ tmp->attrs[1] = NULL;
+ tmp->attrcnt = 2;
+ tmp->next = ldap_info_base;
+ ldap_info_base = tmp;
+ return;
+ }
+
+ tmp->attrs[1]->mod_op = LDAP_MOD_ADD;
+ tmp->attrs[1]->mod_type = relativeDomainName;
+ tmp->attrs[1]->mod_values = (char **) calloc (sizeof (char *), 2);
+
+ if (tmp->attrs[1]->mod_values == (char **)NULL)
+ fatal("calloc");
+
+ tmp->attrs[1]->mod_values[0] = strdup (name);
+ tmp->attrs[1]->mod_values[2] = NULL;
+
+ if (tmp->attrs[1]->mod_values[0] == NULL)
+ fatal("strdup");
+
+ sprintf (ldap_type_buffer, "%sRecord", type);
+
+ tmp->attrs[2]->mod_op = LDAP_MOD_ADD;
+ tmp->attrs[2]->mod_type = strdup (ldap_type_buffer);
+ tmp->attrs[2]->mod_values = (char **) calloc (sizeof (char *), 2);
+
+ if (tmp->attrs[2]->mod_type == NULL ||
+ tmp->attrs[2]->mod_values == (char **)NULL)
+ fatal("strdup/calloc");
+
+ tmp->attrs[2]->mod_values[0] = strdup (data);
+ tmp->attrs[2]->mod_values[1] = NULL;
+
+ if (tmp->attrs[2]->mod_values[0] == NULL)
+ fatal("strdup");
+
+ tmp->attrs[3]->mod_op = LDAP_MOD_ADD;
+ tmp->attrs[3]->mod_type = dNSTTL;
+ tmp->attrs[3]->mod_values = (char **) calloc (sizeof (char *), 2);
+
+ if (tmp->attrs[3]->mod_values == (char **)NULL)
+ fatal("calloc");
+
+ sprintf (charttl, "%d", ttl);
+ tmp->attrs[3]->mod_values[0] = strdup (charttl);
+ tmp->attrs[3]->mod_values[1] = NULL;
+
+ if (tmp->attrs[3]->mod_values[0] == NULL)
+ fatal("strdup");
+
+ znlen=strlen(gbl_zone);
+ if ( *(gbl_zone + (znlen-1)) == '.' )
+ { /* ldapdb MUST search by relative zone name */
+ zn = (char*)malloc(znlen);
+ strncpy(zn,gbl_zone,znlen-1);
+ *(zn + (znlen-1))='\0';
+ }else
+ {
+ zn = gbl_zone;
+ }
+
+ tmp->attrs[4]->mod_op = LDAP_MOD_ADD;
+ tmp->attrs[4]->mod_type = zoneName;
+ tmp->attrs[4]->mod_values = (char **)calloc(sizeof(char *), 2);
+
+ if (tmp->attrs[4]->mod_values == (char **)NULL)
+ fatal("calloc");
+
+ tmp->attrs[4]->mod_values[0] = zn;
+ tmp->attrs[4]->mod_values[1] = NULL;
+
+ tmp->attrs[5] = NULL;
+ tmp->attrcnt = flags;
+ tmp->next = ldap_info_base;
+ ldap_info_base = tmp;
+ }
+ else
+ {
+
+ for (i = 0; tmp->attrs[i] != NULL; i++)
+ {
+ sprintf (ldap_type_buffer, "%sRecord", type);
+ if (!strncmp
+ (ldap_type_buffer, tmp->attrs[i]->mod_type,
+ strlen (tmp->attrs[i]->mod_type)))
+ {
+ attrlist = get_attr_list_size (tmp->attrs[i]->mod_values);
+ tmp->attrs[i]->mod_values =
+ (char **) realloc (tmp->attrs[i]->mod_values,
+ sizeof (char *) * (attrlist + 1));
+
+ if (tmp->attrs[i]->mod_values == (char **) NULL)
+ fatal("realloc");
+
+ for (x = 0; tmp->attrs[i]->mod_values[x] != NULL; x++);
+
+ tmp->attrs[i]->mod_values[x] = strdup (data);
+ if (tmp->attrs[i]->mod_values[x] == NULL)
+ fatal("strdup");
+ tmp->attrs[i]->mod_values[x + 1] = NULL;
+
+ return;
+ }
+ }
+ tmp->attrs =
+ (LDAPMod **) realloc (tmp->attrs,
+ sizeof (LDAPMod) * ++(tmp->attrcnt));
+ if (tmp->attrs == NULL)
+ fatal("realloc");
+
+ for (x = 0; tmp->attrs[x] != NULL; x++);
+ tmp->attrs[x] = (LDAPMod *) malloc (sizeof (LDAPMod));
+ if (tmp->attrs[x] == NULL)
+ fatal("malloc");
+ tmp->attrs[x]->mod_op = LDAP_MOD_ADD;
+ tmp->attrs[x]->mod_type = strdup (ldap_type_buffer);
+ tmp->attrs[x]->mod_values = (char **) calloc (sizeof (char *), 2);
+
+ if (tmp->attrs[x]->mod_type == NULL ||
+ tmp->attrs[x]->mod_values == (char **)NULL)
+ fatal("strdup/calloc");
+
+ tmp->attrs[x]->mod_values[0] = strdup (data);
+ if (tmp->attrs[x]->mod_values[0] == NULL)
+ fatal("strdup");
+ tmp->attrs[x]->mod_values[1] = NULL;
+ tmp->attrs[x + 1] = NULL;
+ }
+}
+
+/* Size of a mod_values list, plus the terminating NULL field. */
+int
+get_attr_list_size (char **tmp)
+{
+ int i = 0;
+ char **ftmp = tmp;
+ while (*ftmp != NULL)
+ {
+ i++;
+ ftmp++;
+ }
+ return ++i;
+}
+
+
+/* take a hostname, and split it into a char ** of the dc parts,
+ * example, we have www.domain.com, this function will return:
+ * array[0] = com, array[1] = domain, array[2] = www. */
+
+char **
+hostname_to_dn_list (char *hostname, char *zone, unsigned int flags)
+{
+ char *tmp;
+ int i = 0;
+ dn_buffer[i] = NULL;
+
+ char *hname=0L, *last=0L;
+ int hlen=strlen(hostname), zlen=(strlen(zone));
+
+ /* printf("hostname: %s zone: %s\n",hostname, zone); */
+ hname=0L;
+ if(flags == DNS_OBJECT)
+ {
+ if( (zone[ zlen - 1 ] == '.') && (hostname[hlen - 1] != '.') )
+ {
+ hname=(char*)malloc(hlen + 1);
+ hlen += 1;
+ sprintf(hname, "%s.", hostname);
+ hostname = hname;
+ }
+ if(strcmp(hostname, zone) == 0)
+ {
+ if( hname == 0 )
+ hname=strdup(hostname);
+ last = strdup(sameZone);
+ }else
+ {
+ if( (hlen < zlen)
+ ||( strcmp( hostname + (hlen - zlen), zone ) != 0)
+ )
+ {
+ if( hname != 0 )
+ free(hname);
+ hname=(char*)malloc( hlen + zlen + 1);
+ if( *zone == '.' )
+ sprintf(hname, "%s%s", hostname, zone);
+ else
+ sprintf(hname,"%s",zone);
+ }else
+ {
+ if( hname == 0 )
+ hname = strdup(hostname);
+ }
+ last = hname;
+ }
+ }else
+ { /* flags == DNS_TOP */
+ hname = strdup(zone);
+ last = hname;
+ }
+
+ for (tmp = strrchr (hname, '.'); tmp != (char *) 0;
+ tmp = strrchr (hname, '.'))
+ {
+ if( *( tmp + 1 ) != '\0' )
+ {
+ *tmp = '\0';
+ dn_buffer[i++] = ++tmp;
+ }else
+ { /* trailing '.' ! */
+ dn_buffer[i++] = strdup(".");
+ *tmp = '\0';
+ if( tmp == hname )
+ break;
+ }
+ }
+ if( ( last != hname ) && (tmp != hname) )
+ dn_buffer[i++] = hname;
+ dn_buffer[i++] = last;
+ return dn_buffer;
+}
+
+
+/* build an sdb compatible LDAP DN from a "dc_list" (char **).
+ * will append dNSTTL information to each RR Record, with the
+ * exception of "@"/SOA. */
+
+char *
+build_dn_from_dc_list (char **dc_list, unsigned int ttl, int flag, char *zone)
+{
+ int size;
+ int x, znlen;
+ static char dn[1024];
+ char tmp[128];
+ char zn[DNS_NAME_MAXTEXT+1];
+
+ bzero (tmp, sizeof (tmp));
+ bzero (dn, sizeof (dn));
+ size = get_attr_list_size (dc_list);
+ znlen = strlen(zone);
+ if ( *(zone + (znlen-1)) == '.' )
+ { /* ldapdb MUST search by relative zone name */
+ memcpy(&(zn[0]),zone,znlen-1);
+ *(zn + (znlen-1))='\0';
+ zone = zn;
+ }
+ for (x = size - 2; x > 0; x--)
+ {
+ if (flag == WI_SPEC)
+ {
+ if (x == (size - 2) && (strncmp (dc_list[x], "@", 1) == 0) && (ttl))
++ sprintf (tmp, "zoneName=%s + relativeDomainName=%s,", zone, dc_list[x]);
+ else if (x == (size - 2))
++ sprintf(tmp, "zoneName=%s + relativeDomainName=%s,", zone, dc_list[x]);
+ else
+ sprintf(tmp,"dc=%s,", dc_list[x]);
+ }
+ else
+ {
+ sprintf(tmp, "dc=%s,", dc_list[x]);
+ }
+
+
+ strlcat (dn, tmp, sizeof (dn));
+ }
+
+ sprintf (tmp, "dc=%s", dc_list[0]);
+ strlcat (dn, tmp, sizeof (dn));
+
+ fflush(NULL);
+ return dn;
+}
+
+
+/* Initialize LDAP Conn */
+void
+init_ldap_conn ()
+{
+ int result;
+ char ldb_tag[]="LDAP Bind";
+ conn = ldap_open (ldapsystem, LDAP_PORT);
+ if (conn == NULL)
+ {
+ fprintf (stderr, "Error opening Ldap connection: %s\n",
+ strerror (errno));
+ exit (-1);
+ }
+
+ result = ldap_simple_bind_s (conn, binddn, bindpw);
+ ldap_result_check ("ldap_simple_bind_s", ldb_tag , result);
+}
+
+/* Like isc_result_check, only for LDAP */
+void
+ldap_result_check (const char *msg, char *dn, int err)
+{
+ if ((err != LDAP_SUCCESS) && (err != LDAP_ALREADY_EXISTS))
+ {
+ fprintf(stderr, "Error while adding %s (%s):\n",
+ dn, msg);
+ ldap_perror (conn, dn);
+ ldap_unbind_s (conn);
+ exit (-1);
+ }
+}
+
+
+
+/* For running the ldap_info run queue. */
+void
+add_ldap_values (ldap_info * ldinfo)
+{
+ int result;
+ char dnbuffer[1024];
+
+
+ if (ldapbase != NULL)
+ sprintf (dnbuffer, "%s,%s", ldinfo->dn, ldapbase);
+ else
+ sprintf (dnbuffer, "%s", ldinfo->dn);
+
+ result = ldap_add_s (conn, dnbuffer, ldinfo->attrs);
+ ldap_result_check ("ldap_add_s", dnbuffer, result);
+}
+
+
+
+
+/* name says it all */
+void
+usage ()
+{
+ fprintf (stderr,
+ "zone2ldap -D [BIND DN] [-w BIND PASSWORD | -W:prompt] -b [BASE DN] -z [ZONE] -f [ZONE FILE] -h [LDAP HOST]\n"
+ "\t[-c Create LDAP Base structure][-d Debug Output (lots !)]\n "
+ );
+}
+