diff -up dhcp-4.2.1/common/conflex.c.ldap_v6 dhcp-4.2.1/common/conflex.c --- dhcp-4.2.1/common/conflex.c.ldap_v6 2011-03-04 17:42:55.000000000 +0100 +++ dhcp-4.2.1/common/conflex.c 2011-03-04 17:45:30.000000000 +0100 @@ -472,6 +472,8 @@ read_whitespace(int c, struct parse *cfi do { cfile->tokbuf[ofs++] = c; c = get_char(cfile); + if (c == EOF) + return END_OF_FILE; } while (!((c == '\n') && cfile->eol_token) && isascii(c) && isspace(c)); diff -up dhcp-4.2.1/contrib/ldap/dhcp.schema.ldap_v6 dhcp-4.2.1/contrib/ldap/dhcp.schema --- dhcp-4.2.1/contrib/ldap/dhcp.schema.ldap_v6 2010-03-25 16:27:16.000000000 +0100 +++ dhcp-4.2.1/contrib/ldap/dhcp.schema 2011-03-04 18:11:59.000000000 +0100 @@ -334,6 +334,18 @@ attributetype ( 2.16.840.1.113719.1.203. DESC 'Generic attribute that allows coments within any DHCP object' SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE ) +attributetype ( 2.16.840.1.113719.1.203.4.57 + NAME 'dhcpClientId' + EQUALITY caseIgnoreIA5Match + DESC 'client Identifier.' + SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 ) + +attributetype ( 2.16.840.1.113719.1.203.4.58 + NAME 'dhcpRange6' + EQUALITY caseIgnoreIA5Match + 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 ) + # Classes objectclass ( 2.16.840.1.113719.1.203.6.1 @@ -378,7 +390,7 @@ objectclass ( 2.16.840.1.113719.1.203.6. DESC 'This represents information about a particular client' SUP top MUST cn - MAY (dhcpLeaseDN $ dhcpHWAddress $ dhcpOptionsDN $ dhcpStatements $ dhcpComments $ dhcpOption) + MAY (dhcpLeaseDN $ dhcpHWAddress $ dhcpOptionsDN $ dhcpStatements $ dhcpComments $ dhcpOption $dhcpClientId ) X-NDS_CONTAINMENT ('dhcpService' 'dhcpSubnet' 'dhcpGroup') ) objectclass ( 2.16.840.1.113719.1.203.6.7 @@ -459,4 +471,18 @@ objectclass ( 2.16.840.1.113719.1.203.6. MAY ( dhcpServiceDN $dhcpServerDN $ dhcpSharedNetworkDN $ dhcpSubnetDN $ dhcpPoolDN $ dhcpGroupDN $ dhcpHostDN $ dhcpClassesDN $ dhcpKeyDN $ dhcpZoneDN $ dhcpFailOverPeerDN $ dhcpOption $ dhcpComments) X-NDS_CONTAINMENT ('organization' 'organizationalunit' 'domain') ) +objectclass ( 2.16.840.1.113719.1.203.6.17 + NAME 'dhcpSubnet6' + DESC 'This class defines an IPv6 subnet. This is a container object.' + SUP top + MUST ( cn ) + MAY ( dhcpRange6 $ dhcpPoolDN $ dhcpGroupDN $ dhcpHostDN $ dhcpClassesDN $ dhcpLeasesDN $ dhcpOptionsDN $ dhcpZoneDN $ dhcpKeyDN $ dhcpFailOverPeerDN $ dhcpStatements $ dhcpComments $ dhcpOption $ dhcpPermitList ) X-NDS_CONTAINMENT ('dhcpService' 'dhcpSharedNetwork') ) + +objectclass ( 2.16.840.1.113719.1.203.6.18 + NAME 'dhcpPool6' + DESC 'This stores configuration information about an IPv6 pool.' + SUP top + MUST ( cn $ dhcpRange6 ) + MAY ( dhcpClassesDN $ dhcpPermitList $ dhcpLeasesDN $ dhcpOptionsDN $ dhcpZoneDN $dhcpKeyDN $ dhcpStatements $ dhcpComments $ dhcpOption ) + X-NDS_CONTAINMENT ('dhcpSubnet' 'dhcpSharedNetwork') ) diff -up dhcp-4.2.1/contrib/ldap/README.ldap.ldap_v6 dhcp-4.2.1/contrib/ldap/README.ldap --- dhcp-4.2.1/contrib/ldap/README.ldap.ldap_v6 2010-03-25 16:27:16.000000000 +0100 +++ dhcp-4.2.1/contrib/ldap/README.ldap 2011-03-04 18:13:13.000000000 +0100 @@ -189,3 +189,38 @@ into problems reading the configuration, 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). + +DHCPv6 requires a separate instance of the dhcpd server from the +DHCPv4 server. + +It is convenient to use distinct LDAP login DNs for the two servers, +and setup LDAP access restrictions in the LDAP server, so that each +DHCP server only has access to its own data. + +You will need to create a separate configuration file, +call it /etc/dhcpd6.conf. For example: + +ldap-server "localhost"; +ldap-port 389; +ldap-username "cn=DHCPv6 User, dc=ntelos, dc=net"; +ldap-password "blahblah"; +ldap-base-dn "dc=ntelos, dc=net"; +ldap-method dynamic; +ldap-debug-file "/var/log/dhcp-ldap-startup.log"; + +And use these command line arguments to dhcpd: + +dhcpd eth... -6 -cf /etc/dhcpd6.conf -pf /var/run/dhcpd6.pid -lf /var/lib/dhcpd6/dhcpd.leases + +For DHCPv6, the client configuration is the same, but substitute the +Client ID for the Ethernet hardware address. Here is an example of a +host definition for a DHCPv6 client: + +dn: cn=examplehost,cn=XXXX:XXXX:XXXX:XXXX::/64,cn=Network-eth1,cn=DHCPv6,dc=example,dc=com +objectClass: top +objectClass: dhcpHost +cn: examplehost +dhcpClientId: XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX +dhcpStatements: fixed-address6 XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX +option host-name "examplehost.ipv6.example.com" +option domain-name "ipv6.example.com" diff -up dhcp-4.2.1/includes/dhcpd.h.ldap_v6 dhcp-4.2.1/includes/dhcpd.h --- dhcp-4.2.1/includes/dhcpd.h.ldap_v6 2011-03-04 17:42:55.000000000 +0100 +++ dhcp-4.2.1/includes/dhcpd.h 2011-03-04 17:53:12.000000000 +0100 @@ -3442,6 +3442,8 @@ int find_haddr_in_ldap (struct host_decl const unsigned char *, const char *, int); int find_subclass_in_ldap (struct class *, struct class **, struct data_string *); +int find_client_in_ldap (struct host_decl **, struct packet*, + struct option_state *, const char *, int); #endif /* mdb6.c */ diff -up dhcp-4.2.1/server/ldap.c.ldap_v6 dhcp-4.2.1/server/ldap.c --- dhcp-4.2.1/server/ldap.c.ldap_v6 2011-03-04 17:42:55.000000000 +0100 +++ dhcp-4.2.1/server/ldap.c 2011-03-04 18:07:26.000000000 +0100 @@ -270,6 +270,55 @@ ldap_parse_subnet (struct ldap_config_st x_strncat (cfile->inbuf, tempbv[i]->bv_val, LDAP_BUFFER_SIZE); x_strncat (cfile->inbuf, ";\n", LDAP_BUFFER_SIZE); } + ldap_value_free_len (tempbv); + } + + item->close_brace = 1; +} + + +static void +ldap_parse_subnet6 (struct ldap_config_stack *item, struct parse *cfile) +{ + struct berval **tempbv; + int i; + + if ((tempbv = ldap_get_values_len (ld, item->ldent, "cn")) == NULL || + tempbv[0] == NULL) + { + if (tempbv != NULL) + ldap_value_free_len (tempbv); + + return; + } + + x_strncat (cfile->inbuf, "subnet6 ", LDAP_BUFFER_SIZE); + x_strncat (cfile->inbuf, tempbv[0]->bv_val, LDAP_BUFFER_SIZE); + + x_strncat (cfile->inbuf, " {\n", LDAP_BUFFER_SIZE); + + ldap_value_free_len (tempbv); + + if ((tempbv = ldap_get_values_len (ld, item->ldent, "dhcpRange")) != NULL) + { + for (i=0; tempbv[i] != NULL; i++) + { + x_strncat (cfile->inbuf, "range6", LDAP_BUFFER_SIZE); + x_strncat (cfile->inbuf, " ", LDAP_BUFFER_SIZE); + x_strncat (cfile->inbuf, tempbv[i]->bv_val, LDAP_BUFFER_SIZE); + x_strncat (cfile->inbuf, ";\n", LDAP_BUFFER_SIZE); + } + ldap_value_free_len (tempbv); + } + + if ((tempbv = ldap_get_values_len (ld, item->ldent, "dhcpPermitList")) != NULL) + { + for (i=0; tempbv[i] != NULL; i++) + { + x_strncat (cfile->inbuf, tempbv[i]->bv_val, LDAP_BUFFER_SIZE); + x_strncat (cfile->inbuf, ";\n", LDAP_BUFFER_SIZE); + } + ldap_value_free_len (tempbv); } item->close_brace = 1; @@ -311,6 +360,40 @@ ldap_parse_pool (struct ldap_config_stac static void +ldap_parse_pool6 (struct ldap_config_stack *item, struct parse *cfile) +{ + struct berval **tempbv; + int i; + + x_strncat (cfile->inbuf, "pool {\n", LDAP_BUFFER_SIZE); + + if ((tempbv = ldap_get_values_len (ld, item->ldent, "dhcpRange")) != NULL) + { + x_strncat (cfile->inbuf, "range6", LDAP_BUFFER_SIZE); + for (i=0; tempbv[i] != NULL; i++) + { + x_strncat (cfile->inbuf, " ", LDAP_BUFFER_SIZE); + x_strncat (cfile->inbuf, tempbv[i]->bv_val, LDAP_BUFFER_SIZE); + } + x_strncat (cfile->inbuf, ";\n", LDAP_BUFFER_SIZE); + ldap_value_free_len (tempbv); + } + + if ((tempbv = ldap_get_values_len (ld, item->ldent, "dhcpPermitList")) != NULL) + { + for (i=0; tempbv[i] != NULL; i++) + { + x_strncat (cfile->inbuf, tempbv[i]->bv_val, LDAP_BUFFER_SIZE); + x_strncat (cfile->inbuf, ";\n", LDAP_BUFFER_SIZE); + } + ldap_value_free_len (tempbv); + } + + item->close_brace = 1; +} + + +static void ldap_parse_group (struct ldap_config_stack *item, struct parse *cfile) { x_strncat (cfile->inbuf, "group {\n", LDAP_BUFFER_SIZE); @@ -1156,8 +1239,12 @@ ldap_generate_config_string (struct pars ldap_parse_class (entry, cfile); else if (strcasecmp (objectClass[i]->bv_val, "dhcpSubnet") == 0) ldap_parse_subnet (entry, cfile); + else if (strcasecmp (objectClass[i]->bv_val, "dhcpSubnet6") == 0) + ldap_parse_subnet6 (entry, cfile); else if (strcasecmp (objectClass[i]->bv_val, "dhcpPool") == 0) ldap_parse_pool (entry, cfile); + else if (strcasecmp (objectClass[i]->bv_val, "dhcpPool6") == 0) + ldap_parse_pool6 (entry, cfile); else if (strcasecmp (objectClass[i]->bv_val, "dhcpGroup") == 0) ldap_parse_group (entry, cfile); else if (strcasecmp (objectClass[i]->bv_val, "dhcpTSigKey") == 0) @@ -2001,4 +2088,156 @@ find_subclass_in_ldap (struct class *cla return (0); } +int find_client_in_ldap (struct host_decl **hp, struct packet *packet, + struct option_state *state, const char *file, int line) +{ + LDAPMessage * res, * ent; + ldap_dn_node *curr; + struct host_decl * host; + isc_result_t status; + struct data_string client_id; + char buf[1024], buf1[1024]; + int ret; + + if (ldap_method == LDAP_METHOD_STATIC) + return (0); + + if (ld == NULL) + ldap_start (); + if (ld == NULL) + return (0); + + memset(&client_id, 0, sizeof(client_id)); + if (get_client_id(packet, &client_id) != ISC_R_SUCCESS) + return (0); + snprintf(buf, sizeof(buf), + "(&(objectClass=dhcpHost)(dhcpClientId=%s))", + print_hw_addr(0, client_id.len, client_id.data)); + + /* log_info ("Searching LDAP for %s (%s)", buf, packet->interface->shared_network->name); */ + + res = ent = NULL; + for (curr = ldap_service_dn_head; + curr != NULL && *curr->dn != '\0'; + curr = curr->next) + { + snprintf(buf1, sizeof(buf1), "cn=%s,%s", packet->interface->shared_network->name, curr->dn); +#if defined (DEBUG_LDAP) + log_info ("Searching for %s in LDAP tree %s", buf, buf1); +#endif + ret = ldap_search_ext_s (ld, buf1, LDAP_SCOPE_SUBTREE, buf, NULL, 0, + NULL, NULL, NULL, 0, &res); + + if(ret == LDAP_SERVER_DOWN) + { + log_info ("LDAP server was down, trying to reconnect..."); + + ldap_stop(); + ldap_start(); + + if(ld == NULL) + { + log_info ("LDAP reconnect failed - try again later..."); + return (0); + } + + ret = ldap_search_ext_s (ld, buf1, LDAP_SCOPE_SUBTREE, buf, + NULL, 0, NULL, NULL, NULL, 0, &res); + } + + if (ret == LDAP_SUCCESS) + { + if( (ent = ldap_first_entry (ld, res)) != NULL) { + log_info ("found entry in search %s", buf1); + break; /* search OK and have entry */ + } + +#if defined (DEBUG_LDAP) + log_info ("No subclass entry for %s in LDAP tree %s", buf, curr->dn); +#endif + if(res) + { + ldap_msgfree (res); + res = NULL; + } + } + else + { + if(res) + { + ldap_msgfree (res); + res = NULL; + } + + if (ret != LDAP_NO_SUCH_OBJECT && ret != LDAP_SUCCESS) + { + log_error ("Cannot search for %s in LDAP tree %s: %s", buf, + curr->dn, ldap_err2string (ret)); + ldap_stop(); + return (0); + } + else + { + log_info ("did not find: %s", buf); + } + } + } + + if (res && ent) + { +#if defined (DEBUG_LDAP) + log_info ("ldap_get_dn", curr->dn); + char *dn = ldap_get_dn (ld, ent); + if (dn != NULL) + { + log_info ("Found subclass LDAP entry %s", dn); + ldap_memfree(dn); + } else { + log_info ("DN is null %s", dn); + } +#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)); + ldap_msgfree (res); + return (0); + } + + host->name = ldap_get_host_name (ent); + if (host->name == NULL) + { + host_dereference (&host, MDL); + ldap_msgfree (res); + return (0); + } + /* log_info ("Host name %s", host->name); */ + + if (!clone_group (&host->group, root_group, MDL)) + { + log_fatal ("can't clone group for host %s", host->name); + host_dereference (&host, MDL); + ldap_msgfree (res); + return (0); + } + + ldap_parse_options (ent, host->group, HOST_DECL, host, NULL); + + *hp = host; + ldap_msgfree (res); + return (1); + } + else + { + log_info ("did not find clientid: %s", buf); + } + + if(res) ldap_msgfree (res); + return (0); + +} + #endif diff -up dhcp-4.2.1/server/mdb.c.ldap_v6 dhcp-4.2.1/server/mdb.c --- dhcp-4.2.1/server/mdb.c.ldap_v6 2011-02-18 19:26:46.000000000 +0100 +++ dhcp-4.2.1/server/mdb.c 2011-03-04 17:51:04.000000000 +0100 @@ -631,7 +631,12 @@ find_hosts_by_option(struct host_decl ** struct option_cache *oc; struct data_string data; int found; - + +#if defined(LDAP_CONFIGURATION) + if ((found = find_client_in_ldap (hp, packet, opt_state, file, line))) + return found; +#endif + for (p = host_id_info; p != NULL; p = p->next) { oc = lookup_option(p->option->universe, opt_state, p->option->code);