diff --git a/ChangeLog b/ChangeLog index 673ec2a..098ef36 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,6 +1,13 @@ # $Id$ -Version 0.3.6 (latest) +Version 0.3.7 (latest) ++ Changed default location of ldap.conf to /etc/ldap.conf ++ Added note on potential security vulns in deprecated/webadmin to README ++ Changed port declarations/format strings from int to unsigned short + to match standards ++ Updated doc/README.html + +Version 0.3.6 + New maintainer: Ben Klang + Fixed bug with duplicate OIDs in dns.schema from partially applied patch + Renamed schema file to ldap2dns.schema diff --git a/FAQ b/FAQ index f57771d..347f73a 100644 --- a/FAQ +++ b/FAQ @@ -1,6 +1,8 @@ 1) What happened to the webadmin directory? -2005-12-07 bklang +2005-12-22 bklang +** See security note at the end of this section regarding the old webadmin ** + I have deprecated that code in favor of another project I am working on. It is called Beatnik and is a Horde framework module. The status of the webadmin code was unclear and I was not willing to support it so I deprecated it. I @@ -12,6 +14,17 @@ own. You might also contact the author, Jacob Rief (jacob.rief@tiscover.com) for more information but he is no longer interested in maintaing this work so do not depend on him. +During a routine code audit on the ldap2dns sources a number of potential LDAP +injection vulnerabilities were discovered. Since this code is deprecated no +attempt to correct these flaws has been made. + + +IF YOU CHOOSE TO RUN THE DEPRECATED WEBADMIN SOFTWARE: Please take all +necessary steps to secure your environment. The author of this package takes no +responsibility for any problems related to the flawed webadmin code. + +Thanks to Erik Cabetas for bringing these issues to my attention. + 2) Why have you deprecated all that code? 2005-12-07 bklang diff --git a/Makefile b/Makefile index 7505ab3..5b3a646 100644 --- a/Makefile +++ b/Makefile @@ -54,7 +54,8 @@ install: all install -o root -g root -m 644 ldap2dns.schema $(LDAPCONFDIR)/schema/ clean: - rm -f *.o *.o-dbg ldap2dns ldap2dnsd data* *.db core $(SPECFILE) + rm -f *.o *.o-dbg ldap2dns ldap2dns-dbg ldap2dnsd data* *.db core \ + $(SPECFILE) tar: clean cd ..; \ diff --git a/doc/README.html b/doc/README.html index 161a655..32f84b5 100644 --- a/doc/README.html +++ b/doc/README.html @@ -1,353 +1,738 @@ -

LDAP to DNS gateway

-

-ldap2dns is a program to create DNS (Domain Name Service) records directly -from a LDAP directory. It can and should be be used to replace the secondary -name-server by a second primary one.
-ldap2dns reduces all kind of administration overhead: -No more flat file editing, no more zone file editing. After having installed -ldap2dns, the administrator only has to access the LDAP directory.
-Optionally she can add access control for each zone, create a GUI -and add all other kind of zone and resource record information without -interfering with the DNS server.
-ldap2dns is designed to write ASCII data files used by tinydns -from the djbdns package, but also may be used to write .db-files used -by named as found in the BIND package.
-

+ + +

+ +

LDAP to DNS gateway

+

ldap2dns is a program to read DNS (Domain Name Service) +records from an LDAP directory and format them into flat files suitable for TinyDNS (or Bind).

+

ldap2dns reduces all kind of administration overhead: No +more flat file editing, no more zone file editing. After having +installed ldap2dns, the administrator only has to access the +LDAP directory.
+Optionally access control can be configured for each zone, GUIs can +be more easily implemented, and add all other kind of zone and resource +record information can be managed without interfering with the DNS server.
+ldap2dns is designed to write ASCII data files used by +tinydns from the djbdns package, but also may be used +to write .db-files used by named as found in the BIND +package.

-

1. Introduction

