Added the contributed LDAP sdb driver and program to convert a zone into an

LDAP schema.
This commit is contained in:
Brian Wellington 2001-03-14 20:22:32 +00:00
parent 02a402afe5
commit bf49a52178
13 changed files with 2244 additions and 0 deletions

59
contrib/sdb/INSTALL.ldap Normal file
View file

@ -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 <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 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 <venaas@uninett.no> 2001-03-03

9
contrib/sdb/README.ldap Normal file
View file

@ -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 <venaas@uninett.no> 2001-03-03

View file

@ -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 <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 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 <venaas@uninett.no> 2001-03-03

View file

@ -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 <venaas@uninett.no> 2001-03-03

304
contrib/sdb/ldap/ldapdb.c Normal file
View file

@ -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 <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 <dns/sdb.h>
#include <named/globals.h>
#include <ldap.h>
#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);
}

View file

@ -0,0 +1,6 @@
#include <isc/types.h>
isc_result_t ldapdb_init(void);
void ldapdb_clear(void);

View file

@ -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 <jeffmcneil@mindspring.com>.
.SH AUTHOR
Jeff McNeil <jmcneil@interland.com>

View file

@ -0,0 +1,677 @@
/*
* Copyright (C) 2001 Jeff McNeil <jeffmcneil@mindspring.com>
*
* 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 <errno.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <getopt.h>
#include <isc/buffer.h>
#include <isc/mem.h>
#include <isc/print.h>
#include <isc/result.h>
#include <dns/db.h>
#include <dns/dbiterator.h>
#include <dns/fixedname.h>
#include <dns/name.h>
#include <dns/rdata.h>
#include <dns/rdataset.h>
#include <dns/rdatasetiter.h>
#include <dns/result.h>
#include <dns/rdatatype.h>
#include <ldap.h>
#define DNS_OBJECT 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 ");}

304
contrib/sdb/ldapdb.c Normal file
View file

@ -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 <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 <dns/sdb.h>
#include <named/globals.h>
#include <ldap.h>
#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);
}

6
contrib/sdb/ldapdb.h Normal file
View file

@ -0,0 +1,6 @@
#include <isc/types.h>
isc_result_t ldapdb_init(void);
void ldapdb_clear(void);

64
contrib/sdb/zone2ldap.1 Normal file
View file

@ -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 <jeffmcneil@mindspring.com>.
.SH AUTHOR
Jeff McNeil <jmcneil@interland.com>

677
contrib/sdb/zone2ldap.c Normal file
View file

@ -0,0 +1,677 @@
/*
* Copyright (C) 2001 Jeff McNeil <jeffmcneil@mindspring.com>
*
* 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 <errno.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <getopt.h>
#include <isc/buffer.h>
#include <isc/mem.h>
#include <isc/print.h>
#include <isc/result.h>
#include <dns/db.h>
#include <dns/dbiterator.h>
#include <dns/fixedname.h>
#include <dns/name.h>
#include <dns/rdata.h>
#include <dns/rdataset.h>
#include <dns/rdatasetiter.h>
#include <dns/result.h>
#include <dns/rdatatype.h>
#include <ldap.h>
#define DNS_OBJECT 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 ");}

View file

@ -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