Blob Blame History Raw
--- dhcp-3.0.5/common/conflex.c.ldapconf	2007-01-31 20:39:38.000000000 -0500
+++ dhcp-3.0.5/common/conflex.c	2007-01-31 20:39:38.000000000 -0500
@@ -47,6 +47,7 @@
 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 ((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 @@
 	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 @@
 	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++;
@@ -1130,3 +1124,25 @@
 	}
 	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;
+}
+
--- dhcp-3.0.5/common/print.c.ldapconf	2007-01-31 20:39:38.000000000 -0500
+++ dhcp-3.0.5/common/print.c	2007-01-31 20:39:38.000000000 -0500
@@ -166,9 +166,9 @@
 }
 
 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;
--- /dev/null	2007-01-31 10:24:38.956568237 -0500
+++ dhcp-3.0.5/contrib/dhcpd-conf-to-ldap.pl	2007-01-31 20:39:38.000000000 -0500
@@ -0,0 +1,517 @@
+#!/usr/bin/perl -w
+
+# Brian Masney <masneyb@ntelos.net>
+# To use this script, set your base DN below. Then run 
+# ./dhcpd-conf-to-ldap.pl < /path-to-dhcpd-conf/dhcpd.conf > output-file
+# The output of this script will generate entries in LDIF format. You can use
+# the slapadd command to add these entries into your LDAP server. You will
+# definately want to double check that your LDAP entries are correct before
+# you load them into LDAP.
+
+# This script does not do much error checking. Make sure before you run this
+# that the DHCP server doesn't give any errors about your config file
+
+use Sys::Hostname;
+
+my $basedn = "dc=ntelos, dc=net";
+
+sub next_token
+{
+  local ($lowercase) = @_;
+  local ($token, $newline);
+
+  do 
+    {
+      if (!defined ($line) || length ($line) == 0)
+        {
+          $line = <>;
+          return undef if !defined ($line);
+          chop $line;
+          $line_number++;
+          $token_number = 0;
+        }
+
+      $line =~ s/#.*//;
+      $line =~ s/^\s+//;
+      $line =~ s/\s+$//;
+    }
+  while (length ($line) == 0);
+
+  if (($token, $newline) = $line =~ /^(.*?)\s+(.*)/)
+    {
+      $line = $newline;
+    }
+  else
+    {
+      $token = $line;
+      $line = '';
+    }
+  $token_number++;
+
+  $token =~ y/[A-Z]/[a-z]/ if $lowercase;
+
+  return ($token);
+}
+
+
+sub remaining_line
+{
+  local ($tmp, $str);
+
+  $str = "";
+  while (($tmp = next_token (0)))
+    {
+      $str .= ' ' if !($str eq "");
+      $str .= $tmp;
+      last if $tmp =~ /;\s*$/;
+    }
+
+  $str =~ s/;$//;
+  return ($str);
+}
+
+
+sub
+add_dn_to_stack
+{
+  local ($dn) = @_;
+
+  $current_dn = "$dn, $current_dn";
+}
+
+
+sub
+remove_dn_from_stack
+{
+  $current_dn =~ s/^.*?,\s*//;
+}
+
+
+sub
+parse_error
+{
+  print "Parse error on line number $line_number at token number $token_number\n";
+  exit (1);
+}
+
+
+sub
+print_entry
+{
+  return if (scalar keys %curentry == 0);
+
+  if (!defined ($curentry{'type'}))
+    {
+      $host = hostname ();
+      $hostdn = "cn=$host, $basedn";
+      print "dn: $hostdn\n";
+      print "objectClass: top\n";
+      print "objectClass: dhcpServer\n";
+      print "cn: $host\n";
+      print "dhcpServiceDN: $current_dn\n\n";
+
+      print "dn: $current_dn\n";
+      print "cn: DHCP Config\n";
+      print "objectClass: top\n";
+      print "objectClass: dhcpService\n";
+      if (defined ($curentry{'options'}))
+        {
+          print "objectClass: dhcpOptions\n";
+        }
+      print "dhcpPrimaryDN: $hostdn\n";
+    }
+  elsif ($curentry{'type'} eq 'subnet')
+    {
+      print "dn: $current_dn\n";
+      print "cn: " . $curentry{'ip'} . "\n";
+      print "objectClass: top\n";
+      print "objectClass: dhcpSubnet\n";
+      if (defined ($curentry{'options'}))
+        {
+          print "objectClass: dhcpOptions\n";
+        }
+      
+      print "dhcpNetMask: " . $curentry{'netmask'} . "\n";
+      if (defined ($curentry{'range'}))
+        {
+          print "dhcpRange: " . $curentry{'range'} . "\n";
+        }
+    }
+  elsif ($curentry{'type'} eq 'shared-network')
+    {
+      print "dn: $current_dn\n";
+      print "cn: " . $curentry{'descr'} . "\n";
+      print "objectClass: top\n";
+      print "objectClass: dhcpSharedNetwork\n";
+      if (defined ($curentry{'options'}))
+        {
+          print "objectClass: dhcpOptions\n";
+        }
+    }
+  elsif ($curentry{'type'} eq 'group')
+    {
+      print "dn: $current_dn\n";
+      print "cn: group\n";
+      print "objectClass: top\n";
+      print "objectClass: dhcpGroup\n";
+      if (defined ($curentry{'options'}))
+        {
+          print "objectClass: dhcpOptions\n";
+        }
+    }
+  elsif ($curentry{'type'} eq 'host')
+    {
+      print "dn: $current_dn\n";
+      print "cn: " . $curentry{'host'} . "\n";
+      print "objectClass: top\n";
+      print "objectClass: dhcpHost\n";
+      if (defined ($curentry{'options'}))
+        {
+          print "objectClass: dhcpOptions\n";
+        }
+
+      if (defined ($curentry{'hwaddress'}))
+        {
+          print "dhcpHWAddress: " . $curentry{'hwaddress'} . "\n";
+        }
+    }
+  elsif ($curentry{'type'} eq 'pool')
+    {
+      print "dn: $current_dn\n";
+      print "cn: pool\n";
+      print "objectClass: top\n";
+      print "objectClass: dhcpPool\n";
+      if (defined ($curentry{'options'}))
+        {
+          print "objectClass: dhcpOptions\n";
+        }
+
+      if (defined ($curentry{'range'}))
+        {
+          print "dhcpRange: " . $curentry{'range'} . "\n";
+        }
+    }
+  elsif ($curentry{'type'} eq 'class')
+    {
+      print "dn: $current_dn\n";
+      print "cn: " . $curentry{'class'} . "\n";
+      print "objectClass: top\n";
+      print "objectClass: dhcpClass\n";
+      if (defined ($curentry{'options'}))
+        {
+          print "objectClass: dhcpOptions\n";
+        }
+    }
+  elsif ($curentry{'type'} eq 'subclass')
+    {
+      print "dn: $current_dn\n";
+      print "cn: " . $curentry{'subclass'} . "\n";
+      print "objectClass: top\n";
+      print "objectClass: dhcpSubClass\n";
+      if (defined ($curentry{'options'}))
+        {
+          print "objectClass: dhcpOptions\n";
+        }
+      print "dhcpClassData: " . $curentry{'class'} . "\n";
+    }
+
+  if (defined ($curentry{'statements'}))
+    {
+      foreach $statement (@{$curentry{'statements'}})
+        {
+          print "dhcpStatements: $statement\n";
+        }
+    }
+
+  if (defined ($curentry{'options'}))
+    {
+      foreach $statement (@{$curentry{'options'}})
+        {
+          print "dhcpOption: $statement\n";
+        }
+    }
+
+  print "\n";
+  undef (%curentry);
+}
+
+
+sub parse_netmask
+{
+  local ($netmask) = @_;
+  local ($i);
+
+  if ((($a, $b, $c, $d) = $netmask =~ /^(\d+)\.(\d+)\.(\d+)\.(\d+)$/) != 4)
+    {
+      parse_error ();
+    }
+
+  $num = (($a & 0xff) << 24) |
+         (($b & 0xff) << 16) |
+         (($c & 0xff) << 8) |
+          ($d & 0xff);
+
+  for ($i=1; $i<=32 && $num & (1 << (32 - $i)); $i++)
+    {
+    }
+  $i--;
+
+  return ($i);
+}
+
+
+sub parse_subnet
+{
+  local ($ip, $tmp, $netmask);
+
+  print_entry () if %curentry;
+    
+  $ip = next_token (0);
+  parse_error () if !defined ($ip);
+
+  $tmp = next_token (1);
+  parse_error () if !defined ($tmp);
+  parse_error () if !($tmp eq 'netmask');
+
+  $tmp = next_token (0);
+  parse_error () if !defined ($tmp);
+  $netmask = parse_netmask ($tmp);
+
+  $tmp = next_token (0);
+  parse_error () if !defined ($tmp);
+  parse_error () if !($tmp eq '{');
+
+  add_dn_to_stack ("cn=$ip");
+  $curentry{'type'} = 'subnet';
+  $curentry{'ip'} = $ip;
+  $curentry{'netmask'} = $netmask;
+}
+
+
+sub parse_shared_network
+{
+  local ($descr, $tmp);
+
+  print_entry () if %curentry;
+
+  $descr = next_token (0);
+  parse_error () if !defined ($descr);
+
+  $tmp = next_token (0);
+  parse_error () if !defined ($tmp);
+  parse_error () if !($tmp eq '{');
+
+  add_dn_to_stack ("cn=$descr");
+  $curentry{'type'} = 'shared-network';
+  $curentry{'descr'} = $descr;
+}
+
+
+sub parse_host
+{
+  local ($descr, $tmp);
+
+  print_entry () if %curentry;
+
+  $host = next_token (0);
+  parse_error () if !defined ($host);
+
+  $tmp = next_token (0);
+  parse_error () if !defined ($tmp);
+  parse_error () if !($tmp eq '{');
+
+  add_dn_to_stack ("cn=$host");
+  $curentry{'type'} = 'host';
+  $curentry{'host'} = $host;
+}
+
+
+sub parse_group
+{
+  local ($descr, $tmp);
+
+  print_entry () if %curentry;
+
+  $tmp = next_token (0);
+  parse_error () if !defined ($tmp);
+  parse_error () if !($tmp eq '{');
+
+  add_dn_to_stack ("cn=group");
+  $curentry{'type'} = 'group';
+}
+
+
+sub parse_pool
+{
+  local ($descr, $tmp);
+
+  print_entry () if %curentry;
+
+  $tmp = next_token (0);
+  parse_error () if !defined ($tmp);
+  parse_error () if !($tmp eq '{');
+
+  add_dn_to_stack ("cn=pool");
+  $curentry{'type'} = 'pool';
+}
+
+
+sub parse_class
+{
+  local ($descr, $tmp);
+
+  print_entry () if %curentry;
+
+  $class = next_token (0);
+  parse_error () if !defined ($class);
+
+  $tmp = next_token (0);
+  parse_error () if !defined ($tmp);
+  parse_error () if !($tmp eq '{');
+
+  $class =~ s/\"//g;
+  add_dn_to_stack ("cn=$class");
+  $curentry{'type'} = 'class';
+  $curentry{'class'} = $class;
+}
+
+
+sub parse_subclass
+{
+  local ($descr, $tmp);
+
+  print_entry () if %curentry;
+
+  $class = next_token (0);
+  parse_error () if !defined ($class);
+
+  $subclass = next_token (0);
+  parse_error () if !defined ($subclass);
+
+  $tmp = next_token (0);
+  parse_error () if !defined ($tmp);
+  parse_error () if !($tmp eq '{');
+
+  add_dn_to_stack ("cn=$subclass");
+  $curentry{'type'} = 'subclass';
+  $curentry{'class'} = $class;
+  $curentry{'subclass'} = $subclass;
+}
+
+
+sub parse_hwaddress
+{
+  local ($type, $hw, $tmp);
+
+  $type = next_token (0);
+  parse_error () if !defined ($type);
+
+  $hw = next_token (0);
+  parse_error () if !defined ($hw);
+  $hw =~ s/;$//;
+
+  $curentry{'hwaddress'} = "$type $hw";
+}
+
+    
+sub parse_range
+{
+  local ($tmp, $str);
+
+  $str = remaining_line ();
+
+  if (!($str eq ''))
+    {
+      $str =~ s/;$//;
+      $curentry{'range'} = $str;
+    }
+}
+
+
+sub parse_statement
+{
+  local ($token) = shift;
+  local ($str);
+
+  if ($token eq 'option')
+    {
+      $str = remaining_line ();
+      push (@{$curentry{'options'}}, $str);
+    }
+  else
+    {
+      $str = $token . " " . remaining_line ();
+      push (@{$curentry{'statements'}}, $str);
+    }
+}
+
+
+my $token;
+my $token_number = 0;
+my $line_number = 0;
+my %curentry;
+
+$current_dn = "cn=DHCP Config, $basedn";
+$curentry{'descr'} = 'DHCP Config';
+$line = '';
+
+while (($token = next_token (1)))
+  {
+    if ($token eq '}')
+      {
+        print_entry () if %curentry;
+        remove_dn_from_stack ();
+      }
+    elsif ($token eq 'subnet')
+      {
+        parse_subnet ();
+        next;
+      }
+    elsif ($token eq 'shared-network')
+      {
+        parse_shared_network ();
+        next;
+      }
+    elsif ($token eq 'class')
+      {
+        parse_class ();
+        next;
+      }
+    elsif ($token eq 'subclass')
+      {
+        parse_subclass ();
+        next;
+      }
+    elsif ($token eq 'pool')
+      {
+        parse_pool ();
+        next;
+      }
+    elsif ($token eq 'group')
+      {
+        parse_group ();
+        next;
+      }
+    elsif ($token eq 'host')
+      {
+        parse_host ();
+        next;
+      }
+    elsif ($token eq 'hardware')
+      {
+        parse_hwaddress ();
+        next;
+      }
+    elsif ($token eq 'range')
+      {
+        parse_range ();
+        next;
+      }
+    else
+      {
+        parse_statement ($token);
+        next;
+      }
+  }
+
+
--- /dev/null	2007-01-31 10:24:38.956568237 -0500
+++ dhcp-3.0.5/doc/draft-ietf-dhc-ldap-schema-01.txt	2007-01-31 20:39:38.000000000 -0500
@@ -0,0 +1,1089 @@
+
+
+
+
+
+Network Working Group                                  M. Meredith,
+Internet Draft                                         V. Nanjundaswamy,
+Document: <draft-ietf-dhc-ldap-schema-00.txt>          M. Hinckley
+Category: Proposed Standard                            Novell Inc.
+Expires: 15th December 2001                            16th June 2001
+
+
+                          LDAP Schema for DHCP
+
+Status of this Memo
+
+This document is an Internet-Draft and is in full conformance with all
+provisions of Section 10 of RFC2026 [ ].
+
+Internet-Drafts are working documents of the Internet Engineering Task
+Force (IETF), its areas, and its working groups.  Note that other groups
+may also distribute working documents as Internet-Drafts. Internet-
+Drafts are draft documents valid for a maximum of six months and may be
+updated, replaced, or obsolete by other documents at any time.  It is
+inappropriate to use Internet-Drafts as reference material or to cite
+them other than as "work in progress."  The list of current Internet-
+Drafts can be accessed at http://www.ietf.org/ietf/1id-abstracts.txt The
+list of Internet-Draft Shadow Directories can be accessed at
+http://www.ietf.org/shadow.html.
+
+1. Abstract
+
+This document defines a schema for representing DHCP configuration in an
+LDAP directory. It can be used to represent the DHCP Service
+configuration(s) for an entire enterprise network, a subset of the
+network, or even a single server. Representing DHCP configuration in an
+LDAP directory enables centralized management of DHCP services offered
+by one or more DHCP Servers within the enterprise.
+
+2. Conventions used in this document
+
+The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
+"SHOULD", "SHOULD NOT", "RECOMMENDED",  "MAY", and "OPTIONAL" in this
+document are to be interpreted as described in RFC-2119 [ ].
+
+In places where different sets of terminology are commonly used to
+represent similar DHCP concepts, this schema uses the terminology of the
+Internet Software Consortium's DHCP server reference implementation.
+For more information see www.isc.org.
+
+3. Design Considerations
+
+The DHCP LDAP schema is designed to be a simple multi-server schema. The
+
+
+
+M. Meredith et al.        Expires December 2001                 [Page 1]
+
+
+
+
+
+INTERNET-DRAFT            LDAP Schema for DHCP              16 June 2001
+
+
+intent of this schema is to provide a basic framework for representing
+the most common elements used in the configuration of DHCP Server.  This
+should allow other network services to obtain and use basic DHCP
+configuration information in a server-independent but knowledgeable way.
+
+It is expected that some implementations may need to extend the schema
+objects, in order to implement all of their features or needs. It is
+recommended that you use the schema defined in this draft to represent
+DHCP configuration information in an LDAP directory.  Conforming to a
+standard schema improves interoperability between DHCP implementations
+from different vendors.
+
+Some implementations may choose not to support all of the objects
+defined here.
+
+Two decisions are explicitly left up to each implementation:
+
+First, implementations may choose not to store the lease information in
+the directory, so those objects would not be used.
+
+Second, implementations may choose not to implement the auditing
+information.
+
+It is up to the implementation to determine if the data in the directory
+is considered "authoritative", or if it is simply a copy of data from an
+authoritative source. Validity of the information if used as a copy is
+to be ensured by the implementation.
+
+Primarily two types of applications will use the information in this
+schema: 1. DHCP servers (for loading their configuration) 2. Management
+Interfaces (for defining/editing configurations).
+
+The schema should be efficient for the needs of both types of
+applications.  The schema is designed to allow objects managed by DHCP
+(such as computers, subnets, etc) to be present anywhere in a directory
+hierarchy (to allow those objects to be placed in the directory for
+managing administrative control and access to the objects).
+
+The schema uses a few naming conventions - all object classes and
+attributes are prefixed with "dhcp" to decrease the chance that object
+classes and attributes will have the same name.  The schema also uses
+standard naming attributes ("cn", "ou", etc) for all objects.
+
+4. Common DHCP Configuration Attributes
+
+Although DHCP manages several different types of objects, the
+configuration of those objects is often similar.  Consequently, most of
+these objects have a common set of attributes, which are defined below.
+
+
+
+M. Meredith et al.        Expires December 2001                 [Page 2]
+
+
+
+
+
+INTERNET-DRAFT            LDAP Schema for DHCP              16 June 2001
+
+
+4.1. Attributes Definitions
+
+The schema definitions listed below are for readability.  The LDIF
+layout for this schema will follow in section 8.
+
+Name: dhcpPrimaryDN Description: The Distinguished Name of the
+dhcpServer object, which is the primary server for the configuration.
+Syntax: DN Flags: SINGLE-VALUE
+
+Named: dhcpSecondaryDN Description: The Distinguished Name(s) of the
+dhcpServer object(s), which are secondary servers for the configuration.
+Syntax: DN
+
+Name: dhcpStatements Description: Flexible storage for representing any
+specific data depending on the object to which it is attached. Examples
+include conditional statements, Server parameters, etc.  This also
+serves as a 'catch-all' attribute that allows the standard to evolve
+without needing to update the schema.  Syntax: IA5String
+
+Name: dhcpRange Description: The starting and ending IP Addresses in the
+range (inclusive), separated by a hyphen; if the range only contains one
+address, then just the address can be specified with no hyphen.  Each
+range is defined as a separate value.  Syntax: IA5String
+
+Name: dhcpPermitList Description: This attribute contains the permit
+lists associated with a pool. Each permit list is defined as a separate
+value.  Syntax: IA5String
+
+Name: dhcpNetMask Description: The subnet mask length for the subnet.
+The mask can be easily computed from this length.  Syntax: Integer
+Flags: SINGLE-VALUE
+
+Name: dhcpOption Description: Encoded option values to be sent to
+clients.  Each value represents a single option and contains (OptionTag,
+Length, OptionData) encoded in the format used by DHCP.  For more
+information see [DHCPOPT].  Syntax: OctetString
+
+Name: dhcpClassData Description: Encoded text string or list of bytes
+expressed in hexadecimal, separated by colons. Clients match subclasses
+based on matching the class data with the results of a 'match' or 'spawn
+with' statement in the class name declarations.  Syntax: IA5String
+Flags: SINGLE-VALUE
+
+Name: dhcpSubclassesDN Description: List of subclasses, these are the
+actual DN of each subclass object.  Syntax: DN
+
+Name: dhcpClassesDN Description: List of classes, these are the actual
+DN of each class object.  Syntax: DN
+
+
+
+M. Meredith et al.        Expires December 2001                 [Page 3]
+
+
+
+
+
+INTERNET-DRAFT            LDAP Schema for DHCP              16 June 2001
+
+
+Name: dhcpSubnetDN Description: List of subnets, these are the actual DN
+of each subnet object.  Syntax: DN
+
+Name: dhcpPoolDN Description: List of pools, these are the actual DN of
+each Pool object.  Syntax: DN
+
+Name: dhcpOptionsDN Description: List of options, these are the actual
+DN of each Options object.  Syntax: DN
+
+Name: dhcpHostDN Description: List of hosts, these are the actual DN of
+each host object.  Syntax: DN
+
+Name: dhcpSharedNetworkDN Description: List of shared networks, these
+are the actual DN of each shared network object.  Syntax: DN
+
+Name: dhcpGroupDN Description: List of groups, these are the actual DN
+of each Group object.  Syntax: DN
+
+Name: dhcpLeaseDN Description: Single Lease DN. A dhcpHost configuration
+uses this attribute to identify a static IP address assignment.  Syntax:
+DN Flags: SINGLE-VALUE
+
+Name: dhcpLeasesDN Description: List of leases, these are the actual DN
+of each lease object.  Syntax: DN
+
+Name: dhcpServiceDN Description: The DN of dhcpService object(s)which
+contain the configuration information. Each dhcpServer object has this
+attribute identifying the DHCP configuration(s) that the server is
+associated with.  Syntax: DN
+
+Name: dhcpHWAddress Description: The hardware address of the client
+associated with a lease Syntax: OctetString Flags: SINGLE-VALUE
+
+Name: dhcpVersion Description: This is the version identified for the
+object that this attribute is part of. In case of the dhcpServer object,
+this represents the DHCP software version.  Syntax: IA5String Flags:
+SINGLE-VALUE
+
+Name: dhcpImplementation Description: DHCP Server implementation
+description e.g. DHCP Vendor information.  Syntax: IA5String Flags:
+SINGLE-VALUE
+
+Name: dhcpHashBucketAssignment Description: HashBucketAssignment bit map
+for the DHCP Server, as defined in DHC Load Balancing Algorithm [RFC
+3074].  Syntax: Octet String Flags: SINGLE-VALUE
+
+Name: dhcpDelayedServiceParameter Description: Delay in seconds
+corresponding to Delayed Service Parameter configuration, as defined in
+
+
+
+M. Meredith et al.        Expires December 2001                 [Page 4]
+
+
+
+
+
+INTERNET-DRAFT            LDAP Schema for DHCP              16 June 2001
+
+
+DHC Load Balancing Algorithm [RFC 3074].  Syntax: Integer Flags: SINGLE-
+VALUE
+
+Name: dhcpMaxClientLeadTime Description: Maximum Client Lead Time
+configuration in seconds, as defined in DHCP Failover Protocol [FAILOVR]
+Syntax: Integer Flags: SINGLE-VALUE
+
+Name: dhcpFailOverEndpointState Description: Server (Failover Endpoint)
+state, as defined in DHCP Failover Protocol [FAILOVR] Syntax: IA5String
+Flags: SINGLE-VALUE
+
+5. Configurations and Services
+
+The schema definitions below are for readability the LDIF layout for
+this schema will follow in section 8.
+
+The DHC working group is currently considering several proposals for
+fail-over and redundancy of DHCP servers.  These may require sharing of
+configuration information between servers.  This schema provides a
+generalized mechanism for supporting any of these proposals, by
+separating the definition of a server from the definition of
+configuration service provided by the server.
+
+Separating the DHCP Server (dhcpServer) and the DHCP Configuration
+(dhcpService) representations allows a configuration service to be
+provided by one or more servers. Similarly, a server may provide one or
+more configurations. The schema allows a server to be configured as
+either a primary or secondary provider of a DHCP configuration.
+
+Configurations are also defined so that one configuration can include
+some of the objects that are defined in another configuration.  This
+allows for sharing and/or a hierarchy of related configuration items.
+
+Name: dhcpService Description:  Service object that represents the
+actual DHCP Service configuration. This will be a container with the
+following attributes.  Must: cn, dhcpPrimaryDN May: dhcpSecondaryDN,
+dhcpSharedNetworkDN, dhcpSubnetDN, dhcpGroupDN, dhcpHostDN,
+dhcpClassesDN, dhcpOptionsDN, dhcpStatements
+
+The following objects could exist inside the dhcpService container:
+dhcpSharedNetwork, dhcpSubnet, dhcpGroup, dhcpHost, dhcpClass,
+dhcpOptions, dhcpLog
+
+Name: dhcpServer Description:  Server object that the DHCP server will
+login as.  The configuration information is in the dhcpService container
+that the dhcpServiceDN points to.  Must: cn, dhcpServiceDN May:
+dhcpVersion, dhcpImplementation, dhcpHashBucketAssignment,
+dhcpDelayedServiceParameter, dhcpMaxClientLeadTime, 
+
+
+
+M. Meredith et al.        Expires December 2001                 [Page 5]
+
+
+
+
+
+INTERNET-DRAFT            LDAP Schema for DHCP              16 June 2001
+dhcpFailOverEndpointState, dhcpStatements
+
+5.1. DHCP Declaration related classes:
+
+Name: dhcpSharedNetwork Description: Shared Network class will list what
+pools and subnets are in this network.
+
+This will be a container with the following attributes.  Must: cn May:
+dhcpSubnetDN, dhcpPoolDN, dhcpOptionsDN, dhcpStatements
+
+The following objects can exist within a dhcpSharedNetwork container:
+dhcpSubnet, dhcpPool, dhcpOptions, dhcpLog
+
+Name: dhcpSubnet Description: Subnet object will include configuration
+information associated with a subnet, including a range and a net mask.
+
+This will be a container with the following attributes.  Must: cn
+(Subnet address), dhcpNetMask May: dhcpRange, dhcpPoolDN, dhcpGroupDN,
+dhcpHostDN, dhcpClassesDN, dhcpLeasesDN, dhcpOptionsDN, dhcpStatements
+
+The following objects can exist within a dhcpSubnet container: dhcpPool,
+dhcpGroup, dhcpHost, dhcpClass, dhcpOptions, dhcpLease, dhcpLog
+
+Name: dhcpGroup Description: Group object will have configuration
+information associated with a group.
+
+This will be a container with the following attributes.  Must: cn May:
+dhcpHostDN, dhcpOptionsDN, dhcpStatements
+
+The following objects can exist within a dhcpGroup container: dhcpHost,
+dhcpOptions
+
+Name: dhcpHost Description: The host object includes DHCP host
+declarations to assign a static IP address or declare the client as
+known or specify statements for a specific client.  Must: cn May:
+dhcpLeaseDN, dhcpHWAddress, dhcpOptionsDN, dhcpStatements
+
+The following objects can exist within a dhcpHost container: dhcpLease,
+dhcpOptions
+
+Name: dhcpOptions Description: The options class is for option space
+declarations, it contains a list of options.  Must: cn, dhcpOption
+
+Name: dhcpClass Description: This is a class to group clients together
+based on matching rules.
+
+This will be a container with the following attributes.  Must: cn May:
+dhcpSubClassesDN, dhcpOptionsDN, dhcpStatements
+
+The following object can exist within a dhcpClass container:
+dhcpSubclass, dhcpOptions
+
+
+
+M. Meredith et al.        Expires December 2001                 [Page 6]
+
+
+
+
+
+INTERNET-DRAFT            LDAP Schema for DHCP              16 June 2001
+
+
+Name: dhcpSubClass Description: This includes configuration information
+for a subclass associated with a class. The dhcpSubClass object will
+always be contained within the corresponding class container object.
+Must: cn May:  dhcpClassData, dhcpOptionsDN, dhcpStatements
+
+Name: dhcpPool Description: This contains configuration for a pool that
+will have the range of addresses, permit lists and point to classes and
+leases that are members of this pool.
+
+This will be a container that could be contained by dhcpSubnet or a
+dhcpSharedNetwork.  Must: cn, dhcpRange May: dhcpClassesDN,
+dhcpPermitList, dhcpLeasesDN, dhcpOptionsDN, dhcpStatements
+
+The following objects can exist within a dhcpPool container: dhcpClass,
+dhcpOptions, dhcpLease, dhcpLog
+
+6. Tracking Address Assignments
+
+The behavior of a DHCP server is influenced by two factors - it's
+configuration and the current state of the addresses that have been
+assigned to clients. This schema defines a set of objects for
+representing the DHCP configuration associated with a server. The
+following object classes provide the ability to record how addresses are
+used including maintaining history (audit log) on individual leases.
+Recording lease information in a directory could result in a significant
+performance impact and is therefore optional. Implementations supporting
+logging of leases need to consider the performance impact.
+
+6.1. dhcpLeases Attribute Definitions
+
+The schema definitions below are for readability the LDIF layout for
+this schema will follow in section 8.
+
+Name: dhcpAddressState Description: This stores information about the
+current binding-status of an address.  For dynamic addresses managed by
+DHCP, the values should be restricted to the states defined in the DHCP
+Failover Protocol draft [FAILOVR]: 'FREE', 'ACTIVE', 'EXPIRED',
+'RELEASED', 'RESET', 'ABANDONED', 'BACKUP'.  For more information on
+these states see [FAILOVR].  For other addresses, it SHOULD be one of
+the following: 'UNKNOWN', 'RESERVED' (an address that is managed by DHCP
+that is reserved for a specific client), 'RESERVED-ACTIVE' (same as
+reserved, but address is currently in use),  'ASSIGNED' (assigned
+manually or by some other mechanism), 'UNASSIGNED', 'NOTASSIGNABLE'.
+Syntax: IA5String Flags: SINGLE-VALUE
+
+Name: dhcpExpirationTime Description: This is the time the current lease
+for an address expires.  Syntax: DateTime Flags: SINGLE-VALUE
+
+
+
+
+M. Meredith et al.        Expires December 2001                 [Page 7]
+
+
+
+
+
+INTERNET-DRAFT            LDAP Schema for DHCP              16 June 2001
+
+
+Name: dhcpStartTimeOfState Description: This is the time of the last
+state change for a leased address.  Syntax: DateTime Flags: SINGLE-VALUE
+
+Name: dhcpLastTransactionTime Description: This is the last time a valid
+DHCP packet was received from the client.  Syntax: DateTime Flags:
+SINGLE-VALUE
+
+Name: dhcpBootpFlag Description: This indicates whether the address was
+assigned via BOOTP Syntax: Boolean Flags: SINGLE-VALUE
+
+Name: dhcpDomainName Description: This is the name of the domain sent to
+the client by the server.  It is essentially the same as the value for
+DHCP option 15 sent to the client, and represents only the domain - not
+the full FQDN.  To obtain the full FQDN assigned to the client you must
+prepend the "dhcpAssignedHostName" to this value with a ".".  Syntax:
+IA5String Flags: SINGLE-VALUE
+
+Name: dhcpDnsStatus Description: This indicates the status of updating
+DNS resource records on behalf of the client by the DHCP server for this
+address.  The value is a 16-bit bitmask that has the same values as
+specified by the Failover-DDNS option (see [FAILOVR]).  Syntax: Integer
+Flags: SINGLE-VALUE
+
+Name: dhcpRequestedHostName Description: This is the hostname that was
+requested by the client.  Syntax: IA5String Flags: SINGLE-VALUE
+
+Name: dhcpAssignedHostName Description: This is the actual hostname that
+was assigned to a client. It may not be the name that was requested by
+the client.  The fully qualified domain name can be determined by
+appending the value of "dhcpDomainName" (with a dot separator) to this
+name.  Syntax: IA5String Flags: SINGLE-VALUE
+
+Name: dhcpReservedForClient Description: This is the distinguished name
+of the "dhcpHost" that an address is reserved for.  This may not be the
+same as the "dhcpAssignedToClient" attribute if the address is being
+reassigned but the current lease has not yet expired.  Syntax: DN Flags:
+SINGLE-VALUE
+
+Name: dhcpAssignedToClient Description: This is the distinguished name
+of a "dhcpHost" that an address is currently assigned to.  This
+attribute is only present in the class when the address is leased.
+Syntax: DN Flags: SINGLE-VALUE
+
+Name: dhcpRelayAgentInfo Description: If the client request was received
+via a relay agent, this contains information about the relay agent that
+was available from the DHCP request.  This is a hex-encoded option
+value.  Syntax: OctetString Flags: SINGLE-VALUE
+
+Name: dhcpErrorLog Description: Generic error log attribute that allows
+logging error conditions within a dhcpService or a dhcpSubnet, like no IP 
+addresses available for lease. Syntax: IA5String 
+
+M. Meredith et al.        Expires December 2001                 [Page 8]
+
+
+
+
+
+INTERNET-DRAFT            LDAP Schema for DHCP              16 June 2001
+
+
+6.2.  dhcpLeases Object Class
+
+This class represents an IP address.  It may or may not be leaseable,
+and the object may exist even though a lease is not currently active for
+the associated IP address.
+
+It is recommended that all Lease objects for a single DHCP Service be
+centrally located within a single container. This ensures that the lease
+objects and the corresponding logs do not have to be relocated, when
+address ranges allocated to individual DHCP subnets and/or pools change.
+
+The schema definitions below are for readability the LDIF layout for
+this schema will follow in section 8.
+
+Name: dhcpLeases Description: This is the object that holds state
+information about an IP address. The cn (which is the IP address), and
+the current address-state are mandatory attributes. If the address is
+assigned then, some of the optional attributes will have valid data.
+Must: cn, dhcpAddressState May: dhcpExpirationTime,
+dhcpStartTimeOfState, dhcpLastTransactionTime, dhcpBootpFlag,
+dhcpDomainName, dhcpDnsStatus, dhcpRequestedHostName,
+dhcpAssignedHostName, dhcpReservedForClient, dhcpAssignedToClient,
+dhcpRelayAgentInfo, dhcpHWAddress
+
+6.3 Audit Log Information
+
+A dhcpLog object is created whenever a lease is assigned or released.
+This object is intended to be created under the corresponding dhcpLeases
+container, or dhcpPool, dhcpSubnet, dhcpSharedNetwork or dhcpService
+containers.
+
+The log information under the dhcpLeases container would be for
+addresses matching that lease information. The log information in the
+other containers could be used for errors, i.e. when a pool or subnet is
+out our addresses or if a server is not able to assign any more
+addresses for a particular dhcpService.
+
+Name: dhcpLog Description: This is the object that holds past
+information about an IP address. The cn is the time/date stamp when the
+address was assigned or released, the address state at the time, if the
+address was assigned or released.  Must: cn May: dhcpAddressState,
+dhcpExpirationTime, dhcpStartTimeOfState, dhcpLastTransactionTime,
+dhcpBootpFlag, dhcpDomainName, dhcpDnsStatus, dhcpRequestedHostName,
+dhcpAssignedHostName, dhcpReservedForClient, dhcpAssignedToClient,
+dhcpRelayAgentInfo, dhcpHWAddress, dhcpErrorLog
+
+
+
+
+
+
+M. Meredith et al.        Expires December 2001                 [Page 9]
+
+
+
+
+
+INTERNET-DRAFT            LDAP Schema for DHCP              16 June 2001
+
+
+7. Determining settings
+
+The dhcpStatements attribute is the key to DHC enhancements that may
+come along, and the different key words that a particular server
+implementation may use. This attribute can be used to hold conditional
+DHCP Statements and DHCP server parameters. Having a generic settings
+attribute that is just a string, allows this schema to be extensible and
+easy to configure.
+
+All of the attributes that end with DN are references to the class that
+precedes the DN e.g. the dhcpPrimaryDN and dhcpSecondaryDN attributes
+hold the Distinguished Names of the dhcpServer objects that are
+associated with the dhcpService object.
+
+8. LDIF format for attributes and classes.
+
+# Attributes
+
+( 2.16.840.1.113719.1.203.4.1 NAME 'dhcpPrimaryDN' DESC
+'The DN of the dhcpServer which is the primary server for the
+configuration.' SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 SINGLE-VALUE )
+
+( 2.16.840.1.113719.1.203.4.2 NAME 'dhcpSecondaryDN' DESC 'The DN of
+dhcpServer(s) which provide backup service for the configuration.'
+SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )
+
+( 2.16.840.1.113719.1.203.4.3 NAME 'dhcpStatements' DESC 'Flexible
+storage for specific data depending on what object this exists in. Like
+conditional statements, server parameters, etc. This allows the standard
+to evolve without needing to adjust the schema.' SYNTAX
+1.3.6.1.4.1.1466.115.121.1.26 )
+
+( 2.16.840.1.113719.1.203.4.4 NAME 'dhcpRange' DESC 'The starting &
+ending IP Addresses in the range (inclusive), separated by a hyphen; if
+the range only contains one address, then just the address can be
+specified with no hyphen.  Each range is defined as a separate value.'
+SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
+
+( 2.16.840.1.113719.1.203.4.5 NAME 'dhcpPermitList' DESC 'This attribute
+contains the permit lists associated with a pool. Each permit list is
+defined as a separate value.' SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
+
+( 2.16.840.1.113719.1.203.4.6 NAME 'dhcpNetMask' DESC 'The subnet mask
+length for the subnet.  The mask can be easily computed from this
+length.' SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
+
+( 2.16.840.1.113719.1.203.4.7 NAME 'dhcpOption' DESC 'Encoded option
+values to be sent to clients.  Each value represents a single option and
+contains (OptionTag, Length, OptionValue) encoded in the format used by
+DHCP.' SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )
+
+M. Meredith et al.        Expires December 2001                [Page 10]
+
+
+
+
+
+INTERNET-DRAFT            LDAP Schema for DHCP              16 June 2001
+
+
+( 2.16.840.1.113719.1.203.4.8 NAME 'dhcpClassData' DESC 'Encoded text
+string or list of bytes expressed in hexadecimal, separated by colons.
+Clients match subclasses based on matching the class data with the
+results of match or spawn with statements in the class name
+declarations.' SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE )
+
+( 2.16.840.1.113719.1.203.4.9 NAME 'dhcpOptionsDN' DESC 'The
+distinguished name(s) of the dhcpOption objects containing the
+configuration options provided by the server.' SYNTAX
+1.3.6.1.4.1.1466.115.121.1.12 )
+
+( 2.16.840.1.113719.1.203.4.10 NAME 'dhcpHostDN' DESC 'the distinguished
+name(s) of the dhcpHost objects.' SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )
+
+( 2.16.840.1.113719.1.203.4.11 NAME 'dhcpPoolDN' DESC 'The distinguished
+name(s) of pools.' SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )
+
+( 2.16.840.1.113719.1.203.4.12 NAME 'dhcpGroupDN' DESC 'The
+distinguished name(s)   of the groups.' SYNTAX
+1.3.6.1.4.1.1466.115.121.1.12 )
+
+( 2.16.840.1.113719.1.203.4.13 NAME 'dhcpSubnetDN' DESC 'The
+distinguished name(s) of the subnets.' SYNTAX
+1.3.6.1.4.1.1466.115.121.1.12 )
+
+( 2.16.840.1.113719.1.203.4.14 NAME 'dhcpLeaseDN' DESC 'The
+distinguished name of a client address.' SYNTAX
+1.3.6.1.4.1.1466.115.121.1.12 SINGLE-VALUE)
+
+( 2.16.840.1.113719.1.203.4.15 NAME 'dhcpLeasesDN' DESC 'The
+distinguished name(s) client addresses.' SYNTAX
+1.3.6.1.4.1.1466.115.121.1.12 )
+
+( 2.16.840.1.113719.1.203.4.16 NAME 'dhcpClassesDN' DESC 'The
+distinguished name(s) of a class(es) in a subclass.' SYNTAX
+1.3.6.1.4.1.1466.115.121.1.12 )
+
+( 2.16.840.1.113719.1.203.4.17 NAME 'dhcpSubclassesDN' DESC 'The
+distinguished name(s) of subclass(es).' SYNTAX
+1.3.6.1.4.1.1466.115.121.1.12 )
+
+( 2.16.840.1.113719.1.203.4.18 NAME 'dhcpSharedNetworkDN' DESC 'The
+distinguished name(s) of sharedNetworks.' SYNTAX
+1.3.6.1.4.1.1466.115.121.1.12 )
+
+( 2.16.840.1.113719.1.203.4.19 NAME 'dhcpServiceDN' DESC 'The DN of
+dhcpService object(s)which contain the configuration information. Each
+dhcpServer object has this attribute identifying the DHCP
+
+
+
+M. Meredith et al.        Expires December 2001                [Page 11]
+
+
+
+
+
+INTERNET-DRAFT            LDAP Schema for DHCP              16 June 2001
+
+
+configuration(s) that the server is associated with.' SYNTAX
+1.3.6.1.4.1.1466.115.121.1.12 )
+
+( 2.16.840.1.113719.1.203.4.20 NAME 'dhcpVersion' DESC 'The version
+attribute of this object.' SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-
+VALUE )
+
+( 2.16.840.1.113719.1.203.4.21 NAME 'dhcpImplementation' DESC
+'Description of the DHCP Server implementation e.g. DHCP Server's
+vendor.' SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE )
+
+( 2.16.840.1.113719.1.203.4.22 NAME 'dhcpAddressState' DESC 'This stores
+information about the current binding-status of an address.  For dynamic
+addresses managed by DHCP, the values should be restricted to the
+following: "FREE", "ACTIVE", "EXPIRED", "RELEASED", "RESET",
+"ABANDONED", "BACKUP".  For other addresses, it SHOULD be one of the
+following: "UNKNOWN", "RESERVED" (an address that is managed by DHCP
+that is reserved for a specific client), "RESERVED-ACTIVE" (same as
+reserved, but address is currently in use), "ASSIGNED" (assigned
+manually or by some other mechanism), "UNASSIGNED", "NOTASSIGNABLE".'
+SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE )
+
+( 2.16.840.1.113719.1.203.4.23 NAME 'dhcpExpirationTime' DESC 'This is
+the time the current lease for an address expires.' SYNTAX
+1.3.6.1.4.1.1466.115.121.1.24 SINGLE-VALUE )
+
+( 2.16.840.1.113719.1.203.4.24 NAME 'dhcpStartTimeOfState' DESC 'This is
+the time of the last state change for a leased address.' SYNTAX
+1.3.6.1.4.1.1466.115.121.1.24 SINGLE-VALUE )
+
+( 2.16.840.1.113719.1.203.4.25 NAME 'dhcpLastTransactionTime' DESC 'This
+is the last time a valid DHCP packet was received from the client.'
+SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 SINGLE-VALUE )
+
+( 2.16.840.1.113719.1.203.4.26 NAME 'dhcpBootpFlag' DESC 'This indicates
+whether the address was assigned via BOOTP.' SYNTAX
+1.3.6.1.4.1.1466.115.121.1.7 SINGLE-VALUE )
+
+( 2.16.840.1.113719.1.203.4.27 NAME 'dhcpDomainName' DESC 'This is the
+name of the domain sent to the client by the server.  It is essentially
+the same as the value for DHCP option 15 sent to the client, and
+represents only the domain - not the full FQDN.  To obtain the full FQDN
+assigned to the client you must prepend the "dhcpAssignedHostName" to
+this value with a ".".' SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-
+VALUE )
+
+( 2.16.840.1.113719.1.203.4.28 NAME 'dhcpDnsStatus' DESC 'This indicates
+the status of updating DNS resource records on behalf of the client by
+
+
+
+M. Meredith et al.        Expires December 2001                [Page 12]
+
+
+
+
+
+INTERNET-DRAFT            LDAP Schema for DHCP              16 June 2001
+
+
+the DHCP server for this address.  The value is a 16-bit bitmask.'
+SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
+
+( 2.16.840.1.113719.1.203.4.29 NAME 'dhcpRequestedHostName' DESC 'This
+is the hostname that was requested by the client.' SYNTAX
+1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE )
+
+( 2.16.840.1.113719.1.203.4.30 NAME 'dhcpAssignedHostName' DESC 'This is
+the actual hostname that was assigned to a client. It may not be the
+name that was requested by the client.  The fully qualified domain name
+can be determined by appending the value of "dhcpDomainName" (with a dot
+separator) to this name.' SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-
+VALUE )
+
+( 2.16.840.1.113719.1.203.4.31 NAME 'dhcpReservedForClient' DESC 'The
+distinguished name of a "dhcpClient" that an address is reserved for.
+This may not be the same as the "dhcpAssignedToClient" attribute if the
+address is being reassigned but the current lease has not yet expired.'
+SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 SINGLE-VALUE )
+
+( 2.16.840.1.113719.1.203.4.32 NAME 'dhcpAssignedToClient' DESC 'This is
+the distinguished name of a "dhcpClient" that an address is currently
+assigned to.  This attribute is only present in the class when the
+address is leased.' SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 SINGLE-VALUE )
+
+( 2.16.840.1.113719.1.203.4.33 NAME 'dhcpRelayAgentInfo' DESC 'If the
+client request was received via a relay agent, this contains information
+about the relay agent that was available from the DHCP request.  This is
+a hex-encoded option value.' SYNTAX 1.3.6.1.4.1.1466.115.121.1.40
+SINGLE-VALUE )
+
+( 2.16.840.1.113719.1.203.4.34 NAME 'dhcpHWAddress' DESC 'The clients
+hardware address that requested this IP address.' SYNTAX
+1.3.6.1.4.1.1466.115.121.1.40 SINGLE-VALUE )
+
+( 2.16.840.1.113719.1.203.4.35 NAME 'dhcpHashBucketAssignment' DESC
+'HashBucketAssignment bit map for the DHCP Server, as defined in DHC
+Load Balancing Algorithm [RFC 3074].' SYNTAX
+1.3.6.1.4.1.1466.115.121.1.40 SINGLE-VALUE )
+
+( 2.16.840.1.113719.1.203.4.36 NAME 'dhcpDelayedServiceParameter' DESC
+'Delay in seconds corresponding to Delayed Service Parameter
+configuration, as defined in  DHC Load Balancing Algorithm [RFC 3074]. '
+SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
+
+( 2.16.840.1.113719.1.203.4.37 NAME 'dhcpMaxClientLeadTime' DESC
+'Maximum Client Lead Time configuration in seconds, as defined in DHCP
+Failover Protocol [FAILOVR]' SYNTAX 1.3.6.1.4.1.1466.115.121.1.27
+
+
+
+M. Meredith et al.        Expires December 2001                [Page 13]
+
+
+
+
+
+INTERNET-DRAFT            LDAP Schema for DHCP              16 June 2001
+
+
+SINGLE-VALUE )
+
+( 2.16.840.1.113719.1.203.4.38 NAME 'dhcpFailOverEndpointState' DESC
+'Server (Failover Endpoint) state, as defined in DHCP Failover Protocol
+[FAILOVR]' SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE )
+
+( 2.16.840.1.113719.1.203.4.39 NAME 'dhcpErrorLog' DESC
+Generic error log attribute that allows logging error conditions within a 
+dhcpService or a dhcpSubnet, like no IP addresses available for lease. 
+SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE )
+
+#Classes
+
+( 2.16.840.1.113719.1.203.6.1 NAME 'dhcpService' DESC ' Service object
+that represents the actual DHCP Service configuration. This is a
+container object.' SUP top MUST (cn $ dhcpPrimaryDN) MAY
+(dhcpSecondaryDN $ dhcpSharedNetworkDN $ dhcpSubnetDN $ dhcpGroupDN $
+dhcpHostDN $  dhcpClassesDN $ dhcpOptionsDN $ dhcpStatements ) )
+
+( 2.16.840.1.113719.1.203.6.2 NAME 'dhcpSharedNetwork' DESC 'This stores
+configuration information for a shared network.' SUP top MUST  cn MAY
+(dhcpSubnetDN $ dhcpPoolDN $ dhcpOptionsDN $ dhcpStatements) X-
+NDS_CONTAINMENT ('dhcpService' ) )
+
+( 2.16.840.1.113719.1.203.6.3 NAME 'dhcpSubnet' DESC 'This class defines
+a subnet. This is a container object.' SUP top MUST ( cn $ dhcpNetMask )
+MAY (dhcpRange $ dhcpPoolDN $ dhcpGroupDN $ dhcpHostDN $ dhcpClassesDN $
+dhcpLeasesDN $ dhcpOptionsDN $ dhcpStatements) X-NDS_CONTAINMENT
+('dhcpService' 'dhcpSharedNetwork') )
+
+( 2.16.840.1.113719.1.203.6.4 NAME 'dhcpPool' DESC 'This stores
+configuration information about a pool.' SUP top MUST ( cn $ dhcpRange )
+MAY (dhcpClassesDN $ dhcpPermitList $ dhcpLeasesDN $ dhcpOptionsDN $
+dhcpStatements) X-NDS_CONTAINMENT ('dhcpSubnet' 'dhcpSharedNetwork') )
+
+( 2.16.840.1.113719.1.203.6.5 NAME 'dhcpGroup' DESC 'Group object that
+lists host DNs and parameters. This is a container object.' SUP top MUST
+cn MAY ( dhcpHostDN $ dhcpOptionsDN $ dhcpStatements ) X-NDS_CONTAINMENT
+('dhcpSubnet' 'dhcpService' ) )
+
+( 2.16.840.1.113719.1.203.6.6 NAME 'dhcpHost' DESC 'This represents
+information about a particular client' SUP top MUST cn MAY  (dhcpLeaseDN
+$ dhcpHWAddress $ dhcpOptionsDN $ dhcpStatements) X-NDS_CONTAINMENT
+('dhcpService' 'dhcpSubnet' 'dhcpGroup') )
+
+( 2.16.840.1.113719.1.203.6.7 NAME 'dhcpClass' DESC 'Represents
+information about a collection of related clients.' SUP top MUST cn MAY
+(dhcpSubClassesDN $ dhcpOptionsDN $ dhcpStatements) X-NDS_CONTAINMENT
+('dhcpService' 'dhcpSubnet' ) )
+
+( 2.16.840.1.113719.1.203.6.8 NAME 'dhcpSubClass' DESC 'Represents
+information about a collection of related classes.' SUP top MUST cn MAY
+(dhcpClassData $ dhcpOptionsDN $ dhcpStatements) X-NDS_CONTAINMENT
+
+
+
+M. Meredith et al.        Expires December 2001                [Page 14]
+
+
+
+
+
+INTERNET-DRAFT            LDAP Schema for DHCP              16 June 2001
+
+
+'dhcpClass' )
+
+( 2.16.840.1.113719.1.203.6.9 NAME 'dhcpOptions' DESC 'Represents
+information about a collection of options defined.' SUP top MUST cn MAY
+( dhcpOption ) X-NDS_CONTAINMENT  ('dhcpService' 'dhcpSharedNetwork'
+'dhcpSubnet' 'dhcpPool' 'dhcpGroup' 'dhcpHost' 'dhcpClass' )
+
+( 2.16.840.1.113719.1.203.6.10 NAME 'dhcpLeases' DESC 'This class
+represents an IP Address, which may or may not have been leased.' SUP
+top MUST ( cn $ dhcpAddressState ) MAY ( dhcpExpirationTime $
+dhcpStartTimeOfState $ dhcpLastTransactionTime $ dhcpBootpFlag $
+dhcpDomainName $ dhcpDnsStatus $ dhcpRequestedHostName $
+dhcpAssignedHostName $ dhcpReservedForClient $ dhcpAssignedToClient $
+dhcpRelayAgentInfo $ dhcpHWAddress ) X-NDS_CONTAINMENT ( 'dhcpService'
+'dhcpSubnet' 'dhcpPool') )
+
+( 2.16.840.1.113719.1.203.6.11 NAME 'dhcpLog' DESC 'This is the object
+that holds past information about the IP address. The cn is the
+time/date stamp when the address was assigned or released, the address
+state at the time, if the address was assigned or released.' SUP top
+MUST ( cn ) MAY ( dhcpAddressState $ dhcpExpirationTime $
+dhcpStartTimeOfState $ dhcpLastTransactionTime $ dhcpBootpFlag $
+dhcpDomainName $ dhcpDnsStatus $ dhcpRequestedHostName $
+dhcpAssignedHostName $ dhcpReservedForClient $ dhcpAssignedToClient $
+dhcpRelayAgentInfo $ dhcpHWAddress $ dhcpErrorLog) X-NDS_CONTAINMENT 
+('dhcpLeases' 'dhcpPool' 'dhcpSubnet' 'dhcpSharedNetwork' 'dhcpService' ) )
+
+( 2.16.840.1.113719.1.203.6.12 NAME 'dhcpServer' DESC 'DHCP Server
+Object' SUP top MUST (cn, dhcpServiceDN) MAY (dhcpVersion $
+dhcpImplementation $ dhcpHashBucketAssignment $
+dhcpDelayedServiceParameter $ dhcpMaxClientLeadTime $
+dhcpFailOverEndpointState $ dhcpStatements) X-NDS_CONTAINMENT ('O' 'OU' 
+'dc') )
+
+9. Security Considerations
+
+Since the DHCP Configuration information is stored in a directory, the
+security of the information is limited to the security offered by the
+directory including the security of the objects within that directory.
+
+10.  Intellectual Property Rights Notices
+
+The IETF takes no position regarding the validity or scope of any
+intellectual property or other rights that might be claimed to pertain
+to the implementation or use of the technology described in this
+document or the extent to which any license under such rights might or
+might not be available; neither does it represent that it has made any
+effort to identify any such rights.  Information on the IETF's
+procedures with respect to rights in standards-track and standards-
+
+
+
+M. Meredith et al.        Expires December 2001                [Page 15]
+
+
+
+
+
+INTERNET-DRAFT            LDAP Schema for DHCP              16 June 2001
+
+
+related documentation can be found in BCP-11.  Copies of claims of
+rights made available for publication and any assurances of licenses to
+be made available, or the result of an attempt made to obtain a general
+license or permission for the use of such proprietary rights by
+implementors or users of this specification can be obtained from the
+IETF Secretariat.
+
+The IETF invites any interested party to bring to its attention any
+copyrights, patents or patent applications, or other proprietary rights
+which may cover technology that may be required to practice this
+standard.  Please address the information to the IETF Executive
+Director.
+
+11.  Full Copyright Statement
+
+Copyright (C) The Internet Society (2001).  All Rights Reserved.
+
+This document and translations of it may be copied and furnished to
+others, and derivative works that comment on or otherwise explain it or
+assist in its implementation may be prepared, copied, published and
+distributed, in whole or in part, without restriction of any kind,
+provided that the above copyright notice and this paragraph are included
+on all such copies and derivative works.  However, this document itself
+may not be modified in any way, such as by removing the copyright notice
+or references to the Internet Society or other Internet organizations,
+except as needed for the purpose of developing Internet standards in
+which case the procedures for copyrights defined in the Internet
+Standards process must be followed, or as required to translate it into
+languages other than English.
+
+The limited permissions granted above are perpetual and will not be
+revoked by the Internet Society or its successors or assigns.
+
+This document and the information contained herein is provided on an "AS
+IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING TASK
+FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT
+LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION HEREIN WILL NOT
+INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF MERCHANTABILITY OR
+FITNESS FOR A PARTICULAR PURPOSE.
+
+12. References
+
+[RFC2131] Droms, R., "Dynamic Host Configuration Protocol", RFC 2131,
+March 1997.
+
+[RFC2132] Alexander, S., Droms, R., "DHCP Options and BOOTP Vendor
+Extensions", RFC 2132, March 1997.
+
+
+
+
+M. Meredith et al.        Expires December 2001                [Page 16]
+
+
+
+
+
+INTERNET-DRAFT            LDAP Schema for DHCP              16 June 2001
+
+
+[MSDHCP]  Gu, Y., Vyaghrapuri, R., "An LDAP Schema for Dynamic Host
+Configuration Protocol Service", Internet Draft <draft-gu-dhcp-ldap-
+schema-00.txt>, August 1998.
+
+[NOVDHCP] Miller, T., Patel, A., Rao, P., "Lightweight Directory Access
+Protocol (v3): Schema for Dynamic Host Configuration Protocol (DHCP)",
+Internet Draft <draft-miller-dhcp-ldap-schema-00.txt>, June 1998.
+
+[FAILOVR] Droms, R., Rabil, G., Dooley, M., Kapur, A., Gonczi, S., Volz,
+B., "DHCP Failover Protocol", Internet Draft <draft-ietf-dhc-
+failover-08.txt>, July 2000.
+
+[RFC 3074] Volz B., Gonczi S., Lemon T., Stevens R., "DHC Load Balancing
+Algorithm", February 2001
+
+[AGENT]   Patrick, M., "DHCP Relay Agent Information Option", Internet
+Draft <draft-ietf-dhc-agent-options-09.txt>, March 2000.
+
+[DHCPOPT] Carney, M., "New Option Review Guidelines and Additional
+Option Namespace", Internet Draft <draft-ietf-dhc-
+option_review_and_namespace-01.txt>, October 1999.
+
+[POLICY]  Strassner, J., Elleson, E., Moore, B., "Policy Framework LDAP
+Core Schema", Internet Draft <draft-ietf-policy-core-schema-06.txt>,
+November 1999.
+
+[RFC2251] Wahl, M., Howes, T., Kille, S., "Lightweight Directory Access
+Protocol (v3)", RFC 2251, December 1997.
+
+[RFC2252] Wahl, M., Coulbeck, A., Howes, T., Kille, S., "Lightweight
+Directory Access Protocol (v3) Attribute Syntax Definitions", RFC 2252,
+December 1997.
+
+[RFC2255] Howes, T., Smith, M., "The LDAP URL Format", RFC 2255,
+December 1997.
+
+[RFC951]  Croft, B., Gilmore, J., "Bootstrap Protocol (BOOTP)", RFC 951,
+September 1985.
+
+[RFC2119] Bradner, S. "Key words for use in RFCs to Indicate Requirement
+Levels", RFC 2119, March 1997.
+
+13. Acknowledgments
+
+This work is partially based on a previous draft draft-ietf-dhc-
+schema-02.doc.
+
+
+
+
+
+M. Meredith et al.        Expires December 2001                [Page 17]
+
+
+
+
+
+INTERNET-DRAFT            LDAP Schema for DHCP              16 June 2001
+
+
+14. Author's Addresses
+
+Comments regarding this draft may be sent to the authors at the
+following address:
+
+Mark Meredith
+Mark Hinckley
+Novell Inc.
+1800 S. Novell Place
+Provo, Utah 84606
+
+Vijay K. Nanjundaswamy
+Novell Software Development (I) Ltd
+49/1 & 49/3, Garvebhavi Palya,
+7th Mile, Hosur Road
+Bangalore 560068
+
+email: mark_meredith@novell.com
+email: knvijay@novell.com
+email: mhinckley@novell.com
+
+This Internet Draft expires December 16, 2001.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+M. Meredith et al.        Expires December 2001                [Page 18]
+
+
+
+
--- dhcp-3.0.5/includes/dhcpd.h.ldapconf	2007-01-31 20:39:38.000000000 -0500
+++ dhcp-3.0.5/includes/dhcpd.h	2007-01-31 20:39:38.000000000 -0500
@@ -79,6 +79,11 @@
 #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 (OPTION_HASH_SIZE)
 # define OPTION_HASH_SIZE 17
 # define OPTION_HASH_PTWO 32	/* Next power of two above option hash. */
@@ -139,6 +144,8 @@
 	char *inbuf;
 	unsigned bufix, buflen;
 	unsigned bufsiz;
+
+	int (*read_function) (struct parse *);
 };
 
 /* Variable-length array of data. */
@@ -244,6 +251,27 @@
 	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,
@@ -426,6 +454,15 @@
 # define DEFAULT_PING_TIMEOUT 1
 #endif
 
+#if defined(LDAP_CONFIGURATION)
+# define SV_LDAP_SERVER  		46
+# define SV_LDAP_PORT  			47
+# define SV_LDAP_USERNAME  		48
+# define SV_LDAP_PASSWORD  		49
+# define SV_LDAP_BASE_DN 		50
+# define SV_LDAP_METHOD			51
+#endif
+
 #if !defined (DEFAULT_DEFAULT_LEASE_TIME)
 # define DEFAULT_DEFAULT_LEASE_TIME 43200
 #endif
@@ -1526,7 +1563,7 @@
 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 *,
@@ -2640,3 +2677,14 @@
 #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
+
--- dhcp-3.0.5/includes/site.h.ldapconf	2002-03-12 13:33:39.000000000 -0500
+++ dhcp-3.0.5/includes/site.h	2007-01-31 20:39:38.000000000 -0500
@@ -177,3 +177,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"
--- dhcp-3.0.5/server/Makefile.dist.ldapconf	2007-01-31 20:39:38.000000000 -0500
+++ dhcp-3.0.5/server/Makefile.dist	2007-01-31 21:00:06.000000000 -0500
@@ -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
+	 omapi.c mdb.c stables.c salloc.c ddns.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
+	 omapi.o mdb.o stables.o salloc.o ddns.o ldap.o
 PROG   = dhcpd
 MAN    = dhcpd.8 dhcpd.conf.5 dhcpd.leases.5
 
@@ -103,6 +103,6 @@
 		-e "s#RUNDIR#$(VARRUN)#g" < dhcpd.leases.5 >dhcpd.leases.man5
 
 dhcpd:	$(OBJS) $(COBJ) $(DHCPLIB)
-	$(CC) $(LFLAGS) -pie $(RPM_OPT_FLAGS) -Wl,-z,relro,-z,now,-z,noexecstack,-z,nodlopen -o dhcpd $(OBJS) $(DHCPLIB) $(LIBS)
+	$(CC) $(LFLAGS) -pie $(RPM_OPT_FLAGS) -Wl,-z,relro,-z,now,-z,noexecstack,-z,nodlopen -o dhcpd $(OBJS) $(DHCPLIB) $(LIBS) -lldap
 
 # Dependencies (semi-automatically-generated)
--- dhcp-3.0.5/server/class.c.ldapconf	2004-06-10 13:59:51.000000000 -0400
+++ dhcp-3.0.5/server/class.c	2007-01-31 20:39:38.000000000 -0500
@@ -90,6 +90,7 @@
 	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,19 @@
 				   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,
--- dhcp-3.0.5/server/confpars.c.ldapconf	2007-01-31 20:39:38.000000000 -0500
+++ dhcp-3.0.5/server/confpars.c	2007-01-31 20:39:38.000000000 -0500
@@ -63,7 +63,17 @@
 
 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,
--- dhcp-3.0.5/server/dhcpd.c.ldapconf	2007-01-31 20:39:38.000000000 -0500
+++ dhcp-3.0.5/server/dhcpd.c	2007-01-31 20:39:38.000000000 -0500
@@ -433,6 +433,9 @@
 	/* 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!");
--- /dev/null	2007-01-31 10:24:38.956568237 -0500
+++ dhcp-3.0.5/server/ldap.c	2007-01-31 20:39:38.000000000 -0500
@@ -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]->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]->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]->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]->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]->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]->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-port, ldap-username, ldap-password and ldap-baes-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]->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]->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
+
--- dhcp-3.0.5/server/mdb.c.ldapconf	2007-01-31 20:39:38.000000000 -0500
+++ dhcp-3.0.5/server/mdb.c	2007-01-31 20:39:38.000000000 -0500
@@ -373,6 +373,12 @@
 			 const char *file, int line)
 {
 	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;
--- dhcp-3.0.5/server/stables.c.ldapconf	2004-06-10 13:59:58.000000000 -0400
+++ dhcp-3.0.5/server/stables.c	2007-01-31 20:39:38.000000000 -0500
@@ -483,12 +483,21 @@
 	{ "log-facility", "Nsyslog-facilities.",	&server_universe, 44 },
 	{ "do-forward-updates", "f",			&server_universe, 45 },
 	{ "ping-timeout", "T",				&server_universe, 46 },
+#if defined(LDAP_CONFIGURATION)
+	{ "ldap-server", "t",				&server_universe, 47 },
+	{ "ldap-port", "d",					&server_universe, 48 },
+	{ "ldap-username", "t",				&server_universe, 49 },
+	{ "ldap-password", "t",				&server_universe, 50 },
+	{ "ldap-base-dn", "t",				&server_universe, 51 },
+	{ "ldap-method", "Nldap-methods.",	&server_universe, 52 },
+#else
 	{ "unknown-47", "X",				&server_universe, 47 },
 	{ "unknown-48", "X",				&server_universe, 48 },
 	{ "unknown-49", "X",				&server_universe, 49 },
 	{ "unknown-50", "X",				&server_universe, 50 },
 	{ "unknown-51", "X",				&server_universe, 51 },
 	{ "unknown-52", "X",				&server_universe, 52 },
+#endif
 	{ "unknown-53", "X",				&server_universe, 53 },
 	{ "unknown-54", "X",				&server_universe, 54 },
 	{ "unknown-55", "X",				&server_universe, 55 },
@@ -694,6 +703,20 @@
 	{ "option-end", "e",				&server_universe, 255 },
 };
 
+#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 },
--- /dev/null	2007-01-31 10:24:38.956568237 -0500
+++ dhcp-3.0.5/README.ldap	2007-01-31 20:39:38.000000000 -0500
@@ -0,0 +1,157 @@
+LDAP Support in DHCP
+Brian Masney <masneyb@ntelos.net>
+Last updated 8/16/2002
+
+This document describes setting up the DHCP server to read it's configuration 
+from LDAP. This work is based on the IETF document 
+draft-ietf-dhc-ldap-schema-01.txt included in the doc directory. For the latest
+version of this document, please see http://home.ntelos.net/~masneyb.
+
+First question on most people's mind is "Why do I want to store my 
+configuration in LDAP?" If you run a small DHCP server, and the configuration
+on it rarely changes, then you won't need to store your configuration in LDAP.
+But, if you have several DHCP servers, and you want an easy way to manage your 
+configuration, this can be a solution. 
+
+The first step will be to setup your LDAP server. I am using OpenLDAP from
+www.openldap.org. Building and installing OpenLDAP is beyond the scope of this 
+document. There is plenty of documentation out there about this. Once you have 
+OpenLDAP installed, you will have to edit your slapd.conf file. I added the 
+following 2 lines to my configuration file:
+
+include         /etc/ldap/schema/dhcp.schema
+index           dhcpHWAddress 	eq
+index           dhcpClassData	eq
+
+The first line tells it to include the dhcp schema file. You will find this 
+file under the contrib directory in this distribution. You will need to copy 
+this file to where your other schema files are (maybe
+/usr/local/openldap/etc/openldap/schema/). The second line sets up
+an index for the dhcpHWAddress parameter. The third parameter is for reading 
+subclasses from LDAP every time a DHCP request comes in. Make sure you run the 
+slapindex command and restart slapd to have these changes to into effect.
+
+Now that you have LDAP setup, you should be able to use gq (http://biot.com/gq/)
+to verify that the dhcp schema file is loaded into LDAP. Pull up gq, and click
+on the Schema tab. Go under objectClasses, and you should see at least the 
+following object classes listed: dhcpClass, dhcpGroup, dhcpHost, dhcpOptions, 
+dhcpPool, dhcpServer, dhcpService, dhcpSharedNetwork, dhcpSubClass, and 
+dhcpSubnet. If you do not see these, you need to check over your LDAP 
+configuration before you go any further.
+
+You should be ready to build DHCP. Edit the includes/site.h file and uncomment
+the #define LDAP_CONFIGURATION. Now run configure in the base source directory.
+Edit the work.os/server/Makefile and add -lldap to the LIBS= line. (replace os
+with your operating system, linux-2.2 on my machine). You should be able to 
+type make to build your DHCP server. 
+
+Once you have DHCP installed, you will need to setup your initial plaintext 
+config file. In my /etc/dhcpd.conf file, I have:
+
+ldap-server "localhost";
+ldap-port 389;
+ldap-username "cn=DHCP User, dc=ntelos, dc=net";
+ldap-password "blah";
+ldap-base-dn "dc=ntelos, dc=net";
+ldap-method dynamic;
+
+All of these parameters should be self explanatory except for the ldap-method.
+You can set this to static or dynamic. If you set it to static, the 
+configuration is read once on startup, and LDAP isn't used anymore. But, if you
+set this to dynamic, the configuration is read once on startup, and the 
+hosts that are stored in LDAP are looked up every time a DHCP request comes in.
+
+The next step is to set up your LDAP tree. Here is an example config that will
+give a 10.100.0.x address to machines that have a host entry in LDAP. 
+Otherwise, it will give a 10.200.0.x address to them. (NOTE: replace 
+dc=ntelos, dc=net with your base dn). If you would like to convert your 
+existing dhcpd.conf file to LDIF format, there is a script 
+contrib/dhcpd-conf-to-ldap.pl that will convert it for you.
+
+# You must specify the server's host name in LDAP that you are going to run
+# DHCP on and point it to which config tree you want to use. Whenever DHCP 
+# first starts up, it will do a search for this entry to find out which 
+# config to use
+dn: cn=brian.ntelos.net, dc=ntelos, dc=net
+objectClass: top
+objectClass: dhcpServer
+cn: brian.ntelos.net
+dhcpServiceDN: cn=DHCP Service Config, dc=ntelos, dc=net
+
+# Here is the config tree that brian.ntelos.net points to. 
+dn: cn=DHCP Service Config, dc=ntelos, dc=net
+cn: DHCP Service Config
+objectClass: top
+objectClass: dhcpService
+dhcpPrimaryDN: dc=ntelos, dc=net
+dhcpStatements: ddns-update-style ad-hoc
+dhcpStatements: default-lease-time 600
+dhcpStatements: max-lease-time 7200
+
+# Set up a shared network segment
+dn: cn=WV Test, cn=DHCP Service Config, dc=ntelos, dc=net
+cn: WV
+objectClass: top
+objectClass: dhcpSharedNetwork
+
+# Set up a subnet declaration with a pool statement. Also note that we have
+# a dhcpOptions object with this entry
+dn: cn=10.100.0.0, cn=WV Test, cn=DHCP Service Config, dc=ntelos, dc=net
+cn: 10.100.0.0
+objectClass: top
+objectClass: dhcpSubnet
+objectClass: dhcpOptions
+dhcpOption: domain-name-servers 10.100.0.2
+dhcpOption: routers 10.100.0.1
+dhcpOption: subnet-mask 255.255.255.0
+dhcpOption: broadcast-address 10.100.0.255
+dhcpNetMask: 24
+
+# Set up a pool for this subnet. Only known hosts will get these IPs
+dn: cn=Known Pool, cn=10.100.0.0, cn=WV Test, cn=DHCP Service Config, dc=ntelos, dc=net
+cn: Known Pool
+objectClass: top
+objectClass: dhcpPool
+dhcpRange: 10.100.0.3 10.100.0.254
+dhcpPermitList: deny unknown-clients
+
+# Set up another subnet declaration with a pool statement
+dn: cn=10.200.0.0, cn=WV Test, cn=DHCP Service Config, dc=ntelos, dc=net
+cn: 10.200.0.0
+objectClass: top
+objectClass: dhcpSubnet
+objectClass: dhcpOptions
+dhcpOption: domain-name-servers 10.200.0.2
+dhcpOption: routers 10.200.0.1
+dhcpOption: subnet-mask 255.255.255.0
+dhcpOption: broadcast-address 10.200.0.255
+dhcpNetMask: 24
+
+# Set up a pool for this subnet. Only unknown hosts will get these IPs
+dn: cn=Known Pool, cn=10.200.0.0, cn=WV Test, cn=DHCP Service Config, dc=ntelos, dc=net
+cn: Known Pool
+objectClass: top
+objectClass: dhcpPool
+dhcpRange: 10.200.0.3 10.200.0.254
+dhcpPermitList: deny known clients
+
+# Set aside a group for all of our known MAC addresses
+dn: cn=Customers, cn=DHCP Service Config, dc=ntelos, dc=net
+objectClass: top
+objectClass: dhcpGroup
+cn: Customers
+
+# Host entry for my laptop
+dn: cn=brianlaptop, cn=Customers, cn=DHCP Service Config, dc=ntelos, dc=net
+objectClass: top
+objectClass: dhcpHost
+cn: brianlaptop
+dhcpHWAddress: ethernet 00:00:00:00:00:00
+
+You can use the command slapadd to load all of these entries into your LDAP 
+server. After you load this, you should be able to start up DHCP. If you run
+into problems reading the configuration, try running dhcpd with the -d flag. 
+If you still have problems, edit the site.conf file in the DHCP source and
+add the line: COPTS= -DDEBUG_LDAP and recompile DHCP. (make sure you run make 
+clean and rerun configure before you rebuild).
+
--- dhcp-3.0.5/site.conf.ldapconf	1999-07-07 11:20:10.000000000 -0400
+++ dhcp-3.0.5/site.conf	2007-01-31 20:39:38.000000000 -0500
@@ -1,2 +1,7 @@
-# Put local site configuration stuff here to override the default
-# settings in Makefile.conf
+VARDB=/var/lib/dhcpd
+ADMMANDIR=/usr/share/man/man8
+FFMANDIR=/usr/share/man/man5
+LIBMANDIR=/usr/share/man/man3
+USRMANDIR=/usr/share/man/man1
+LIBDIR=/usr/lib
+INCDIR=/usr/include