From 24f0ba9a9c5984c30b62b3220f6e83afc3370ced Mon Sep 17 00:00:00 2001 From: Ben Klang Date: Fri, 2 Dec 2005 04:26:14 +0000 Subject: [PATCH] Importing version 0.3.4 git-svn-id: https://svn.alkaloid.net/gpl/ldap2dns/trunk@7 06cd67b6-e706-0410-b29e-9de616bca6e9 --- CHANGELOG | 33 +- FAQ | 19 + Makefile | 31 +- README.html | 8 +- TODO.schema | 1 + askldap.c | 743 +++++++++++++++++++++++ askldap.h | 10 + djbdns-1.0.5.patch | 972 +++++++++++++++++++++++++++++++ dns.at.conf | 24 - dns.oc.conf | 45 -- dns.schema => dns.schema-2.0 | 76 ++- dns.schema-2.2 | 126 ++++ export-ldap2dns.pl | 190 ++++++ ldap2dns-dbg | Bin 0 -> 71947 bytes ldap2dns-ldapuri.patch | 134 +++++ ldap2dns-loccode.patch | 299 ++++++++++ ldap2dns.c | 216 ++++++- webadmin/.htaccess | 2 + webadmin/common.inc | 81 +++ webadmin/config.inc | 44 ++ webadmin/footer.inc | 3 + webadmin/framesets.inc | 8 + webadmin/icons/branch-cont.gif | Bin 0 -> 849 bytes webadmin/icons/branch-end.gif | Bin 0 -> 843 bytes webadmin/icons/folder-closed.gif | Bin 0 -> 887 bytes webadmin/icons/folder-open.gif | Bin 0 -> 911 bytes webadmin/icons/img-blank.gif | Bin 0 -> 834 bytes webadmin/icons/img-vert-line.gif | Bin 0 -> 844 bytes webadmin/icons/minus-cont.gif | Bin 0 -> 867 bytes webadmin/icons/minus-end.gif | Bin 0 -> 864 bytes webadmin/icons/plus-cont.gif | Bin 0 -> 872 bytes webadmin/icons/plus-end.gif | Bin 0 -> 871 bytes webadmin/icons/zone_forb.gif | Bin 0 -> 972 bytes webadmin/icons/zone_new.gif | Bin 0 -> 947 bytes webadmin/icons/zone_unkn.gif | Bin 0 -> 263 bytes webadmin/icons/zone_unre.gif | Bin 0 -> 267 bytes webadmin/icons/zone_val.gif | Bin 0 -> 264 bytes webadmin/index.php | 725 +++++++++++++++++++++++ webadmin/main.css | 17 + webadmin/mainheader.inc | 8 + webadmin/menu.css | 37 ++ webadmin/menuheader.inc | 8 + webadmin/xearth.css | 21 + webadmin/xearth.php | 16 + webadmin/xearthimage.php | 4 + 45 files changed, 3757 insertions(+), 144 deletions(-) create mode 100644 FAQ create mode 100644 TODO.schema create mode 100644 askldap.c create mode 100644 askldap.h create mode 100644 djbdns-1.0.5.patch delete mode 100644 dns.at.conf delete mode 100644 dns.oc.conf rename dns.schema => dns.schema-2.0 (56%) create mode 100644 dns.schema-2.2 create mode 100755 export-ldap2dns.pl create mode 100755 ldap2dns-dbg create mode 100644 ldap2dns-ldapuri.patch create mode 100644 ldap2dns-loccode.patch create mode 100644 webadmin/.htaccess create mode 100644 webadmin/common.inc create mode 100644 webadmin/config.inc create mode 100644 webadmin/footer.inc create mode 100644 webadmin/framesets.inc create mode 100644 webadmin/icons/branch-cont.gif create mode 100644 webadmin/icons/branch-end.gif create mode 100644 webadmin/icons/folder-closed.gif create mode 100644 webadmin/icons/folder-open.gif create mode 100644 webadmin/icons/img-blank.gif create mode 100644 webadmin/icons/img-vert-line.gif create mode 100644 webadmin/icons/minus-cont.gif create mode 100644 webadmin/icons/minus-end.gif create mode 100644 webadmin/icons/plus-cont.gif create mode 100644 webadmin/icons/plus-end.gif create mode 100644 webadmin/icons/zone_forb.gif create mode 100644 webadmin/icons/zone_new.gif create mode 100644 webadmin/icons/zone_unkn.gif create mode 100644 webadmin/icons/zone_unre.gif create mode 100644 webadmin/icons/zone_val.gif create mode 100644 webadmin/index.php create mode 100644 webadmin/main.css create mode 100644 webadmin/mainheader.inc create mode 100644 webadmin/menu.css create mode 100644 webadmin/menuheader.inc create mode 100644 webadmin/xearth.css create mode 100644 webadmin/xearth.php create mode 100644 webadmin/xearthimage.php diff --git a/CHANGELOG b/CHANGELOG index a811ec1..2778c87 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,9 +1,38 @@ -Version 0.2.7 (next) +Version ?.?.? (next) + Make ldap2dns behave like a secondary nameserver by storing the serial number, expire, refresh, retry and minimum values in a record. -Version 0.2.6 (latest) +Version 0.3.3 (latest) +- Removed a bug which caused ldap2dns to etablish more than one connections + to the LDAP server. + +Version 0.3.2 ++ Only patches from Martin Lesser + applied. Nothing from myself. ++ connecting to a ldap-server where the server is given as URI works + (both ldap:// [with TLS] and ldaps://) ++ we use location-codes here, so ldap2dns.c was extended to make use of + them, this also requires an extension of dns.schema. + +Version 0.3.1 ++ ldap2dns now can work together with tinydns. This means that + all DNS queries are passed through tinydns directly onto the + LDAP backend. This avoids generating a data-file and calling + tinydns-data (or restarting BIND). + Drawback: Queries are much slower now. I am not sure if this + is acceptable on the long run. This is caused by the LDAP-schema + used here, were many objects with strict attribute-value-pair mapping + is used. Other schemas, such as the core- and cosine-schema need + less LDAP-objects, since they code multiple values into one attribute. + Nameservers based on this schema (such as ldapdns + http://nimh.org/code/ldapdns/) can therefore answer much faster. + +Version 0.3.0 ++ A new interface for web-administration written compleatly in PHP. + Much easier to install that the old mod_perl interface. + +Version 0.2.6 + Password passed with option -w now is invisible to 'ps'. + ldap2tinydns-conf now takes a parameter to specify to user under which ldap2dns will be running. diff --git a/FAQ b/FAQ new file mode 100644 index 0000000..0945ca8 --- /dev/null +++ b/FAQ @@ -0,0 +1,19 @@ +From: Steven Dossett +Right after I mailed you, I patched the schema :) +I moved from IA5 Strings to Numeric Strings in that section of the schema: + +attributetype ( 1.3.6.1.4.1.7222.1.4.12 + NAME 'dnsipaddr' + EQUALITY numericStringMatch + SUBSTR numericStringSubstringsMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.36{16} ) + +attributetype ( 1.3.6.1.4.1.7222.1.4.13 + NAME 'dnscipaddr' + EQUALITY numericStringMatch + SUBSTR numericStringSubstringsMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.36{16} ) + +Thanks for the quick reply. Take care. + + diff --git a/Makefile b/Makefile index 459624b..05e29d5 100644 --- a/Makefile +++ b/Makefile @@ -1,9 +1,9 @@ -# $Id: Makefile,v 1.27 2001/08/09 10:35:49 jrief Exp $ -VERSION=0.2.6 +# $Id: Makefile,v 1.30 2003/01/20 14:33:25 jrief Exp $ +VERSION=0.3.4 RELEASE=1 CC=gcc -O2 +CCDEBUG=gcc -g CFLAGS=$(INC) -DVERSION='"$(VERSION)"' -OBJS=ldap2dns.o LIBS=-lldap -llber LD=gcc LDFLAGS= @@ -13,30 +13,37 @@ LDAPCONFDIR=$(INSTALL_PREFIX)/etc/openldap TARFILE=/usr/src/redhat/SOURCES/ldap2dns-$(VERSION).tar.gz SPECFILE=ldap2dns.spec -all: ldap2dns +all: ldap2dns ldap2dnsd ldap2dns-dbg -ldap2dns: $(OBJS) $(LIBS) - $(LD) $(LDFLAGS) -o $@ $(OBJS) $(LIBS) +ldap2dns: ldap2dns.o $(LIBS) + $(LD) $(LDFLAGS) -o $@ $+ + +ldap2dnsd: ldap2dns ln -f ldap2dns ldap2dnsd +ldap2dns-dbg: ldap2dns.o-dbg $(LIBS) + $(LD) $(LDFLAGS) -o $@ $+ + ldap2dns.o: ldap2dns.c - $(CC) $(CFLAGS) -c $< + $(CC) $(CFLAGS) -c $< -o $@ + +ldap2dns.o-dbg: ldap2dns.c + $(CCDEBUG) $(CFLAGS) -c $< -o $@ install: all mkdir -p $(PREFIXDIR)/bin - mkdir -p $(LDAPCONFDIR) + mkdir -p $(LDAPCONFDIR)/schema install -s -o root -g root -m 755 ldap2dns $(PREFIXDIR)/bin/ ln -f $(PREFIXDIR)/bin/ldap2dns $(PREFIXDIR)/bin/ldap2dnsd install -o root -g root -m 755 ldap2tinydns-conf $(PREFIXDIR)/bin/ - install -o root -g root -m 644 dns.at.conf $(LDAPCONFDIR)/ - install -o root -g root -m 644 dns.oc.conf $(LDAPCONFDIR)/ + install -o root -g root -m 644 dns.schema $(LDAPCONFDIR)/schema/ clean: - rm -f $(OBJS) ldap2dns ldap2dnsd data* *.db core $(SPECFILE) + rm -f *.o *.o-dbg ldap2dns ldap2dnsd data* *.db core $(SPECFILE) tar: clean cd ..; \ - tar czf $(TARFILE) ldap2dns-$(VERSION) --exclude CVS --exclude DNSadmin + tar czf $(TARFILE) ldap2dns-$(VERSION) --exclude CVS $(SPECFILE): Specfile sed -e 's#%VERSION%#$(VERSION)#g' \ diff --git a/README.html b/README.html index 2eb03b6..161a655 100644 --- a/README.html +++ b/README.html @@ -195,8 +195,12 @@ include /etc/openldap/dns.at.conf include /etc/openldap/dns.oc.conf or, if You are using openldap-2.0.x:
-copy the file dns.schema into the directory /etc/openldap/schema or -appropriate and add the following line to Your slapd.conf file:
+copy the file dns.schema-2.0 into the directory /etc/openldap/schema +and rename it to dns.schema. +If You are using openldap-2.2.x:
+copy the file dns.schema-2.2 into the directory /etc/openldap/schema +and rename it to dns.schema. +Add the following line to Your slapd.conf file:
 include         /etc/openldap/schema/dns.schema
 
