Commit bf49a521 authored by Brian Wellington's avatar Brian Wellington

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

LDAP schema.
parent 02a402af
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
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
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
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
/*
* 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);
}
#include <isc/types.h>
isc_result_t ldapdb_init(void);
void ldapdb_clear(void);
.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>
/*
* 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);