summaryrefslogtreecommitdiffstats
path: root/contrib/sdb/ldap
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/sdb/ldap')
-rw-r--r--contrib/sdb/ldap/INSTALL.ldap83
-rw-r--r--contrib/sdb/ldap/README.ldap48
-rw-r--r--contrib/sdb/ldap/README.zone2ldap17
-rw-r--r--contrib/sdb/ldap/ldapdb.c667
-rw-r--r--contrib/sdb/ldap/ldapdb.h6
-rw-r--r--contrib/sdb/ldap/zone2ldap.164
-rw-r--r--contrib/sdb/ldap/zone2ldap.c734
7 files changed, 1619 insertions, 0 deletions
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..edb367b
--- /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/ldapdb.c b/contrib/sdb/ldap/ldapdb.c
new file mode 100644
index 0000000..ed124c0
--- /dev/null
+++ b/contrib/sdb/ldap/ldapdb.c
@@ -0,0 +1,667 @@
+/*
+ * 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
+#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;
+ free(conndata->index);
+ 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;
+ }
+}
+
+static isc_result_t
+ldapdb_search(const char *zone, const char *name, void *dbdata, void *retdata)
+{
+ 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;
+
+ ldp = ldapdb_getconn(data);
+ if (ldp == NULL)
+ return (ISC_R_FAILURE);
+ if (*ldp == NULL) {
+ ldapdb_bind(data, ldp);
+ 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);
+ }
+ }
+
+ 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;
+ }
+
+ 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(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);
+ }
+
+ /* 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(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;
+ }
+
+ 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(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 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 */
+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)
+{
+ return ldapdb_search(zone, NULL, dbdata, allnodes);
+}
+
+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(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, *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(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);
+ }
+
+ 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(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
+ "LDAP sdb zone '%s': URL: extension syntax error", zone);
+ } else if (err == -2) {
+ isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_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(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_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(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 = {
+ ldapdb_lookup,
+ NULL, /* authority */
+ ldapdb_allnodes,
+ ldapdb_create,
+ ldapdb_destroy
+};
+
+/* 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,
+ ns_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..c2820fd
--- /dev/null
+++ b/contrib/sdb/ldap/zone2ldap.c
@@ -0,0 +1,734 @@
+/*
+ * 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
+ */
+
+#include <errno.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <getopt.h>
+
+#include <isc/buffer.h>
+#include <isc/entropy.h>
+#include <isc/hash.h>
+#include <isc/mem.h>
+#include <isc/print.h>
+#include <isc/result.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>
+
+#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 ();
+
+/* Add to the ldap dit */
+void add_ldap_values (ldap_info * ldinfo);
+
+/* Init an ldap connection */
+void init_ldap_conn ();
+
+/* Ldap error checking */
+void ldap_result_check (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);
+
+/* 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, 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;
+
+char *argzone, *ldapbase, *binddn, *bindpw = NULL;
+char *ldapsystem = "localhost";
+static char *objectClasses[] =
+ { "top", "dNSZone", NULL };
+static char *topObjectClasses[] = { "top", NULL };
+LDAP *conn;
+unsigned int debug = 0;
+
+#ifdef DEBUG
+debug = 1;
+#endif
+
+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[2];
+ LDAPMod base;
+ isc_buffer_t buff;
+ char *zonefile;
+ char fullbasedn[1024];
+ char *ctmp;
+ 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;
+
+ if ((int) argc < 2)
+ {
+ usage ();
+ exit (-1);
+ }
+
+ while ((topt = getopt ((int) argc, argv, "D:w: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);
+ break;
+ case 'w':
+ bindpw = strdup (optarg);
+ break;
+ case 'b':
+ ldapbase = strdup (optarg);
+ break;
+ case 'z':
+ argzone = strdup (optarg);
+ // We wipe argzone all to hell when we parse it for the DN */
+ gbl_zone = strdup(argzone);
+ break;
+ case 'f':
+ zonefile = strdup (optarg);
+ break;
+ case 'h':
+ ldapsystem = strdup (optarg);
+ 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, ISC_FALSE, 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);
+ 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);
+
+ for (ctmp = &basedn[strlen (basedn)]; 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] = &base;
+ base_attrs[1] = 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);
+ }
+ 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);
+
+ 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, 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)
+{
+ unsigned char name[DNS_NAME_MAXTEXT + 1];
+ unsigned int len;
+ unsigned char type[20];
+ unsigned 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, ISC_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 (name, argzone, DNS_OBJECT);
+ len = (get_attr_list_size (dc_list) - 2);
+ dn = build_dn_from_dc_list (dc_list, ttl, WI_SPEC);
+
+ if (debug)
+ printf ("Adding %s (%s %s) to run queue list.\n", dn, type, data);
+
+ add_to_rr_list (dn, dc_list[len], type, 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];
+
+
+ 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)
+ {
+ fprintf (stderr, "malloc: %s\n", strerror (errno));
+ ldap_unbind_s (conn);
+ exit (-1);
+ }
+
+ tmp->dn = strdup (dn);
+ tmp->attrs = (LDAPMod **) calloc (sizeof (LDAPMod *), flags);
+ if (tmp->attrs == (LDAPMod **) NULL)
+ {
+ fprintf (stderr, "calloc: %s\n", strerror (errno));
+ ldap_unbind_s (conn);
+ exit (-1);
+ }
+
+ for (i = 0; i < flags; i++)
+ {
+ tmp->attrs[i] = (LDAPMod *) malloc (sizeof (LDAPMod));
+ if (tmp->attrs[i] == (LDAPMod *) NULL)
+ {
+ fprintf (stderr, "malloc: %s\n", strerror (errno));
+ exit (-1);
+ }
+ }
+ 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)
+ exit(-1);
+
+ tmp->attrs[1]->mod_values[0] = strdup (name);
+ tmp->attrs[1]->mod_values[2] = NULL;
+
+ 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_values == (char **)NULL)
+ exit(-1);
+
+ tmp->attrs[2]->mod_values[0] = strdup (data);
+ tmp->attrs[2]->mod_values[1] = NULL;
+
+ 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)
+ exit(-1);
+
+ sprintf (charttl, "%d", ttl);
+ tmp->attrs[3]->mod_values[0] = strdup (charttl);
+ tmp->attrs[3]->mod_values[1] = NULL;
+
+ tmp->attrs[4]->mod_op = LDAP_MOD_ADD;
+ tmp->attrs[4]->mod_type = "zoneName";
+ tmp->attrs[4]->mod_values = (char **)calloc(sizeof(char *), 2);
+ tmp->attrs[4]->mod_values[0] = gbl_zone;
+ 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)
+ {
+ fprintf (stderr, "realloc: %s\n", strerror (errno));
+ ldap_unbind_s (conn);
+ exit (-1);
+ }
+ for (x = 0; tmp->attrs[i]->mod_values[x] != NULL; x++);
+
+ tmp->attrs[i]->mod_values[x] = strdup (data);
+ tmp->attrs[i]->mod_values[x + 1] = NULL;
+ return;
+ }
+ }
+ tmp->attrs =
+ (LDAPMod **) realloc (tmp->attrs,
+ sizeof (LDAPMod) * ++(tmp->attrcnt));
+ if (tmp->attrs == NULL)
+ {
+ fprintf (stderr, "realloc: %s\n", strerror (errno));
+ ldap_unbind_s (conn);
+ exit (-1);
+ }
+
+ for (x = 0; tmp->attrs[x] != NULL; x++);
+ tmp->attrs[x] = (LDAPMod *) malloc (sizeof (LDAPMod));
+ 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);
+ tmp->attrs[x]->mod_values[0] = strdup (data);
+ 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;
+ static char *dn_buffer[64];
+ int i = 0;
+ char *zname;
+ char *hnamebuff;
+
+ zname = strdup (hostname);
+
+ if (flags == DNS_OBJECT)
+ {
+
+ if (strlen (zname) != strlen (zone))
+ {
+ tmp = &zname[strlen (zname) - strlen (zone)];
+ *--tmp = '\0';
+ hnamebuff = strdup (zname);
+ zname = ++tmp;
+ }
+ else
+ hnamebuff = "@";
+ }
+ else
+ {
+ zname = zone;
+ hnamebuff = NULL;
+ }
+
+ for (tmp = strrchr (zname, '.'); tmp != (char *) 0;
+ tmp = strrchr (zname, '.'))
+ {
+ *tmp++ = '\0';
+ dn_buffer[i++] = tmp;
+ }
+ dn_buffer[i++] = zname;
+ dn_buffer[i++] = hnamebuff;
+ dn_buffer[i] = NULL;
+
+ 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)
+{
+ int size;
+ int x;
+ static char dn[1024];
+ char tmp[128];
+
+ bzero (tmp, sizeof (tmp));
+ bzero (dn, sizeof (dn));
+ size = get_attr_list_size (dc_list);
+ for (x = size - 2; x > 0; x--)
+ {
+ if (flag == WI_SPEC)
+ {
+ if (x == (size - 2) && (strncmp (dc_list[x], "@", 1) == 0) && (ttl))
+ sprintf (tmp, "relativeDomainName=%s + dNSTTL=%d,", dc_list[x], ttl);
+ else if (x == (size - 2))
+ sprintf(tmp, "relativeDomainName=%s,",dc_list[x]);
+ else
+ sprintf(tmp,"dc=%s,", dc_list[x]);
+ }
+ else
+ {
+ sprintf(tmp, "dc=%s,", dc_list[x]);
+ }
+
+
+ strncat (dn, tmp, sizeof (dn) - strlen (dn));
+ }
+
+ sprintf (tmp, "dc=%s", dc_list[0]);
+ strncat (dn, tmp, sizeof (dn) - strlen (dn));
+
+ fflush(NULL);
+ return dn;
+}
+
+
+/* Initialize LDAP Conn */
+void
+init_ldap_conn ()
+{
+ int result;
+ 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", "LDAP Bind", result);
+}
+
+/* Like isc_result_check, only for LDAP */
+void
+ldap_result_check (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] -b [BASE DN] -z [ZONE] -f [ZONE FILE] -h [LDAP HOST]
+ [-c Create LDAP Base structure][-d Debug Output (lots !)] \n ");}