diff --git a/TODO.schema b/TODO.schema new file mode 100644 index 0000000..668aa32 --- /dev/null +++ b/TODO.schema @@ -0,0 +1 @@ +# schema for DNS data# include this file into Your slapd.conf for openldap-2.0.x# $Id: dns.schema,v 1.9 2001/11/06 08:01:51 config Exp $attributetype ( 1.3.6.1.4.1.7222.1.4.1 NAME 'dnszonename' SUP name )attributetype ( 1.3.6.1.4.1.7222.1.4.2 NAME 'dnsserial' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )attributetype ( 1.3.6.1.4.1.7222.1.4.3 NAME 'dnsrefresh' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )attributetype ( 1.3.6.1.4.1.7222.1.4.4 NAME 'dnsretry' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )attributetype ( 1.3.6.1.4.1.7222.1.4.5 NAME 'dnsexpire' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )attributetype ( 1.3.6.1.4.1.7222.1.4.6 NAME 'dnsminimum' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )attributetype ( 1.3.6.1.4.1.7222.1.4.7 NAME 'dnsadminmailbox' SUP name )attributetype ( 1.3.6.1.4.1.7222.1.4.8 NAME 'dnszonemaster' SUP name )attributetype ( 1.3.6.1.4.1.7222.1.4.9 NAME 'dnstype' SUP name )attributetype ( 1.3.6.1.4.1.7222.1.4.10 NAME 'dnsclass' SUP name )attributetype ( 1.3.6.1.4.1.7222.1.4.11 NAME 'dnsdomainname' SUP name )attributetype ( 1.3.6.1.4.1.7222.1.4.12 NAME 'dnsipaddr' EQUALITY caseIgnoreIA5Match SUBSTR caseIgnoreIA5SubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{16} ) SINGLE-VALUE )attributetype ( 1.3.6.1.4.1.7222.1.4.13 NAME 'dnscipaddr' EQUALITY caseIgnoreIA5Match SUBSTR caseIgnoreIA5SubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{16} )attributetype ( 1.3.6.1.4.1.7222.1.4.14 NAME 'dnscname' SUP name )attributetype ( 1.3.6.1.4.1.7222.1.4.15 NAME 'dnspreference' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )attributetype ( 1.3.6.1.4.1.7222.1.4.16 NAME 'dnsrr' SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE )attributetype ( 1.3.6.1.4.1.7222.1.4.17 NAME 'dnsttl' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )attributetype ( 1.3.6.1.4.1.7222.1.4.18 NAME 'dnstimestamp' SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE )attributetype ( 1.3.6.1.4.1.7222.1.4.21 NAME 'NIChandle' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{16} )attributetype ( 1.3.6.1.4.1.7222.1.4.22 NAME 'TIShandle' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{16} )objectclass ( 1.3.6.1.4.1.7222.1.4.19 NAME 'dnszone' MUST ( objectclass $ cn ) MAY ( dnszonename $ dnsserial $ dnsrefresh $ dnsretry $ dnsexpire $ dnsminimum $ dnsadminmailbox $ dnszonemaster $ dnstype $ dnsclass $ dnsttl $ dnstimestamp $ owner $ NIChandle $ TIShandle ) )objectclass ( 1.3.6.1.4.1.7222.1.4.20 NAME 'dnsrrset' SUP dnszone MUST ( objectclass $ cn ) MAY ( dnsdomainname $ dnsrr $ dnsclass $ dnstype $ dnsipaddr $ dnscipaddr $ dnscname $ dnspreference $ dnsttl $ dnstimestamp $ owner ) ) diff --git a/askldap.c b/askldap.c new file mode 100644 index 0000000..5d9f2da --- /dev/null +++ b/askldap.c @@ -0,0 +1,743 @@ +/* Patch for tinydns to pass DNS-query to LDAP in favour of a cdb lookup. + * $Id: askldap.c,v 1.8 2002/08/12 16:41:25 jrief Exp $ + * Copyright 2002 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "alloc.h" +#include "byte.h" +#include "response.h" +#include "askldap.h" +#include "dns.h" + +static LDAP* ldap_con; +static sigjmp_buf stack_context; + +static struct { + char ldaphosts[256]; + const char* basedn; + char binddn[256]; + char bindpwd[16]; + struct timeval timeout; + int verbose; + int initialized; +} options; + +struct zonerecord { + char zonedn[256]; + char zonename[64]; + char class[16]; + char type[16]; + char adminmailbox[64]; + char zonemaster[64]; + unsigned long serial, refresh, retry, expire, minimum; + int ttl; + int timestamp; +}; + +struct resourcerecord { + char qualifieddomainname[256]; + char class[16]; + char type[16]; + char ipaddr[8][4]; + int numipaddrs; + char cname[256]; + unsigned int preference; + int ttl; + int timestamp; + int additionalinfo; + struct resourcerecord* next; +}; + +enum { ASKLDAP_RETRY = 1, ASKLDAP_RETURN = 2, ASKLDAP_RECONNECT = 3 }; + +static +void assert_ldap(int err) +{ + static int retries; + switch (err) { + case LDAP_SUCCESS: + return; + case LDAP_TIMELIMIT_EXCEEDED: + fprintf(stderr, "Warning: %s\n", ldap_err2string(err)); + retries++; + if (retries<3) + siglongjmp(stack_context, ASKLDAP_RETRY); + retries = 0; + siglongjmp(stack_context, ASKLDAP_RETURN); + case LDAP_TIMEOUT: + case LDAP_NO_SUCH_OBJECT: + fprintf(stderr, "Warning: %s\n", ldap_err2string(err)); + siglongjmp(stack_context, ASKLDAP_RETURN); + case LDAP_BUSY: + case LDAP_UNAVAILABLE: + case LDAP_UNWILLING_TO_PERFORM: + case LDAP_SERVER_DOWN: + fprintf(stderr, "Warning: %s\n", ldap_err2string(err)); + siglongjmp(stack_context, ASKLDAP_RECONNECT); + default: + fprintf(stderr, "Fatal error: %s\n", ldap_err2string(err)); +#ifdef _DEBUG + abort(); +#else + exit(1); +#endif + } +} + +void free_domainrecords(struct resourcerecord* anchor) +{ + struct resourcerecord* ptr; + for (ptr = anchor; ptr; ptr = anchor) { + anchor = anchor->next; + alloc_free(ptr); + } +} + +static +void fill_resourcerecord(struct resourcerecord* rr, LDAPMessage* m, const char* zonename) +{ + BerElement* ber = NULL; + char* attr; + + byte_zero(rr, sizeof(struct resourcerecord)); + strcpy(rr->class, "IN"); + for (attr = ldap_first_attribute(ldap_con, m, &ber); attr; attr = ldap_next_attribute(ldap_con, m, ber)) { + struct berval** bvals = ldap_get_values_len(ldap_con, m, attr); + if (bvals && bvals[0] && bvals[0]->bv_len>0) { + if (strcasecmp(attr, "dnsdomainname")==0) { + char tmp[64]; + if (sscanf(bvals[0]->bv_val, "%64s", tmp)==1) { + if (zonename[0]!='\0') + snprintf(rr->qualifieddomainname, 256, "%s.%s", tmp, zonename); + else + strncpy(rr->qualifieddomainname, tmp, 256); + } + } else if (strcasecmp(attr, "dnstype")==0) { + if (sscanf(bvals[0]->bv_val, "%16s", rr->type)!=1) { + rr->type[0] = '\0'; + } + } else if (strcasecmp(attr, "dnsipaddr")==0) { + int k, ip[4]; + for (k = 0; bvals[k] && k < 8-rr->numipaddrs; k++) { + if (sscanf(bvals[k]->bv_val, "%d.%d.%d.%d", &ip[0], &ip[1], &ip[2], &ip[3])==4) { + rr->ipaddr[rr->numipaddrs][0] = (char)ip[0]; + rr->ipaddr[rr->numipaddrs][1] = (char)ip[1]; + rr->ipaddr[rr->numipaddrs][2] = (char)ip[2]; + rr->ipaddr[rr->numipaddrs][3] = (char)ip[3]; + rr->numipaddrs++; + } + } + } else if (rr->numipaddrs<8 && strcasecmp(attr, "dnscipaddr")==0) { + int ip[4]; + if (sscanf(bvals[0]->bv_val, "%d.%d.%d.%d", &ip[0], &ip[1], &ip[2], &ip[3])==4) { + rr->ipaddr[rr->numipaddrs][0] = (char)ip[0]; + rr->ipaddr[rr->numipaddrs][1] = (char)ip[1]; + rr->ipaddr[rr->numipaddrs][2] = (char)ip[2]; + rr->ipaddr[rr->numipaddrs][3] = (char)ip[3]; + rr->numipaddrs++; + } + } else if (strcasecmp(attr, "dnscname")==0) { + if (sscanf(bvals[0]->bv_val, "%256s", rr->cname)==1) { + int len = strlen(rr->cname); + if (rr->cname[len-1]!='.' && zonename[0]!='\0') { + strcat(rr->cname, "."); + strncat(rr->cname, zonename, 252-len); + strcat(rr->cname, "."); + } + } else { + rr->cname[0] = '\0'; + } + } else if (strcasecmp(attr, "dnsttl")==0) { + if (sscanf(bvals[0]->bv_val, "%d", &rr->ttl)!=1) + rr->ttl = 0; + } else if (strcasecmp(attr, "dnstimestamp")==0) { + if (sscanf(bvals[0]->bv_val, "%d", &rr->timestamp)!=1) + rr->timestamp = 0; + } else if (strcasecmp(attr, "dnspreference")==0) { + if (sscanf(bvals[0]->bv_val, "%u", &rr->preference)!=1) + rr->preference = 1; + } + } + ldap_value_free_len(bvals); + } + if (rr->qualifieddomainname[0]=='\0') + strncpy(rr->qualifieddomainname, zonename, 256); +} + +static +void fill_zonerecord(struct zonerecord* zone, LDAPMessage* m) +{ + BerElement* ber = NULL; + char* attr; + + byte_zero(zone, sizeof(struct zonerecord)); + strcpy(zone->class, "IN"); + for (attr = ldap_first_attribute(ldap_con, m, &ber); attr; attr = ldap_next_attribute(ldap_con, m, ber)) { + struct berval** bvals = ldap_get_values_len(ldap_con, m, attr); + if (bvals && bvals[0] && bvals[0]->bv_len>0) { + if (strcasecmp(attr, "dnstype")==0) { + if (sscanf(bvals[0]->bv_val, "%16s", zone->type)!=1) + zone->type[0] = '\0'; + } else if (strcasecmp(attr, "dnsserial")==0) { + if (sscanf(bvals[0]->bv_val, "%lu", &zone->serial)!=1) + zone->serial = 0; + } else if (strcasecmp(attr, "dnsrefresh")==0) { + if (sscanf(bvals[0]->bv_val, "%lu", &zone->refresh)!=1) + zone->refresh = 0; + } else if (strcasecmp(attr, "dnsretry")==0) { + if (sscanf(bvals[0]->bv_val, "%lu", &zone->retry)!=1) + zone->retry = 0; + } else if (strcasecmp(attr, "dnsexpire")==0) { + if (sscanf(bvals[0]->bv_val, "%lu", &zone->expire)!=1) + zone->expire = 0; + } else if (strcasecmp(attr, "dnsminimum")==0) { + if (sscanf(bvals[0]->bv_val, "%lu", &zone->minimum)!=1) + zone->minimum = 0; + } else if (strcasecmp(attr, "dnsadminmailbox")==0) { + if (sscanf(bvals[0]->bv_val, "%64s", zone->adminmailbox)!=1) + zone->adminmailbox[0] = '\0'; + } else if (strcasecmp(attr, "dnszonemaster")==0) { + if (sscanf(bvals[0]->bv_val, "%64s", zone->zonemaster)!=1) + zone->zonemaster[0] = '\0'; + } else if (strcasecmp(attr, "dnsttl")==0) { + if (sscanf(bvals[0]->bv_val, "%d", &zone->ttl)!=1) + zone->ttl = 0; + } else if (strcasecmp(attr, "dnstimestamp")==0) { + if (sscanf(bvals[0]->bv_val, "%d", &zone->timestamp)!=1) + zone->timestamp = 0; + } else if (strcasecmp(attr, "dnszonename")==0) { + if (sscanf(bvals[0]->bv_val, "%s", zone->zonename)!=1) + zone->zonename[0] = '\0'; + } + } + ldap_value_free_len(bvals); + } +} + +static +int find_ipaddr(const char* queryname, char ip[4]) +{ + static char *rrattrs[] = { "dnsipaddr", "dnscipaddr", 0 }; + LDAPMessage* res = NULL; + LDAPMessage* m; + int ret = 0; + char filter[256], domainname[64]; + const char *zonename = queryname; + domainname[0] = '\0'; + while (*zonename) { + int len = snprintf(filter, 256, "(&(dnszonename=%s", zonename); + if (filter[len-1]=='.') + filter[len-1] = '\0'; + strncat(filter, ")(objectclass=dnszone)(dnsclass=IN))", 256-len); + assert_ldap(ldap_search_st(ldap_con, options.basedn, LDAP_SCOPE_SUBTREE, filter, rrattrs, 0, &options.timeout, &res)); + if (m = ldap_first_entry(ldap_con, res)) { + char* zonedn = ldap_get_dn(ldap_con, m); + if (ldap_next_entry(ldap_con, m)) + printf("Warning: ambigous zonename for %s in %s\n", zonename, zonedn); + if (domainname[0]!='\0') { + len = strlen(domainname); + if (domainname[len-1]=='.') + domainname[len-1] = '\0'; + snprintf(filter, 256, "(&(|(dnsdomainname=%s)(dnscname=%s))(objectclass=dnsrrset)(dnsclass=IN)(|(dnsipaddr=*)(dnscipaddr=*)))", domainname, domainname); + } else { + strcpy(filter, "(&(!(dnsdomainname=*))(objectclass=dnsrrset)(dnsclass=IN)(|(dnsipaddr=*)(dnscipaddr=*)))"); + } + ldap_msgfree(res); + assert_ldap(ldap_search_st(ldap_con, zonedn, LDAP_SCOPE_SUBTREE, filter, rrattrs, 0, &options.timeout, &res)); + if (m = ldap_first_entry(ldap_con, res)) { + struct resourcerecord rr; + fill_resourcerecord(&rr, m, ""); + if (rr.numipaddrs>0) { + rr.numipaddrs = rand()%rr.numipaddrs; + ip[0] = rr.ipaddr[rr.numipaddrs][0]; + ip[1] = rr.ipaddr[rr.numipaddrs][1]; + ip[2] = rr.ipaddr[rr.numipaddrs][2]; + ip[3] = rr.ipaddr[rr.numipaddrs][3]; + ret = 1; + } + } + ldap_memfree(zonedn); + ldap_msgfree(res); res = NULL; + if (ret) + return 1; + break; + } + while (*zonename && *zonename!='.') { + domainname[zonename-queryname] = *zonename; + zonename++; + } + domainname[zonename-queryname] = *zonename; + if (*zonename=='.') { + zonename++; + domainname[zonename-queryname] = '\0'; + } + } + /* sometimes the queryname resolves directly as cname in some other records */ + snprintf(filter, 256, "(&(dnscname=%s)(objectclass=dnsrrset)(dnsclass=IN)(|(dnsipaddr=*)(dnscipaddr=*)))", queryname); + assert_ldap(ldap_search_st(ldap_con, options.basedn, LDAP_SCOPE_SUBTREE, filter, rrattrs, 0, &options.timeout, &res)); + if (m = ldap_first_entry(ldap_con, res)) { + struct resourcerecord rr; + fill_resourcerecord(&rr, m, ""); + if (rr.numipaddrs>0) { + rr.numipaddrs = rand()%rr.numipaddrs; + ip[0] = rr.ipaddr[rr.numipaddrs][0]; + ip[1] = rr.ipaddr[rr.numipaddrs][1]; + ip[2] = rr.ipaddr[rr.numipaddrs][2]; + ip[3] = rr.ipaddr[rr.numipaddrs][3]; + ret = 1; + } + } + ldap_msgfree(res); + return ret; +} + +static +struct resourcerecord* find_reverserecord(const char* queryname, int ip[4]) +{ + static char *rrattrs[] = { "dnstype", "dnsdomainname", "dnscname", "dnsttl", 0 }; + LDAPMessage* res = NULL; + struct resourcerecord* rr = NULL; + LDAPMessage* m; + char filter[256]; + snprintf(filter, 256, "(&(dnscipaddr=%u.%u.%u.%u)(objectclass=dnsrrset)(dnsclass=IN))", ip[0], ip[1], ip[2], ip[3]); + assert_ldap(ldap_search_st(ldap_con, options.basedn, LDAP_SCOPE_SUBTREE, filter, rrattrs, 0, &options.timeout, &res)); + if (m = ldap_first_entry(ldap_con, res)) { + char* rrsetdn = ldap_get_dn(ldap_con, m); + char** explodedn = NULL; + + rr = (void*)alloc(sizeof(struct resourcerecord)); + fill_resourcerecord(rr, m, ""); + if (ldap_next_entry(ldap_con, m)) + printf("Warning: ambigous IP-address for %u.%u.%u.%u in dn: %s\n", ip[0], ip[1], ip[2], ip[3], rrsetdn); + explodedn = ldap_explode_dn(rrsetdn, 0); + if (explodedn[0]) { + static char *zoneattrs[] = { "dnszonename", 0 }; + char zonedn[256]; + int i, len = 0; + struct zonerecord zone; + + zonedn[0] = '\0'; + for (i = 1; explodedn[i]; i++) + len += snprintf(zonedn+len, 256-len, "%s,", explodedn[i]); + zonedn[len-1] = '\0'; + ldap_msgfree(res); + assert_ldap(ldap_search_st(ldap_con, zonedn, LDAP_SCOPE_SUBTREE, "(objectclass=dnszone)", zoneattrs, 0, &options.timeout, &res)); + m = ldap_first_entry(ldap_con, res); + if (m==NULL) + printf("Error: parent dn: %s not found for %s\n", zonedn, rrsetdn); + fill_zonerecord(&zone, m); + len = strlen(rr->qualifieddomainname); + if (len==0) { + len = strlen(rr->cname); + if (rr->cname[len-1]!='.') { + strcat(rr->cname, "."); + strncat(rr->cname, zone.zonename, 252-len); + } + } else { + /* in those situations where a dnsrrset + * defines something like MX or NS for a zone + * and also sets a canonical name for the + * service. */ + snprintf(rr->cname, 256, "%s.%s", rr->qualifieddomainname, zone.zonename); + } + strcpy(rr->type, "PTR"); + strncpy(rr->qualifieddomainname, queryname, 256); + } + ldap_memfree(rrsetdn); + ldap_value_free(explodedn); + } + ldap_msgfree(res); + return rr; +} + +static +struct resourcerecord* read_domainrecords(const char* zonedn, const char* domainname, const char* zonename) +{ + static char *rrattrs[] = { "dnsdomainname", "dnstype", "dnsttl", "dnscname", "dnsipaddr", "dnscipaddr", "dnstimestamp", "dnspreference", 0 }; + LDAPMessage* res = NULL; + LDAPMessage* m; + char filter[256]; + struct resourcerecord *prev, *anchor = NULL; + + if (domainname[0]) { + if (strstr(zonename, "in-addr.arpa")) { + unsigned int ip[4]; + char queryname[256]; + snprintf(queryname, 256, "%s.%s", domainname, zonename); + if (sscanf(queryname, "%3u.%3u.%3u.%3u", &ip[3], &ip[2], &ip[1], &ip[0])!=4) + return NULL; + snprintf(filter, 256, "(&(dnsipaddr=%u.%u.%u.%u)(objectclass=dnsrrset)(dnsclass=IN))", ip[0], ip[1], ip[2], ip[3]); + assert_ldap(ldap_search_st(ldap_con, zonedn, LDAP_SCOPE_SUBTREE, filter, rrattrs, 0, &options.timeout, &res)); + if (m = ldap_first_entry(ldap_con, res)) { + struct resourcerecord* rr; + rr = (void*)alloc(sizeof(struct resourcerecord)); + fill_resourcerecord(rr, m, zonename); + strncpy(rr->qualifieddomainname, queryname, 256); + ldap_msgfree(res); + return rr; + } else { + /* ipaddr not in our baliwick, search the whole tree for canonical ipaddr */ + ldap_msgfree(res); + return find_reverserecord(queryname, ip); + } + } else { + snprintf(filter, 256, "(&(dnsdomainname=%s)(objectclass=dnsrrset)(dnsclass=IN))", domainname); + assert_ldap(ldap_search_st(ldap_con, zonedn, LDAP_SCOPE_SUBTREE, filter, rrattrs, 0, &options.timeout, &res)); + } + } else { + snprintf(filter, 256, "(&(!(dnsdomainname=*))(objectclass=dnsrrset)(dnsclass=IN))"); + assert_ldap(ldap_search_st(ldap_con, zonedn, LDAP_SCOPE_SUBTREE, filter, rrattrs, 0, &options.timeout, &res)); + } + for (m = ldap_first_entry(ldap_con, res); m; m = ldap_next_entry(ldap_con, m)) { + struct resourcerecord* rr; + rr = (void*)alloc(sizeof(struct resourcerecord)); + fill_resourcerecord(rr, m, zonename); + if (anchor==NULL) { + prev = anchor = rr; + } else { + prev->next = rr; + prev = rr; + } + if (options.verbose&1) + printf("\trr: %s %s\n", domainname, rr->type); + } + ldap_msgfree(res); + return anchor; +} + +static +int read_dnszone(struct zonerecord* zone, const char* zonename) +{ + static char *zoneattrs[] = { "dnszonename", "dnstype", "dnsserial", "dnsrefresh", "dnsretry", "dnsexpire", "dnsminimum", "dnszonemaster", "dnsadminmailbox", "dnsttl", "dnstimestamp", 0 }; + LDAPMessage* res = NULL; + LDAPMessage* m; + char* dn; + char filter[256]; + + snprintf(filter, 256, "(&(dnszonename=%s)(objectclass=dnszone)(dnsclass=IN))", zonename); + assert_ldap(ldap_search_st(ldap_con, options.basedn, LDAP_SCOPE_SUBTREE, filter, zoneattrs, 0, &options.timeout, &res)); + m = ldap_first_entry(ldap_con, res); + if (m==NULL) { + ldap_msgfree(res); + return 0; + } + dn = ldap_get_dn(ldap_con, m); + fill_zonerecord(zone, m); + m = ldap_next_entry(ldap_con, m); + if (m) { + char* otherdn = ldap_get_dn(ldap_con, m); + printf("Warning: ambigous zonename found in dn: %s and dn: %s\n", dn, otherdn); + ldap_memfree(otherdn); + } + strncpy(zone->zonedn, dn, 256); + ldap_memfree(dn); + ldap_msgfree(res); + return 1; +} + +static +void djb_name(const char* dotname, char* djbname) +{ + const char* c = dotname; + int i, k; + for (i = 0; *c; c++) { + k = i; + while (*c!='.') { + k++; + djbname[k] = *c; + if (*c=='\0') { + djbname[i] = k-i-1; + return; + } + c++; + } + djbname[i] = k-i; + i = k+1; + } + djbname[i] = '\0'; +} + +static +void djb_type(const char* dottype, char djbtype[2]) +{ + djbtype[0] = '\0'; + if (strcasecmp(dottype, "A")==0) + djbtype[1] = 001; + else if (strcasecmp(dottype, "NS")==0) + djbtype[1] = 002; + else if (strcasecmp(dottype, "CNAME")==0) + djbtype[1] = 005; + else if (strcasecmp(dottype, "SOA")==0) + djbtype[1] = 006; + else if (strcasecmp(dottype, "PTR")==0) + djbtype[1] = 014; + else if (strcasecmp(dottype, "MX")==0) + djbtype[1] = 017; + else if (strcasecmp(dottype, "TXT")==0) + djbtype[1] = 020; +} + +static +void split_djbstyle(const char* djbname, char* domainname, char* zonename, int offset) +{ + int i, k, m = 0, n = 0; + for (i = *djbname; i; i = *++djbname) { + if (offset>0) { + offset--; + for (k = m; k0 ? m-1 : 0] = '\0'; + zonename[n>0 ? n-1 : 0] = '\0'; +} + +static +void build_response_section(struct resourcerecord *rr, char qtype[2], int section) +{ + char djbname[256], djbtype[2]; + djb_name(rr->qualifieddomainname, djbname); + djb_type(rr->type, djbtype); + if (byte_equal(djbtype, 2, DNS_T_A)) { + if (byte_equal(qtype, 2, DNS_T_A) || byte_equal(qtype, 2, DNS_T_ANY)) { + response_rstart(djbname, djbtype, rr->ttl); + response_addbytes(rr->ipaddr[rand()%rr->numipaddrs], 4); + response_rfinish(section); + } + } else if (byte_equal(djbtype, 2, DNS_T_CNAME)) { + response_rstart(djbname, djbtype, rr->ttl); + djb_name(rr->cname, djbname); + response_addname(djbname); + response_rfinish(section); + } else if (byte_equal(djbtype, 2, DNS_T_NS)) { + if (byte_equal(qtype, 2, DNS_T_NS) || byte_equal(qtype, 2, DNS_T_ANY)) { + response_rstart(djbname, djbtype, rr->ttl); + if (rr->cname[0]) { + djb_name(rr->cname, djbname); + response_addname(djbname); + rr->additionalinfo = 1; + } else { + response_addbytes(rr->ipaddr[rand()%rr->numipaddrs], 4); + } + response_rfinish(section); + } + } else if (byte_equal(djbtype, 2, DNS_T_PTR)) { + response_rstart(djbname, djbtype, rr->ttl); + djb_name(rr->cname, djbname); + response_addname(djbname); + response_rfinish(section); + } else if (byte_equal(djbtype, 2, DNS_T_MX)) { + if (byte_equal(qtype, 2, DNS_T_MX) || byte_equal(qtype, 2, DNS_T_ANY)) { + char tmp[2]; + response_rstart(djbname, djbtype, rr->ttl); + tmp[0] = rr->preference/0x100; + tmp[1] = rr->preference%0x100; + response_addbytes(tmp, 2); + if (rr->cname[0]) { + djb_name(rr->cname, djbname); + response_addname(djbname); + rr->additionalinfo = 1; + } else { + response_addbytes(rr->ipaddr[rand()%rr->numipaddrs], 4); + } + response_rfinish(section); + } + } +} + +static +void build_soa_section(struct zonerecord *zone, int section) +{ + time_t now; + char defaultsoa[20]; + char djbname[256]; + char zonesoa[20]; + unsigned long tmp; + time(&now); + djb_name(zone->zonename, djbname); + response_rstart(djbname, DNS_T_SOA, zone->ttl); + djb_name(zone->zonemaster, djbname); + response_addname(djbname); + djb_name(zone->adminmailbox, djbname); + response_addname(djbname); + uint32_pack_big(defaultsoa, now); + if (byte_equal(defaultsoa,4,"\0\0\0\0")) + defaultsoa[3] = 1; + byte_copy(defaultsoa + 4, 16, "\0\0\100\000\0\0\010\000\0\020\000\000\0\0\012\000"); + if (zone->serial==0) + uint32_unpack_big(defaultsoa, &tmp); + else + tmp = zone->serial; + uint32_pack_big(zonesoa, tmp); + if (zone->refresh==0) + uint32_unpack_big(defaultsoa+4, &tmp); + else + tmp = zone->refresh; + uint32_pack_big(zonesoa+4, tmp); + if (zone->retry==0) + uint32_unpack_big(defaultsoa+8, &tmp); + else + tmp = zone->retry; + uint32_pack_big(zonesoa+8, tmp); + if (zone->expire==0) + uint32_unpack_big(defaultsoa+12, &tmp); + else + tmp = zone->expire; + uint32_pack_big(zonesoa+12, tmp); + if (zone->minimum==0) + uint32_unpack_big(defaultsoa+16, &tmp); + else + tmp = zone->minimum; + uint32_pack_big(zonesoa+16, tmp); + response_addbytes(zonesoa, 20); + response_rfinish(section); +} + +static +void build_additional_section(struct resourcerecord *rr) +{ + char djbname[256], ip[4]; + if (rr->additionalinfo && find_ipaddr(rr->cname, ip)) { + djb_name(rr->cname, djbname); + response_rstart(djbname, DNS_T_A, rr->ttl); + response_addbytes(ip, 4); + response_rfinish(RESPONSE_ADDITIONAL); + } +} + +static +int connect_and_bind() +{ + ldap_con = ldap_init(options.ldaphosts, LDAP_PORT); + if (ldap_simple_bind_s(ldap_con, options.binddn, options.bindpwd)==LDAP_SUCCESS) { + printf("Connected to %s as \"%s\"\n", options.ldaphosts, options.binddn); + return 1; + } + ldap_con = NULL; + return 0; +} + +int askldap_query(const char* djbdomainname, char qtype[2]) +{ + int offset; + char domainname[64], zonename[64]; + struct zonerecord zoneinfo; + int answer_ok = 0, flagsoa = 0, flagns = 0; + if (!options.initialized) + return 0; + switch (sigsetjmp(stack_context, 1)) { + default: + if (ldap_con==NULL && !connect_and_bind()) + return answer_ok; + break; + case ASKLDAP_RECONNECT: + if (connect_and_bind()) + break; + return answer_ok; + case ASKLDAP_RETURN: + return answer_ok; + } + for (offset = 0; offset<32; offset++) { + struct resourcerecord *rransw, *rrauth, *rr; + + split_djbstyle(djbdomainname, domainname, zonename, offset); + if (zonename[0]=='\0') return 0; + if (!read_dnszone(&zoneinfo, zonename)) + continue; + rransw = read_domainrecords(zoneinfo.zonedn, domainname, zonename); + rrauth = NULL; + if (offset==0) { + /* query is in our bailiwick */ + if (byte_equal(qtype, 2, DNS_T_ANY) || byte_equal(qtype, 2, DNS_T_SOA)) { + build_soa_section(&zoneinfo, RESPONSE_ANSWER); + flagsoa = 1; + } + for (rr = rransw; rr; rr = rr->next) { + build_response_section(rr, qtype, RESPONSE_ANSWER); + answer_ok = 1; + } + if (!flagsoa) { + build_soa_section(&zoneinfo, RESPONSE_AUTHORITY); + flagsoa = 1; + } + if (!byte_equal(qtype, 2, DNS_T_ANY) && !byte_equal(qtype, 2, DNS_T_NS)) { + for (rr = rransw; rr; rr = rr->next) + if (strcmp(rr->type, "NS")==0) { + build_response_section(rr, DNS_T_NS, RESPONSE_AUTHORITY); + flagns = 1; + } + } + } else { + for (rr = rransw; rr; rr = rr->next) { + if (strcmp(rr->type, "NS")==0) { + build_response_section(rr, qtype, RESPONSE_AUTHORITY); + flagns = 1; + } + } + if (!flagns) { + for (rr = rransw; rr; rr = rr->next) { + build_response_section(rr, qtype, RESPONSE_ANSWER); + answer_ok = 1; + } + if (answer_ok) { + rrauth = read_domainrecords(zoneinfo.zonedn, "", zonename); + } else { + build_soa_section(&zoneinfo, RESPONSE_AUTHORITY); + flagsoa = 1; + } + } + for (rr = rrauth; rr; rr = rr->next) { + if (strcmp(rr->type, "NS")==0) { + build_response_section(rr, DNS_T_NS, RESPONSE_AUTHORITY); + flagns = 1; + } + } + } + for (rr = rransw; rr; rr = rr->next) + build_additional_section(rr); + for (rr = rrauth; rr; rr = rr->next) + build_additional_section(rr); + free_domainrecords(rransw); + free_domainrecords(rrauth); + break; + } + return answer_ok || flagsoa || flagns; +} + +void askldap_init(const char* ldaphost, const char* basedn, const char* binddn, const char* passwd) +{ + strncpy(options.ldaphosts, ldaphost, 256); + options.basedn = basedn; + if (binddn) strncpy(options.binddn, binddn, 256); + if (passwd) strncpy(options.bindpwd, passwd, 16); + /* LDAP timeout is hardcoded to 2/10 second. + * This must be enough because bindoperations usually + * timeout after one second and here we usually have to + * send five queries to the LDAP-server */ + options.timeout.tv_sec = 1; + options.timeout.tv_usec = 200000; + options.verbose = 0; + options.initialized = 1; + connect_and_bind(); +} + diff --git a/askldap.h b/askldap.h new file mode 100644 index 0000000..1338808 --- /dev/null +++ b/askldap.h @@ -0,0 +1,10 @@ +/* Patch for tinydns to pass DNS-query to LDAP in favour of a cdb lookup. + * $Id: askldap.h,v 1.8 2002/08/12 16:41:25 jrief Exp $ + * Copyright 2002 + */ + +extern +int askldap_query(const char* djbdomainname, char qtype[2]); + +extern +void askldap_init(const char* ldaphost, const char* basedn, const char* binddn, const char* passwd); diff --git a/djbdns-1.0.5.patch b/djbdns-1.0.5.patch new file mode 100644 index 0000000..ad6cb2f --- /dev/null +++ b/djbdns-1.0.5.patch @@ -0,0 +1,972 @@ +diff -Naur djbdns-1.05.orig/Makefile djbdns-1.05/Makefile +--- djbdns-1.05.orig/Makefile Sun Feb 11 22:11:45 2001 ++++ djbdns-1.05/Makefile Tue Aug 13 14:28:52 2002 +@@ -1,9 +1,6 @@ +-# Don't edit Makefile! Use conf-* for configuration. +- +-SHELL=/bin/sh +- + default: it + ++ + alloc.a: \ + makelib alloc.o alloc_re.o getln.o getln2.o stralloc_cat.o \ + stralloc_catb.o stralloc_cats.o stralloc_copy.o stralloc_eady.o \ +@@ -55,8 +52,8 @@ + prot.o timeoutread.o timeoutwrite.o dns.a libtai.a alloc.a env.a \ + cdb.a buffer.a unix.a byte.a + ./load axfrdns iopause.o droproot.o tdlookup.o response.o \ +- qlog.o prot.o timeoutread.o timeoutwrite.o dns.a libtai.a \ +- alloc.a env.a cdb.a buffer.a unix.a byte.a ++ qlog.o prot.o timeoutread.o timeoutwrite.o askldap.o dns.a libtai.a \ ++ alloc.a env.a cdb.a buffer.a unix.a byte.a `cat ldap.lib` + + axfrdns-conf: \ + load axfrdns-conf.o generic-conf.o auto_home.o buffer.a unix.a byte.a +@@ -626,11 +623,11 @@ + ./compile parsetype.c + + pickdns: \ +-load pickdns.o server.o response.o droproot.o qlog.o prot.o dns.a \ ++load pickdns.o server.o response.o droproot.o qlog.o prot.o askldap.o dns.a \ + env.a libtai.a cdb.a alloc.a buffer.a unix.a byte.a socket.lib + ./load pickdns server.o response.o droproot.o qlog.o \ +- prot.o dns.a env.a libtai.a cdb.a alloc.a buffer.a unix.a \ +- byte.a `cat socket.lib` ++ prot.o askldap.o dns.a env.a libtai.a cdb.a alloc.a buffer.a unix.a \ ++ byte.a `cat socket.lib` `cat ldap.lib` + + pickdns-conf: \ + load pickdns-conf.o generic-conf.o auto_home.o buffer.a unix.a byte.a +@@ -704,11 +701,11 @@ + ./compile random-ip.c + + rbldns: \ +-load rbldns.o server.o response.o dd.o droproot.o qlog.o prot.o dns.a \ ++load rbldns.o server.o response.o dd.o droproot.o qlog.o prot.o askldap.o dns.a \ + env.a libtai.a cdb.a alloc.a buffer.a unix.a byte.a socket.lib + ./load rbldns server.o response.o dd.o droproot.o qlog.o \ +- prot.o dns.a env.a libtai.a cdb.a alloc.a buffer.a unix.a \ +- byte.a `cat socket.lib` ++ prot.o askldap.o dns.a env.a libtai.a cdb.a alloc.a buffer.a unix.a \ ++ byte.a `cat socket.lib` `cat ldap.lib` + + rbldns-conf: \ + load rbldns-conf.o generic-conf.o auto_home.o buffer.a unix.a byte.a +@@ -792,6 +789,9 @@ + && echo -lsocket -lnsl || exit 0 ) > socket.lib + rm -f trylsock.o trylsock + ++ldap.lib: ++ echo -lldap -llber > ldap.lib ++ + socket_accept.o: \ + compile socket_accept.c byte.h socket.h uint16.h + ./compile socket_accept.c +@@ -978,13 +978,17 @@ + timeoutwrite.h + ./compile timeoutwrite.c + ++askldap.o: \ ++compile askldap.c askldap.h ++ ./compile askldap.c ++ + tinydns: \ + load tinydns.o server.o droproot.o tdlookup.o response.o qlog.o \ +-prot.o dns.a libtai.a env.a cdb.a alloc.a buffer.a unix.a byte.a \ +-socket.lib ++prot.o askldap.o dns.a libtai.a env.a cdb.a alloc.a buffer.a unix.a byte.a \ ++socket.lib ldap.lib + ./load tinydns server.o droproot.o tdlookup.o response.o \ +- qlog.o prot.o dns.a libtai.a env.a cdb.a alloc.a buffer.a \ +- unix.a byte.a `cat socket.lib` ++ qlog.o prot.o askldap.o dns.a libtai.a env.a cdb.a alloc.a buffer.a \ ++ unix.a byte.a `cat socket.lib` `cat ldap.lib` + + tinydns-conf: \ + load tinydns-conf.o generic-conf.o auto_home.o buffer.a unix.a byte.a +@@ -1015,26 +1019,26 @@ + tinydns-edit.o: \ + compile tinydns-edit.c stralloc.h gen_alloc.h buffer.h exit.h open.h \ + getln.h buffer.h stralloc.h strerr.h scan.h byte.h str.h fmt.h ip4.h \ +-dns.h stralloc.h iopause.h taia.h tai.h uint64.h taia.h ++dns.h stralloc.h iopause.h taia.h tai.h uint64.h taia.h askldap.h + ./compile tinydns-edit.c + + tinydns-get: \ + load tinydns-get.o tdlookup.o response.o printpacket.o printrecord.o \ + parsetype.o dns.a libtai.a cdb.a buffer.a alloc.a unix.a byte.a + ./load tinydns-get tdlookup.o response.o printpacket.o \ +- printrecord.o parsetype.o dns.a libtai.a cdb.a buffer.a \ +- alloc.a unix.a byte.a ++ printrecord.o parsetype.o askldap.o dns.a libtai.a cdb.a buffer.a \ ++ alloc.a unix.a byte.a `cat ldap.lib` + + tinydns-get.o: \ + compile tinydns-get.c str.h byte.h scan.h exit.h stralloc.h \ + gen_alloc.h buffer.h strerr.h uint16.h response.h uint32.h case.h \ + printpacket.h stralloc.h parsetype.h ip4.h dns.h stralloc.h iopause.h \ +-taia.h tai.h uint64.h taia.h ++taia.h tai.h uint64.h taia.h askldap.h + ./compile tinydns-get.c + + tinydns.o: \ + compile tinydns.c dns.h stralloc.h gen_alloc.h iopause.h taia.h tai.h \ +-uint64.h taia.h ++uint64.h taia.h askldap.h + ./compile tinydns.c + + uint16_pack.o: \ +@@ -1084,11 +1088,11 @@ + ./compile utime.c + + walldns: \ +-load walldns.o server.o response.o droproot.o qlog.o prot.o dd.o \ ++load walldns.o server.o response.o droproot.o qlog.o prot.o dd.o askldap.o \ + dns.a env.a cdb.a alloc.a buffer.a unix.a byte.a socket.lib + ./load walldns server.o response.o droproot.o qlog.o \ +- prot.o dd.o dns.a env.a cdb.a alloc.a buffer.a unix.a \ +- byte.a `cat socket.lib` ++ prot.o dd.o askldap.o dns.a env.a cdb.a alloc.a buffer.a unix.a \ ++ byte.a `cat socket.lib` `cat ldap.lib` + + walldns-conf: \ + load walldns-conf.o generic-conf.o auto_home.o buffer.a unix.a byte.a +diff -Naur djbdns-1.05.orig/askldap.c djbdns-1.05/askldap.c +--- djbdns-1.05.orig/askldap.c Thu Jan 1 01:00:00 1970 ++++ djbdns-1.05/askldap.c Tue Aug 13 14:30:18 2002 +@@ -0,0 +1,750 @@ ++/* Patch for tinydns to pass DNS-query to LDAP in favour of a cdb lookup. ++ * $Id$ ++ * Copyright 2002 ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "alloc.h" ++#include "byte.h" ++#include "response.h" ++#include "askldap.h" ++#include "dns.h" ++ ++static LDAP* ldap_con; ++static sigjmp_buf stack_context; ++ ++static struct { ++ char ldaphosts[256]; ++ const char* basedn; ++ char binddn[256]; ++ char bindpwd[16]; ++ struct timeval timeout; ++ int verbose; ++ int initialized; ++} options; ++ ++struct zonerecord { ++ char zonedn[256]; ++ char zonename[64]; ++ char class[16]; ++ char type[16]; ++ char adminmailbox[64]; ++ char zonemaster[64]; ++ unsigned long serial, refresh, retry, expire, minimum; ++ int ttl; ++ int timestamp; ++}; ++ ++struct resourcerecord { ++ char qualifieddomainname[256]; ++ char class[16]; ++ char type[16]; ++ char ipaddr[8][4]; ++ int numipaddrs; ++ char cname[256]; ++ unsigned int preference; ++ int ttl; ++ int timestamp; ++ int additionalinfo; ++ struct resourcerecord* next; ++}; ++ ++enum { ASKLDAP_RETRY = 1, ASKLDAP_RETURN = 2, ASKLDAP_RECONNECT = 3 }; ++ ++static ++void assert_ldap(int err) ++{ ++ static int retries; ++ switch (err) { ++ case LDAP_SUCCESS: ++ return; ++ case LDAP_TIMELIMIT_EXCEEDED: ++ fprintf(stderr, "Warning: %s\n", ldap_err2string(err)); ++ retries++; ++ if (retries<3) ++ siglongjmp(stack_context, ASKLDAP_RETRY); ++ retries = 0; ++ siglongjmp(stack_context, ASKLDAP_RETURN); ++ case LDAP_TIMEOUT: ++ case LDAP_NO_SUCH_OBJECT: ++ fprintf(stderr, "Warning: %s\n", ldap_err2string(err)); ++ siglongjmp(stack_context, ASKLDAP_RETURN); ++ case LDAP_BUSY: ++ case LDAP_UNAVAILABLE: ++ case LDAP_UNWILLING_TO_PERFORM: ++ case LDAP_SERVER_DOWN: ++ fprintf(stderr, "Warning: %s\n", ldap_err2string(err)); ++ siglongjmp(stack_context, ASKLDAP_RECONNECT); ++ default: ++ fprintf(stderr, "Fatal error: %s\n", ldap_err2string(err)); ++#ifdef _DEBUG ++ abort(); ++#else ++ exit(1); ++#endif ++ } ++} ++ ++void free_domainrecords(struct resourcerecord* anchor) ++{ ++ struct resourcerecord* ptr; ++ for (ptr = anchor; ptr; ptr = anchor) { ++ anchor = anchor->next; ++ alloc_free(ptr); ++ } ++} ++ ++static ++void fill_resourcerecord(struct resourcerecord* rr, LDAPMessage* m, const char* zonename) ++{ ++ BerElement* ber = NULL; ++ char* attr; ++ ++ byte_zero(rr, sizeof(struct resourcerecord)); ++ strcpy(rr->class, "IN"); ++ for (attr = ldap_first_attribute(ldap_con, m, &ber); attr; attr = ldap_next_attribute(ldap_con, m, ber)) { ++ struct berval** bvals = ldap_get_values_len(ldap_con, m, attr); ++ if (bvals && bvals[0] && bvals[0]->bv_len>0) { ++ if (strcasecmp(attr, "dnsdomainname")==0) { ++ char tmp[64]; ++ if (sscanf(bvals[0]->bv_val, "%64s", tmp)==1) { ++ if (zonename[0]!='\0') ++ snprintf(rr->qualifieddomainname, 256, "%s.%s", tmp, zonename); ++ else ++ strncpy(rr->qualifieddomainname, tmp, 256); ++ } ++ } else if (strcasecmp(attr, "dnstype")==0) { ++ if (sscanf(bvals[0]->bv_val, "%16s", rr->type)!=1) { ++ rr->type[0] = '\0'; ++ } ++ } else if (strcasecmp(attr, "dnsipaddr")==0) { ++ int k, ip[4]; ++ for (k = 0; bvals[k] && k < 8-rr->numipaddrs; k++) { ++ if (sscanf(bvals[k]->bv_val, "%d.%d.%d.%d", &ip[0], &ip[1], &ip[2], &ip[3])==4) { ++ rr->ipaddr[rr->numipaddrs][0] = (char)ip[0]; ++ rr->ipaddr[rr->numipaddrs][1] = (char)ip[1]; ++ rr->ipaddr[rr->numipaddrs][2] = (char)ip[2]; ++ rr->ipaddr[rr->numipaddrs][3] = (char)ip[3]; ++ rr->numipaddrs++; ++ } ++ } ++ } else if (rr->numipaddrs<8 && strcasecmp(attr, "dnscipaddr")==0) { ++ int ip[4]; ++ if (sscanf(bvals[0]->bv_val, "%d.%d.%d.%d", &ip[0], &ip[1], &ip[2], &ip[3])==4) { ++ rr->ipaddr[rr->numipaddrs][0] = (char)ip[0]; ++ rr->ipaddr[rr->numipaddrs][1] = (char)ip[1]; ++ rr->ipaddr[rr->numipaddrs][2] = (char)ip[2]; ++ rr->ipaddr[rr->numipaddrs][3] = (char)ip[3]; ++ rr->numipaddrs++; ++ } ++ } else if (strcasecmp(attr, "dnscname")==0) { ++ if (sscanf(bvals[0]->bv_val, "%256s", rr->cname)==1) { ++ int len = strlen(rr->cname); ++ if (rr->cname[len-1]!='.' && zonename[0]!='\0') { ++ strcat(rr->cname, "."); ++ strncat(rr->cname, zonename, 252-len); ++ strcat(rr->cname, "."); ++ } ++ } else { ++ rr->cname[0] = '\0'; ++ } ++ } else if (strcasecmp(attr, "dnsttl")==0) { ++ if (sscanf(bvals[0]->bv_val, "%d", &rr->ttl)!=1) ++ rr->ttl = 0; ++ } else if (strcasecmp(attr, "dnstimestamp")==0) { ++ if (sscanf(bvals[0]->bv_val, "%d", &rr->timestamp)!=1) ++ rr->timestamp = 0; ++ } else if (strcasecmp(attr, "dnspreference")==0) { ++ if (sscanf(bvals[0]->bv_val, "%u", &rr->preference)!=1) ++ rr->preference = 1; ++ } ++ } ++ ldap_value_free_len(bvals); ++ } ++} ++ ++static ++void fill_zonerecord(struct zonerecord* zone, LDAPMessage* m) ++{ ++ BerElement* ber = NULL; ++ char* attr; ++ ++ byte_zero(zone, sizeof(struct zonerecord)); ++ strcpy(zone->class, "IN"); ++ for (attr = ldap_first_attribute(ldap_con, m, &ber); attr; attr = ldap_next_attribute(ldap_con, m, ber)) { ++ struct berval** bvals = ldap_get_values_len(ldap_con, m, attr); ++ if (bvals && bvals[0] && bvals[0]->bv_len>0) { ++ if (strcasecmp(attr, "dnstype")==0) { ++ if (sscanf(bvals[0]->bv_val, "%16s", zone->type)!=1) ++ zone->type[0] = '\0'; ++ } else if (strcasecmp(attr, "dnsserial")==0) { ++ if (sscanf(bvals[0]->bv_val, "%lu", &zone->serial)!=1) ++ zone->serial = 0; ++ } else if (strcasecmp(attr, "dnsrefresh")==0) { ++ if (sscanf(bvals[0]->bv_val, "%lu", &zone->refresh)!=1) ++ zone->refresh = 0; ++ } else if (strcasecmp(attr, "dnsretry")==0) { ++ if (sscanf(bvals[0]->bv_val, "%lu", &zone->retry)!=1) ++ zone->retry = 0; ++ } else if (strcasecmp(attr, "dnsexpire")==0) { ++ if (sscanf(bvals[0]->bv_val, "%lu", &zone->expire)!=1) ++ zone->expire = 0; ++ } else if (strcasecmp(attr, "dnsminimum")==0) { ++ if (sscanf(bvals[0]->bv_val, "%lu", &zone->minimum)!=1) ++ zone->minimum = 0; ++ } else if (strcasecmp(attr, "dnsadminmailbox")==0) { ++ if (sscanf(bvals[0]->bv_val, "%64s", zone->adminmailbox)!=1) ++ zone->adminmailbox[0] = '\0'; ++ } else if (strcasecmp(attr, "dnszonemaster")==0) { ++ if (sscanf(bvals[0]->bv_val, "%64s", zone->zonemaster)!=1) ++ zone->zonemaster[0] = '\0'; ++ } else if (strcasecmp(attr, "dnsttl")==0) { ++ if (sscanf(bvals[0]->bv_val, "%d", &zone->ttl)!=1) ++ zone->ttl = 0; ++ } else if (strcasecmp(attr, "dnstimestamp")==0) { ++ if (sscanf(bvals[0]->bv_val, "%d", &zone->timestamp)!=1) ++ zone->timestamp = 0; ++ } else if (strcasecmp(attr, "dnszonename")==0) { ++ if (sscanf(bvals[0]->bv_val, "%s", zone->zonename)!=1) ++ zone->zonename[0] = '\0'; ++ } ++ } ++ ldap_value_free_len(bvals); ++ } ++} ++ ++static ++int find_ipaddr(const char* queryname, char ip[4]) ++{ ++ static char *rrattrs[] = { "dnsipaddr", "dnscipaddr", 0 }; ++ LDAPMessage* res = NULL; ++ LDAPMessage* m; ++ int ret = 0; ++ char filter[256], domainname[64]; ++ const char *zonename = queryname; ++ domainname[0] = '\0'; ++ while (*zonename) { ++ int len = snprintf(filter, 256, "(&(dnszonename=%s", zonename); ++ if (filter[len-1]=='.') ++ filter[len-1] = '\0'; ++ strncat(filter, ")(objectclass=dnszone)(dnsclass=IN))", 256-len); ++ assert_ldap(ldap_search_st(ldap_con, options.basedn, LDAP_SCOPE_SUBTREE, filter, rrattrs, 0, &options.timeout, &res)); ++ if (m = ldap_first_entry(ldap_con, res)) { ++ char* zonedn = ldap_get_dn(ldap_con, m); ++ if (ldap_next_entry(ldap_con, m)) ++ printf("Warning: ambigous zonename for %s in %s\n", zonename, zonedn); ++ if (domainname[0]!='\0') { ++ len = strlen(domainname); ++ if (domainname[len-1]=='.') ++ domainname[len-1] = '\0'; ++ snprintf(filter, 256, "(&(|(dnsdomainname=%s)(dnscname=%s))(objectclass=dnsrrset)(dnsclass=IN)(|(dnsipaddr=*)(dnscipaddr=*)))", domainname, domainname); ++ } else { ++ strcpy(filter, "(&(!(dnsdomainname=*))(objectclass=dnsrrset)(dnsclass=IN)(|(dnsipaddr=*)(dnscipaddr=*)))"); ++ } ++ ldap_msgfree(res); ++ assert_ldap(ldap_search_st(ldap_con, zonedn, LDAP_SCOPE_SUBTREE, filter, rrattrs, 0, &options.timeout, &res)); ++ if (m = ldap_first_entry(ldap_con, res)) { ++ struct resourcerecord rr; ++ fill_resourcerecord(&rr, m, ""); ++ if (rr.numipaddrs>0) { ++ rr.numipaddrs = rand()%rr.numipaddrs; ++ ip[0] = rr.ipaddr[rr.numipaddrs][0]; ++ ip[1] = rr.ipaddr[rr.numipaddrs][1]; ++ ip[2] = rr.ipaddr[rr.numipaddrs][2]; ++ ip[3] = rr.ipaddr[rr.numipaddrs][3]; ++ ret = 1; ++ } ++ } ++ ldap_memfree(zonedn); ++ ldap_msgfree(res); res = NULL; ++ if (ret) ++ return 1; ++ break; ++ } ++ while (*zonename && *zonename!='.') { ++ domainname[zonename-queryname] = *zonename; ++ zonename++; ++ } ++ domainname[zonename-queryname] = *zonename; ++ if (*zonename=='.') { ++ zonename++; ++ domainname[zonename-queryname] = '\0'; ++ } ++ } ++ /* sometimes the queryname resolves directly as cname in some other records */ ++ snprintf(filter, 256, "(&(dnscname=%s)(objectclass=dnsrrset)(dnsclass=IN)(|(dnsipaddr=*)(dnscipaddr=*)))", queryname); ++ assert_ldap(ldap_search_st(ldap_con, options.basedn, LDAP_SCOPE_SUBTREE, filter, rrattrs, 0, &options.timeout, &res)); ++ if (m = ldap_first_entry(ldap_con, res)) { ++ struct resourcerecord rr; ++ fill_resourcerecord(&rr, m, ""); ++ if (rr.numipaddrs>0) { ++ rr.numipaddrs = rand()%rr.numipaddrs; ++ ip[0] = rr.ipaddr[rr.numipaddrs][0]; ++ ip[1] = rr.ipaddr[rr.numipaddrs][1]; ++ ip[2] = rr.ipaddr[rr.numipaddrs][2]; ++ ip[3] = rr.ipaddr[rr.numipaddrs][3]; ++ ret = 1; ++ } ++ } ++ ldap_msgfree(res); ++ return ret; ++} ++ ++static ++struct resourcerecord* find_reverserecord(const char* queryname, int ip[4]) ++{ ++ static char *rrattrs[] = { "dnstype", "dnsdomainname", "dnscname", "dnsttl", 0 }; ++ LDAPMessage* res = NULL; ++ struct resourcerecord* rr = NULL; ++ LDAPMessage* m; ++ char filter[256]; ++ snprintf(filter, 256, "(&(dnscipaddr=%u.%u.%u.%u)(objectclass=dnsrrset)(dnsclass=IN))", ip[0], ip[1], ip[2], ip[3]); ++ assert_ldap(ldap_search_st(ldap_con, options.basedn, LDAP_SCOPE_SUBTREE, filter, rrattrs, 0, &options.timeout, &res)); ++ if (m = ldap_first_entry(ldap_con, res)) { ++ char* rrsetdn = ldap_get_dn(ldap_con, m); ++ char** explodedn = NULL; ++ ++ rr = (void*)alloc(sizeof(struct resourcerecord)); ++ fill_resourcerecord(rr, m, ""); ++ if (ldap_next_entry(ldap_con, m)) ++ printf("Warning: ambigous IP-address for %u.%u.%u.%u in dn: %s\n", ip[0], ip[1], ip[2], ip[3], rrsetdn); ++ explodedn = ldap_explode_dn(rrsetdn, 0); ++ if (explodedn[0]) { ++ static char *zoneattrs[] = { "dnszonename", 0 }; ++ char zonedn[256]; ++ int i, len = 0; ++ struct zonerecord zone; ++ ++ zonedn[0] = '\0'; ++ for (i = 1; explodedn[i]; i++) ++ len += snprintf(zonedn+len, 256-len, "%s,", explodedn[i]); ++ zonedn[len-1] = '\0'; ++ ldap_msgfree(res); ++ assert_ldap(ldap_search_st(ldap_con, zonedn, LDAP_SCOPE_SUBTREE, "(objectclass=dnszone)", zoneattrs, 0, &options.timeout, &res)); ++ m = ldap_first_entry(ldap_con, res); ++ if (m==NULL) ++ printf("Error: parent dn: %s not found for %s\n", zonedn, rrsetdn); ++ fill_zonerecord(&zone, m); ++ len = strlen(rr->qualifieddomainname); ++ if (len==0) { ++ len = strlen(rr->cname); ++ if (rr->cname[len-1]!='.') { ++ strcat(rr->cname, "."); ++ strncat(rr->cname, zone.zonename, 252-len); ++ } ++ } else { ++ /* in those situations where a dnsrrset ++ * defines something like MX or NS for a zone ++ * and also sets a canonical name for the ++ * service. */ ++ snprintf(rr->cname, 256, "%s.%s", rr->qualifieddomainname, zone.zonename); ++ } ++ strcpy(rr->type, "PTR"); ++ strncpy(rr->qualifieddomainname, queryname, 256); ++ } ++ ldap_memfree(rrsetdn); ++ ldap_value_free(explodedn); ++ } ++ ldap_msgfree(res); ++ return rr; ++} ++ ++static ++struct resourcerecord* read_domainrecords(const char* zonedn, const char* domainname, const char* zonename) ++{ ++ static char *rrattrs[] = { "dnsdomainname", "dnstype", "dnsttl", "dnscname", "dnsipaddr", "dnscipaddr", "dnstimestamp", "dnspreference", 0 }; ++ LDAPMessage* res = NULL; ++ LDAPMessage* m; ++ char filter[256]; ++ struct resourcerecord *prev, *anchor = NULL; ++ ++ if (domainname[0]) { ++ if (strstr(zonename, "in-addr.arpa")) { ++ unsigned int ip[4]; ++ char queryname[256]; ++ snprintf(queryname, 256, "%s.%s", domainname, zonename); ++ if (sscanf(queryname, "%3u.%3u.%3u.%3u", &ip[3], &ip[2], &ip[1], &ip[0])!=4) ++ return NULL; ++ snprintf(filter, 256, "(&(dnsipaddr=%u.%u.%u.%u)(objectclass=dnsrrset)(dnsclass=IN))", ip[0], ip[1], ip[2], ip[3]); ++ assert_ldap(ldap_search_st(ldap_con, zonedn, LDAP_SCOPE_SUBTREE, filter, rrattrs, 0, &options.timeout, &res)); ++ if (m = ldap_first_entry(ldap_con, res)) { ++ struct resourcerecord* rr; ++ rr = (void*)alloc(sizeof(struct resourcerecord)); ++ fill_resourcerecord(rr, m, zonename); ++ strncpy(rr->qualifieddomainname, queryname, 256); ++ ldap_msgfree(res); ++ return rr; ++ } else { ++ /* ipaddr not in our baliwick, search the whole tree for canonical ipaddr */ ++ ldap_msgfree(res); ++ return find_reverserecord(queryname, ip); ++ } ++ } else { ++ int i; ++ for (i = 0; domainname[i]; i++) { ++ snprintf(filter, 256, (i==0 ? "(&(dnsdomainname=%s)(objectclass=dnsrrset)(dnsclass=IN))" : ++ "(&(dnsdomainname=\\*.%s)(objectclass=dnsrrset)(dnsclass=IN))"), &domainname[i]); ++ assert_ldap(ldap_search_st(ldap_con, zonedn, LDAP_SCOPE_SUBTREE, filter, rrattrs, 0, &options.timeout, &res)); ++ if (ldap_count_entries(ldap_con, res)>0) ++ break; ++ while (domainname[i] && domainname[i]!='.') ++ i++; ++ } ++ } ++ } else { ++ snprintf(filter, 256, "(&(!(dnsdomainname=*))(objectclass=dnsrrset)(dnsclass=IN))"); ++ assert_ldap(ldap_search_st(ldap_con, zonedn, LDAP_SCOPE_SUBTREE, filter, rrattrs, 0, &options.timeout, &res)); ++ } ++ for (m = ldap_first_entry(ldap_con, res); m; m = ldap_next_entry(ldap_con, m)) { ++ struct resourcerecord* rr; ++ rr = (void*)alloc(sizeof(struct resourcerecord)); ++ fill_resourcerecord(rr, m, zonename); ++ snprintf(rr->qualifieddomainname, 256, "%s%s%s", domainname, domainname[0] ? "." : "", zonename); ++ if (anchor==NULL) { ++ prev = anchor = rr; ++ } else { ++ prev->next = rr; ++ prev = rr; ++ } ++ if (options.verbose&1) ++ printf("\trr: %s %s\n", domainname, rr->type); ++ } ++ ldap_msgfree(res); ++ return anchor; ++} ++ ++static ++int read_dnszone(struct zonerecord* zone, const char* zonename) ++{ ++ static char *zoneattrs[] = { "dnszonename", "dnstype", "dnsserial", "dnsrefresh", "dnsretry", "dnsexpire", "dnsminimum", "dnszonemaster", "dnsadminmailbox", "dnsttl", "dnstimestamp", 0 }; ++ LDAPMessage* res = NULL; ++ LDAPMessage* m; ++ char* dn; ++ char filter[256]; ++ ++ snprintf(filter, 256, "(&(dnszonename=%s)(objectclass=dnszone)(dnsclass=IN))", zonename); ++ assert_ldap(ldap_search_st(ldap_con, options.basedn, LDAP_SCOPE_SUBTREE, filter, zoneattrs, 0, &options.timeout, &res)); ++ m = ldap_first_entry(ldap_con, res); ++ if (m==NULL) { ++ ldap_msgfree(res); ++ return 0; ++ } ++ dn = ldap_get_dn(ldap_con, m); ++ fill_zonerecord(zone, m); ++ m = ldap_next_entry(ldap_con, m); ++ if (m) { ++ char* otherdn = ldap_get_dn(ldap_con, m); ++ printf("Warning: ambigous zonename found in dn: %s and dn: %s\n", dn, otherdn); ++ ldap_memfree(otherdn); ++ } ++ strncpy(zone->zonedn, dn, 256); ++ ldap_memfree(dn); ++ ldap_msgfree(res); ++ return 1; ++} ++ ++static ++void djb_name(const char* dotname, char* djbname) ++{ ++ const char* c = dotname; ++ int i, k; ++ for (i = 0; *c; c++) { ++ k = i; ++ while (*c!='.') { ++ k++; ++ djbname[k] = *c; ++ if (*c=='\0') { ++ djbname[i] = k-i-1; ++ return; ++ } ++ c++; ++ } ++ djbname[i] = k-i; ++ i = k+1; ++ } ++ djbname[i] = '\0'; ++} ++ ++static ++void djb_type(const char* dottype, char djbtype[2]) ++{ ++ djbtype[0] = '\0'; ++ if (strcasecmp(dottype, "A")==0) ++ djbtype[1] = 001; ++ else if (strcasecmp(dottype, "NS")==0) ++ djbtype[1] = 002; ++ else if (strcasecmp(dottype, "CNAME")==0) ++ djbtype[1] = 005; ++ else if (strcasecmp(dottype, "SOA")==0) ++ djbtype[1] = 006; ++ else if (strcasecmp(dottype, "PTR")==0) ++ djbtype[1] = 014; ++ else if (strcasecmp(dottype, "MX")==0) ++ djbtype[1] = 017; ++ else if (strcasecmp(dottype, "TXT")==0) ++ djbtype[1] = 020; ++} ++ ++static ++void split_djbstyle(const char* djbname, char* domainname, char* zonename, int offset) ++{ ++ int i, k, m = 0, n = 0; ++ for (i = *djbname; i; i = *++djbname) { ++ if (offset>0) { ++ offset--; ++ for (k = m; k0 ? m-1 : 0] = '\0'; ++ zonename[n>0 ? n-1 : 0] = '\0'; ++} ++ ++static ++void build_response_section(struct resourcerecord *rr, char qtype[2], int section) ++{ ++ char djbname[256], djbtype[2]; ++ djb_name(rr->qualifieddomainname, djbname); ++ djb_type(rr->type, djbtype); ++ if (byte_equal(djbtype, 2, DNS_T_A)) { ++ if (byte_equal(qtype, 2, DNS_T_A) || byte_equal(qtype, 2, DNS_T_ANY)) { ++ response_rstart(djbname, djbtype, rr->ttl); ++ response_addbytes(rr->ipaddr[rand()%rr->numipaddrs], 4); ++ response_rfinish(section); ++ } ++ } else if (byte_equal(djbtype, 2, DNS_T_CNAME)) { ++ response_rstart(djbname, djbtype, rr->ttl); ++ djb_name(rr->cname, djbname); ++ response_addname(djbname); ++ response_rfinish(section); ++ } else if (byte_equal(djbtype, 2, DNS_T_NS)) { ++ if (byte_equal(qtype, 2, DNS_T_NS) || byte_equal(qtype, 2, DNS_T_ANY)) { ++ response_rstart(djbname, djbtype, rr->ttl); ++ if (rr->cname[0]) { ++ djb_name(rr->cname, djbname); ++ response_addname(djbname); ++ rr->additionalinfo = 1; ++ } else { ++ response_addbytes(rr->ipaddr[rand()%rr->numipaddrs], 4); ++ } ++ response_rfinish(section); ++ } ++ } else if (byte_equal(djbtype, 2, DNS_T_PTR)) { ++ response_rstart(djbname, djbtype, rr->ttl); ++ djb_name(rr->cname, djbname); ++ response_addname(djbname); ++ response_rfinish(section); ++ } else if (byte_equal(djbtype, 2, DNS_T_MX)) { ++ if (byte_equal(qtype, 2, DNS_T_MX) || byte_equal(qtype, 2, DNS_T_ANY)) { ++ char tmp[2]; ++ response_rstart(djbname, djbtype, rr->ttl); ++ tmp[0] = rr->preference/0x100; ++ tmp[1] = rr->preference%0x100; ++ response_addbytes(tmp, 2); ++ if (rr->cname[0]) { ++ djb_name(rr->cname, djbname); ++ response_addname(djbname); ++ rr->additionalinfo = 1; ++ } else { ++ response_addbytes(rr->ipaddr[rand()%rr->numipaddrs], 4); ++ } ++ response_rfinish(section); ++ } ++ } ++} ++ ++static ++void build_soa_section(struct zonerecord *zone, int section) ++{ ++ time_t now; ++ char defaultsoa[20]; ++ char djbname[256]; ++ char zonesoa[20]; ++ unsigned long tmp; ++ time(&now); ++ djb_name(zone->zonename, djbname); ++ response_rstart(djbname, DNS_T_SOA, zone->ttl); ++ djb_name(zone->zonemaster, djbname); ++ response_addname(djbname); ++ djb_name(zone->adminmailbox, djbname); ++ response_addname(djbname); ++ uint32_pack_big(defaultsoa, now); ++ if (byte_equal(defaultsoa,4,"\0\0\0\0")) ++ defaultsoa[3] = 1; ++ byte_copy(defaultsoa + 4, 16, "\0\0\100\000\0\0\010\000\0\020\000\000\0\0\012\000"); ++ if (zone->serial==0) ++ uint32_unpack_big(defaultsoa, &tmp); ++ else ++ tmp = zone->serial; ++ uint32_pack_big(zonesoa, tmp); ++ if (zone->refresh==0) ++ uint32_unpack_big(defaultsoa+4, &tmp); ++ else ++ tmp = zone->refresh; ++ uint32_pack_big(zonesoa+4, tmp); ++ if (zone->retry==0) ++ uint32_unpack_big(defaultsoa+8, &tmp); ++ else ++ tmp = zone->retry; ++ uint32_pack_big(zonesoa+8, tmp); ++ if (zone->expire==0) ++ uint32_unpack_big(defaultsoa+12, &tmp); ++ else ++ tmp = zone->expire; ++ uint32_pack_big(zonesoa+12, tmp); ++ if (zone->minimum==0) ++ uint32_unpack_big(defaultsoa+16, &tmp); ++ else ++ tmp = zone->minimum; ++ uint32_pack_big(zonesoa+16, tmp); ++ response_addbytes(zonesoa, 20); ++ response_rfinish(section); ++} ++ ++static ++void build_additional_section(struct resourcerecord *rr) ++{ ++ char djbname[256], ip[4]; ++ if (rr->additionalinfo && find_ipaddr(rr->cname, ip)) { ++ djb_name(rr->cname, djbname); ++ response_rstart(djbname, DNS_T_A, rr->ttl); ++ response_addbytes(ip, 4); ++ response_rfinish(RESPONSE_ADDITIONAL); ++ } ++} ++ ++static ++int connect_and_bind() ++{ ++ ldap_con = ldap_init(options.ldaphosts, LDAP_PORT); ++ if (ldap_simple_bind_s(ldap_con, options.binddn, options.bindpwd)==LDAP_SUCCESS) { ++ printf("Connected to %s as \"%s\"\n", options.ldaphosts, options.binddn); ++ return 1; ++ } ++ ldap_con = NULL; ++ return 0; ++} ++ ++int askldap_query(const char* djbdomainname, char qtype[2]) ++{ ++ int offset; ++ char domainname[64], zonename[64]; ++ struct zonerecord zoneinfo; ++ int answer_ok = 0, flagsoa = 0, flagns = 0; ++ if (!options.initialized) ++ return 0; ++ switch (sigsetjmp(stack_context, 1)) { ++ default: ++ if (ldap_con==NULL && !connect_and_bind()) ++ return answer_ok; ++ break; ++ case ASKLDAP_RECONNECT: ++ if (connect_and_bind()) ++ break; ++ return answer_ok; ++ case ASKLDAP_RETURN: ++ return answer_ok; ++ } ++ for (offset = 0; offset<32; offset++) { ++ struct resourcerecord *rransw, *rrauth, *rr; ++ ++ split_djbstyle(djbdomainname, domainname, zonename, offset); ++ if (zonename[0]=='\0') return 0; ++ if (!read_dnszone(&zoneinfo, zonename)) ++ continue; ++ rransw = read_domainrecords(zoneinfo.zonedn, domainname, zonename); ++ rrauth = NULL; ++ if (offset==0) { ++ /* query is in our bailiwick */ ++ if (byte_equal(qtype, 2, DNS_T_ANY) || byte_equal(qtype, 2, DNS_T_SOA)) { ++ build_soa_section(&zoneinfo, RESPONSE_ANSWER); ++ flagsoa = 1; ++ } ++ for (rr = rransw; rr; rr = rr->next) { ++ build_response_section(rr, qtype, RESPONSE_ANSWER); ++ answer_ok = 1; ++ } ++ if (!flagsoa) { ++ build_soa_section(&zoneinfo, RESPONSE_AUTHORITY); ++ flagsoa = 1; ++ } ++ if (!byte_equal(qtype, 2, DNS_T_ANY) && !byte_equal(qtype, 2, DNS_T_NS)) { ++ for (rr = rransw; rr; rr = rr->next) ++ if (strcmp(rr->type, "NS")==0) { ++ build_response_section(rr, DNS_T_NS, RESPONSE_AUTHORITY); ++ flagns = 1; ++ } ++ } ++ } else { ++ for (rr = rransw; rr; rr = rr->next) { ++ if (strcmp(rr->type, "NS")==0) { ++ build_response_section(rr, qtype, RESPONSE_AUTHORITY); ++ flagns = 1; ++ } ++ } ++ if (!flagns) { ++ for (rr = rransw; rr; rr = rr->next) { ++ build_response_section(rr, qtype, RESPONSE_ANSWER); ++ answer_ok = 1; ++ } ++ if (answer_ok) { ++ rrauth = read_domainrecords(zoneinfo.zonedn, "", zonename); ++ } else { ++ build_soa_section(&zoneinfo, RESPONSE_AUTHORITY); ++ flagsoa = 1; ++ } ++ } ++ for (rr = rrauth; rr; rr = rr->next) { ++ if (strcmp(rr->type, "NS")==0) { ++ build_response_section(rr, DNS_T_NS, RESPONSE_AUTHORITY); ++ flagns = 1; ++ } ++ } ++ } ++ for (rr = rransw; rr; rr = rr->next) ++ build_additional_section(rr); ++ for (rr = rrauth; rr; rr = rr->next) ++ build_additional_section(rr); ++ free_domainrecords(rransw); ++ free_domainrecords(rrauth); ++ break; ++ } ++ return answer_ok || flagsoa || flagns; ++} ++ ++void askldap_init(const char* ldaphost, const char* basedn, const char* binddn, const char* passwd) ++{ ++ strncpy(options.ldaphosts, ldaphost, 256); ++ options.basedn = basedn; ++ if (binddn) strncpy(options.binddn, binddn, 256); ++ if (passwd) strncpy(options.bindpwd, passwd, 16); ++ /* LDAP timeout is hardcoded to 2/10 second. ++ * This must be enough because bindoperations usually ++ * timeout after one second and here we usually have to ++ * send five queries to the LDAP-server */ ++ options.timeout.tv_sec = 1; ++ options.timeout.tv_usec = 200000; ++ options.verbose = 0; ++ options.initialized = 1; ++ connect_and_bind(); ++} ++ +diff -Naur djbdns-1.05.orig/askldap.h djbdns-1.05/askldap.h +--- djbdns-1.05.orig/askldap.h Thu Jan 1 01:00:00 1970 ++++ djbdns-1.05/askldap.h Tue Aug 13 14:30:22 2002 +@@ -0,0 +1,10 @@ ++/* Patch for tinydns to pass DNS-query to LDAP in favour of a cdb lookup. ++ * $Id$ ++ * Copyright 2002 ++ */ ++ ++extern ++int askldap_query(const char* djbdomainname, char qtype[2]); ++ ++extern ++void askldap_init(const char* ldaphost, const char* basedn, const char* binddn, const char* passwd); +diff -Naur djbdns-1.05.orig/ldap.lib djbdns-1.05/ldap.lib +--- djbdns-1.05.orig/ldap.lib Thu Jan 1 01:00:00 1970 ++++ djbdns-1.05/ldap.lib Tue Aug 13 14:29:53 2002 +@@ -0,0 +1 @@ ++-lldap -llber +diff -Naur djbdns-1.05.orig/server.c djbdns-1.05/server.c +--- djbdns-1.05.orig/server.c Sun Feb 11 22:11:45 2001 ++++ djbdns-1.05/server.c Tue Aug 13 14:29:15 2002 +@@ -11,6 +11,7 @@ + #include "qlog.h" + #include "response.h" + #include "dns.h" ++#include "askldap.h" + + extern char *fatal; + extern char *starting; +@@ -79,6 +80,7 @@ + return 0; + } + ++ + int main() + { + char *x; +@@ -90,6 +92,19 @@ + if (!ip4_scan(x,ip)) + strerr_die3x(111,fatal,"unable to parse IP address ",x); + ++ x = env_get("LDAPHOSTS"); ++ if (x) { ++ char *basedn = env_get("LDAPBASEDN"); ++ char *binddn = env_get("LDAPBINDDN"); ++ char *bindpwd = env_get("LDAPPASSWD"); ++ if (basedn) ++ askldap_init(x, basedn, binddn, bindpwd); ++ if (bindpwd) { ++ int len = str_len(bindpwd); ++ while (len) bindpwd[--len] = 'x'; ++ } ++ } ++ + udp53 = socket_udp(); + if (udp53 == -1) + strerr_die2sys(111,fatal,"unable to create UDP socket: "); +diff -Naur djbdns-1.05.orig/tdlookup.c djbdns-1.05/tdlookup.c +--- djbdns-1.05.orig/tdlookup.c Sun Feb 11 22:11:45 2001 ++++ djbdns-1.05/tdlookup.c Tue Aug 13 14:29:29 2002 +@@ -8,6 +8,7 @@ + #include "dns.h" + #include "seek.h" + #include "response.h" ++#include "askldap.h" + + static int want(const char *owner,const char type[2]) + { +@@ -285,10 +286,13 @@ + char key[6]; + + tai_now(&now); ++ if (askldap_query(q, qtype)) ++ return 1; ++ + fd = open_read("data.cdb"); + if (fd == -1) return 0; + cdb_init(&c,fd); +- ++ + byte_zero(clientloc,2); + key[0] = 0; + key[1] = '%'; diff --git a/dns.at.conf b/dns.at.conf deleted file mode 100644 index 30e42d0..0000000 --- a/dns.at.conf +++ /dev/null @@ -1,24 +0,0 @@ -# include this file into Your slapd.conf for openldap-1.2.x -# $Id: dns.at.conf,v 1.5 2000/12/04 12:59:57 jrief Exp $ -attribute DNSzonename cis -attribute DNSserial cis -attribute DNSrefresh cis -attribute DNSretry cis -attribute DNSexpire cis -attribute DNSminimum cis -attribute DNSadminmailbox cis -attribute DNSzonemaster cis -attribute DNStype cis -attribute DNSclass cis -attribute DNSdomainname cis -attribute DNSipaddr cis -attribute DNScname cis -attribute DNSpreference cis -attribute DNSttl cis -attribute DNStimestamp cis - -#attribute DNSaliasedobjectname cis -#attribute DNSrr cis -#attribute DNSrrcount cis -#attribute DNSmacaddress cis - diff --git a/dns.oc.conf b/dns.oc.conf deleted file mode 100644 index 6a6359c..0000000 --- a/dns.oc.conf +++ /dev/null @@ -1,45 +0,0 @@ -# include this file into Your slapd.conf for openldap-1.2.x -# $Id: dns.oc.conf,v 1.4 2000/12/01 14:48:25 jrief Exp $ - -# child of anybody -# information to setup a DNS zone -objectclass DNSzone - requires - objectclass, - cn - allows - DNSzonename, - DNSserial, - DNSrefresh, - DNSretry, - DNSexpire, - DNSminimum, - DNSadminmailbox, - DNSzonemaster, - DNStype, - DNSclass, - DNSttl, - DNStimestamp - - #DNSrrcount, - -# child of a DNSzone -# information to setup a resource record -objectclass DNSrrset - requires - objectclass, - cn - allows - DNSdomainname, - DNSclass, - DNStype, - DNSipaddr, - DNScname, - DNSpreference, - DNSttl, - DNStimestamp - - #DNSaliasedobjectname, - #DNSrr, - #DNSmacaddress, - diff --git a/dns.schema b/dns.schema-2.0 similarity index 56% rename from dns.schema rename to dns.schema-2.0 index 81044c4..6bcabbb 100644 --- a/dns.schema +++ b/dns.schema-2.0 @@ -1,103 +1,125 @@ # schema for DNS data # include this file into Your slapd.conf for openldap-2.0.x -# $Id: dns.schema,v 1.8 2001/08/09 10:35:49 jrief Exp $ +# $Id: dns.schema,v 1.9 2003/01/20 14:33:25 jrief Exp $ attributetype ( 1.3.6.1.4.1.7222.1.4.1 - NAME 'DNSzonename' + NAME 'dnszonename' SUP name ) attributetype ( 1.3.6.1.4.1.7222.1.4.2 - NAME 'DNSserial' + NAME 'dnsserial' SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) attributetype ( 1.3.6.1.4.1.7222.1.4.3 - NAME 'DNSrefresh' + NAME 'dnsrefresh' SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) attributetype ( 1.3.6.1.4.1.7222.1.4.4 - NAME 'DNSretry' + NAME 'dnsretry' SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) attributetype ( 1.3.6.1.4.1.7222.1.4.5 - NAME 'DNSexpire' + NAME 'dnsexpire' SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) attributetype ( 1.3.6.1.4.1.7222.1.4.6 - NAME 'DNSminimum' + NAME 'dnsminimum' SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) attributetype ( 1.3.6.1.4.1.7222.1.4.7 - NAME 'DNSadminmailbox' + NAME 'dnsadminmailbox' SUP name ) attributetype ( 1.3.6.1.4.1.7222.1.4.8 - NAME 'DNSzonemaster' + NAME 'dnszonemaster' SUP name ) attributetype ( 1.3.6.1.4.1.7222.1.4.9 - NAME 'DNStype' + NAME 'dnstype' SUP name ) attributetype ( 1.3.6.1.4.1.7222.1.4.10 - NAME 'DNSclass' + NAME 'dnsclass' SUP name ) attributetype ( 1.3.6.1.4.1.7222.1.4.11 - NAME 'DNSdomainname' + NAME 'dnsdomainname' SUP name ) attributetype ( 1.3.6.1.4.1.7222.1.4.12 - NAME 'DNSipaddr' + NAME 'dnsipaddr' EQUALITY numericStringMatch SUBSTR numericStringSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{16} ) attributetype ( 1.3.6.1.4.1.7222.1.4.13 - NAME 'DNScipaddr' + NAME 'dnscipaddr' EQUALITY numericStringMatch SUBSTR numericStringSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{16} ) attributetype ( 1.3.6.1.4.1.7222.1.4.14 - NAME 'DNScname' + NAME 'dnscname' SUP name ) attributetype ( 1.3.6.1.4.1.7222.1.4.15 - NAME 'DNSpreference' + NAME 'dnspreference' SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) attributetype ( 1.3.6.1.4.1.7222.1.4.16 - NAME 'DNSrr' + NAME 'dnsrr' SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE ) attributetype ( 1.3.6.1.4.1.7222.1.4.17 - NAME 'DNSttl' + NAME 'dnsttl' SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) attributetype ( 1.3.6.1.4.1.7222.1.4.18 - NAME 'DNStimestamp' + NAME 'dnstimestamp' SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE ) +attributetype ( 1.3.6.1.4.1.7222.1.4.21 + NAME 'NIChandle' + EQUALITY caseIgnoreMatch + SUBSTR caseIgnoreSubstringsMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{16} ) + +attributetype ( 1.3.6.1.4.1.7222.1.4.22 + NAME 'TIShandle' + EQUALITY caseIgnoreMatch + SUBSTR caseIgnoreSubstringsMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{16} ) + +attributetype ( 1.3.6.1.4.1.7222.1.4.23 + NAME 'dnslocation' + EQUALITY caseExactIA5Match + SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{2} + SINGLE-VALUE ) + objectclass ( 1.3.6.1.4.1.7222.1.4.19 - NAME 'DNSzone' + NAME 'dnszone' MUST ( objectclass $ cn ) - MAY ( DNSzonename $ DNSserial $ DNSrefresh $ DNSretry $ DNSexpire - $ DNSminimum $ DNSadminmailbox $ DNSzonemaster $ DNStype $ DNSclass - $ DNSttl $ DNStimestamp $ owner ) ) + MAY ( dnszonename $ dnsserial $ dnsrefresh $ dnsretry $ dnsexpire + $ dnsminimum $ dnsadminmailbox $ dnszonemaster $ dnstype $ dnsclass + $ dnsttl $ dnstimestamp $ owner $ NIChandle $ TIShandle $ dnslocation ) ) objectclass ( 1.3.6.1.4.1.7222.1.4.20 - NAME 'DNSrrset' - SUP DNSzone + NAME 'dnsrrset' + SUP dnszone MUST ( objectclass $ cn ) - MAY ( DNSdomainname $ DNSrr $ DNSclass $ DNStype $ DNSipaddr $ DNScipaddr - $ DNScname $ DNSpreference $ DNSttl $ DNStimestamp $ owner ) ) + MAY ( dnsdomainname $ dnsrr $ dnsclass $ dnstype $ dnsipaddr $ dnscipaddr + $ dnscname $ dnspreference $ dnsttl $ dnstimestamp $ owner ) ) +objectclass ( 1.3.6.1.4.1.7222.1.4.24 + NAME 'dnsloccodes' + MUST ( objectclass $ dnslocation ) + MAY ( dnsipaddr $ uid $ description ) ) diff --git a/dns.schema-2.2 b/dns.schema-2.2 new file mode 100644 index 0000000..1be6a2e --- /dev/null +++ b/dns.schema-2.2 @@ -0,0 +1,126 @@ +# schema for DNS data +# include this file into Your slapd.conf for openldap-2.0.x +# $Id: dns.schema,v 1.9 2001/11/06 08:01:51 config Exp $ + +attributetype ( 1.3.6.1.4.1.7222.1.4.1 + NAME 'dnszonename' + SUP name ) + +attributetype ( 1.3.6.1.4.1.7222.1.4.2 + NAME 'dnsserial' + EQUALITY integerMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 + SINGLE-VALUE ) + +attributetype ( 1.3.6.1.4.1.7222.1.4.3 + NAME 'dnsrefresh' + EQUALITY integerMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 + SINGLE-VALUE ) + +attributetype ( 1.3.6.1.4.1.7222.1.4.4 + NAME 'dnsretry' + EQUALITY integerMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 + SINGLE-VALUE ) + +attributetype ( 1.3.6.1.4.1.7222.1.4.5 + NAME 'dnsexpire' + EQUALITY integerMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 + SINGLE-VALUE ) + +attributetype ( 1.3.6.1.4.1.7222.1.4.6 + NAME 'dnsminimum' + EQUALITY integerMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 + SINGLE-VALUE ) + +attributetype ( 1.3.6.1.4.1.7222.1.4.7 + NAME 'dnsadminmailbox' + SUP name ) + +attributetype ( 1.3.6.1.4.1.7222.1.4.8 + NAME 'dnszonemaster' + SUP name ) + +attributetype ( 1.3.6.1.4.1.7222.1.4.9 + NAME 'dnstype' + SUP name ) + +attributetype ( 1.3.6.1.4.1.7222.1.4.10 + NAME 'dnsclass' + SUP name ) + +attributetype ( 1.3.6.1.4.1.7222.1.4.11 + NAME 'dnsdomainname' + SUP name ) + +attributetype ( 1.3.6.1.4.1.7222.1.4.12 + NAME 'dnsipaddr' + EQUALITY caseIgnoreIA5Match + SUBSTR caseIgnoreIA5SubstringsMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{16} ) + SINGLE-VALUE ) + + +attributetype ( 1.3.6.1.4.1.7222.1.4.13 + NAME 'dnscipaddr' + EQUALITY caseIgnoreIA5Match + SUBSTR caseIgnoreIA5SubstringsMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{16} ) + +attributetype ( 1.3.6.1.4.1.7222.1.4.14 + NAME 'dnscname' + SUP name ) + +attributetype ( 1.3.6.1.4.1.7222.1.4.15 + NAME 'dnspreference' + EQUALITY integerMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 + SINGLE-VALUE ) + +attributetype ( 1.3.6.1.4.1.7222.1.4.16 + NAME 'dnsrr' + SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 + SINGLE-VALUE ) + +attributetype ( 1.3.6.1.4.1.7222.1.4.17 + NAME 'dnsttl' + EQUALITY integerMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 + SINGLE-VALUE ) + +attributetype ( 1.3.6.1.4.1.7222.1.4.18 + NAME 'dnstimestamp' + SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 + SINGLE-VALUE ) + +attributetype ( 1.3.6.1.4.1.7222.1.4.21 + NAME 'NIChandle' + EQUALITY caseIgnoreMatch + SUBSTR caseIgnoreSubstringsMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{16} ) + +attributetype ( 1.3.6.1.4.1.7222.1.4.22 + NAME 'TIShandle' + EQUALITY caseIgnoreMatch + SUBSTR caseIgnoreSubstringsMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{16} ) + +objectclass ( 1.3.6.1.4.1.7222.1.4.19 + NAME 'dnszone' + MUST ( objectclass $ cn ) + MAY ( dnszonename $ dnsserial $ dnsrefresh $ dnsretry $ dnsexpire + $ dnsminimum $ dnsadminmailbox $ dnszonemaster $ dnstype $ dnsclass + $ dnsttl $ dnstimestamp $ owner $ NIChandle $ TIShandle ) ) + +objectclass ( 1.3.6.1.4.1.7222.1.4.20 + NAME 'dnsrrset' + SUP dnszone + MUST ( objectclass $ cn ) + MAY ( dnsdomainname $ dnsrr $ dnsclass $ dnstype $ dnsipaddr $ dnscipaddr + $ dnscname $ dnspreference $ dnsttl $ dnstimestamp $ owner ) ) + + + diff --git a/export-ldap2dns.pl b/export-ldap2dns.pl new file mode 100755 index 0000000..5119189 --- /dev/null +++ b/export-ldap2dns.pl @@ -0,0 +1,190 @@ +#!/usr/bin/perl +# Script to import data from DNS into LDAP +# Copyright 2000, Jacob Rief +# $Id: export-ldap2dns.pl,v 1.1 2002/09/03 10:43:40 jrief Exp $ + +###### configure this ###### +# remember to allow zone transfers from Your nameserver +my $LDAPHOST = "localhost"; +my $LDAPBINDDN = "uid=root,o=tiscover"; +my $LDAPPASSWD = "1Fnegu!"; +my $BASEDN = "ou=dns,o=tiscover"; + +###### don't edit below this line ###### +use strict; +use Net::LDAP qw(LDAP_NO_SUCH_OBJECT LDAP_ALREADY_EXISTS); + +my $ldap; +initialize(); +migrate_zones(); + +sub initialize +{ + $ldap = Net::LDAP->new($LDAPHOST) or die "Can't connect to LDAP server"; + my $mesg = $ldap->bind( dn => $LDAPBINDDN, password => $LDAPPASSWD ); + die "Unable to bind to LDAP ", $mesg->error if ($mesg->code); +} + +sub migrate_zones +{ + my $mesg = $ldap->search(base=>$BASEDN, scope=>'sub', filter=>"(objectclass=dnszone)"); + my @oldzones = $mesg->entries(); + foreach my $oldzone (@oldzones) { + my @zonename = $oldzone->get_value('dnszonename'); + my $masterdn = dn_domain($zonename[0]) if ($#zonename>=0); + foreach my $zn (@zonename) { + my $newdn = dn_domain($zn); + next unless ($newdn =~ /^dc=\s*([^,]+).*/); + my $dc = $1; + my $soarecord = $oldzone->get_value('dnsserial')." " + .$oldzone->get_value('dnsrefresh')." " + .$oldzone->get_value('dnsretry')." " + .$oldzone->get_value('dnsexpire')." " + .$oldzone->get_value('dnsminimum'); + my %attrs = ( 'objectclass' => [ qw(dNSDomain dcObject) ], 'dc' => $dc, 'sOARecord' => [ $soarecord ] ); + $mesg = $ldap->modify($newdn, 'replace' => \%attrs); + while ($mesg->code()==LDAP_NO_SUCH_OBJECT) { + repeat: + $mesg = $ldap->add($newdn, 'attrs' => list_attrs(\%attrs)); + last unless ($mesg->code()==LDAP_NO_SUCH_OBJECT); + my $filldn = $newdn; + do { + die("Invalid dn: $filldn") unless ($filldn =~ /[^,]+,((dc=[^,]+),.+)/); + $filldn = $1; + $mesg = $ldap->add($filldn, 'attrs' => [ 'objectclass'=>'dcObject', 'dc'=>$2) ]); + } until ($mesg->code()==0 || $mesg->code()==LDAP_ALREADY_EXISTS); + goto repeat; + } + die("Error from LDAP: \"".$mesg->error()."\" on $newdn (".$mesg->code().")") if ($mesg->code()); + if ($masterdn ne $newdn) { + $mesg = $ldap->modify($masterdn, 'replace' => [ 'objectclass' => 'alias' ]); + $mesg = $ldap->modify($masterdn, 'add' => [ 'alias' => $newdn ]); + $mesg = $ldap->modify($newdn, 'replace' => [ 'objectclass' => 'alias', 'alias' => $masterdn ]); + } + migrate_rrrecords($zn, $newdn, $oldzone->dn()); + } + } +} + +sub migrate_rrrecords +{ + my ($zonename, $newzonedn, $oldzonedn) = (@_); + my @objectclass = qw(dNSDomain dcObject); + my $mesg = $ldap->search(base=>$oldzonedn, scope=>'sub', filter=>"(objectclass=dnsrrset)"); + my @rrsets = $mesg->entries(); + foreach my $rr (@rrsets) { + my $domainname = $rr->get_value('dnsdomainname'); + my $dn = dn_domain(length($domainname)>0 ? "$domainname.$zonename" : "$zonename"); + my $type = $rr->get_value('dnstype'); + print "dn: $dn (type: $type)\n"; + next unless ($dn =~ /^dc=\s*([^,]+).*/); + my %attrs = read_ldapobject($dn); + $attrs{'objectclass'} = \@objectclass; + $attrs{'dc'} = $1; + my @cname = $rr->get_value('dnscname'); + my @ipaddr = $rr->get_value('dnsipaddr'); + my $cipaddr = $rr->get_value('dnscipaddr'); + if ($type eq "A") { + push(@ipaddr, $cipaddr) if (length($cipaddr)>5); + my $ta = $attrs{'aRecord'}; + push(@$ta, @ipaddr) if ($#ipaddr>=0); + } elsif ($type eq "NS") { + my $ta = $attrs{'NSRecord'}; + foreach my $cn (@cname) { + if ($cn =~ /\.$/) { + push(@$ta, $cn); + } else { + push(@$ta, "$cn.$zonename"); + } + } + } elsif ($type eq "MX") { + my $ta = $attrs{'MXRecord'}; + my $pref = $rr->get_value('dnspreference'); + foreach my $cn (@cname) { + if ($cn =~ /\.$/) { + push(@$ta, "$pref $cn"); + } else { + push(@$ta, "$pref $cn.$zonename"); + } + } + } elsif ($type eq "CNAME") { + my $ta = $attrs{'cNAMERecord'}; + die("no CNAME") unless($#cname>=0); + foreach my $cn (@cname) { + if ($cn =~ /\.$/) { + push(@$ta, $cn); + } else { + push(@$ta, "$cn.$zonename"); + } + } + } + remove_unused(\%attrs); + $mesg = $ldap->modify($dn, 'replace' => \%attrs); + while ($mesg->code()==LDAP_NO_SUCH_OBJECT) { + repeat: + $mesg = $ldap->add($dn, 'attrs' => list_attrs(\%attrs)); + last unless ($mesg->code()==LDAP_NO_SUCH_OBJECT); + my $filldn = $dn; + do { + die("Invalid dn: $filldn") unless ($filldn =~ /[^,]+,((dc=[^,]+),.+)/); + $filldn = $1; + $mesg = $ldap->add($filldn, 'attrs' => [ qw(objectclass dcObject dc $2) ]); + } until ($mesg->code()==0 || $mesg->code()==LDAP_ALREADY_EXISTS); + goto repeat; + } + die("Error from LDAP: \"".$mesg->error()."\" on $dn") if ($mesg->code()); + } +} + +sub dn_domain +{ + my ($domain)=(@_); + my @p = split /\./, lc($domain); + my $dc = 'dc='.join(',dc=', @p); + $dc .= ','.$BASEDN; + return $dc; +} + +sub list_attrs +{ + my $attr = shift; + my (@list, $key, $value); + while (($key, $value) = each %$attr) { + push(@list, $key => $value); + } + return \@list; +} + +sub read_ldapobject +{ + my $dn = shift; + my %attrs = (); + $attrs{'aRecord'} = []; + $attrs{'cNAMERecord'} = []; + $attrs{'MXRecord'} = []; + $attrs{'NSRecord'} = []; + my $mesg = $ldap->search(base => $dn, scope => 'base', filter => "(objectclass=dcObject)"); + return %attrs if ($mesg->code()==LDAP_NO_SUCH_OBJECT); + return %attrs if ($mesg->count()==0); + my $obj = $mesg->entry(0); + my @tempa = $obj->get_value('aRecord'); + $attrs{'aRecord'} = \@tempa if ($#tempa>=0); + my @tempcname = $obj->get_value('cNAMERecord'); + $attrs{'cNAMERecord'} = \@tempcname if ($#tempcname>=0); + my @tempmx = $obj->get_value('MXRecord'); + $attrs{'MXRecord'} = \@tempmx if ($#tempmx>=0); + my @tempns = $obj->get_value('NSRecord'); + $attrs{'NSRecord'} = \@tempns if ($#tempns>=0); + return %attrs; +} + +sub remove_unused +{ + my $hash = shift; + foreach my $key (keys %$hash) { + my $ta = $$hash{$key}; + next if ($key eq "dc"); + delete $$hash{$key} if ($#$ta<0); + } +} + diff --git a/ldap2dns-dbg b/ldap2dns-dbg new file mode 100755 index 0000000000000000000000000000000000000000..0427d1802dbe3d01c48d9900ef03d8a4f3bce222 GIT binary patch literal 71947 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 literal 0 HcmV?d00001 diff --git a/ldap2dns-ldapuri.patch b/ldap2dns-ldapuri.patch new file mode 100644 index 0000000..40c15a1 --- /dev/null +++ b/ldap2dns-ldapuri.patch @@ -0,0 +1,134 @@ +--- ldap2dns-0.3.1-orig/ldap2dns.c 2002-08-02 17:19:36.000000000 +0200 ++++ ldap2dns-0.3.1/ldap2dns.c 2002-09-01 13:31:52.000000000 +0200 +@@ -14,7 +14,7 @@ + #include + + #define UPDATE_INTERVALL 59 +-#define LDAP_CONF "/etc/ldap.conf" ++#define LDAP_CONF "/etc/ldap/ldap.conf" + #define OUTPUT_DATA 1 + #define OUTPUT_DB 2 + #define MAXHOSTS 10 +@@ -85,6 +85,7 @@ + char searchbase[128]; + char binddn[128]; + char hostname[MAXHOSTS][128]; ++ char urildap[MAXHOSTS][128]; + int port[MAXHOSTS]; + char password[128]; + int usedhosts; +@@ -94,6 +95,7 @@ + int verbose; + char ldifname[128]; + char exec_command[128]; ++ int use_tls[MAXHOSTS]; + } options; + + +@@ -130,7 +132,8 @@ + static void print_usage(void) + { + print_version(); +- printf("usage: ldap2dns[d] [-D binddn] [-b searchbase] [-o data|db] [-h host] [-p port] [-w password] [-L[filename]] [-u numsecs] [-v[v]] [-V]\n\n"); ++ printf("usage: ldap2dns[d] [-D binddn] [-b searchbase] [-o data|db] [-h host] [-p port] [-H hostURI] " ++ "[-w password] [-L[filename]] [-u numsecs] [-v[v]] [-V]\n\n"); + printf("ldap2dns connects to an LDAP server reads the DNS information stored in objectclasses\n" + "\t\tDNSzone and DNSrrset and writes a file to be used by tinydns or named.\n" + "\t\tldap2dnsd starts as background-job and continouesly updates DNS information.\n"); +@@ -143,6 +146,7 @@ + printf(" -L[filename] Print output in LDIF format for reimport\n"); + printf(" -h host\tHostname of LDAP server, defaults to localhost\n"); + printf(" -p port\tPortnumber to connect to LDAP server, defaults to %d\n", LDAP_PORT); ++ printf(" -H hostURI\tURI (ldap://hostname or ldaps://hostname of LDAP server\n"); + printf(" -u numsecs\tUpdate DNS data after numsecs. Defaults to %d if started as daemon.\n\t\t" + "Important notice: data.cdb is rewritten only after DNSserial in DNSzone is increased.\n", + UPDATE_INTERVALL); +@@ -159,7 +163,18 @@ + + options.usedhosts = 0; + for (i = 0; i=2) { ++ if (!strncasecmp(buf, "ldaps://", 8) || !strncasecmp(buf, "ldap://", 7)) { ++ // LDAP-URI is given/found, at the moment only the standard-ports 389 and 636 are supported ++ if (!strncasecmp(buf, "ldap://", 7)) ++ options.use_tls[i] = 1; ++ if ((k = sscanf(buf, "%128s %512[A-Za-z0-9 .:/_+-]", value, rest))>=1) { ++ strcpy(options.urildap[i], value); ++ options.usedhosts++; ++ if (k==1) ++ break; ++ buf = rest; ++ } else break; ++ } else if ((k = sscanf(buf, "%128s:%d %512[A-Za-z0-9 .:_+-]", value, &port, rest))>=2) { + strcpy(options.hostname[i], value); + options.port[i] = port; + options.usedhosts++; +@@ -194,6 +209,8 @@ + int i; + if (sscanf(buf, "BASE %128s", value)==1) + strcpy(options.searchbase, value); ++ if (sscanf(buf, "URI %512[A-Za-z0-9 .:/_+-]", value)==1) ++ parse_hosts(value); + if (sscanf(buf, "HOST %512[A-Za-z0-9 .:_+-]", value)==1) + parse_hosts(value); + if (sscanf(buf, "PORT %d", &len)==1) +@@ -239,7 +256,7 @@ + options.ldifname[0] = '\0'; + strcpy(options.password, ""); + strcpy(options.exec_command, ""); +- while ( (len = getopt(main_argc, main_argv, "b:D:e:h:o:p:u:V:v::w:L::"))>0 ) { ++ while ( (len = getopt(main_argc, main_argv, "b:D:e:h:H:o:p:u:V:v::w:L::"))>0 ) { + if (optarg && strlen(optarg)>127) { + fprintf(stderr, "argument %s too long\n", optarg); + continue; +@@ -260,6 +277,10 @@ + strcpy(options.hostname[0], optarg); + options.usedhosts = 1; + break; ++ case 'H': ++ strcpy(options.urildap[0], optarg); ++ options.usedhosts = 1; ++ break; + case 'L': + if (optarg==NULL) + strcpy(options.ldifname, "-"); +@@ -796,12 +817,37 @@ + + static int connect() + { +- int i; ++ int i, rc, version; + for (i = 0; i 0) { ++ rc = ldap_initialize(&ldap_con, options.urildap[i]); ++ if (options.verbose&1 && rc == LDAP_SUCCESS) { ++ printf("ldap_initialization successful (%s)\n", options.urildap[i]); ++ } else if ( rc != LDAP_SUCCESS ) { ++ printf("ldap_initialization to %s failed %d\n", options.urildap[i], ldap_err2string(rc)); ++ ldap_con = NULL; ++ return 0; ++ } ++ version = LDAP_VERSION3; ++ if ( (rc=ldap_set_option(ldap_con, LDAP_OPT_PROTOCOL_VERSION, &version)) != LDAP_SUCCESS ) { ++ printf("ldap_set_option to %s failed with err %s!\n", options.urildap[i], ldap_err2string(rc)); ++ ldap_con = NULL; ++ return 0; ++ } ++ if ( options.use_tls[i] && (rc=ldap_start_tls_s( ldap_con, NULL, NULL )) != LDAP_SUCCESS ) { ++ printf("ldap_start_tls_s to %s failed with err %s!\n", options.urildap[i], ldap_err2string(rc)); ++ ldap_con = NULL; ++ return 0; ++ } ++ } else { + ldap_con = ldap_init(options.hostname[i], options.port[i]); ++ } + if (ldap_simple_bind_s(ldap_con, options.binddn, options.password)==LDAP_SUCCESS) { +- if (options.verbose&1) ++ if (options.verbose&1 && strlen(options.urildap[i]) > 0) { ++ printf("Connected to %s as \"%s\"\n", options.urildap[i], options.binddn); ++ } else if (options.verbose&1) { + printf("Connected to %s:%d as \"%s\"\n", options.hostname[i], options.port[i], options.binddn); ++ } + return 1; + } + } diff --git a/ldap2dns-loccode.patch b/ldap2dns-loccode.patch new file mode 100644 index 0000000..f177354 --- /dev/null +++ b/ldap2dns-loccode.patch @@ -0,0 +1,299 @@ +diff -bu ldap2dns-0.3.1-p1/dns.schema ldap2dns-0.3.1/dns.schema +--- ldap2dns-0.3.1-p1/dns.schema 2002-08-13 14:23:53.000000000 +0200 ++++ ldap2dns-0.3.1/dns.schema 2002-09-02 10:10:32.000000000 +0200 +@@ -99,12 +99,18 @@ + SUBSTR caseIgnoreSubstringsMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{16} ) + ++attributetype ( 1.3.6.1.4.1.7222.1.4.23 ++ NAME 'dnslocation' ++ EQUALITY caseExactIA5Match ++ SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{2} ++ SINGLE-VALUE ) ++ + objectclass ( 1.3.6.1.4.1.7222.1.4.19 + NAME 'dnszone' + MUST ( objectclass $ cn ) + MAY ( dnszonename $ dnsserial $ dnsrefresh $ dnsretry $ dnsexpire + $ dnsminimum $ dnsadminmailbox $ dnszonemaster $ dnstype $ dnsclass +- $ dnsttl $ dnstimestamp $ owner $ NIChandle $ TIShandle ) ) ++ $ dnsttl $ dnstimestamp $ owner $ NIChandle $ TIShandle $ dnslocation ) ) + + objectclass ( 1.3.6.1.4.1.7222.1.4.20 + NAME 'dnsrrset' +@@ -113,3 +119,7 @@ + MAY ( dnsdomainname $ dnsrr $ dnsclass $ dnstype $ dnsipaddr $ dnscipaddr + $ dnscname $ dnspreference $ dnsttl $ dnstimestamp $ owner ) ) + ++objectclass ( 1.3.6.1.4.1.7222.1.4.24 ++ NAME 'dnsloccodes' ++ MUST ( objectclass $ dnslocation ) ++ MAY ( dnsipaddr $ uid $ description ) ) +diff -bu ldap2dns-0.3.1-p1/ldap2dns.c ldap2dns-0.3.1/ldap2dns.c +--- ldap2dns-0.3.1-p1/ldap2dns.c 2002-09-02 10:45:43.000000000 +0200 ++++ ldap2dns-0.3.1/ldap2dns.c 2002-09-02 10:04:50.000000000 +0200 +@@ -58,8 +58,15 @@ + char minimum[12]; + char ttl[12]; + char timestamp[20]; ++ char location[2]; + } zone; + ++static struct ++{ ++ char locname[3]; ++ char member[256][16]; ++} loc_rec; ++ + struct resourcerecord + { + char cn[64]; +@@ -72,6 +79,7 @@ + char ttl[12]; + char timestamp[20]; + char preference[12]; ++ char location[2]; + #if defined DRAFT_RFC + char rr[1024]; + char aliasedobjectname[256]; +@@ -360,19 +368,19 @@ + if (tinyfile) { + if (znix==0) { + if (ipdx<=0 && rr->cipaddr[0]) { +- fprintf(tinyfile, "&%s::%s:%s:%s\n", rr->dnsdomainname, rr->cname, rr->ttl, rr->timestamp); ++ fprintf(tinyfile, "&%s::%s:%s:%s:%s\n", rr->dnsdomainname, rr->cname, rr->ttl, rr->timestamp, rr->location); + if (rr->cname[0]) +- fprintf(tinyfile, "=%s:%s:%s:%s\n", rr->cname, rr->cipaddr, rr->ttl, rr->timestamp); ++ fprintf(tinyfile, "=%s:%s:%s:%s:%s\n", rr->cname, rr->cipaddr, rr->ttl, rr->timestamp, rr->location); + if (ipdx==0) +- fprintf(tinyfile, "+%s:%s:%s:%s\n", rr->cname, rr->ipaddr[0], rr->ttl, rr->timestamp); ++ fprintf(tinyfile, "+%s:%s:%s:%s:%s\n", rr->cname, rr->ipaddr[0], rr->ttl, rr->timestamp, rr->location); + } else if (ipdx<0) +- fprintf(tinyfile, "&%s::%s:%s:%s\n", rr->dnsdomainname, rr->cname, rr->ttl, rr->timestamp); ++ fprintf(tinyfile, "&%s::%s:%s:%s:%s\n", rr->dnsdomainname, rr->cname, rr->ttl, rr->timestamp, rr->location); + else if (ipdx==0) +- fprintf(tinyfile, "&%s:%s:%s:%s:%s\n", rr->dnsdomainname, rr->ipaddr[0], rr->cname, rr->ttl, rr->timestamp); ++ fprintf(tinyfile, "&%s:%s:%s:%s:%s:%s\n", rr->dnsdomainname, rr->ipaddr[0], rr->cname, rr->ttl, rr->timestamp, rr->location); + else if (ipdx>0 && rr->cname[0]) +- fprintf(tinyfile, "+%s:%s:%s:%s\n", rr->cname, rr->ipaddr[ipdx], rr->ttl, rr->timestamp); ++ fprintf(tinyfile, "+%s:%s:%s:%s:%s\n", rr->cname, rr->ipaddr[ipdx], rr->ttl, rr->timestamp, rr->location); + } else if (ipdx<=0) { +- fprintf(tinyfile, "&%s::%s:%s:%s\n", rr->dnsdomainname, rr->cname, rr->ttl, rr->timestamp); ++ fprintf(tinyfile, "&%s::%s:%s:%s:%s\n", rr->dnsdomainname, rr->cname, rr->ttl, rr->timestamp, rr->location); + } + } + if (namedzone) { +@@ -384,19 +392,19 @@ + if (tinyfile) { + if (znix==0) { + if (ipdx<=0 && rr->cipaddr[0]) { +- fprintf(tinyfile, "@%s::%s:%s:%s:%s\n", rr->dnsdomainname, rr->cname, rr->preference, rr->ttl, rr->timestamp); ++ fprintf(tinyfile, "@%s::%s:%s:%s:%s:%s\n", rr->dnsdomainname, rr->cname, rr->preference, rr->ttl, rr->timestamp, rr->location); + if (rr->cname[0]) +- fprintf(tinyfile, "=%s:%s:%s:%s\n", rr->cname, rr->cipaddr, rr->ttl, rr->timestamp); ++ fprintf(tinyfile, "=%s:%s:%s:%s:%s\n", rr->cname, rr->cipaddr, rr->ttl, rr->timestamp, rr->location); + if (ipdx==0) +- fprintf(tinyfile, "+%s:%s:%s:%s\n", rr->cname, rr->ipaddr[0], rr->ttl, rr->timestamp); ++ fprintf(tinyfile, "+%s:%s:%s:%s:%s\n", rr->cname, rr->ipaddr[0], rr->ttl, rr->timestamp, rr->location); + } else if (ipdx<0) +- fprintf(tinyfile, "@%s::%s:%s:%s:%s\n", rr->dnsdomainname, rr->cname, rr->preference, rr->ttl, rr->timestamp); ++ fprintf(tinyfile, "@%s::%s:%s:%s:%s:%s\n", rr->dnsdomainname, rr->cname, rr->preference, rr->ttl, rr->timestamp, rr->location); + else if (ipdx==0) +- fprintf(tinyfile, "@%s:%s:%s:%s:%s:%s\n", rr->dnsdomainname, rr->ipaddr[0], rr->cname, rr->preference, rr->ttl, rr->timestamp); ++ fprintf(tinyfile, "@%s:%s:%s:%s:%s:%s:%s\n", rr->dnsdomainname, rr->ipaddr[0], rr->cname, rr->preference, rr->ttl, rr->timestamp, rr->location); + else if (ipdx>0 && rr->cname[0]) +- fprintf(tinyfile, "+%s:%s:%s:%s\n", rr->cname, rr->ipaddr[ipdx], rr->ttl, rr->timestamp); ++ fprintf(tinyfile, "+%s:%s:%s:%s:%s\n", rr->cname, rr->ipaddr[ipdx], rr->ttl, rr->timestamp, rr->location); + } else if (ipdx<=0) { +- fprintf(tinyfile, "@%s::%s:%s:%s:%s\n", rr->dnsdomainname, rr->cname, rr->preference, rr->ttl, rr->timestamp); ++ fprintf(tinyfile, "@%s::%s:%s:%s:%s:%s\n", rr->dnsdomainname, rr->cname, rr->preference, rr->ttl, rr->timestamp, rr->location); + } + } + if (namedzone) { +@@ -407,9 +415,9 @@ + } else if ( strcasecmp(rr->type, "A")==0) { + if (tinyfile) { + if (ipdx<=0 && rr->cipaddr[0]) +- fprintf(tinyfile, "%s%s:%s:%s:%s\n", (znix==0 ? "=" : "+"), rr->dnsdomainname, rr->cipaddr, rr->ttl, rr->timestamp); ++ fprintf(tinyfile, "%s%s:%s:%s:%s:%s\n", (znix==0 ? "=" : "+"), rr->dnsdomainname, rr->cipaddr, rr->ttl, rr->timestamp, rr->location); + if (ipdx>=0) +- fprintf(tinyfile, "+%s:%s:%s:%s\n", rr->dnsdomainname, rr->ipaddr[ipdx], rr->ttl, rr->timestamp); ++ fprintf(tinyfile, "+%s:%s:%s:%s:%s\n", rr->dnsdomainname, rr->ipaddr[ipdx], rr->ttl, rr->timestamp, rr->location); + } + if (namedzone) { + if (ipdx<=0 && rr->cipaddr[0]) +@@ -431,17 +439,17 @@ + strcpy(buf, rr->dnsdomainname); + } + if (tinyfile) +- fprintf(tinyfile, "^%s:%s:%s:%s\n", buf, rr->cname, rr->ttl, rr->timestamp); ++ fprintf(tinyfile, "^%s:%s:%s:%s:%s\n", buf, rr->cname, rr->ttl, rr->timestamp, rr->location); + if (namedzone) + fprintf(namedzone, "%s.\tIN PTR\t%s.\n", buf, rr->cname); + } else if (strcasecmp(rr->type, "CNAME")==0) { + if (tinyfile) +- fprintf(tinyfile, "C%s:%s:%s:%s\n", rr->dnsdomainname, rr->cname, rr->ttl, rr->timestamp); ++ fprintf(tinyfile, "C%s:%s:%s:%s:%s\n", rr->dnsdomainname, rr->cname, rr->ttl, rr->timestamp, rr->location); + if (namedzone) + fprintf(namedzone, "%s.\tIN CNAME\t%s.\n", rr->dnsdomainname, rr->cname); + } else if (strcasecmp(rr->type, "TXT")==0) { + if (tinyfile) +- fprintf(tinyfile, "'%s:%s:%s:%s\n", rr->dnsdomainname, rr->cname, rr->ttl, rr->timestamp); ++ fprintf(tinyfile, "'%s:%s:%s:%s:%s\n", rr->dnsdomainname, rr->cname, rr->ttl, rr->timestamp, rr->location); + if (namedzone) + fprintf(namedzone, "%s.\tIN TXT\t%s.\n", rr->dnsdomainname, rr->cname); + } +@@ -515,6 +523,7 @@ + rr.ttl[0] = '\0'; + rr.timestamp[0] = '\0'; + rr.preference[0] = '\0'; ++ rr.location[0] = '\0'; + #if defined DRAFT_RFC + rr.aliasedobjectname[0] = '\0'; + rr.rr[0] = '\0'; +@@ -585,6 +594,11 @@ + rr.preference[0] = '\0'; + else if (options.ldifname[0]) + fprintf(ldifout, "%s: %s\n", attr, bvals[0]->bv_val); ++ } else if (strcasecmp(attr, "DNSlocation")==0) { ++ if (sscanf(bvals[0]->bv_val, "%s", rr.location)!=1) ++ rr.location[0] = '\0'; ++ else if (options.ldifname[0]) ++ fprintf(ldifout, "%s: %s\n", attr, bvals[0]->bv_val); + } + #if defined DRAFT_RFC + else if (strcasecmp(attr, "DNSrr")==0) { +@@ -632,10 +646,10 @@ + char soa[20]; + + if (tinyfile) { +- fprintf(tinyfile, "Z%s:%s:%s:%s:%s:%s:%s:%s:%s:%s\n", ++ fprintf(tinyfile, "Z%s:%s:%s:%s:%s:%s:%s:%s:%s:%s:%s\n", + zone.domainname, zone.zonemaster, zone.adminmailbox, + zone.serial, zone.refresh, zone.retry, zone.expire, +- zone.minimum, zone.ttl, zone.timestamp); ++ zone.minimum, zone.ttl, zone.timestamp, zone.location); + } + if (namedmaster) { + fprintf(namedmaster, "zone \"%s\" %s {\n\ttype master;\n\tfile \"%s.db\";\n};\n", +@@ -717,6 +731,7 @@ + zone.minimum[0] = '\0'; + zone.ttl[0] = '\0'; + zone.timestamp[0] = '\0'; ++ zone.location[0] = '\0'; + dn = ldap_get_dn(ldap_con, m); + if (options.ldifname[0]) + fprintf(ldifout, "dn: %s\n", dn); +@@ -782,6 +797,11 @@ + zone.timestamp[0] = '\0'; + else if (options.ldifname[0]) + fprintf(ldifout, "%s: %s\n", attr, zone.timestamp); ++ } else if (strcasecmp(attr, "DNSlocation")==0) { ++ if (sscanf(bvals[0]->bv_val, "%2s", zone.location)!=1) ++ zone.location[0] = '\0'; ++ else if (options.ldifname[0]) ++ fprintf(ldifout, "%s: %s\n", attr, zone.location); + } + } + ldap_value_free_len(bvals); +@@ -815,6 +835,91 @@ + ldap_msgfree(res); + } + ++static void write_loccode(int lidx) ++{ ++ if (tinyfile) { ++ fprintf(tinyfile, "%%%s:%s\n", loc_rec.locname, loc_rec.member[lidx]); ++ } ++ if (options.ldifname[0]) ++ fprintf(ldifout, "\n"); ++} ++ ++ ++static void read_loccodes(void) ++{ ++ LDAPMessage* res = NULL; ++ LDAPMessage* m; ++ int ldaperr; ++ ++ if (tinyfile) ++ fprintf(tinyfile, "# Location Codes (if any) - generated by ldap2dns - DO NOT EDIT!\n"); ++ ++ if ( (ldaperr = ldap_search_s(ldap_con, options.searchbase[0] ? options.searchbase : NULL, ++ LDAP_SCOPE_SUBTREE, ++ "objectclass=DNSloccodes", ++ NULL, ++ 0, ++ &res) ++ )!=LDAP_SUCCESS ) ++ die_ldap(ldaperr); ++ for (m = ldap_first_entry(ldap_con, res); m; m = ldap_next_entry(ldap_con, m)) { ++ BerElement* ber = NULL; ++ char* attr; ++ char* dn = ldap_get_dn(ldap_con, m); ++ int i, locmembers = 0; ++ char l_members[256][15]; ++ //char loc[256][64]; ++ char loc[2]; ++ char ldif0; ++ ++ loc_rec.locname[0] = '\0'; ++ if (options.ldifname[0]) ++ fprintf(ldifout, "dn: %s\n", dn); ++ for (attr = ldap_first_attribute(ldap_con, m, &ber); attr; attr = ldap_next_attribute(ldap_con, m, ber)) { ++ struct berval** bvals = ldap_get_values_len(ldap_con, m, attr); ++ if (bvals!=NULL) { ++ if (bvals[0] && bvals[0]->bv_len>0) { ++ if (strcasecmp(attr, "objectclass")==0 ++ || strcasecmp(attr, "cn")==0) { ++ if (options.ldifname[0]) ++ fprintf(ldifout, "%s: %s\n", attr, bvals[0]->bv_val); ++ } else if (strcasecmp(attr, "DNSlocation")==0) { ++ if (sscanf(bvals[0]->bv_val, "%2s", loc_rec.locname)!=1) ++ loc_rec.locname[0] = '\0'; ++ else if (options.ldifname[0]) ++ fprintf(ldifout, "%s: %s\n", attr, loc_rec.locname); ++ } else if (strcasecmp(attr, "DNSipaddr")==0) { ++ for (locmembers = 0; bvals[locmembers] && locmembers<256; locmembers++) { ++ if (sscanf(bvals[locmembers]->bv_val, "%15s", loc_rec.member[locmembers])!=1) ++ loc_rec.member[locmembers][0] = '\0'; ++ else if (options.ldifname[0]) ++ fprintf(ldifout, "%s: %s\n", attr, loc_rec.member[locmembers]); ++ } ++ } else { ++ if (options.ldifname[0]) ++ fprintf(ldifout, "%s: %s\n", attr, bvals[0]->bv_val); ++ } ++ } ++ ldap_value_free_len(bvals); ++ } ++ } ++ ldif0 = options.ldifname[0]; ++ if (options.verbose&1) ++ printf("locationcodename: %s (%d members)\n", loc_rec.locname, locmembers); ++ for (i = 0; i0) ++ options.ldifname[0] = '\0'; ++ write_loccode(i); ++ if (options.ldifname[0]) ++ fprintf(ldifout, "\n"); ++ } ++ options.ldifname[0] = ldif0; ++ free(dn); ++ } ++ ldap_msgfree(res); ++} ++ ++ + static int connect() + { + int i, rc, version; +@@ -906,6 +1011,7 @@ + die_exit("Unable to open file 'data.temp' for writing"); + if ( options.output&OUTPUT_DB && !(namedmaster = fopen("named.zones", "w")) ) + die_exit("Unable to open file 'named.zones' for writing"); ++ read_loccodes(); + read_dnszones(); + if (namedmaster) + fclose(namedmaster); +Gemeinsame Unterverzeichnisse: ldap2dns-0.3.1-p1/webadmin und ldap2dns-0.3.1/webadmin. diff --git a/ldap2dns.c b/ldap2dns.c index a54dc3d..d70d8bd 100644 --- a/ldap2dns.c +++ b/ldap2dns.c @@ -1,6 +1,6 @@ /* * Create data from an LDAP directory service to be used for tinydns - * $Id: ldap2dns.c,v 1.30 2001/08/09 10:35:49 jrief Exp $ + * $Id: ldap2dns.c,v 1.33 2003/01/20 14:33:25 jrief Exp $ * Copyright 2000 by Jacob Rief * License: GPL version 2 or later. See http://www.fsf.org for details */ @@ -14,7 +14,7 @@ #include #define UPDATE_INTERVALL 59 -#define LDAP_CONF "/etc/ldap.conf" +#define LDAP_CONF "/etc/ldap/ldap.conf" #define OUTPUT_DATA 1 #define OUTPUT_DB 2 #define MAXHOSTS 10 @@ -58,8 +58,15 @@ static struct char minimum[12]; char ttl[12]; char timestamp[20]; + char location[2]; } zone; +static struct +{ + char locname[3]; + char member[256][16]; +} loc_rec; + struct resourcerecord { char cn[64]; @@ -72,6 +79,7 @@ struct resourcerecord char ttl[12]; char timestamp[20]; char preference[12]; + char location[2]; #if defined DRAFT_RFC char rr[1024]; char aliasedobjectname[256]; @@ -85,6 +93,7 @@ static struct char searchbase[128]; char binddn[128]; char hostname[MAXHOSTS][128]; + char urildap[MAXHOSTS][128]; int port[MAXHOSTS]; char password[128]; int usedhosts; @@ -94,6 +103,7 @@ static struct int verbose; char ldifname[128]; char exec_command[128]; + int use_tls[MAXHOSTS]; } options; @@ -130,7 +140,8 @@ static void set_datadir(void) static void print_usage(void) { print_version(); - printf("usage: ldap2dns[d] [-D binddn] [-b searchbase] [-o data|db] [-h host] [-p port] [-w password] [-L[filename]] [-u numsecs] [-v[v]] [-V]\n\n"); + printf("usage: ldap2dns[d] [-D binddn] [-b searchbase] [-o data|db] [-h host] [-p port] [-H hostURI] " + "[-w password] [-L[filename]] [-u numsecs] [-v[v]] [-V]\n\n"); printf("ldap2dns connects to an LDAP server reads the DNS information stored in objectclasses\n" "\t\tDNSzone and DNSrrset and writes a file to be used by tinydns or named.\n" "\t\tldap2dnsd starts as background-job and continouesly updates DNS information.\n"); @@ -143,6 +154,7 @@ static void print_usage(void) printf(" -L[filename] Print output in LDIF format for reimport\n"); printf(" -h host\tHostname of LDAP server, defaults to localhost\n"); printf(" -p port\tPortnumber to connect to LDAP server, defaults to %d\n", LDAP_PORT); + printf(" -H hostURI\tURI (ldap://hostname or ldaps://hostname of LDAP server\n"); printf(" -u numsecs\tUpdate DNS data after numsecs. Defaults to %d if started as daemon.\n\t\t" "Important notice: data.cdb is rewritten only after DNSserial in DNSzone is increased.\n", UPDATE_INTERVALL); @@ -159,7 +171,18 @@ static void parse_hosts(char* buf) options.usedhosts = 0; for (i = 0; i=2) { + if (!strncasecmp(buf, "ldaps://", 8) || !strncasecmp(buf, "ldap://", 7)) { + // LDAP-URI is given/found, at the moment only the standard-ports 389 and 636 are supported + if (!strncasecmp(buf, "ldap://", 7)) + options.use_tls[i] = 1; + if ((k = sscanf(buf, "%128s %512[A-Za-z0-9 .:/_+-]", value, rest))>=1) { + strcpy(options.urildap[i], value); + options.usedhosts++; + if (k==1) + break; + buf = rest; + } else break; + } else if ((k = sscanf(buf, "%128s:%d %512[A-Za-z0-9 .:_+-]", value, &port, rest))>=2) { strcpy(options.hostname[i], value); options.port[i] = port; options.usedhosts++; @@ -194,6 +217,8 @@ static int parse_options() int i; if (sscanf(buf, "BASE %128s", value)==1) strcpy(options.searchbase, value); + if (sscanf(buf, "URI %512[A-Za-z0-9 .:/_+-]", value)==1) + parse_hosts(value); if (sscanf(buf, "HOST %512[A-Za-z0-9 .:_+-]", value)==1) parse_hosts(value); if (sscanf(buf, "PORT %d", &len)==1) @@ -239,7 +264,7 @@ static int parse_options() options.ldifname[0] = '\0'; strcpy(options.password, ""); strcpy(options.exec_command, ""); - while ( (len = getopt(main_argc, main_argv, "b:D:e:h:o:p:u:V:v::w:L::"))>0 ) { + while ( (len = getopt(main_argc, main_argv, "b:D:e:h:H:o:p:u:V:v::w:L::"))>0 ) { if (optarg && strlen(optarg)>127) { fprintf(stderr, "argument %s too long\n", optarg); continue; @@ -260,6 +285,10 @@ static int parse_options() strcpy(options.hostname[0], optarg); options.usedhosts = 1; break; + case 'H': + strcpy(options.urildap[0], optarg); + options.usedhosts = 1; + break; case 'L': if (optarg==NULL) strcpy(options.ldifname, "-"); @@ -339,19 +368,19 @@ static void write_rr(struct resourcerecord* rr, int ipdx, int znix) if (tinyfile) { if (znix==0) { if (ipdx<=0 && rr->cipaddr[0]) { - fprintf(tinyfile, "&%s::%s:%s:%s\n", rr->dnsdomainname, rr->cname, rr->ttl, rr->timestamp); + fprintf(tinyfile, "&%s::%s:%s:%s:%s\n", rr->dnsdomainname, rr->cname, rr->ttl, rr->timestamp, rr->location); if (rr->cname[0]) - fprintf(tinyfile, "=%s:%s:%s:%s\n", rr->cname, rr->cipaddr, rr->ttl, rr->timestamp); + fprintf(tinyfile, "=%s:%s:%s:%s:%s\n", rr->cname, rr->cipaddr, rr->ttl, rr->timestamp, rr->location); if (ipdx==0) - fprintf(tinyfile, "+%s:%s:%s:%s\n", rr->cname, rr->ipaddr[0], rr->ttl, rr->timestamp); + fprintf(tinyfile, "+%s:%s:%s:%s:%s\n", rr->cname, rr->ipaddr[0], rr->ttl, rr->timestamp, rr->location); } else if (ipdx<0) - fprintf(tinyfile, "&%s::%s:%s:%s\n", rr->dnsdomainname, rr->cname, rr->ttl, rr->timestamp); + fprintf(tinyfile, "&%s::%s:%s:%s:%s\n", rr->dnsdomainname, rr->cname, rr->ttl, rr->timestamp, rr->location); else if (ipdx==0) - fprintf(tinyfile, "&%s:%s:%s:%s:%s\n", rr->dnsdomainname, rr->ipaddr[0], rr->cname, rr->ttl, rr->timestamp); + fprintf(tinyfile, "&%s:%s:%s:%s:%s:%s\n", rr->dnsdomainname, rr->ipaddr[0], rr->cname, rr->ttl, rr->timestamp, rr->location); else if (ipdx>0 && rr->cname[0]) - fprintf(tinyfile, "+%s:%s:%s:%s\n", rr->cname, rr->ipaddr[ipdx], rr->ttl, rr->timestamp); + fprintf(tinyfile, "+%s:%s:%s:%s:%s\n", rr->cname, rr->ipaddr[ipdx], rr->ttl, rr->timestamp, rr->location); } else if (ipdx<=0) { - fprintf(tinyfile, "&%s::%s:%s:%s\n", rr->dnsdomainname, rr->cname, rr->ttl, rr->timestamp); + fprintf(tinyfile, "&%s::%s:%s:%s:%s\n", rr->dnsdomainname, rr->cname, rr->ttl, rr->timestamp, rr->location); } } if (namedzone) { @@ -363,19 +392,19 @@ static void write_rr(struct resourcerecord* rr, int ipdx, int znix) if (tinyfile) { if (znix==0) { if (ipdx<=0 && rr->cipaddr[0]) { - fprintf(tinyfile, "@%s::%s:%s:%s:%s\n", rr->dnsdomainname, rr->cname, rr->preference, rr->ttl, rr->timestamp); + fprintf(tinyfile, "@%s::%s:%s:%s:%s:%s\n", rr->dnsdomainname, rr->cname, rr->preference, rr->ttl, rr->timestamp, rr->location); if (rr->cname[0]) - fprintf(tinyfile, "=%s:%s:%s:%s\n", rr->cname, rr->cipaddr, rr->ttl, rr->timestamp); + fprintf(tinyfile, "=%s:%s:%s:%s:%s\n", rr->cname, rr->cipaddr, rr->ttl, rr->timestamp, rr->location); if (ipdx==0) - fprintf(tinyfile, "+%s:%s:%s:%s\n", rr->cname, rr->ipaddr[0], rr->ttl, rr->timestamp); + fprintf(tinyfile, "+%s:%s:%s:%s:%s\n", rr->cname, rr->ipaddr[0], rr->ttl, rr->timestamp, rr->location); } else if (ipdx<0) - fprintf(tinyfile, "@%s::%s:%s:%s:%s\n", rr->dnsdomainname, rr->cname, rr->preference, rr->ttl, rr->timestamp); + fprintf(tinyfile, "@%s::%s:%s:%s:%s:%s\n", rr->dnsdomainname, rr->cname, rr->preference, rr->ttl, rr->timestamp, rr->location); else if (ipdx==0) - fprintf(tinyfile, "@%s:%s:%s:%s:%s:%s\n", rr->dnsdomainname, rr->ipaddr[0], rr->cname, rr->preference, rr->ttl, rr->timestamp); + fprintf(tinyfile, "@%s:%s:%s:%s:%s:%s:%s\n", rr->dnsdomainname, rr->ipaddr[0], rr->cname, rr->preference, rr->ttl, rr->timestamp, rr->location); else if (ipdx>0 && rr->cname[0]) - fprintf(tinyfile, "+%s:%s:%s:%s\n", rr->cname, rr->ipaddr[ipdx], rr->ttl, rr->timestamp); + fprintf(tinyfile, "+%s:%s:%s:%s:%s\n", rr->cname, rr->ipaddr[ipdx], rr->ttl, rr->timestamp, rr->location); } else if (ipdx<=0) { - fprintf(tinyfile, "@%s::%s:%s:%s:%s\n", rr->dnsdomainname, rr->cname, rr->preference, rr->ttl, rr->timestamp); + fprintf(tinyfile, "@%s::%s:%s:%s:%s:%s\n", rr->dnsdomainname, rr->cname, rr->preference, rr->ttl, rr->timestamp, rr->location); } } if (namedzone) { @@ -386,9 +415,9 @@ static void write_rr(struct resourcerecord* rr, int ipdx, int znix) } else if ( strcasecmp(rr->type, "A")==0) { if (tinyfile) { if (ipdx<=0 && rr->cipaddr[0]) - fprintf(tinyfile, "%s%s:%s:%s:%s\n", (znix==0 ? "=" : "+"), rr->dnsdomainname, rr->cipaddr, rr->ttl, rr->timestamp); + fprintf(tinyfile, "%s%s:%s:%s:%s:%s\n", (znix==0 ? "=" : "+"), rr->dnsdomainname, rr->cipaddr, rr->ttl, rr->timestamp, rr->location); if (ipdx>=0) - fprintf(tinyfile, "+%s:%s:%s:%s\n", rr->dnsdomainname, rr->ipaddr[ipdx], rr->ttl, rr->timestamp); + fprintf(tinyfile, "+%s:%s:%s:%s:%s\n", rr->dnsdomainname, rr->ipaddr[ipdx], rr->ttl, rr->timestamp, rr->location); } if (namedzone) { if (ipdx<=0 && rr->cipaddr[0]) @@ -410,17 +439,17 @@ static void write_rr(struct resourcerecord* rr, int ipdx, int znix) strcpy(buf, rr->dnsdomainname); } if (tinyfile) - fprintf(tinyfile, "^%s:%s:%s:%s\n", buf, rr->cname, rr->ttl, rr->timestamp); + fprintf(tinyfile, "^%s:%s:%s:%s:%s\n", buf, rr->cname, rr->ttl, rr->timestamp, rr->location); if (namedzone) fprintf(namedzone, "%s.\tIN PTR\t%s.\n", buf, rr->cname); } else if (strcasecmp(rr->type, "CNAME")==0) { if (tinyfile) - fprintf(tinyfile, "C%s:%s:%s:%s\n", rr->dnsdomainname, rr->cname, rr->ttl, rr->timestamp); + fprintf(tinyfile, "C%s:%s:%s:%s:%s\n", rr->dnsdomainname, rr->cname, rr->ttl, rr->timestamp, rr->location); if (namedzone) fprintf(namedzone, "%s.\tIN CNAME\t%s.\n", rr->dnsdomainname, rr->cname); } else if (strcasecmp(rr->type, "TXT")==0) { if (tinyfile) - fprintf(tinyfile, "'%s:%s:%s:%s\n", rr->dnsdomainname, rr->cname, rr->ttl, rr->timestamp); + fprintf(tinyfile, "'%s:%s:%s:%s:%s\n", rr->dnsdomainname, rr->cname, rr->ttl, rr->timestamp, rr->location); if (namedzone) fprintf(namedzone, "%s.\tIN TXT\t%s.\n", rr->dnsdomainname, rr->cname); } @@ -474,7 +503,7 @@ static void read_resourcerecords(char* dn, int znix) LDAPMessage* m; int ldaperr; - if ( (ldaperr = ldap_search_s(ldap_con, dn, LDAP_SCOPE_ONELEVEL, "objectclass=DNSrrset", NULL, 0, &res))!=LDAP_SUCCESS ) + if ( (ldaperr = ldap_search_s(ldap_con, dn, LDAP_SCOPE_SUBTREE, "objectclass=DNSrrset", NULL, 0, &res))!=LDAP_SUCCESS ) die_ldap(ldaperr); for (m = ldap_first_entry(ldap_con, res); m; m = ldap_next_entry(ldap_con, m)) { BerElement* ber = NULL; @@ -494,6 +523,7 @@ static void read_resourcerecords(char* dn, int znix) rr.ttl[0] = '\0'; rr.timestamp[0] = '\0'; rr.preference[0] = '\0'; + rr.location[0] = '\0'; #if defined DRAFT_RFC rr.aliasedobjectname[0] = '\0'; rr.rr[0] = '\0'; @@ -564,6 +594,11 @@ static void read_resourcerecords(char* dn, int znix) rr.preference[0] = '\0'; else if (options.ldifname[0]) fprintf(ldifout, "%s: %s\n", attr, bvals[0]->bv_val); + } else if (strcasecmp(attr, "DNSlocation")==0) { + if (sscanf(bvals[0]->bv_val, "%s", rr.location)!=1) + rr.location[0] = '\0'; + else if (options.ldifname[0]) + fprintf(ldifout, "%s: %s\n", attr, bvals[0]->bv_val); } #if defined DRAFT_RFC else if (strcasecmp(attr, "DNSrr")==0) { @@ -611,17 +646,17 @@ static void write_zone(void) char soa[20]; if (tinyfile) { - fprintf(tinyfile, "Z%s:%s:%s:%s:%s:%s:%s:%s:%s:%s\n", + fprintf(tinyfile, "Z%s:%s:%s:%s:%s:%s:%s:%s:%s:%s:%s\n", zone.domainname, zone.zonemaster, zone.adminmailbox, zone.serial, zone.refresh, zone.retry, zone.expire, - zone.minimum, zone.ttl, zone.timestamp); + zone.minimum, zone.ttl, zone.timestamp, zone.location); } if (namedmaster) { fprintf(namedmaster, "zone \"%s\" %s {\n\ttype master;\n\tfile \"%s.db\";\n};\n", zone.domainname, zone.class, zone.domainname); } if (namedzone) { - fprintf(namedzone, "# Automatically generated by ldap2dns - DO NOT EDIT!\n"); + fprintf(namedzone, "; Automatically generated by ldap2dns - DO NOT EDIT!\n"); if (zone.ttl[0]) fprintf(namedzone, "$TTL %s\n", zone.ttl); else @@ -677,7 +712,7 @@ static void read_dnszones(void) if (tinyfile) fprintf(tinyfile, "# Automatically generated by ldap2dns - DO NOT EDIT!\n"); if (namedmaster) - fprintf(namedmaster, "# Automatically generated by ldap2dns - DO NOT EDIT!\n"); + fprintf(namedmaster, "; Automatically generated by ldap2dns - DO NOT EDIT!\n"); if ( (ldaperr = ldap_search_s(ldap_con, options.searchbase[0] ? options.searchbase : NULL, LDAP_SCOPE_SUBTREE, "objectclass=DNSzone", NULL, 0, &res))!=LDAP_SUCCESS ) die_ldap(ldaperr); for (m = ldap_first_entry(ldap_con, res); m; m = ldap_next_entry(ldap_con, m)) { @@ -696,6 +731,7 @@ static void read_dnszones(void) zone.minimum[0] = '\0'; zone.ttl[0] = '\0'; zone.timestamp[0] = '\0'; + zone.location[0] = '\0'; dn = ldap_get_dn(ldap_con, m); if (options.ldifname[0]) fprintf(ldifout, "dn: %s\n", dn); @@ -761,6 +797,11 @@ static void read_dnszones(void) zone.timestamp[0] = '\0'; else if (options.ldifname[0]) fprintf(ldifout, "%s: %s\n", attr, zone.timestamp); + } else if (strcasecmp(attr, "DNSlocation")==0) { + if (sscanf(bvals[0]->bv_val, "%2s", zone.location)!=1) + zone.location[0] = '\0'; + else if (options.ldifname[0]) + fprintf(ldifout, "%s: %s\n", attr, zone.location); } } ldap_value_free_len(bvals); @@ -794,14 +835,124 @@ static void read_dnszones(void) ldap_msgfree(res); } +static void write_loccode(int lidx) +{ + if (tinyfile) { + fprintf(tinyfile, "%%%s:%s\n", loc_rec.locname, loc_rec.member[lidx]); + } + if (options.ldifname[0]) + fprintf(ldifout, "\n"); +} + + +static void read_loccodes(void) +{ + LDAPMessage* res = NULL; + LDAPMessage* m; + int ldaperr; + + if (tinyfile) + fprintf(tinyfile, "# Location Codes (if any) - generated by ldap2dns - DO NOT EDIT!\n"); + + if ( (ldaperr = ldap_search_s(ldap_con, options.searchbase[0] ? options.searchbase : NULL, + LDAP_SCOPE_SUBTREE, + "objectclass=DNSloccodes", + NULL, + 0, + &res) + )!=LDAP_SUCCESS ) + die_ldap(ldaperr); + for (m = ldap_first_entry(ldap_con, res); m; m = ldap_next_entry(ldap_con, m)) { + BerElement* ber = NULL; + char* attr; + char* dn = ldap_get_dn(ldap_con, m); + int i, locmembers = 0; + char l_members[256][15]; + //char loc[256][64]; + char loc[2]; + char ldif0; + + loc_rec.locname[0] = '\0'; + if (options.ldifname[0]) + fprintf(ldifout, "dn: %s\n", dn); + for (attr = ldap_first_attribute(ldap_con, m, &ber); attr; attr = ldap_next_attribute(ldap_con, m, ber)) { + struct berval** bvals = ldap_get_values_len(ldap_con, m, attr); + if (bvals!=NULL) { + if (bvals[0] && bvals[0]->bv_len>0) { + if (strcasecmp(attr, "objectclass")==0 + || strcasecmp(attr, "cn")==0) { + if (options.ldifname[0]) + fprintf(ldifout, "%s: %s\n", attr, bvals[0]->bv_val); + } else if (strcasecmp(attr, "DNSlocation")==0) { + if (sscanf(bvals[0]->bv_val, "%2s", loc_rec.locname)!=1) + loc_rec.locname[0] = '\0'; + else if (options.ldifname[0]) + fprintf(ldifout, "%s: %s\n", attr, loc_rec.locname); + } else if (strcasecmp(attr, "DNSipaddr")==0) { + for (locmembers = 0; bvals[locmembers] && locmembers<256; locmembers++) { + if (sscanf(bvals[locmembers]->bv_val, "%15s", loc_rec.member[locmembers])!=1) + loc_rec.member[locmembers][0] = '\0'; + else if (options.ldifname[0]) + fprintf(ldifout, "%s: %s\n", attr, loc_rec.member[locmembers]); + } + } else { + if (options.ldifname[0]) + fprintf(ldifout, "%s: %s\n", attr, bvals[0]->bv_val); + } + } + ldap_value_free_len(bvals); + } + } + ldif0 = options.ldifname[0]; + if (options.verbose&1) + printf("locationcodename: %s (%d members)\n", loc_rec.locname, locmembers); + for (i = 0; i0) + options.ldifname[0] = '\0'; + write_loccode(i); + if (options.ldifname[0]) + fprintf(ldifout, "\n"); + } + options.ldifname[0] = ldif0; + free(dn); + } + ldap_msgfree(res); +} + + static int connect() { - int i; + int i, rc, version; for (i = 0; i 0) { + rc = ldap_initialize(&ldap_con, options.urildap[i]); + if (options.verbose&1 && rc == LDAP_SUCCESS) { + printf("ldap_initialization successful (%s)\n", options.urildap[i]); + } else if ( rc != LDAP_SUCCESS ) { + printf("ldap_initialization to %s failed %d\n", options.urildap[i], ldap_err2string(rc)); + ldap_con = NULL; + return 0; + } + version = LDAP_VERSION3; + if ( (rc=ldap_set_option(ldap_con, LDAP_OPT_PROTOCOL_VERSION, &version)) != LDAP_SUCCESS ) { + printf("ldap_set_option to %s failed with err %s!\n", options.urildap[i], ldap_err2string(rc)); + ldap_con = NULL; + return 0; + } + if ( options.use_tls[i] && (rc=ldap_start_tls_s( ldap_con, NULL, NULL )) != LDAP_SUCCESS ) { + printf("ldap_start_tls_s to %s failed with err %s!\n", options.urildap[i], ldap_err2string(rc)); + ldap_con = NULL; + return 0; + } + } else { + ldap_con = ldap_init(options.hostname[i], options.port[i]); + } if (ldap_simple_bind_s(ldap_con, options.binddn, options.password)==LDAP_SUCCESS) { - if (options.verbose&1) + if (options.verbose&1 && strlen(options.urildap[i]) > 0) { + printf("Connected to %s as \"%s\"\n", options.urildap[i], options.binddn); + } else if (options.verbose&1) { printf("Connected to %s:%d as \"%s\"\n", options.hostname[i], options.port[i], options.binddn); + } return 1; } } @@ -860,6 +1011,7 @@ int main(int argc, char** argv) die_exit("Unable to open file 'data.temp' for writing"); if ( options.output&OUTPUT_DB && !(namedmaster = fopen("named.zones", "w")) ) die_exit("Unable to open file 'named.zones' for writing"); + read_loccodes(); read_dnszones(); if (namedmaster) fclose(namedmaster); diff --git a/webadmin/.htaccess b/webadmin/.htaccess new file mode 100644 index 0000000..070e8fc --- /dev/null +++ b/webadmin/.htaccess @@ -0,0 +1,2 @@ +AddType application/x-httpd-php .php +DirectoryIndex index.php diff --git a/webadmin/common.inc b/webadmin/common.inc new file mode 100644 index 0000000..f07931e --- /dev/null +++ b/webadmin/common.inc @@ -0,0 +1,81 @@ +