-Often it is desirable to store DNS information in a database rather than -in flat text files. This can greatly help to reduce administration overhead -since associate information such as billing contact, account management, etc. -can be stored and processed inside the same database. Also due to the nature of -DNS, information must be stored redundantly on two or more hosts. -The classical data replication through zone transfer is unreliable, insecure -and difficult to administer.
-To solve this problem some proprietary attempts have been proposed to -store DNS information in relational databases. The nature of DNS, however, -is hierarchical and such should the database be. Using a relational database -to store DNS information is undesirable, because it becomes difficult -to store free form information. Within a hierachical data scheme, the -administrator might define more than one IP-address for each canonical name. -To implement such a feature in a relational database without breaking the -normalization rules, one would have to add another table.
-One of the most widely spread hierarchical database protocols is LDAP. -ldap2dns retrieves DNS information stored in an LDAP directory service -and generates a file suitable for name-servers.
-Actually the most widely spread name-servers -named and -tinydns are -supported. ldap2dns specially has been designed to work with -tinydns and is the favored name server daemon for the author of this program. -ldap2dns can also generate files suitable for named version 8, -but this feature is not well supported. -There is a - -RFC for a format description how to store DNS information in LDAP. -This paper a draft RFC which expired in February 1999, looks as if it has been -specially designed to be used by named. This scheme -does not have strict attribute-value-pair mapping, making it difficult to be used by -user interfaces. It also lacks of an implementation (or I have never heard of any).
-Since tinydns is going another descriptive way. Therefore I implemented a similar -object-scheme more suitable for tinydns. Two object-classes have been defined. -DNSzone stores all the information to define a DNS zone, such as the SOA -(Start Of Authority), serial numbers etc. DNSrrset is used to store the information -for a single resource record, such as the domain name, IP-addresses, class and type.
-Here are the tables: -

-

DNSzone

