diff options
Diffstat (limited to 'contrib/sdb/ldap')
-rw-r--r-- | contrib/sdb/ldap/INSTALL.ldap | 83 | ||||
-rw-r--r-- | contrib/sdb/ldap/README.ldap | 48 | ||||
-rw-r--r-- | contrib/sdb/ldap/README.zone2ldap | 17 | ||||
-rw-r--r-- | contrib/sdb/ldap/ldapdb.c | 690 | ||||
-rw-r--r-- | contrib/sdb/ldap/ldapdb.h | 6 | ||||
-rw-r--r-- | contrib/sdb/ldap/zone2ldap.1 | 64 | ||||
-rw-r--r-- | contrib/sdb/ldap/zone2ldap.c | 772 |
7 files changed, 1680 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..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/ldapdb.c b/contrib/sdb/ldap/ldapdb.c new file mode 100644 index 0000000..c43342c --- /dev/null +++ b/contrib/sdb/ldap/ldapdb.c @@ -0,0 +1,690 @@ +/* + * 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; + 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(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 */ +#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(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, + 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, + 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..301265a --- /dev/null +++ b/contrib/sdb/ldap/zone2ldap.c @@ -0,0 +1,772 @@ +/* + * 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 <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 (); + +/* 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 + +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[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 (argc < 2) + { + usage (); + exit (-1); + } + + while ((topt = getopt (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); + if (binddn == NULL) + fatal("strdup"); + break; + case 'w': + bindpw = strdup (optarg); + if (bindpw == NULL) + fatal("strdup"); + 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)); + zone = dns_fixedname_initname(&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); + 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"); + + name = dns_fixedname_initname(&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); + 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, 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 (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) + 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 < 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"); + + 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] = 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) + 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; + static char *dn_buffer[64]; + int i = 0; + char *zname; + char *hnamebuff; + + zname = strdup (hostname); + if (zname == NULL) + fatal("strdup"); + + if (flags == DNS_OBJECT) + { + + if (strlen (zname) != strlen (zone)) + { + tmp = &zname[strlen (zname) - strlen (zone)]; + *--tmp = '\0'; + hnamebuff = strdup (zname); + if (hnamebuff == NULL) + fatal("strdup"); + 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]); + } + + + 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; + 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 ");} |