$errmsg


\n"; + log_action("error: ".$errmsg); +} + +function log_action($errmsg) +{ + global $LOGFILE, $REMOTE_ADDR, $PHP_AUTH_USER; + $fd = fopen("$LOGFILE", "a"); + fwrite($fd, "[".date("H:i:s d/M/Y")."] $PHP_AUTH_USER@$REMOTE_ADDR $errmsg\n"); + fclose($fd); +} + +# Use this function to determine contraints on objects and returns a set +# of characters with the following meaning: +# o: binddn owns the object +# a: binddn is administrator +# m: binddn is member +function check_constraint($dn = "") +{ + global $ldap, $binddn, $BASEDN; + $result = ""; + $num_owners = 0; + if (strlen($dn)>0) { + // get owners for this object + $query = ldap_read($ldap, $dn, "(objectclass=*)", array("owner")); + $entries = ldap_get_entries($ldap, $query); + ldap_free_result($query); + $num_owners = $entries[0][owner][count]; + for ($i = 0; $i<$num_owners; $i++) { + if ($entries[0][owner][$i]==$binddn) { + $result .= "o"; + $num_owners = 0; + } + } + } + // get administrators for BASEDN + $query = ldap_read($ldap, $BASEDN, "(objectclass=*)", array("administrator", "member")); + $entries = ldap_get_entries($ldap, $query); + ldap_free_result($query); + for ($i = 0; $i<$entries[0][administrator][count]; $i++) { + if ($entries[0][administrator][$i]==$binddn) { + $result .= "a"; + break; + } + } + if ($num_owners==0) { + // only objects owned by nobody except binddn are granted to members + for ($i = 0; $i<$entries[0][member][count]; $i++) { + if ($entries[0][member][$i]==$binddn) { + $result .= "m"; + break; + } + } + } + print ""; + return $result; +} + +?> diff --git a/webadmin/config.inc b/webadmin/config.inc new file mode 100644 index 0000000..5ee0603 --- /dev/null +++ b/webadmin/config.inc @@ -0,0 +1,44 @@ + "", + "dnsserial" => "", + "dnsclass" => "IN", + "dnstype" => "SOA", + "dnsexpire" => "604800", + "dnsretry" => "3600", + "dnsminimum" => "86400", + "dnsrefresh" => "10800", + "dnsttl" => "3600", + "dnszonemaster" => "ns1.company.com.", + "dnsadminmailbox" => "hostmaster.company.com.", +); +$ZONE_ENTRY = array( + array("cn"=>"NS1:", "objectclass"=>"dnsrrset", "dnstype"=>"NS", "dnsclass"=>"IN", "dnsttl"=>"3600", "dnscname"=>"ns1.company.com."), + array("cn"=>"NS2:", "objectclass"=>"dnsrrset", "dnstype"=>"NS", "dnsclass"=>"IN", "dnsttl"=>"3600", "dnscname"=>"ns2.company.com."), +); + +#################### whois configuration #################### +$WHOISSERVERS = array( "at"=>"whois.nic.at", "de"=>"whois.denic.de", "ch"=>"whois.nic.ch", + "com"=>"whois.networksolutions.com", "net"=>"whois.networksolutions.com", + "org"=>"whois.networksolutions.com", "be"=>"whois.dns.be", "cz"=>"whois.nic.cz", + "fr"=>"whois.nic.fr", "hu"=>"whois.nic.hu", "it"=>"whois.nic.it", "dk"=>"whois.dk-hostmaster.dk", + "li"=>"whois.nic.li", "lu"=>"whois.dns.lu", "cc"=>"whois.nic.cc", "uk"=>"whois.nic.uk" ); +?> diff --git a/webadmin/footer.inc b/webadmin/footer.inc new file mode 100644 index 0000000..8d4ef1e --- /dev/null +++ b/webadmin/footer.inc @@ -0,0 +1,3 @@ +
+ + diff --git a/webadmin/framesets.inc b/webadmin/framesets.inc new file mode 100644 index 0000000..29186c3 --- /dev/null +++ b/webadmin/framesets.inc @@ -0,0 +1,8 @@ +DNS Zone Admin + + + + + You need a frame capable browser + + diff --git a/webadmin/icons/branch-cont.gif b/webadmin/icons/branch-cont.gif new file mode 100644 index 0000000000000000000000000000000000000000..29a4e9b01bfda9832f8e5144d7c40ef125d83eba GIT binary patch literal 849 zcmZ?wbhEHb6lM@$_|5+Z^fq{uZ2b2>)dBTB1kAam##$&^R vgUuYmS}`X!EIiyUpe)CuFfqxcTR<~QWP@O`V?UpxnaIfrPYyINFjxZsw$2TT literal 0 HcmV?d00001 diff --git a/webadmin/icons/branch-end.gif b/webadmin/icons/branch-end.gif new file mode 100644 index 0000000000000000000000000000000000000000..b3d5b2f933ec08d091fe566785800aa0f286ac71 GIT binary patch literal 843 zcmZ?wbhEHb6lM@$_|5+Z^fq{uZ2b2>)dBTB1gMpPp#$&^R ogUuYmS}`X!EIiyUpe)CuFfqxcTR<~QWP{-1BmD}BY%C1c0BXbvd;kCd literal 0 HcmV?d00001 diff --git a/webadmin/icons/folder-closed.gif b/webadmin/icons/folder-closed.gif new file mode 100644 index 0000000000000000000000000000000000000000..b785fc431501a702ec108ad8a56e031b5e2af636 GIT binary patch literal 887 zcmZ?wbhEHb6krfw_|CwPoSdA!_5YM9$>+``Kfjm#{eAWSQ7{?;BPIkCf3h$#FfcOc zFaQB4PcU$VFfg-7I21H6G;#>@sT`Ql;MmH+?KQ{a!vh9p3FE9Y8Vm=HGATHBvE2Ol y_{3yY-Z?HW1D|?L)QmrrqiLLSW)`bg(4Cut4d>@OG&41LY*}$}u`4qZgEas?(i}Me literal 0 HcmV?d00001 diff --git a/webadmin/icons/folder-open.gif b/webadmin/icons/folder-open.gif new file mode 100644 index 0000000000000000000000000000000000000000..ff82c95bfe3908e52f4ec9657b96f41623d79a5a GIT binary patch literal 911 zcmZ?wbhEHb6krfw_|CwPoSdAUJtceV|0z?F&z%FJDbMd^e}7;7e-w;{zz7Hd#h)yU z3=B*RIt)Mn$`cG6ISi~EDh?A4Ff?)qb15V&SjgDSC1_M~V?)BhW^T=_5(|a{hnN(c zyJQj;C^NEX1g}zINNDh6VNW_W<>V#RhRMdoaw}d6E+Z^fq{uZ2b2>)dBTB1o`ID^#$&^R fgUuYmS}`X!EIiyUpzJlrW8RZaks1PuKUo+V7#JCJ7=QqjCmc958JIa_JT@#i p*vuiU6?0<4!o%$X%5p3U6O&xJ1q|)3yqJ*e+|T34$HT#34FD;J4kZ8p literal 0 HcmV?d00001 diff --git a/webadmin/icons/minus-cont.gif b/webadmin/icons/minus-cont.gif new file mode 100644 index 0000000000000000000000000000000000000000..a86b6b67c35e741347b953bdc9fdb81a50688823 GIT binary patch literal 867 zcmZ?wbhEHb6lM@$_|5+Z^fq{uZ2b2>)dBTCifq|7n#$&?* z$3{jzHJgqA#l!6a%1$v66Bao)i>YR*%=nnt(68X=x95a`V#8#0R+X5QlaxJM6`k|m NXiR)|pn-wG8UWfl6uAHZ literal 0 HcmV?d00001 diff --git a/webadmin/icons/minus-end.gif b/webadmin/icons/minus-end.gif new file mode 100644 index 0000000000000000000000000000000000000000..dc3b247f8a80477970ab567d4c3303c88ddaef6e GIT binary patch literal 864 zcmZ?wbhEHb6lM@$_|5+Z^fq{uZ2b2>)dBTCimVuQ+#$&?* z$3{jzHJgqA#l!6a%1$v66Bao)i>YR*%=nnt(68X=x95a`V#8#0R+X5QlaxJM6`k|u KSQ;xZSOWl*s}d6c literal 0 HcmV?d00001 diff --git a/webadmin/icons/plus-cont.gif b/webadmin/icons/plus-cont.gif new file mode 100644 index 0000000000000000000000000000000000000000..b05c44849766ad5cf83f1d6339c9347e42313a5a GIT binary patch literal 872 zcmZ?wbhEHb6lM@$_|5+Z^fq{uZ2b2>)dBTCim4TH*#$&?* z$3{jrCW#pz6b?1>%6iT5xR`jPm0#6OWyi)v?tSvi9Ws_hk6hc-SQ#RA200v>uII>g SL?T$(bCRO{sS*hR25SIQAr&hC literal 0 HcmV?d00001 diff --git a/webadmin/icons/plus-end.gif b/webadmin/icons/plus-end.gif new file mode 100644 index 0000000000000000000000000000000000000000..b617d611354eb2604fbeba61fbbbaf7184fb3f7d GIT binary patch literal 871 zcmZ?wbhEHb6lM@$_|5+Z^fq{uZ2b2>)dBTCig@Khr#$&?* z$3{jrCW#pz6b?1>%6iT5xR`jPm0#6OWyi)v?tSvi9Ws_hk6hc-SQ#RA200v>uII>g RL?T$(bCP`VGae2GYXCj46z~85 literal 0 HcmV?d00001 diff --git a/webadmin/icons/zone_forb.gif b/webadmin/icons/zone_forb.gif new file mode 100644 index 0000000000000000000000000000000000000000..94c250ccf9d5693d80fd4385928800a1d933b529 GIT binary patch literal 972 zcma)5Ur1A76hF?}y?1NG*i@zuGFgT*m4OJ;Ml7|-VB%O3B7qYN>LHka;9C&1tqm?X zNaCWSKVUHJ4?Zj(dTKWGA(4=vQm_z<%oSSp2dszuI^W&2(NhP`{m#Gd{C?+r+%}if z*4V299qa%Kwe(Stsb!H`C|#sS}7YQ@4BB<=XQ5KMxJj-CauQ z>gsALm6ByS5{V2B4tl*_qtS@H(&;p7nJ2+bG0)?n>$MqF4hX6+YR&L)w|{~pzwuxz zPY{;#!~|Gd=OON%Ccf`H$o(%#rtJkmPW&F6Y4PL0w>mU$bm_Hj%TJZyO%ZO zDDeWwnC}^rNT5I|+yB&Hyb9F&e!g*-4VNcBuMYqZBFxrG#Q!x$24snJp^CW~m7TaX z%8i&-1KcKZ!o9MwvYiB&`iJM^oZo_{9ru=aK0AocN}Z?gjw6U zd6n4O?<;^BM|}1!0p!Tu_a6G}E!bw5y*J0{QHj){7H$9S$@**}Mv2l;Q21xxLkax% zr{Wif8!v+zc7y#BAl`=tu_!+73qzqn@7DFMjB=vN)H&~832Th?-SgJuI~7-KYBiSj zHb+CE?y}ZXF&i2aj7|R2Y0LU#ZT!we=t(ej=-Eht YBdV4RX6H@oT=eOP`RJ`Fs|k+%0f^TER{#J2 literal 0 HcmV?d00001 diff --git a/webadmin/icons/zone_new.gif b/webadmin/icons/zone_new.gif new file mode 100644 index 0000000000000000000000000000000000000000..192039b1f78f275fc96c3395dafd515712b85639 GIT binary patch literal 947 zcmZ?wbhEHb6krfw_|5pl4v~rl4;Y!5g@tSi6q%ZsS$PyfPFz^n+$|x^AQ2(x$jC14)YkGKA)%2; zj<-RilJQXMBsLYE4vU1P9!wUTM`9){SnfNKU&_EBprFBjnuDZ)i^72y{u2eJxD{wP z9JoA@M@Ob(!Gniar$zE>yr_DReWjJ1Va8c40fq(!K7|u=wWq&zVBq=m>h9_d>kl{9khlgXTF+&2#@X|0iqy{~r_- zR9sx#($X?z%9Oo(_n!NI?%eFm;IQIb71T8}kh$NhrGo8LGu4ZGm<=FonJF0lw^J7$L_U#1kkJl2Mz#9WT5zy zg^__lia`e?2(r_GwPS%=m)A;`$17Y;DDs4|oSksQXZkjs6GBH!PN)P0PBk)YE9z8s z73%0J$vWA=#Cj-!nWDo!V literal 0 HcmV?d00001 diff --git a/webadmin/icons/zone_val.gif b/webadmin/icons/zone_val.gif new file mode 100644 index 0000000000000000000000000000000000000000..54433f35b35e04ae422acd3ebd1c6ade63481f2b GIT binary patch literal 264 zcmZ?wbhEHb6krfwIP#wX4E{4DGcZi~FCihJnarS>{9khlgXTF+&2#@X|0iqy{~r_- zR9sx#($X?z%9Oo(_n!NI?%eFm;IQIb71T8}kh$NhrGo8LGu4ZGm<=FonJF0lw^J7$LHyjSOWl&qg|f> literal 0 HcmV?d00001 diff --git a/webadmin/index.php b/webadmin/index.php new file mode 100644 index 0000000..902c5ca --- /dev/null +++ b/webadmin/index.php @@ -0,0 +1,725 @@ +0) { + zone_edit_plus($zonedn); + } else { + new_zone($HTTP_GET_VARS[zonename]); + } + } + include("footer.inc"); + break; + case "editzone": + connect_ldap(); + include("mainheader.inc"); + if (isset($HTTP_POST_VARS[modifysoa])) { + modify_zone_soa($HTTP_POST_VARS[zonedn]); + log_action("modify_zone_soa: $HTTP_POST_VARS[zonedn]"); + } elseif (isset($HTTP_POST_VARS[addrrset])) { + add_rrset($HTTP_POST_VARS[zonedn]); + log_action("add_rrset: $HTTP_POST_VARS[zonedn]"); + } elseif (isset($HTTP_POST_VARS[modifyrrset])) { + if (isset($HTTP_POST_VARS[deleterrset])) { + delete_rrset($HTTP_POST_VARS[zonedn], $HTTP_POST_VARS[setdn]); + log_action("delete_rrset: $HTTP_POST_VARS[setdn]"); + } else { + modify_rrset($HTTP_POST_VARS[zonedn], $HTTP_POST_VARS[setdn]); + log_action("modify_rrset: ".$HTTP_POST_VARS[setdn]); + } + } + if (isset($HTTP_GET_VARS[zonedn])) + zone_edit_plus($HTTP_GET_VARS[zonedn]); + elseif (isset($HTTP_POST_VARS[zonedn])) + edit_zone_attrs($HTTP_POST_VARS[zonedn]); + include("footer.inc"); + break; + case "newzone": + connect_ldap(); + include("mainheader.inc"); + new_zone(); + include("footer.inc"); + break; + case "addzone": + connect_ldap(); + include("mainheader.inc"); + zone_edit_plus(add_zone()); + include("footer.inc"); + break; + case "removezone": + connect_ldap(); + if (isset($HTTP_GET_VARS[zonedn]) && remove_zone($HTTP_GET_VARS[zonedn])) { + include("xearthheader.inc"); + include("footer.inc"); + } + break; + } +} + + +function full_dns_list() +{ + global $ldap, $BASEDN, $ZONEEDIT, $HTTP_GET_VARS; + $letters = array( "0-9","A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q-R","S","T","U","V","W","X-Z" ); + if (isset($HTTP_GET_VARS[wait])) sleep($HTTP_GET_VARS[wait]); + if (isset($HTTP_GET_VARS[selet])) $selet = $HTTP_GET_VARS[selet]; +?> +
+ + Find  +
+" TARGET="main"> +  Add new Zone
+". + "". + "...$let
\n"; + } else { + $newselet = $selet.$let; + print "". + "". + "...$let
\n"; + continue; + } + $filter = "(&(objectclass=dnszone)"; + if (ereg("([0-9A-Z])-([0-9A-Z])", $let, $regs)) { + $filter .= "(|"; + for ($i = ord($regs[1]); $i<=ord($regs[2]); $i++) { + $filter .= "(cn=".chr($i)."*)"; + } + $filter .= "))"; + } else { + $filter .= "(cn=$let*))"; + } + $query = ldap_search($ldap, $BASEDN, $filter); + //ldap_sort($ldap, $query, "cn"); + $entries = ldap_get_entries($ldap, $query); + ldap_free_result($query); + for ($i = 0; $i<$entries[count]; $i++) { + $zonedn = $entries[$i]["dn"]; + $zonename = $entries[$i]["dnszonename"][0]; + $tree2 = ($i==$entries[count]-1 ? "end" : "cont"); + print "". + "". + " $zonename
\n"; + } + print "\n"; + } + #print "Without DNS-lookup
\n"; + } else { + print "With DNS-lookup
\n"; + } +} + +function individual_dns_list() +{ + global $ldap, $binddn, $BASEDN, $ZONEEDIT, $HTTP_GET_VARS; + $query = ldap_search($ldap, $BASEDN, "(&(objectclass=DNSzone)(owner=$binddn))"); + $entries = ldap_get_entries($ldap, $query); + for ($i = 0; $i<$entries[count]; $i++) { + $zonedn = $entries[$i][dn]; + $zonename = $entries[$i][dnszonename][0]; + $tree = ($i==$entries[count]-1 ? "end" : "cont"); + print "". + "". + " $zonename
\n"; + } +} + +function search_zone($zonename) +{ + global $ldap, $BASEDN; + $filter = "(&(objectclass=dnszone)(dnszonename=$zonename))"; + $query = ldap_search($ldap, $BASEDN, $filter); + $entries = ldap_get_entries($ldap, $query); + if ($entries[count]>1) { + $mesg = "Ambigous zonenames $zonename in
"; + for ($i = 0; $i<$entries[count]; $i++) { + $mesg .= "dn: ". + $entries[$i]["dn"]."
"; + } + print "