-This object-class represents a DNS zone. It is the container for all the resource records -within a zone. Zones can be primary or secondary. If used in conjunction with -tinydns zones are always primary. Secondary zones don't make sense anyway! -In addition to being a container, the zone object has attributes related to -the management of the zone. These include the zone's SOA information. Each zone-object -can have none to many children of class DNSrrset.
- - - - - - - - - - - - - - - - -
ATTRIBUTEVALUEComment
objectclassDNSzonerequired
cncommon namerequired
DNSzonenameName of the zonerequired, multivalued
DNSserialSerial number of SOAoptional
DNSrefreshRefresh time of SOAoptional, only used for zone transfers
DNSretryRetry time of SOAoptional, only used for zone transfers
DNSexpireExpire time of SOAoptional, only used for zone transfers
DNSminimumMinimum time to liveoptional, only used for zone transfers
DNSadminmailboxHostmaster's contact addressoptional
DNSzonemasterPrimary nameserver for this zoneoptional
DNStypeSOAmust be SOA
DNSclassINmust be IN
DNSttltime to liveoptional, only used with tinydns
DNStimestamptimestampoptional, only used with tinydns
-
+ \ No newline at end of file diff --git a/ldap2dns.c b/ldap2dns.c index 9f40eaf..7635d96 100644 --- a/ldap2dns.c +++ b/ldap2dns.c @@ -15,7 +15,7 @@ #include #define UPDATE_INTERVALL 59 -#define LDAP_CONF "/etc/ldap/ldap.conf" +#define LDAP_CONF "/etc/ldap.conf" #define OUTPUT_DATA 1 #define OUTPUT_DB 2 #define MAXHOSTS 10 @@ -100,11 +100,11 @@ static struct char binddn[128]; char hostname[MAXHOSTS][128]; char urildap[MAXHOSTS][128]; - int port[MAXHOSTS]; + unsigned short port[MAXHOSTS]; char password[128]; int usedhosts; int is_daemon; - int update_iv; + unsigned int update_iv; unsigned int output; int verbose; char ldifname[128]; @@ -172,7 +172,8 @@ static void print_usage(void) static void parse_hosts(char* buf) { - int i, port, k; + int i, k; + unsigned short port; char value[128], rest[512]; options.usedhosts = 0; @@ -182,13 +183,15 @@ static void parse_hosts(char* buf) 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); + strncpy(options.urildap[i], value, sizeof(options.urildap[i])); + options.urildap[i][ sizeof(options.urildap[i]) -1 ] = '\0'; + 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) { + } else if ((k = sscanf(buf, "%128s:%hd %512[A-Za-z0-9 .:_+-]", value, &port, rest))>=2) { strcpy(options.hostname[i], value); options.port[i] = port; options.usedhosts++; @@ -221,19 +224,23 @@ static int parse_options() if (ldap_conf = fopen(LDAP_CONF, "r")) { while(fgets(buf, 256, ldap_conf)!=0) { int i; - if (sscanf(buf, "BASE %128s", value)==1) - strcpy(options.searchbase, value); + if (sscanf(buf, "BASE %128s", value)==1){ + strncpy(options.searchbase, value, sizeof(options.searchbase)); + options.searchbase[sizeof(options.searchbase) -1] = '\0'; + } 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) + if (sscanf(buf, "PORT %hd", &len)==1) for (i = 0; iipaddr[0], "%d.%d.%d.%d", &ip[0], &ip[1], &ip[2], &ip[3])==4) { /* lazy user, used DNSipaddr for reverse lookup */ - sprintf(buf, "%d.%d.%d.%d.in-addr.arpa", ip[3], ip[2], ip[1], ip[0]); + snprintf(buf, sizeof(buf), "%d.%d.%d.%d.in-addr.arpa", ip[3], ip[2], ip[1], ip[0]); } else { - strcpy(buf, rr->dnsdomainname); + strncpy(buf, rr->dnsdomainname, sizeof(buf)); + buf[ sizeof(buf) -1 ] = '\0'; } if (tinyfile) fprintf(tinyfile, "^%s:%s:%s:%s:%s\n", buf, rr->cname, rr->ttl, rr->timestamp, rr->location); @@ -486,7 +505,7 @@ static void parse_rr(struct resourcerecord* rr) sscanf(rr->rr, "%16s %16s %64s %64s", rr->class, rr->type, word1, word2); if (strcasecmp(rr->type, "NS")==0) { if (sscanf(word1, "%d.%d.%d.%d", &ip[0], &ip[1], &ip[2], &ip[3])==4) { - sprintf(rr->ipaddr[0], "%d.%d.%d.%d", ip[0], ip[1], ip[2], ip[3]); + snprintf(rr->ipaddr[0], sizeof(rr->ipaddr[0]), "%d.%d.%d.%d", ip[0], ip[1], ip[2], ip[3]); } else { int len = strlen(word1); expand_domainname(rr->cname, word1, len); @@ -495,14 +514,14 @@ static void parse_rr(struct resourcerecord* rr) if (sscanf(word1, "%s", rr->preference)!=1) rr->preference[0] = '\0'; if (sscanf(word2, "%d.%d.%d.%d", &ip[0], &ip[1], &ip[2], &ip[3])==4) { - sprintf(rr->ipaddr[0], "%d.%d.%d.%d", ip[0], ip[1], ip[2], ip[3]); + snprintf(rr->ipaddr[0], sizeof(rr->ipaddr[0]), "%d.%d.%d.%d", ip[0], ip[1], ip[2], ip[3]); } else { int len = strlen(word2); expand_domainname(rr->cname, word2, len); } } else if (strcasecmp(rr->type, "A")==0) { if (sscanf(word1, "%d.%d.%d.%d", &ip[0], &ip[1], &ip[2], &ip[3])==4) - sprintf(rr->ipaddr[0], "%d.%d.%d.%d", ip[0], ip[1], ip[2], ip[3]); + snprintf(rr->ipaddr[0], sizeof(rr->ipaddr[0]), "%d.%d.%d.%d", ip[0], ip[1], ip[2], ip[3]); else rr->ipaddr[0][0] = '\0'; } else if (strcasecmp(rr->type, "PTR")==0) { @@ -585,7 +604,7 @@ static void read_resourcerecords(char* dn, int znix) for (ipaddresses = 0; bvals[ipaddresses] && ipaddresses<256; ipaddresses++) { rr.ipaddr[ipaddresses][0] = '\0'; if (sscanf(bvals[ipaddresses]->bv_val, "%d.%d.%d.%d", &ip[0], &ip[1], &ip[2], &ip[3])==4) { - sprintf(rr.ipaddr[ipaddresses], "%d.%d.%d.%d", ip[0], ip[1], ip[2], ip[3]); + snprintf(rr.ipaddr[ipaddresses], sizeof(rr.ipaddr[ipaddresses]), "%d.%d.%d.%d", ip[0], ip[1], ip[2], ip[3]); if (options.ldifname[0]) fprintf(ldifout, "%s: %s\n", attr, rr.ipaddr[ipaddresses]); } @@ -593,7 +612,7 @@ static void read_resourcerecords(char* dn, int znix) } else if (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) { - sprintf(rr.cipaddr, "%d.%d.%d.%d", ip[0], ip[1], ip[2], ip[3]); + snprintf(rr.cipaddr, sizeof(rr.cipaddr), "%d.%d.%d.%d", ip[0], ip[1], ip[2], ip[3]); if (options.ldifname[0]) fprintf(ldifout, "%s: %s\n", attr, rr.cipaddr); } @@ -855,7 +874,7 @@ static void read_dnszones(void) printf("zonename: %s\n", zone.domainname); if (options.output&OUTPUT_DB) { char namedzonename[128]; - sprintf(namedzonename, "%s.db", zone.domainname); + snprintf(namedzonename, sizeof(namedzonename), "%s.db", zone.domainname); if ( !(namedzone = fopen(namedzonename, "w")) ) die_exit("Unable to open db-file for writing"); }