server/ldap.c

Go to the documentation of this file.
00001 /* ldap.c
00002 
00003    Routines for reading the configuration from LDAP */
00004 
00005 /*
00006  * Copyright (c) 2003-2006 Ntelos, Inc.
00007  * All rights reserved.
00008  *
00009  * Redistribution and use in source and binary forms, with or without
00010  * modification, are permitted provided that the following conditions
00011  * are met:
00012  *
00013  * 1. Redistributions of source code must retain the above copyright
00014  *    notice, this list of conditions and the following disclaimer.
00015  * 2. Redistributions in binary form must reproduce the above copyright
00016  *    notice, this list of conditions and the following disclaimer in the
00017  *    documentation and/or other materials provided with the distribution.
00018  * 3. Neither the name of The Internet Software Consortium nor the names
00019  *    of its contributors may be used to endorse or promote products derived
00020  *    from this software without specific prior written permission.
00021  *
00022  * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND
00023  * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
00024  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
00025  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
00026  * DISCLAIMED.  IN NO EVENT SHALL THE INTERNET SOFTWARE CONSORTIUM OR
00027  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
00028  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
00029  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
00030  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
00031  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
00032  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
00033  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
00034  * SUCH DAMAGE.
00035  *
00036  * This LDAP module was written by Brian Masney <masneyb@ntelos.net>. Its
00037  * development was sponsored by Ntelos, Inc. (www.ntelos.com).
00038  */
00039 
00040 #include "dhcpd.h"
00041 #include <signal.h>
00042 #include <errno.h>
00043 
00044 #if defined(LDAP_CONFIGURATION)
00045 
00046 #if defined(LDAP_CASA_AUTH)
00047 #include "ldap_casa.h"
00048 #endif
00049 
00050 static LDAP * ld = NULL;
00051 static char *ldap_server = NULL, 
00052             *ldap_username = NULL, 
00053             *ldap_password = NULL,
00054             *ldap_base_dn = NULL,
00055             *ldap_dhcp_server_cn = NULL,
00056             *ldap_debug_file = NULL;
00057 static int ldap_port = LDAP_PORT,
00058            ldap_method = LDAP_METHOD_DYNAMIC,
00059            ldap_referrals = -1,
00060            ldap_debug_fd = -1;
00061 #if defined (LDAP_USE_SSL)
00062 static int ldap_use_ssl = -1,        /* try TLS if possible */
00063            ldap_tls_reqcert = -1,
00064            ldap_tls_crlcheck = -1;
00065 static char *ldap_tls_ca_file = NULL,
00066             *ldap_tls_ca_dir = NULL,
00067             *ldap_tls_cert = NULL,
00068             *ldap_tls_key = NULL,
00069             *ldap_tls_ciphers = NULL,
00070             *ldap_tls_randfile = NULL;
00071 #endif
00072 static struct ldap_config_stack *ldap_stack = NULL;
00073 
00074 typedef struct ldap_dn_node {
00075     struct ldap_dn_node *next;
00076     size_t refs;
00077     char *dn;
00078 } ldap_dn_node;
00079 
00080 static ldap_dn_node *ldap_service_dn_head = NULL;
00081 static ldap_dn_node *ldap_service_dn_tail = NULL;
00082 
00083 
00084 static char *
00085 x_strncat(char *dst, const char *src, size_t dst_size)
00086 {
00087   size_t len = strlen(dst);
00088   return strncat(dst, src, dst_size > len ? dst_size - len - 1: 0);
00089 }
00090 
00091 static void
00092 ldap_parse_class (struct ldap_config_stack *item, struct parse *cfile)
00093 {
00094   struct berval **tempbv;
00095 
00096   if ((tempbv = ldap_get_values_len (ld, item->ldent, "cn")) == NULL ||
00097       tempbv[0] == NULL)
00098     {
00099       if (tempbv != NULL)
00100         ldap_value_free_len (tempbv);
00101 
00102       return;
00103     }
00104 
00105   x_strncat (cfile->inbuf, "class \"", LDAP_BUFFER_SIZE);
00106   x_strncat (cfile->inbuf, tempbv[0]->bv_val, LDAP_BUFFER_SIZE);
00107   x_strncat (cfile->inbuf, "\" {\n", LDAP_BUFFER_SIZE);
00108 
00109   item->close_brace = 1;
00110   ldap_value_free_len (tempbv);
00111 }
00112 
00113 
00114 static void
00115 ldap_parse_subclass (struct ldap_config_stack *item, struct parse *cfile)
00116 {
00117   struct berval **tempbv, **classdata;
00118 
00119   if ((tempbv = ldap_get_values_len (ld, item->ldent, "cn")) == NULL ||
00120       tempbv[0] == NULL)
00121     {
00122       if (tempbv != NULL)
00123         ldap_value_free_len (tempbv);
00124 
00125       return;
00126     }
00127 
00128   if ((classdata = ldap_get_values_len (ld, item->ldent, 
00129                                   "dhcpClassData")) == NULL || 
00130       classdata[0] == NULL)
00131     {
00132       if (classdata != NULL)
00133         ldap_value_free_len (classdata);
00134       ldap_value_free_len (tempbv);
00135 
00136       return;
00137     }
00138 
00139   x_strncat (cfile->inbuf, "subclass ", LDAP_BUFFER_SIZE);
00140   x_strncat (cfile->inbuf, classdata[0]->bv_val, LDAP_BUFFER_SIZE);
00141   x_strncat (cfile->inbuf, " ", LDAP_BUFFER_SIZE);
00142   x_strncat (cfile->inbuf, tempbv[0]->bv_val, LDAP_BUFFER_SIZE);
00143   x_strncat (cfile->inbuf, " {\n", LDAP_BUFFER_SIZE);
00144 
00145   item->close_brace = 1;
00146   ldap_value_free_len (tempbv);
00147   ldap_value_free_len (classdata);
00148 }
00149 
00150 
00151 static void
00152 ldap_parse_host (struct ldap_config_stack *item, struct parse *cfile)
00153 {
00154   struct berval **tempbv, **hwaddr;
00155 
00156   if ((tempbv = ldap_get_values_len (ld, item->ldent, "cn")) == NULL ||
00157       tempbv[0] == NULL)
00158     {
00159       if (tempbv != NULL)
00160         ldap_value_free_len (tempbv);
00161 
00162       return;
00163     }
00164 
00165   hwaddr = ldap_get_values_len (ld, item->ldent, "dhcpHWAddress");
00166 
00167   x_strncat (cfile->inbuf, "host ", LDAP_BUFFER_SIZE);
00168   x_strncat (cfile->inbuf, tempbv[0]->bv_val, LDAP_BUFFER_SIZE);
00169 
00170   if (hwaddr != NULL && hwaddr[0] != NULL)
00171     {
00172       x_strncat (cfile->inbuf, " {\nhardware ", LDAP_BUFFER_SIZE);
00173       x_strncat (cfile->inbuf, hwaddr[0]->bv_val, LDAP_BUFFER_SIZE);
00174       x_strncat (cfile->inbuf, ";\n", LDAP_BUFFER_SIZE);
00175       ldap_value_free_len (hwaddr);
00176     }
00177 
00178   item->close_brace = 1;
00179   ldap_value_free_len (tempbv);
00180 }
00181 
00182 
00183 static void
00184 ldap_parse_shared_network (struct ldap_config_stack *item, struct parse *cfile)
00185 {
00186   struct berval **tempbv;
00187 
00188   if ((tempbv = ldap_get_values_len (ld, item->ldent, "cn")) == NULL ||
00189       tempbv[0] == NULL)
00190     {
00191       if (tempbv != NULL)
00192         ldap_value_free_len (tempbv);
00193 
00194       return;
00195     }
00196 
00197   x_strncat (cfile->inbuf, "shared-network \"", LDAP_BUFFER_SIZE);
00198   x_strncat (cfile->inbuf, tempbv[0]->bv_val, LDAP_BUFFER_SIZE);
00199   x_strncat (cfile->inbuf, "\" {\n", LDAP_BUFFER_SIZE);
00200 
00201   item->close_brace = 1;
00202   ldap_value_free_len (tempbv);
00203 }
00204 
00205 
00206 static void
00207 parse_netmask (int netmask, char *netmaskbuf)
00208 {
00209   unsigned long nm;
00210   int i;
00211 
00212   nm = 0;
00213   for (i=1; i <= netmask; i++)
00214     {
00215       nm |= 1 << (32 - i);
00216     }
00217 
00218   sprintf (netmaskbuf, "%d.%d.%d.%d", (int) (nm >> 24) & 0xff, 
00219                                       (int) (nm >> 16) & 0xff, 
00220                                       (int) (nm >> 8) & 0xff, 
00221                                       (int) nm & 0xff);
00222 }
00223 
00224 
00225 static void
00226 ldap_parse_subnet (struct ldap_config_stack *item, struct parse *cfile)
00227 {
00228   struct berval **tempbv, **netmaskstr;
00229   char netmaskbuf[sizeof("255.255.255.255")];
00230   int i;
00231 
00232   if ((tempbv = ldap_get_values_len (ld, item->ldent, "cn")) == NULL ||
00233       tempbv[0] == NULL)
00234     {
00235       if (tempbv != NULL)
00236         ldap_value_free_len (tempbv);
00237 
00238       return;
00239     }
00240 
00241   if ((netmaskstr = ldap_get_values_len (ld, item->ldent, 
00242                                      "dhcpNetmask")) == NULL || 
00243       netmaskstr[0] == NULL)
00244     {
00245       if (netmaskstr != NULL)
00246         ldap_value_free_len (netmaskstr);
00247       ldap_value_free_len (tempbv);
00248 
00249       return;
00250     }
00251 
00252   x_strncat (cfile->inbuf, "subnet ", LDAP_BUFFER_SIZE);
00253   x_strncat (cfile->inbuf, tempbv[0]->bv_val, LDAP_BUFFER_SIZE);
00254 
00255   x_strncat (cfile->inbuf, " netmask ", LDAP_BUFFER_SIZE);
00256   parse_netmask (strtol (netmaskstr[0]->bv_val, NULL, 10), netmaskbuf);
00257   x_strncat (cfile->inbuf, netmaskbuf, LDAP_BUFFER_SIZE);
00258 
00259   x_strncat (cfile->inbuf, " {\n", LDAP_BUFFER_SIZE);
00260 
00261   ldap_value_free_len (tempbv);
00262   ldap_value_free_len (netmaskstr);
00263 
00264   if ((tempbv = ldap_get_values_len (ld, item->ldent, "dhcpRange")) != NULL)
00265     {
00266       for (i=0; tempbv[i] != NULL; i++)
00267         {
00268           x_strncat (cfile->inbuf, "range", LDAP_BUFFER_SIZE);
00269           x_strncat (cfile->inbuf, " ", LDAP_BUFFER_SIZE);
00270           x_strncat (cfile->inbuf, tempbv[i]->bv_val, LDAP_BUFFER_SIZE);
00271           x_strncat (cfile->inbuf, ";\n", LDAP_BUFFER_SIZE);
00272         }
00273     }
00274 
00275   item->close_brace = 1;
00276 }
00277 
00278 
00279 static void
00280 ldap_parse_pool (struct ldap_config_stack *item, struct parse *cfile)
00281 {
00282   struct berval **tempbv;
00283   int i;
00284 
00285   x_strncat (cfile->inbuf, "pool {\n", LDAP_BUFFER_SIZE);
00286 
00287   if ((tempbv = ldap_get_values_len (ld, item->ldent, "dhcpRange")) != NULL)
00288     {
00289       x_strncat (cfile->inbuf, "range", LDAP_BUFFER_SIZE);
00290       for (i=0; tempbv[i] != NULL; i++)
00291         {
00292           x_strncat (cfile->inbuf, " ", LDAP_BUFFER_SIZE);
00293           x_strncat (cfile->inbuf, tempbv[i]->bv_val, LDAP_BUFFER_SIZE);
00294         }
00295       x_strncat (cfile->inbuf, ";\n", LDAP_BUFFER_SIZE);
00296       ldap_value_free_len (tempbv);
00297     }
00298 
00299   if ((tempbv = ldap_get_values_len (ld, item->ldent, "dhcpPermitList")) != NULL)
00300     {
00301       for (i=0; tempbv[i] != NULL; i++)
00302         {
00303           x_strncat (cfile->inbuf, tempbv[i]->bv_val, LDAP_BUFFER_SIZE);
00304           x_strncat (cfile->inbuf, ";\n", LDAP_BUFFER_SIZE);
00305         }
00306       ldap_value_free_len (tempbv);
00307     }
00308 
00309   item->close_brace = 1;
00310 }
00311 
00312 
00313 static void
00314 ldap_parse_group (struct ldap_config_stack *item, struct parse *cfile)
00315 {
00316   x_strncat (cfile->inbuf, "group {\n", LDAP_BUFFER_SIZE);
00317   item->close_brace = 1;
00318 }
00319 
00320 
00321 static void
00322 ldap_parse_key (struct ldap_config_stack *item, struct parse *cfile)
00323 {
00324   struct berval **tempbv;
00325 
00326   if ((tempbv = ldap_get_values_len (ld, item->ldent, "cn")) != NULL)
00327     {
00328       x_strncat (cfile->inbuf, "key ", LDAP_BUFFER_SIZE);
00329       x_strncat (cfile->inbuf, tempbv[0]->bv_val, LDAP_BUFFER_SIZE);
00330       x_strncat (cfile->inbuf, " {\n", LDAP_BUFFER_SIZE);
00331       ldap_value_free_len (tempbv);
00332     }
00333 
00334   if ((tempbv = ldap_get_values_len (ld, item->ldent, "dhcpKeyAlgorithm")) != NULL)
00335     {
00336       x_strncat (cfile->inbuf, "algorithm ", LDAP_BUFFER_SIZE);
00337       x_strncat (cfile->inbuf, tempbv[0]->bv_val, LDAP_BUFFER_SIZE);
00338       x_strncat (cfile->inbuf, ";\n", LDAP_BUFFER_SIZE);
00339       ldap_value_free_len (tempbv);
00340     }
00341 
00342   if ((tempbv = ldap_get_values_len (ld, item->ldent, "dhcpKeySecret")) != NULL)
00343     {
00344       x_strncat (cfile->inbuf, "secret ", LDAP_BUFFER_SIZE);
00345       x_strncat (cfile->inbuf, tempbv[0]->bv_val, LDAP_BUFFER_SIZE);
00346       x_strncat (cfile->inbuf, ";\n", LDAP_BUFFER_SIZE);
00347       ldap_value_free_len (tempbv);
00348     }
00349 
00350   item->close_brace = 1;
00351 }
00352 
00353 
00354 static void
00355 ldap_parse_zone (struct ldap_config_stack *item, struct parse *cfile)
00356 {
00357   char *cnFindStart, *cnFindEnd;
00358   struct berval **tempbv;
00359   char *keyCn;
00360   size_t len;
00361 
00362   if ((tempbv = ldap_get_values_len (ld, item->ldent, "cn")) != NULL)
00363     {
00364       x_strncat (cfile->inbuf, "zone ", LDAP_BUFFER_SIZE);
00365       x_strncat (cfile->inbuf, tempbv[0]->bv_val, LDAP_BUFFER_SIZE);
00366       x_strncat (cfile->inbuf, " {\n", LDAP_BUFFER_SIZE);
00367       ldap_value_free_len (tempbv);
00368     }
00369 
00370   if ((tempbv = ldap_get_values_len (ld, item->ldent, "dhcpDnsZoneServer")) != NULL)
00371     {
00372       x_strncat (cfile->inbuf, "primary ", LDAP_BUFFER_SIZE);
00373       x_strncat (cfile->inbuf, tempbv[0]->bv_val, LDAP_BUFFER_SIZE);
00374 
00375       x_strncat (cfile->inbuf, ";\n", LDAP_BUFFER_SIZE);
00376       ldap_value_free_len (tempbv);
00377     }
00378 
00379   if ((tempbv = ldap_get_values_len (ld, item->ldent, "dhcpKeyDN")) != NULL)
00380     {
00381       cnFindStart = strchr(tempbv[0]->bv_val,'=');
00382       if (cnFindStart != NULL)
00383         cnFindEnd = strchr(++cnFindStart,',');
00384       else
00385         cnFindEnd = NULL;
00386 
00387       if (cnFindEnd != NULL && cnFindEnd > cnFindStart)
00388         {
00389           len = cnFindEnd - cnFindStart;
00390           keyCn = dmalloc (len + 1, MDL);
00391         }
00392       else
00393         {
00394           len = 0;
00395           keyCn = NULL;
00396         }
00397 
00398       if (keyCn != NULL)
00399         {
00400           strncpy (keyCn, cnFindStart, len);
00401           keyCn[len] = '\0';
00402 
00403           x_strncat (cfile->inbuf, "key ", LDAP_BUFFER_SIZE);
00404           x_strncat (cfile->inbuf, keyCn, LDAP_BUFFER_SIZE);
00405           x_strncat (cfile->inbuf, ";\n", LDAP_BUFFER_SIZE);
00406 
00407           dfree (keyCn, MDL);
00408         }
00409 
00410       ldap_value_free_len (tempbv);
00411      }
00412 
00413   item->close_brace = 1;
00414 }
00415 
00416 
00417 static void
00418 add_to_config_stack (LDAPMessage * res, LDAPMessage * ent)
00419 {
00420   struct ldap_config_stack *ns;
00421 
00422   ns = dmalloc (sizeof (*ns), MDL);
00423   ns->res = res;
00424   ns->ldent = ent;
00425   ns->close_brace = 0;
00426   ns->processed = 0;
00427   ns->next = ldap_stack;
00428   ldap_stack = ns;
00429 }
00430 
00431 
00432 static void
00433 ldap_stop()
00434 {
00435   struct sigaction old, new;
00436 
00437   if (ld == NULL)
00438     return;
00439 
00440   /*
00441    ** ldap_unbind after a LDAP_SERVER_DOWN result
00442    ** causes a SIGPIPE and dhcpd gets terminated,
00443    ** since it doesn't handle it...
00444    */
00445 
00446   new.sa_flags   = 0;
00447   new.sa_handler = SIG_IGN;
00448   sigemptyset (&new.sa_mask);
00449   sigaction (SIGPIPE, &new, &old);
00450 
00451   ldap_unbind_ext_s (ld, NULL, NULL);
00452   ld = NULL;
00453 
00454   sigaction (SIGPIPE, &old, &new);
00455 }
00456 
00457 
00458 static char *
00459 _do_lookup_dhcp_string_option (struct option_state *options, int option_name)
00460 {
00461   struct option_cache *oc;
00462   struct data_string db;
00463   char *ret;
00464 
00465   memset (&db, 0, sizeof (db));
00466   oc = lookup_option (&server_universe, options, option_name);
00467   if (oc &&
00468       evaluate_option_cache (&db, (struct packet*) NULL,
00469                              (struct lease *) NULL,
00470                              (struct client_state *) NULL, options,
00471                              (struct option_state *) NULL,
00472                              &global_scope, oc, MDL) &&
00473       db.data != NULL && *db.data != '\0')
00474 
00475     {
00476       ret = dmalloc (db.len + 1, MDL);
00477       if (ret == NULL)
00478         log_fatal ("no memory for ldap option %d value", option_name);
00479 
00480       memcpy (ret, db.data, db.len);
00481       ret[db.len] = 0;
00482       data_string_forget (&db, MDL);
00483     }
00484   else
00485     ret = NULL;
00486 
00487   return (ret);
00488 }
00489 
00490 
00491 static int
00492 _do_lookup_dhcp_int_option (struct option_state *options, int option_name)
00493 {
00494   struct option_cache *oc;
00495   struct data_string db;
00496   int ret;
00497 
00498   memset (&db, 0, sizeof (db));
00499   oc = lookup_option (&server_universe, options, option_name);
00500   if (oc &&
00501       evaluate_option_cache (&db, (struct packet*) NULL,
00502                              (struct lease *) NULL,
00503                              (struct client_state *) NULL, options,
00504                              (struct option_state *) NULL,
00505                              &global_scope, oc, MDL) &&
00506       db.data != NULL && *db.data != '\0')
00507     {
00508       ret = strtol ((const char *) db.data, NULL, 10);
00509       data_string_forget (&db, MDL);
00510     }
00511   else
00512     ret = 0;
00513 
00514   return (ret);
00515 }
00516 
00517 
00518 static int
00519 _do_lookup_dhcp_enum_option (struct option_state *options, int option_name)
00520 {
00521   struct option_cache *oc;
00522   struct data_string db;
00523   int ret = -1;
00524 
00525   memset (&db, 0, sizeof (db));
00526   oc = lookup_option (&server_universe, options, option_name);
00527   if (oc &&
00528       evaluate_option_cache (&db, (struct packet*) NULL,
00529                              (struct lease *) NULL,
00530                              (struct client_state *) NULL, options,
00531                              (struct option_state *) NULL,
00532                              &global_scope, oc, MDL) &&
00533       db.data != NULL && *db.data != '\0')
00534     {
00535       if (db.len == 1) 
00536         ret = db.data [0];
00537       else
00538         log_fatal ("invalid option name %d", option_name);
00539 
00540       data_string_forget (&db, MDL);
00541     }
00542   else
00543     ret = 0;
00544 
00545   return (ret);
00546 }
00547 
00548 int
00549 ldap_rebind_cb (LDAP *ld, LDAP_CONST char *url, ber_tag_t request, ber_int_t msgid, void *parms)
00550 {
00551   int ret;
00552   LDAPURLDesc *ldapurl = NULL;
00553   char *who = NULL;
00554   struct berval creds;
00555 
00556   log_info("LDAP rebind to '%s'", url);
00557   if ((ret = ldap_url_parse(url, &ldapurl)) != LDAP_SUCCESS)
00558     {
00559       log_error ("Error: Can not parse ldap rebind url '%s': %s",
00560                  url, ldap_err2string(ret));
00561       return ret;
00562     }
00563 
00564 
00565 #if defined (LDAP_USE_SSL)
00566   if (strcasecmp(ldapurl->lud_scheme, "ldaps") == 0)
00567     {
00568       int opt = LDAP_OPT_X_TLS_HARD;
00569       if ((ret = ldap_set_option (ld, LDAP_OPT_X_TLS, &opt)) != LDAP_SUCCESS)
00570         {
00571           log_error ("Error: Cannot init LDAPS session to %s:%d: %s",
00572                     ldapurl->lud_host, ldapurl->lud_port, ldap_err2string (ret));
00573           return ret;
00574         }
00575       else
00576         {
00577           log_info ("LDAPS session successfully enabled to %s", ldap_server);
00578         }
00579     }
00580   else
00581   if (strcasecmp(ldapurl->lud_scheme, "ldap") == 0 &&
00582       ldap_use_ssl != LDAP_SSL_OFF)
00583     {
00584       if ((ret = ldap_start_tls_s (ld, NULL, NULL)) != LDAP_SUCCESS)
00585         {
00586           log_error ("Error: Cannot start TLS session to %s:%d: %s",
00587                      ldapurl->lud_host, ldapurl->lud_port, ldap_err2string (ret));
00588           return ret;
00589         }
00590       else
00591         {
00592           log_info ("TLS session successfully started to %s:%d",
00593                     ldapurl->lud_host, ldapurl->lud_port);
00594         }
00595     }
00596 #endif
00597 
00598 
00599   if (ldap_username != NULL || *ldap_username != '\0')
00600     {
00601       who = ldap_username;
00602       creds.bv_val = strdup(ldap_password);
00603       creds.bv_len = strlen(ldap_password);
00604     }
00605 
00606   if ((ret = ldap_sasl_bind_s (ld, who, LDAP_SASL_SIMPLE, &creds,
00607                                NULL, NULL, NULL)) != LDAP_SUCCESS)
00608     {
00609       log_error ("Error: Cannot login into ldap server %s:%d: %s",
00610                  ldapurl->lud_host, ldapurl->lud_port, ldap_err2string (ret));
00611     }
00612   return ret;
00613 }
00614 
00615 static void
00616 ldap_start (void)
00617 {
00618   struct option_state *options;
00619   int ret, version;
00620   char *uri = NULL;
00621   struct berval creds;
00622 
00623   if (ld != NULL)
00624     return;
00625 
00626   if (ldap_server == NULL)
00627     {
00628       options = NULL;
00629       option_state_allocate (&options, MDL);
00630 
00631       execute_statements_in_scope (NULL, NULL, NULL, NULL, NULL,
00632                                    options, &global_scope, root_group,
00633                                    NULL, NULL);
00634 
00635       ldap_server = _do_lookup_dhcp_string_option (options, SV_LDAP_SERVER);
00636       ldap_dhcp_server_cn = _do_lookup_dhcp_string_option (options,
00637                                                       SV_LDAP_DHCP_SERVER_CN);
00638       ldap_port = _do_lookup_dhcp_int_option (options, SV_LDAP_PORT);
00639       ldap_base_dn = _do_lookup_dhcp_string_option (options, SV_LDAP_BASE_DN);
00640       ldap_method = _do_lookup_dhcp_enum_option (options, SV_LDAP_METHOD);
00641       ldap_debug_file = _do_lookup_dhcp_string_option (options,
00642                                                        SV_LDAP_DEBUG_FILE);
00643       ldap_referrals = _do_lookup_dhcp_enum_option (options, SV_LDAP_REFERRALS);
00644 
00645 #if defined (LDAP_USE_SSL)
00646       ldap_use_ssl = _do_lookup_dhcp_enum_option (options, SV_LDAP_SSL);
00647       if( ldap_use_ssl != LDAP_SSL_OFF)
00648         {
00649           ldap_tls_reqcert = _do_lookup_dhcp_enum_option (options, SV_LDAP_TLS_REQCERT);
00650           ldap_tls_ca_file = _do_lookup_dhcp_string_option (options, SV_LDAP_TLS_CA_FILE);
00651           ldap_tls_ca_dir = _do_lookup_dhcp_string_option (options, SV_LDAP_TLS_CA_DIR);
00652           ldap_tls_cert = _do_lookup_dhcp_string_option (options, SV_LDAP_TLS_CERT);
00653           ldap_tls_key = _do_lookup_dhcp_string_option (options, SV_LDAP_TLS_KEY);
00654           ldap_tls_crlcheck = _do_lookup_dhcp_enum_option (options, SV_LDAP_TLS_CRLCHECK);
00655           ldap_tls_ciphers = _do_lookup_dhcp_string_option (options, SV_LDAP_TLS_CIPHERS);
00656           ldap_tls_randfile = _do_lookup_dhcp_string_option (options, SV_LDAP_TLS_RANDFILE);
00657         }
00658 #endif
00659 
00660 #if defined (LDAP_CASA_AUTH)
00661       if (!load_uname_pwd_from_miCASA(&ldap_username,&ldap_password))
00662         {
00663 #if defined (DEBUG_LDAP)
00664           log_info ("Authentication credential taken from file");
00665 #endif
00666 #endif
00667 
00668       ldap_username = _do_lookup_dhcp_string_option (options, SV_LDAP_USERNAME);
00669       ldap_password = _do_lookup_dhcp_string_option (options, SV_LDAP_PASSWORD);
00670 
00671 #if defined (LDAP_CASA_AUTH)
00672       }
00673 #endif
00674 
00675       option_state_dereference (&options, MDL);
00676     }
00677 
00678   if (ldap_server == NULL || ldap_base_dn == NULL)
00679     {
00680       log_info ("Not searching LDAP since ldap-server, ldap-port and ldap-base-dn were not specified in the config file");
00681       ldap_method = LDAP_METHOD_STATIC;
00682       return;
00683     }
00684 
00685   if (ldap_debug_file != NULL && ldap_debug_fd == -1)
00686     {
00687       if ((ldap_debug_fd = open (ldap_debug_file, O_CREAT | O_TRUNC | O_WRONLY | O_CLOEXEC,
00688                                  S_IRUSR | S_IWUSR)) < 0)
00689         log_error ("Error opening debug LDAP log file %s: %s", ldap_debug_file,
00690                    strerror (errno));
00691     }
00692 
00693 #if defined (DEBUG_LDAP)
00694   log_info ("Connecting to LDAP server %s:%d", ldap_server, ldap_port);
00695 #endif
00696 
00697 #if defined (LDAP_USE_SSL)
00698   if (ldap_use_ssl == -1)
00699     {
00700       /*
00701       ** There was no "ldap-ssl" option in dhcpd.conf (also not "off").
00702       ** Let's try, if we can use an anonymous TLS session without to
00703       ** verify the server certificate -- if not continue without TLS.
00704       */
00705       int opt = LDAP_OPT_X_TLS_ALLOW;
00706       if ((ret = ldap_set_option (NULL, LDAP_OPT_X_TLS_REQUIRE_CERT,
00707                                   &opt)) != LDAP_SUCCESS)
00708         {
00709           log_error ("Warning: Cannot set LDAP TLS require cert option to 'allow': %s",
00710                      ldap_err2string (ret));
00711         }
00712     }
00713 
00714   if (ldap_use_ssl != LDAP_SSL_OFF)
00715     {
00716       if (ldap_tls_reqcert != -1)
00717         {
00718           if ((ret = ldap_set_option (NULL, LDAP_OPT_X_TLS_REQUIRE_CERT,
00719                                       &ldap_tls_reqcert)) != LDAP_SUCCESS)
00720             {
00721               log_error ("Cannot set LDAP TLS require cert option: %s",
00722                          ldap_err2string (ret));
00723             }
00724         }
00725 
00726       if( ldap_tls_ca_file != NULL)
00727         {
00728           if ((ret = ldap_set_option (NULL, LDAP_OPT_X_TLS_CACERTFILE,
00729                                       ldap_tls_ca_file)) != LDAP_SUCCESS)
00730             {
00731               log_error ("Cannot set LDAP TLS CA certificate file %s: %s",
00732                          ldap_tls_ca_file, ldap_err2string (ret));
00733             }
00734         }
00735       if( ldap_tls_ca_dir != NULL)
00736         {
00737           if ((ret = ldap_set_option (NULL, LDAP_OPT_X_TLS_CACERTDIR,
00738                                       ldap_tls_ca_dir)) != LDAP_SUCCESS)
00739             {
00740               log_error ("Cannot set LDAP TLS CA certificate dir %s: %s",
00741                          ldap_tls_ca_dir, ldap_err2string (ret));
00742             }
00743         }
00744       if( ldap_tls_cert != NULL)
00745         {
00746           if ((ret = ldap_set_option (NULL, LDAP_OPT_X_TLS_CERTFILE,
00747                                       ldap_tls_cert)) != LDAP_SUCCESS)
00748             {
00749               log_error ("Cannot set LDAP TLS client certificate file %s: %s",
00750                          ldap_tls_cert, ldap_err2string (ret));
00751             }
00752         }
00753       if( ldap_tls_key != NULL)
00754         {
00755           if ((ret = ldap_set_option (NULL, LDAP_OPT_X_TLS_KEYFILE,
00756                                       ldap_tls_key)) != LDAP_SUCCESS)
00757             {
00758               log_error ("Cannot set LDAP TLS certificate key file %s: %s",
00759                          ldap_tls_key, ldap_err2string (ret));
00760             }
00761         }
00762       if( ldap_tls_crlcheck != -1)
00763         {
00764           int opt = ldap_tls_crlcheck;
00765           if ((ret = ldap_set_option (NULL, LDAP_OPT_X_TLS_CRLCHECK,
00766                                       &opt)) != LDAP_SUCCESS)
00767             {
00768               log_error ("Cannot set LDAP TLS crl check option: %s",
00769                          ldap_err2string (ret));
00770             }
00771         }
00772       if( ldap_tls_ciphers != NULL)
00773         {
00774           if ((ret = ldap_set_option (NULL, LDAP_OPT_X_TLS_CIPHER_SUITE,
00775                                       ldap_tls_ciphers)) != LDAP_SUCCESS)
00776             {
00777               log_error ("Cannot set LDAP TLS cipher suite %s: %s",
00778                          ldap_tls_ciphers, ldap_err2string (ret));
00779             }
00780         }
00781       if( ldap_tls_randfile != NULL)
00782         {
00783           if ((ret = ldap_set_option (NULL, LDAP_OPT_X_TLS_RANDOM_FILE,
00784                                       ldap_tls_randfile)) != LDAP_SUCCESS)
00785             {
00786               log_error ("Cannot set LDAP TLS random file %s: %s",
00787                          ldap_tls_randfile, ldap_err2string (ret));
00788             }
00789         }
00790     }
00791 #endif
00792 
00793   /* enough for 'ldap://+ + hostname + ':' + port number */
00794   uri = malloc(strlen(ldap_server) + 16);
00795   if (uri == NULL)
00796     {
00797       log_error ("Cannot build ldap init URI %s:%d", ldap_server, ldap_port);
00798       return;
00799     }
00800 
00801   sprintf(uri, "ldap://%s:%d", ldap_server, ldap_port);
00802   ldap_initialize(&ld, uri);
00803 
00804   if (ld == NULL)
00805     {
00806       log_error ("Cannot init ldap session to %s:%d", ldap_server, ldap_port);
00807       return;
00808     }
00809 
00810   free(uri);
00811 
00812   version = LDAP_VERSION3;
00813   if ((ret = ldap_set_option (ld, LDAP_OPT_PROTOCOL_VERSION, &version)) != LDAP_OPT_SUCCESS)
00814     {
00815       log_error ("Cannot set LDAP version to %d: %s", version,
00816                  ldap_err2string (ret));
00817     }
00818 
00819   if (ldap_referrals != -1)
00820     {
00821       if ((ret = ldap_set_option (ld, LDAP_OPT_REFERRALS, ldap_referrals ?
00822                                   LDAP_OPT_ON : LDAP_OPT_OFF)) != LDAP_OPT_SUCCESS)
00823         {
00824           log_error ("Cannot %s LDAP referrals option: %s",
00825                      (ldap_referrals ? "enable" : "disable"),
00826                      ldap_err2string (ret));
00827         }
00828     }
00829 
00830   if ((ret = ldap_set_rebind_proc(ld, ldap_rebind_cb, NULL)) != LDAP_SUCCESS)
00831     {
00832       log_error ("Warning: Cannot set ldap rebind procedure: %s",
00833                  ldap_err2string (ret));
00834     }
00835 
00836 #if defined (LDAP_USE_SSL)
00837   if (ldap_use_ssl == LDAP_SSL_LDAPS ||
00838      (ldap_use_ssl == LDAP_SSL_ON && ldap_port == LDAPS_PORT))
00839     {
00840       int opt = LDAP_OPT_X_TLS_HARD;
00841       if ((ret = ldap_set_option (ld, LDAP_OPT_X_TLS, &opt)) != LDAP_SUCCESS)
00842         {
00843           log_error ("Error: Cannot init LDAPS session to %s:%d: %s",
00844                     ldap_server, ldap_port, ldap_err2string (ret));
00845           ldap_stop();
00846           return;
00847         }
00848       else
00849         {
00850           log_info ("LDAPS session successfully enabled to %s:%d",
00851                     ldap_server, ldap_port);
00852         }
00853     }
00854   else if (ldap_use_ssl != LDAP_SSL_OFF)
00855     {
00856       if ((ret = ldap_start_tls_s (ld, NULL, NULL)) != LDAP_SUCCESS)
00857         {
00858           log_error ("Error: Cannot start TLS session to %s:%d: %s",
00859                      ldap_server, ldap_port, ldap_err2string (ret));
00860           ldap_stop();
00861           return;
00862         }
00863       else
00864         {
00865           log_info ("TLS session successfully started to %s:%d",
00866                     ldap_server, ldap_port);
00867         }
00868     }
00869 #endif
00870 
00871   if (ldap_username != NULL && *ldap_username != '\0')
00872     {
00873       creds.bv_val = strdup(ldap_password);
00874       creds.bv_len = strlen(ldap_password);
00875 
00876       if ((ret = ldap_sasl_bind_s (ld, ldap_username, LDAP_SASL_SIMPLE,
00877                                    &creds, NULL, NULL, NULL)) != LDAP_SUCCESS)
00878         {
00879           log_error ("Error: Cannot login into ldap server %s:%d: %s",
00880                      ldap_server, ldap_port, ldap_err2string (ret));
00881           ldap_stop();
00882           return;
00883         }
00884     }
00885 
00886 #if defined (DEBUG_LDAP)
00887   log_info ("Successfully logged into LDAP server %s", ldap_server);
00888 #endif
00889 }
00890 
00891 
00892 static void
00893 parse_external_dns (LDAPMessage * ent)
00894 {
00895   char *search[] = {"dhcpFailOverPeerDN", "dhcpOptionsDN", "dhcpSharedNetworkDN", "dhcpSubnetDN",
00896                     "dhcpGroupDN", "dhcpHostDN", "dhcpClassesDN",
00897                     "dhcpPoolDN", NULL};
00898   LDAPMessage * newres, * newent;
00899   struct berval **tempbv;
00900   int i, j, ret;
00901 #if defined (DEBUG_LDAP)
00902   char *dn;
00903 
00904   dn = ldap_get_dn (ld, ent);
00905   if (dn != NULL)
00906     {
00907       log_info ("Parsing external DNs for '%s'", dn);
00908       ldap_memfree (dn);
00909     }
00910 #endif
00911 
00912   if (ld == NULL)
00913     ldap_start ();
00914   if (ld == NULL)
00915     return;
00916 
00917   for (i=0; search[i] != NULL; i++)
00918     {
00919       if ((tempbv = ldap_get_values_len (ld, ent, search[i])) == NULL)
00920         continue;
00921 
00922       for (j=0; tempbv[j] != NULL; j++)
00923         {
00924           if (*tempbv[j]->bv_val == '\0')
00925             continue;
00926 
00927           if ((ret = ldap_search_ext_s(ld, tempbv[j]->bv_val, LDAP_SCOPE_BASE,
00928                                        "objectClass=*", NULL, 0, NULL,
00929                                        NULL, NULL, 0, &newres)) != LDAP_SUCCESS)
00930             {
00931               ldap_value_free_len (tempbv);
00932               ldap_stop();
00933               return;
00934             }
00935     
00936 #if defined (DEBUG_LDAP)
00937           log_info ("Adding contents of subtree '%s' to config stack from '%s' reference", tempbv[j], search[i]);
00938 #endif
00939           for (newent = ldap_first_entry (ld, newres);
00940                newent != NULL;
00941                newent = ldap_next_entry (ld, newent))
00942             {
00943 #if defined (DEBUG_LDAP)
00944               dn = ldap_get_dn (ld, newent);
00945               if (dn != NULL)
00946                 {
00947                   log_info ("Adding LDAP result set starting with '%s' to config stack", dn);
00948                   ldap_memfree (dn);
00949                 }
00950 #endif
00951 
00952               add_to_config_stack (newres, newent);
00953               /* don't free newres here */
00954             }
00955         }
00956 
00957       ldap_value_free_len (tempbv);
00958     }
00959 }
00960 
00961 
00962 static void
00963 free_stack_entry (struct ldap_config_stack *item)
00964 {
00965   struct ldap_config_stack *look_ahead_pointer = item;
00966   int may_free_msg = 1;
00967 
00968   while (look_ahead_pointer->next != NULL)
00969     {
00970       look_ahead_pointer = look_ahead_pointer->next;
00971       if (look_ahead_pointer->res == item->res)
00972         {
00973           may_free_msg = 0;
00974           break;
00975         }
00976     }
00977 
00978   if (may_free_msg) 
00979     ldap_msgfree (item->res);
00980 
00981   dfree (item, MDL);
00982 }
00983 
00984 
00985 static void
00986 next_ldap_entry (struct parse *cfile)
00987 {
00988   struct ldap_config_stack *temp_stack;
00989 
00990   if (ldap_stack != NULL && ldap_stack->close_brace)
00991     {
00992       x_strncat (cfile->inbuf, "}\n", LDAP_BUFFER_SIZE);
00993       ldap_stack->close_brace = 0;
00994     }
00995 
00996   while (ldap_stack != NULL && 
00997          (ldap_stack->ldent == NULL ||
00998           (ldap_stack->ldent = ldap_next_entry (ld, ldap_stack->ldent)) == NULL))
00999     {
01000       if (ldap_stack->close_brace)
01001         {
01002           x_strncat (cfile->inbuf, "}\n", LDAP_BUFFER_SIZE);
01003           ldap_stack->close_brace = 0;
01004         }
01005 
01006       temp_stack = ldap_stack;
01007       ldap_stack = ldap_stack->next;
01008       free_stack_entry (temp_stack);
01009     }
01010 
01011   if (ldap_stack != NULL && ldap_stack->close_brace)
01012     {
01013       x_strncat (cfile->inbuf, "}\n", LDAP_BUFFER_SIZE);
01014       ldap_stack->close_brace = 0;
01015     }
01016 }
01017 
01018 
01019 static char
01020 check_statement_end (const char *statement)
01021 {
01022   char *ptr;
01023 
01024   if (statement == NULL || *statement == '\0')
01025     return ('\0');
01026 
01027   /*
01028   ** check if it ends with "}", e.g.:
01029   **   "zone my.domain. { ... }"
01030   ** optionally followed by spaces
01031   */
01032   ptr = strrchr (statement, '}');
01033   if (ptr != NULL)
01034     {
01035       /* skip following white-spaces */
01036       for (++ptr; isspace ((int)*ptr); ptr++);
01037 
01038       /* check if we reached the end */
01039       if (*ptr == '\0')
01040         return ('}'); /* yes, block end */
01041       else
01042         return (*ptr);
01043     }
01044 
01045   /*
01046   ** this should not happen, but...
01047   ** check if it ends with ";", e.g.:
01048   **   "authoritative;"
01049   ** optionally followed by spaces
01050   */
01051   ptr = strrchr (statement, ';');
01052   if (ptr != NULL)
01053     {
01054       /* skip following white-spaces */
01055       for (++ptr; isspace ((int)*ptr); ptr++);
01056 
01057       /* check if we reached the end */
01058       if (*ptr == '\0')
01059         return (';'); /* ends with a ; */
01060       else
01061         return (*ptr);
01062     }
01063 
01064   return ('\0');
01065 }
01066 
01067 
01068 static isc_result_t
01069 ldap_parse_entry_options (LDAPMessage *ent, char *buffer, size_t size,
01070                           int *lease_limit)
01071 {
01072   struct berval **tempbv;
01073   int i;
01074 
01075   if (ent == NULL || buffer == NULL || size == 0)
01076     return (ISC_R_FAILURE);
01077 
01078   if ((tempbv = ldap_get_values_len (ld, ent, "dhcpStatements")) != NULL)
01079     {
01080       for (i=0; tempbv[i] != NULL; i++)
01081         {
01082           if (lease_limit != NULL &&
01083               strncasecmp ("lease limit ", tempbv[i]->bv_val, 12) == 0)
01084             {
01085               *lease_limit = (int) strtol ((tempbv[i]->bv_val) + 12, NULL, 10);
01086               continue;
01087             }
01088 
01089           x_strncat (buffer, tempbv[i]->bv_val, size);
01090 
01091           switch((int) check_statement_end (tempbv[i]->bv_val))
01092             {
01093               case '}':
01094               case ';':
01095                 x_strncat (buffer, "\n", size);
01096                 break;
01097               default:
01098                 x_strncat (buffer, ";\n", size);
01099                 break;
01100             }
01101         }
01102       ldap_value_free_len (tempbv);
01103     }
01104 
01105   if ((tempbv = ldap_get_values_len (ld, ent, "dhcpOption")) != NULL)
01106     {
01107       for (i=0; tempbv[i] != NULL; i++)
01108         {
01109           x_strncat (buffer, "option ", size);
01110           x_strncat (buffer, tempbv[i]->bv_val, size);
01111           switch ((int) check_statement_end (tempbv[i]->bv_val))
01112             {
01113               case ';':
01114                 x_strncat (buffer, "\n", size);
01115                 break;
01116               default:
01117                 x_strncat (buffer, ";\n", size);
01118                 break;
01119             }
01120         }
01121       ldap_value_free_len (tempbv);
01122     }
01123 
01124   return (ISC_R_SUCCESS);
01125 }
01126 
01127 
01128 static void
01129 ldap_generate_config_string (struct parse *cfile)
01130 {
01131   struct berval **objectClass;
01132   char *dn;
01133   struct ldap_config_stack *entry;
01134   LDAPMessage * ent, * res;
01135   int i, ignore, found;
01136   int ret;
01137 
01138   if (ld == NULL)
01139     ldap_start ();
01140   if (ld == NULL)
01141     return;
01142 
01143   entry = ldap_stack;
01144   if ((objectClass = ldap_get_values_len (ld, entry->ldent, 
01145                                       "objectClass")) == NULL)
01146     return;
01147     
01148   ignore = 0;
01149   found = 1;
01150   for (i=0; objectClass[i] != NULL; i++)
01151     {
01152       if (strcasecmp (objectClass[i]->bv_val, "dhcpSharedNetwork") == 0)
01153         ldap_parse_shared_network (entry, cfile);
01154       else if (strcasecmp (objectClass[i]->bv_val, "dhcpClass") == 0)
01155         ldap_parse_class (entry, cfile);
01156       else if (strcasecmp (objectClass[i]->bv_val, "dhcpSubnet") == 0)
01157         ldap_parse_subnet (entry, cfile);
01158       else if (strcasecmp (objectClass[i]->bv_val, "dhcpPool") == 0)
01159         ldap_parse_pool (entry, cfile);
01160       else if (strcasecmp (objectClass[i]->bv_val, "dhcpGroup") == 0)
01161         ldap_parse_group (entry, cfile);
01162       else if (strcasecmp (objectClass[i]->bv_val, "dhcpTSigKey") == 0)
01163         ldap_parse_key (entry, cfile);
01164       else if (strcasecmp (objectClass[i]->bv_val, "dhcpDnsZone") == 0)
01165         ldap_parse_zone (entry, cfile);
01166       else if (strcasecmp (objectClass[i]->bv_val, "dhcpHost") == 0)
01167         {
01168           if (ldap_method == LDAP_METHOD_STATIC)
01169             ldap_parse_host (entry, cfile);
01170           else
01171             {
01172               ignore = 1;
01173               break;
01174             }
01175         }
01176       else if (strcasecmp (objectClass[i]->bv_val, "dhcpSubClass") == 0)
01177         {
01178           if (ldap_method == LDAP_METHOD_STATIC)
01179             ldap_parse_subclass (entry, cfile);
01180           else
01181             {
01182               ignore = 1;
01183               break;
01184             }
01185         }
01186       else
01187         found = 0;
01188 
01189       if (found && cfile->inbuf[0] == '\0')
01190         {
01191           ignore = 1;
01192           break;
01193         }
01194     }
01195 
01196   ldap_value_free_len (objectClass);
01197 
01198   if (ignore)
01199     {
01200       next_ldap_entry (cfile);
01201       return;
01202     }
01203 
01204   ldap_parse_entry_options(entry->ldent, cfile->inbuf,
01205                            LDAP_BUFFER_SIZE-1, NULL);
01206 
01207   dn = ldap_get_dn (ld, entry->ldent);
01208 
01209 #if defined(DEBUG_LDAP)
01210   if (dn != NULL)
01211     log_info ("Found LDAP entry '%s'", dn);
01212 #endif
01213 
01214   if (dn == NULL ||
01215       (ret = ldap_search_ext_s (ld, dn, LDAP_SCOPE_ONELEVEL,
01216                                 "objectClass=*", NULL, 0, NULL, NULL,
01217                                 NULL, 0, &res)) != LDAP_SUCCESS)
01218     {
01219       if (dn)
01220         ldap_memfree (dn);
01221 
01222       ldap_stop();
01223       return;
01224     }
01225 
01226   ldap_memfree (dn);
01227 
01228   if ((ent = ldap_first_entry (ld, res)) != NULL)
01229     {
01230       add_to_config_stack (res, ent);
01231       parse_external_dns (entry->ldent);
01232     }
01233   else
01234     {
01235       ldap_msgfree (res);
01236       parse_external_dns (entry->ldent);
01237       next_ldap_entry (cfile);
01238     }
01239 }
01240 
01241 
01242 static void
01243 ldap_close_debug_fd()
01244 {
01245   if (ldap_debug_fd != -1)
01246     {
01247       close (ldap_debug_fd);
01248       ldap_debug_fd = -1;
01249     }
01250 }
01251 
01252 
01253 static void
01254 ldap_write_debug (const void *buff, size_t size)
01255 {
01256   if (ldap_debug_fd != -1)
01257     {
01258       if (write (ldap_debug_fd, buff, size) < 0)
01259         {
01260           log_error ("Error writing to LDAP debug file %s: %s."
01261                      " Disabling log file.", ldap_debug_file,
01262                      strerror (errno));
01263           ldap_close_debug_fd();
01264         }
01265     }
01266 }
01267 
01268 static int
01269 ldap_read_function (struct parse *cfile)
01270 {
01271   cfile->inbuf[0] = '\0';
01272   cfile->buflen = 0;
01273  
01274   while (ldap_stack != NULL && *cfile->inbuf == '\0')
01275     ldap_generate_config_string (cfile);
01276 
01277   if (ldap_stack == NULL && *cfile->inbuf == '\0')
01278     return (EOF);
01279 
01280   cfile->bufix = 1;
01281   cfile->buflen = strlen (cfile->inbuf) - 1;
01282   if (cfile->buflen > 0)
01283     ldap_write_debug (cfile->inbuf, cfile->buflen);
01284 
01285 #if defined (DEBUG_LDAP)
01286   log_info ("Sending config line '%s'", cfile->inbuf);
01287 #endif
01288 
01289   return (cfile->inbuf[0]);
01290 }
01291 
01292 
01293 static char *
01294 ldap_get_host_name (LDAPMessage * ent)
01295 {
01296   struct berval **name;
01297   char *ret;
01298 
01299   ret = NULL;
01300   if ((name = ldap_get_values_len (ld, ent, "cn")) == NULL || name[0] == NULL)
01301     {
01302       if (name != NULL)
01303         ldap_value_free_len (name);
01304 
01305 #if defined (DEBUG_LDAP)
01306       ret = ldap_get_dn (ld, ent);
01307       if (ret != NULL)
01308         {
01309           log_info ("Cannot get cn attribute for LDAP entry %s", ret);
01310           ldap_memfree(ret);
01311         }
01312 #endif
01313       return (NULL);
01314     }
01315 
01316   ret = dmalloc (strlen (name[0]->bv_val) + 1, MDL);
01317   strcpy (ret, name[0]->bv_val);
01318   ldap_value_free_len (name);
01319 
01320   return (ret);
01321 }
01322 
01323 
01324 static int
01325 getfqhostname(char *fqhost, size_t size)
01326 {
01327 #if defined(MAXHOSTNAMELEN)
01328   char   hname[MAXHOSTNAMELEN];
01329 #else
01330   char   hname[65];
01331 #endif
01332   struct hostent *hp;
01333 
01334   if(NULL == fqhost || 1 >= size)
01335     return -1;
01336 
01337   memset(hname, 0, sizeof(hname));
01338   if( gethostname(hname, sizeof(hname)-1))
01339     return -1;
01340 
01341   if(NULL == (hp = gethostbyname(hname)))
01342     return -1;
01343 
01344   strncpy(fqhost, hp->h_name, size-1);
01345   fqhost[size-1] = '\0';
01346   return 0;
01347 }
01348 
01349 
01350 isc_result_t
01351 ldap_read_config (void)
01352 {
01353   LDAPMessage * ldres, * hostres, * ent, * hostent;
01354   char hfilter[1024], sfilter[1024], fqdn[257];
01355   char *buffer, *hostdn;
01356   ldap_dn_node *curr = NULL;
01357   struct parse *cfile;
01358   struct utsname unme;
01359   isc_result_t res;
01360   size_t length;
01361   int ret, cnt;
01362   struct berval **tempbv = NULL;
01363 
01364   if (ld == NULL)
01365     ldap_start ();
01366   if (ld == NULL)
01367     return (ldap_server == NULL ? ISC_R_SUCCESS : ISC_R_FAILURE);
01368  
01369   buffer = dmalloc (LDAP_BUFFER_SIZE+1, MDL);
01370   if (buffer == NULL)
01371     return (ISC_R_FAILURE);
01372 
01373   cfile = (struct parse *) NULL;
01374   res = new_parse (&cfile, -1, buffer, LDAP_BUFFER_SIZE, "LDAP", 0);
01375   if (res != ISC_R_SUCCESS)
01376     return (res);
01377  
01378   uname (&unme);
01379   if (ldap_dhcp_server_cn != NULL)
01380     {
01381      snprintf (hfilter, sizeof (hfilter),
01382                 "(&(objectClass=dhcpServer)(cn=%s))", ldap_dhcp_server_cn);
01383     }
01384   else
01385   {
01386   if(0 == getfqhostname(fqdn, sizeof(fqdn)))
01387     {
01388       snprintf (hfilter, sizeof (hfilter),
01389                 "(&(objectClass=dhcpServer)(|(cn=%s)(cn=%s)))", 
01390                 unme.nodename, fqdn);
01391     }
01392   else
01393     {
01394       snprintf (hfilter, sizeof (hfilter),
01395                 "(&(objectClass=dhcpServer)(cn=%s))", unme.nodename);
01396     }
01397 
01398   }
01399   hostres = NULL;
01400   if ((ret = ldap_search_ext_s (ld, ldap_base_dn, LDAP_SCOPE_SUBTREE,
01401                                 hfilter, NULL, 0, NULL, NULL, NULL, 0,
01402                                 &hostres)) != LDAP_SUCCESS)
01403     {
01404       log_error ("Cannot find host LDAP entry %s %s",
01405                  ((ldap_dhcp_server_cn == NULL)?(unme.nodename):(ldap_dhcp_server_cn)), hfilter);
01406       if(NULL != hostres)
01407         ldap_msgfree (hostres);
01408       ldap_stop();
01409       return (ISC_R_FAILURE);
01410     }
01411 
01412   if ((hostent = ldap_first_entry (ld, hostres)) == NULL)
01413     {
01414       log_error ("Error: Cannot find LDAP entry matching %s", hfilter);
01415       ldap_msgfree (hostres);
01416       ldap_stop();
01417       return (ISC_R_FAILURE);
01418     }
01419 
01420   hostdn = ldap_get_dn (ld, hostent);
01421 #if defined(DEBUG_LDAP)
01422   if (hostdn != NULL)
01423     log_info ("Found dhcpServer LDAP entry '%s'", hostdn);
01424 #endif
01425 
01426   if (hostdn == NULL ||
01427       (tempbv = ldap_get_values_len (ld, hostent, "dhcpServiceDN")) == NULL ||
01428       tempbv[0] == NULL)
01429     {
01430       log_error ("Error: Cannot find LDAP entry matching %s", hfilter);
01431 
01432       if (tempbv != NULL)
01433         ldap_value_free_len (tempbv);
01434 
01435       if (hostdn)
01436         ldap_memfree (hostdn);
01437       ldap_msgfree (hostres);
01438       ldap_stop();
01439       return (ISC_R_FAILURE);
01440     }
01441 
01442 #if defined(DEBUG_LDAP)
01443   log_info ("LDAP: Parsing dhcpServer options '%s' ...", hostdn);
01444 #endif
01445 
01446   cfile->inbuf[0] = '\0';
01447   ldap_parse_entry_options(hostent, cfile->inbuf, LDAP_BUFFER_SIZE, NULL);
01448   cfile->buflen = strlen (cfile->inbuf);
01449   if(cfile->buflen > 0)
01450     {
01451       ldap_write_debug (cfile->inbuf, cfile->buflen);
01452 
01453       res = conf_file_subparse (cfile, root_group, ROOT_GROUP);
01454       if (res != ISC_R_SUCCESS)
01455         {
01456           log_error ("LDAP: cannot parse dhcpServer entry '%s'", hostdn);
01457           ldap_memfree (hostdn);
01458           ldap_stop();
01459           return res;
01460         }
01461       cfile->inbuf[0] = '\0';
01462     }
01463   ldap_msgfree (hostres);
01464 
01465   /*
01466   ** attach ldap (tree) read function now
01467   */
01468   cfile->bufix = cfile->buflen = 0;
01469   cfile->read_function = ldap_read_function;
01470 
01471   res = ISC_R_SUCCESS;
01472   for (cnt=0; tempbv[cnt] != NULL; cnt++)
01473     {
01474       snprintf(sfilter, sizeof(sfilter), "(&(objectClass=dhcpService)"
01475                         "(|(dhcpPrimaryDN=%s)(dhcpSecondaryDN=%s)))",
01476                         hostdn, hostdn);
01477       ldres = NULL;
01478       if ((ret = ldap_search_ext_s (ld, tempbv[cnt]->bv_val, LDAP_SCOPE_BASE,
01479                                     sfilter, NULL, 0, NULL, NULL, NULL,
01480                                     0, &ldres)) != LDAP_SUCCESS)
01481         {
01482           log_error ("Error searching for dhcpServiceDN '%s': %s. Please update the LDAP entry '%s'",
01483                      tempbv[cnt]->bv_val, ldap_err2string (ret), hostdn);
01484           if(NULL != ldres)
01485             ldap_msgfree(ldres);
01486           res = ISC_R_FAILURE;
01487           break;
01488         }
01489 
01490       if ((ent = ldap_first_entry (ld, ldres)) == NULL)
01491         {
01492           log_error ("Error: Cannot find dhcpService DN '%s' with primary or secondary server reference. Please update the LDAP server entry '%s'",
01493                      tempbv[cnt]->bv_val, hostdn);
01494 
01495           ldap_msgfree(ldres);
01496           res = ISC_R_FAILURE;
01497           break;
01498         }
01499 
01500       /*
01501       ** FIXME: how to free the remembered dn's on exit?
01502       **        This should be OK if dmalloc registers the
01503       **        memory it allocated and frees it on exit..
01504       */
01505 
01506       curr = dmalloc (sizeof (*curr), MDL);
01507       if (curr != NULL)
01508         {
01509           length = strlen (tempbv[cnt]->bv_val);
01510           curr->dn = dmalloc (length + 1, MDL);
01511           if (curr->dn == NULL)
01512             {
01513               dfree (curr, MDL);
01514               curr = NULL;
01515             }
01516           else
01517             strcpy (curr->dn, tempbv[cnt]->bv_val);
01518         }
01519 
01520       if (curr != NULL)
01521         {
01522           curr->refs++;
01523 
01524           /* append to service-dn list */
01525           if (ldap_service_dn_tail != NULL)
01526             ldap_service_dn_tail->next = curr;
01527           else
01528             ldap_service_dn_head = curr;
01529 
01530           ldap_service_dn_tail = curr;
01531         }
01532       else
01533         log_fatal ("no memory to remember ldap service dn");
01534 
01535 #if defined (DEBUG_LDAP)
01536       log_info ("LDAP: Parsing dhcpService DN '%s' ...", tempbv[cnt]);
01537 #endif
01538       add_to_config_stack (ldres, ent);
01539       res = conf_file_subparse (cfile, root_group, ROOT_GROUP);
01540       if (res != ISC_R_SUCCESS)
01541         {
01542           log_error ("LDAP: cannot parse dhcpService entry '%s'", tempbv[cnt]->bv_val);
01543           break;
01544         }
01545     }
01546 
01547   end_parse (&cfile);
01548   ldap_close_debug_fd();
01549 
01550   ldap_memfree (hostdn);
01551   ldap_value_free_len (tempbv);
01552 
01553   if (res != ISC_R_SUCCESS)
01554     {
01555       struct ldap_config_stack *temp_stack;
01556 
01557       while ((curr = ldap_service_dn_head) != NULL)
01558         {
01559           ldap_service_dn_head = curr->next;
01560           dfree (curr->dn, MDL);
01561           dfree (curr, MDL);
01562         }
01563 
01564       ldap_service_dn_tail = NULL;
01565 
01566       while ((temp_stack = ldap_stack) != NULL)
01567         {
01568           ldap_stack = temp_stack->next;
01569           free_stack_entry (temp_stack);
01570         }
01571 
01572       ldap_stop();
01573     }
01574 
01575   /* Unbind from ldap immediately after reading config in static mode. */
01576   if (ldap_method == LDAP_METHOD_STATIC)
01577     ldap_stop();
01578 
01579   return (res);
01580 }
01581 
01582 
01583 /* This function will parse the dhcpOption and dhcpStatements field in the LDAP
01584    entry if it exists. Right now, type will be either HOST_DECL or CLASS_DECL.
01585    If we are parsing a HOST_DECL, this always returns 0. If we are parsing a 
01586    CLASS_DECL, this will return what the current lease limit is in LDAP. If
01587    there is no lease limit specified, we return 0 */
01588 
01589 static int
01590 ldap_parse_options (LDAPMessage * ent, struct group *group,
01591                          int type, struct host_decl *host,
01592                          struct class **class)
01593 {
01594   int declaration, lease_limit;
01595   char option_buffer[8192];
01596   enum dhcp_token token;
01597   struct parse *cfile;
01598   isc_result_t res;
01599   const char *val;
01600 
01601   lease_limit = 0;
01602   *option_buffer = '\0';
01603  
01604  /* This block of code will try to find the parent of the host, and
01605     if it is a group object, fetch the options and apply to the host. */
01606   if (type == HOST_DECL) 
01607     {
01608       char *hostdn, *basedn, *temp1, *temp2, filter[1024];
01609       LDAPMessage *groupdn, *entry;
01610       int ret;
01611 
01612       hostdn = ldap_get_dn (ld, ent);
01613       if( hostdn != NULL)
01614         {
01615           basedn = NULL;
01616 
01617           temp1 = strchr (hostdn, '=');
01618           if (temp1 != NULL)
01619             temp1 = strchr (++temp1, '=');
01620           if (temp1 != NULL)
01621             temp2 = strchr (++temp1, ',');
01622           else
01623             temp2 = NULL;
01624 
01625           if (temp2 != NULL)
01626             {
01627               snprintf (filter, sizeof(filter),
01628                         "(&(cn=%.*s)(objectClass=dhcpGroup))",
01629                         (int)(temp2 - temp1), temp1);
01630 
01631               basedn = strchr (temp1, ',');
01632               if (basedn != NULL)
01633                 ++basedn;
01634             }
01635 
01636           if (basedn != NULL && *basedn != '\0')
01637             {
01638               ret = ldap_search_ext_s (ld, basedn, LDAP_SCOPE_SUBTREE, filter,
01639                                        NULL, 0, NULL, NULL, NULL, 0, &groupdn);
01640               if (ret == LDAP_SUCCESS)
01641                 {
01642                   if ((entry = ldap_first_entry (ld, groupdn)) != NULL)
01643                     {
01644                       res = ldap_parse_entry_options (entry, option_buffer,
01645                                                       sizeof(option_buffer) - 1,
01646                                                       &lease_limit);
01647                       if (res != ISC_R_SUCCESS)
01648                         {
01649                           /* reset option buffer discarding any results */
01650                           *option_buffer = '\0';
01651                           lease_limit = 0;
01652                         }
01653                     }
01654                   ldap_msgfree( groupdn);
01655                 }
01656             }
01657           ldap_memfree( hostdn);
01658         }
01659     }
01660 
01661   res = ldap_parse_entry_options (ent, option_buffer, sizeof(option_buffer) - 1,
01662                                   &lease_limit);
01663   if (res != ISC_R_SUCCESS)
01664     return (lease_limit);
01665 
01666   option_buffer[sizeof(option_buffer) - 1] = '\0';
01667   if (*option_buffer == '\0')
01668     return (lease_limit);
01669 
01670   cfile = (struct parse *) NULL;
01671   res = new_parse (&cfile, -1, option_buffer, strlen (option_buffer), 
01672                    type == HOST_DECL ? "LDAP-HOST" : "LDAP-SUBCLASS", 0);
01673   if (res != ISC_R_SUCCESS)
01674     return (lease_limit);
01675 
01676 #if defined (DEBUG_LDAP)
01677   log_info ("Sending the following options: '%s'", option_buffer);
01678 #endif
01679 
01680   declaration = 0;
01681   do
01682     {
01683       token = peek_token (&val, NULL, cfile);
01684       if (token == END_OF_FILE)
01685         break;
01686        declaration = parse_statement (cfile, group, type, host, declaration);
01687     } while (1);
01688 
01689   end_parse (&cfile);
01690 
01691   return (lease_limit);
01692 }
01693 
01694 
01695 
01696 int
01697 find_haddr_in_ldap (struct host_decl **hp, int htype, unsigned hlen,
01698                     const unsigned char *haddr, const char *file, int line)
01699 {
01700   char buf[128], *type_str;
01701   LDAPMessage * res, *ent;
01702   struct host_decl * host;
01703   isc_result_t status;
01704   ldap_dn_node *curr;
01705   int ret;
01706 
01707   if (ldap_method == LDAP_METHOD_STATIC)
01708     return (0);
01709 
01710   if (ld == NULL)
01711     ldap_start ();
01712   if (ld == NULL)
01713     return (0);
01714 
01715   switch (htype)
01716     {
01717       case HTYPE_ETHER:
01718         type_str = "ethernet";
01719         break;
01720       case HTYPE_IEEE802:
01721         type_str = "token-ring";
01722         break;
01723       case HTYPE_FDDI:
01724         type_str = "fddi";
01725         break;
01726       default:
01727         log_info ("Ignoring unknown type %d", htype);
01728         return (0);
01729     }
01730 
01731   /*
01732   ** FIXME: It is not guaranteed, that the dhcpHWAddress attribute
01733   **        contains _exactly_ "type addr" with one space between!
01734   */
01735   snprintf (buf, sizeof (buf),
01736             "(&(objectClass=dhcpHost)(dhcpHWAddress=%s %s))",
01737            type_str, print_hw_addr (htype, hlen, haddr));
01738 
01739   res = ent = NULL;
01740   for (curr = ldap_service_dn_head;
01741        curr != NULL && *curr->dn != '\0';
01742        curr = curr->next)
01743     {
01744 #if defined (DEBUG_LDAP)
01745       log_info ("Searching for %s in LDAP tree %s", buf, curr->dn);
01746 #endif
01747       ret = ldap_search_ext_s (ld, curr->dn, LDAP_SCOPE_SUBTREE, buf, NULL, 0,
01748                                NULL, NULL, NULL, 0, &res);
01749 
01750       if(ret == LDAP_SERVER_DOWN)
01751         {
01752           log_info ("LDAP server was down, trying to reconnect...");
01753 
01754           ldap_stop();
01755           ldap_start();
01756           if(ld == NULL)
01757             {
01758               log_info ("LDAP reconnect failed - try again later...");
01759               return (0);
01760             }
01761 
01762           ret = ldap_search_ext_s (ld, curr->dn, LDAP_SCOPE_SUBTREE, buf, NULL,
01763                                    0, NULL, NULL, NULL, 0, &res);
01764         }
01765 
01766       if (ret == LDAP_SUCCESS)
01767         {
01768           if( (ent = ldap_first_entry (ld, res)) != NULL)
01769             break; /* search OK and have entry */
01770 
01771 #if defined (DEBUG_LDAP)
01772           log_info ("No host entry for %s in LDAP tree %s",
01773                     buf, curr->dn);
01774 #endif
01775           if(res)
01776             {
01777               ldap_msgfree (res);
01778               res = NULL;
01779             }
01780         }
01781       else
01782         {
01783           if(res)
01784             {
01785               ldap_msgfree (res);
01786               res = NULL;
01787             }
01788 
01789           if (ret != LDAP_NO_SUCH_OBJECT && ret != LDAP_SUCCESS)
01790             {
01791               log_error ("Cannot search for %s in LDAP tree %s: %s", buf, 
01792                          curr->dn, ldap_err2string (ret));
01793               ldap_stop();
01794               return (0);
01795             }
01796 #if defined (DEBUG_LDAP)
01797           else
01798             {
01799               log_info ("ldap_search_ext_s returned %s when searching for %s in %s",
01800                         ldap_err2string (ret), buf, curr->dn);
01801             }
01802 #endif
01803         }
01804     }
01805 
01806   if (res && ent)
01807     {
01808 #if defined (DEBUG_LDAP)
01809       char *dn = ldap_get_dn (ld, ent);
01810       if (dn != NULL)
01811         {
01812           log_info ("Found dhcpHWAddress LDAP entry %s", dn);
01813           ldap_memfree(dn);
01814         }
01815 #endif
01816 
01817       host = (struct host_decl *)0;
01818       status = host_allocate (&host, MDL);
01819       if (status != ISC_R_SUCCESS)
01820         {
01821           log_fatal ("can't allocate host decl struct: %s", 
01822                      isc_result_totext (status)); 
01823           ldap_msgfree (res);
01824           return (0);
01825         }
01826 
01827       host->name = ldap_get_host_name (ent);
01828       if (host->name == NULL)
01829         {
01830           host_dereference (&host, MDL);
01831           ldap_msgfree (res);
01832           return (0);
01833         }
01834 
01835       if (!clone_group (&host->group, root_group, MDL))
01836         {
01837           log_fatal ("can't clone group for host %s", host->name);
01838           host_dereference (&host, MDL);
01839           ldap_msgfree (res);
01840           return (0);
01841         }
01842 
01843       ldap_parse_options (ent, host->group, HOST_DECL, host, NULL);
01844 
01845       *hp = host;
01846       ldap_msgfree (res);
01847       return (1);
01848     }
01849 
01850 
01851   if(res) ldap_msgfree (res);
01852   return (0);
01853 }
01854 
01855 
01856 int
01857 find_subclass_in_ldap (struct class *class, struct class **newclass, 
01858                        struct data_string *data)
01859 {
01860   LDAPMessage * res, * ent;
01861   int ret, lease_limit;
01862   isc_result_t status;
01863   ldap_dn_node *curr;
01864   char buf[1024];
01865 
01866   if (ldap_method == LDAP_METHOD_STATIC)
01867     return (0);
01868 
01869   if (ld == NULL)
01870     ldap_start ();
01871   if (ld == NULL)
01872     return (0);
01873 
01874   snprintf (buf, sizeof (buf),
01875             "(&(objectClass=dhcpSubClass)(cn=%s)(dhcpClassData=%s))",
01876             print_hex_1 (data->len, data->data, 60),
01877             print_hex_2 (strlen (class->name), (u_int8_t *) class->name, 60));
01878 #if defined (DEBUG_LDAP)
01879   log_info ("Searching LDAP for %s", buf);
01880 #endif
01881 
01882   res = ent = NULL;
01883   for (curr = ldap_service_dn_head;
01884        curr != NULL && *curr->dn != '\0';
01885        curr = curr->next)
01886     {
01887 #if defined (DEBUG_LDAP)
01888       log_info ("Searching for %s in LDAP tree %s", buf, curr->dn);
01889 #endif
01890       ret = ldap_search_ext_s (ld, curr->dn, LDAP_SCOPE_SUBTREE, buf, NULL, 0,
01891                                NULL, NULL, NULL, 0, &res);
01892 
01893       if(ret == LDAP_SERVER_DOWN)
01894         {
01895           log_info ("LDAP server was down, trying to reconnect...");
01896 
01897           ldap_stop();
01898           ldap_start();
01899 
01900           if(ld == NULL)
01901             {
01902               log_info ("LDAP reconnect failed - try again later...");
01903               return (0);
01904             }
01905 
01906           ret = ldap_search_ext_s (ld, curr->dn, LDAP_SCOPE_SUBTREE, buf,
01907                                    NULL, 0, NULL, NULL, NULL, 0, &res);
01908         }
01909 
01910       if (ret == LDAP_SUCCESS)
01911         {
01912           if( (ent = ldap_first_entry (ld, res)) != NULL)
01913             break; /* search OK and have entry */
01914 
01915 #if defined (DEBUG_LDAP)
01916           log_info ("No subclass entry for %s in LDAP tree %s",
01917                     buf, curr->dn);
01918 #endif
01919           if(res)
01920             {
01921               ldap_msgfree (res);
01922               res = NULL;
01923             }
01924         }
01925       else
01926         {
01927           if(res)
01928             {
01929               ldap_msgfree (res);
01930               res = NULL;
01931             }
01932 
01933           if (ret != LDAP_NO_SUCH_OBJECT && ret != LDAP_SUCCESS)
01934             {
01935               log_error ("Cannot search for %s in LDAP tree %s: %s", buf, 
01936                          curr->dn, ldap_err2string (ret));
01937               ldap_stop();
01938               return (0);
01939             }
01940 #if defined (DEBUG_LDAP)
01941           else
01942             {
01943               log_info ("ldap_search_ext_s returned %s when searching for %s in %s",
01944                         ldap_err2string (ret), buf, curr->dn);
01945             }
01946 #endif
01947         }
01948     }
01949 
01950   if (res && ent)
01951     {
01952 #if defined (DEBUG_LDAP)
01953       char *dn = ldap_get_dn (ld, ent);
01954       if (dn != NULL)
01955         {
01956           log_info ("Found subclass LDAP entry %s", dn);
01957           ldap_memfree(dn);
01958         }
01959 #endif
01960 
01961       status = class_allocate (newclass, MDL);
01962       if (status != ISC_R_SUCCESS)
01963         {
01964           log_error ("Cannot allocate memory for a new class");
01965           ldap_msgfree (res);
01966           return (0);
01967         }
01968 
01969       group_reference (&(*newclass)->group, class->group, MDL);
01970       class_reference (&(*newclass)->superclass, class, MDL);
01971       lease_limit = ldap_parse_options (ent, (*newclass)->group, 
01972                                         CLASS_DECL, NULL, newclass);
01973       if (lease_limit == 0)
01974         (*newclass)->lease_limit = class->lease_limit; 
01975       else
01976         class->lease_limit = lease_limit;
01977 
01978       if ((*newclass)->lease_limit) 
01979         {
01980           (*newclass)->billed_leases = 
01981               dmalloc ((*newclass)->lease_limit * sizeof (struct lease *), MDL);
01982           if (!(*newclass)->billed_leases) 
01983             {
01984               log_error ("no memory for billing");
01985               class_dereference (newclass, MDL);
01986               ldap_msgfree (res);
01987               return (0);
01988             }
01989           memset ((*newclass)->billed_leases, 0, 
01990                   ((*newclass)->lease_limit * sizeof (struct lease *)));
01991         }
01992 
01993       data_string_copy (&(*newclass)->hash_string, data, MDL);
01994 
01995       ldap_msgfree (res);
01996       return (1);
01997     }
01998 
01999   if(res) ldap_msgfree (res);
02000   return (0);
02001 }
02002 
02003 #endif

Generated on 5 Apr 2014 for ISC DHCP by  doxygen 1.6.1