diff --git a/contrib/sdb/INSTALL.ldap b/contrib/sdb/INSTALL.ldap new file mode 100644 index 0000000000..80561a8b26 --- /dev/null +++ b/contrib/sdb/INSTALL.ldap @@ -0,0 +1,59 @@ +This is the INSTALL file for 0.3. 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 doesn't make sense, +please have a look at that 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 ". 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 it. + + +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. +If you like, you could try to use my LDAP server as a test. To test, +add the following to your named.conf: + +zone "ldap" { + type master; + database "ldap ldap://129.241.20.67/dc=venaas,dc=com,o=DNS,dc=venaas,dc=no 86400"; +}; + +and then try to do for instance host www.ldap. localhost + +The LDAP URL consists of a hostport part and the base (the node above +where the zone is stored). BIND will do a one-level search with this +base. Finally, the number 86400 is the TTL which will be used for all +entries that haven't got the dNSTTL attribute. + +To store data in your own LDAP server you can use the Cosine dNSDomain +class, or even better dNSDomain2. Your LDAP server probably comes +with dNSDomain, you can find dNSDomain2 and further details on how +to store the data in your LDAP server at + +http://www.venaas.no/ldap/bind-sdb/ + +You can also see how I did it by searching in my LDAP server, the +address and base is as in the LDAP URL above. + +Stig Venaas 2001-03-03 diff --git a/contrib/sdb/README.ldap b/contrib/sdb/README.ldap new file mode 100644 index 0000000000..e952531997 --- /dev/null +++ b/contrib/sdb/README.ldap @@ -0,0 +1,9 @@ +This is an attempt at an LDAP back-end for BIND 9 using the new +simplified database interface "sdb". This is the third release +(0.3) and is not ready for production use yet. 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 2001-03-03 diff --git a/contrib/sdb/ldap/INSTALL.ldap b/contrib/sdb/ldap/INSTALL.ldap new file mode 100644 index 0000000000..80561a8b26 --- /dev/null +++ b/contrib/sdb/ldap/INSTALL.ldap @@ -0,0 +1,59 @@ +This is the INSTALL file for 0.3. 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 doesn't make sense, +please have a look at that 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 ". 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 it. + + +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. +If you like, you could try to use my LDAP server as a test. To test, +add the following to your named.conf: + +zone "ldap" { + type master; + database "ldap ldap://129.241.20.67/dc=venaas,dc=com,o=DNS,dc=venaas,dc=no 86400"; +}; + +and then try to do for instance host www.ldap. localhost + +The LDAP URL consists of a hostport part and the base (the node above +where the zone is stored). BIND will do a one-level search with this +base. Finally, the number 86400 is the TTL which will be used for all +entries that haven't got the dNSTTL attribute. + +To store data in your own LDAP server you can use the Cosine dNSDomain +class, or even better dNSDomain2. Your LDAP server probably comes +with dNSDomain, you can find dNSDomain2 and further details on how +to store the data in your LDAP server at + +http://www.venaas.no/ldap/bind-sdb/ + +You can also see how I did it by searching in my LDAP server, the +address and base is as in the LDAP URL above. + +Stig Venaas 2001-03-03 diff --git a/contrib/sdb/ldap/README.ldap b/contrib/sdb/ldap/README.ldap new file mode 100644 index 0000000000..e952531997 --- /dev/null +++ b/contrib/sdb/ldap/README.ldap @@ -0,0 +1,9 @@ +This is an attempt at an LDAP back-end for BIND 9 using the new +simplified database interface "sdb". This is the third release +(0.3) and is not ready for production use yet. 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 2001-03-03 diff --git a/contrib/sdb/ldap/ldapdb.c b/contrib/sdb/ldap/ldapdb.c new file mode 100644 index 0000000000..5413ded941 --- /dev/null +++ b/contrib/sdb/ldap/ldapdb.c @@ -0,0 +1,304 @@ +/* + * Copyright (C) 2001 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. + */ + +#include + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +#include + +#include +#include "ldapdb.h" + +/* + * A simple database driver for LDAP. Not production quality yet. + */ + +static dns_sdbimplementation_t *ldapdb = NULL; + +struct ldapdb_data { + char *hostname; + int portno; + char *base; + int defaultttl; + LDAP *ld; +}; + +static isc_result_t +ldapdb_create(const char *zone, int argc, char **argv, + void *driverdata, void **dbdata) +{ + struct ldapdb_data *data; + char *s; + int defaultttl; + + UNUSED(zone); + UNUSED(driverdata); + + 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); + data->hostname = isc_mem_strdup(ns_g_mctx, argv[0] + strlen("ldap://")); + if (data->hostname == NULL) { + isc_mem_put(ns_g_mctx, data, sizeof(struct ldapdb_data)); + return (ISC_R_NOMEMORY); + } + data->defaultttl = defaultttl; + s = strchr(data->hostname, '/'); + if (s != NULL) { + *s++ = '\0'; + data->base = *s != '\0' ? s : NULL; + } + s = strchr(data->hostname, ':'); + if (s != NULL) { + *s++ = '\0'; + data->portno = atoi(s); + } else + data->portno = LDAP_PORT; + data->ld = NULL; + *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); + + if (data == NULL) + return; + if (data->ld != NULL) + ldap_unbind(data->ld); + if (data->hostname != NULL) + isc_mem_free(ns_g_mctx, data->hostname); + isc_mem_put(ns_g_mctx, data, sizeof(struct ldapdb_data)); +} + +static void +ldapdb_bind(struct ldapdb_data *data) +{ + if (data->ld != NULL) + ldap_unbind(data->ld); + data->ld = ldap_open(data->hostname, data->portno); + if (data->ld == NULL) + return; + if (ldap_simple_bind_s(data->ld, NULL, NULL) != LDAP_SUCCESS) { + ldap_unbind(data->ld); + data->ld = NULL; + } +} + +static isc_result_t +ldapdb_lookup(const char *zone, const char *name, void *dbdata, + dns_sdblookup_t *lookup) +{ + isc_result_t result = ISC_R_NOTFOUND; + struct ldapdb_data *data = dbdata; + LDAPMessage *res, *e; + char *fltr, *a, **vals; + char type[64]; + BerElement *ptr; + int i; + + UNUSED(zone); + + if (data->ld == NULL) { + ldapdb_bind(data); + if (data->ld == NULL) + return (ISC_R_FAILURE); + } + fltr = isc_mem_get(ns_g_mctx, strlen(name) + strlen("(dc=)") + 1); + if (fltr == NULL) + return (ISC_R_NOMEMORY); + strcpy(fltr, "(dc="); + strcat(fltr, name); + strcat(fltr, ")"); + if (ldap_search_s(data->ld, data->base, LDAP_SCOPE_ONELEVEL, fltr, NULL, 0, &res) != LDAP_SUCCESS) { + ldapdb_bind(data); + if (data->ld != NULL) + ldap_search_s(data->ld, data->base, LDAP_SCOPE_ONELEVEL, fltr, NULL, 0, &res); + } + isc_mem_put(ns_g_mctx, fltr, strlen(fltr) + 1); + if (data->ld == NULL) + goto exit; + + for (e = ldap_first_entry(data->ld, res); e != NULL; + e = ldap_next_entry(data->ld, e)) { + LDAP *ld = data->ld; + int ttl = data->defaultttl; + + for (a = ldap_first_attribute(ld, e, &ptr); a != NULL; + a = ldap_next_attribute(ld, e, ptr)) { + if (!strcmp(a, "dNSTTL")) { + vals = ldap_get_values(ld, e, a); + ttl = atoi(vals[0]); + ldap_value_free(vals); + ldap_memfree(a); + break; + } + ldap_memfree(a); + } + 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(ld, e, a); + for (i=0; vals[i] != NULL; i++) { + result = dns_sdb_putrr(lookup, type, ttl, vals[i]); + if (result != ISC_R_SUCCESS) { + ldap_value_free(vals); + ldap_memfree(a); + result = ISC_R_FAILURE; + goto exit; + } + } + ldap_value_free(vals); + ldap_memfree(a); + } + } + exit: + ldap_msgfree(res); + return (result); +} + +static isc_result_t +ldapdb_allnodes(const char *zone, void *dbdata, dns_sdballnodes_t *allnodes) { + isc_result_t result = ISC_R_NOTFOUND; + struct ldapdb_data *data = dbdata; + LDAPMessage *res, *e; + char type[64]; + char *a, **vals; + BerElement *ptr; + int i; + + UNUSED(zone); + + if (data->ld == NULL) { + ldapdb_bind(data); + if (data->ld == NULL) + return (ISC_R_FAILURE); + } + + if (ldap_search_s(data->ld, data->base, LDAP_SCOPE_ONELEVEL, "(objectclass=*)", NULL, 0, &res) != LDAP_SUCCESS) { + ldapdb_bind(data); + if (data->ld != NULL) + ldap_search_s(data->ld, data->base, LDAP_SCOPE_ONELEVEL, "(objectclass=*)", NULL, 0, &res); + } + + for (e = ldap_first_entry(data->ld, res); e != NULL; + e = ldap_next_entry(data->ld, e)) { + LDAP *ld = data->ld; + char *name = NULL; + int ttl = data->defaultttl; + + for (a = ldap_first_attribute(ld, e, &ptr); a != NULL; + a = ldap_next_attribute(ld, e, ptr)) { + if (!strcmp(a, "dNSTTL")) { + vals = ldap_get_values(ld, e, a); + ttl = atoi(vals[0]); + ldap_value_free(vals); + } else if (!strcmp(a, "dc")) { + vals = ldap_get_values(ld, e, a); + name = isc_mem_strdup(ns_g_mctx, vals[0]); + ldap_value_free(vals); + } + ldap_memfree(a); + } + + if (name == NULL) + continue; + + 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(ld, e, a); + for (i=0; vals[i] != NULL; i++) { + result = dns_sdb_putnamedrr(allnodes, name, type, ttl, vals[i]); + if (result != ISC_R_SUCCESS) { + ldap_value_free(vals); + ldap_memfree(a); + isc_mem_free(ns_g_mctx, name); + result = ISC_R_FAILURE; + goto exit; + } + } + ldap_value_free(vals); + ldap_memfree(a); + } + isc_mem_free(ns_g_mctx, name); + } + + exit: + ldap_msgfree(res); + return (result); +} + +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; + flags = DNS_SDBFLAG_RELATIVEOWNER | DNS_SDBFLAG_RELATIVERDATA; + 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) + dns_sdb_unregister(&ldapdb); +} diff --git a/contrib/sdb/ldap/ldapdb.h b/contrib/sdb/ldap/ldapdb.h new file mode 100644 index 0000000000..a08eb20bf3 --- /dev/null +++ b/contrib/sdb/ldap/ldapdb.h @@ -0,0 +1,6 @@ +#include + +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 0000000000..8f4cb35add --- /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) +.SH "BUGS" +Send all bug reports to Jeff McNeil . +.SH AUTHOR +Jeff McNeil + diff --git a/contrib/sdb/ldap/zone2ldap.c b/contrib/sdb/ldap/zone2ldap.c new file mode 100644 index 0000000000..79941ae7d2 --- /dev/null +++ b/contrib/sdb/ldap/zone2ldap.c @@ -0,0 +1,677 @@ +/* + * Copyright (C) 2001 Jeff McNeil + * + * 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. + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#define DNS_OBJECT 5 +#define DNS_TOP 2 + +#define VERSION "0.2-ALPHA" + +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); + +/* 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", "domain", "dNSDomain", "dNSDomain2", 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 *isc_ctx = 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); + 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, &isc_ctx); + isc_result_check (result, "isc_mem_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 (isc_ctx, "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, ISC_FALSE, &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); + 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"); + + 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); + + 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 = "dc"; + tmp->attrs[1]->mod_values = (char **) calloc (sizeof (char *), 2); + 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); + 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); + sprintf (charttl, "%d", ttl); + tmp->attrs[3]->mod_values[0] = strdup (charttl); + tmp->attrs[3]->mod_values[1] = NULL; + + + tmp->attrs[4] = 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 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 (x == (size - 2) && (strncmp (dc_list[x], "@", 1)) && (ttl)) + sprintf (tmp, "dc=%s + dNSTTL=%d,", dc_list[x], ttl); + 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)); + + 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)) + { + 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 ");} diff --git a/contrib/sdb/ldapdb.c b/contrib/sdb/ldapdb.c new file mode 100644 index 0000000000..5413ded941 --- /dev/null +++ b/contrib/sdb/ldapdb.c @@ -0,0 +1,304 @@ +/* + * Copyright (C) 2001 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. + */ + +#include + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +#include + +#include +#include "ldapdb.h" + +/* + * A simple database driver for LDAP. Not production quality yet. + */ + +static dns_sdbimplementation_t *ldapdb = NULL; + +struct ldapdb_data { + char *hostname; + int portno; + char *base; + int defaultttl; + LDAP *ld; +}; + +static isc_result_t +ldapdb_create(const char *zone, int argc, char **argv, + void *driverdata, void **dbdata) +{ + struct ldapdb_data *data; + char *s; + int defaultttl; + + UNUSED(zone); + UNUSED(driverdata); + + 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); + data->hostname = isc_mem_strdup(ns_g_mctx, argv[0] + strlen("ldap://")); + if (data->hostname == NULL) { + isc_mem_put(ns_g_mctx, data, sizeof(struct ldapdb_data)); + return (ISC_R_NOMEMORY); + } + data->defaultttl = defaultttl; + s = strchr(data->hostname, '/'); + if (s != NULL) { + *s++ = '\0'; + data->base = *s != '\0' ? s : NULL; + } + s = strchr(data->hostname, ':'); + if (s != NULL) { + *s++ = '\0'; + data->portno = atoi(s); + } else + data->portno = LDAP_PORT; + data->ld = NULL; + *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); + + if (data == NULL) + return; + if (data->ld != NULL) + ldap_unbind(data->ld); + if (data->hostname != NULL) + isc_mem_free(ns_g_mctx, data->hostname); + isc_mem_put(ns_g_mctx, data, sizeof(struct ldapdb_data)); +} + +static void +ldapdb_bind(struct ldapdb_data *data) +{ + if (data->ld != NULL) + ldap_unbind(data->ld); + data->ld = ldap_open(data->hostname, data->portno); + if (data->ld == NULL) + return; + if (ldap_simple_bind_s(data->ld, NULL, NULL) != LDAP_SUCCESS) { + ldap_unbind(data->ld); + data->ld = NULL; + } +} + +static isc_result_t +ldapdb_lookup(const char *zone, const char *name, void *dbdata, + dns_sdblookup_t *lookup) +{ + isc_result_t result = ISC_R_NOTFOUND; + struct ldapdb_data *data = dbdata; + LDAPMessage *res, *e; + char *fltr, *a, **vals; + char type[64]; + BerElement *ptr; + int i; + + UNUSED(zone); + + if (data->ld == NULL) { + ldapdb_bind(data); + if (data->ld == NULL) + return (ISC_R_FAILURE); + } + fltr = isc_mem_get(ns_g_mctx, strlen(name) + strlen("(dc=)") + 1); + if (fltr == NULL) + return (ISC_R_NOMEMORY); + strcpy(fltr, "(dc="); + strcat(fltr, name); + strcat(fltr, ")"); + if (ldap_search_s(data->ld, data->base, LDAP_SCOPE_ONELEVEL, fltr, NULL, 0, &res) != LDAP_SUCCESS) { + ldapdb_bind(data); + if (data->ld != NULL) + ldap_search_s(data->ld, data->base, LDAP_SCOPE_ONELEVEL, fltr, NULL, 0, &res); + } + isc_mem_put(ns_g_mctx, fltr, strlen(fltr) + 1); + if (data->ld == NULL) + goto exit; + + for (e = ldap_first_entry(data->ld, res); e != NULL; + e = ldap_next_entry(data->ld, e)) { + LDAP *ld = data->ld; + int ttl = data->defaultttl; + + for (a = ldap_first_attribute(ld, e, &ptr); a != NULL; + a = ldap_next_attribute(ld, e, ptr)) { + if (!strcmp(a, "dNSTTL")) { + vals = ldap_get_values(ld, e, a); + ttl = atoi(vals[0]); + ldap_value_free(vals); + ldap_memfree(a); + break; + } + ldap_memfree(a); + } + 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(ld, e, a); + for (i=0; vals[i] != NULL; i++) { + result = dns_sdb_putrr(lookup, type, ttl, vals[i]); + if (result != ISC_R_SUCCESS) { + ldap_value_free(vals); + ldap_memfree(a); + result = ISC_R_FAILURE; + goto exit; + } + } + ldap_value_free(vals); + ldap_memfree(a); + } + } + exit: + ldap_msgfree(res); + return (result); +} + +static isc_result_t +ldapdb_allnodes(const char *zone, void *dbdata, dns_sdballnodes_t *allnodes) { + isc_result_t result = ISC_R_NOTFOUND; + struct ldapdb_data *data = dbdata; + LDAPMessage *res, *e; + char type[64]; + char *a, **vals; + BerElement *ptr; + int i; + + UNUSED(zone); + + if (data->ld == NULL) { + ldapdb_bind(data); + if (data->ld == NULL) + return (ISC_R_FAILURE); + } + + if (ldap_search_s(data->ld, data->base, LDAP_SCOPE_ONELEVEL, "(objectclass=*)", NULL, 0, &res) != LDAP_SUCCESS) { + ldapdb_bind(data); + if (data->ld != NULL) + ldap_search_s(data->ld, data->base, LDAP_SCOPE_ONELEVEL, "(objectclass=*)", NULL, 0, &res); + } + + for (e = ldap_first_entry(data->ld, res); e != NULL; + e = ldap_next_entry(data->ld, e)) { + LDAP *ld = data->ld; + char *name = NULL; + int ttl = data->defaultttl; + + for (a = ldap_first_attribute(ld, e, &ptr); a != NULL; + a = ldap_next_attribute(ld, e, ptr)) { + if (!strcmp(a, "dNSTTL")) { + vals = ldap_get_values(ld, e, a); + ttl = atoi(vals[0]); + ldap_value_free(vals); + } else if (!strcmp(a, "dc")) { + vals = ldap_get_values(ld, e, a); + name = isc_mem_strdup(ns_g_mctx, vals[0]); + ldap_value_free(vals); + } + ldap_memfree(a); + } + + if (name == NULL) + continue; + + 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(ld, e, a); + for (i=0; vals[i] != NULL; i++) { + result = dns_sdb_putnamedrr(allnodes, name, type, ttl, vals[i]); + if (result != ISC_R_SUCCESS) { + ldap_value_free(vals); + ldap_memfree(a); + isc_mem_free(ns_g_mctx, name); + result = ISC_R_FAILURE; + goto exit; + } + } + ldap_value_free(vals); + ldap_memfree(a); + } + isc_mem_free(ns_g_mctx, name); + } + + exit: + ldap_msgfree(res); + return (result); +} + +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; + flags = DNS_SDBFLAG_RELATIVEOWNER | DNS_SDBFLAG_RELATIVERDATA; + 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) + dns_sdb_unregister(&ldapdb); +} diff --git a/contrib/sdb/ldapdb.h b/contrib/sdb/ldapdb.h new file mode 100644 index 0000000000..a08eb20bf3 --- /dev/null +++ b/contrib/sdb/ldapdb.h @@ -0,0 +1,6 @@ +#include + +isc_result_t ldapdb_init(void); + +void ldapdb_clear(void); + diff --git a/contrib/sdb/zone2ldap.1 b/contrib/sdb/zone2ldap.1 new file mode 100644 index 0000000000..8f4cb35add --- /dev/null +++ b/contrib/sdb/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) +.SH "BUGS" +Send all bug reports to Jeff McNeil . +.SH AUTHOR +Jeff McNeil + diff --git a/contrib/sdb/zone2ldap.c b/contrib/sdb/zone2ldap.c new file mode 100644 index 0000000000..79941ae7d2 --- /dev/null +++ b/contrib/sdb/zone2ldap.c @@ -0,0 +1,677 @@ +/* + * Copyright (C) 2001 Jeff McNeil + * + * 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. + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#define DNS_OBJECT 5 +#define DNS_TOP 2 + +#define VERSION "0.2-ALPHA" + +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); + +/* 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", "domain", "dNSDomain", "dNSDomain2", 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 *isc_ctx = 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); + 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, &isc_ctx); + isc_result_check (result, "isc_mem_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 (isc_ctx, "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, ISC_FALSE, &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); + 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"); + + 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); + + 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 = "dc"; + tmp->attrs[1]->mod_values = (char **) calloc (sizeof (char *), 2); + 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); + 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); + sprintf (charttl, "%d", ttl); + tmp->attrs[3]->mod_values[0] = strdup (charttl); + tmp->attrs[3]->mod_values[1] = NULL; + + + tmp->attrs[4] = 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 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 (x == (size - 2) && (strncmp (dc_list[x], "@", 1)) && (ttl)) + sprintf (tmp, "dc=%s + dNSTTL=%d,", dc_list[x], ttl); + 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)); + + 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)) + { + 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 ");} diff --git a/util/copyrights b/util/copyrights index e2bdce5e41..63e54bc674 100644 --- a/util/copyrights +++ b/util/copyrights @@ -763,8 +763,12 @@ ./contrib/linux/coredump-patch X 2000,2001 ./contrib/named-bootconf/named-bootconf.sh SH.PORTION 1999,2000,2001 ./contrib/nanny/nanny.pl PERL 2000,2001 +./contrib/sdb/INSTALL.ldap X 2001 +./contrib/sdb/README.ldap X 2001 ./contrib/sdb/dirdb.c C 2000,2001 ./contrib/sdb/dirdb.h C 2000,2001 +./contrib/sdb/ldapdb.c X 2001 +./contrib/sdb/ldapdb.h X 2001 ./contrib/sdb/lookup.tcl TCL 2000,2001 ./contrib/sdb/pgsqldb.c C 2000,2001 ./contrib/sdb/pgsqldb.h C 2000,2001 @@ -773,6 +777,8 @@ ./contrib/sdb/timedb.c C 2000,2001 ./contrib/sdb/timedb.h C 2000,2001 ./contrib/sdb/zonetodb.c C 2000,2001 +./contrib/sdb/zonetoldap.c X 2001 +./contrib/sdb/zonetoldap.1 X 2001 ./doc/.cvsignore X 2000,2001 ./doc/Makefile.in MAKE 2000,2001 ./doc/arm/.cvsignore X 2000,2001