Warning: $mesg

"; + exit; + } + if ($entries[count]==1) { + return $entries[0][dn]; + } else switch (authorized($zonename)) { + case -2: + error_confirm("The zone does not belong to a valid top level domain"); + exit; + case -1: + error_confirm("The zone is owned by someone else"); + print_whois($zonename); + exit; + default: + return; + } +} + +function print_zone_soa($zonedata, $constr) +{ + print "Serial: "; + if (ereg("[amo]", $constr)) { + print ""; + } else { + print " ".$zonedata["dnsserial"]." "; + } + print "Refresh: "; + if (ereg("[amo]", $constr)) { + print ""; + } else { + print " ".$zonedata["dnsrefresh"]." "; + } + print "\nRetry: "; + if (ereg("[amo]", $constr)) { + print ""; + } else { + print " ".$zonedata["dnsretry"]." "; + } + print "\nExpire: "; + if (ereg("[amo]", $constr)) { + print ""; + } else { + print " ".$zonedata["dnsexpire"]." "; + } + print "\nMinimum: "; + if (ereg("[amo]", $constr)) { + print ""; + } else { + print " ".$zonedata["dnsminimum"]." "; + } + print "\nAdminmailbox: "; + if (ereg("[amo]", $constr)) { + print ""; + } else { + print " ".$zonedata["dnsadminmailbox"]." "; + } + print "\nZonemaster: "; + if (ereg("[amo]", $constr)) { + print ""; + } else { + print " ".$zonedata["dnszonemaster"]." "; + } + print "\nTime to live: "; + if (ereg("[amo]", $constr)) { + print ""; + } else { + print " ".$zonedata["dnsttl"]." "; + } + print "\n"; +} + +function get_zone_name($zonedn) +{ + global $ldap; + $query = ldap_read($ldap, $zonedn, "(objectclass=dnszone)", array("dnszonename")); + $entries = ldap_get_entries($ldap, $query); + $zonename = $entries[0][dnszonename][0]; + ldap_free_result($query); + return $zonename; +} + +function modify_zone_soa($zonedn) +{ + global $ldap, $ZONE_INFO, $HTTP_POST_VARS; + $zonename = get_zone_name($zonedn); + $entry = array(); + foreach ($ZONE_INFO as $za) { + if (strlen($HTTP_POST_VARS["$za"])>0) + $entry["$za"] = $HTTP_POST_VARS["$za"]; + } + if (ereg("[a]", check_constraint($zonedn))) { + $entry[dnszonename] = array("$zonename"); + for ($i = 0; isset($HTTP_POST_VARS["dnszonename$i"]); $i++) { + if (strlen($HTTP_POST_VARS["dnszonename$i"])>3) + array_push($entry[dnszonename], $HTTP_POST_VARS["dnszonename$i"]); + } + } + ldap_modify($ldap, $zonedn, $entry) or die("ldap_modify failed to update SOA for $zonedn"); +} + +function authorized($zonename) +{ + return 1; +} + +function zone_edit_plus($zonedn) +{ + $zonename = get_zone_name($zonedn); + $auth = authorized($zonename); + if ($auth==1) { + print "

