diff --git a/bin/named/Makefile.in b/bin/named/Makefile.in index efc58bc..5f31c4e 100644 --- a/bin/named/Makefile.in +++ b/bin/named/Makefile.in @@ -34,10 +34,10 @@ top_srcdir = @top_srcdir@ # # 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 4af55bd..99c5948 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 /* @@ -803,6 +804,8 @@ dump_symboltable(void) { if (!isc_log_wouldlog(ns_g_lctx, ISC_LOG_DEBUG(99))) return; + ldapdb_clear(); + isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_MAIN, ISC_LOG_DEBUG(99), "Symbol table:"); @@ -1084,6 +1087,24 @@ setup(void) { isc_result_totext(result)); #endif + result = ldapdb_init(); + if (result != ISC_R_SUCCESS) + { + isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_MAIN, + ISC_LOG_ERROR, + "SDB ldap module initialisation failed: %s.", + isc_result_totext(result) + ); + isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_MAIN, + ISC_LOG_ERROR, + "SDB ldap zone database will be unavailable." + ); + }else + isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_MAIN, + ISC_LOG_NOTICE, "SDB ldap zone database module loaded." + ); + + ns_server_create(ns_g_mctx, &ns_g_server); #ifdef HAVE_LIBSECCOMP @@ -1119,6 +1140,8 @@ cleanup(void) { dns_name_destroy(); + ldapdb_clear(); + isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_MAIN, ISC_LOG_NOTICE, "exiting"); ns_log_shutdown(); diff --git a/bin/tools/Makefile.in b/bin/tools/Makefile.in index 253dd37..0e1581a 100644 --- a/bin/tools/Makefile.in +++ b/bin/tools/Makefile.in @@ -23,33 +23,43 @@ top_srcdir = @top_srcdir@ CINCLUDES = ${DNS_INCLUDES} ${ISC_INCLUDES} ${ISCCFG_INCLUDES} \ ${LWRES_INCLUDES} ${OMAPI_INCLUDES} -CDEFINES = +CDEFINES = -DBIND9 CWARNINGS = DNSLIBS = ../../lib/dns/libdns.@A@ @DNS_CRYPTO_LIBS@ +ISCCFGLIBS = ../../lib/isccfg/libisccfg.@A@ +ISCCCLIBS = ../../lib/isccc/libisccc.@A@ ISCLIBS = ../../lib/isc/libisc.@A@ @DNS_CRYPTO_LIBS@ ISCNOSYMLIBS = ../../lib/isc/libisc-nosymtbl.@A@ -ISCCFGLIBS = ../../lib/isccfg/libisccfg.@A@ LWRESLIBS = ../../lib/lwres/liblwres.@A@ +BIND9LIBS = ../../lib/bind9/libbind9.@A@ DNSDEPLIBS = ../../lib/dns/libdns.@A@ +ISCCFGDEPLIBS = ../../lib/isccfg/libisccfg.@A@ +ISCCCDEPLIBS = ../../lib/isccc/libisccc.@A@ ISCDEPLIBS = ../../lib/isc/libisc.@A@ -ISCCFGDEPLIBS = ../../lib/isccfg/libisccfg.@A@ LWRESDEPLIBS = ../../lib/lwres/liblwres.@A@ +BIND9DEPLIBS = ../../lib/bind9/libbind9.@A@ +DEPLIBS = ${LWRESDEPLIBS} ${DNSDEPLIBS} ${BIND9DEPLIBS} \ + ${ISCCFGDEPLIBS} ${ISCCCDEPLIBS} ${ISCDEPLIBS} + +LIBS = ${LWRESLIBS} ${DNSLIBS} ${BIND9LIBS} \ + ${ISCCFGLIBS} ${ISCCCLIBS} ${ISCLIBS} ${DBDRIVER_LIBS} @LIBS@ + -LIBS = ${ISCLIBS} @LIBS@ NOSYMLIBS = ${ISCNOSYMLIBS} @LIBS@ SUBDIRS = TARGETS = arpaname@EXEEXT@ named-journalprint@EXEEXT@ \ named-rrchecker@EXEEXT@ nsec3hash@EXEEXT@ \ - genrandom@EXEEXT@ isc-hmac-fixup@EXEEXT@ + genrandom@EXEEXT@ isc-hmac-fixup@EXEEXT@ ldap2zone@EXEEXT@ \ + zone2ldap@EXEEXT@ SRCS = arpaname.c named-journalprint.c named-rrchecker.c \ - nsec3hash.c genrandom.c isc-hmac-fixup.c + nsec3hash.c genrandom.c isc-hmac-fixup.c ldap2zone.c zone2ldap.c MANPAGES = arpaname.1 named-journalprint.8 named-rrchecker.1 nsec3hash.8 \ - genrandom.8 isc-hmac-fixup.8 + genrandom.8 isc-hmac-fixup.8 ldap2zone.1 zone2ldap.1 HTMLPAGES = arpaname.html named-journalprint.html named-rrchecker.html \ nsec3hash.html genrandom.html isc-hmac-fixup.html MANOBJS = ${MANPAGES} ${HTMLPAGES} @@ -84,6 +94,12 @@ genrandom@EXEEXT@: genrandom.@O@ ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} \ -o $@ genrandom.@O@ @GENRANDOMLIB@ ${LIBS} +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:: @@ -107,7 +123,11 @@ install:: ${TARGETS} installdirs ${DESTDIR}${sbindir} ${LIBTOOL_MODE_INSTALL} ${INSTALL_PROGRAM} isc-hmac-fixup@EXEEXT@ \ ${DESTDIR}${sbindir} + ${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}/isc-hmac-fixup.8 ${DESTDIR}${mandir}/man8 ${INSTALL_DATA} ${srcdir}/named-journalprint.8 ${DESTDIR}${mandir}/man8 ${INSTALL_DATA} ${srcdir}/named-rrchecker.1 ${DESTDIR}${mandir}/man1 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 +.\" +.\" 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 + * $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 +#include +#include +#include + +#include + +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 index c43342c..62d3fb4 100644 --- a/contrib/sdb/ldap/ldapdb.c +++ b/contrib/sdb/ldap/ldapdb.c @@ -25,6 +25,7 @@ /* 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 diff --git a/contrib/sdb/ldap/zone2ldap.c b/contrib/sdb/ldap/zone2ldap.c index 6db7f85..4447c8c 100644 --- a/contrib/sdb/ldap/zone2ldap.c +++ b/contrib/sdb/ldap/zone2ldap.c @@ -13,6 +13,8 @@ * ditched dNSDomain2 schema support. Version 0.3-ALPHA */ +#define LDAP_DEPRECATED 1 + #include #include #include @@ -24,6 +26,7 @@ #include #include #include +#include #include #include @@ -59,16 +62,19 @@ typedef struct LDAP_INFO ldap_info; /* usage Info */ -void usage (); +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 init_ldap_conn (void); /* Ldap error checking */ -void ldap_result_check (char *msg, char *dn, int err); +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); @@ -77,14 +83,14 @@ char **hostname_to_dn_list (char *hostname, char *zone, unsigned int flags); 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 *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, char *errorstr); +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, @@ -93,11 +99,33 @@ void generate_ldap (dns_name_t * dnsname, dns_rdata_t * rdata, /* 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_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; @@ -106,19 +134,19 @@ debug = 1; #endif int -main (int *argc, char **argv) +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; + LDAPMod *base_attrs[5]; + LDAPMod base, dcBase, znBase, rdnBase; isc_buffer_t buff; - char *zonefile; + char *zonefile=0L; char fullbasedn[1024]; - char *ctmp; + char *ctmp, *zn, *dcp[2], *znp[2], *rdn[2]; dns_fixedname_t fixedzone, fixedname; dns_rdataset_t rdataset; char **dc_list; @@ -131,7 +159,7 @@ main (int *argc, char **argv) extern char *optarg; extern int optind, opterr, optopt; int create_base = 0; - int topt; + int topt, dcn, zdn, znlen; if ((int) argc < 2) { @@ -139,7 +167,7 @@ main (int *argc, char **argv) exit (-1); } - while ((topt = getopt ((int) argc, argv, "D:w:b:z:f:h:?dcv")) != -1) + while ((topt = getopt ((int) argc, argv, "D:Ww:b:z:f:h:?dcv")) != -1) { switch (topt) { @@ -158,8 +186,11 @@ main (int *argc, char **argv) case 'w': bindpw = strdup (optarg); break; + case 'W': + bindpw = getpass("Enter LDAP Password: "); + break; case 'b': - ldapbase = strdup (optarg); + ldapbase = strdup (optarg); break; case 'z': argzone = strdup (optarg); @@ -271,27 +302,62 @@ main (int *argc, char **argv) { 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--) + 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])) + if ((*ctmp == ',') || (ctmp == &basedn[0])) { + base.mod_op = LDAP_MOD_ADD; - base.mod_type = "objectClass"; + base.mod_type = objectClass; base.mod_values = topObjectClasses; - base_attrs[0] = &base; - base_attrs[1] = NULL; + 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); - + sprintf (fullbasedn, "%s,%s", ctmp, ldapbase); } else { @@ -300,8 +366,13 @@ main (int *argc, char **argv) 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); + } } @@ -339,7 +410,7 @@ main (int *argc, char **argv) * 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) +isc_result_check (isc_result_t res, const char *errorstr) { if (res != ISC_R_SUCCESS) { @@ -379,14 +450,14 @@ generate_ldap (dns_name_t * dnsname, dns_rdata_t * rdata, unsigned int ttl) isc_result_check (result, "dns_rdata_totext"); data[isc_buffer_usedlength (&buff)] = 0; - dc_list = hostname_to_dn_list (name, argzone, DNS_OBJECT); + 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); + 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], type, data, ttl, DNS_OBJECT); + add_to_rr_list (dn, dc_list[len], (char*)type, (char*)data, ttl, DNS_OBJECT); } @@ -426,7 +497,8 @@ add_to_rr_list (char *dn, char *name, char *type, int attrlist; char ldap_type_buffer[128]; char charttl[64]; - + char *zn; + int znlen; if ((tmp = locate_by_dn (dn)) == NULL) { @@ -451,7 +523,7 @@ add_to_rr_list (char *dn, char *name, char *type, exit (-1); } - for (i = 0; i < flags; i++) + for (i = 0; i < (int)flags; i++) { tmp->attrs[i] = (LDAPMod *) malloc (sizeof (LDAPMod)); if (tmp->attrs[i] == (LDAPMod *) NULL) @@ -461,13 +533,13 @@ add_to_rr_list (char *dn, char *name, char *type, } } tmp->attrs[0]->mod_op = LDAP_MOD_ADD; - tmp->attrs[0]->mod_type = "objectClass"; + 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[0]->mod_values =topObjectClasses; tmp->attrs[1] = NULL; tmp->attrcnt = 2; tmp->next = ldap_info_base; @@ -476,7 +548,7 @@ add_to_rr_list (char *dn, char *name, char *type, } tmp->attrs[1]->mod_op = LDAP_MOD_ADD; - tmp->attrs[1]->mod_type = "relativeDomainName"; + tmp->attrs[1]->mod_type = relativeDomainName; tmp->attrs[1]->mod_values = (char **) calloc (sizeof (char *), 2); if (tmp->attrs[1]->mod_values == (char **)NULL) @@ -498,7 +570,7 @@ add_to_rr_list (char *dn, char *name, char *type, 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_type = dNSTTL; tmp->attrs[3]->mod_values = (char **) calloc (sizeof (char *), 2); if (tmp->attrs[3]->mod_values == (char **)NULL) @@ -508,10 +580,21 @@ add_to_rr_list (char *dn, char *name, char *type, tmp->attrs[3]->mod_values[0] = strdup (charttl); tmp->attrs[3]->mod_values[1] = NULL; + 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_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[0] = zn; tmp->attrs[4]->mod_values[1] = NULL; tmp->attrs[5] = NULL; @@ -522,7 +605,7 @@ add_to_rr_list (char *dn, char *name, char *type, else { - for (i = 0; tmp->attrs[i] != NULL; i++) + for (i = 0; tmp->attrs[i] != NULL; i++) { sprintf (ldap_type_buffer, "%sRecord", type); if (!strncmp @@ -591,69 +674,105 @@ 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; + 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; 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) +build_dn_from_dc_list (char **dc_list, unsigned int ttl, int flag, char *zone) { int size; - int x; + 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, "relativeDomainName=%s + dNSTTL=%d,", dc_list[x], ttl); + sprintf (tmp, "zoneName=%s + relativeDomainName=%s,", zone, dc_list[x]); else if (x == (size - 2)) - sprintf(tmp, "relativeDomainName=%s,",dc_list[x]); + sprintf(tmp, "zoneName=%s + relativeDomainName=%s,", zone, dc_list[x]); else sprintf(tmp,"dc=%s,", dc_list[x]); } @@ -679,6 +798,7 @@ void init_ldap_conn () { int result; + char ldb_tag[]="LDAP Bind"; conn = ldap_open (ldapsystem, LDAP_PORT); if (conn == NULL) { @@ -688,12 +808,12 @@ init_ldap_conn () } result = ldap_simple_bind_s (conn, binddn, bindpw); - ldap_result_check ("ldap_simple_bind_s", "LDAP Bind", result); + ldap_result_check ("ldap_simple_bind_s", ldb_tag , result); } /* Like isc_result_check, only for LDAP */ void -ldap_result_check (char *msg, char *dn, int err) +ldap_result_check (const char *msg, char *dn, int err) { if ((err != LDAP_SUCCESS) && (err != LDAP_ALREADY_EXISTS)) { @@ -705,8 +825,6 @@ ldap_result_check (char *msg, char *dn, int err) } } - - /* For running the ldap_info run queue. */ void add_ldap_values (ldap_info * ldinfo) @@ -714,14 +832,14 @@ 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); + ldap_result_check ("ldap_add_s", dnbuffer, result); + } @@ -732,5 +850,8 @@ 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 ");} + "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 " + ); +} +