Blob Blame History Raw
diff -up dhcp-3.1.0/server/mdb.c.ldap dhcp-3.1.0/server/mdb.c
--- dhcp-3.1.0/server/mdb.c.ldap	2007-06-08 14:57:02.000000000 -0400
+++ dhcp-3.1.0/server/mdb.c	2007-10-22 16:29:48.000000000 -0400
@@ -454,6 +454,12 @@ int find_hosts_by_haddr (struct host_dec
 {
 	struct host_decl *foo;
 	struct hardware h;
+	int ret;
+
+#if defined(LDAP_CONFIGURATION)
+	if ((ret = find_haddr_in_ldap (hp, htype, hlen, haddr, file, line)))
+		return ret;
+#endif
 
 	h.hlen = hlen + 1;
 	h.hbuf [0] = htype;
diff -up dhcp-3.1.0/server/Makefile.dist.ldap dhcp-3.1.0/server/Makefile.dist
--- dhcp-3.1.0/server/Makefile.dist.ldap	2006-07-25 09:26:00.000000000 -0400
+++ dhcp-3.1.0/server/Makefile.dist	2007-10-22 16:29:48.000000000 -0400
@@ -25,9 +25,9 @@
 CATMANPAGES = dhcpd.cat8 dhcpd.conf.cat5 dhcpd.leases.cat5
 SEDMANPAGES = dhcpd.man8 dhcpd.conf.man5 dhcpd.leases.man5
 SRCS   = dhcpd.c dhcp.c bootp.c confpars.c db.c class.c failover.c \
-	 omapi.c mdb.c stables.c salloc.c ddns.c dhcpleasequery.c
+	 omapi.c mdb.c stables.c salloc.c ddns.c dhcpleasequery.c ldap.c
 OBJS   = dhcpd.o dhcp.o bootp.o confpars.o db.o class.o failover.o \
-	 omapi.o mdb.o stables.o salloc.o ddns.o dhcpleasequery.o
+	 omapi.o mdb.o stables.o salloc.o ddns.o dhcpleasequery.o ldap.o
 PROG   = dhcpd
 MAN    = dhcpd.8 dhcpd.conf.5 dhcpd.leases.5
 
@@ -106,6 +106,6 @@ dhcpd.leases.man5:	dhcpd.leases.5
 		-e "s#RUNDIR#$(VARRUN)#g" < dhcpd.leases.5 >dhcpd.leases.man5
 
 dhcpd:	$(OBJS) $(COBJ) $(DHCPLIB)
-	$(CC) $(LFLAGS) -o dhcpd $(OBJS) $(DHCPLIB) $(LIBS)
+	$(CC) $(LFLAGS) -o dhcpd $(OBJS) $(DHCPLIB) $(LIBS) -lldap
 
 # Dependencies (semi-automatically-generated)
diff -up dhcp-3.1.0/server/dhcpd.c.ldap dhcp-3.1.0/server/dhcpd.c
--- dhcp-3.1.0/server/dhcpd.c.ldap	2007-05-29 13:49:44.000000000 -0400
+++ dhcp-3.1.0/server/dhcpd.c	2007-10-22 16:29:48.000000000 -0400
@@ -440,6 +440,9 @@ int main (argc, argv, envp)
 	/* Add the ddns update style enumeration prior to parsing. */
 	add_enumeration (&ddns_styles);
 	add_enumeration (&syslog_enum);
+#if defined (LDAP_CONFIGURATION)
+	add_enumeration (&ldap_methods);
+#endif
 
 	if (!group_allocate (&root_group, MDL))
 		log_fatal ("Can't allocate root group!");
diff -up /dev/null dhcp-3.1.0/server/ldap.c
--- /dev/null	2007-10-22 10:27:59.854008585 -0400
+++ dhcp-3.1.0/server/ldap.c	2007-10-22 16:29:48.000000000 -0400
@@ -0,0 +1,1142 @@
+/* ldap.c
+
+   Routines for reading the configuration from LDAP */
+
+/*
+ * Copyright (c) 1996-2001 Ntelos, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of The Internet Software Consortium nor the names
+ *    of its contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND
+ * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED.  IN NO EVENT SHALL THE INTERNET SOFTWARE CONSORTIUM OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * This LDAP module was written by Brian Masney <masneyb@ntelos.net>. It's
+ * development was sponsored by Ntelos, Inc. (www.ntelos.com).
+ */
+
+#include "dhcpd.h"
+
+#if defined(LDAP_CONFIGURATION)
+
+static LDAP * ld = NULL;
+static char *ldap_server = NULL, 
+            *ldap_username = NULL, 
+            *ldap_password = NULL,
+            *ldap_base_dn = NULL;
+static int ldap_method = LDAP_METHOD_DYNAMIC,
+           disable_ldap = 0;
+static struct ldap_config_stack *ldap_stack = NULL;
+
+
+static void
+ldap_parse_class (struct ldap_config_stack *item, struct parse *cfile)
+{
+  struct berval **temp;
+
+  if ((temp = ldap_get_values_len (ld, item->ldent, "cn")) == NULL ||
+      temp[0]->bv_val == NULL)
+    {
+      if (temp != NULL)
+        ldap_value_free_len (temp);
+
+      return;
+    }
+
+  strncat (cfile->inbuf, "class \"", LDAP_BUFFER_SIZE);
+  strncat (cfile->inbuf, temp[0]->bv_val, LDAP_BUFFER_SIZE);
+  strncat (cfile->inbuf, "\" {\n", LDAP_BUFFER_SIZE);
+
+  item->close_brace = 1;
+  ldap_value_free_len (temp);
+}
+
+
+static void
+ldap_parse_subclass (struct ldap_config_stack *item, struct parse *cfile)
+{
+  struct berval **temp, **classdata;
+
+  if ((temp = ldap_get_values_len (ld, item->ldent, "cn")) == NULL ||
+      temp[0]->bv_val == NULL)
+    {
+      if (temp != NULL)
+        ldap_value_free_len (temp);
+
+      return;
+    }
+
+
+  if ((classdata = ldap_get_values_len (ld, item->ldent, 
+                                  "dhcpClassData")) == NULL || 
+      classdata[0]->bv_val == NULL)
+    {
+      if (classdata != NULL)
+        ldap_value_free_len (classdata);
+      ldap_value_free_len (temp);
+
+      return;
+    }
+
+  strncat (cfile->inbuf, "subclass ", LDAP_BUFFER_SIZE);
+  strncat (cfile->inbuf, (*classdata)->bv_val, LDAP_BUFFER_SIZE);
+  strncat (cfile->inbuf, " ", LDAP_BUFFER_SIZE);
+  strncat (cfile->inbuf, (*temp)->bv_val, LDAP_BUFFER_SIZE);
+  strncat (cfile->inbuf, " {\n", LDAP_BUFFER_SIZE);
+
+  item->close_brace = 1;
+  ldap_value_free_len (temp);
+  ldap_value_free_len (classdata);
+}
+
+
+static void
+ldap_parse_host (struct ldap_config_stack *item, struct parse *cfile)
+{
+  struct berval **temp, **hwaddr;
+
+
+  if ((temp = ldap_get_values_len (ld, item->ldent, "cn")) == NULL ||
+      temp[0]->bv_val == NULL)
+    {
+      if (temp != NULL)
+        ldap_value_free_len (temp);
+
+      return;
+    }
+
+  if ((hwaddr = ldap_get_values_len (ld, item->ldent, 
+                                 "dhcpHWAddress")) == NULL || 
+      hwaddr[0]->bv_val == NULL)
+    {
+      if (hwaddr != NULL)
+        ldap_value_free_len (hwaddr);
+      ldap_value_free_len (temp);
+
+      return;
+    }
+
+  strncat (cfile->inbuf, "host ", LDAP_BUFFER_SIZE);
+  strncat (cfile->inbuf, (*temp)->bv_val, LDAP_BUFFER_SIZE);
+  strncat (cfile->inbuf, " {\nhardware ", LDAP_BUFFER_SIZE);
+  strncat (cfile->inbuf, (*hwaddr)->bv_val, LDAP_BUFFER_SIZE);
+  strncat (cfile->inbuf, ";\n", LDAP_BUFFER_SIZE);
+
+  item->close_brace = 1;
+  ldap_value_free_len (temp);
+  ldap_value_free_len (hwaddr);
+}
+
+
+static void
+ldap_parse_shared_network (struct ldap_config_stack *item, struct parse *cfile)
+{
+  struct berval **temp;
+
+
+  if ((temp = ldap_get_values_len (ld, item->ldent, "cn")) == NULL ||
+      temp[0]->bv_val == NULL)
+    {
+      if (temp != NULL)
+        ldap_value_free_len (temp);
+
+      return;
+    }
+
+  strncat (cfile->inbuf, "shared-network ", LDAP_BUFFER_SIZE);
+  strncat (cfile->inbuf, (*temp)->bv_val, LDAP_BUFFER_SIZE);
+  strncat (cfile->inbuf, " {\n", LDAP_BUFFER_SIZE);
+
+  item->close_brace = 1;
+  ldap_value_free_len (temp);
+}
+
+
+static void
+parse_netmask (int netmask, char *netmaskbuf)
+{
+  unsigned long nm;
+  int i;
+
+  nm = 0;
+  for (i=1; i <= netmask; i++)
+    {
+      nm |= 1 << (32 - i);
+    }
+
+  sprintf (netmaskbuf, "%d.%d.%d.%d", (int) (nm >> 24) & 0xff, 
+                                      (int) (nm >> 16) & 0xff, 
+                                      (int) (nm >> 8) & 0xff, 
+                                      (int) nm & 0xff);
+}
+
+static void
+ldap_parse_subnet (struct ldap_config_stack *item, struct parse *cfile)
+{
+  struct berval **temp, **netmask;
+  char netmaskbuf[16];
+  int i;
+
+  if ((temp = ldap_get_values_len (ld, item->ldent, "cn")) == NULL ||
+      temp[0]->bv_val == NULL)
+    {
+      if (temp != NULL)
+        ldap_value_free_len (temp);
+
+      return;
+    }
+
+  if ((netmask = ldap_get_values_len (ld, item->ldent, 
+                                     "dhcpNetmask")) == NULL || 
+      netmask[0]->bv_val == NULL)
+    {
+      if (netmask != NULL)
+        ldap_value_free_len (netmask);
+      ldap_value_free_len (temp);
+
+      return;
+    }
+
+  strncat (cfile->inbuf, "subnet ", LDAP_BUFFER_SIZE);
+  strncat (cfile->inbuf, temp[0]->bv_val, LDAP_BUFFER_SIZE);
+
+  strncat (cfile->inbuf, " netmask ", LDAP_BUFFER_SIZE);
+  parse_netmask (strtol (netmask[0]->bv_val, NULL, 10), netmaskbuf);
+  strncat (cfile->inbuf, netmaskbuf, LDAP_BUFFER_SIZE);
+
+  strncat (cfile->inbuf, " {\n", LDAP_BUFFER_SIZE);
+
+  ldap_value_free_len (temp);
+  ldap_value_free_len (netmask);
+
+  if ((temp = ldap_get_values_len (ld, item->ldent, "dhcpRange")) != NULL)
+    {
+      strncat (cfile->inbuf, "range", LDAP_BUFFER_SIZE);
+      for (i=0; temp[i] != NULL && temp[i]->bv_val != NULL; i++)
+        {
+          strncat (cfile->inbuf, " ", LDAP_BUFFER_SIZE);
+          strncat (cfile->inbuf, temp[i]->bv_val, LDAP_BUFFER_SIZE);
+        }
+      strncat (cfile->inbuf, ";\n", LDAP_BUFFER_SIZE);
+      ldap_value_free_len (temp);
+    }
+
+  item->close_brace = 1;
+}
+
+
+static void
+ldap_parse_pool (struct ldap_config_stack *item, struct parse *cfile)
+{
+  struct berval **temp;
+  int i;
+
+  strncat (cfile->inbuf, "pool {\n", LDAP_BUFFER_SIZE);
+
+  if ((temp = ldap_get_values_len (ld, item->ldent, "dhcpRange")) != NULL)
+    {
+      strncat (cfile->inbuf, "range", LDAP_BUFFER_SIZE);
+      for (i=0; temp[i] != NULL && temp[i]->bv_val != NULL; i++)
+        {
+          strncat (cfile->inbuf, " ", LDAP_BUFFER_SIZE);
+          strncat (cfile->inbuf, temp[i]->bv_val, LDAP_BUFFER_SIZE);
+        }
+      strncat (cfile->inbuf, ";\n", LDAP_BUFFER_SIZE);
+      ldap_value_free_len (temp);
+    }
+
+  if ((temp = ldap_get_values_len (ld, item->ldent, "dhcpPermitList")) != NULL)
+    {
+      for (i=0; temp[i] != NULL && temp[i]->bv_val != NULL; i++)
+        {
+          strncat (cfile->inbuf, temp[i]->bv_val, LDAP_BUFFER_SIZE);
+          strncat (cfile->inbuf, ";\n", LDAP_BUFFER_SIZE);
+        }
+      ldap_value_free_len (temp);
+    }
+
+  item->close_brace = 1;
+}
+
+
+static void
+ldap_parse_group (struct ldap_config_stack *item, struct parse *cfile)
+{
+  strncat (cfile->inbuf, "group {\n", LDAP_BUFFER_SIZE);
+  item->close_brace = 1;
+}
+
+
+static void
+parse_external_dns (LDAPMessage * ent)
+{
+  char *search[] = {"dhcpOptionsDN", "dhcpSharedNetworkDN", "dhcpSubnetDN",
+                    "dhcpGroupDN", "dhcpHostDN", "dhcpClassesDN", 
+                    "dhcpPoolDN", NULL};
+  LDAPMessage * newres, * newent;
+  struct ldap_config_stack *ns;
+  struct berval **temp;
+  int i, ret;
+
+  for (i=0; search[i] != NULL; i++)
+    {
+      if ((ldap_method == LDAP_METHOD_DYNAMIC) &&
+          (strcmp (search[i], "dhcpHostDN") == 0))
+        continue;
+
+      if ((temp = ldap_get_values_len (ld, ent, search[i])) == NULL)
+        continue;
+
+      if ((ret = ldap_search_ext_s (ld, temp[0]->bv_val, LDAP_SCOPE_BASE, 
+                                    "objectClass=*", NULL, 0, 
+                                    NULL, NULL, NULL, 0,
+                                    &newres)) != LDAP_SUCCESS)
+        {
+          ldap_value_free_len (temp);
+          ldap_unbind_ext (ld, NULL, NULL);
+          ld = NULL;
+          return;
+        }
+
+      ldap_value_free_len (temp);
+
+      newent = ldap_first_entry (ld, newres);
+      if (newent == NULL)
+        {
+          ldap_msgfree (newres);
+          continue;
+        }
+
+#if defined(DEBUG_LDAP)
+      log_info ("Adding LDAP entry '%s' as child", ldap_get_dn (ld, newent));
+#endif
+
+      ns = dmalloc (sizeof (*ns), MDL);
+      ns->res = newres;
+      ns->ldent = newent;
+      ns->close_brace = 0;
+      ns->processed = 0;
+      ns->children = NULL;
+      ns->next = ldap_stack->children;
+      ldap_stack->children = ns;
+    }
+}
+
+
+static void
+ldap_generate_config_string (struct ldap_config_stack *item, struct parse *cfile)
+{
+  struct berval **objectClass, **temp;
+  int i, j, ignore, found;
+
+  if ((objectClass = ldap_get_values_len (ld, item->ldent, 
+                                      "objectClass")) == NULL)
+    return;
+    
+  ignore = 0;
+  found = 1;
+  for (i=0; objectClass[i] != NULL && objectClass[i]->bv_val != NULL; i++)
+    {
+      if (strcmp (objectClass[i]->bv_val, "dhcpSharedNetwork") == 0)
+        ldap_parse_shared_network (item, cfile);
+      else if (strcmp (objectClass[i]->bv_val, "dhcpClass") == 0)
+        ldap_parse_class (item, cfile);
+      else if (strcmp (objectClass[i]->bv_val, "dhcpSubnet") == 0)
+        ldap_parse_subnet (item, cfile);
+      else if (strcmp (objectClass[i]->bv_val, "dhcpPool") == 0)
+        ldap_parse_pool (item, cfile);
+      else if (strcmp (objectClass[i]->bv_val, "dhcpGroup") == 0)
+        ldap_parse_group (item, cfile);
+      else if (strcmp (objectClass[i]->bv_val, "dhcpHost") == 0)
+        {
+          if (ldap_method == LDAP_METHOD_STATIC)
+            ldap_parse_host (item, cfile);
+          else
+            {
+              ignore = 1;
+              break;
+            }
+        }
+      else if (strcmp (objectClass[i]->bv_val, "dhcpSubClass") == 0)
+        {
+          if (ldap_method == LDAP_METHOD_STATIC)
+            ldap_parse_subclass (item, cfile);
+          else
+            {
+              ignore = 1;
+              break;
+            }
+        }
+      else
+        found = 0;
+
+      if (found && cfile->inbuf[0] == '\0')
+        {
+          ignore = 1;
+          break;
+        }
+    }
+
+  ldap_value_free_len (objectClass);
+
+  if (ignore)
+    return;
+
+  if ((temp = ldap_get_values_len (ld, item->ldent, "dhcpOption")) != NULL)
+    {
+      for (j=0; temp[j] != NULL && temp[j]->bv_val != NULL; j++)
+        {
+          strncat (cfile->inbuf, "option ", LDAP_BUFFER_SIZE);
+          strncat (cfile->inbuf, temp[j]->bv_val, LDAP_BUFFER_SIZE);
+          strncat (cfile->inbuf, ";\n", LDAP_BUFFER_SIZE);
+        }
+      ldap_value_free_len (temp);
+    }
+
+  if ((temp = ldap_get_values_len (ld, item->ldent, "dhcpStatements")) != NULL)
+    {
+      for (j=0; temp[j] != NULL && temp[j]->bv_val != NULL; j++)
+        {
+          strncat (cfile->inbuf, temp[j]->bv_val, LDAP_BUFFER_SIZE);
+          strncat (cfile->inbuf, ";\n", LDAP_BUFFER_SIZE);
+        }
+      ldap_value_free_len (temp);
+    }
+
+  parse_external_dns (item->ldent);
+}
+
+
+static void
+free_stack_entry (struct ldap_config_stack *item)
+{
+  ldap_msgfree (item->res);
+  dfree (item, MDL);
+}
+
+
+static void
+next_ldap_entry (struct parse *cfile)
+{
+  struct ldap_config_stack *temp_stack;
+
+  if (ldap_stack->processed && ldap_stack->children != NULL)
+    {
+      temp_stack = ldap_stack->children;
+      if (temp_stack->close_brace)
+        strncat (cfile->inbuf, "}\n", LDAP_BUFFER_SIZE);
+
+      ldap_stack->children = ldap_stack->children->next;
+      free_stack_entry (temp_stack);
+
+      if (ldap_stack->processed && ldap_stack->children != NULL)
+        return;
+    }
+
+  if (ldap_stack->close_brace)
+    {
+      strncat (cfile->inbuf, "}\n", LDAP_BUFFER_SIZE);
+      ldap_stack->close_brace = 0;
+    }
+
+  while (ldap_stack != NULL && ldap_stack->children == NULL &&
+         (ldap_stack->ldent = ldap_next_entry (ld, ldap_stack->ldent)) == NULL)
+    {
+      if (ldap_stack->close_brace)
+        {
+          strncat (cfile->inbuf, "}\n", LDAP_BUFFER_SIZE);
+          ldap_stack->close_brace = 0;
+        }
+
+      temp_stack = ldap_stack;
+      ldap_stack = ldap_stack->next;
+      free_stack_entry (temp_stack);
+    }
+
+  if (ldap_stack != NULL && ldap_stack->children == NULL &&
+      ldap_stack->close_brace)
+    {
+      strncat (cfile->inbuf, "}\n", LDAP_BUFFER_SIZE);
+      ldap_stack->close_brace = 0;
+    }
+}
+
+
+static void
+add_to_config_stack (LDAPMessage * res, LDAPMessage * ent)
+{
+  struct ldap_config_stack *ns;
+
+  ns = dmalloc (sizeof (*ns), MDL);
+  ns->res = res;
+  ns->ldent = ent;
+  ns->close_brace = 0;
+  ns->processed = 0;
+  ns->children = NULL;
+  ns->next = ldap_stack;
+  ldap_stack = ns;
+}
+
+
+static void
+ldap_start (void)
+{
+  struct option_state *options;
+  struct option_cache *oc;
+  struct data_string db;
+  int ret;
+
+  if (ld != NULL)
+    return;
+
+  if (ldap_server == NULL)
+    {
+      options = NULL;
+      option_state_allocate (&options, MDL);
+
+      execute_statements_in_scope ((struct binding_value **) NULL,
+                 (struct packet *) NULL, (struct lease *) NULL,
+                 (struct client_state *) NULL, (struct option_state *) NULL,
+                 options, &global_scope, root_group, (struct group *) NULL);
+
+      memset (&db, 0, sizeof (db));
+      oc = lookup_option (&server_universe, options, SV_LDAP_SERVER);
+      if (oc &&
+          evaluate_option_cache (&db,  (struct packet*) NULL,
+                (struct lease *) NULL, (struct client_state *) NULL,
+                options, (struct option_state *) NULL, &global_scope, oc, MDL))
+        {
+          ldap_server = dmalloc (db.len + 1, MDL);
+          if (!ldap_server)
+            log_fatal ("no memory for ldap server");
+          memcpy (ldap_server, db.data, db.len);
+          ldap_server[db.len] = 0;
+          data_string_forget (&db, MDL);
+        }
+
+      oc = lookup_option (&server_universe, options, SV_LDAP_USERNAME);
+      if (oc &&
+          evaluate_option_cache (&db,  (struct packet*) NULL,
+                (struct lease *) NULL, (struct client_state *) NULL,
+                options, (struct option_state *) NULL, &global_scope, oc, MDL))
+        {
+          ldap_username = dmalloc (db.len + 1, MDL);
+          if (!ldap_username)
+            log_fatal ("no memory for ldap username");
+          memcpy (ldap_username, db.data, db.len);
+          ldap_username[db.len] = 0;
+          data_string_forget (&db, MDL);
+        }
+
+      oc = lookup_option (&server_universe, options, SV_LDAP_PASSWORD);
+      if (oc &&
+          evaluate_option_cache (&db,  (struct packet*) NULL,
+                (struct lease *) NULL, (struct client_state *) NULL,
+                options, (struct option_state *) NULL, &global_scope, oc, MDL))
+        {
+          ldap_password = dmalloc (db.len + 1, MDL);
+          if (!ldap_password)
+            log_fatal ("no memory for ldap password");
+          memcpy (ldap_password, db.data, db.len);
+          ldap_password[db.len] = 0;
+          data_string_forget (&db, MDL);
+        }
+
+      oc = lookup_option (&server_universe, options, SV_LDAP_BASE_DN);
+      if (oc &&
+          evaluate_option_cache (&db,  (struct packet*) NULL,
+                (struct lease *) NULL, (struct client_state *) NULL,
+                options, (struct option_state *) NULL, &global_scope, oc, MDL))
+        {
+          ldap_base_dn = dmalloc (db.len + 1, MDL);
+          if (!ldap_base_dn)
+            log_fatal ("no memory for ldap password");
+          memcpy (ldap_base_dn, db.data, db.len);
+          ldap_base_dn[db.len] = 0;
+          data_string_forget (&db, MDL);
+        }
+
+      oc = lookup_option (&server_universe, options, SV_LDAP_METHOD);
+      if (oc &&
+          evaluate_option_cache (&db,  (struct packet*) NULL,
+                (struct lease *) NULL, (struct client_state *) NULL,
+                options, (struct option_state *) NULL, &global_scope, oc, MDL))
+        {
+
+          if (db.len == 1) 
+            ldap_method = db.data [0];
+          else
+            log_fatal ("invalid dns update type");
+          data_string_forget (&db, MDL);
+        }
+
+      option_state_dereference (&options, MDL);
+    }
+
+  if (ldap_server == NULL || ldap_username == NULL || ldap_password == NULL ||
+      ldap_base_dn == NULL)
+    {
+      log_info ("Not searching LDAP since ldap-server, ldap-username, ldap-password and ldap-base-dn were not specified in the config file");
+      disable_ldap = 1;
+      return;
+    }
+
+#if defined (DEBUG_LDAP)
+  log_info ("Connecting to LDAP server ldap://%s", ldap_server);
+#endif
+
+  char *tmpserver = NULL;
+  if ((tmpserver = malloc(strlen(ldap_server) + 8)) == NULL)
+    {
+      log_error ("Cannot init tmpldapserver string to ldap://%s", ldap_server);
+      disable_ldap = 1;
+      return;
+    }
+
+  if (sprintf(tmpserver, "ldap://%s", ldap_server) == -1)
+    {
+      log_error ("Cannot init tmpldapserver via sprintf()");
+      disable_ldap = 1;
+      return;
+    }
+
+  ldap_initialize (&ld, tmpserver);
+  if (ld == NULL)
+    {
+      log_error ("Cannot init ldap session to %s", ldap_server);
+      disable_ldap = 1;
+      return;
+    }
+
+  free (tmpserver);
+
+  struct berval cred;
+  cred.bv_val = strdup(ldap_password);
+  cred.bv_len = strlen(ldap_password);
+  ret = ldap_sasl_bind_s (ld, ldap_username, LDAP_SASL_SIMPLE,
+                          &cred, NULL,NULL, NULL);
+  if (ret != LDAP_SUCCESS)
+    {
+      log_error ("Error: Cannot log into ldap server %s: %s", ldap_server,
+                 ldap_err2string (ret));
+      disable_ldap = 1;
+      ldap_unbind_ext (ld, NULL, NULL);
+      ld = NULL;
+      return;
+    }
+
+#if defined (DEBUG_LDAP)
+  log_info ("Successfully logged into LDAP server %s", ldap_server);
+#endif
+}
+
+
+static int
+ldap_read_function (struct parse *cfile)
+{
+  char *dn, eofstring[2] = {EOF, '\0'};
+  struct ldap_config_stack *curentry;
+  LDAPMessage * ent, * res;
+  int ret;
+ 
+  cfile->inbuf[0] = '\0';
+  cfile->buflen = 0;
+  while (1)
+    {
+      if (ldap_stack == NULL)
+        {
+          strncat (cfile->inbuf, eofstring, LDAP_BUFFER_SIZE);
+          cfile->buflen = strlen (cfile->inbuf);
+          cfile->bufix = 1;
+          return (cfile->inbuf[0]);
+        }
+
+      if (ldap_stack->processed && ldap_stack->children != NULL)
+        curentry = ldap_stack->children;
+      else
+        curentry = ldap_stack;
+
+      dn = ldap_get_dn (ld, curentry->ldent);
+#if defined(DEBUG_LDAP)
+      log_info ("Found LDAP entry '%s'", dn);
+#endif
+
+      ldap_generate_config_string (curentry, cfile);
+      if (strlen (cfile->inbuf) == 0)
+        {
+#if defined(DEBUG_LDAP)
+          log_info ("Skipping LDAP entry '%s'", dn);
+#endif
+          ldap_memfree (dn);
+          dn = NULL;
+          next_ldap_entry (cfile);
+          continue;
+        }
+
+      curentry->processed = 1;
+      break;
+    }
+
+  if (ld == NULL)
+    ldap_start ();
+
+  if (ld == NULL)
+    {
+      strncat (cfile->inbuf, eofstring, LDAP_BUFFER_SIZE);
+      cfile->buflen = strlen (cfile->inbuf);
+      cfile->bufix = 1;
+      return (cfile->inbuf[0]);
+    }
+
+  if ((ret = ldap_search_ext_s (ld, dn, LDAP_SCOPE_ONELEVEL, "objectClass=*", 
+                                NULL, 0, NULL, NULL, NULL, 0,
+                                &res)) != LDAP_SUCCESS)
+    {
+      ldap_unbind_ext (ld, NULL, NULL);
+      ld = NULL;
+
+      strncat (cfile->inbuf, eofstring, LDAP_BUFFER_SIZE);
+      cfile->buflen = strlen (cfile->inbuf);
+      cfile->bufix = 1;
+      return (cfile->inbuf[0]);
+    }
+
+  ldap_memfree (dn);
+
+  ent = ldap_first_entry (ld, res);
+  if (ent != NULL)
+    add_to_config_stack (res, ent);
+  else
+    {
+      ldap_msgfree (res);
+      next_ldap_entry (cfile);
+    }
+
+#if defined (DEBUG_LDAP)
+  log_info ("Sending config line '%s'", cfile->inbuf);
+#endif
+
+  cfile->buflen = strlen (cfile->inbuf);
+  cfile->bufix = 1;
+  return (cfile->inbuf[0]);
+}
+
+
+static char *
+ldap_get_host_name (LDAPMessage * ent)
+{
+  struct berval **name;
+  char *ret;
+
+  ret = NULL;
+  if ((name = ldap_get_values_len (ld, ent, "cn")) == NULL || name[0] == NULL)
+    {
+      if (name != NULL)
+        ldap_value_free_len (name);
+
+#if defined (DEBUG_LDAP)
+      log_info ("Cannot get cn attribute for LDAP entry %s",
+                ldap_get_dn (ld, ent));
+#endif
+      return (NULL);
+    }
+
+  ret = dmalloc (strlen (name[0]->bv_val) + 1, MDL);
+  strcpy (ret, name[0]->bv_val);
+  ldap_value_free_len (name);
+
+  return (ret);
+}
+
+
+isc_result_t
+ldap_read_config (void)
+{
+  struct berval **temp;
+  char *buffer, dn[256];
+  LDAPMessage * ldres, * ent;
+  struct parse *cfile;
+  struct utsname unme;
+  isc_result_t res;
+  int ret;
+
+
+  buffer = dmalloc (LDAP_BUFFER_SIZE, MDL);
+  cfile = (struct parse *) NULL;
+  res = new_parse (&cfile, -1, buffer, LDAP_BUFFER_SIZE, "LDAP", 0);
+  if (res != ISC_R_SUCCESS)
+    return (res);
+
+  cfile->bufix = cfile->buflen = 0;
+  cfile->read_function = ldap_read_function;
+
+  if (ld == NULL)
+    ldap_start ();
+  if (ld == NULL)
+    return (ldap_server == NULL ? ISC_R_SUCCESS : ISC_R_FAILURE);
+  
+  uname (&unme);
+  snprintf (dn, sizeof (dn), "(&(objectClass=dhcpServer)(cn=%s))", 
+            unme.nodename);
+
+  if ((ret = ldap_search_ext_s (ld, ldap_base_dn, LDAP_SCOPE_SUBTREE, dn, NULL, 
+                               0, NULL, NULL, NULL, 0, &ldres)) != LDAP_SUCCESS)
+    {
+      ldap_unbind_ext (ld, NULL, NULL);
+      ld = NULL;
+      log_error ("Cannot search LDAP for %s: %s", dn, ldap_err2string (ret));
+      return (ISC_R_FAILURE);
+    }
+
+  if ((ent = ldap_first_entry (ld, ldres)) == NULL)
+    {
+      ldap_unbind_ext (ld, NULL, NULL);
+      ld = NULL;
+      log_error ("Error: Cannot find LDAP entry matching %s", dn);
+      return (ISC_R_FAILURE);
+    }
+
+#if defined(DEBUG_LDAP)
+  buffer = ldap_get_dn (ld, ent);
+  log_info ("Found LDAP entry '%s'", buffer);
+  ldap_memfree (buffer);
+#endif
+
+  if ((temp = ldap_get_values_len (ld, ent, "dhcpServiceDN")) == NULL ||
+      temp[0]->bv_val == NULL)
+    {
+      if (temp != NULL)
+        ldap_value_free_len (temp);
+
+      ldap_unbind_ext (ld, NULL, NULL);
+      ld = NULL;
+      log_error ("Error: Cannot find LDAP entry matching %s", dn);
+      return (ISC_R_FAILURE);
+    }
+
+  ldap_msgfree (ldres);
+
+  if ((ret = ldap_search_ext_s (ld, temp[0]->bv_val, LDAP_SCOPE_BASE, 
+                                "objectClass=*", NULL, 0,
+                                NULL, NULL, NULL, 0, &ldres)) != LDAP_SUCCESS)
+    {
+      ldap_value_free_len (temp);
+      ldap_unbind_ext (ld, NULL, NULL);
+      ld = NULL;
+      log_error ("Cannot search LDAP for %s: %s", temp[0]->bv_val, 
+                 ldap_err2string (ret));
+      return (ISC_R_FAILURE);
+    }
+
+  if ((ent = ldap_first_entry (ld, ldres)) == NULL)
+    {
+      ldap_value_free_len (temp);
+      ldap_unbind_ext (ld, NULL, NULL);
+      ld = NULL;
+      log_error ("Error: Cannot find LDAP entry matching %s", temp[0]->bv_val);
+      return (ISC_R_FAILURE);
+    }
+
+  ldap_value_free_len (temp);
+
+  add_to_config_stack (ldres, ent);
+
+  res = conf_file_subparse (cfile, root_group, ROOT_GROUP);
+  end_parse (&cfile);
+
+  return (res);
+}
+
+
+/* This function will parse the dhcpOption and dhcpStatements field in the LDAP
+   entry if it exists. Right now, type will be either HOST_DECL or CLASS_DECL.
+   If we are parsing a HOST_DECL, this always returns 0. If we are parsing a 
+   CLASS_DECL, this will return what the current lease limit is in LDAP. If
+   there is no lease limit specified, we return 0 */
+
+static int
+ldap_parse_options (LDAPMessage * ent, struct group *group,
+                         int type, struct host_decl *host,
+                         struct class **class)
+{
+  struct berval **temp;
+  char option_buffer[8192];
+  int i, declaration, lease_limit;
+  enum dhcp_token token;
+  struct parse *cfile;
+  isc_result_t res;
+  const char *val;
+
+  lease_limit = 0;
+  *option_buffer = '\0';
+  if ((temp = ldap_get_values_len (ld, ent, "dhcpStatements")) != NULL)
+    {
+      for (i=0; temp[i] != NULL && temp[i]->bv_val != NULL; i++)
+        {
+          if (strncasecmp ("lease limit ", temp[i]->bv_val, 12) == 0)
+            {
+              lease_limit = strtol ((temp[i]->bv_val) + 12, NULL, 10);
+              continue;
+            }
+
+          strncat (option_buffer, temp[i]->bv_val, sizeof (option_buffer) - strlen (option_buffer) - 1);
+          strncat (option_buffer, ";\n", sizeof (option_buffer) - strlen (option_buffer) - 1);
+        }
+      ldap_value_free_len (temp);
+    }
+
+  if ((temp = ldap_get_values_len (ld, ent, "dhcpOption")) != NULL)
+    {
+      for (i=0; temp[i] != NULL && temp[i]->bv_val != NULL; i++)
+        {
+          strncat (option_buffer, "option ", sizeof (option_buffer) - strlen (option_buffer) - 1);
+          strncat (option_buffer, temp[i]->bv_val, sizeof (option_buffer) - strlen (option_buffer) - 1);
+          strncat (option_buffer, ";\n", sizeof (option_buffer) - strlen (option_buffer) - 1);
+        }
+      ldap_value_free_len (temp);
+    }
+
+  if (*option_buffer == '\0')
+    return (lease_limit);
+
+  cfile = (struct parse *) NULL;
+  res = new_parse (&cfile, -1, option_buffer, strlen (option_buffer), 
+                   type == HOST_DECL ? "LDAP-HOST" : "LDAP-SUBCLASS", 0);
+  if (res != ISC_R_SUCCESS)
+    return (lease_limit);
+
+#if defined (DEBUG_LDAP)
+  log_info ("Sending the following options: '%s'", option_buffer);
+#endif
+
+  declaration = 0;
+  do {
+     token = peek_token (&val, NULL, cfile);
+     if (token == END_OF_FILE)
+       break;
+      declaration = parse_statement (cfile, group, type, host, declaration);
+    } while (1);
+
+  end_parse (&cfile);
+
+  return (lease_limit);
+}
+
+
+
+int
+find_haddr_in_ldap (struct host_decl **hp, int htype, unsigned hlen,
+                    const unsigned char *haddr, const char *file, int line)
+{
+  char buf[60], *type_str;
+  LDAPMessage * res, *ent;
+  struct host_decl * host;
+  isc_result_t status;
+  int ret;
+
+  if (disable_ldap || ldap_method == LDAP_METHOD_STATIC)
+    return (0);
+
+  if (ld == NULL)
+    ldap_start ();
+  if (ld == NULL)
+    return (0);
+
+  switch (htype)
+    {
+      case HTYPE_ETHER:
+        type_str = "ethernet";
+        break;
+      case HTYPE_IEEE802:
+        type_str = "token-ring";
+        break;
+      case HTYPE_FDDI:
+        type_str = "fddi";
+        break;
+      default:
+        log_info ("Ignoring unknown type %d", htype);
+        return (0);
+    }
+  
+  snprintf (buf, sizeof (buf), "dhcpHWAddress=%s %s", type_str,
+            print_hw_addr (htype, hlen, haddr));
+#if defined (DEBUG_LDAP)
+  log_info ("Searching for %s in LDAP tree %s", buf, ldap_base_dn);
+#endif
+
+  if ((ret = ldap_search_ext_s (ld, ldap_base_dn, LDAP_SCOPE_SUBTREE, 
+                                buf, NULL, 0, NULL, NULL, NULL, 0, 
+                                &res)) != LDAP_SUCCESS)
+    {
+      if (ret != LDAP_NO_SUCH_OBJECT)
+        {
+          log_error ("Cannot search for %s in LDAP tree %s: %s", buf, 
+                     ldap_base_dn, ldap_err2string (ret));
+          ldap_unbind_ext (ld, NULL, NULL);
+          ld = NULL;
+        }
+#if defined (DEBUG_LDAP)
+      else
+        log_info ("ldap_search_ext_s returned %s when searching for %s in %s",
+                  ldap_err2string (ret), buf, ldap_base_dn);
+#endif
+
+      return (0);
+    }
+
+  if ((ent = ldap_first_entry (ld, res)) != NULL)
+    {
+#if defined (DEBUG_LDAP)
+      log_info ("Found LDAP entry %s", ldap_get_dn (ld, ent));
+#endif
+      
+      host = (struct host_decl *)0;
+      status = host_allocate (&host, MDL);
+      if (status != ISC_R_SUCCESS)
+        {
+          log_fatal ("can't allocate host decl struct: %s", 
+                     isc_result_totext (status)); 
+          return (0);
+        }
+
+      host->name = ldap_get_host_name (ent);
+      if (host->name == NULL)
+        {
+          host_dereference (&host, MDL);
+          ldap_msgfree (res);
+          return (0);
+        }
+
+      if (!clone_group (&host->group, root_group, MDL))
+        {
+          log_fatal ("can't clone group for host %s", host->name);
+          host_dereference (&host, MDL);
+          return (0);
+        }
+
+      ldap_parse_options (ent, host->group, HOST_DECL, host, NULL);
+
+      *hp = host;
+      ldap_msgfree (res);
+      return (1);
+    }
+
+
+  ldap_msgfree (res);
+  return (0);
+}
+
+
+int
+find_subclass_in_ldap (struct class *class, struct class **newclass, 
+                       struct data_string *data)
+{
+  LDAPMessage * res, * ent;
+  int ret, lease_limit;
+  isc_result_t status;
+  char buf[1024];
+
+  if (disable_ldap || ldap_method == LDAP_METHOD_STATIC)
+    return (0);
+
+  if (ld == NULL)
+    ldap_start ();
+  if (ld == NULL)
+    return (0);
+
+  snprintf (buf, sizeof (buf), "(&(objectClass=dhcpSubClass)(cn=%s)(dhcpClassData=%s))", print_hex_1 (data->len, data->data, 60), print_hex_2 (strlen (class->name), (const u_int8_t *) class->name, 60));
+#if defined (DEBUG_LDAP)
+  log_info ("Searching LDAP for %s", buf);
+#endif
+
+  if ((ret = ldap_search_ext_s (ld, ldap_base_dn, LDAP_SCOPE_SUBTREE, 
+                                buf, NULL, 0, NULL, NULL, NULL, 0,
+                                &res)) != LDAP_SUCCESS)
+    {
+      if (ret != LDAP_NO_SUCH_OBJECT)
+        {
+          log_error ("Cannot search for %s in LDAP tree %s: %s", buf, 
+                     ldap_base_dn, ldap_err2string (ret));
+          ldap_unbind_ext (ld, NULL, NULL);
+          ld = NULL;
+        }
+#if defined (DEBUG_LDAP)
+      else
+        log_info ("ldap_search_ext_s returned %s when searching for %s in %s",
+                  ldap_err2string (ret), buf, ldap_base_dn);
+#endif
+
+      return (0);
+    }
+
+  if ((ent = ldap_first_entry (ld, res)) != NULL)
+    {
+#if defined (DEBUG_LDAP)
+      log_info ("Found LDAP entry %s", ldap_get_dn (ld, ent));
+#endif
+      
+      status = class_allocate (newclass, MDL);
+      if (status != ISC_R_SUCCESS)
+        {
+          log_error ("Cannot allocate memory for a new class");
+          return (0);
+        }
+
+      group_reference (&(*newclass)->group, class->group, MDL);
+      class_reference (&(*newclass)->superclass, class, MDL);
+      lease_limit = ldap_parse_options (ent, (*newclass)->group, 
+                                        CLASS_DECL, NULL, newclass);
+      if (lease_limit == 0)
+        (*newclass)->lease_limit = class->lease_limit; 
+      else
+        class->lease_limit = lease_limit;
+
+      if ((*newclass)->lease_limit) 
+        {
+          (*newclass)->billed_leases = 
+              dmalloc ((*newclass)->lease_limit * sizeof (struct lease *), MDL);
+          if (!(*newclass)->billed_leases) 
+            {
+              log_error ("no memory for billing");
+              class_dereference (newclass, MDL);
+              return (0);
+            }
+          memset ((*newclass)->billed_leases, 0, 
+                ((*newclass)->lease_limit * sizeof (*newclass)->billed_leases));
+        }
+
+      data_string_copy (&(*newclass)->hash_string, data, MDL);
+
+      ldap_msgfree (res);
+      return (1);
+    }
+
+
+  ldap_msgfree (res);
+  return (0);
+}
+
+#endif
+
diff -up dhcp-3.1.0/server/confpars.c.ldap dhcp-3.1.0/server/confpars.c
--- dhcp-3.1.0/server/confpars.c.ldap	2007-06-28 13:20:40.000000000 -0400
+++ dhcp-3.1.0/server/confpars.c	2007-10-22 16:29:48.000000000 -0400
@@ -63,7 +63,17 @@ void parse_trace_setup ()
 
 isc_result_t readconf ()
 {
-	return read_conf_file (path_dhcpd_conf, root_group, ROOT_GROUP, 0);
+	isc_result_t res;
+
+	res = read_conf_file (path_dhcpd_conf, root_group, ROOT_GROUP, 0);
+#if defined(LDAP_CONFIGURATION)
+	if (res != ISC_R_SUCCESS)
+		return (res);
+
+	return ldap_read_config ();
+#else
+	return (res);
+#endif
 }
 
 isc_result_t read_conf_file (const char *filename, struct group *group,
diff -up dhcp-3.1.0/server/class.c.ldap dhcp-3.1.0/server/class.c
--- dhcp-3.1.0/server/class.c.ldap	2006-06-01 16:23:17.000000000 -0400
+++ dhcp-3.1.0/server/class.c	2007-10-22 16:29:48.000000000 -0400
@@ -90,6 +90,7 @@ int check_collection (packet, lease, col
 	int matched = 0;
 	int status;
 	int ignorep;
+	int classfound;
 
 	for (class = collection -> classes; class; class = class -> nic) {
 #if defined (DEBUG_CLASS_MATCHING)
@@ -135,9 +136,15 @@ int check_collection (packet, lease, col
 				   class -> submatch, MDL));
 			if (status && data.len) {
 				nc = (struct class *)0;
-				if (class_hash_lookup (&nc, class -> hash,
-						       (const char *)data.data,
-						       data.len, MDL)) {
+				classfound = class_hash_lookup (&nc, class -> hash,
+					(const char *)data.data, data.len, MDL);
+
+#ifdef LDAP_CONFIGURATION
+				if (!classfound && find_subclass_in_ldap (class, &nc, &data))
+					classfound = 1;
+#endif
+
+				if (classfound) {
 #if defined (DEBUG_CLASS_MATCHING)
 					log_info ("matches subclass %s.",
 					      print_hex_1 (data.len,
diff -up dhcp-3.1.0/server/stables.c.ldap dhcp-3.1.0/server/stables.c
--- dhcp-3.1.0/server/stables.c.ldap	2007-04-27 18:48:10.000000000 -0400
+++ dhcp-3.1.0/server/stables.c	2007-10-22 16:29:48.000000000 -0400
@@ -238,9 +238,38 @@ static struct option server_options[] = 
 	{ "adaptive-lease-time-threshold", "B",	&server_universe,  50, 1 },
 	{ "do-reverse-updates", "f",		&server_universe,  51, 1 },
 	{ "fqdn-reply", "f",			&server_universe,  52, 1 },
+#if defined(LDAP_CONFIGURATION)
+	{ "ldap-server", "t",				&server_universe, 53 },
+	{ "ldap-port", "d",					&server_universe, 54 },
+	{ "ldap-username", "t",				&server_universe, 55 },
+	{ "ldap-password", "t",				&server_universe, 56 },
+	{ "ldap-base-dn", "t",				&server_universe, 57 },
+	{ "ldap-method", "Nldap-methods.",	&server_universe, 58 },
+#else
+	{ "unknown-53", "X",				&server_universe, 53 },
+	{ "unknown-54", "X",				&server_universe, 54 },
+	{ "unknown-55", "X",				&server_universe, 55 },
+	{ "unknown-56", "X",				&server_universe, 56 },
+	{ "unknown-57", "X",				&server_universe, 57 },
+	{ "unknown-58", "X",				&server_universe, 58 },
+#endif
 	{ NULL, NULL, NULL, 0, 0 }
 };
 
+#if defined(LDAP_CONFIGURATION)
+struct enumeration_value ldap_values [] = {
+	{ "static", LDAP_METHOD_STATIC },
+	{ "dynamic", LDAP_METHOD_DYNAMIC },
+	{ (char *) 0, 0 }
+};
+
+struct enumeration ldap_methods = {
+	(struct enumeration *)0,
+	"ldap-methods",
+	ldap_values
+};
+#endif
+
 struct enumeration_value ddns_styles_values [] = {
 	{ "none", 0 },
 	{ "ad-hoc", 1 },
diff -up dhcp-3.1.0/common/print.c.ldap dhcp-3.1.0/common/print.c
--- dhcp-3.1.0/common/print.c.ldap	2007-05-29 13:49:44.000000000 -0400
+++ dhcp-3.1.0/common/print.c	2007-10-22 16:29:48.000000000 -0400
@@ -168,9 +168,9 @@ char *print_base64 (const unsigned char 
 }
 
 char *print_hw_addr (htype, hlen, data)
-	int htype;
-	int hlen;
-	unsigned char *data;
+	const int htype;
+	const int hlen;
+	const unsigned char *data;
 {
 	static char habuf [49];
 	char *s;
diff -up dhcp-3.1.0/common/conflex.c.ldap dhcp-3.1.0/common/conflex.c
--- dhcp-3.1.0/common/conflex.c.ldap	2007-05-29 13:49:44.000000000 -0400
+++ dhcp-3.1.0/common/conflex.c	2007-10-22 16:29:48.000000000 -0400
@@ -47,6 +47,7 @@ static enum dhcp_token read_string PROTO
 static enum dhcp_token read_number PROTO ((int, struct parse *));
 static enum dhcp_token read_num_or_name PROTO ((int, struct parse *));
 static enum dhcp_token intern PROTO ((unsigned char *, enum dhcp_token));
+static int read_function PROTO ((struct parse *));
 
 isc_result_t new_parse (cfile, file, inbuf, buflen, name, eolp)
 	struct parse **cfile;
@@ -74,6 +75,10 @@ isc_result_t new_parse (cfile, file, inb
 	tmp -> file = file;
 	tmp -> eol_token = eolp;
 
+	if (file != -1) {
+		tmp -> read_function = read_function;;
+	}
+
 	tmp -> bufix = 0;
 	tmp -> buflen = buflen;
 	if (inbuf) {
@@ -113,22 +118,11 @@ static int get_char (cfile)
 	int c;
 
 	if (cfile -> bufix == cfile -> buflen) {
-		if (cfile -> file != -1) {
-			cfile -> buflen =
-				read (cfile -> file,
-				      cfile -> inbuf, cfile -> bufsiz);
-			if (cfile -> buflen == 0) {
-				c = EOF;
-				cfile -> bufix = 0;
-			} else if (cfile -> buflen < 0) {
-				c = EOF;
-				cfile -> bufix = cfile -> buflen = 0;
-			} else {
-				c = cfile -> inbuf [0];
-				cfile -> bufix = 1;
-			}
-		} else
+		if (cfile -> read_function) {
+			c = cfile -> read_function (cfile);
+		} else {
 			c = EOF;
+		}
 	} else {
 		c = cfile -> inbuf [cfile -> bufix];
 		cfile -> bufix++;
@@ -1213,3 +1207,23 @@ static enum dhcp_token intern (atom, dfv
 	}
 	return dfv;
 }
+
+static int
+read_function (struct parse * cfile)
+{
+	int c;
+
+	cfile -> buflen = read (cfile -> file, cfile -> inbuf, cfile -> bufsiz);
+	if (cfile -> buflen == 0) {
+		c = EOF;
+		cfile -> bufix = 0;
+	} else if (cfile -> buflen < 0) {
+		c = EOF;
+		cfile -> bufix = cfile -> buflen = 0;
+	} else {
+		c = cfile -> inbuf [0];
+		cfile -> bufix = 1;
+	}
+
+	return c;
+}
diff -up dhcp-3.1.0/includes/dhcpd.h.ldap dhcp-3.1.0/includes/dhcpd.h
--- dhcp-3.1.0/includes/dhcpd.h.ldap	2007-05-29 13:49:44.000000000 -0400
+++ dhcp-3.1.0/includes/dhcpd.h	2007-10-22 16:29:56.000000000 -0400
@@ -81,6 +81,11 @@ typedef struct hash_table class_hash_t;
 #include <isc-dhcp/result.h>
 #include <omapip/omapip_p.h>
 
+#if defined(LDAP_CONFIGURATION)
+# include <ldap.h>
+# include <sys/utsname.h> /* for uname() */
+#endif
+
 #if !defined (BYTE_NAME_HASH_SIZE)
 # define BYTE_NAME_HASH_SIZE	401	/* Default would be rediculous. */
 #endif
@@ -251,6 +256,8 @@ struct parse {
 	char *inbuf;
 	unsigned bufix, buflen;
 	unsigned bufsiz;
+
+	int (*read_function) (struct parse *);
 };
 
 /* Variable-length array of data. */
@@ -362,6 +369,26 @@ struct hardware {
 	u_int8_t hbuf [17];
 };
 
+#if defined(LDAP_CONFIGURATION)
+# define LDAP_BUFFER_SIZE		8192
+# define LDAP_METHOD_STATIC		0
+# define LDAP_METHOD_DYNAMIC	1
+
+/* This is a tree of the current configuration we are building from LDAP */
+struct ldap_config_stack {
+	LDAPMessage * res;	/* Pointer returned from ldap_search */
+	LDAPMessage * ldent;	/* Current item in LDAP that we're processing.
+							in res */
+	int close_brace;	/* Put a closing } after we're through with
+						this item */
+	int processed;	/* We set this flag if this base item has been
+					processed. After this base item is processed,
+					we can start processing the children */
+	struct ldap_config_stack *children;
+	struct ldap_config_stack *next;
+};
+#endif
+
 typedef enum {
 	server_startup = 0,
 	server_running = 1,
@@ -558,6 +585,15 @@ struct lease_state {
 # define DEFAULT_PING_TIMEOUT 1
 #endif
 
+#if defined(LDAP_CONFIGURATION)
+# define SV_LDAP_SERVER		47
+# define SV_LDAP_PORT		48
+# define SV_LDAP_USERNAME	49
+# define SV_LDAP_PASSWORD	50
+# define SV_LDAP_BASE_DN	51
+# define SV_LDAP_METHOD		52
+#endif
+
 #if !defined (DEFAULT_DEFAULT_LEASE_TIME)
 # define DEFAULT_DEFAULT_LEASE_TIME 43200
 #endif
@@ -1702,7 +1738,7 @@ extern int db_time_format;
 char *quotify_string (const char *, const char *, int);
 char *quotify_buf (const unsigned char *, unsigned, const char *, int);
 char *print_base64 (const unsigned char *, unsigned, const char *, int);
-char *print_hw_addr PROTO ((int, int, unsigned char *));
+char *print_hw_addr PROTO ((const int, const int, const unsigned char *));
 void print_lease PROTO ((struct lease *));
 void dump_raw PROTO ((const unsigned char *, unsigned));
 void dump_packet_option (struct option_cache *, struct packet *,
@@ -2812,3 +2848,13 @@ OMAPI_OBJECT_ALLOC_DECL (dhcp_failover_l
 #endif /* FAILOVER_PROTOCOL */
 
 const char *binding_state_print (enum failover_state);
+
+/* ldap.c */
+#if defined(LDAP_CONFIGURATION)
+extern struct enumeration ldap_methods;
+isc_result_t ldap_read_config (void);
+int find_haddr_in_ldap (struct host_decl **, int, unsigned,
+                        const unsigned char *, const char *, int);
+int find_subclass_in_ldap (struct class *, struct class **,
+                           struct data_string *);
+#endif
diff -up dhcp-3.1.0/includes/site.h.ldap dhcp-3.1.0/includes/site.h
--- dhcp-3.1.0/includes/site.h.ldap	2006-07-31 18:19:51.000000000 -0400
+++ dhcp-3.1.0/includes/site.h	2007-10-22 16:29:48.000000000 -0400
@@ -183,3 +183,13 @@
    traces. */
 
 #define TRACING
+
+/* Define this if you want to read your config from LDAP. Read README.ldap
+   about how to set this up */
+
+#define LDAP_CONFIGURATION
+
+#define _PATH_DHCPD_DB    "/var/lib/dhcpd/dhcpd.leases"
+#define _PATH_DHCLIENT_DB "/var/lib/dhclient/dhclient.leases"
+#define _PATH_DHCPD_DB    "/var/lib/dhcpd/dhcpd.leases"
+#define _PATH_DHCLIENT_DB "/var/lib/dhclient/dhclient.leases"