The nameserver is active and authorized to handle this zone

\n"; + edit_zone_attrs($zonedn); + print_whois($zonename); + } elseif ($auth==0) { + print "

The nameserver is not active for this zone

\n"; + edit_zone_attrs($zonedn); + print_whois($zonename); + } elseif ($auth==-1) { + print "

The nameserver is not authorized to handle this zone

\n"; + edit_zone_attrs($zonedn); + print_whois($zonename); + } else { + print "

Zone $zonename does not not belong to a valid TLD

\n"; + delete_zone(); + } +} + +function edit_zone_attrs($zonedn) +{ + global $ldap, $ZONE_INFO, $ZONEEDIT, $HTTP_GET_VARS, $HTTP_POST_VARS; + if (isset($HTTP_GET_VARS[selet])) $selet = $HTTP_GET_VARS[selet]; elseif (isset($HTTP_POST_VARS[selet])) $selet = $HTTP_POST_VARS[selet]; + $query = ldap_read($ldap, $zonedn, "(objectclass=dnszone)"); + $entries = ldap_get_entries($ldap, $query); + $zonename = $entries[0][dnszonename][0]; + ldap_free_result($query); + $zonedn = $entries[0][dn]; + $zonename0 = $entries[0][dnszonename][0]; + $zonenames = array(); + for ($i = 1; $i<$entries[0][dnszonename][count]; $i++) { + array_push($zonenames, $entries[0][dnszonename][$i]); + } + $zonedata = array(); + foreach ($ZONE_INFO as $za) { + $zonedata[$za] = $entries[0][$za][0]; + } + + print "

Edit DNS zone $zonename0

"; + $zoneconstr = check_constraint($zonedn); + if (ereg("[a]", $zoneconstr)) { + # Print modifiable table for SOA + if (ereg("[f]", $selet)) { + print "
". + "". + ""; + } else { + print "". + "". + "". + ""; + } + print "\n"; + $zc = 0; + foreach ($zonenames as $zn) { + print "\n"; + $zc++; + } + if (ereg("[a]", $zoneconstr)) { + print "\n"; + } + print_zone_soa($zonedata, $zoneconstr); + print "
Aliasing Zonename: "; + if (ereg("[a]", $zoneconstr)) + print ""; + else + print "$zn"; + print "
Add aliasing Zonename: ". + "
". + "

"; + } else { + # Print non-modifiable table for SOA + print "\n"; + foreach ($zonenames as $zn) { + print "\n"; + } + print_zone_soa($zonedata, $zoneconstr); + print "
Aliasing Zonename: $zn

\n"; + } + + # Tables for RRsets + $query = ldap_list($ldap, $zonedn, "(objectclass=dnsrrset)"); + $rrsets = ldap_get_entries($ldap, $query); + ldap_free_result($query); + print "\n". + "". + "\n"; + for ($i = 0; $i<$rrsets[count]; $i++) { + $setdn = $rrsets[$i][dn]; + $setconstr = $zoneconstr.check_constraint($setdn); + $domainname = $rrsets[$i][dnsdomainname][0]; + $ipaddr = $rrsets[$i][dnsipaddr]; + $cipaddr = $rrsets[$i][dnscipaddr][0]; + $cname = $rrsets[$i][dnscname][0]; + $type = $rrsets[$i][dnstype][0]; + $ttl = $rrsets[$i][dnsttl][0]; + $preference = $rrsets[$i][dnspreference][0]; + if (ereg("[amo]", $setconstr)) { + if (ereg("[f]", $selet)) { + print "". + "". + "". + "". + ""; + } else { + print "". + "". + "". + ""; + } + } + if (ereg("[amo]", $setconstr)) { + print "
Delete"; + } + print ""; + if (ereg("[amo]", $setconstr)) { + print "\n"; + } else { + print "\n"; + } + } + if (ereg("[amo]", $setconstr)) { + if (ereg("[f]", $selet)) { + print "\n". + "". + "". + "". + "". + "". + "". + "". + ""; + } + print "
DNS NameTypeMappingTTL/Pref 
$type"; + if ($type=="CNAME" || $type=="MX" || $type=="NS") { + print ""; + if (ereg("[amo]", $setconstr)) + print "\n"; + else + print "\n"; + } + if ($type=="A" || $type=="MX" || $type=="NS") { + if (ereg("[a]", $setconstr)) { + print "". + "\n"; + } else if (isset($cipaddr)) { + print "\n"; + } + for ($k = 0; $k<$rrsets[$i][dnsipaddr][count]; $k++) { + print ""; + $ipaddr = $rrsets[$i][dnsipaddr][$k]; + if (ereg("[amo]", $setconstr)) + print "\n"; + else + print "\n"; + } + if (ereg("[amo]", $setconstr)) { + print "\n"; + } + } + print "
CName:
$cname
Canonical IP:
Canonical IP:$cipaddr
Modify IP:
$ipaddr
Add IP:
TTL: "; + if ($type=="MX") + print "
Pref: "; + print "
TTL: $ttl"; + if ($type=="MX") + print "
Pref: $preference"; + print "
 

\n"; + + print ""; + // 'Delete' form + $onclick = "if(confirm('Do you really want to remove zone: $zonename0 and all its resource records?'))"; + if (ereg("[f]", $selet)) { + $onclick .= "{ parent.frames.menu.location='$ZONEEDIT?call=dnslist&selet=$selet&wait=1';". + "parent.frames.main.location='$ZONEEDIT?call=removezone&zonedn=$zonedn&selet=$selet'; }"; + } else { + $onclick .= "{ parent.window.location='$ZONEEDIT?call=removezone&zonedn=$zonedn'; }"; + } + if (ereg("[am]", $setconstr)) { + print "\n"; + } + + // form for reset/refresh button + if (ereg("[f]", $selet)) { + print "". + "". + "". + ""; + } else { + print "". + "". + ""; + } + print "". + "
\n"; +} + +function new_zone($new_zonename = "") +{ + global $HTTP_GET_VARS, $ZONE_SOA, $ZONEEDIT, $BASEDN; + if (isset($HTTP_GET_VARS[selet])) $selet = $HTTP_GET_VARS[selet]; + $zonedata = $ZONE_SOA; + $zonedata[dnsserial] = new_serial(); + $onsubmit = "{ parent.frames.menu.location='$ZONEEDIT?call=dnslist&selet=$selet&wait=1'; }"; + print "

Add new DNS zone

"; + print "
". + "". + "". + "\n". + "\n"; + print_zone_soa($zonedata, check_constraint()); + print "
New Zonename: ". + "". + "
". + "". + "". + "". + "
\n". + "
"; +} + +function add_zone() +{ + global $ldap, $HTTP_POST_VARS, $BASEDN, $ZONE_SOA, $ZONE_ENTRY, $ZONE_INFO; + $zonedata = array(); + foreach ($ZONE_INFO as $za) { + if (strlen($HTTP_POST_VARS[$za])>0) { + $zonedata[$za] = $HTTP_POST_VARS[$za]; + } + } + $zonedata["cn"] = $zonedata["dnszonename"]; + $zonedata["objectclass"] = "dnszone"; + $zonedn = "cn=$zonedata[cn],$BASEDN"; + ldap_add($ldap, $zonedn, $zonedata) or die("Failed to add zonedn: $zonedn"); + + foreach ($ZONE_ENTRY as $ze) { + $dnch = "cn=$ze[cn],$zonedn"; + ldap_add($ldap, $dnch, $ze) or die("Failed to add rrset dn: $dnch"); + } + return $zonedn; +} + +function remove_zone($zonedn) +{ + global $ldap; + $query = ldap_list($ldap, $zonedn, "(objectclass=DNSrrset)"); + $entries = ldap_get_entries($ldap, $query); + ldap_free_result($query); + for ($i = 0; $i<$entries[count]; $i++) { + ldap_delete($ldap, $entries[$i][dn]) or die("Failed to delete dn: $entries[$i][dn]"); + } + ldap_delete($ldap, $zonedn) or die("Failed to delete dn: $zonedn"); + return 1; +} + +function new_serial($zonedn = 0) +{ + global $ldap; + $newserial = date("Ymd")."00"; + if ($zonedn) { + $query = ldap_read($ldap, $zonedn, "(objectclass=DNSzone)"); + $entries = ldap_get_entries($ldap, $query); + $oldserial = $entries[0][dnsserial][0]; + } + return ($newserial>$oldserial) ? $newserial : $oldserial+1; +} + +function add_rrset($zonedn) +{ + global $ldap, $binddn, $HTTP_POST_VARS, $DEFAULT_TTL, $DEFAULT_PREFERENCE; + if (!isset($HTTP_POST_VARS[dnsdomainname])) die("No domainname specified"); + if (strlen($HTTP_POST_VARS[dnsdomainname])>0) + $entry[dnsdomainname] = $HTTP_POST_VARS[dnsdomainname]; + if (!isset($HTTP_POST_VARS[dnstype])) die("No type specified"); + $entry[dnstype] = $HTTP_POST_VARS[dnstype]; + $entry[dnsclass] = "IN"; // INternet is hardcoded + $entry[dnsttl] = $DEFAULT_TTL; + // $entry[owner] = $binddn; + if ($entry[dnstype]=="MX" || $entry[dnstype]=="NS") { + for ($i = 1;; $i++) { + $setcn = "$entry[dnstype]$i:$entry[dnsdomainname]"; + $query = ldap_list($ldap, $zonedn, "(&(objectclass=dnsrrset)(cn=$setcn))"); + $rrset = ldap_get_entries($ldap, $query); + ldap_free_result($query); + if ($rrset[count]==0) + break; + } + if ($entry[dnstype]=="MX") + $entry[dnspreference] = $DEFAULT_PREFERENCE; + } else { + $setcn = "$entry[dnstype]:$entry[dnsdomainname]"; + $query = ldap_list($ldap, $zonedn, "(&(objectclass=dnsrrset)(cn=$setcn))"); + $rrset = ldap_get_entries($ldap, $query); + ldap_free_result($query); + if ($rrset[count]>0) { + error_confirm("$entry[dnsdomainname] has already been added to this zone"); + return; + } + } + $entry[objectclass] = "dnsrrset"; + $entry[cn] = $setcn; + $setdn = "cn=$setcn,$zonedn"; + ldap_add($ldap, $setdn, $entry) or die("Faild to add DNSrrset $setdn to DNSzone $zonedn"); +} + +function modify_rrset($zonedn, $setdn) +{ + global $ldap, $HTTP_POST_VARS; + $zonename = get_zone_name($zonedn); + $entry = array(); + if (isset($HTTP_POST_VARS[dnscname])) { + if ($HTTP_POST_VARS[dnscname]=="") { + $entry[dnscname] = array(); + } elseif (ereg("\.$", $HTTP_POST_VARS[dnscname])) { + if (checkdnsrr($HTTP_POST_VARS[dnscname], "A")) { + $entry[dnscname] = $HTTP_POST_VARS[dnscname]; + } else { + error_confirm("Error: $HTTP_POST_VARS[dnscname] does not resolve to a valid IP-address"); + return; + } + } elseif (isset($HTTP_POST_VARS[dnsipaddr0]) || isset($HTTP_POST_VARS[dnscipaddr])) { + // records with their own address settings are not checked against DNS + $entry[dnscname] = $HTTP_POST_VARS[dnscname]; + } else { + if (!checkdnsrr("$HTTP_POST_VARS[dnscname].$zonename", "A")) { + print "

Warning: $HTTP_POST_VARS[dnscname].$zonename". + " does not resolve to a valid IP-address

\n"; + } + $entry[dnscname] = $HTTP_POST_VARS[dnscname]; + } + } + if (isset($HTTP_POST_VARS[dnscipaddr])) { + if (ereg("^([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})$", $HTTP_POST_VARS[dnscipaddr], $reg)) { + $regip = "$reg[1].$reg[2].$reg[3].$reg[4]"; + if (check_unique_cipaddr($setdn, $regip)) + $entry[dnscipaddr] = $regip; + else + return; + } elseif ($HTTP_POST_VARS[dnscipaddr]=="") { + $entry[dnscipaddr] = array(); + } else { + error_confirm("$HTTP_POST_VARS[dnscipaddr] is not a valid IP-address"); + return; + } + } + if (isset($HTTP_POST_VARS[dnsttl])) { + if (ereg("([0-9]+)", $HTTP_POST_VARS[dnsttl], $reg)) { + $entry[dnsttl] = $reg[1]; + } else { + error_confirm("$HTTP_POST_VARS[dnsttl] is not a valid Time To Live"); + return; + } + } + if (isset($HTTP_POST_VARS[dnspreference])) { + if (ereg("([0-9]+)", $HTTP_POST_VARS[dnspreference], $reg)) { + $entry[dnspreference] = $reg[1]; + } else { + error_confirm("$HTTP_POST_VARS[dnspreference] is not a valid MX-prefrence"); + return; + } + } + $entry[dnsipaddr] = array(); + for ($i = 0; isset($HTTP_POST_VARS["dnsipaddr$i"]); $i++) { + $ipaddr = $HTTP_POST_VARS["dnsipaddr$i"]; + if (ereg("^([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})$", $ipaddr, $reg)) { + array_push($entry[dnsipaddr], "$reg[1].$reg[2].$reg[3].$reg[4]"); + } elseif ($ipaddr!="") { + error_confirm("$ipaddr is not a valid IP-address"); + return; + } + } + ldap_modify($ldap, $setdn, $entry) or die("Faild to modify DNSrrest $setdn in DNSzone $zonedn"); + ldap_mod_replace($ldap, $zonedn, array("dnsserial"=>new_serial($zonedn))); +} + +function delete_rrset($zonedn, $setdn) +{ + global $ldap; + ldap_delete($ldap, $setdn) or die("Failed to delete $setdn from LDAP");; + ldap_mod_replace($ldap, $zonedn, array("dnsserial"=>new_serial($zonedn))); +} + +function check_unique_cipaddr($setdn, $cipaddr) +{ + global $ldap, $BASEDN; + $query = ldap_search($ldap, $BASEDN, "(&(objectclass=dnsrrset)(dnscipaddr=$cipaddr))"); + $entries = ldap_get_entries($ldap, $query); + ldap_free_result($query); + for ($i = 0; $i<$entries[count]; $i++) { + $dn = $entries[$i][dn]; + if ($dn!=$setdn) { + error_confirm("Canonical IP-address $cipaddr is already used by $dn"); + return 0; + } + } + return 1; +} + +function print_whois($zonename) +{ + global $WHOISSERVERS; + return; // weil unser FW-Gschaftler den Port 43 von innen nach aussen zugedreht hat + + if (ereg("\.([a-zA-Z]+)$", $zonename, $regex)) { + $whoissrv = $WHOISSERVERS["$regex[1]"]; + if (isset($whoissrv)) { + $whoisrecord = system("whois -h $whoissrv $zonename"); + print "

Whois-record for zone $zonename

\n". + "as serverd by $whoissrv
\n". + "". + "
$whoisrecord
\n"; + } else { + print "

No WHOIS-Server found for \"$regex[1]\"

\n"; + } + } +} + +?> diff --git a/webadmin/main.css b/webadmin/main.css new file mode 100644 index 0000000..a78a6d6 --- /dev/null +++ b/webadmin/main.css @@ -0,0 +1,17 @@ +BODY, TD { + font-family: Verdana,Arial,Helvetica; + font-size: 11pt; + background-color: white; + color: black; +} + +SMALL { + font-family: Verdana,Arial,Helvetica; + font-size: 8pt; +} + +BIG { + font-family: Verdana,Arial,Helvetica; + font-size: 14pt; +} + diff --git a/webadmin/mainheader.inc b/webadmin/mainheader.inc new file mode 100644 index 0000000..a29cca2 --- /dev/null +++ b/webadmin/mainheader.inc @@ -0,0 +1,8 @@ + + + Zone-Editor + + + + + diff --git a/webadmin/menu.css b/webadmin/menu.css new file mode 100644 index 0000000..5f17597 --- /dev/null +++ b/webadmin/menu.css @@ -0,0 +1,37 @@ +A { + text-decoration: none; +} + +A:link { + font-family: Verdana, Arial, Helvetica, sans-serif; + font-size: 10px; + color: black; +} + +A:visited { + font-family: Verdana, Arial, Helvetica, sans-serif; + font-size: 10px; + color: #222222; +} + +A:hover { + text-decoration: underline; +} + +BODY, TD { + font-family: Verdana,Arial,Helvetica; + font-size: 10pt; + background-color: lightgrey; + color: black; +} + +SMALL { + font-family: Verdana,Arial,Helvetica; + font-size: 8pt; +} + +BIG { + font-family: Verdana,Arial,Helvetica; + font-size: 14pt; +} + diff --git a/webadmin/menuheader.inc b/webadmin/menuheader.inc new file mode 100644 index 0000000..2ae4a1b --- /dev/null +++ b/webadmin/menuheader.inc @@ -0,0 +1,8 @@ + + + + Zone-Selector + + + +
diff --git a/webadmin/xearth.css b/webadmin/xearth.css new file mode 100644 index 0000000..cc181e3 --- /dev/null +++ b/webadmin/xearth.css @@ -0,0 +1,21 @@ +A { + text-decoration: none; +} + +BODY, TD { + font-family: Verdana,Arial,Helvetica; + font-size: 10pt; + background-color: black; + color: white; +} + +SMALL { + font-family: Verdana,Arial,Helvetica; + font-size: 8pt; +} + +BIG { + font-family: Verdana,Arial,Helvetica; + font-size: 12pt; +} + diff --git a/webadmin/xearth.php b/webadmin/xearth.php new file mode 100644 index 0000000..8c9b9cb --- /dev/null +++ b/webadmin/xearth.php @@ -0,0 +1,16 @@ + + + + XEarth + + + +



+ + + +
+
+ + + diff --git a/webadmin/xearthimage.php b/webadmin/xearthimage.php new file mode 100644 index 0000000..2f07167 --- /dev/null +++ b/webadmin/xearthimage.php @@ -0,0 +1,4 @@ +