server/confpars.c

Go to the documentation of this file.
00001 /* confpars.c
00002 
00003    Parser for dhcpd config file... */
00004 
00005 /*
00006  * Copyright (c) 2004-2014 by Internet Systems Consortium, Inc. ("ISC")
00007  * Copyright (c) 1995-2003 by Internet Software Consortium
00008  *
00009  * Permission to use, copy, modify, and distribute this software for any
00010  * purpose with or without fee is hereby granted, provided that the above
00011  * copyright notice and this permission notice appear in all copies.
00012  *
00013  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
00014  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
00015  * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
00016  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
00017  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
00018  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
00019  * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
00020  *
00021  *   Internet Systems Consortium, Inc.
00022  *   950 Charter Street
00023  *   Redwood City, CA 94063
00024  *   <info@isc.org>
00025  *   https://www.isc.org/
00026  *
00027  */
00028 
00031 #include "dhcpd.h"
00032 
00033 static unsigned char global_host_once = 1;
00034 
00035 static int parse_binding_value(struct parse *cfile,
00036                                 struct binding_value *value);
00037 
00038 #if defined (TRACING)
00039 trace_type_t *trace_readconf_type;
00040 trace_type_t *trace_readleases_type;
00041 
00042 void parse_trace_setup ()
00043 {
00044         trace_readconf_type = trace_type_register ("readconf", (void *)0,
00045                                                    trace_conf_input,
00046                                                    trace_conf_stop, MDL);
00047         trace_readleases_type = trace_type_register ("readleases", (void *)0,
00048                                                      trace_conf_input,
00049                                                      trace_conf_stop, MDL);
00050 }
00051 #endif
00052 
00053 /* conf-file :== parameters declarations END_OF_FILE
00054    parameters :== <nil> | parameter | parameters parameter
00055    declarations :== <nil> | declaration | declarations declaration */
00056 
00057 isc_result_t readconf ()
00058 {
00059         isc_result_t res;
00060 
00061         res = read_conf_file (path_dhcpd_conf, root_group, ROOT_GROUP, 0);
00062 #if defined(LDAP_CONFIGURATION)
00063         if (res != ISC_R_SUCCESS)
00064                 return (res);
00065 
00066         return ldap_read_config ();
00067 #else
00068         return (res);
00069 #endif
00070 }
00071 
00072 isc_result_t read_conf_file (const char *filename, struct group *group,
00073                              int group_type, int leasep)
00074 {
00075         int file;
00076         struct parse *cfile;
00077         isc_result_t status;
00078 #if defined (TRACING)
00079         char *fbuf, *dbuf;
00080         off_t flen;
00081         int result;
00082         unsigned tflen, ulen;
00083         trace_type_t *ttype;
00084 
00085         if (leasep)
00086                 ttype = trace_readleases_type;
00087         else
00088                 ttype = trace_readconf_type;
00089 
00090         /* If we're in playback, we need to snarf the contents of the
00091            named file out of the playback file rather than trying to
00092            open and read it. */
00093         if (trace_playback ()) {
00094                 dbuf = (char *)0;
00095                 tflen = 0;
00096                 status = trace_get_file (ttype, filename, &tflen, &dbuf);
00097                 if (status != ISC_R_SUCCESS)
00098                         return status;
00099                 ulen = tflen;
00100 
00101                 /* What we get back is filename\0contents, where contents is
00102                    terminated just by the length.  So we figure out the length
00103                    of the filename, and subtract that and the NUL from the
00104                    total length to get the length of the contents of the file.
00105                    We make fbuf a pointer to the contents of the file, and
00106                    leave dbuf as it is so we can free it later. */
00107                 tflen = strlen (dbuf);
00108                 ulen = ulen - tflen - 1;
00109                 fbuf = dbuf + tflen + 1;
00110                 goto memfile;
00111         }
00112 #endif
00113 
00114         if ((file = open (filename, O_RDONLY | O_CLOEXEC)) < 0) {
00115                 if (leasep) {
00116                         log_error ("Can't open lease database %s: %m --",
00117                                    path_dhcpd_db);
00118                         log_error ("  check for failed database %s!",
00119                                    "rewrite attempt");
00120                         log_error ("Please read the dhcpd.leases manual%s",
00121                                    " page if you");
00122                         log_fatal ("don't know what to do about this.");
00123                 } else {
00124                         log_fatal ("Can't open %s: %m", filename);
00125                 }
00126         }
00127 
00128         cfile = (struct parse *)0;
00129 #if defined (TRACING)
00130         flen = lseek (file, (off_t)0, SEEK_END);
00131         if (flen < 0) {
00132               boom:
00133                 log_fatal ("Can't lseek on %s: %m", filename);
00134         }
00135         if (lseek (file, (off_t)0, SEEK_SET) < 0)
00136                 goto boom;
00137         /* Can't handle files greater than 2^31-1. */
00138         if (flen > 0x7FFFFFFFUL)
00139                 log_fatal ("%s: file is too long to buffer.", filename);
00140         ulen = flen;
00141 
00142         /* Allocate a buffer that will be what's written to the tracefile,
00143            and also will be what we parse from. */
00144         tflen = strlen (filename);
00145         dbuf = dmalloc (ulen + tflen + 1, MDL);
00146         if (!dbuf)
00147                 log_fatal ("No memory for %s (%d bytes)",
00148                            filename, ulen);
00149 
00150         /* Copy the name into the beginning, nul-terminated. */
00151         strcpy (dbuf, filename);
00152 
00153         /* Load the file in after the NUL. */
00154         fbuf = dbuf + tflen + 1;
00155         result = read (file, fbuf, ulen);
00156         if (result < 0)
00157                 log_fatal ("Can't read in %s: %m", filename);
00158         if (result != ulen)
00159                 log_fatal ("%s: short read of %d bytes instead of %d.",
00160                            filename, ulen, result);
00161         close (file);
00162       memfile:
00163         /* If we're recording, write out the filename and file contents. */
00164         if (trace_record ())
00165                 trace_write_packet (ttype, ulen + tflen + 1, dbuf, MDL);
00166         status = new_parse(&cfile, -1, fbuf, ulen, filename, 0); /* XXX */
00167 #else
00168         status = new_parse(&cfile, file, NULL, 0, filename, 0);
00169 #endif
00170         if (status != ISC_R_SUCCESS || cfile == NULL)
00171                 return status;
00172 
00173         if (leasep)
00174                 status = lease_file_subparse (cfile);
00175         else
00176                 status = conf_file_subparse (cfile, group, group_type);
00177         end_parse (&cfile);
00178 #if defined (TRACING)
00179         dfree (dbuf, MDL);
00180 #endif
00181         return status;
00182 }
00183 
00184 #if defined (TRACING)
00185 void trace_conf_input (trace_type_t *ttype, unsigned len, char *data)
00186 {
00187         char *fbuf;
00188         unsigned flen;
00189         unsigned tflen;
00190         struct parse *cfile = (struct parse *)0;
00191         static int postconf_initialized;
00192         static int leaseconf_initialized;
00193         isc_result_t status;
00194         
00195         /* Do what's done above, except that we don't have to read in the
00196            data, because it's already been read for us. */
00197         tflen = strlen (data);
00198         flen = len - tflen - 1;
00199         fbuf = data + tflen + 1;
00200 
00201         /* If we're recording, write out the filename and file contents. */
00202         if (trace_record ())
00203                 trace_write_packet (ttype, len, data, MDL);
00204 
00205         status = new_parse(&cfile, -1, fbuf, flen, data, 0);
00206         if (status == ISC_R_SUCCESS || cfile != NULL) {
00207                 if (ttype == trace_readleases_type)
00208                         lease_file_subparse (cfile);
00209                 else
00210                         conf_file_subparse (cfile, root_group, ROOT_GROUP);
00211                 end_parse (&cfile);
00212         }
00213 
00214         /* Postconfiguration needs to be done after the config file
00215            has been loaded. */
00216         if (!postconf_initialized && ttype == trace_readconf_type) {
00217                 postconf_initialization (0);
00218                 postconf_initialized = 1;
00219         }
00220 
00221         if (!leaseconf_initialized && ttype == trace_readleases_type) {
00222 #if defined (PARANOIA)
00223                 db_startup (0, 0, 0);
00224 #else
00225                 db_startup (0);
00226 #endif /* PARANOIA */
00227                 leaseconf_initialized = 1;
00228                 postdb_startup ();
00229         }
00230 }
00231 
00232 void trace_conf_stop (trace_type_t *ttype) { }
00233 #endif
00234 
00235 /* conf-file :== parameters declarations END_OF_FILE
00236    parameters :== <nil> | parameter | parameters parameter
00237    declarations :== <nil> | declaration | declarations declaration */
00238 
00239 isc_result_t conf_file_subparse (struct parse *cfile, struct group *group,
00240                                  int group_type)
00241 {
00242         const char *val;
00243         enum dhcp_token token;
00244         int declaration = 0;
00245         int status;
00246 
00247         do {
00248                 token = peek_token (&val, (unsigned *)0, cfile);
00249                 if (token == END_OF_FILE)
00250                         break;
00251                 declaration = parse_statement (cfile, group, group_type,
00252                                                (struct host_decl *)0,
00253                                                declaration);
00254         } while (1);
00255         skip_token(&val, (unsigned *)0, cfile);
00256 
00257         status = cfile->warnings_occurred ? DHCP_R_BADPARSE : ISC_R_SUCCESS;
00258         return status;
00259 }
00260 
00261 /* lease-file :== lease-declarations END_OF_FILE
00262    lease-statements :== <nil>
00263                      | lease-declaration
00264                      | lease-declarations lease-declaration */
00265 
00266 isc_result_t lease_file_subparse (struct parse *cfile)
00267 {
00268         const char *val;
00269         enum dhcp_token token;
00270         isc_result_t status;
00271 
00272         do {
00273                 token = next_token (&val, (unsigned *)0, cfile);
00274                 if (token == END_OF_FILE)
00275                         break;
00276                 if (token == LEASE) {
00277                         struct lease *lease = (struct lease *)0;
00278                         if (parse_lease_declaration (&lease, cfile)) {
00279                                 enter_lease (lease);
00280                                 lease_dereference (&lease, MDL);
00281                         } else
00282                                 parse_warn (cfile,
00283                                             "possibly corrupt lease file");
00284                 } else if (token == IA_NA) {
00285                         parse_ia_na_declaration(cfile);
00286                 } else if (token == IA_TA) {
00287                         parse_ia_ta_declaration(cfile);
00288                 } else if (token == IA_PD) {
00289                         parse_ia_pd_declaration(cfile);
00290                 } else if (token == CLASS) {
00291                         parse_class_declaration(0, cfile, root_group,
00292                                                 CLASS_TYPE_CLASS);
00293                 } else if (token == SUBCLASS) {
00294                         parse_class_declaration(0, cfile, root_group,
00295                                                 CLASS_TYPE_SUBCLASS);
00296                 } else if (token == HOST) {
00297                         parse_host_declaration (cfile, root_group);
00298                 } else if (token == GROUP) {
00299                         parse_group_declaration (cfile, root_group);
00300 #if defined (FAILOVER_PROTOCOL)
00301                 } else if (token == FAILOVER) {
00302                         parse_failover_state_declaration
00303                                 (cfile, (dhcp_failover_state_t *)0);
00304 #endif
00305 #ifdef DHCPv6
00306                 } else if (token == SERVER_DUID) {
00307                         parse_server_duid(cfile);
00308 #endif /* DHCPv6 */
00309                 } else {
00310                         log_error ("Corrupt lease file - possible data loss!");
00311                         skip_to_semi (cfile);
00312                 }
00313 
00314         } while (1);
00315 
00316         status = cfile->warnings_occurred ? DHCP_R_BADPARSE : ISC_R_SUCCESS;
00317         return status;
00318 }
00319 
00320 /* statement :== parameter | declaration
00321 
00322    parameter :== DEFAULT_LEASE_TIME lease_time
00323                | MAX_LEASE_TIME lease_time
00324                | DYNAMIC_BOOTP_LEASE_CUTOFF date
00325                | DYNAMIC_BOOTP_LEASE_LENGTH lease_time
00326                | BOOT_UNKNOWN_CLIENTS boolean
00327                | ONE_LEASE_PER_CLIENT boolean
00328                | GET_LEASE_HOSTNAMES boolean
00329                | USE_HOST_DECL_NAME boolean
00330                | NEXT_SERVER ip-addr-or-hostname SEMI
00331                | option_parameter
00332                | SERVER-IDENTIFIER ip-addr-or-hostname SEMI
00333                | FILENAME string-parameter
00334                | SERVER_NAME string-parameter
00335                | hardware-parameter
00336                | fixed-address-parameter
00337                | ALLOW allow-deny-keyword
00338                | DENY allow-deny-keyword
00339                | USE_LEASE_ADDR_FOR_DEFAULT_ROUTE boolean
00340                | AUTHORITATIVE
00341                | NOT AUTHORITATIVE
00342 
00343    declaration :== host-declaration
00344                  | group-declaration
00345                  | shared-network-declaration
00346                  | subnet-declaration
00347                  | VENDOR_CLASS class-declaration
00348                  | USER_CLASS class-declaration
00349                  | RANGE address-range-declaration */
00350 
00351 int parse_statement (cfile, group, type, host_decl, declaration)
00352         struct parse *cfile;
00353         struct group *group;
00354         int type;
00355         struct host_decl *host_decl;
00356         int declaration;
00357 {
00358         enum dhcp_token token;
00359         const char *val;
00360         struct shared_network *share;
00361         char *n;
00362         struct hardware hardware;
00363         struct executable_statement *et, *ep;
00364         struct option *option = NULL;
00365         struct option_cache *cache;
00366         int lose;
00367         int known;
00368         isc_result_t status;
00369         unsigned code;
00370 
00371         token = peek_token (&val, (unsigned *)0, cfile);
00372 
00373         switch (token) {
00374               case INCLUDE:
00375                 skip_token(&val, (unsigned *)0, cfile);
00376                 token = next_token (&val, (unsigned *)0, cfile);
00377                 if (token != STRING) {
00378                         parse_warn (cfile, "filename string expected.");
00379                         skip_to_semi (cfile);
00380                 } else {
00381                         status = read_conf_file (val, group, type, 0);
00382                         if (status != ISC_R_SUCCESS)
00383                                 parse_warn (cfile, "%s: bad parse.", val);
00384                         parse_semi (cfile);
00385                 }
00386                 return 1;
00387                 
00388               case HOST:
00389                 skip_token(&val, (unsigned *)0, cfile);
00390                 if (type != HOST_DECL && type != CLASS_DECL) {
00391                         if (global_host_once &&
00392                             (type == SUBNET_DECL || type == SHARED_NET_DECL)) {
00393                                 global_host_once = 0;
00394                                 log_error("WARNING: Host declarations are "
00395                                           "global.  They are not limited to "
00396                                           "the scope you declared them in.");
00397                         }
00398 
00399                         parse_host_declaration (cfile, group);
00400                 } else {
00401                         parse_warn (cfile,
00402                                     "host declarations not allowed here.");
00403                         skip_to_semi (cfile);
00404                 }
00405                 return 1;
00406 
00407               case GROUP:
00408                 skip_token(&val, (unsigned *)0, cfile);
00409                 if (type != HOST_DECL && type != CLASS_DECL)
00410                         parse_group_declaration (cfile, group);
00411                 else {
00412                         parse_warn (cfile,
00413                                     "group declarations not allowed here.");
00414                         skip_to_semi (cfile);
00415                 }
00416                 return 1;
00417 
00418               case SHARED_NETWORK:
00419                 skip_token(&val, (unsigned *)0, cfile);
00420                 if (type == SHARED_NET_DECL ||
00421                     type == HOST_DECL ||
00422                     type == SUBNET_DECL ||
00423                     type == CLASS_DECL) {
00424                         parse_warn (cfile, "shared-network parameters not %s.",
00425                                     "allowed here");
00426                         skip_to_semi (cfile);
00427                         break;
00428                 }
00429 
00430                 parse_shared_net_declaration (cfile, group);
00431                 return 1;
00432 
00433               case SUBNET:
00434               case SUBNET6:
00435                 skip_token(&val, (unsigned *)0, cfile);
00436                 if (type == HOST_DECL || type == SUBNET_DECL ||
00437                     type == CLASS_DECL) {
00438                         parse_warn (cfile,
00439                                     "subnet declarations not allowed here.");
00440                         skip_to_semi (cfile);
00441                         return 1;
00442                 }
00443 
00444                 /* If we're in a subnet declaration, just do the parse. */
00445                 if (group->shared_network != NULL) {
00446                         if (token == SUBNET) {
00447                                 parse_subnet_declaration(cfile,
00448                                                          group->shared_network);
00449                         } else {
00450                                 parse_subnet6_declaration(cfile,
00451                                                          group->shared_network);
00452                         }
00453                         break;
00454                 }
00455 
00456                 /*
00457                  * Otherwise, cons up a fake shared network structure
00458                  * and populate it with the lone subnet...because the
00459                  * intention most likely is to refer to the entire link
00460                  * by shorthand, any configuration inside the subnet is
00461                  * actually placed in the shared-network's group.
00462                  */
00463 
00464                 share = NULL;
00465                 status = shared_network_allocate (&share, MDL);
00466                 if (status != ISC_R_SUCCESS)
00467                         log_fatal ("Can't allocate shared subnet: %s",
00468                                    isc_result_totext (status));
00469                 if (!clone_group (&share -> group, group, MDL))
00470                         log_fatal ("Can't allocate group for shared net");
00471                 shared_network_reference (&share -> group -> shared_network,
00472                                           share, MDL);
00473 
00474                 /*
00475                  * This is an implicit shared network, not explicit in
00476                  * the config.
00477                  */
00478                 share->flags |= SHARED_IMPLICIT;
00479 
00480                 if (token == SUBNET) {
00481                         parse_subnet_declaration(cfile, share);
00482                 } else {
00483                         parse_subnet6_declaration(cfile, share);
00484                 }
00485 
00486                 /* share -> subnets is the subnet we just parsed. */
00487                 if (share->subnets) {
00488                         interface_reference(&share->interface,
00489                                             share->subnets->interface,
00490                                             MDL);
00491 
00492                         /* Make the shared network name from network number. */
00493                         if (token == SUBNET) {
00494                                 n = piaddrmask(&share->subnets->net,
00495                                                &share->subnets->netmask);
00496                         } else {
00497                                 n = piaddrcidr(&share->subnets->net,
00498                                                share->subnets->prefix_len);
00499                         }
00500 
00501                         share->name = strdup(n);
00502 
00503                         if (share->name == NULL)
00504                                 log_fatal("Out of memory allocating default "
00505                                           "shared network name (\"%s\").", n);
00506 
00507                         /* Copy the authoritative parameter from the subnet,
00508                            since there is no opportunity to declare it here. */
00509                         share->group->authoritative =
00510                                 share->subnets->group->authoritative;
00511                         enter_shared_network(share);
00512                 }
00513                 shared_network_dereference(&share, MDL);
00514                 return 1;
00515 
00516               case VENDOR_CLASS:
00517                 skip_token(&val, (unsigned *)0, cfile);
00518                 if (type == CLASS_DECL) {
00519                         parse_warn (cfile,
00520                                     "class declarations not allowed here.");
00521                         skip_to_semi (cfile);
00522                         break;
00523                 }
00524                 parse_class_declaration(NULL, cfile, group, CLASS_TYPE_VENDOR);
00525                 return 1;
00526 
00527               case USER_CLASS:
00528                 skip_token(&val, (unsigned *)0, cfile);
00529                 if (type == CLASS_DECL) {
00530                         parse_warn (cfile,
00531                                     "class declarations not allowed here.");
00532                         skip_to_semi (cfile);
00533                         break;
00534                 }
00535                 parse_class_declaration(NULL, cfile, group, CLASS_TYPE_USER);
00536                 return 1;
00537 
00538               case CLASS:
00539                 skip_token(&val, (unsigned *)0, cfile);
00540                 if (type == CLASS_DECL) {
00541                         parse_warn (cfile,
00542                                     "class declarations not allowed here.");
00543                         skip_to_semi (cfile);
00544                         break;
00545                 }
00546                 parse_class_declaration(NULL, cfile, group, CLASS_TYPE_CLASS);
00547                 return 1;
00548 
00549               case SUBCLASS:
00550                 skip_token(&val, (unsigned *)0, cfile);
00551                 if (type == CLASS_DECL) {
00552                         parse_warn (cfile,
00553                                     "class declarations not allowed here.");
00554                         skip_to_semi (cfile);
00555                         break;
00556                 }
00557                 parse_class_declaration(NULL, cfile, group,
00558                                         CLASS_TYPE_SUBCLASS);
00559                 return 1;
00560 
00561               case HARDWARE:
00562                 skip_token(&val, (unsigned *)0, cfile);
00563                 memset (&hardware, 0, sizeof hardware);
00564                 if (host_decl && memcmp(&hardware, &(host_decl->interface),
00565                                         sizeof(hardware)) != 0) {
00566                         parse_warn(cfile, "Host %s hardware address already "
00567                                           "configured.", host_decl->name);
00568                         break;
00569                 }
00570 
00571                 parse_hardware_param (cfile, &hardware);
00572                 if (host_decl)
00573                         host_decl -> interface = hardware;
00574                 else
00575                         parse_warn (cfile, "hardware address parameter %s",
00576                                     "not allowed here.");
00577                 break;
00578 
00579               case FIXED_ADDR:
00580               case FIXED_ADDR6:
00581                 skip_token(&val, NULL, cfile);
00582                 cache = NULL;
00583                 if (parse_fixed_addr_param(&cache, cfile, token)) {
00584                         if (host_decl) {
00585                                 if (host_decl->fixed_addr) {
00586                                         option_cache_dereference(&cache, MDL);
00587                                         parse_warn(cfile,
00588                                                    "Only one fixed address "
00589                                                    "declaration per host.");
00590                                 } else {
00591                                         host_decl->fixed_addr = cache;
00592                                 }
00593                         } else {
00594                                 parse_warn(cfile,
00595                                            "fixed-address parameter not "
00596                                            "allowed here.");
00597                                 option_cache_dereference(&cache, MDL);
00598                         }
00599                 }
00600                 break;
00601 
00602               case POOL:
00603                 skip_token(&val, (unsigned *)0, cfile);
00604                 if (type == POOL_DECL) {
00605                         parse_warn (cfile, "pool declared within pool.");
00606                         skip_to_semi(cfile);
00607                 } else if (type != SUBNET_DECL && type != SHARED_NET_DECL) {
00608                         parse_warn (cfile, "pool declared outside of network");
00609                         skip_to_semi(cfile);
00610                 } else 
00611                         parse_pool_statement (cfile, group, type);
00612 
00613                 return declaration;
00614 
00615               case RANGE:
00616                 skip_token(&val, (unsigned *)0, cfile);
00617                 if (type != SUBNET_DECL || !group -> subnet) {
00618                         parse_warn (cfile,
00619                                     "range declaration not allowed here.");
00620                         skip_to_semi (cfile);
00621                         return declaration;
00622                 }
00623                 parse_address_range (cfile, group, type, (struct pool *)0,
00624                                      (struct lease **)0);
00625                 return declaration;
00626 
00627 #ifdef DHCPv6
00628               case RANGE6:
00629                 skip_token(NULL, NULL, cfile);
00630                 if ((type != SUBNET_DECL) || (group->subnet == NULL)) {
00631                         parse_warn (cfile,
00632                                     "range6 declaration not allowed here.");
00633                         skip_to_semi(cfile);
00634                         return declaration;
00635                 }
00636                 parse_address_range6(cfile, group, NULL);
00637                 return declaration;
00638 
00639               case PREFIX6:
00640                 skip_token(NULL, NULL, cfile);
00641                 if ((type != SUBNET_DECL) || (group->subnet == NULL)) {
00642                         parse_warn (cfile,
00643                                     "prefix6 declaration not allowed here.");
00644                         skip_to_semi(cfile);
00645                         return declaration;
00646                 }
00647                 parse_prefix6(cfile, group, NULL);
00648                 return declaration;
00649 
00650               case FIXED_PREFIX6:
00651                 skip_token(&val, NULL, cfile);
00652                 if (!host_decl) {
00653                         parse_warn (cfile,
00654                                     "fixed-prefix6 declaration not "
00655                                     "allowed here.");
00656                         skip_to_semi(cfile);
00657                         break;
00658                 }
00659                 parse_fixed_prefix6(cfile, host_decl);
00660                 break;
00661 
00662               case POOL6:
00663                 skip_token(&val, NULL, cfile);
00664                 if (type == POOL_DECL) {
00665                         parse_warn (cfile, "pool declared within pool.");
00666                         skip_to_semi(cfile);
00667                 } else if (type != SUBNET_DECL) {
00668                         parse_warn (cfile, "pool declared outside of network");
00669                         skip_to_semi(cfile);
00670                 } else 
00671                         parse_pool6_statement (cfile, group, type);
00672 
00673                 return declaration;
00674 
00675 #endif /* DHCPv6 */
00676 
00677               case TOKEN_NOT:
00678                 skip_token(&val, (unsigned *)0, cfile);
00679                 token = next_token (&val, (unsigned *)0, cfile);
00680                 switch (token) {
00681                       case AUTHORITATIVE:
00682                         group -> authoritative = 0;
00683                         goto authoritative;
00684                       default:
00685                         parse_warn (cfile, "expecting assertion");
00686                         skip_to_semi (cfile);
00687                         break;
00688                 }
00689                 break;
00690               case AUTHORITATIVE:
00691                 skip_token(&val, (unsigned *)0, cfile);
00692                 group -> authoritative = 1;
00693               authoritative:
00694                 if (type == HOST_DECL)
00695                         parse_warn (cfile, "authority makes no sense here."); 
00696                 parse_semi (cfile);
00697                 break;
00698 
00699                 /* "server-identifier" is a special hack, equivalent to
00700                    "option dhcp-server-identifier". */
00701               case SERVER_IDENTIFIER:
00702                 code = DHO_DHCP_SERVER_IDENTIFIER;
00703                 if (!option_code_hash_lookup(&option, dhcp_universe.code_hash,
00704                                              &code, 0, MDL))
00705                         log_fatal("Server identifier not in hash (%s:%d).",
00706                                   MDL);
00707                 skip_token(&val, (unsigned *)0, cfile);
00708                 goto finish_option;
00709 
00710               case OPTION:
00711                 skip_token(&val, (unsigned *)0, cfile);
00712                 token = peek_token (&val, (unsigned *)0, cfile);
00713                 if (token == SPACE) {
00714                         if (type != ROOT_GROUP) {
00715                                 parse_warn (cfile,
00716                                             "option space definitions %s",
00717                                             "may not be scoped.");
00718                                 skip_to_semi (cfile);
00719                                 break;
00720                         }
00721                         parse_option_space_decl (cfile);
00722                         return declaration;
00723                 }
00724 
00725                 known = 0;
00726                 status = parse_option_name(cfile, 1, &known, &option);
00727                 if (status == ISC_R_SUCCESS) {
00728                         token = peek_token (&val, (unsigned *)0, cfile);
00729                         if (token == CODE) {
00730                                 if (type != ROOT_GROUP) {
00731                                         parse_warn (cfile,
00732                                                     "option definitions%s",
00733                                                     " may not be scoped.");
00734                                         skip_to_semi (cfile);
00735                                         option_dereference(&option, MDL);
00736                                         break;
00737                                 }
00738                                 skip_token(&val, (unsigned *)0, cfile);
00739 
00740                                 /*
00741                                  * If the option was known, remove it from the
00742                                  * code and name hashes before redefining it.
00743                                  */
00744                                 if (known) {
00745                                         option_name_hash_delete(
00746                                                 option->universe->name_hash,
00747                                                         option->name, 0, MDL);
00748                                         option_code_hash_delete(
00749                                                 option->universe->code_hash,
00750                                                         &option->code, 0, MDL);
00751                                 }
00752 
00753                                 parse_option_code_definition(cfile, option);
00754                                 option_dereference(&option, MDL);
00755                                 return declaration;
00756                         }
00757 
00758                         /* If this wasn't an option code definition, don't
00759                            allow an unknown option. */
00760                         if (!known) {
00761                                 parse_warn (cfile, "unknown option %s.%s",
00762                                             option -> universe -> name,
00763                                             option -> name);
00764                                 skip_to_semi (cfile);
00765                                 option_dereference(&option, MDL);
00766                                 return declaration;
00767                         }
00768 
00769                       finish_option:
00770                         et = (struct executable_statement *)0;
00771                         if (!parse_option_statement
00772                                 (&et, cfile, 1, option,
00773                                  supersede_option_statement))
00774                                 return declaration;
00775                         option_dereference(&option, MDL);
00776                         goto insert_statement;
00777                 } else
00778                         return declaration;
00779 
00780                 break;
00781 
00782               case FAILOVER:
00783                 if (type != ROOT_GROUP && type != SHARED_NET_DECL) {
00784                         parse_warn (cfile, "failover peers may only be %s",
00785                                     "defined in shared-network");
00786                         log_error ("declarations and the outer scope.");
00787                         skip_to_semi (cfile);
00788                         break;
00789                 }
00790                 token = next_token (&val, (unsigned *)0, cfile);
00791 #if defined (FAILOVER_PROTOCOL)
00792                 parse_failover_peer (cfile, group, type);
00793 #else
00794                 parse_warn (cfile, "No failover support.");
00795                 skip_to_semi (cfile);
00796 #endif
00797                 break;
00798                         
00799 #ifdef DHCPv6 
00800               case SERVER_DUID:
00801                 parse_server_duid_conf(cfile);
00802                 break;
00803 #endif /* DHCPv6 */
00804 
00805               default:
00806                 et = (struct executable_statement *)0;
00807                 lose = 0;
00808                 if (!parse_executable_statement (&et, cfile, &lose,
00809                                                  context_any)) {
00810                         if (!lose) {
00811                                 if (declaration)
00812                                         parse_warn (cfile,
00813                                                     "expecting a declaration");
00814                                 else
00815                                         parse_warn (cfile,
00816                                                     "expecting a parameter %s",
00817                                                     "or declaration");
00818                                 skip_to_semi (cfile);
00819                         }
00820                         return declaration;
00821                 }
00822                 if (!et)
00823                         return declaration;
00824               insert_statement:
00825                 if (group -> statements) {
00826                         int multi = 0;
00827 
00828                         /* If this set of statements is only referenced
00829                            by this group, just add the current statement
00830                            to the end of the chain. */
00831                         for (ep = group -> statements; ep -> next;
00832                              ep = ep -> next)
00833                                 if (ep -> refcnt > 1) /* XXX */
00834                                         multi = 1;
00835                         if (!multi) {
00836                                 executable_statement_reference (&ep -> next,
00837                                                                 et, MDL);
00838                                 executable_statement_dereference (&et, MDL);
00839                                 return declaration;
00840                         }
00841 
00842                         /* Otherwise, make a parent chain, and put the
00843                            current group statements first and the new
00844                            statement in the next pointer. */
00845                         ep = (struct executable_statement *)0;
00846                         if (!executable_statement_allocate (&ep, MDL))
00847                                 log_fatal ("No memory for statements.");
00848                         ep -> op = statements_statement;
00849                         executable_statement_reference (&ep -> data.statements,
00850                                                         group -> statements,
00851                                                         MDL);
00852                         executable_statement_reference (&ep -> next, et, MDL);
00853                         executable_statement_dereference (&group -> statements,
00854                                                           MDL);
00855                         executable_statement_reference (&group -> statements,
00856                                                         ep, MDL);
00857                         executable_statement_dereference (&ep, MDL);
00858                 } else {
00859                         executable_statement_reference (&group -> statements,
00860                                                         et, MDL);
00861                 }
00862                 executable_statement_dereference (&et, MDL);
00863                 return declaration;
00864         }
00865 
00866         return 0;
00867 }
00868 
00869 #if defined (FAILOVER_PROTOCOL)
00870 void parse_failover_peer (cfile, group, type)
00871         struct parse *cfile;
00872         struct group *group;
00873         int type;
00874 {
00875         enum dhcp_token token;
00876         const char *val;
00877         dhcp_failover_state_t *peer;
00878         u_int32_t *tp;
00879         char *name;
00880         u_int32_t split;
00881         u_int8_t hba [32];
00882         unsigned hba_len = sizeof hba;
00883         int i;
00884         struct expression *expr;
00885         isc_result_t status;
00886         dhcp_failover_config_t *cp;
00887 
00888         token = next_token (&val, (unsigned *)0, cfile);
00889         if (token != PEER) {
00890                 parse_warn (cfile, "expecting \"peer\"");
00891                 skip_to_semi (cfile);
00892                 return;
00893         }
00894 
00895         token = next_token (&val, (unsigned *)0, cfile);
00896         if (is_identifier (token) || token == STRING) {
00897                 name = dmalloc (strlen (val) + 1, MDL);
00898                 if (!name)
00899                         log_fatal ("no memory for peer name %s", name);
00900                 strcpy (name, val);
00901         } else {
00902                 parse_warn (cfile, "expecting failover peer name.");
00903                 skip_to_semi (cfile);
00904                 return;
00905         }
00906 
00907         /* See if there's a peer declaration by this name. */
00908         peer = (dhcp_failover_state_t *)0;
00909         find_failover_peer (&peer, name, MDL);
00910 
00911         token = next_token (&val, (unsigned *)0, cfile);
00912         if (token == SEMI) {
00913                 dfree (name, MDL);
00914                 if (type != SHARED_NET_DECL)
00915                         parse_warn (cfile, "failover peer reference not %s",
00916                                     "in shared-network declaration");
00917                 else {
00918                         if (!peer) {
00919                                 parse_warn (cfile, "reference to unknown%s%s",
00920                                             " failover peer ", name);
00921                                 return;
00922                         }
00923                         dhcp_failover_state_reference
00924                                 (&group -> shared_network -> failover_peer,
00925                                  peer, MDL);
00926                 }
00927                 dhcp_failover_state_dereference (&peer, MDL);
00928                 return;
00929         } else if (token == STATE) {
00930                 if (!peer) {
00931                         parse_warn (cfile, "state declaration for unknown%s%s",
00932                                     " failover peer ", name);
00933                         return;
00934                 }
00935                 parse_failover_state_declaration (cfile, peer);
00936                 dhcp_failover_state_dereference (&peer, MDL);
00937                 return;
00938         } else if (token != LBRACE) {
00939                 parse_warn (cfile, "expecting left brace");
00940                 skip_to_semi (cfile);
00941         }
00942 
00943         /* Make sure this isn't a redeclaration. */
00944         if (peer) {
00945                 parse_warn (cfile, "redeclaration of failover peer %s", name);
00946                 skip_to_rbrace (cfile, 1);
00947                 dhcp_failover_state_dereference (&peer, MDL);
00948                 return;
00949         }
00950 
00951         status = dhcp_failover_state_allocate (&peer, MDL);
00952         if (status != ISC_R_SUCCESS)
00953                 log_fatal ("Can't allocate failover peer %s: %s",
00954                            name, isc_result_totext (status));
00955 
00956         /* Save the name. */
00957         peer -> name = name;
00958 
00959         do {
00960                 cp = &peer -> me;
00961               peer:
00962                 token = next_token (&val, (unsigned *)0, cfile);
00963                 switch (token) {
00964                       case RBRACE:
00965                         break;
00966 
00967                       case PRIMARY:
00968                         peer -> i_am = primary;
00969                         break;
00970 
00971                       case SECONDARY:
00972                         peer -> i_am = secondary;
00973                         if (peer -> hba)
00974                                 parse_warn (cfile,
00975                                             "secondary may not define %s",
00976                                             "load balance settings.");
00977                         break;
00978 
00979                       case PEER:
00980                         cp = &peer -> partner;
00981                         goto peer;
00982 
00983                       case ADDRESS:
00984                         expr = (struct expression *)0;
00985                         if (!parse_ip_addr_or_hostname (&expr, cfile, 0)) {
00986                                 skip_to_rbrace (cfile, 1);
00987                                 dhcp_failover_state_dereference (&peer, MDL);
00988                                 return;
00989                         }
00990                         option_cache (&cp -> address,
00991                                       (struct data_string *)0, expr,
00992                                       (struct option *)0, MDL);
00993                         expression_dereference (&expr, MDL);
00994                         break;
00995 
00996                       case PORT:
00997                         token = next_token (&val, (unsigned *)0, cfile);
00998                         if (token != NUMBER) {
00999                                 parse_warn (cfile, "expecting number");
01000                                 skip_to_rbrace (cfile, 1);
01001                         }
01002                         cp -> port = atoi (val);
01003                         break;
01004 
01005                       case MAX_LEASE_MISBALANCE:
01006                         tp = &peer->max_lease_misbalance;
01007                         goto parse_idle;
01008 
01009                       case MAX_LEASE_OWNERSHIP:
01010                         tp = &peer->max_lease_ownership;
01011                         goto parse_idle;
01012 
01013                       case MAX_BALANCE:
01014                         tp = &peer->max_balance;
01015                         goto parse_idle;
01016 
01017                       case MIN_BALANCE:
01018                         tp = &peer->min_balance;
01019                         goto parse_idle;
01020 
01021                       case AUTO_PARTNER_DOWN:
01022                         tp = &peer->auto_partner_down;
01023                         goto parse_idle;
01024 
01025                       case MAX_RESPONSE_DELAY:
01026                         tp = &cp -> max_response_delay;
01027                       parse_idle:
01028                         token = next_token (&val, (unsigned *)0, cfile);
01029                         if (token != NUMBER) {
01030                                 parse_warn (cfile, "expecting number.");
01031                                 skip_to_rbrace (cfile, 1);
01032                                 dhcp_failover_state_dereference (&peer, MDL);
01033                                 return;
01034                         }
01035                         *tp = atoi (val);
01036                         break;
01037 
01038                       case MAX_UNACKED_UPDATES:
01039                         tp = &cp -> max_flying_updates;
01040                         goto parse_idle;
01041 
01042                       case MCLT:
01043                         tp = &peer -> mclt;
01044                         goto parse_idle;
01045 
01046                       case HBA:
01047                         hba_len = 32;
01048                         if (peer -> i_am == secondary)
01049                                 parse_warn (cfile,
01050                                             "secondary may not define %s",
01051                                             "load balance settings.");
01052                         if (!parse_numeric_aggregate (cfile, hba, &hba_len,
01053                                                       COLON, 16, 8)) {
01054                                 skip_to_rbrace (cfile, 1);
01055                                 dhcp_failover_state_dereference (&peer, MDL);
01056                                 return;
01057                         }
01058                         if (hba_len != 32) {
01059                                 parse_warn (cfile,
01060                                             "HBA must be exactly 32 bytes.");
01061                                 break;
01062                         }
01063                       make_hba:
01064                         peer -> hba = dmalloc (32, MDL);
01065                         if (!peer -> hba) {
01066                                 dfree (peer -> name, MDL);
01067                                 dfree (peer, MDL);
01068                         }
01069                         memcpy (peer -> hba, hba, 32);
01070                         break;
01071 
01072                       case SPLIT:
01073                         token = next_token (&val, (unsigned *)0, cfile);
01074                         if (peer -> i_am == secondary)
01075                                 parse_warn (cfile,
01076                                             "secondary may not define %s",
01077                                             "load balance settings.");
01078                         if (token != NUMBER) {
01079                                 parse_warn (cfile, "expecting number");
01080                                 skip_to_rbrace (cfile, 1);
01081                                 dhcp_failover_state_dereference (&peer, MDL);
01082                                 return;
01083                         }
01084                         split = atoi (val);
01085                         if (split > 255) {
01086                                 parse_warn (cfile, "split must be < 256");
01087                         } else {
01088                                 memset (hba, 0, sizeof hba);
01089                                 for (i = 0; i < split; i++) {
01090                                         if (i < split)
01091                                                 hba [i / 8] |= (1 << (i & 7));
01092                                 }
01093                                 goto make_hba;
01094                         }
01095                         break;
01096                         
01097                       case LOAD:
01098                         token = next_token (&val, (unsigned *)0, cfile);
01099                         if (token != BALANCE) {
01100                                 parse_warn (cfile, "expecting 'balance'");
01101                               badload:
01102                                 skip_to_rbrace (cfile, 1);
01103                                 break;
01104                         }
01105                         token = next_token (&val, (unsigned *)0, cfile);
01106                         if (token != TOKEN_MAX) {
01107                                 parse_warn (cfile, "expecting 'max'");
01108                                 goto badload;
01109                         }
01110                         token = next_token (&val, (unsigned *)0, cfile);
01111                         if (token != SECONDS) {
01112                                 parse_warn (cfile, "expecting 'secs'");
01113                                 goto badload;
01114                         }
01115                         token = next_token (&val, (unsigned *)0, cfile);
01116                         if (token != NUMBER) {
01117                                 parse_warn (cfile, "expecting number");
01118                                 goto badload;
01119                         }
01120                         peer -> load_balance_max_secs = atoi (val);
01121                         break;
01122                         
01123                       default:
01124                         parse_warn (cfile,
01125                                     "invalid statement in peer declaration");
01126                         skip_to_rbrace (cfile, 1);
01127                         dhcp_failover_state_dereference (&peer, MDL);
01128                         return;
01129                 }
01130                 if (token != RBRACE && !parse_semi (cfile)) {
01131                         skip_to_rbrace (cfile, 1);
01132                         dhcp_failover_state_dereference (&peer, MDL);
01133                         return;
01134                 }
01135         } while (token != RBRACE);
01136 
01137         /* me.address can be null; the failover link initiate code tries to
01138          * derive a reasonable address to use.
01139          */
01140         if (!peer -> partner.address)
01141                 parse_warn (cfile, "peer address may not be omitted");
01142 
01143         if (!peer->me.port)
01144                 peer->me.port = DEFAULT_FAILOVER_PORT;
01145         if (!peer->partner.port)
01146                 peer->partner.port = DEFAULT_FAILOVER_PORT;
01147 
01148         if (peer -> i_am == primary) {
01149             if (!peer -> hba) {
01150                 parse_warn (cfile,
01151                             "primary failover server must have hba or split.");
01152             } else if (!peer -> mclt) {
01153                 parse_warn (cfile,
01154                             "primary failover server must have mclt.");
01155             }
01156         }
01157 
01158         if (!peer->max_lease_misbalance)
01159                 peer->max_lease_misbalance = DEFAULT_MAX_LEASE_MISBALANCE;
01160         if (!peer->max_lease_ownership)
01161                 peer->max_lease_ownership = DEFAULT_MAX_LEASE_OWNERSHIP;
01162         if (!peer->max_balance)
01163                 peer->max_balance = DEFAULT_MAX_BALANCE_TIME;
01164         if (!peer->min_balance)
01165                 peer->min_balance = DEFAULT_MIN_BALANCE_TIME;
01166         if (!peer->me.max_flying_updates)
01167                 peer->me.max_flying_updates = DEFAULT_MAX_FLYING_UPDATES;
01168         if (!peer->me.max_response_delay)
01169                 peer->me.max_response_delay = DEFAULT_MAX_RESPONSE_DELAY;
01170 
01171         if (type == SHARED_NET_DECL)
01172                 group->shared_network->failover_peer = peer;
01173 
01174         /* Set the initial state. */
01175         if (peer -> i_am == primary) {
01176                 peer -> me.state = recover;
01177                 peer -> me.stos = cur_time;
01178                 peer -> partner.state = unknown_state;
01179                 peer -> partner.stos = cur_time;
01180         } else {
01181                 peer -> me.state = recover;
01182                 peer -> me.stos = cur_time;
01183                 peer -> partner.state = unknown_state;
01184                 peer -> partner.stos = cur_time;
01185         }
01186 
01187         status = enter_failover_peer (peer);
01188         if (status != ISC_R_SUCCESS)
01189                 parse_warn (cfile, "failover peer %s: %s",
01190                             peer -> name, isc_result_totext (status));
01191         dhcp_failover_state_dereference (&peer, MDL);
01192 }
01193 
01194 void parse_failover_state_declaration (struct parse *cfile,
01195                                        dhcp_failover_state_t *peer)
01196 {
01197         enum dhcp_token token;
01198         const char *val;
01199         char *name;
01200         dhcp_failover_state_t *state;
01201         dhcp_failover_config_t *cp;
01202 
01203         if (!peer) {
01204                 token = next_token (&val, (unsigned *)0, cfile);
01205                 if (token != PEER) {
01206                         parse_warn (cfile, "expecting \"peer\"");
01207                         skip_to_semi (cfile);
01208                         return;
01209                 }
01210 
01211                 token = next_token (&val, (unsigned *)0, cfile);
01212                 if (is_identifier (token) || token == STRING) {
01213                         name = dmalloc (strlen (val) + 1, MDL);
01214                         if (!name)
01215                                 log_fatal ("failover peer name %s: no memory",
01216                                            name);
01217                         strcpy (name, val);
01218                 } else {
01219                         parse_warn (cfile, "expecting failover peer name.");
01220                         skip_to_semi (cfile);
01221                         return;
01222                 }
01223 
01224                 /* See if there's a peer declaration by this name. */
01225                 state = (dhcp_failover_state_t *)0;
01226                 find_failover_peer (&state, name, MDL);
01227                 if (!state) {
01228                         parse_warn (cfile, "unknown failover peer: %s", name);
01229                         skip_to_semi (cfile);
01230                         return;
01231                 }
01232 
01233                 token = next_token (&val, (unsigned *)0, cfile);
01234                 if (token != STATE) {
01235                         parse_warn (cfile, "expecting 'state'");
01236                         if (token != SEMI)
01237                                 skip_to_semi (cfile);
01238                         return;
01239                 }
01240         } else {
01241                 state = (dhcp_failover_state_t *)0;
01242                 dhcp_failover_state_reference (&state, peer, MDL);
01243         }
01244         token = next_token (&val, (unsigned *)0, cfile);
01245         if (token != LBRACE) {
01246                 parse_warn (cfile, "expecting left brace");
01247                 if (token != SEMI)
01248                         skip_to_semi (cfile);
01249                 dhcp_failover_state_dereference (&state, MDL);
01250                 return;
01251         }
01252         do {
01253                 token = next_token (&val, (unsigned *)0, cfile);
01254                 switch (token) {
01255                       case RBRACE:
01256                         break;
01257                       case MY:
01258                         cp = &state -> me;
01259                       do_state:
01260                         token = next_token (&val, (unsigned *)0, cfile);
01261                         if (token != STATE) {
01262                                 parse_warn (cfile, "expecting 'state'");
01263                                 goto bogus;
01264                         }
01265                         parse_failover_state (cfile,
01266                                               &cp -> state, &cp -> stos);
01267                         break;
01268 
01269                       case PARTNER:
01270                         cp = &state -> partner;
01271                         goto do_state;
01272 
01273                       case MCLT:
01274                         if (state -> i_am == primary) {
01275                                 parse_warn (cfile,
01276                                             "mclt not valid for primary");
01277                                 goto bogus;
01278                         }
01279                         token = next_token (&val, (unsigned *)0, cfile);
01280                         if (token != NUMBER) {
01281                                 parse_warn (cfile, "expecting a number.");
01282                                 goto bogus;
01283                         }
01284                         state -> mclt = atoi (val);
01285                         parse_semi (cfile);
01286                         break;
01287                         
01288                       default:
01289                         parse_warn (cfile, "expecting state setting.");
01290                       bogus:
01291                         skip_to_rbrace (cfile, 1);      
01292                         dhcp_failover_state_dereference (&state, MDL);
01293                         return;
01294                 }
01295         } while (token != RBRACE);
01296         dhcp_failover_state_dereference (&state, MDL);
01297 }
01298 
01299 void parse_failover_state (cfile, state, stos)
01300         struct parse *cfile;
01301         enum failover_state *state;
01302         TIME *stos;
01303 {
01304         enum dhcp_token token;
01305         const char *val;
01306         enum failover_state state_in;
01307         TIME stos_in;
01308 
01309         token = next_token (&val, (unsigned *)0, cfile);
01310         switch (token) {
01311               case UNKNOWN_STATE:
01312                 state_in = unknown_state;
01313                 break;
01314 
01315               case PARTNER_DOWN:
01316                 state_in = partner_down;
01317                 break;
01318 
01319               case NORMAL:
01320                 state_in = normal;
01321                 break;
01322 
01323               case COMMUNICATIONS_INTERRUPTED:
01324                 state_in = communications_interrupted;
01325                 break;
01326 
01327               case CONFLICT_DONE:
01328                 state_in = conflict_done;
01329                 break;
01330 
01331               case RESOLUTION_INTERRUPTED:
01332                 state_in = resolution_interrupted;
01333                 break;
01334 
01335               case POTENTIAL_CONFLICT:
01336                 state_in = potential_conflict;
01337                 break;
01338 
01339               case RECOVER:
01340                 state_in = recover;
01341                 break;
01342                 
01343               case RECOVER_WAIT:
01344                 state_in = recover_wait;
01345                 break;
01346                 
01347               case RECOVER_DONE:
01348                 state_in = recover_done;
01349                 break;
01350                 
01351               case SHUTDOWN:
01352                 state_in = shut_down;
01353                 break;
01354                 
01355               case PAUSED:
01356                 state_in = paused;
01357                 break;
01358                 
01359               case STARTUP:
01360                 state_in = startup;
01361                 break;
01362 
01363               default:
01364                 parse_warn (cfile, "unknown failover state");
01365                 skip_to_semi (cfile);
01366                 return;
01367         }
01368 
01369         token = next_token (&val, (unsigned *)0, cfile);
01370         if (token == SEMI) {
01371                 stos_in = cur_time;
01372         } else {
01373                 if (token != AT) {
01374                         parse_warn (cfile, "expecting \"at\"");
01375                         skip_to_semi (cfile);
01376                         return;
01377                 }
01378                 
01379                 stos_in = parse_date (cfile);
01380                 if (!stos_in)
01381                         return;
01382         }
01383 
01384         /* Now that we've apparently gotten a clean parse, we
01385            can trust that this is a state that was fully committed to
01386            disk, so we can install it. */
01387         *stos = stos_in;
01388         *state = state_in;
01389 }
01390 #endif /* defined (FAILOVER_PROTOCOL) */
01391 
01424 void get_permit(cfile, permit_head, is_allow, valid_from, valid_until)
01425         struct parse *cfile;
01426         struct permit **permit_head;
01427         int is_allow;
01428         TIME *valid_from, *valid_until;
01429 {
01430         enum dhcp_token token;
01431         struct permit *permit;
01432         const char *val;
01433         int need_clients = 1;
01434         TIME t;
01435 
01436         /* Create our permit structure */
01437         permit = new_permit(MDL);
01438         if (!permit)
01439                 log_fatal ("no memory for permit");
01440 
01441         token = next_token(&val, NULL, cfile);
01442         switch (token) {
01443               case UNKNOWN:
01444                 permit->type = permit_unknown_clients;
01445                 break;
01446                                 
01447               case KNOWN_CLIENTS:
01448                 need_clients = 0;
01449                 permit->type = permit_known_clients;
01450                 break;
01451 
01452               case UNKNOWN_CLIENTS:
01453                 need_clients = 0;
01454                 permit->type = permit_unknown_clients;
01455                 break;
01456 
01457               case KNOWN:
01458                 permit->type = permit_known_clients;
01459                 break;
01460                                 
01461               case AUTHENTICATED:
01462                 permit->type = permit_authenticated_clients;
01463                 break;
01464                                 
01465               case UNAUTHENTICATED:
01466                 permit->type = permit_unauthenticated_clients;
01467                 break;
01468 
01469               case ALL:
01470                 permit->type = permit_all_clients;
01471                 break;
01472                                 
01473               case DYNAMIC:
01474                 permit->type = permit_dynamic_bootp_clients;
01475                 if (next_token (&val, NULL, cfile) != TOKEN_BOOTP) {
01476                         parse_warn (cfile, "expecting \"bootp\"");
01477                         skip_to_semi (cfile);
01478                         free_permit (permit, MDL);
01479                         return;
01480                 }
01481                 break;
01482 
01483               case MEMBERS:
01484                 need_clients = 0;
01485                 if (next_token (&val, NULL, cfile) != OF) {
01486                         parse_warn (cfile, "expecting \"of\"");
01487                         skip_to_semi (cfile);
01488                         free_permit (permit, MDL);
01489                         return;
01490                 }
01491                 if (next_token (&val, NULL, cfile) != STRING) {
01492                         parse_warn (cfile, "expecting class name.");
01493                         skip_to_semi (cfile);
01494                         free_permit (permit, MDL);
01495                         return;
01496                 }
01497                 permit->type = permit_class;
01498                 permit->class = NULL;
01499                 find_class(&permit->class, val, MDL);
01500                 if (!permit->class)
01501                         parse_warn(cfile, "no such class: %s", val);
01502                 break;
01503 
01504               case AFTER:
01505                 need_clients = 0;
01506                 if (*valid_from || *valid_until) {
01507                         parse_warn(cfile, "duplicate \"after\" clause.");
01508                         skip_to_semi(cfile);
01509                         free_permit(permit, MDL);
01510                         return;
01511                 }
01512                 t = parse_date_core(cfile);
01513                 permit->type = permit_after;
01514                 permit->after = t;
01515                 if (is_allow) {
01516                         *valid_from = t;
01517                 } else {
01518                         *valid_until = t;
01519                 }
01520                 break;
01521 
01522               default:
01523                 parse_warn (cfile, "expecting permit type.");
01524                 skip_to_semi (cfile);
01525                 free_permit (permit, MDL);
01526                 return;
01527         }
01528 
01529         /*
01530          * The need_clients flag is set if we are expecting the
01531          * CLIENTS token
01532          */
01533         if ((need_clients != 0)  &&
01534             (next_token (&val, NULL, cfile) != CLIENTS)) {
01535                 parse_warn (cfile, "expecting \"clients\"");
01536                 skip_to_semi (cfile);
01537                 free_permit (permit, MDL);
01538                 return;
01539         }
01540 
01541         while (*permit_head)
01542                 permit_head = &((*permit_head)->next);
01543         *permit_head = permit;
01544         parse_semi (cfile);
01545 
01546         return;
01547 }
01548 
01549 /* Permit_list_match returns 1 if every element of the permit list in lhs
01550    also appears in rhs.   Note that this doesn't by itself mean that the
01551    two lists are equal - to check for equality, permit_list_match has to
01552    return 1 with (list1, list2) and with (list2, list1). */
01553 
01554 int permit_list_match (struct permit *lhs, struct permit *rhs)
01555 {
01556         struct permit *plp, *prp;
01557         int matched;
01558 
01559         if (!lhs)
01560                 return 1;
01561         if (!rhs)
01562                 return 0;
01563         for (plp = lhs; plp; plp = plp -> next) {
01564                 matched = 0;
01565                 for (prp = rhs; prp; prp = prp -> next) {
01566                         if (prp -> type == plp -> type &&
01567                             (prp -> type != permit_class ||
01568                              prp -> class == plp -> class)) {
01569                                 matched = 1;
01570                                 break;
01571                         }
01572                 }
01573                 if (!matched)
01574                         return 0;
01575         }
01576         return 1;
01577 }
01578 
01598 void parse_pool_statement (cfile, group, type)
01599         struct parse *cfile;
01600         struct group *group;
01601         int type;
01602 {
01603         enum dhcp_token token;
01604         const char *val;
01605         int done = 0;
01606         struct pool *pool, **p, *pp;
01607         int declaration = 0;
01608         isc_result_t status;
01609         struct lease *lpchain = NULL, *lp;
01610 
01611         pool = NULL;
01612         status = pool_allocate(&pool, MDL);
01613         if (status != ISC_R_SUCCESS)
01614                 log_fatal ("no memory for pool: %s",
01615                            isc_result_totext (status));
01616 
01617         if (type == SUBNET_DECL)
01618                 shared_network_reference(&pool->shared_network,
01619                                          group->subnet->shared_network,
01620                                          MDL);
01621         else if (type == SHARED_NET_DECL)
01622                 shared_network_reference(&pool->shared_network,
01623                                          group->shared_network, MDL);
01624         else {
01625                 parse_warn(cfile, "Dynamic pools are only valid inside "
01626                                   "subnet or shared-network statements.");
01627                 skip_to_semi(cfile);
01628                 return;
01629         }
01630 
01631         if (pool->shared_network == NULL ||
01632             !clone_group(&pool->group, pool->shared_network->group, MDL))
01633                 log_fatal("can't clone pool group.");
01634 
01635 #if defined (FAILOVER_PROTOCOL)
01636         /* Inherit the failover peer from the shared network. */
01637         if (pool->shared_network->failover_peer)
01638             dhcp_failover_state_reference
01639                     (&pool->failover_peer, 
01640                      pool->shared_network->failover_peer, MDL);
01641 #endif
01642 
01643         if (!parse_lbrace(cfile)) {
01644                 pool_dereference(&pool, MDL);
01645                 return;
01646         }
01647 
01648         do {
01649                 token = peek_token(&val, NULL, cfile);
01650                 switch (token) {
01651                       case TOKEN_NO:
01652                         skip_token(&val, NULL, cfile);
01653                         token = next_token(&val, NULL, cfile);
01654                         if (token != FAILOVER ||
01655                             (token = next_token(&val, NULL, cfile)) != PEER) {
01656                                 parse_warn(cfile,
01657                                            "expecting \"failover peer\".");
01658                                 skip_to_semi(cfile);
01659                                 continue;
01660                         }
01661 #if defined (FAILOVER_PROTOCOL)
01662                         if (pool->failover_peer)
01663                                 dhcp_failover_state_dereference
01664                                         (&pool->failover_peer, MDL);
01665 #endif
01666                         break;
01667                                 
01668 #if defined (FAILOVER_PROTOCOL)
01669                       case FAILOVER:
01670                         skip_token(&val, NULL, cfile);
01671                         token = next_token (&val, NULL, cfile);
01672                         if (token != PEER) {
01673                                 parse_warn(cfile, "expecting 'peer'.");
01674                                 skip_to_semi(cfile);
01675                                 break;
01676                         }
01677                         token = next_token(&val, NULL, cfile);
01678                         if (token != STRING) {
01679                                 parse_warn(cfile, "expecting string.");
01680                                 skip_to_semi(cfile);
01681                                 break;
01682                         }
01683                         if (pool->failover_peer)
01684                                 dhcp_failover_state_dereference
01685                                         (&pool->failover_peer, MDL);
01686                         status = find_failover_peer(&pool->failover_peer,
01687                                                     val, MDL);
01688                         if (status != ISC_R_SUCCESS)
01689                                 parse_warn(cfile,
01690                                            "failover peer %s: %s", val,
01691                                            isc_result_totext (status));
01692                         else
01693                                 pool->failover_peer->pool_count++;
01694                         parse_semi(cfile);
01695                         break;
01696 #endif
01697 
01698                       case RANGE:
01699                         skip_token(&val, NULL, cfile);
01700                         parse_address_range (cfile, group, type,
01701                                              pool, &lpchain);
01702                         break;
01703                       case ALLOW:
01704                         skip_token(&val, NULL, cfile);
01705                         get_permit(cfile, &pool->permit_list, 1,
01706                                    &pool->valid_from, &pool->valid_until);
01707                         break;
01708 
01709                       case DENY:
01710                         skip_token(&val, NULL, cfile);
01711                         get_permit(cfile, &pool->prohibit_list, 0,
01712                                    &pool->valid_from, &pool->valid_until);
01713                         break;
01714                         
01715                       case RBRACE:
01716                         skip_token(&val, NULL, cfile);
01717                         done = 1;
01718                         break;
01719 
01720                       case END_OF_FILE:
01721                         /*
01722                          * We can get to END_OF_FILE if, for instance,
01723                          * the parse_statement() reads all available tokens
01724                          * and leaves us at the end.
01725                          */
01726                         parse_warn(cfile, "unexpected end of file");
01727                         goto cleanup;
01728 
01729                       default:
01730                         declaration = parse_statement(cfile, pool->group,
01731                                                       POOL_DECL, NULL,
01732                                                        declaration);
01733                         break;
01734                 }
01735         } while (!done);
01736 
01737         /* See if there's already a pool into which we can merge this one. */
01738         for (pp = pool->shared_network->pools; pp; pp = pp->next) {
01739                 if (pp->group->statements != pool->group->statements)
01740                         continue;
01741 #if defined (FAILOVER_PROTOCOL)
01742                 if (pool->failover_peer != pp->failover_peer)
01743                         continue;
01744 #endif
01745                 if (!permit_list_match(pp->permit_list,
01746                                        pool->permit_list) ||
01747                     !permit_list_match(pool->permit_list,
01748                                        pp->permit_list) ||
01749                     !permit_list_match(pp->prohibit_list,
01750                                        pool->prohibit_list) ||
01751                     !permit_list_match(pool->prohibit_list,
01752                                        pp->prohibit_list))
01753                         continue;
01754 
01755                 /* Okay, we can merge these two pools.    All we have to
01756                    do is fix up the leases, which all point to their pool. */
01757                 for (lp = lpchain; lp; lp = lp->next) {
01758                         pool_dereference(&lp->pool, MDL);
01759                         pool_reference(&lp->pool, pp, MDL);
01760                 }
01761                 break;
01762         }
01763 
01764         /* If we didn't succeed in merging this pool into another, put
01765            it on the list. */
01766         if (!pp) {
01767                 p = &pool->shared_network->pools;
01768                 for (; *p; p = &((*p)->next))
01769                         ;
01770                 pool_reference(p, pool, MDL);
01771         }
01772 
01773         /* Don't allow a pool declaration with no addresses, since it is
01774            probably a configuration error. */
01775         if (!lpchain) {
01776                 parse_warn(cfile, "Pool declaration with no address range.");
01777                 log_error("Pool declarations must always contain at least");
01778                 log_error("one range statement.");
01779         }
01780 
01781 cleanup:
01782         /* Dereference the lease chain. */
01783         lp = NULL;
01784         while (lpchain) {
01785                 lease_reference(&lp, lpchain, MDL);
01786                 lease_dereference(&lpchain, MDL);
01787                 if (lp->next) {
01788                         lease_reference(&lpchain, lp->next, MDL);
01789                         lease_dereference(&lp->next, MDL);
01790                         lease_dereference(&lp, MDL);
01791                 }
01792         }
01793         pool_dereference(&pool, MDL);
01794 }
01795 
01796 /* Expect a left brace; if there isn't one, skip over the rest of the
01797    statement and return zero; otherwise, return 1. */
01798 
01799 int parse_lbrace (cfile)
01800         struct parse *cfile;
01801 {
01802         enum dhcp_token token;
01803         const char *val;
01804 
01805         token = next_token (&val, (unsigned *)0, cfile);
01806         if (token != LBRACE) {
01807                 parse_warn (cfile, "expecting left brace.");
01808                 skip_to_semi (cfile);
01809                 return 0;
01810         }
01811         return 1;
01812 }
01813 
01814 
01815 /* host-declaration :== hostname RBRACE parameters declarations LBRACE */
01816 
01817 void parse_host_declaration (cfile, group)
01818         struct parse *cfile;
01819         struct group *group;
01820 {
01821         const char *val;
01822         enum dhcp_token token;
01823         struct host_decl *host;
01824         char *name;
01825         int declaration = 0;
01826         int dynamicp = 0;
01827         int deleted = 0;
01828         isc_result_t status;
01829         int known;
01830         struct option *option;
01831         struct expression *expr = NULL;
01832 
01833         name = parse_host_name (cfile);
01834         if (!name) {
01835                 parse_warn (cfile, "expecting a name for host declaration.");
01836                 skip_to_semi (cfile);
01837                 return;
01838         }
01839 
01840         host = (struct host_decl *)0;
01841         status = host_allocate (&host, MDL);
01842         if (status != ISC_R_SUCCESS)
01843                 log_fatal ("can't allocate host decl struct %s: %s",
01844                            name, isc_result_totext (status));
01845         host -> name = name;
01846         if (!clone_group (&host -> group, group, MDL)) {
01847                 log_fatal ("can't clone group for host %s", name);
01848               boom:
01849                 host_dereference (&host, MDL);
01850                 return;
01851         }
01852 
01853         if (!parse_lbrace (cfile))
01854                 goto boom;
01855 
01856         do {
01857                 token = peek_token (&val, (unsigned *)0, cfile);
01858                 if (token == RBRACE) {
01859                         skip_token(&val, (unsigned *)0, cfile);
01860                         break;
01861                 }
01862                 if (token == END_OF_FILE) {
01863                         skip_token(&val, (unsigned *)0, cfile);
01864                         parse_warn (cfile, "unexpected end of file");
01865                         break;
01866                 }
01867                 /* If the host declaration was created by the server,
01868                    remember to save it. */
01869                 if (token == DYNAMIC) {
01870                         dynamicp = 1;
01871                         skip_token(&val, (unsigned *)0, cfile);
01872                         if (!parse_semi (cfile))
01873                                 break;
01874                         continue;
01875                 }
01876                 /* If the host declaration was created by the server,
01877                    remember to save it. */
01878                 if (token == TOKEN_DELETED) {
01879                         deleted = 1;
01880                         skip_token(&val, (unsigned *)0, cfile);
01881                         if (!parse_semi (cfile))
01882                                 break;
01883                         continue;
01884                 }
01885 
01886                 if (token == GROUP) {
01887                         struct group_object *go;
01888                         skip_token(&val, (unsigned *)0, cfile);
01889                         token = next_token (&val, (unsigned *)0, cfile);
01890                         if (token != STRING && !is_identifier (token)) {
01891                                 parse_warn (cfile,
01892                                             "expecting string or identifier.");
01893                                 skip_to_rbrace (cfile, 1);
01894                                 break;
01895                         }
01896                         go = (struct group_object *)0;
01897                         if (!group_hash_lookup (&go, group_name_hash,
01898                                                 val, strlen (val), MDL)) {
01899                             parse_warn (cfile, "unknown group %s in host %s",
01900                                         val, host -> name);
01901                         } else {
01902                                 if (host -> named_group)
01903                                         group_object_dereference
01904                                                 (&host -> named_group, MDL);
01905                                 group_object_reference (&host -> named_group,
01906                                                         go, MDL);
01907                                 group_object_dereference (&go, MDL);
01908                         }
01909                         if (!parse_semi (cfile))
01910                                 break;
01911                         continue;
01912                 }
01913 
01914                 if (token == UID) {
01915                         const char *s;
01916                         unsigned char *t = 0;
01917                         unsigned len;
01918 
01919                         skip_token(&val, (unsigned *)0, cfile);
01920                         data_string_forget (&host -> client_identifier, MDL);
01921 
01922                         if (host->client_identifier.len != 0) {
01923                                 parse_warn(cfile, "Host %s already has a "
01924                                                   "client identifier.",
01925                                            host->name);
01926                                 break;
01927                         }
01928 
01929                         /* See if it's a string or a cshl. */
01930                         token = peek_token (&val, (unsigned *)0, cfile);
01931                         if (token == STRING) {
01932                                 skip_token(&val, &len, cfile);
01933                                 s = val;
01934                                 host -> client_identifier.terminated = 1;
01935                         } else {
01936                                 len = 0;
01937                                 t = parse_numeric_aggregate
01938                                         (cfile,
01939                                          (unsigned char *)0, &len, ':', 16, 8);
01940                                 if (!t) {
01941                                         parse_warn (cfile,
01942                                                     "expecting hex list.");
01943                                         skip_to_semi (cfile);
01944                                 }
01945                                 s = (const char *)t;
01946                         }
01947                         if (!buffer_allocate
01948                             (&host -> client_identifier.buffer,
01949                              len + host -> client_identifier.terminated, MDL))
01950                                 log_fatal ("no memory for uid for host %s.",
01951                                            host -> name);
01952                         host -> client_identifier.data =
01953                                 host -> client_identifier.buffer -> data;
01954                         host -> client_identifier.len = len;
01955                         memcpy (host -> client_identifier.buffer -> data, s,
01956                                 len + host -> client_identifier.terminated);
01957                         if (t)
01958                                 dfree (t, MDL);
01959 
01960                         if (!parse_semi (cfile))
01961                                 break;
01962                         continue;
01963                 }
01964 
01965                 if (token == HOST_IDENTIFIER) {
01966                         if (host->host_id_option != NULL) {
01967                                 parse_warn(cfile,
01968                                            "only one host-identifier allowed "
01969                                            "per host");
01970                                 skip_to_rbrace(cfile, 1);
01971                                 break;
01972                         }
01973                         skip_token(&val, NULL, cfile);
01974                         token = next_token(&val, NULL, cfile);
01975                         if (token == V6RELOPT) {
01976                                 token = next_token(&val, NULL, cfile);                          
01977                                 if (token != NUMBER) {
01978                                         parse_warn(cfile,
01979                                                    "host-identifier v6relopt "
01980                                                    "must have a number");
01981                                         skip_to_rbrace(cfile, 1);
01982                                         break;
01983                                 }
01984                                 host->relays = atoi(val);
01985                                 if (host->relays < 0) {
01986                                         parse_warn(cfile,
01987                                                    "host-identifier v6relopt "
01988                                                    "must have a number >= 0");
01989                                         skip_to_rbrace(cfile, 1);
01990                                         break;
01991                                 }
01992                         } else if (token != OPTION) {
01993                                 parse_warn(cfile, 
01994                                            "host-identifier must be an option"
01995                                            " or v6relopt");
01996                                 skip_to_rbrace(cfile, 1);
01997                                 break;
01998                         }
01999                         known = 0;
02000                         option = NULL;
02001                         status = parse_option_name(cfile, 1, &known, &option);
02002                         if ((status != ISC_R_SUCCESS) || (option == NULL)) {
02003                                 break;
02004                         }
02005                         if (!known) {
02006                                 parse_warn(cfile, "unknown option %s.%s",
02007                                            option->universe->name, 
02008                                            option->name);
02009                                 skip_to_rbrace(cfile, 1);
02010                                 break;
02011                         }
02012 
02013                         if (! parse_option_data(&expr, cfile, 1, option)) {
02014                                 skip_to_rbrace(cfile, 1);
02015                                 option_dereference(&option, MDL);
02016                                 break;
02017                         }
02018                         
02019                         if (!parse_semi(cfile)) {
02020                                 skip_to_rbrace(cfile, 1);
02021                                 expression_dereference(&expr, MDL);
02022                                 option_dereference(&option, MDL);
02023                                 break;
02024                         }
02025 
02026                         option_reference(&host->host_id_option, option, MDL);
02027                         option_dereference(&option, MDL);
02028                         data_string_copy(&host->host_id, 
02029                                          &expr->data.const_data, MDL);
02030                         expression_dereference(&expr, MDL);
02031                         continue;
02032                 }
02033 
02034                 declaration = parse_statement(cfile, host->group, HOST_DECL,
02035                                               host, declaration);
02036         } while (1);
02037 
02038         if (deleted) {
02039                 struct host_decl *hp = (struct host_decl *)0;
02040                 if (host_hash_lookup (&hp, host_name_hash,
02041                                       (unsigned char *)host -> name,
02042                                       strlen (host -> name), MDL)) {
02043                         delete_host (hp, 0);
02044                         host_dereference (&hp, MDL);
02045                 }
02046         } else {
02047                 if (host -> named_group && host -> named_group -> group) {
02048                         if (host -> group -> statements ||
02049                             (host -> group -> authoritative !=
02050                              host -> named_group -> group -> authoritative)) {
02051                                 if (host -> group -> next)
02052                                     group_dereference (&host -> group -> next,
02053                                                        MDL);
02054                                 group_reference (&host -> group -> next,
02055                                                  host -> named_group -> group,
02056                                                  MDL);
02057                         } else {
02058                                 group_dereference (&host -> group, MDL);
02059                                 group_reference (&host -> group,
02060                                                  host -> named_group -> group,
02061                                                  MDL);
02062                         }
02063                 }
02064                                 
02065                 if (dynamicp)
02066                         host -> flags |= HOST_DECL_DYNAMIC;
02067                 else
02068                         host -> flags |= HOST_DECL_STATIC;
02069 
02070                 status = enter_host (host, dynamicp, 0);
02071                 if (status != ISC_R_SUCCESS)
02072                         parse_warn (cfile, "host %s: %s", host -> name,
02073                                     isc_result_totext (status));
02074         }
02075         host_dereference (&host, MDL);
02076 }
02077 
02078 /* class-declaration :== STRING LBRACE parameters declarations RBRACE
02079 */
02080 
02081 int parse_class_declaration (cp, cfile, group, type)
02082         struct class **cp;
02083         struct parse *cfile;
02084         struct group *group;
02085         int type;
02086 {
02087         const char *val;
02088         enum dhcp_token token;
02089         struct class *class = NULL, *pc = NULL;
02090         int declaration = 0;
02091         int lose = 0;
02092         struct data_string data;
02093         char *name;
02094         const char *tname;
02095         struct executable_statement *stmt = NULL;
02096         int new = 1;
02097         isc_result_t status = ISC_R_FAILURE;
02098         int matchedonce = 0;
02099         int submatchedonce = 0;
02100         unsigned code;
02101 
02102         token = next_token (&val, NULL, cfile);
02103         if (token != STRING) {
02104                 parse_warn (cfile, "Expecting class name");
02105                 skip_to_semi (cfile);
02106                 return 0;
02107         }
02108 
02109         /* See if there's already a class with the specified name. */
02110         find_class (&pc, val, MDL);
02111 
02112         /* If it is a class, we're updating it.  If it's any of the other
02113          * types (subclass, vendor or user class), the named class is a
02114          * reference to the parent class so its mandatory.
02115          */
02116         if (pc && (type == CLASS_TYPE_CLASS)) {
02117                 class_reference(&class, pc, MDL);
02118                 new = 0;
02119                 class_dereference(&pc, MDL);
02120         } else if (!pc && (type != CLASS_TYPE_CLASS)) {
02121                 parse_warn(cfile, "no class named %s", val);
02122                 skip_to_semi(cfile);
02123                 return 0;
02124         }
02125 
02126         /* The old vendor-class and user-class declarations had an implicit
02127            match.   We don't do the implicit match anymore.   Instead, for
02128            backward compatibility, we have an implicit-vendor-class and an
02129            implicit-user-class.   vendor-class and user-class declarations
02130            are turned into subclasses of the implicit classes, and the
02131            submatch expression of the implicit classes extracts the contents of
02132            the vendor class or user class. */
02133         if ((type == CLASS_TYPE_VENDOR) || (type == CLASS_TYPE_USER)) {
02134                 data.len = strlen (val);
02135                 data.buffer = NULL;
02136                 if (!buffer_allocate (&data.buffer, data.len + 1, MDL))
02137                         log_fatal ("no memory for class name.");
02138                 data.data = &data.buffer -> data [0];
02139                 data.terminated = 1;
02140 
02141                 tname = type ? "implicit-vendor-class" : "implicit-user-class";
02142         } else if (type == CLASS_TYPE_CLASS) {
02143                 tname = val;
02144         } else {
02145                 tname = NULL;
02146         }
02147 
02148         if (tname) {
02149                 name = dmalloc (strlen (tname) + 1, MDL);
02150                 if (!name)
02151                         log_fatal ("No memory for class name %s.", tname);
02152                 strcpy (name, val);
02153         } else
02154                 name = NULL;
02155 
02156         /* If this is a straight subclass, parse the hash string. */
02157         if (type == CLASS_TYPE_SUBCLASS) {
02158                 token = peek_token (&val, NULL, cfile);
02159                 if (token == STRING) {
02160                         skip_token(&val, &data.len, cfile);
02161                         data.buffer = NULL;
02162 
02163                         if (!buffer_allocate (&data.buffer,
02164                                               data.len + 1, MDL)) {
02165                                 if (pc)
02166                                         class_dereference (&pc, MDL);
02167                                 
02168                                 return 0;
02169                         }
02170                         data.terminated = 1;
02171                         data.data = &data.buffer -> data [0];
02172                         memcpy ((char *)data.buffer -> data, val,
02173                                 data.len + 1);
02174                 } else if (token == NUMBER_OR_NAME || token == NUMBER) {
02175                         memset (&data, 0, sizeof data);
02176                         if (!parse_cshl (&data, cfile)) {
02177                                 if (pc)
02178                                         class_dereference (&pc, MDL);
02179                                 return 0;
02180                         }
02181                 } else {
02182                         parse_warn (cfile, "Expecting string or hex list.");
02183                         if (pc)
02184                                 class_dereference (&pc, MDL);
02185                         return 0;
02186                 }
02187         }
02188 
02189         /* See if there's already a class in the hash table matching the
02190            hash data. */
02191         if (type != CLASS_TYPE_CLASS)
02192                 class_hash_lookup (&class, pc -> hash,
02193                                    (const char *)data.data, data.len, MDL);
02194 
02195         /* If we didn't find an existing class, allocate a new one. */
02196         if (!class) {
02197                 /* Allocate the class structure... */
02198                 if (type == CLASS_TYPE_SUBCLASS) {
02199                         status = subclass_allocate (&class, MDL);
02200                 } else {
02201                         status = class_allocate (&class, MDL);
02202                 }
02203                 if (pc) {
02204                         group_reference (&class -> group, pc -> group, MDL);
02205                         class_reference (&class -> superclass, pc, MDL);
02206                         class -> lease_limit = pc -> lease_limit;
02207                         if (class -> lease_limit) {
02208                                 class -> billed_leases =
02209                                         dmalloc (class -> lease_limit *
02210                                                  sizeof (struct lease *), MDL);
02211                                 if (!class -> billed_leases)
02212                                         log_fatal ("no memory for billing");
02213                                 memset (class -> billed_leases, 0,
02214                                         (class -> lease_limit *
02215                                          sizeof (struct lease *)));
02216                         }
02217                         data_string_copy (&class -> hash_string, &data, MDL);
02218                         if (!pc -> hash &&
02219                             !class_new_hash (&pc->hash, SCLASS_HASH_SIZE, MDL))
02220                                 log_fatal ("No memory for subclass hash.");
02221                         class_hash_add (pc -> hash,
02222                                         (const char *)class -> hash_string.data,
02223                                         class -> hash_string.len,
02224                                         (void *)class, MDL);
02225                 } else {
02226                         if (class->group)
02227                                 group_dereference(&class->group, MDL);
02228                         if (!clone_group (&class -> group, group, MDL))
02229                                 log_fatal ("no memory to clone class group.");
02230                 }
02231 
02232                 /* If this is an implicit vendor or user class, add a
02233                    statement that causes the vendor or user class ID to
02234                    be sent back in the reply. */
02235                 if (type == CLASS_TYPE_VENDOR || type == CLASS_TYPE_USER) {
02236                         stmt = NULL;
02237                         if (!executable_statement_allocate (&stmt, MDL))
02238                                 log_fatal ("no memory for class statement.");
02239                         stmt -> op = supersede_option_statement;
02240                         if (option_cache_allocate (&stmt -> data.option,
02241                                                    MDL)) {
02242                                 stmt -> data.option -> data = data;
02243                                 code = (type == CLASS_TYPE_VENDOR)
02244                                         ? DHO_VENDOR_CLASS_IDENTIFIER
02245                                         : DHO_USER_CLASS;
02246                                 option_code_hash_lookup(
02247                                                 &stmt->data.option->option,
02248                                                         dhcp_universe.code_hash,
02249                                                         &code, 0, MDL);
02250                         }
02251                         class -> statements = stmt;
02252                 }
02253 
02254                 /* Save the name, if there is one. */
02255                 if (class->name != NULL)
02256                         dfree(class->name, MDL);
02257                 class->name = name;
02258         }
02259 
02260         if (type != CLASS_TYPE_CLASS)
02261                 data_string_forget(&data, MDL);
02262 
02263         /* Spawned classes don't have to have their own settings. */
02264         if (class -> superclass) {
02265                 token = peek_token (&val, NULL, cfile);
02266                 if (token == SEMI) {
02267                         skip_token(&val, NULL, cfile);
02268 
02269                         if (cp)
02270                                 status = class_reference (cp, class, MDL);
02271                         class_dereference (&class, MDL);
02272                         if (pc)
02273                                 class_dereference (&pc, MDL);
02274                         return cp ? (status == ISC_R_SUCCESS) : 1;
02275                 }
02276                 /* Give the subclass its own group. */
02277                 if (!clone_group (&class -> group, class -> group, MDL))
02278                         log_fatal ("can't clone class group.");
02279 
02280         }
02281 
02282         if (!parse_lbrace (cfile)) {
02283                 class_dereference (&class, MDL);
02284                 if (pc)
02285                         class_dereference (&pc, MDL);
02286                 return 0;
02287         }
02288 
02289         do {
02290                 token = peek_token (&val, NULL, cfile);
02291                 if (token == RBRACE) {
02292                         skip_token(&val, NULL, cfile);
02293                         break;
02294                 } else if (token == END_OF_FILE) {
02295                         skip_token(&val, NULL, cfile);
02296                         parse_warn (cfile, "unexpected end of file");
02297                         break;
02298                 } else if (token == DYNAMIC) {
02299                         class->flags |= CLASS_DECL_DYNAMIC;
02300                         skip_token(&val, NULL, cfile);
02301                         if (!parse_semi (cfile))
02302                                 break;
02303                         continue;
02304                 } else if (token == TOKEN_DELETED) {
02305                         class->flags |= CLASS_DECL_DELETED;
02306                         skip_token(&val, NULL, cfile);
02307                         if (!parse_semi (cfile))
02308                                 break;
02309                         continue;
02310                 } else if (token == MATCH) {
02311                         if (pc) {
02312                                 parse_warn (cfile,
02313                                             "invalid match in subclass.");
02314                                 skip_to_semi (cfile);
02315                                 break;
02316                         }
02317                         skip_token(&val, NULL, cfile);
02318                         token = peek_token (&val, NULL, cfile);
02319                         if (token != IF)
02320                                 goto submatch;
02321                         skip_token(&val, NULL, cfile);
02322                         if (matchedonce) {
02323                                 parse_warn(cfile, "A class may only have "
02324                                                   "one 'match if' clause.");
02325                                 skip_to_semi(cfile);
02326                                 break;
02327                         }
02328                         matchedonce = 1;
02329                         if (class->expr)
02330                                 expression_dereference(&class->expr, MDL);
02331                         if (!parse_boolean_expression (&class->expr, cfile,
02332                                                        &lose)) {
02333                                 if (!lose) {
02334                                         parse_warn (cfile,
02335                                                     "expecting boolean expr.");
02336                                         skip_to_semi (cfile);
02337                                 }
02338                         } else {
02339 #if defined (DEBUG_EXPRESSION_PARSE)
02340                                 print_expression ("class match",
02341                                                   class -> expr);
02342 #endif
02343                                 parse_semi (cfile);
02344                         }
02345                 } else if (token == SPAWN) {
02346                         skip_token(&val, NULL, cfile);
02347                         if (pc) {
02348                                 parse_warn (cfile,
02349                                             "invalid spawn in subclass.");
02350                                 skip_to_semi (cfile);
02351                                 break;
02352                         }
02353                         class -> spawning = 1;
02354                         token = next_token (&val, NULL, cfile);
02355                         if (token != WITH) {
02356                                 parse_warn (cfile,
02357                                             "expecting with after spawn");
02358                                 skip_to_semi (cfile);
02359                                 break;
02360                         }
02361                       submatch:
02362                         if (submatchedonce) {
02363                                 parse_warn (cfile,
02364                                             "can't override existing %s.",
02365                                             "submatch/spawn");
02366                                 skip_to_semi (cfile);
02367                                 break;
02368                         }
02369                         submatchedonce = 1;
02370                         if (class->submatch)
02371                                 expression_dereference(&class->submatch, MDL);
02372                         if (!parse_data_expression (&class -> submatch,
02373                                                     cfile, &lose)) {
02374                                 if (!lose) {
02375                                         parse_warn (cfile,
02376                                                     "expecting data expr.");
02377                                         skip_to_semi (cfile);
02378                                 }
02379                         } else {
02380 #if defined (DEBUG_EXPRESSION_PARSE)
02381                                 print_expression ("class submatch",
02382                                                   class -> submatch);
02383 #endif
02384                                 parse_semi (cfile);
02385                         }
02386                 } else if (token == LEASE) {
02387                         skip_token(&val, NULL, cfile);
02388                         token = next_token (&val, NULL, cfile);
02389                         if (token != LIMIT) {
02390                                 parse_warn (cfile, "expecting \"limit\"");
02391                                 if (token != SEMI)
02392                                         skip_to_semi (cfile);
02393                                 break;
02394                         }
02395                         token = next_token (&val, NULL, cfile);
02396                         if (token != NUMBER) {
02397                                 parse_warn (cfile, "expecting a number");
02398                                 if (token != SEMI)
02399                                         skip_to_semi (cfile);
02400                                 break;
02401                         }
02402                         class -> lease_limit = atoi (val);
02403                         if (class->billed_leases)
02404                                 dfree(class->billed_leases, MDL);
02405                         class -> billed_leases =
02406                                 dmalloc (class -> lease_limit *
02407                                          sizeof (struct lease *), MDL);
02408                         if (!class -> billed_leases)
02409                                 log_fatal ("no memory for billed leases.");
02410                         memset (class -> billed_leases, 0,
02411                                 (class -> lease_limit *
02412                                  sizeof (struct lease *)));
02413                         have_billing_classes = 1;
02414                         parse_semi (cfile);
02415                 } else {
02416                         declaration = parse_statement (cfile, class -> group,
02417                                                        CLASS_DECL, NULL,
02418                                                        declaration);
02419                 }
02420         } while (1);
02421 
02422         if (class->flags & CLASS_DECL_DELETED) {
02423                 if (type == CLASS_TYPE_CLASS) {
02424                         struct class *theclass = NULL;
02425                 
02426                         status = find_class(&theclass, class->name, MDL);
02427                         if (status == ISC_R_SUCCESS) {
02428                                 delete_class(theclass, 0);
02429                                 class_dereference(&theclass, MDL);
02430                         }
02431                 } else {
02432                         class_hash_delete(pc->hash,
02433                                           (char *)class->hash_string.data,
02434                                           class->hash_string.len, MDL);
02435                 }
02436         } else if (type == CLASS_TYPE_CLASS && new) {
02437                 if (!collections -> classes)
02438                         class_reference (&collections -> classes, class, MDL);
02439                 else {
02440                         struct class *c;
02441                         for (c = collections -> classes;
02442                              c -> nic; c = c -> nic)
02443                                 ;
02444                         class_reference (&c -> nic, class, MDL);
02445                 }
02446         }
02447 
02448         if (cp)                         /* should always be 0??? */
02449                 status = class_reference (cp, class, MDL);
02450         class_dereference (&class, MDL);
02451         if (pc)
02452                 class_dereference (&pc, MDL);
02453         return cp ? (status == ISC_R_SUCCESS) : 1;
02454 }
02455 
02456 /* shared-network-declaration :==
02457                         hostname LBRACE declarations parameters RBRACE */
02458 
02459 void parse_shared_net_declaration (cfile, group)
02460         struct parse *cfile;
02461         struct group *group;
02462 {
02463         const char *val;
02464         enum dhcp_token token;
02465         struct shared_network *share;
02466         char *name;
02467         int declaration = 0;
02468         isc_result_t status;
02469 
02470         share = (struct shared_network *)0;
02471         status = shared_network_allocate (&share, MDL);
02472         if (status != ISC_R_SUCCESS)
02473                 log_fatal ("Can't allocate shared subnet: %s",
02474                            isc_result_totext (status));
02475         if (clone_group (&share -> group, group, MDL) == 0) {
02476                 log_fatal ("Can't clone group for shared net");
02477         }
02478         shared_network_reference (&share -> group -> shared_network,
02479                                   share, MDL);
02480 
02481         /* Get the name of the shared network... */
02482         token = peek_token (&val, (unsigned *)0, cfile);
02483         if (token == STRING) {
02484                 skip_token(&val, (unsigned *)0, cfile);
02485 
02486                 if (val [0] == 0) {
02487                         parse_warn (cfile, "zero-length shared network name");
02488                         val = "<no-name-given>";
02489                 }
02490                 name = dmalloc (strlen (val) + 1, MDL);
02491                 if (!name)
02492                         log_fatal ("no memory for shared network name");
02493                 strcpy (name, val);
02494         } else {
02495                 name = parse_host_name (cfile);
02496                 if (!name) {
02497                         parse_warn (cfile,
02498                                      "expecting a name for shared-network");
02499                         skip_to_semi (cfile);
02500                         shared_network_dereference (&share, MDL);
02501                         return;
02502                 }
02503         }
02504         share -> name = name;
02505 
02506         if (!parse_lbrace (cfile)) {
02507                 shared_network_dereference (&share, MDL);
02508                 return;
02509         }
02510 
02511         do {
02512                 token = peek_token (&val, (unsigned *)0, cfile);
02513                 if (token == RBRACE) {
02514                         skip_token(&val, (unsigned *)0, cfile);
02515                         if (!share -> subnets)
02516                                 parse_warn (cfile,
02517                                             "empty shared-network decl");
02518                         else
02519                                 enter_shared_network (share);
02520                         shared_network_dereference (&share, MDL);
02521                         return;
02522                 } else if (token == END_OF_FILE) {
02523                         skip_token(&val, (unsigned *)0, cfile);
02524                         parse_warn (cfile, "unexpected end of file");
02525                         break;
02526                 } else if (token == INTERFACE) {
02527                         skip_token(&val, (unsigned *)0, cfile);
02528                         token = next_token (&val, (unsigned *)0, cfile);
02529                         new_shared_network_interface (cfile, share, val);
02530                         if (!parse_semi (cfile))
02531                                 break;
02532                         continue;
02533                 }
02534 
02535                 declaration = parse_statement (cfile, share -> group,
02536                                                SHARED_NET_DECL,
02537                                                (struct host_decl *)0,
02538                                                declaration);
02539         } while (1);
02540         shared_network_dereference (&share, MDL);
02541 }
02542 
02543 
02544 static int
02545 common_subnet_parsing(struct parse *cfile, 
02546                       struct shared_network *share,
02547                       struct subnet *subnet) {
02548         enum dhcp_token token;
02549         struct subnet *t, *u;
02550         const char *val;
02551         int declaration = 0;
02552 
02553         enter_subnet(subnet);
02554 
02555         if (!parse_lbrace(cfile)) {
02556                 subnet_dereference(&subnet, MDL);
02557                 return 0;
02558         }
02559 
02560         do {
02561                 token = peek_token(&val, NULL, cfile);
02562                 if (token == RBRACE) {
02563                         skip_token(&val, NULL, cfile);
02564                         break;
02565                 } else if (token == END_OF_FILE) {
02566                         skip_token(&val, NULL, cfile);
02567                         parse_warn (cfile, "unexpected end of file");
02568                         break;
02569                 } else if (token == INTERFACE) {
02570                         skip_token(&val, NULL, cfile);
02571                         token = next_token(&val, NULL, cfile);
02572                         new_shared_network_interface(cfile, share, val);
02573                         if (!parse_semi(cfile))
02574                                 break;
02575                         continue;
02576                 }
02577                 declaration = parse_statement(cfile, subnet->group,
02578                                               SUBNET_DECL,
02579                                               NULL,
02580                                               declaration);
02581         } while (1);
02582 
02583         /* Add the subnet to the list of subnets in this shared net. */
02584         if (share->subnets == NULL) {
02585                 subnet_reference(&share->subnets, subnet, MDL);
02586         } else {
02587                 u = NULL;
02588                 for (t = share->subnets; t->next_sibling; t = t->next_sibling) {
02589                         if (subnet_inner_than(subnet, t, 0)) {
02590                                 subnet_reference(&subnet->next_sibling, t, MDL);
02591                                 if (u) {
02592                                         subnet_dereference(&u->next_sibling,
02593                                                            MDL);
02594                                         subnet_reference(&u->next_sibling,
02595                                                          subnet, MDL);
02596                                 } else {
02597                                         subnet_dereference(&share->subnets,
02598                                                            MDL);
02599                                         subnet_reference(&share->subnets,
02600                                                          subnet, MDL);
02601                                 }
02602                                 subnet_dereference(&subnet, MDL);
02603                                 return 1;
02604                         }
02605                         u = t;
02606                 }
02607                 subnet_reference(&t->next_sibling, subnet, MDL);
02608         }
02609         subnet_dereference(&subnet, MDL);
02610         return 1;
02611 }
02612 
02613 /* subnet-declaration :==
02614         net NETMASK netmask RBRACE parameters declarations LBRACE */
02615 
02616 void parse_subnet_declaration (cfile, share)
02617         struct parse *cfile;
02618         struct shared_network *share;
02619 {
02620         const char *val;
02621         enum dhcp_token token;
02622         struct subnet *subnet;
02623         struct iaddr iaddr;
02624         unsigned char addr [4];
02625         unsigned len = sizeof addr;
02626         isc_result_t status;
02627 
02628         subnet = (struct subnet *)0;
02629         status = subnet_allocate (&subnet, MDL);
02630         if (status != ISC_R_SUCCESS)
02631                 log_fatal ("Allocation of new subnet failed: %s",
02632                            isc_result_totext (status));
02633         shared_network_reference (&subnet -> shared_network, share, MDL);
02634 
02635         /*
02636          * If our parent shared network was implicitly created by the software,
02637          * and not explicitly configured by the user, then we actually put all
02638          * configuration scope in the parent (the shared network and subnet
02639          * share the same {}-level scope).
02640          *
02641          * Otherwise, we clone the parent group and continue as normal.
02642          */
02643         if (share->flags & SHARED_IMPLICIT) {
02644                 group_reference(&subnet->group, share->group, MDL);
02645         } else {
02646                 if (!clone_group(&subnet->group, share->group, MDL)) {
02647                         log_fatal("Allocation of group for new subnet failed.");
02648                 }
02649         }
02650         subnet_reference (&subnet -> group -> subnet, subnet, MDL);
02651 
02652         /* Get the network number... */
02653         if (!parse_numeric_aggregate (cfile, addr, &len, DOT, 10, 8)) {
02654                 subnet_dereference (&subnet, MDL);
02655                 return;
02656         }
02657         memcpy (iaddr.iabuf, addr, len);
02658         iaddr.len = len;
02659         subnet -> net = iaddr;
02660 
02661         token = next_token (&val, (unsigned *)0, cfile);
02662         if (token != NETMASK) {
02663                 parse_warn (cfile, "Expecting netmask");
02664                 skip_to_semi (cfile);
02665                 return;
02666         }
02667 
02668         /* Get the netmask... */
02669         if (!parse_numeric_aggregate (cfile, addr, &len, DOT, 10, 8)) {
02670                 subnet_dereference (&subnet, MDL);
02671                 return;
02672         }
02673         memcpy (iaddr.iabuf, addr, len);
02674         iaddr.len = len;
02675         subnet -> netmask = iaddr;
02676 
02677         /* Validate the network number/netmask pair. */
02678         if (host_addr (subnet -> net, subnet -> netmask)) {
02679                 char *maskstr;
02680 
02681                 maskstr = strdup (piaddr (subnet -> netmask));
02682                 parse_warn (cfile,
02683                    "subnet %s netmask %s: bad subnet number/mask combination.",
02684                             piaddr (subnet -> net), maskstr);
02685                 free(maskstr);
02686                 subnet_dereference (&subnet, MDL);
02687                 skip_to_semi (cfile);
02688                 return;
02689         }
02690 
02691         common_subnet_parsing(cfile, share, subnet);
02692 }
02693 
02694 /* subnet6-declaration :==
02695         net / bits RBRACE parameters declarations LBRACE */
02696 
02697 void
02698 parse_subnet6_declaration(struct parse *cfile, struct shared_network *share) {
02699 #if !defined(DHCPv6)
02700         parse_warn(cfile, "No DHCPv6 support.");
02701         skip_to_semi(cfile);
02702 #else /* defined(DHCPv6) */
02703         struct subnet *subnet;
02704         isc_result_t status;
02705         enum dhcp_token token;
02706         const char *val;
02707         char *endp;
02708         int ofs;
02709         const static int mask[] = { 0x00, 0x80, 0xC0, 0xE0, 
02710                                     0xF0, 0xF8, 0xFC, 0xFE };
02711         struct iaddr iaddr;
02712 
02713         if (local_family != AF_INET6) {
02714                 parse_warn(cfile, "subnet6 statement is only supported "
02715                                   "in DHCPv6 mode.");
02716                 skip_to_semi(cfile);
02717                 return;
02718         }
02719 
02720         subnet = NULL;
02721         status = subnet_allocate(&subnet, MDL);
02722         if (status != ISC_R_SUCCESS) {
02723                 log_fatal("Allocation of new subnet failed: %s",
02724                           isc_result_totext(status));
02725         }
02726         shared_network_reference(&subnet->shared_network, share, MDL);
02727 
02728         /*
02729          * If our parent shared network was implicitly created by the software,
02730          * and not explicitly configured by the user, then we actually put all
02731          * configuration scope in the parent (the shared network and subnet
02732          * share the same {}-level scope).
02733          *
02734          * Otherwise, we clone the parent group and continue as normal.
02735          */
02736         if (share->flags & SHARED_IMPLICIT) {
02737                 group_reference(&subnet->group, share->group, MDL);
02738         } else {
02739                 if (!clone_group(&subnet->group, share->group, MDL)) {
02740                         log_fatal("Allocation of group for new subnet failed.");
02741                 }
02742         }
02743         subnet_reference(&subnet->group->subnet, subnet, MDL);
02744 
02745         if (!parse_ip6_addr(cfile, &subnet->net)) {
02746                 subnet_dereference(&subnet, MDL);
02747                 return;
02748         }
02749 
02750         token = next_token(&val, NULL, cfile);
02751         if (token != SLASH) {
02752                 parse_warn(cfile, "Expecting a '/'.");
02753                 skip_to_semi(cfile);
02754                 return;
02755         }
02756 
02757         token = next_token(&val, NULL, cfile);
02758         if (token != NUMBER) {
02759                 parse_warn(cfile, "Expecting a number.");
02760                 skip_to_semi(cfile);
02761                 return;
02762         }
02763 
02764         subnet->prefix_len = strtol(val, &endp, 10);
02765         if ((subnet->prefix_len < 0) || 
02766             (subnet->prefix_len > 128) || 
02767             (*endp != '\0')) {
02768                 parse_warn(cfile, "Expecting a number between 0 and 128.");
02769                 skip_to_semi(cfile);
02770                 return;
02771         }
02772 
02773         if (!is_cidr_mask_valid(&subnet->net, subnet->prefix_len)) {
02774                 parse_warn(cfile, "New subnet mask too short.");
02775                 skip_to_semi(cfile);
02776                 return;
02777         }
02778 
02779         /* 
02780          * Create a netmask. 
02781          */
02782         subnet->netmask.len = 16;
02783         ofs = subnet->prefix_len / 8;
02784         if (ofs < subnet->netmask.len) {
02785                 subnet->netmask.iabuf[ofs] = mask[subnet->prefix_len % 8];
02786         }
02787         while (--ofs >= 0) {
02788                 subnet->netmask.iabuf[ofs] = 0xFF;
02789         }
02790 
02791         /* Validate the network number/netmask pair. */
02792         iaddr = subnet_number(subnet->net, subnet->netmask);
02793         if (memcmp(&iaddr, &subnet->net, 16) != 0) {
02794                 parse_warn(cfile,
02795                    "subnet %s/%d: prefix not long enough for address.",
02796                             piaddr(subnet->net), subnet->prefix_len);
02797                 subnet_dereference(&subnet, MDL);
02798                 skip_to_semi(cfile);
02799                 return;
02800         }
02801 
02802         if (!common_subnet_parsing(cfile, share, subnet)) {
02803                 return;
02804         }
02805 #endif /* defined(DHCPv6) */
02806 }
02807 
02808 /* group-declaration :== RBRACE parameters declarations LBRACE */
02809 
02810 void parse_group_declaration (cfile, group)
02811         struct parse *cfile;
02812         struct group *group;
02813 {
02814         const char *val;
02815         enum dhcp_token token;
02816         struct group *g;
02817         int declaration = 0;
02818         struct group_object *t = NULL;
02819         isc_result_t status;
02820         char *name = NULL;
02821         int deletedp = 0;
02822         int dynamicp = 0;
02823         int staticp = 0;
02824 
02825         g = NULL;
02826         if (!clone_group(&g, group, MDL))
02827                 log_fatal("no memory for explicit group.");
02828 
02829         token = peek_token(&val, NULL, cfile);
02830         if (is_identifier (token) || token == STRING) {
02831                 skip_token(&val, NULL, cfile);
02832                 
02833                 name = dmalloc(strlen(val) + 1, MDL);
02834                 if (!name)
02835                         log_fatal("no memory for group decl name %s", val);
02836                 strcpy(name, val);
02837         }               
02838 
02839         if (!parse_lbrace(cfile)) {
02840                 group_dereference(&g, MDL);
02841                 return;
02842         }
02843 
02844         do {
02845                 token = peek_token(&val, NULL, cfile);
02846                 if (token == RBRACE) {
02847                         skip_token(&val, NULL, cfile);
02848                         break;
02849                 } else if (token == END_OF_FILE) {
02850                         skip_token(&val, NULL, cfile);
02851                         parse_warn(cfile, "unexpected end of file");
02852                         break;
02853                 } else if (token == TOKEN_DELETED) {
02854                         skip_token(&val, NULL, cfile);
02855                         parse_semi(cfile);
02856                         deletedp = 1;
02857                 } else if (token == DYNAMIC) {
02858                         skip_token(&val, NULL, cfile);
02859                         parse_semi(cfile);
02860                         dynamicp = 1;
02861                 } else if (token == STATIC) {
02862                         skip_token(&val, NULL, cfile);
02863                         parse_semi(cfile);
02864                         staticp = 1;
02865                 }
02866                 declaration = parse_statement(cfile, g, GROUP_DECL,
02867                                               NULL, declaration);
02868         } while (1);
02869 
02870         if (name) {
02871                 if (deletedp) {
02872                         if (group_name_hash) {
02873                                 t = NULL;
02874                                 if (group_hash_lookup(&t, group_name_hash,
02875                                                       name,
02876                                                       strlen(name), MDL)) {
02877                                         delete_group(t, 0);
02878                                 }
02879                         }
02880                 } else {
02881                         t = NULL;
02882                         status = group_object_allocate(&t, MDL);
02883                         if (status != ISC_R_SUCCESS)
02884                                 log_fatal("no memory for group decl %s: %s",
02885                                           val, isc_result_totext(status));
02886                         group_reference(&t->group, g, MDL);
02887                         t->name = name;
02888                         /* no need to include deletedp as it's handled above */
02889                         t->flags = ((staticp ? GROUP_OBJECT_STATIC : 0) |
02890                                     (dynamicp ? GROUP_OBJECT_DYNAMIC : 0));
02891                         supersede_group(t, 0);
02892                 }
02893                 if (t != NULL)
02894                         group_object_dereference(&t, MDL);
02895         }
02896 }
02897 
02898 /* fixed-addr-parameter :== ip-addrs-or-hostnames SEMI
02899    ip-addrs-or-hostnames :== ip-addr-or-hostname
02900                            | ip-addrs-or-hostnames ip-addr-or-hostname */
02901 
02902 int
02903 parse_fixed_addr_param(struct option_cache **oc, 
02904                        struct parse *cfile, 
02905                        enum dhcp_token type) {
02906         int parse_ok;
02907         const char *val;
02908         enum dhcp_token token;
02909         struct expression *expr = NULL;
02910         struct expression *tmp, *new;
02911         int status;
02912 
02913         do {
02914                 tmp = NULL;
02915                 if (type == FIXED_ADDR) {
02916                         parse_ok = parse_ip_addr_or_hostname(&tmp, cfile, 1);
02917                 } else {
02918                         /* INSIST(type == FIXED_ADDR6); */
02919                         parse_ok = parse_ip6_addr_expr(&tmp, cfile);
02920                 }
02921                 if (parse_ok) {
02922                         if (expr != NULL) {
02923                                 new = NULL;
02924                                 status = make_concat(&new, expr, tmp);
02925                                 expression_dereference(&expr, MDL);
02926                                 expression_dereference(&tmp, MDL);
02927                                 if (!status) {
02928                                         return 0;
02929                                 }
02930                                 expr = new;
02931                         } else {
02932                                 expr = tmp;
02933                         }
02934                 } else {
02935                         if (expr != NULL) {
02936                                 expression_dereference (&expr, MDL);
02937                         }
02938                         return 0;
02939                 }
02940                 token = peek_token(&val, NULL, cfile);
02941                 if (token == COMMA) {
02942                         token = next_token(&val, NULL, cfile);
02943                 }
02944         } while (token == COMMA);
02945 
02946         if (!parse_semi(cfile)) {
02947                 if (expr) {
02948                         expression_dereference (&expr, MDL);
02949                 }
02950                 return 0;
02951         }
02952 
02953         status = option_cache(oc, NULL, expr, NULL, MDL);
02954         expression_dereference(&expr, MDL);
02955         return status;
02956 }
02957 
02958 /* lease_declaration :== LEASE ip_address LBRACE lease_parameters RBRACE
02959 
02960    lease_parameters :== <nil>
02961                       | lease_parameter
02962                       | lease_parameters lease_parameter
02963 
02964    lease_parameter :== STARTS date
02965                      | ENDS date
02966                      | TIMESTAMP date
02967                      | HARDWARE hardware-parameter
02968                      | UID hex_numbers SEMI
02969                      | HOSTNAME hostname SEMI
02970                      | CLIENT_HOSTNAME hostname SEMI
02971                      | CLASS identifier SEMI
02972                      | DYNAMIC_BOOTP SEMI */
02973 
02974 int parse_lease_declaration (struct lease **lp, struct parse *cfile)
02975 {
02976         const char *val;
02977         enum dhcp_token token;
02978         unsigned char addr [4];
02979         unsigned len = sizeof addr;
02980         int seenmask = 0;
02981         int seenbit;
02982         char tbuf [32];
02983         struct lease *lease;
02984         struct executable_statement *on;
02985         int lose;
02986         TIME t;
02987         int noequal, newbinding;
02988         struct binding *binding;
02989         struct binding_value *nv;
02990         isc_result_t status;
02991         struct option_cache *oc;
02992         pair *p;
02993         binding_state_t new_state;
02994         unsigned buflen = 0;
02995         struct class *class;
02996 
02997         lease = (struct lease *)0;
02998         status = lease_allocate (&lease, MDL);
02999         if (status != ISC_R_SUCCESS)
03000                 return 0;
03001 
03002         /* Get the address for which the lease has been issued. */
03003         if (!parse_numeric_aggregate (cfile, addr, &len, DOT, 10, 8)) {
03004                 lease_dereference (&lease, MDL);
03005                 return 0;
03006         }
03007         memcpy (lease -> ip_addr.iabuf, addr, len);
03008         lease -> ip_addr.len = len;
03009 
03010         if (!parse_lbrace (cfile)) {
03011                 lease_dereference (&lease, MDL);
03012                 return 0;
03013         }
03014 
03015         do {
03016                 token = next_token (&val, (unsigned *)0, cfile);
03017                 if (token == RBRACE)
03018                         break;
03019                 else if (token == END_OF_FILE) {
03020                         parse_warn (cfile, "unexpected end of file");
03021                         break;
03022                 }
03023                 strncpy (tbuf, val, sizeof tbuf);
03024                 tbuf [(sizeof tbuf) - 1] = 0;
03025 
03026                 /* Parse any of the times associated with the lease. */
03027                 switch (token) {
03028                       case STARTS:
03029                       case ENDS:
03030                       case TIMESTAMP:
03031                       case TSTP:
03032                       case TSFP:
03033                       case ATSFP:
03034                       case CLTT:
03035                         t = parse_date (cfile);
03036                         switch (token) {
03037                               case STARTS:
03038                                 seenbit = 1;
03039                                 lease -> starts = t;
03040                                 break;
03041                         
03042                               case ENDS:
03043                                 seenbit = 2;
03044                                 lease -> ends = t;
03045                                 break;
03046                                 
03047                               case TSTP:
03048                                 seenbit = 65536;
03049                                 lease -> tstp = t;
03050                                 break;
03051                                 
03052                               case TSFP:
03053                                 seenbit = 131072;
03054                                 lease -> tsfp = t;
03055                                 break;
03056 
03057                               case ATSFP:
03058                                 seenbit = 262144;
03059                                 lease->atsfp = t;
03060                                 break;
03061                                 
03062                               case CLTT:
03063                                 seenbit = 524288;
03064                                 lease -> cltt = t;
03065                                 break;
03066                                 
03067                               default: /* for gcc, we'll never get here. */
03068                                 log_fatal ("Impossible error at %s:%d.", MDL);
03069                                 return 0;
03070                         }
03071                         break;
03072 
03073                         /* Colon-separated hexadecimal octets... */
03074                       case UID:
03075                         seenbit = 8;
03076                         token = peek_token (&val, (unsigned *)0, cfile);
03077                         if (token == STRING) {
03078                                 unsigned char *tuid;
03079                                 skip_token(&val, &buflen, cfile);
03080                                 if (buflen < sizeof lease -> uid_buf) {
03081                                         tuid = lease -> uid_buf;
03082                                         lease -> uid_max =
03083                                                 sizeof lease -> uid_buf;
03084                                 } else {
03085                                         tuid = ((unsigned char *)
03086                                                 dmalloc (buflen, MDL));
03087                                         if (!tuid) {
03088                                                 log_error ("no space for uid");
03089                                                 lease_dereference (&lease,
03090                                                                    MDL);
03091                                                 return 0;
03092                                         }
03093                                         lease -> uid_max = buflen;
03094                                 }
03095                                 lease -> uid_len = buflen;
03096                                 memcpy (tuid, val, lease -> uid_len);
03097                                 lease -> uid = tuid;
03098                         } else {
03099                                 buflen = 0;
03100                                 lease -> uid = (parse_numeric_aggregate
03101                                                 (cfile, (unsigned char *)0,
03102                                                  &buflen, ':', 16, 8));
03103                                 if (!lease -> uid) {
03104                                         lease_dereference (&lease, MDL);
03105                                         return 0;
03106                                 }
03107                                 lease -> uid_len = buflen;
03108                                 lease -> uid_max = buflen;
03109                                 if (lease -> uid_len == 0) {
03110                                         lease -> uid = (unsigned char *)0;
03111                                         parse_warn (cfile, "zero-length uid");
03112                                         seenbit = 0;
03113                                         parse_semi (cfile);
03114                                         break;
03115                                 }
03116                         }
03117                         parse_semi (cfile);
03118                         if (!lease -> uid) {
03119                                 log_fatal ("No memory for lease uid");
03120                         }
03121                         break;
03122 
03123                       case CLASS:
03124                         seenbit = 32;
03125                         token = next_token (&val, (unsigned *)0, cfile);
03126                         if (!is_identifier (token)) {
03127                                 if (token != SEMI)
03128                                         skip_to_rbrace (cfile, 1);
03129                                 lease_dereference (&lease, MDL);
03130                                 return 0;
03131                         }
03132                         parse_semi (cfile);
03133                         /* for now, we aren't using this. */
03134                         break;
03135 
03136                       case HARDWARE:
03137                         seenbit = 64;
03138                         parse_hardware_param (cfile,
03139                                               &lease -> hardware_addr);
03140                         break;
03141 
03142                       case TOKEN_RESERVED:
03143                         seenbit = 0;
03144                         lease->flags |= RESERVED_LEASE;
03145                         parse_semi(cfile);
03146                         break;
03147 
03148                       case DYNAMIC_BOOTP:
03149                         seenbit = 0;
03150                         lease -> flags |= BOOTP_LEASE;
03151                         parse_semi (cfile);
03152                         break;
03153 
03154                         /* XXX: Reverse compatibility? */
03155                       case TOKEN_ABANDONED:
03156                         seenbit = 256;
03157                         lease -> binding_state = FTS_ABANDONED;
03158                         lease -> next_binding_state = FTS_ABANDONED;
03159                         parse_semi (cfile);
03160                         break;
03161 
03162                       case TOKEN_NEXT:
03163                         seenbit = 128;
03164                         token = next_token (&val, (unsigned *)0, cfile);
03165                         if (token != BINDING) {
03166                                 parse_warn (cfile, "expecting 'binding'");
03167                                 skip_to_semi (cfile);
03168                                 break;
03169                         }
03170                         goto do_binding_state;
03171 
03172                       case REWIND:
03173                         seenbit = 512;
03174                         token = next_token(&val, NULL, cfile);
03175                         if (token != BINDING) {
03176                                 parse_warn(cfile, "expecting 'binding'");
03177                                 skip_to_semi(cfile);
03178                                 break;
03179                         }
03180                         goto do_binding_state;
03181 
03182                       case BINDING:
03183                         seenbit = 256;
03184 
03185                       do_binding_state:
03186                         token = next_token (&val, (unsigned *)0, cfile);
03187                         if (token != STATE) {
03188                                 parse_warn (cfile, "expecting 'state'");
03189                                 skip_to_semi (cfile);
03190                                 break;
03191                         }
03192                         token = next_token (&val, (unsigned *)0, cfile);
03193                         switch (token) {
03194                               case TOKEN_ABANDONED:
03195                                 new_state = FTS_ABANDONED;
03196                                 break;
03197                               case TOKEN_FREE:
03198                                 new_state = FTS_FREE;
03199                                 break;
03200                               case TOKEN_ACTIVE:
03201                                 new_state = FTS_ACTIVE;
03202                                 break;
03203                               case TOKEN_EXPIRED:
03204                                 new_state = FTS_EXPIRED;
03205                                 break;
03206                               case TOKEN_RELEASED:
03207                                 new_state = FTS_RELEASED;
03208                                 break;
03209                               case TOKEN_RESET:
03210                                 new_state = FTS_RESET;
03211                                 break;
03212                               case TOKEN_BACKUP:
03213                                 new_state = FTS_BACKUP;
03214                                 break;
03215 
03216                                 /* RESERVED and BOOTP states preserved for
03217                                  * compatibleness with older versions.
03218                                  */
03219                               case TOKEN_RESERVED:
03220                                 new_state = FTS_ACTIVE;
03221                                 lease->flags |= RESERVED_LEASE;
03222                                 break;
03223                               case TOKEN_BOOTP:
03224                                 new_state = FTS_ACTIVE;
03225                                 lease->flags |= BOOTP_LEASE;
03226                                 break;
03227 
03228                               default:
03229                                 parse_warn (cfile,
03230                                             "%s: expecting a binding state.",
03231                                             val);
03232                                 skip_to_semi (cfile);
03233                                 return 0;
03234                         }
03235 
03236                         if (seenbit == 256) {
03237                                 lease -> binding_state = new_state;
03238 
03239                                 /*
03240                                  * Apply default/conservative next/rewind
03241                                  * binding states if they haven't been set
03242                                  * yet.  These defaults will be over-ridden if
03243                                  * they are set later in parsing.
03244                                  */
03245                                 if (!(seenmask & 128))
03246                                     lease->next_binding_state = new_state;
03247 
03248                                 /* The most conservative rewind state. */
03249                                 if (!(seenmask & 512))
03250                                     lease->rewind_binding_state = new_state;
03251                         } else if (seenbit == 128)
03252                                 lease -> next_binding_state = new_state;
03253                         else if (seenbit == 512)
03254                                 lease->rewind_binding_state = new_state;
03255                         else
03256                                 log_fatal("Impossible condition at %s:%d.",
03257                                           MDL);
03258 
03259                         parse_semi (cfile);
03260                         break;
03261 
03262                       case CLIENT_HOSTNAME:
03263                         seenbit = 1024;
03264                         token = peek_token (&val, (unsigned *)0, cfile);
03265                         if (token == STRING) {
03266                                 if (!parse_string (cfile,
03267                                                    &lease -> client_hostname,
03268                                                    (unsigned *)0)) {
03269                                         lease_dereference (&lease, MDL);
03270                                         return 0;
03271                                 }
03272                         } else {
03273                                 lease -> client_hostname =
03274                                         parse_host_name (cfile);
03275                                 if (lease -> client_hostname)
03276                                         parse_semi (cfile);
03277                                 else {
03278                                         parse_warn (cfile,
03279                                                     "expecting a hostname.");
03280                                         skip_to_semi (cfile);
03281                                         lease_dereference (&lease, MDL);
03282                                         return 0;
03283                                 }
03284                         }
03285                         break;
03286                         
03287                       case BILLING:
03288                         seenbit = 2048;
03289                         class = (struct class *)0;
03290                         token = next_token (&val, (unsigned *)0, cfile);
03291                         if (token == CLASS) {
03292                                 token = next_token (&val,
03293                                                     (unsigned *)0, cfile);
03294                                 if (token != STRING) {
03295                                         parse_warn (cfile, "expecting string");
03296                                         if (token != SEMI)
03297                                                 skip_to_semi (cfile);
03298                                         token = BILLING;
03299                                         break;
03300                                 }
03301                                 if (lease -> billing_class)
03302                                     class_dereference (&lease -> billing_class,
03303                                                        MDL);
03304                                 find_class (&class, val, MDL);
03305                                 if (!class)
03306                                         parse_warn (cfile,
03307                                                     "unknown class %s", val);
03308                                 parse_semi (cfile);
03309                         } else if (token == SUBCLASS) {
03310                                 if (lease -> billing_class)
03311                                     class_dereference (&lease -> billing_class,
03312                                                        MDL);
03313                                 parse_class_declaration(&class, cfile, NULL,
03314                                                         CLASS_TYPE_SUBCLASS);
03315                         } else {
03316                                 parse_warn (cfile, "expecting \"class\"");
03317                                 if (token != SEMI)
03318                                         skip_to_semi (cfile);
03319                         }
03320                         if (class) {
03321                                 class_reference (&lease -> billing_class,
03322                                                  class, MDL);
03323                                 class_dereference (&class, MDL);
03324                         }
03325                         break;
03326 
03327                       case ON:
03328                         on = (struct executable_statement *)0;
03329                         lose = 0;
03330                         if (!parse_on_statement (&on, cfile, &lose)) {
03331                                 skip_to_rbrace (cfile, 1);
03332                                 lease_dereference (&lease, MDL);
03333                                 return 0;
03334                         }
03335                         seenbit = 0;
03336                         if ((on->data.on.evtypes & ON_EXPIRY) &&
03337                             on->data.on.statements) {
03338                                 seenbit |= 16384;
03339                                 executable_statement_reference
03340                                         (&lease->on_star.on_expiry,
03341                                          on->data.on.statements, MDL);
03342                         }
03343                         if ((on->data.on.evtypes & ON_RELEASE) &&
03344                             on->data.on.statements) {
03345                                 seenbit |= 32768;
03346                                 executable_statement_reference
03347                                         (&lease->on_star.on_release,
03348                                          on->data.on.statements, MDL);
03349                         }
03350                         executable_statement_dereference (&on, MDL);
03351                         break;
03352 
03353                       case OPTION:
03354                       case SUPERSEDE:
03355                         noequal = 0;
03356                         seenbit = 0;
03357                         oc = (struct option_cache *)0;
03358                         if (parse_option_decl (&oc, cfile)) {
03359                             if (oc -> option -> universe !=
03360                                 &agent_universe) {
03361                                     parse_warn (cfile,
03362                                                 "agent option expected.");
03363                                     option_cache_dereference (&oc, MDL);
03364                                     break;
03365                             }
03366                             if (!lease -> agent_options &&
03367                                 !(option_chain_head_allocate
03368                                   (&lease -> agent_options, MDL))) {
03369                                 log_error ("no memory to stash agent option");
03370                                 break;
03371                             }
03372                             for (p = &lease -> agent_options -> first;
03373                                  *p; p = &((*p) -> cdr))
03374                                     ;
03375                             *p = cons (0, 0);
03376                             option_cache_reference (((struct option_cache **)
03377                                                      &((*p) -> car)), oc, MDL);
03378                             option_cache_dereference (&oc, MDL);
03379                         }
03380                         break;
03381 
03382                       case TOKEN_SET:
03383                         noequal = 0;
03384                         
03385                         token = next_token (&val, (unsigned *)0, cfile);
03386                         if (token != NAME && token != NUMBER_OR_NAME) {
03387                                 parse_warn (cfile,
03388                                             "%s can't be a variable name",
03389                                             val);
03390                               badset:
03391                                 skip_to_semi (cfile);
03392                                 lease_dereference (&lease, MDL);
03393                                 return 0;
03394                         }
03395                         
03396                         seenbit = 0;
03397                       special_set:
03398                         if (lease -> scope)
03399                                 binding = find_binding (lease -> scope, val);
03400                         else
03401                                 binding = (struct binding *)0;
03402 
03403                         if (!binding) {
03404                             if (!lease -> scope)
03405                                 if (!(binding_scope_allocate
03406                                       (&lease -> scope, MDL)))
03407                                         log_fatal ("no memory for scope");
03408                             binding = dmalloc (sizeof *binding, MDL);
03409                             if (!binding)
03410                                     log_fatal ("No memory for lease %s.",
03411                                                "binding");
03412                             memset (binding, 0, sizeof *binding);
03413                             binding -> name =
03414                                     dmalloc (strlen (val) + 1, MDL);
03415                             if (!binding -> name)
03416                                     log_fatal ("No memory for binding %s.",
03417                                                "name");
03418                             strcpy (binding -> name, val);
03419                             newbinding = 1;
03420                         } else  {
03421                             newbinding = 0;
03422                         }
03423 
03424                         nv = NULL;
03425                         if (!binding_value_allocate(&nv, MDL))
03426                                 log_fatal("no memory for binding value.");
03427 
03428                         if (!noequal) {
03429                             token = next_token (&val, (unsigned *)0, cfile);
03430                             if (token != EQUAL) {
03431                                 parse_warn (cfile,
03432                                             "expecting '=' in set statement.");
03433                                 goto badset;
03434                             }
03435                         }
03436 
03437                         if (!parse_binding_value(cfile, nv)) {
03438                                 binding_value_dereference(&nv, MDL);
03439                                 lease_dereference(&lease, MDL);
03440                                 return 0;
03441                         }
03442 
03443                         if (newbinding) {
03444                                 binding_value_reference(&binding->value,
03445                                                         nv, MDL);
03446                                 binding->next = lease->scope->bindings;
03447                                 lease->scope->bindings = binding;
03448                         } else {
03449                                 binding_value_dereference(&binding->value, MDL);
03450                                 binding_value_reference(&binding->value,
03451                                                         nv, MDL);
03452                         }
03453 
03454                         binding_value_dereference(&nv, MDL);
03455                         parse_semi(cfile);
03456                         break;
03457 
03458                         /* case NAME: */
03459                       default:
03460                         if (!strcasecmp (val, "ddns-fwd-name")) {
03461                                 seenbit = 4096;
03462                                 noequal = 1;
03463                                 goto special_set;
03464                         } else if (!strcasecmp (val, "ddns-rev-name")) {
03465                                 seenbit = 8192;
03466                                 noequal = 1;
03467                                 goto special_set;
03468                         } else
03469                                 parse_warn(cfile, "Unexpected configuration "
03470                                                   "directive.");
03471                         skip_to_semi (cfile);
03472                         seenbit = 0;
03473                         lease_dereference (&lease, MDL);
03474                         return 0;
03475                 }
03476 
03477                 if (seenmask & seenbit) {
03478                         parse_warn (cfile,
03479                                     "Too many %s parameters in lease %s\n",
03480                                     tbuf, piaddr (lease -> ip_addr));
03481                 } else
03482                         seenmask |= seenbit;
03483 
03484         } while (1);
03485 
03486         /* If no binding state is specified, make one up. */
03487         if (!(seenmask & 256)) {
03488                 if (lease->ends > cur_time ||
03489                     lease->on_star.on_expiry || lease->on_star.on_release)
03490                         lease->binding_state = FTS_ACTIVE;
03491 #if defined (FAILOVER_PROTOCOL)
03492                 else if (lease->pool && lease->pool->failover_peer)
03493                         lease->binding_state = FTS_EXPIRED;
03494 #endif
03495                 else
03496                         lease->binding_state = FTS_FREE;
03497                 if (lease->binding_state == FTS_ACTIVE) {
03498 #if defined (FAILOVER_PROTOCOL)
03499                         if (lease->pool && lease->pool->failover_peer)
03500                                 lease->next_binding_state = FTS_EXPIRED;
03501                         else
03502 #endif
03503                                 lease->next_binding_state = FTS_FREE;
03504                 } else
03505                         lease->next_binding_state = lease->binding_state;
03506 
03507                 /* The most conservative rewind state implies no rewind. */
03508                 lease->rewind_binding_state = lease->binding_state;
03509         }
03510 
03511         if (!(seenmask & 65536))
03512                 lease->tstp = lease->ends;
03513 
03514         lease_reference (lp, lease, MDL);
03515         lease_dereference (&lease, MDL);
03516         return 1;
03517 }
03518 
03519 /* Parse the right side of a 'binding value'.
03520  *
03521  * set foo = "bar"; is a string
03522  * set foo = false; is a boolean
03523  * set foo = %31; is a numeric value.
03524  */
03525 static int
03526 parse_binding_value(struct parse *cfile, struct binding_value *value)
03527 {
03528         struct data_string *data;
03529         unsigned char *s;
03530         const char *val;
03531         unsigned buflen;
03532         int token;
03533 
03534         if ((cfile == NULL) || (value == NULL))
03535                 log_fatal("Invalid arguments at %s:%d.", MDL);
03536 
03537         token = peek_token(&val, NULL, cfile);
03538         if (token == STRING) {
03539                 skip_token(&val, &buflen, cfile);
03540 
03541                 value->type = binding_data;
03542                 value->value.data.len = buflen;
03543 
03544                 data = &value->value.data;
03545 
03546                 if (!buffer_allocate(&data->buffer, buflen + 1, MDL))
03547                         log_fatal ("No memory for binding.");
03548 
03549                 memcpy(data->buffer->data, val, buflen + 1);
03550 
03551                 data->data = data->buffer->data;
03552                 data->terminated = 1;
03553         } else if (token == NUMBER_OR_NAME) {
03554                 value->type = binding_data;
03555 
03556                 data = &value->value.data;
03557                 s = parse_numeric_aggregate(cfile, NULL, &data->len,
03558                                             ':', 16, 8);
03559                 if (s == NULL) {
03560                         skip_to_semi(cfile);
03561                         return 0;
03562                 }
03563 
03564                 if (data->len) {
03565                         if (!buffer_allocate(&data->buffer, data->len + 1,
03566                                              MDL))
03567                                 log_fatal("No memory for binding.");
03568 
03569                         memcpy(data->buffer->data, s, data->len);
03570                         data->data = data->buffer->data;
03571 
03572                         dfree (s, MDL);
03573                 }
03574         } else if (token == PERCENT) {
03575                 skip_token(&val, NULL, cfile);
03576                 token = next_token(&val, NULL, cfile);
03577                 if (token != NUMBER) {
03578                         parse_warn(cfile, "expecting decimal number.");
03579                         if (token != SEMI)
03580                                 skip_to_semi(cfile);
03581                         return 0;
03582                 }
03583                 value->type = binding_numeric;
03584                 value->value.intval = atol(val);
03585         } else if (token == NAME) {
03586                 token = next_token(&val, NULL, cfile);
03587                 value->type = binding_boolean;
03588                 if (!strcasecmp(val, "true"))
03589                         value->value.boolean = 1;
03590                 else if (!strcasecmp(val, "false"))
03591                         value->value.boolean = 0;
03592                 else {
03593                         parse_warn(cfile, "expecting true or false");
03594                         if (token != SEMI)
03595                                 skip_to_semi(cfile);
03596                         return 0;
03597                 }
03598         } else {
03599                 parse_warn (cfile, "expecting a constant value.");
03600                 if (token != SEMI)
03601                         skip_to_semi (cfile);
03602                 return 0;
03603         }
03604 
03605         return 1;
03606 }
03607 
03608 /* address-range-declaration :== ip-address ip-address SEMI
03609                                | DYNAMIC_BOOTP ip-address ip-address SEMI */
03610 
03611 void parse_address_range (cfile, group, type, inpool, lpchain)
03612         struct parse *cfile;
03613         struct group *group;
03614         int type;
03615         struct pool *inpool;
03616         struct lease **lpchain;
03617 {
03618         struct iaddr low, high, net;
03619         unsigned char addr [4];
03620         unsigned len = sizeof addr;
03621         enum dhcp_token token;
03622         const char *val;
03623         int dynamic = 0;
03624         struct subnet *subnet;
03625         struct shared_network *share;
03626         struct pool *pool;
03627         isc_result_t status;
03628 
03629         if ((token = peek_token (&val,
03630                                  (unsigned *)0, cfile)) == DYNAMIC_BOOTP) {
03631                 skip_token(&val, (unsigned *)0, cfile);
03632                 dynamic = 1;
03633         }
03634 
03635         /* Get the bottom address in the range... */
03636         if (!parse_numeric_aggregate (cfile, addr, &len, DOT, 10, 8))
03637                 return;
03638         memcpy (low.iabuf, addr, len);
03639         low.len = len;
03640 
03641         /* Only one address? */
03642         token = peek_token (&val, (unsigned *)0, cfile);
03643         if (token == SEMI)
03644                 high = low;
03645         else {
03646         /* Get the top address in the range... */
03647                 if (!parse_numeric_aggregate (cfile, addr, &len, DOT, 10, 8))
03648                         return;
03649                 memcpy (high.iabuf, addr, len);
03650                 high.len = len;
03651         }
03652 
03653         token = next_token (&val, (unsigned *)0, cfile);
03654         if (token != SEMI) {
03655                 parse_warn (cfile, "semicolon expected.");
03656                 skip_to_semi (cfile);
03657                 return;
03658         }
03659 
03660         if (type == SUBNET_DECL) {
03661                 subnet = group -> subnet;
03662                 share = subnet -> shared_network;
03663         } else {
03664                 share = group -> shared_network;
03665                 for (subnet = share -> subnets;
03666                      subnet; subnet = subnet -> next_sibling) {
03667                         net = subnet_number (low, subnet -> netmask);
03668                         if (addr_eq (net, subnet -> net))
03669                                 break;
03670                 }
03671                 if (!subnet) {
03672                         parse_warn (cfile, "address range not on network %s",
03673                                     group -> shared_network -> name);
03674                         log_error ("Be sure to place pool statement after %s",
03675                                    "related subnet declarations.");
03676                         return;
03677                 }
03678         }
03679 
03680         if (!inpool) {
03681                 struct pool *last = (struct pool *)0;
03682 
03683                 /* If we're permitting dynamic bootp for this range,
03684                    then look for a pool with an empty prohibit list and
03685                    a permit list with one entry that permits all clients. */
03686                 for (pool = share -> pools; pool; pool = pool -> next) {
03687                         if ((!dynamic && !pool -> permit_list && 
03688                              pool -> prohibit_list &&
03689                              !pool -> prohibit_list -> next &&
03690                              (pool -> prohibit_list -> type ==
03691                               permit_dynamic_bootp_clients)) ||
03692                             (dynamic && !pool -> prohibit_list &&
03693                              pool -> permit_list &&
03694                              !pool -> permit_list -> next &&
03695                              (pool -> permit_list -> type ==
03696                               permit_all_clients))) {
03697                                 break;
03698                         }
03699                         last = pool;
03700                 }
03701 
03702                 /* If we didn't get a pool, make one. */
03703                 if (!pool) {
03704                         struct permit *p;
03705                         status = pool_allocate (&pool, MDL);
03706                         if (status != ISC_R_SUCCESS)
03707                                 log_fatal ("no memory for ad-hoc pool: %s",
03708                                            isc_result_totext (status));
03709                         p = new_permit (MDL);
03710                         if (!p)
03711                                 log_fatal ("no memory for ad-hoc permit.");
03712 
03713                         /* Dynamic pools permit all clients.   Otherwise
03714                            we prohibit BOOTP clients. */
03715                         if (dynamic) {
03716                                 p -> type = permit_all_clients;
03717                                 pool -> permit_list = p;
03718                         } else {
03719                                 p -> type = permit_dynamic_bootp_clients;
03720                                 pool -> prohibit_list = p;
03721                         }
03722 
03723                         if (share -> pools)
03724                                 pool_reference (&last -> next, pool, MDL);
03725                         else
03726                                 pool_reference (&share -> pools, pool, MDL);
03727                         shared_network_reference (&pool -> shared_network,
03728                                                   share, MDL);
03729                         if (!clone_group (&pool -> group, share -> group, MDL))
03730                                 log_fatal ("no memory for anon pool group.");
03731                 } else {
03732                         pool = (struct pool *)0;
03733                         if (last)
03734                                 pool_reference (&pool, last, MDL);
03735                         else
03736                                 pool_reference (&pool, share -> pools, MDL);
03737                 }
03738         } else {
03739                 pool = (struct pool *)0;
03740                 pool_reference (&pool, inpool, MDL);
03741         }
03742 
03743 #if defined (FAILOVER_PROTOCOL)
03744         if (pool -> failover_peer && dynamic) {
03745                 /* Doctor, do you think I'm overly sensitive
03746                    about getting bug reports I can't fix? */
03747                 parse_warn (cfile, "dynamic-bootp flag is %s",
03748                             "not permitted for address");
03749                 log_error ("range declarations where there is a failover");
03750                 log_error ("peer in scope.   If you wish to declare an");
03751                 log_error ("address range from which dynamic bootp leases");
03752                 log_error ("can be allocated, please declare it within a");
03753                 log_error ("pool declaration that also contains the \"no");
03754                 log_error ("failover\" statement.   The failover protocol");
03755                 log_error ("itself does not permit dynamic bootp - this");
03756                 log_error ("is not a limitation specific to the ISC DHCP");
03757                 log_error ("server.   Please don't ask me to defend this");
03758                 log_error ("until you have read and really tried %s",
03759                            "to understand");
03760                 log_error ("the failover protocol specification.");
03761 
03762                 /* We don't actually bomb at this point - instead,
03763                    we let parse_lease_file notice the error and
03764                    bomb at that point - it's easier. */
03765         }
03766 #endif /* FAILOVER_PROTOCOL */
03767 
03768         /* Create the new address range... */
03769         new_address_range (cfile, low, high, subnet, pool, lpchain);
03770         pool_dereference (&pool, MDL);
03771 }
03772 
03773 #ifdef DHCPv6
03774 static void
03775 add_ipv6_pool_to_subnet(struct subnet *subnet, u_int16_t type,
03776                         struct iaddr *lo_addr, int bits, int units,
03777                         struct ipv6_pond *pond) {
03778         struct ipv6_pool *pool;
03779         struct in6_addr tmp_in6_addr;
03780         int num_pools;
03781         struct ipv6_pool **tmp;
03782 
03783         /*
03784          * Create our pool.
03785          */
03786         if (lo_addr->len != sizeof(tmp_in6_addr)) {
03787                 log_fatal("Internal error: Attempt to add non-IPv6 address "
03788                           "to IPv6 shared network.");
03789         }
03790         memcpy(&tmp_in6_addr, lo_addr->iabuf, sizeof(tmp_in6_addr));
03791         pool = NULL;
03792         if (ipv6_pool_allocate(&pool, type, &tmp_in6_addr,
03793                                bits, units, MDL) != ISC_R_SUCCESS) {
03794                 log_fatal("Out of memory");
03795         }
03796 
03797         /*
03798          * Add to our global IPv6 pool set.
03799          */
03800         if (add_ipv6_pool(pool) != ISC_R_SUCCESS) {
03801                 log_fatal ("Out of memory");
03802         }
03803 
03804         /*
03805          * Link the pool to its network.
03806          */
03807         pool->subnet = NULL;
03808         subnet_reference(&pool->subnet, subnet, MDL);
03809         pool->shared_network = NULL;
03810         shared_network_reference(&pool->shared_network,
03811                                  subnet->shared_network, MDL);
03812         pool->ipv6_pond = NULL;
03813         ipv6_pond_reference(&pool->ipv6_pond, pond, MDL);
03814 
03815         /* 
03816          * Increase our array size for ipv6_pools in the pond
03817          */
03818         if (pond->ipv6_pools == NULL) {
03819                 num_pools = 0;
03820         } else {
03821                 num_pools = 0;
03822                 while (pond->ipv6_pools[num_pools] != NULL) {
03823                         num_pools++;
03824                 }
03825         }
03826         tmp = dmalloc(sizeof(struct ipv6_pool *) * (num_pools + 2), MDL);
03827         if (tmp == NULL) {
03828                 log_fatal("Out of memory");
03829         }
03830         if (num_pools > 0) {
03831                 memcpy(tmp, pond->ipv6_pools, 
03832                        sizeof(struct ipv6_pool *) * num_pools);
03833         }
03834         if (pond->ipv6_pools != NULL) {
03835                 dfree(pond->ipv6_pools, MDL);
03836         }
03837         pond->ipv6_pools = tmp;
03838 
03839         /* 
03840          * Record this pool in our array of pools for this shared network.
03841          */
03842         ipv6_pool_reference(&pond->ipv6_pools[num_pools], pool, MDL);
03843         pond->ipv6_pools[num_pools+1] = NULL;
03844 }
03845 
03872 static void
03873 add_ipv6_pond_to_network(struct group *group,
03874                          struct ipv6_pond **ret_pond) {
03875 
03876         struct ipv6_pond *pond = NULL, *last = NULL;
03877         struct permit *p;
03878         isc_result_t status;
03879         struct shared_network *shared = group->subnet->shared_network;
03880 
03881         for (pond = shared->ipv6_pond; pond; pond = pond->next) {
03882                 if ((pond->group->statements == group->statements) &&
03883                     (pond->prohibit_list == NULL) &&
03884                     (pond->permit_list != NULL) &&
03885                     (pond->permit_list->next == NULL) &&
03886                     (pond->permit_list->type == permit_all_clients)) {
03887                         ipv6_pond_reference(ret_pond, pond, MDL);
03888                         return;
03889                 }
03890                 last = pond;
03891         }
03892 
03893         /* no pond available, make one */
03894         status = ipv6_pond_allocate(&pond, MDL);
03895         if (status != ISC_R_SUCCESS) 
03896                 log_fatal ("no memory for ad-hoc ipv6 pond: %s",
03897                            isc_result_totext (status));
03898         p = new_permit (MDL);
03899         if (p == NULL)
03900                 log_fatal ("no memory for ad-hoc ipv6 permit.");
03901 
03902         /* we permit all clients */
03903         p->type = permit_all_clients;
03904         pond->permit_list = p;
03905 
03906         /* and attach the pond to the return argument and the shared network */
03907         ipv6_pond_reference(ret_pond, pond, MDL);
03908 
03909         if (shared->ipv6_pond)
03910                 ipv6_pond_reference(&last->next, pond, MDL);
03911         else 
03912                 ipv6_pond_reference(&shared->ipv6_pond, pond, MDL);
03913 
03914         shared_network_reference(&pond->shared_network, shared, MDL);
03915         if (!clone_group (&pond->group, group, MDL))
03916                 log_fatal ("no memory for anon pool group.");
03917 
03918         ipv6_pond_dereference(&pond, MDL);
03919         return;
03920 }
03921 
03922 static void
03923 check_addr_in_subnet(struct subnet *subnet, struct iaddr *addr) {
03924         char lowbuf [INET6_ADDRSTRLEN], netbuf [INET6_ADDRSTRLEN];
03925 
03926         if (!addr_eq(subnet->net, subnet_number(*addr, subnet->netmask))) {
03927                 strncpy(lowbuf, piaddr(*addr), INET6_ADDRSTRLEN);
03928                 strncpy(netbuf, piaddr(subnet->net), INET6_ADDRSTRLEN);
03929                 log_fatal("bad range6, address %s not in subnet6 %s/%d",
03930                         lowbuf, netbuf, subnet->prefix_len);
03931         }
03932 
03933 }
03934 
03935 /* address-range6-declaration :== ip-address6 ip-address6 SEMI
03936                                | ip-address6 SLASH number SEMI
03937                                | ip-address6 [SLASH number] TEMPORARY SEMI */
03938 
03939 void 
03940 parse_address_range6(struct parse *cfile,
03941                      struct group *group,
03942                      struct ipv6_pond *inpond) {
03943         struct iaddr lo, hi;
03944         int bits;
03945         enum dhcp_token token;
03946         const char *val;
03947         struct iaddrcidrnetlist *nets, net;
03948         struct iaddrcidrnetlist *p;
03949         u_int16_t type = D6O_IA_NA;
03950         struct ipv6_pond *pond = NULL;
03951 
03952         if (local_family != AF_INET6) {
03953                 parse_warn(cfile, "range6 statement is only supported "
03954                                   "in DHCPv6 mode.");
03955                 skip_to_semi(cfile);
03956                 return;
03957         }
03958 
03959         /* This is enforced by the caller, this is just a sanity check. */
03960         if (group->subnet == NULL)
03961                 log_fatal("Impossible condition at %s:%d.", MDL);
03962 
03963         /*
03964          * Read starting address.
03965          */
03966         if (!parse_ip6_addr(cfile, &lo)) {
03967                 return;
03968         }
03969 
03970         /*
03971          * zero out the net entry in case we use it
03972          */
03973         memset(&net, 0, sizeof(net));
03974         net.cidrnet.lo_addr = lo;
03975 
03976         check_addr_in_subnet(group->subnet, &lo);
03977 
03978         /* 
03979          * See if we we're using range or CIDR notation or TEMPORARY
03980          */
03981         token = peek_token(&val, NULL, cfile);
03982         if (token == SLASH) {
03983                 /*
03984                  * '/' means CIDR notation, so read the bits we want.
03985                  */
03986                 skip_token(NULL, NULL, cfile);
03987                 token = next_token(&val, NULL, cfile);
03988                 if (token != NUMBER) { 
03989                         parse_warn(cfile, "expecting number");
03990                         skip_to_semi(cfile);
03991                         return;
03992                 }
03993                 net.cidrnet.bits = atoi(val);
03994                 bits = net.cidrnet.bits;
03995                 if ((bits < 0) || (bits > 128)) {
03996                         parse_warn(cfile, "networks have 0 to 128 bits");
03997                         skip_to_semi(cfile);
03998                         return;
03999                 }
04000 
04001                 if (!is_cidr_mask_valid(&net.cidrnet.lo_addr, bits)) {
04002                         parse_warn(cfile, "network mask too short");
04003                         skip_to_semi(cfile);
04004                         return;
04005                 }
04006 
04007                 /*
04008                  * can be temporary (RFC 4941 like)
04009                  */
04010                 token = peek_token(&val, NULL, cfile);
04011                 if (token == TEMPORARY) {
04012                         if (bits < 64)
04013                                 parse_warn(cfile, "temporary mask too short");
04014                         if (bits == 128)
04015                                 parse_warn(cfile, "temporary singleton?");
04016                         skip_token(NULL, NULL, cfile);
04017                         type = D6O_IA_TA;
04018                 }
04019 
04020                 nets = &net;
04021 
04022         } else if (token == TEMPORARY) {
04023                 /*
04024                  * temporary (RFC 4941)
04025                  */
04026                 type = D6O_IA_TA;
04027                 skip_token(NULL, NULL, cfile);
04028                 net.cidrnet.bits = 64;
04029                 if (!is_cidr_mask_valid(&net.cidrnet.lo_addr,
04030                                         net.cidrnet.bits)) {
04031                         parse_warn(cfile, "network mask too short");
04032                         skip_to_semi(cfile);
04033                         return;
04034                 }
04035 
04036                 nets = &net;
04037 
04038         } else {
04039                 /*
04040                  * No '/', so we are looking for the end address of 
04041                  * the IPv6 pool.
04042                  */
04043                 if (!parse_ip6_addr(cfile, &hi)) {
04044                         return;
04045                 }
04046 
04047                 check_addr_in_subnet(group->subnet, &hi);
04048 
04049                 /*
04050                  * Convert our range to a set of CIDR networks.
04051                  */
04052                 nets = NULL;
04053                 if (range2cidr(&nets, &lo, &hi) != ISC_R_SUCCESS) {
04054                         log_fatal("Error converting range to CIDR networks");
04055                 }
04056 
04057         }
04058 
04059         /*
04060          * See if we have a pond for this set of pools.
04061          * If the caller supplied one we use it, otherwise
04062          * check the shared network
04063          */
04064 
04065         if (inpond != NULL) {
04066                 ipv6_pond_reference(&pond, inpond, MDL);
04067         } else {
04068                 add_ipv6_pond_to_network(group, &pond);
04069         }
04070 
04071         /* Now that we have a pond add the nets we have parsed */
04072         for (p=nets; p != NULL; p=p->next) {
04073                 add_ipv6_pool_to_subnet(group->subnet, type,
04074                                         &p->cidrnet.lo_addr, 
04075                                         p->cidrnet.bits, 128, pond);
04076         }
04077 
04078         /* if we allocated a list free it now */
04079         if (nets != &net) 
04080                 free_iaddrcidrnetlist(&nets);
04081 
04082         ipv6_pond_dereference(&pond, MDL);
04083 
04084         token = next_token(NULL, NULL, cfile);
04085         if (token != SEMI) {
04086                 parse_warn(cfile, "semicolon expected.");
04087                 skip_to_semi(cfile);
04088                 return;
04089         }
04090 }
04091 
04092 /* prefix6-declaration :== ip-address6 ip-address6 SLASH number SEMI */
04093 
04094 void 
04095 parse_prefix6(struct parse *cfile,
04096               struct group *group,
04097               struct ipv6_pond *inpond) {
04098         struct iaddr lo, hi;
04099         int bits;
04100         enum dhcp_token token;
04101         const char *val;
04102         struct iaddrcidrnetlist *nets;
04103         struct iaddrcidrnetlist *p;
04104         struct ipv6_pond *pond = NULL;
04105 
04106         if (local_family != AF_INET6) {
04107                 parse_warn(cfile, "prefix6 statement is only supported "
04108                                   "in DHCPv6 mode.");
04109                 skip_to_semi(cfile);
04110                 return;
04111         }
04112 
04113         /* This is enforced by the caller, so it's just a sanity check. */
04114         if (group->subnet == NULL)
04115                 log_fatal("Impossible condition at %s:%d.", MDL);
04116 
04117         /*
04118          * Read starting and ending address.
04119          */
04120         if (!parse_ip6_addr(cfile, &lo)) {
04121                 return;
04122         }
04123         if (!parse_ip6_addr(cfile, &hi)) {
04124                 return;
04125         }
04126 
04127         /*
04128          * Next is '/' number ';'.
04129          */
04130         token = next_token(NULL, NULL, cfile);
04131         if (token != SLASH) {
04132                 parse_warn(cfile, "expecting '/'");
04133                 if (token != SEMI)
04134                         skip_to_semi(cfile);
04135                 return;
04136         }
04137         token = next_token(&val, NULL, cfile);
04138         if (token != NUMBER) {
04139                 parse_warn(cfile, "expecting number");
04140                 if (token != SEMI)
04141                         skip_to_semi(cfile);
04142                 return;
04143         }
04144         bits = atoi(val);
04145         if ((bits <= 0) || (bits >= 128)) {
04146                 parse_warn(cfile, "networks have 0 to 128 bits (exclusive)");
04147                 return;
04148         }
04149         if (!is_cidr_mask_valid(&lo, bits) ||
04150             !is_cidr_mask_valid(&hi, bits)) {
04151                 parse_warn(cfile, "network mask too short");
04152                 return;
04153         }
04154         token = next_token(NULL, NULL, cfile);
04155         if (token != SEMI) {
04156                 parse_warn(cfile, "semicolon expected.");
04157                 skip_to_semi(cfile);
04158                 return;
04159         }
04160 
04161         /*
04162          * Convert our range to a set of CIDR networks.
04163          */
04164         nets = NULL;
04165         if (range2cidr(&nets, &lo, &hi) != ISC_R_SUCCESS) {
04166                 log_fatal("Error converting prefix to CIDR");
04167         }
04168 
04169         /*
04170          * See if we have a pond for this set of pools.
04171          * If the caller supplied one we use it, otherwise
04172          * check the shared network
04173          */
04174 
04175         if (inpond != NULL) {
04176                 ipv6_pond_reference(&pond, inpond, MDL);
04177         } else {
04178                 add_ipv6_pond_to_network(group, &pond);
04179         }
04180                 
04181         for (p = nets; p != NULL; p = p->next) {
04182                 /* Normalize and check. */
04183                 if (p->cidrnet.bits == 128) {
04184                         p->cidrnet.bits = bits;
04185                 }
04186                 if (p->cidrnet.bits > bits) {
04187                         parse_warn(cfile, "impossible mask length");
04188                         continue;
04189                 }
04190                 add_ipv6_pool_to_subnet(group->subnet, D6O_IA_PD,
04191                                         &p->cidrnet.lo_addr,
04192                                         p->cidrnet.bits, bits, pond);
04193         }
04194 
04195         free_iaddrcidrnetlist(&nets);
04196 }
04197 
04198 /* fixed-prefix6 :== ip6-address SLASH number SEMI */
04199 
04200 void
04201 parse_fixed_prefix6(struct parse *cfile, struct host_decl *host_decl) {
04202         struct iaddrcidrnetlist *ia, **h;
04203         enum dhcp_token token;
04204         const char *val;
04205 
04206         /*
04207          * Get the head of the fixed-prefix list.
04208          */
04209         h = &host_decl->fixed_prefix;
04210 
04211         /*
04212          * Walk to the end.
04213          */
04214         while (*h != NULL) {
04215                 h = &((*h)->next);
04216         }
04217 
04218         /*
04219          * Allocate a new iaddrcidrnetlist structure.
04220          */
04221         ia = dmalloc(sizeof(*ia), MDL);
04222         if (!ia) {
04223                 log_fatal("Out of memory");
04224         }
04225 
04226         /*
04227          * Parse it.
04228          */
04229         if (!parse_ip6_addr(cfile, &ia->cidrnet.lo_addr)) {
04230                 dfree(ia, MDL);
04231                 return;
04232         }
04233         token = next_token(NULL, NULL, cfile);
04234         if (token != SLASH) {
04235                 dfree(ia, MDL);
04236                 parse_warn(cfile, "expecting '/'");
04237                 if (token != SEMI)
04238                         skip_to_semi(cfile);
04239                 return;
04240         }
04241         token = next_token(&val, NULL, cfile);
04242         if (token != NUMBER) {
04243                 dfree(ia, MDL);
04244                 parse_warn(cfile, "expecting number");
04245                 if (token != SEMI)
04246                         skip_to_semi(cfile);
04247                 return;
04248         }
04249         token = next_token(NULL, NULL, cfile);
04250         if (token != SEMI) {
04251                 dfree(ia, MDL);
04252                 parse_warn(cfile, "semicolon expected.");
04253                 skip_to_semi(cfile);
04254                 return;
04255         }
04256 
04257         /*
04258          * Fill it.
04259          */
04260         ia->cidrnet.bits = atoi(val);
04261         if ((ia->cidrnet.bits < 0) || (ia->cidrnet.bits > 128)) {
04262                 dfree(ia, MDL);
04263                 parse_warn(cfile, "networks have 0 to 128 bits");
04264                 return;
04265         }
04266         if (!is_cidr_mask_valid(&ia->cidrnet.lo_addr, ia->cidrnet.bits)) {
04267                 dfree(ia, MDL);
04268                 parse_warn(cfile, "network mask too short");
04269                 return;
04270         }
04271 
04272         /*
04273          * Store it.
04274          */
04275         *h = ia;
04276         return;
04277 }
04278 
04298 void parse_pool6_statement (cfile, group, type)
04299         struct parse *cfile;
04300         struct group *group;
04301         int type;
04302 {
04303         enum dhcp_token token;
04304         const char *val;
04305         int done = 0;
04306         struct ipv6_pond *pond, **p;
04307         int declaration = 0;
04308         isc_result_t status;
04309 
04310         pond = NULL;
04311         status = ipv6_pond_allocate(&pond, MDL);
04312         if (status != ISC_R_SUCCESS)
04313                 log_fatal("no memory for pool6: %s",
04314                           isc_result_totext (status));
04315 
04316         if (type == SUBNET_DECL)
04317                 shared_network_reference(&pond->shared_network,
04318                                          group->subnet->shared_network,
04319                                          MDL);
04320         else {
04321                 parse_warn(cfile, "Dynamic pool6s are only valid inside "
04322                                   "subnet statements.");
04323                 skip_to_semi(cfile);
04324                 return;
04325         }
04326 
04327         if (clone_group(&pond->group, group, MDL) == 0)
04328                 log_fatal("can't clone pool6 group.");
04329 
04330         if (parse_lbrace(cfile) == 0) {
04331                 ipv6_pond_dereference(&pond, MDL);
04332                 return;
04333         }
04334 
04335         do {
04336                 token = peek_token(&val, NULL, cfile);
04337                 switch (token) {
04338                       case RANGE6:
04339                         skip_token(NULL, NULL, cfile);
04340                         parse_address_range6(cfile, group, pond);
04341                         break;
04342 
04343                       case PREFIX6:
04344                         skip_token(NULL, NULL, cfile);
04345                         parse_prefix6(cfile, group, pond);
04346                         break;
04347 
04348                       case ALLOW:
04349                         skip_token(NULL, NULL, cfile);
04350                         get_permit(cfile, &pond->permit_list, 1,
04351                                    &pond->valid_from, &pond->valid_until);
04352                         break;
04353 
04354                       case DENY:
04355                         skip_token(NULL, NULL, cfile);
04356                         get_permit(cfile, &pond->prohibit_list, 0,
04357                                    &pond->valid_from, &pond->valid_until);
04358                         break;
04359                         
04360                       case RBRACE:
04361                         skip_token(&val, NULL, cfile);
04362                         done = 1;
04363                         break;
04364 
04365                       case END_OF_FILE:
04366                         /*
04367                          * We can get to END_OF_FILE if, for instance,
04368                          * the parse_statement() reads all available tokens
04369                          * and leaves us at the end.
04370                          */
04371                         parse_warn(cfile, "unexpected end of file");
04372                         goto cleanup;
04373 
04374                       default:
04375                         declaration = parse_statement(cfile, pond->group,
04376                                                       POOL_DECL, NULL,
04377                                                       declaration);
04378                         break;
04379                 }
04380         } while (!done);
04381 
04382         /*
04383          * A possible optimization is to see if this pond can be merged into
04384          * an already existing pond.  But I'll pass on that for now as we need
04385          * to repoint the leases to the other pond which is annoying. SAR
04386          */
04387 
04388         /* 
04389          * Add this pond to the list (will need updating if we add the
04390          * optimization).
04391          */
04392 
04393         p = &pond->shared_network->ipv6_pond;
04394         for (; *p; p = &((*p)->next))
04395                 ;
04396         ipv6_pond_reference(p, pond, MDL);
04397 
04398         /* Don't allow a pool6 declaration with no addresses or
04399            prefixes, since it is probably a configuration error. */
04400         if (pond->ipv6_pools == NULL) {
04401                 parse_warn (cfile, "Pool6 declaration with no %s.",
04402                             "address range6 or prefix6");
04403                 log_error ("Pool6 declarations must always contain at least");
04404                 log_error ("one range6 or prefix6 statement.");
04405         }
04406 
04407 cleanup:
04408         ipv6_pond_dereference(&pond, MDL);
04409 }
04410 
04411 
04412 
04413 #endif /* DHCPv6 */
04414 
04415 /* allow-deny-keyword :== BOOTP
04416                         | BOOTING
04417                         | DYNAMIC_BOOTP
04418                         | UNKNOWN_CLIENTS */
04419 
04420 int parse_allow_deny (oc, cfile, flag)
04421         struct option_cache **oc;
04422         struct parse *cfile;
04423         int flag;
04424 {
04425         enum dhcp_token token;
04426         const char *val;
04427         unsigned char rf = flag;
04428         unsigned code;
04429         struct option *option = NULL;
04430         struct expression *data = (struct expression *)0;
04431         int status;
04432 
04433         if (!make_const_data (&data, &rf, 1, 0, 1, MDL))
04434                 return 0;
04435 
04436         token = next_token (&val, (unsigned *)0, cfile);
04437         switch (token) {
04438               case TOKEN_BOOTP:
04439                 code = SV_ALLOW_BOOTP;
04440                 break;
04441 
04442               case BOOTING:
04443                 code = SV_ALLOW_BOOTING;
04444                 break;
04445 
04446               case DYNAMIC_BOOTP:
04447                 code = SV_DYNAMIC_BOOTP;
04448                 break;
04449 
04450               case UNKNOWN_CLIENTS:
04451                 code = SV_BOOT_UNKNOWN_CLIENTS;
04452                 break;
04453 
04454               case DUPLICATES:
04455                 code = SV_DUPLICATES;
04456                 break;
04457 
04458               case DECLINES:
04459                 code= SV_DECLINES;
04460                 break;
04461 
04462               case CLIENT_UPDATES:
04463                 code = SV_CLIENT_UPDATES;
04464                 break;
04465 
04466               case LEASEQUERY:
04467                 code = SV_LEASEQUERY;
04468                 break;
04469 
04470               default:
04471                 parse_warn (cfile, "expecting allow/deny key");
04472                 skip_to_semi (cfile);
04473                 return 0;
04474         }
04475         /* Reference on option is passed to option cache. */
04476         if (!option_code_hash_lookup(&option, server_universe.code_hash,
04477                                      &code, 0, MDL))
04478                 log_fatal("Unable to find server option %u (%s:%d).",
04479                           code, MDL);
04480         status = option_cache(oc, NULL, data, option, MDL);
04481         expression_dereference (&data, MDL);
04482         parse_semi (cfile);
04483         return status;
04484 }
04485 
04486 void
04487 parse_ia_na_declaration(struct parse *cfile) {
04488 #if !defined(DHCPv6)
04489         parse_warn(cfile, "No DHCPv6 support.");
04490         skip_to_semi(cfile);
04491 #else /* defined(DHCPv6) */
04492         enum dhcp_token token;
04493         struct ia_xx *ia;
04494         const char *val;
04495         struct ia_xx *old_ia;
04496         unsigned int len;
04497         u_int32_t iaid;
04498         struct iaddr iaddr;
04499         binding_state_t state;
04500         u_int32_t prefer;
04501         u_int32_t valid;
04502         TIME end_time;
04503         struct iasubopt *iaaddr;
04504         struct ipv6_pool *pool;
04505         char addr_buf[sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255")];
04506         isc_boolean_t newbinding;
04507         struct binding_scope *scope = NULL;
04508         struct binding *bnd;
04509         struct binding_value *nv = NULL;
04510         struct executable_statement *on_star[2] = {NULL, NULL};
04511         int lose, i;
04512 
04513         if (local_family != AF_INET6) {
04514                 parse_warn(cfile, "IA_NA is only supported in DHCPv6 mode.");
04515                 skip_to_semi(cfile);
04516                 return;
04517         }
04518 
04519         token = next_token(&val, &len, cfile);
04520         if (token != STRING) {
04521                 parse_warn(cfile, "corrupt lease file; "
04522                                   "expecting an iaid+ia_na string");
04523                 skip_to_semi(cfile);
04524                 return;
04525         }
04526         if (len < 5) {
04527                 parse_warn(cfile, "corrupt lease file; "
04528                                   "iaid+ia_na string too short");
04529                 skip_to_semi(cfile);
04530                 return;
04531         }
04532 
04533         memcpy(&iaid, val, 4);
04534         ia = NULL;
04535         if (ia_allocate(&ia, iaid, val+4, len-4, MDL) != ISC_R_SUCCESS) {
04536                 log_fatal("Out of memory.");
04537         }
04538         ia->ia_type = D6O_IA_NA;
04539 
04540         token = next_token(&val, NULL, cfile);
04541         if (token != LBRACE) {
04542                 parse_warn(cfile, "corrupt lease file; expecting left brace");
04543                 skip_to_semi(cfile);
04544                 return;
04545         }
04546 
04547         for (;;) {
04548                 token = next_token(&val, NULL, cfile);
04549                 if (token == RBRACE) break;
04550 
04551                 if (token == CLTT) {
04552                         ia->cltt = parse_date (cfile);
04553                         continue;
04554                 }
04555 
04556                 if (token != IAADDR) {
04557                         parse_warn(cfile, "corrupt lease file; "
04558                                           "expecting IAADDR or right brace");
04559                         skip_to_semi(cfile);
04560                         return;
04561                 }
04562 
04563                 if (!parse_ip6_addr(cfile, &iaddr)) {
04564                         parse_warn(cfile, "corrupt lease file; "
04565                                           "expecting IPv6 address");
04566                         skip_to_semi(cfile);
04567                         return;
04568                 }
04569 
04570                 token = next_token(&val, NULL, cfile);
04571                 if (token != LBRACE) {
04572                         parse_warn(cfile, "corrupt lease file; "
04573                                           "expecting left brace");
04574                         skip_to_semi(cfile);
04575                         return;
04576                 }
04577 
04578                 state = FTS_LAST+1;
04579                 prefer = valid = 0;
04580                 end_time = -1;
04581                 for (;;) {
04582                         token = next_token(&val, NULL, cfile);
04583                         if (token == RBRACE) break;
04584 
04585                         switch(token) {
04586                                 /* Lease binding state. */
04587                              case BINDING:
04588                                 token = next_token(&val, NULL, cfile);
04589                                 if (token != STATE) {
04590                                         parse_warn(cfile, "corrupt lease file; "
04591                                                           "expecting state");
04592                                         skip_to_semi(cfile);
04593                                         return;
04594                                 }
04595                                 token = next_token(&val, NULL, cfile);
04596                                 switch (token) {
04597                                         case TOKEN_ABANDONED:
04598                                                 state = FTS_ABANDONED;
04599                                                 break;
04600                                         case TOKEN_FREE:
04601                                                 state = FTS_FREE;
04602                                                 break;
04603                                         case TOKEN_ACTIVE:
04604                                                 state = FTS_ACTIVE;
04605                                                 break;
04606                                         case TOKEN_EXPIRED:
04607                                                 state = FTS_EXPIRED;
04608                                                 break;
04609                                         case TOKEN_RELEASED:
04610                                                 state = FTS_RELEASED;
04611                                                 break;
04612                                         default:
04613                                                 parse_warn(cfile,
04614                                                            "corrupt lease "
04615                                                            "file; "
04616                                                            "expecting a "
04617                                                            "binding state.");
04618                                                 skip_to_semi(cfile);
04619                                                 return;
04620                                 }
04621 
04622                                 token = next_token(&val, NULL, cfile);
04623                                 if (token != SEMI) {
04624                                         parse_warn(cfile, "corrupt lease file; "
04625                                                           "expecting "
04626                                                           "semicolon.");
04627                                 }
04628                                 break;
04629 
04630                                 /* Lease preferred lifetime. */
04631                               case PREFERRED_LIFE:
04632                                 token = next_token(&val, NULL, cfile);
04633                                 if (token != NUMBER) {
04634                                         parse_warn(cfile, "%s is not a valid "
04635                                                           "preferred time",
04636                                                    val);
04637                                         skip_to_semi(cfile);
04638                                         continue;
04639                                 }
04640                                 prefer = atoi (val);
04641 
04642                                 /*
04643                                  * Currently we peek for the semi-colon to 
04644                                  * allow processing of older lease files that
04645                                  * don't have the semi-colon.  Eventually we
04646                                  * should remove the peeking code.
04647                                  */
04648                                 token = peek_token(&val, NULL, cfile);
04649                                 if (token == SEMI) {
04650                                         skip_token(&val, NULL, cfile);
04651                                 } else {
04652                                         parse_warn(cfile,
04653                                                    "corrupt lease file; "
04654                                                    "expecting semicolon.");
04655                                 }
04656                                 break;
04657 
04658                                 /* Lease valid lifetime. */
04659                               case MAX_LIFE:
04660                                 token = next_token(&val, NULL, cfile);
04661                                 if (token != NUMBER) {
04662                                         parse_warn(cfile, "%s is not a valid "
04663                                                           "max time",
04664                                                    val);
04665                                         skip_to_semi(cfile);
04666                                         continue;
04667                                 }
04668                                 valid = atoi (val);
04669 
04670                                 /*
04671                                  * Currently we peek for the semi-colon to 
04672                                  * allow processing of older lease files that
04673                                  * don't have the semi-colon.  Eventually we
04674                                  * should remove the peeking code.
04675                                  */
04676                                 token = peek_token(&val, NULL, cfile);
04677                                 if (token == SEMI) {
04678                                         skip_token(&val, NULL, cfile);
04679                                 } else {
04680                                         parse_warn(cfile,
04681                                                    "corrupt lease file; "
04682                                                    "expecting semicolon.");
04683                                 }
04684                                 break;
04685 
04686                                 /* Lease expiration time. */
04687                               case ENDS:
04688                                 end_time = parse_date(cfile);
04689                                 break;
04690 
04691                                 /* Lease binding scopes. */
04692                               case TOKEN_SET:
04693                                 token = next_token(&val, NULL, cfile);
04694                                 if ((token != NAME) &&
04695                                     (token != NUMBER_OR_NAME)) {
04696                                         parse_warn(cfile, "%s is not a valid "
04697                                                           "variable name",
04698                                                    val);
04699                                         skip_to_semi(cfile);
04700                                         continue;
04701                                 }
04702 
04703                                 if (scope != NULL)
04704                                         bnd = find_binding(scope, val);
04705                                 else {
04706                                         if (!binding_scope_allocate(&scope,
04707                                                                     MDL)) {
04708                                                 log_fatal("Out of memory for "
04709                                                           "lease binding "
04710                                                           "scope.");
04711                                         }
04712 
04713                                         bnd = NULL;
04714                                 }
04715 
04716                                 if (bnd == NULL) {
04717                                         bnd = dmalloc(sizeof(*bnd),
04718                                                           MDL);
04719                                         if (bnd == NULL) {
04720                                                 log_fatal("No memory for "
04721                                                           "lease binding.");
04722                                         }
04723 
04724                                         bnd->name = dmalloc(strlen(val) + 1,
04725                                                             MDL);
04726                                         if (bnd->name == NULL) {
04727                                                 log_fatal("No memory for "
04728                                                           "binding name.");
04729                                         }
04730                                         strcpy(bnd->name, val);
04731 
04732                                         newbinding = ISC_TRUE;
04733                                 } else {
04734                                         newbinding = ISC_FALSE;
04735                                 }
04736 
04737                                 if (!binding_value_allocate(&nv, MDL)) {
04738                                         log_fatal("no memory for binding "
04739                                                   "value.");
04740                                 }
04741 
04742                                 token = next_token(NULL, NULL, cfile);
04743                                 if (token != EQUAL) {
04744                                         parse_warn(cfile, "expecting '=' in "
04745                                                           "set statement.");
04746                                         goto binding_err;
04747                                 }
04748 
04749                                 if (!parse_binding_value(cfile, nv)) {
04750                                       binding_err:
04751                                         binding_value_dereference(&nv, MDL);
04752                                         binding_scope_dereference(&scope, MDL);
04753                                         return;
04754                                 }
04755 
04756                                 if (newbinding) {
04757                                         binding_value_reference(&bnd->value,
04758                                                                 nv, MDL);
04759                                         bnd->next = scope->bindings;
04760                                         scope->bindings = bnd;
04761                                 } else {
04762                                         binding_value_dereference(&bnd->value,
04763                                                                   MDL);
04764                                         binding_value_reference(&bnd->value,
04765                                                                 nv, MDL);
04766                                 }
04767 
04768                                 binding_value_dereference(&nv, MDL);
04769                                 parse_semi(cfile);
04770                                 break;
04771 
04772                               case ON:
04773                                 lose = 0;
04774                                 /*
04775                                  * Depending on the user config we may
04776                                  * have one or two on statements.  We
04777                                  * need to save information about both
04778                                  * of them until we allocate the
04779                                  * iasubopt to hold them.
04780                                  */
04781                                 if (on_star[0] == NULL) {
04782                                         if (!parse_on_statement (&on_star[0],
04783                                                                  cfile,
04784                                                                  &lose)) {
04785                                                 parse_warn(cfile,
04786                                                            "corrupt lease "
04787                                                            "file; bad ON "
04788                                                            "statement");
04789                                                 skip_to_rbrace (cfile, 1);
04790                                                 return;
04791                                         }
04792                                 } else {
04793                                         if (!parse_on_statement (&on_star[1],
04794                                                                  cfile,
04795                                                                  &lose)) {
04796                                                 parse_warn(cfile,
04797                                                            "corrupt lease "
04798                                                            "file; bad ON "
04799                                                            "statement");
04800                                                 skip_to_rbrace (cfile, 1);
04801                                                 return;
04802                                         }
04803                                 }
04804 
04805                                 break;
04806                           
04807                               default:
04808                                 parse_warn(cfile, "corrupt lease file; "
04809                                                   "expecting ia_na contents, "
04810                                                   "got '%s'", val);
04811                                 skip_to_semi(cfile);
04812                                 continue;
04813                         }
04814                 }
04815 
04816                 if (state == FTS_LAST+1) {
04817                         parse_warn(cfile, "corrupt lease file; "
04818                                           "missing state in iaaddr");
04819                         return;
04820                 }
04821                 if (end_time == -1) {
04822                         parse_warn(cfile, "corrupt lease file; "
04823                                           "missing end time in iaaddr");
04824                         return;
04825                 }
04826 
04827                 iaaddr = NULL;
04828                 if (iasubopt_allocate(&iaaddr, MDL) != ISC_R_SUCCESS) {
04829                         log_fatal("Out of memory.");
04830                 }
04831                 memcpy(&iaaddr->addr, iaddr.iabuf, sizeof(iaaddr->addr));
04832                 iaaddr->plen = 0;
04833                 iaaddr->state = state;
04834                 iaaddr->prefer = prefer;
04835                 iaaddr->valid = valid;
04836                 if (iaaddr->state == FTS_RELEASED)
04837                         iaaddr->hard_lifetime_end_time = end_time;
04838 
04839                 if (scope != NULL) {
04840                         binding_scope_reference(&iaaddr->scope, scope, MDL);
04841                         binding_scope_dereference(&scope, MDL);
04842                 }
04843 
04844                 /*
04845                  * Check on both on statements.  Because of how we write the
04846                  * lease file we know which is which if we have two but it's
04847                  * easier to write the code to be independent.  We do assume
04848                  * that the statements won't overlap.
04849                  */
04850                 for (i = 0;
04851                      (i < 2) && on_star[i] != NULL ;
04852                      i++) {
04853                         if ((on_star[i]->data.on.evtypes & ON_EXPIRY) &&
04854                             on_star[i]->data.on.statements) {
04855                                 executable_statement_reference
04856                                         (&iaaddr->on_star.on_expiry,
04857                                          on_star[i]->data.on.statements, MDL);
04858                         }
04859                         if ((on_star[i]->data.on.evtypes & ON_RELEASE) &&
04860                             on_star[i]->data.on.statements) {
04861                                 executable_statement_reference
04862                                         (&iaaddr->on_star.on_release,
04863                                          on_star[i]->data.on.statements, MDL);
04864                         }
04865                         executable_statement_dereference (&on_star[i], MDL);
04866                 }
04867                         
04868                 /* find the pool this address is in */
04869                 pool = NULL;
04870                 if (find_ipv6_pool(&pool, D6O_IA_NA,
04871                                    &iaaddr->addr) != ISC_R_SUCCESS) {
04872                         inet_ntop(AF_INET6, &iaaddr->addr,
04873                                   addr_buf, sizeof(addr_buf));
04874                         parse_warn(cfile, "no pool found for address %s",
04875                                    addr_buf);
04876                         return;
04877                 }
04878 
04879                 /* remove old information */
04880                 if (cleanup_lease6(ia_na_active, pool,
04881                                    iaaddr, ia) != ISC_R_SUCCESS) {
04882                         inet_ntop(AF_INET6, &iaaddr->addr,
04883                                   addr_buf, sizeof(addr_buf));
04884                         parse_warn(cfile, "duplicate na lease for address %s",
04885                                    addr_buf);
04886                 }
04887 
04888                 /*
04889                  * if we like the lease we add it to our various structues
04890                  * otherwise we leave it and it will get cleaned when we
04891                  * do the iasubopt_dereference.
04892                  */
04893                 if ((state == FTS_ACTIVE) || (state == FTS_ABANDONED)) {
04894                         ia_add_iasubopt(ia, iaaddr, MDL);
04895                         ia_reference(&iaaddr->ia, ia, MDL);
04896                         add_lease6(pool, iaaddr, end_time);
04897                 }
04898 
04899                 iasubopt_dereference(&iaaddr, MDL);
04900                 ipv6_pool_dereference(&pool, MDL);
04901         }
04902 
04903         /*
04904          * If we have an existing record for this IA_NA, remove it.
04905          */
04906         old_ia = NULL;
04907         if (ia_hash_lookup(&old_ia, ia_na_active,
04908                            (unsigned char *)ia->iaid_duid.data,
04909                            ia->iaid_duid.len, MDL)) {
04910                 ia_hash_delete(ia_na_active, 
04911                                (unsigned char *)ia->iaid_duid.data,
04912                                ia->iaid_duid.len, MDL);
04913                 ia_dereference(&old_ia, MDL);
04914         }
04915 
04916         /*
04917          * If we have addresses, add this, otherwise don't bother.
04918          */
04919         if (ia->num_iasubopt > 0) {
04920                 ia_hash_add(ia_na_active, 
04921                             (unsigned char *)ia->iaid_duid.data,
04922                             ia->iaid_duid.len, ia, MDL);
04923         }
04924         ia_dereference(&ia, MDL);
04925 #endif /* defined(DHCPv6) */
04926 }
04927 
04928 void
04929 parse_ia_ta_declaration(struct parse *cfile) {
04930 #if !defined(DHCPv6)
04931         parse_warn(cfile, "No DHCPv6 support.");
04932         skip_to_semi(cfile);
04933 #else /* defined(DHCPv6) */
04934         enum dhcp_token token;
04935         struct ia_xx *ia;
04936         const char *val;
04937         struct ia_xx *old_ia;
04938         unsigned int len;
04939         u_int32_t iaid;
04940         struct iaddr iaddr;
04941         binding_state_t state;
04942         u_int32_t prefer;
04943         u_int32_t valid;
04944         TIME end_time;
04945         struct iasubopt *iaaddr;
04946         struct ipv6_pool *pool;
04947         char addr_buf[sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255")];
04948         isc_boolean_t newbinding;
04949         struct binding_scope *scope = NULL;
04950         struct binding *bnd;
04951         struct binding_value *nv = NULL;
04952         struct executable_statement *on_star[2] = {NULL, NULL};
04953         int lose, i;
04954 
04955         if (local_family != AF_INET6) {
04956                 parse_warn(cfile, "IA_TA is only supported in DHCPv6 mode.");
04957                 skip_to_semi(cfile);
04958                 return;
04959         }
04960 
04961         token = next_token(&val, &len, cfile);
04962         if (token != STRING) {
04963                 parse_warn(cfile, "corrupt lease file; "
04964                                   "expecting an iaid+ia_ta string");
04965                 skip_to_semi(cfile);
04966                 return;
04967         }
04968         if (len < 5) {
04969                 parse_warn(cfile, "corrupt lease file; "
04970                                   "iaid+ia_ta string too short");
04971                 skip_to_semi(cfile);
04972                 return;
04973         }
04974 
04975         memcpy(&iaid, val, 4);
04976         ia = NULL;
04977         if (ia_allocate(&ia, iaid, val+4, len-4, MDL) != ISC_R_SUCCESS) {
04978                 log_fatal("Out of memory.");
04979         }
04980         ia->ia_type = D6O_IA_TA;
04981 
04982         token = next_token(&val, NULL, cfile);
04983         if (token != LBRACE) {
04984                 parse_warn(cfile, "corrupt lease file; expecting left brace");
04985                 skip_to_semi(cfile);
04986                 return;
04987         }
04988 
04989         for (;;) {
04990                 token = next_token(&val, NULL, cfile);
04991                 if (token == RBRACE) break;
04992 
04993                 if (token == CLTT) {
04994                         ia->cltt = parse_date (cfile);
04995                         continue;
04996                 }
04997 
04998                 if (token != IAADDR) {
04999                         parse_warn(cfile, "corrupt lease file; "
05000                                           "expecting IAADDR or right brace");
05001                         skip_to_semi(cfile);
05002                         return;
05003                 }
05004 
05005                 if (!parse_ip6_addr(cfile, &iaddr)) {
05006                         parse_warn(cfile, "corrupt lease file; "
05007                                           "expecting IPv6 address");
05008                         skip_to_semi(cfile);
05009                         return;
05010                 }
05011 
05012                 token = next_token(&val, NULL, cfile);
05013                 if (token != LBRACE) {
05014                         parse_warn(cfile, "corrupt lease file; "
05015                                           "expecting left brace");
05016                         skip_to_semi(cfile);
05017                         return;
05018                 }
05019 
05020                 state = FTS_LAST+1;
05021                 prefer = valid = 0;
05022                 end_time = -1;
05023                 for (;;) {
05024                         token = next_token(&val, NULL, cfile);
05025                         if (token == RBRACE) break;
05026 
05027                         switch(token) {
05028                                 /* Lease binding state. */
05029                              case BINDING:
05030                                 token = next_token(&val, NULL, cfile);
05031                                 if (token != STATE) {
05032                                         parse_warn(cfile, "corrupt lease file; "
05033                                                           "expecting state");
05034                                         skip_to_semi(cfile);
05035                                         return;
05036                                 }
05037                                 token = next_token(&val, NULL, cfile);
05038                                 switch (token) {
05039                                         case TOKEN_ABANDONED:
05040                                                 state = FTS_ABANDONED;
05041                                                 break;
05042                                         case TOKEN_FREE:
05043                                                 state = FTS_FREE;
05044                                                 break;
05045                                         case TOKEN_ACTIVE:
05046                                                 state = FTS_ACTIVE;
05047                                                 break;
05048                                         case TOKEN_EXPIRED:
05049                                                 state = FTS_EXPIRED;
05050                                                 break;
05051                                         case TOKEN_RELEASED:
05052                                                 state = FTS_RELEASED;
05053                                                 break;
05054                                         default:
05055                                                 parse_warn(cfile,
05056                                                            "corrupt lease "
05057                                                            "file; "
05058                                                            "expecting a "
05059                                                            "binding state.");
05060                                                 skip_to_semi(cfile);
05061                                                 return;
05062                                 }
05063 
05064                                 token = next_token(&val, NULL, cfile);
05065                                 if (token != SEMI) {
05066                                         parse_warn(cfile, "corrupt lease file; "
05067                                                           "expecting "
05068                                                           "semicolon.");
05069                                 }
05070                                 break;
05071 
05072                                 /* Lease preferred lifetime. */
05073                               case PREFERRED_LIFE:
05074                                 token = next_token(&val, NULL, cfile);
05075                                 if (token != NUMBER) {
05076                                         parse_warn(cfile, "%s is not a valid "
05077                                                           "preferred time",
05078                                                    val);
05079                                         skip_to_semi(cfile);
05080                                         continue;
05081                                 }
05082                                 prefer = atoi (val);
05083 
05084                                 /*
05085                                  * Currently we peek for the semi-colon to 
05086                                  * allow processing of older lease files that
05087                                  * don't have the semi-colon.  Eventually we
05088                                  * should remove the peeking code.
05089                                  */
05090                                 token = peek_token(&val, NULL, cfile);
05091                                 if (token == SEMI) {
05092                                         skip_token(&val, NULL, cfile);
05093                                 } else {
05094                                         parse_warn(cfile,
05095                                                    "corrupt lease file; "
05096                                                    "expecting semicolon.");
05097                                 }
05098                                 break;
05099 
05100                                 /* Lease valid lifetime. */
05101                               case MAX_LIFE:
05102                                 token = next_token(&val, NULL, cfile);
05103                                 if (token != NUMBER) {
05104                                         parse_warn(cfile, "%s is not a valid "
05105                                                           "max time",
05106                                                    val);
05107                                         skip_to_semi(cfile);
05108                                         continue;
05109                                 }
05110                                 valid = atoi (val);
05111 
05112                                 /*
05113                                  * Currently we peek for the semi-colon to 
05114                                  * allow processing of older lease files that
05115                                  * don't have the semi-colon.  Eventually we
05116                                  * should remove the peeking code.
05117                                  */
05118                                 token = peek_token(&val, NULL, cfile);
05119                                 if (token == SEMI) {
05120                                         skip_token(&val, NULL, cfile);
05121                                 } else {
05122                                         parse_warn(cfile,
05123                                                    "corrupt lease file; "
05124                                                    "expecting semicolon.");
05125                                 }
05126                                 break;
05127 
05128                                 /* Lease expiration time. */
05129                               case ENDS:
05130                                 end_time = parse_date(cfile);
05131                                 break;
05132 
05133                                 /* Lease binding scopes. */
05134                               case TOKEN_SET:
05135                                 token = next_token(&val, NULL, cfile);
05136                                 if ((token != NAME) &&
05137                                     (token != NUMBER_OR_NAME)) {
05138                                         parse_warn(cfile, "%s is not a valid "
05139                                                           "variable name",
05140                                                    val);
05141                                         skip_to_semi(cfile);
05142                                         continue;
05143                                 }
05144 
05145                                 if (scope != NULL)
05146                                         bnd = find_binding(scope, val);
05147                                 else {
05148                                         if (!binding_scope_allocate(&scope,
05149                                                                     MDL)) {
05150                                                 log_fatal("Out of memory for "
05151                                                           "lease binding "
05152                                                           "scope.");
05153                                         }
05154 
05155                                         bnd = NULL;
05156                                 }
05157 
05158                                 if (bnd == NULL) {
05159                                         bnd = dmalloc(sizeof(*bnd),
05160                                                           MDL);
05161                                         if (bnd == NULL) {
05162                                                 log_fatal("No memory for "
05163                                                           "lease binding.");
05164                                         }
05165 
05166                                         bnd->name = dmalloc(strlen(val) + 1,
05167                                                             MDL);
05168                                         if (bnd->name == NULL) {
05169                                                 log_fatal("No memory for "
05170                                                           "binding name.");
05171                                         }
05172                                         strcpy(bnd->name, val);
05173 
05174                                         newbinding = ISC_TRUE;
05175                                 } else {
05176                                         newbinding = ISC_FALSE;
05177                                 }
05178 
05179                                 if (!binding_value_allocate(&nv, MDL)) {
05180                                         log_fatal("no memory for binding "
05181                                                   "value.");
05182                                 }
05183 
05184                                 token = next_token(NULL, NULL, cfile);
05185                                 if (token != EQUAL) {
05186                                         parse_warn(cfile, "expecting '=' in "
05187                                                           "set statement.");
05188                                         goto binding_err;
05189                                 }
05190 
05191                                 if (!parse_binding_value(cfile, nv)) {
05192                                       binding_err:
05193                                         binding_value_dereference(&nv, MDL);
05194                                         binding_scope_dereference(&scope, MDL);
05195                                         return;
05196                                 }
05197 
05198                                 if (newbinding) {
05199                                         binding_value_reference(&bnd->value,
05200                                                                 nv, MDL);
05201                                         bnd->next = scope->bindings;
05202                                         scope->bindings = bnd;
05203                                 } else {
05204                                         binding_value_dereference(&bnd->value,
05205                                                                   MDL);
05206                                         binding_value_reference(&bnd->value,
05207                                                                 nv, MDL);
05208                                 }
05209 
05210                                 binding_value_dereference(&nv, MDL);
05211                                 parse_semi(cfile);
05212                                 break;
05213 
05214                               case ON:
05215                                 lose = 0;
05216                                 /*
05217                                  * Depending on the user config we may
05218                                  * have one or two on statements.  We
05219                                  * need to save information about both
05220                                  * of them until we allocate the
05221                                  * iasubopt to hold them.
05222                                  */
05223                                 if (on_star[0] == NULL) {
05224                                         if (!parse_on_statement (&on_star[0],
05225                                                                  cfile,
05226                                                                  &lose)) {
05227                                                 parse_warn(cfile,
05228                                                            "corrupt lease "
05229                                                            "file; bad ON "
05230                                                            "statement");
05231                                                 skip_to_rbrace (cfile, 1);
05232                                                 return;
05233                                         }
05234                                 } else {
05235                                         if (!parse_on_statement (&on_star[1],
05236                                                                  cfile,
05237                                                                  &lose)) {
05238                                                 parse_warn(cfile,
05239                                                            "corrupt lease "
05240                                                            "file; bad ON "
05241                                                            "statement");
05242                                                 skip_to_rbrace (cfile, 1);
05243                                                 return;
05244                                         }
05245                                 }
05246                                         
05247                                 break;
05248                           
05249                               default:
05250                                 parse_warn(cfile, "corrupt lease file; "
05251                                                   "expecting ia_ta contents, "
05252                                                   "got '%s'", val);
05253                                 skip_to_semi(cfile);
05254                                 continue;
05255                         }
05256                 }
05257 
05258                 if (state == FTS_LAST+1) {
05259                         parse_warn(cfile, "corrupt lease file; "
05260                                           "missing state in iaaddr");
05261                         return;
05262                 }
05263                 if (end_time == -1) {
05264                         parse_warn(cfile, "corrupt lease file; "
05265                                           "missing end time in iaaddr");
05266                         return;
05267                 }
05268 
05269                 iaaddr = NULL;
05270                 if (iasubopt_allocate(&iaaddr, MDL) != ISC_R_SUCCESS) {
05271                         log_fatal("Out of memory.");
05272                 }
05273                 memcpy(&iaaddr->addr, iaddr.iabuf, sizeof(iaaddr->addr));
05274                 iaaddr->plen = 0;
05275                 iaaddr->state = state;
05276                 iaaddr->prefer = prefer;
05277                 iaaddr->valid = valid;
05278                 if (iaaddr->state == FTS_RELEASED)
05279                         iaaddr->hard_lifetime_end_time = end_time;
05280 
05281                 if (scope != NULL) {
05282                         binding_scope_reference(&iaaddr->scope, scope, MDL);
05283                         binding_scope_dereference(&scope, MDL);
05284                 }
05285 
05286                 /*
05287                  * Check on both on statements.  Because of how we write the
05288                  * lease file we know which is which if we have two but it's
05289                  * easier to write the code to be independent.  We do assume
05290                  * that the statements won't overlap.
05291                  */
05292                 for (i = 0;
05293                      (i < 2) && on_star[i] != NULL ;
05294                      i++) {
05295                         if ((on_star[i]->data.on.evtypes & ON_EXPIRY) &&
05296                             on_star[i]->data.on.statements) {
05297                                 executable_statement_reference
05298                                         (&iaaddr->on_star.on_expiry,
05299                                          on_star[i]->data.on.statements, MDL);
05300                         }
05301                         if ((on_star[i]->data.on.evtypes & ON_RELEASE) &&
05302                             on_star[i]->data.on.statements) {
05303                                 executable_statement_reference
05304                                         (&iaaddr->on_star.on_release,
05305                                          on_star[i]->data.on.statements, MDL);
05306                         }
05307                         executable_statement_dereference (&on_star[i], MDL);
05308                 }
05309                         
05310                 /* find the pool this address is in */
05311                 pool = NULL;
05312                 if (find_ipv6_pool(&pool, D6O_IA_TA,
05313                                    &iaaddr->addr) != ISC_R_SUCCESS) {
05314                         inet_ntop(AF_INET6, &iaaddr->addr,
05315                                   addr_buf, sizeof(addr_buf));
05316                         parse_warn(cfile, "no pool found for address %s",
05317                                    addr_buf);
05318                         return;
05319                 }
05320 
05321                 /* remove old information */
05322                 if (cleanup_lease6(ia_ta_active, pool,
05323                                    iaaddr, ia) != ISC_R_SUCCESS) {
05324                         inet_ntop(AF_INET6, &iaaddr->addr,
05325                                   addr_buf, sizeof(addr_buf));
05326                         parse_warn(cfile, "duplicate ta lease for address %s",
05327                                    addr_buf);
05328                 }
05329 
05330                 /*
05331                  * if we like the lease we add it to our various structues
05332                  * otherwise we leave it and it will get cleaned when we
05333                  * do the iasubopt_dereference.
05334                  */
05335                 if ((state == FTS_ACTIVE) || (state == FTS_ABANDONED)) {
05336                         ia_add_iasubopt(ia, iaaddr, MDL);
05337                         ia_reference(&iaaddr->ia, ia, MDL);
05338                         add_lease6(pool, iaaddr, end_time);
05339                 }
05340 
05341                 ipv6_pool_dereference(&pool, MDL);
05342                 iasubopt_dereference(&iaaddr, MDL);
05343         }
05344 
05345         /*
05346          * If we have an existing record for this IA_TA, remove it.
05347          */
05348         old_ia = NULL;
05349         if (ia_hash_lookup(&old_ia, ia_ta_active,
05350                            (unsigned char *)ia->iaid_duid.data,
05351                            ia->iaid_duid.len, MDL)) {
05352                 ia_hash_delete(ia_ta_active, 
05353                                (unsigned char *)ia->iaid_duid.data,
05354                                ia->iaid_duid.len, MDL);
05355                 ia_dereference(&old_ia, MDL);
05356         }
05357 
05358         /*
05359          * If we have addresses, add this, otherwise don't bother.
05360          */
05361         if (ia->num_iasubopt > 0) {
05362                 ia_hash_add(ia_ta_active, 
05363                             (unsigned char *)ia->iaid_duid.data,
05364                             ia->iaid_duid.len, ia, MDL);
05365         }
05366         ia_dereference(&ia, MDL);
05367 #endif /* defined(DHCPv6) */
05368 }
05369 
05370 void
05371 parse_ia_pd_declaration(struct parse *cfile) {
05372 #if !defined(DHCPv6)
05373         parse_warn(cfile, "No DHCPv6 support.");
05374         skip_to_semi(cfile);
05375 #else /* defined(DHCPv6) */
05376         enum dhcp_token token;
05377         struct ia_xx *ia;
05378         const char *val;
05379         struct ia_xx *old_ia;
05380         unsigned int len;
05381         u_int32_t iaid;
05382         struct iaddr iaddr;
05383         u_int8_t plen;
05384         binding_state_t state;
05385         u_int32_t prefer;
05386         u_int32_t valid;
05387         TIME end_time;
05388         struct iasubopt *iapref;
05389         struct ipv6_pool *pool;
05390         char addr_buf[sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255")];
05391         isc_boolean_t newbinding;
05392         struct binding_scope *scope = NULL;
05393         struct binding *bnd;
05394         struct binding_value *nv = NULL;
05395         struct executable_statement *on_star[2] = {NULL, NULL};
05396         int lose, i;
05397 
05398         if (local_family != AF_INET6) {
05399                 parse_warn(cfile, "IA_PD is only supported in DHCPv6 mode.");
05400                 skip_to_semi(cfile);
05401                 return;
05402         }
05403 
05404         token = next_token(&val, &len, cfile);
05405         if (token != STRING) {
05406                 parse_warn(cfile, "corrupt lease file; "
05407                                   "expecting an iaid+ia_pd string");
05408                 skip_to_semi(cfile);
05409                 return;
05410         }
05411         if (len < 5) {
05412                 parse_warn(cfile, "corrupt lease file; "
05413                                   "iaid+ia_pd string too short");
05414                 skip_to_semi(cfile);
05415                 return;
05416         }
05417 
05418         memcpy(&iaid, val, 4);
05419         ia = NULL;
05420         if (ia_allocate(&ia, iaid, val+4, len-4, MDL) != ISC_R_SUCCESS) {
05421                 log_fatal("Out of memory.");
05422         }
05423         ia->ia_type = D6O_IA_PD;
05424 
05425         token = next_token(&val, NULL, cfile);
05426         if (token != LBRACE) {
05427                 parse_warn(cfile, "corrupt lease file; expecting left brace");
05428                 skip_to_semi(cfile);
05429                 return;
05430         }
05431 
05432         for (;;) {
05433                 token = next_token(&val, NULL, cfile);
05434                 if (token == RBRACE) break;
05435 
05436                 if (token == CLTT) {
05437                         ia->cltt = parse_date (cfile);
05438                         continue;
05439                 }
05440 
05441                 if (token != IAPREFIX) {
05442                         parse_warn(cfile, "corrupt lease file; expecting "
05443                                    "IAPREFIX or right brace");
05444                         skip_to_semi(cfile);
05445                         return;
05446                 }
05447 
05448                 if (!parse_ip6_prefix(cfile, &iaddr, &plen)) {
05449                         parse_warn(cfile, "corrupt lease file; "
05450                                           "expecting IPv6 prefix");
05451                         skip_to_semi(cfile);
05452                         return;
05453                 }
05454 
05455                 token = next_token(&val, NULL, cfile);
05456                 if (token != LBRACE) {
05457                         parse_warn(cfile, "corrupt lease file; "
05458                                           "expecting left brace");
05459                         skip_to_semi(cfile);
05460                         return;
05461                 }
05462 
05463                 state = FTS_LAST+1;
05464                 prefer = valid = 0;
05465                 end_time = -1;
05466                 for (;;) {
05467                         token = next_token(&val, NULL, cfile);
05468                         if (token == RBRACE) break;
05469 
05470                         switch(token) {
05471                                 /* Prefix binding state. */
05472                              case BINDING:
05473                                 token = next_token(&val, NULL, cfile);
05474                                 if (token != STATE) {
05475                                         parse_warn(cfile, "corrupt lease file; "
05476                                                           "expecting state");
05477                                         skip_to_semi(cfile);
05478                                         return;
05479                                 }
05480                                 token = next_token(&val, NULL, cfile);
05481                                 switch (token) {
05482                                         case TOKEN_ABANDONED:
05483                                                 state = FTS_ABANDONED;
05484                                                 break;
05485                                         case TOKEN_FREE:
05486                                                 state = FTS_FREE;
05487                                                 break;
05488                                         case TOKEN_ACTIVE:
05489                                                 state = FTS_ACTIVE;
05490                                                 break;
05491                                         case TOKEN_EXPIRED:
05492                                                 state = FTS_EXPIRED;
05493                                                 break;
05494                                         case TOKEN_RELEASED:
05495                                                 state = FTS_RELEASED;
05496                                                 break;
05497                                         default:
05498                                                 parse_warn(cfile,
05499                                                            "corrupt lease "
05500                                                            "file; "
05501                                                            "expecting a "
05502                                                            "binding state.");
05503                                                 skip_to_semi(cfile);
05504                                                 return;
05505                                 }
05506 
05507                                 token = next_token(&val, NULL, cfile);
05508                                 if (token != SEMI) {
05509                                         parse_warn(cfile, "corrupt lease file; "
05510                                                           "expecting "
05511                                                           "semicolon.");
05512                                 }
05513                                 break;
05514 
05515                                 /* Lease preferred lifetime. */
05516                               case PREFERRED_LIFE:
05517                                 token = next_token(&val, NULL, cfile);
05518                                 if (token != NUMBER) {
05519                                         parse_warn(cfile, "%s is not a valid "
05520                                                           "preferred time",
05521                                                    val);
05522                                         skip_to_semi(cfile);
05523                                         continue;
05524                                 }
05525                                 prefer = atoi (val);
05526 
05527                                 /*
05528                                  * Currently we peek for the semi-colon to 
05529                                  * allow processing of older lease files that
05530                                  * don't have the semi-colon.  Eventually we
05531                                  * should remove the peeking code.
05532                                  */
05533                                 token = peek_token(&val, NULL, cfile);
05534                                 if (token == SEMI) {
05535                                         skip_token(&val, NULL, cfile);
05536                                 } else {
05537                                         parse_warn(cfile,
05538                                                    "corrupt lease file; "
05539                                                    "expecting semicolon.");
05540                                 }
05541                                 break;
05542 
05543                                 /* Lease valid lifetime. */
05544                               case MAX_LIFE:
05545                                 token = next_token(&val, NULL, cfile);
05546                                 if (token != NUMBER) {
05547                                         parse_warn(cfile, "%s is not a valid "
05548                                                           "max time",
05549                                                    val);
05550                                         skip_to_semi(cfile);
05551                                         continue;
05552                                 }
05553                                 valid = atoi (val);
05554 
05555                                 /*
05556                                  * Currently we peek for the semi-colon to 
05557                                  * allow processing of older lease files that
05558                                  * don't have the semi-colon.  Eventually we
05559                                  * should remove the peeking code.
05560                                  */
05561                                 token = peek_token(&val, NULL, cfile);
05562                                 if (token == SEMI) {
05563                                         skip_token(&val, NULL, cfile);
05564                                 } else {
05565                                         parse_warn(cfile,
05566                                                    "corrupt lease file; "
05567                                                    "expecting semicolon.");
05568                                 }
05569                                 break;
05570 
05571                                 /* Prefix expiration time. */
05572                               case ENDS:
05573                                 end_time = parse_date(cfile);
05574                                 break;
05575 
05576                                 /* Prefix binding scopes. */
05577                               case TOKEN_SET:
05578                                 token = next_token(&val, NULL, cfile);
05579                                 if ((token != NAME) &&
05580                                     (token != NUMBER_OR_NAME)) {
05581                                         parse_warn(cfile, "%s is not a valid "
05582                                                           "variable name",
05583                                                    val);
05584                                         skip_to_semi(cfile);
05585                                         continue;
05586                                 }
05587 
05588                                 if (scope != NULL)
05589                                         bnd = find_binding(scope, val);
05590                                 else {
05591                                         if (!binding_scope_allocate(&scope,
05592                                                                     MDL)) {
05593                                                 log_fatal("Out of memory for "
05594                                                           "lease binding "
05595                                                           "scope.");
05596                                         }
05597 
05598                                         bnd = NULL;
05599                                 }
05600 
05601                                 if (bnd == NULL) {
05602                                         bnd = dmalloc(sizeof(*bnd),
05603                                                           MDL);
05604                                         if (bnd == NULL) {
05605                                                 log_fatal("No memory for "
05606                                                           "prefix binding.");
05607                                         }
05608 
05609                                         bnd->name = dmalloc(strlen(val) + 1,
05610                                                             MDL);
05611                                         if (bnd->name == NULL) {
05612                                                 log_fatal("No memory for "
05613                                                           "binding name.");
05614                                         }
05615                                         strcpy(bnd->name, val);
05616 
05617                                         newbinding = ISC_TRUE;
05618                                 } else {
05619                                         newbinding = ISC_FALSE;
05620                                 }
05621 
05622                                 if (!binding_value_allocate(&nv, MDL)) {
05623                                         log_fatal("no memory for binding "
05624                                                   "value.");
05625                                 }
05626 
05627                                 token = next_token(NULL, NULL, cfile);
05628                                 if (token != EQUAL) {
05629                                         parse_warn(cfile, "expecting '=' in "
05630                                                           "set statement.");
05631                                         goto binding_err;
05632                                 }
05633 
05634                                 if (!parse_binding_value(cfile, nv)) {
05635                                       binding_err:
05636                                         binding_value_dereference(&nv, MDL);
05637                                         binding_scope_dereference(&scope, MDL);
05638                                         return;
05639                                 }
05640 
05641                                 if (newbinding) {
05642                                         binding_value_reference(&bnd->value,
05643                                                                 nv, MDL);
05644                                         bnd->next = scope->bindings;
05645                                         scope->bindings = bnd;
05646                                 } else {
05647                                         binding_value_dereference(&bnd->value,
05648                                                                   MDL);
05649                                         binding_value_reference(&bnd->value,
05650                                                                 nv, MDL);
05651                                 }
05652 
05653                                 binding_value_dereference(&nv, MDL);
05654                                 parse_semi(cfile);
05655                                 break;
05656 
05657                               case ON:
05658                                 lose = 0;
05659                                 /*
05660                                  * Depending on the user config we may
05661                                  * have one or two on statements.  We
05662                                  * need to save information about both
05663                                  * of them until we allocate the
05664                                  * iasubopt to hold them.
05665                                  */
05666                                 if (on_star[0] == NULL) {
05667                                         if (!parse_on_statement (&on_star[0],
05668                                                                  cfile,
05669                                                                  &lose)) {
05670                                                 parse_warn(cfile,
05671                                                            "corrupt lease "
05672                                                            "file; bad ON "
05673                                                            "statement");
05674                                                 skip_to_rbrace (cfile, 1);
05675                                                 return;
05676                                         }
05677                                 } else {
05678                                         if (!parse_on_statement (&on_star[1],
05679                                                                  cfile,
05680                                                                  &lose)) {
05681                                                 parse_warn(cfile,
05682                                                            "corrupt lease "
05683                                                            "file; bad ON "
05684                                                            "statement");
05685                                                 skip_to_rbrace (cfile, 1);
05686                                                 return;
05687                                         }
05688                                 }
05689 
05690                                 break;
05691                           
05692                               default:
05693                                 parse_warn(cfile, "corrupt lease file; "
05694                                                   "expecting ia_pd contents, "
05695                                                   "got '%s'", val);
05696                                 skip_to_semi(cfile);
05697                                 continue;
05698                         }
05699                 }
05700 
05701                 if (state == FTS_LAST+1) {
05702                         parse_warn(cfile, "corrupt lease file; "
05703                                           "missing state in iaprefix");
05704                         return;
05705                 }
05706                 if (end_time == -1) {
05707                         parse_warn(cfile, "corrupt lease file; "
05708                                           "missing end time in iaprefix");
05709                         return;
05710                 }
05711 
05712                 iapref = NULL;
05713                 if (iasubopt_allocate(&iapref, MDL) != ISC_R_SUCCESS) {
05714                         log_fatal("Out of memory.");
05715                 }
05716                 memcpy(&iapref->addr, iaddr.iabuf, sizeof(iapref->addr));
05717                 iapref->plen = plen;
05718                 iapref->state = state;
05719                 iapref->prefer = prefer;
05720                 iapref->valid = valid;
05721                 if (iapref->state == FTS_RELEASED)
05722                         iapref->hard_lifetime_end_time = end_time;
05723 
05724                 if (scope != NULL) {
05725                         binding_scope_reference(&iapref->scope, scope, MDL);
05726                         binding_scope_dereference(&scope, MDL);
05727                 }
05728 
05729                 /*
05730                  * Check on both on statements.  Because of how we write the
05731                  * lease file we know which is which if we have two but it's
05732                  * easier to write the code to be independent.  We do assume
05733                  * that the statements won't overlap.
05734                  */
05735                 for (i = 0;
05736                      (i < 2) && on_star[i] != NULL ;
05737                      i++) {
05738                         if ((on_star[i]->data.on.evtypes & ON_EXPIRY) &&
05739                             on_star[i]->data.on.statements) {
05740                                 executable_statement_reference
05741                                         (&iapref->on_star.on_expiry,
05742                                          on_star[i]->data.on.statements, MDL);
05743                         }
05744                         if ((on_star[i]->data.on.evtypes & ON_RELEASE) &&
05745                             on_star[i]->data.on.statements) {
05746                                 executable_statement_reference
05747                                         (&iapref->on_star.on_release,
05748                                          on_star[i]->data.on.statements, MDL);
05749                         }
05750                         executable_statement_dereference (&on_star[i], MDL);
05751                 }
05752                         
05753                 /* find the pool this address is in */
05754                 pool = NULL;
05755                 if (find_ipv6_pool(&pool, D6O_IA_PD,
05756                                    &iapref->addr) != ISC_R_SUCCESS) {
05757                         inet_ntop(AF_INET6, &iapref->addr,
05758                                   addr_buf, sizeof(addr_buf));
05759                         parse_warn(cfile, "no pool found for address %s",
05760                                    addr_buf);
05761                         return;
05762                 }
05763 
05764                 /* remove old information */
05765                 if (cleanup_lease6(ia_pd_active, pool,
05766                                    iapref, ia) != ISC_R_SUCCESS) {
05767                         inet_ntop(AF_INET6, &iapref->addr,
05768                                   addr_buf, sizeof(addr_buf));
05769                         parse_warn(cfile, "duplicate pd lease for address %s",
05770                                    addr_buf);
05771                 }
05772 
05773                 /*
05774                  * if we like the lease we add it to our various structues
05775                  * otherwise we leave it and it will get cleaned when we
05776                  * do the iasubopt_dereference.
05777                  */
05778                 if ((state == FTS_ACTIVE) || (state == FTS_ABANDONED)) {
05779                         ia_add_iasubopt(ia, iapref, MDL);
05780                         ia_reference(&iapref->ia, ia, MDL);
05781                         add_lease6(pool, iapref, end_time);
05782                 }
05783 
05784                 ipv6_pool_dereference(&pool, MDL);
05785                 iasubopt_dereference(&iapref, MDL);
05786         }
05787 
05788         /*
05789          * If we have an existing record for this IA_PD, remove it.
05790          */
05791         old_ia = NULL;
05792         if (ia_hash_lookup(&old_ia, ia_pd_active,
05793                            (unsigned char *)ia->iaid_duid.data,
05794                            ia->iaid_duid.len, MDL)) {
05795                 ia_hash_delete(ia_pd_active,
05796                                (unsigned char *)ia->iaid_duid.data,
05797                                ia->iaid_duid.len, MDL);
05798                 ia_dereference(&old_ia, MDL);
05799         }
05800 
05801         /*
05802          * If we have prefixes, add this, otherwise don't bother.
05803          */
05804         if (ia->num_iasubopt > 0) {
05805                 ia_hash_add(ia_pd_active, 
05806                             (unsigned char *)ia->iaid_duid.data,
05807                             ia->iaid_duid.len, ia, MDL);
05808         }
05809         ia_dereference(&ia, MDL);
05810 #endif /* defined(DHCPv6) */
05811 }
05812 
05813 #ifdef DHCPv6 
05814 /*
05815  * When we parse a server-duid statement in a lease file, we are 
05816  * looking at the saved server DUID from a previous run. In this case
05817  * we expect it to be followed by the binary representation of the
05818  * DUID stored in a string:
05819  *
05820  * server-duid "\000\001\000\001\015\221\034JRT\000\0224Y";
05821  */
05822 void 
05823 parse_server_duid(struct parse *cfile) {
05824         enum dhcp_token token;
05825         const char *val;
05826         unsigned int len;
05827         struct data_string duid;
05828 
05829         token = next_token(&val, &len, cfile);
05830         if (token != STRING) {
05831                 parse_warn(cfile, "corrupt lease file; expecting a DUID");
05832                 skip_to_semi(cfile);
05833                 return;
05834         }
05835 
05836         memset(&duid, 0, sizeof(duid));
05837         duid.len = len;
05838         if (!buffer_allocate(&duid.buffer, duid.len, MDL)) {
05839                 log_fatal("Out of memory storing DUID");
05840         }
05841         duid.data = (unsigned char *)duid.buffer->data;
05842         memcpy(duid.buffer->data, val, len);
05843 
05844         set_server_duid(&duid);
05845 
05846         data_string_forget(&duid, MDL);
05847 
05848         token = next_token(&val, &len, cfile);
05849         if (token != SEMI) {
05850                 parse_warn(cfile, "corrupt lease file; expecting a semicolon");
05851                 skip_to_semi(cfile);
05852                 return;
05853         }
05854 }
05855 
05856 /*
05857  * When we parse a server-duid statement in a config file, we will
05858  * have the type of the server DUID to generate, and possibly the
05859  * actual value defined.
05860  *
05861  * server-duid llt;
05862  * server-duid llt ethernet|ieee802|fddi 213982198 00:16:6F:49:7D:9B;
05863  * server-duid ll;
05864  * server-duid ll ethernet|ieee802|fddi 00:16:6F:49:7D:9B;
05865  * server-duid en 2495 "enterprise-specific-identifier-1234";
05866  */
05867 void 
05868 parse_server_duid_conf(struct parse *cfile) {
05869         enum dhcp_token token;
05870         const char *val;
05871         unsigned int len;
05872         u_int32_t enterprise_number;
05873         int ll_type;
05874         struct data_string ll_addr;
05875         u_int32_t llt_time;
05876         struct data_string duid;
05877         int duid_type_num;
05878 
05879         /*
05880          * Consume the SERVER_DUID token.
05881          */
05882         skip_token(NULL, NULL, cfile);
05883 
05884         /*
05885          * Obtain the DUID type.
05886          */
05887         token = next_token(&val, NULL, cfile);
05888 
05889         /* 
05890          * Enterprise is the easiest - enterprise number and raw data
05891          * are required.
05892          */
05893         if (token == EN) {
05894                 /*
05895                  * Get enterprise number and identifier.
05896                  */
05897                 token = next_token(&val, NULL, cfile);
05898                 if (token != NUMBER) {
05899                         parse_warn(cfile, "enterprise number expected");
05900                         skip_to_semi(cfile);
05901                         return;
05902                 }
05903                 enterprise_number = atoi(val);
05904 
05905                 token = next_token(&val, &len, cfile);
05906                 if (token != STRING) {
05907                         parse_warn(cfile, "identifier expected");
05908                         skip_to_semi(cfile);
05909                         return;
05910                 }
05911 
05912                 /*
05913                  * Save the DUID.
05914                  */
05915                 memset(&duid, 0, sizeof(duid));
05916                 duid.len = 2 + 4 + len;
05917                 if (!buffer_allocate(&duid.buffer, duid.len, MDL)) {
05918                         log_fatal("Out of memory storing DUID");
05919                 }
05920                 duid.data = (unsigned char *)duid.buffer->data;
05921                 putUShort(duid.buffer->data, DUID_EN);
05922                 putULong(duid.buffer->data + 2, enterprise_number);
05923                 memcpy(duid.buffer->data + 6, val, len);
05924 
05925                 set_server_duid(&duid);
05926                 data_string_forget(&duid, MDL);
05927         }
05928 
05929         /* 
05930          * Next easiest is the link-layer DUID. It consists only of
05931          * the LL directive, or optionally the specific value to use.
05932          *
05933          * If we have LL only, then we set the type. If we have the
05934          * value, then we set the actual DUID.
05935          */
05936         else if (token == LL) {
05937                 if (peek_token(NULL, NULL, cfile) == SEMI) {
05938                         set_server_duid_type(DUID_LL);
05939                 } else {
05940                         /*
05941                          * Get our hardware type and address.
05942                          */
05943                         token = next_token(NULL, NULL, cfile);
05944                         switch (token) {
05945                               case ETHERNET:
05946                                 ll_type = HTYPE_ETHER;
05947                                 break;
05948                               case TOKEN_RING:
05949                                 ll_type = HTYPE_IEEE802;
05950                                 break;
05951                               case TOKEN_FDDI:
05952                                 ll_type = HTYPE_FDDI;
05953                                 break;
05954                               default:
05955                                 parse_warn(cfile, "hardware type expected");
05956                                 skip_to_semi(cfile);
05957                                 return;
05958                         } 
05959                         memset(&ll_addr, 0, sizeof(ll_addr));
05960                         if (!parse_cshl(&ll_addr, cfile)) {
05961                                 return;
05962                         }
05963 
05964                         /*
05965                          * Save the DUID.
05966                          */
05967                         memset(&duid, 0, sizeof(duid));
05968                         duid.len = 2 + 2 + ll_addr.len;
05969                         if (!buffer_allocate(&duid.buffer, duid.len, MDL)) {
05970                                 log_fatal("Out of memory storing DUID");
05971                         }
05972                         duid.data = (unsigned char *)duid.buffer->data;
05973                         putUShort(duid.buffer->data, DUID_LL);
05974                         putULong(duid.buffer->data + 2, ll_type);
05975                         memcpy(duid.buffer->data + 4, 
05976                                ll_addr.data, ll_addr.len);
05977 
05978                         set_server_duid(&duid);
05979                         data_string_forget(&duid, MDL);
05980                         data_string_forget(&ll_addr, MDL);
05981                 }
05982         }
05983 
05984         /* 
05985          * Finally the link-layer DUID plus time. It consists only of
05986          * the LLT directive, or optionally the specific value to use.
05987          *
05988          * If we have LLT only, then we set the type. If we have the
05989          * value, then we set the actual DUID.
05990          */
05991         else if (token == LLT) {
05992                 if (peek_token(NULL, NULL, cfile) == SEMI) {
05993                         set_server_duid_type(DUID_LLT);
05994                 } else {
05995                         /*
05996                          * Get our hardware type, timestamp, and address.
05997                          */
05998                         token = next_token(NULL, NULL, cfile);
05999                         switch (token) {
06000                               case ETHERNET:
06001                                 ll_type = HTYPE_ETHER;
06002                                 break;
06003                               case TOKEN_RING:
06004                                 ll_type = HTYPE_IEEE802;
06005                                 break;
06006                               case TOKEN_FDDI:
06007                                 ll_type = HTYPE_FDDI;
06008                                 break;
06009                               default:
06010                                 parse_warn(cfile, "hardware type expected");
06011                                 skip_to_semi(cfile);
06012                                 return;
06013                         } 
06014                         
06015                         token = next_token(&val, NULL, cfile);
06016                         if (token != NUMBER) {
06017                                 parse_warn(cfile, "timestamp expected");
06018                                 skip_to_semi(cfile);
06019                                 return;
06020                         }
06021                         llt_time = atoi(val);
06022 
06023                         memset(&ll_addr, 0, sizeof(ll_addr));
06024                         if (!parse_cshl(&ll_addr, cfile)) {
06025                                 return;
06026                         }
06027 
06028                         /*
06029                          * Save the DUID.
06030                          */
06031                         memset(&duid, 0, sizeof(duid));
06032                         duid.len = 2 + 2 + 4 + ll_addr.len;
06033                         if (!buffer_allocate(&duid.buffer, duid.len, MDL)) {
06034                                 log_fatal("Out of memory storing DUID");
06035                         }
06036                         duid.data = (unsigned char *)duid.buffer->data;
06037                         putUShort(duid.buffer->data, DUID_LLT);
06038                         putULong(duid.buffer->data + 2, ll_type);
06039                         putULong(duid.buffer->data + 4, llt_time);
06040                         memcpy(duid.buffer->data + 8, 
06041                                ll_addr.data, ll_addr.len);
06042 
06043                         set_server_duid(&duid);
06044                         data_string_forget(&duid, MDL);
06045                         data_string_forget(&ll_addr, MDL);
06046                 }
06047         }
06048 
06049         /*
06050          * If users want they can use a number for DUID types.
06051          * This is useful for supporting future, not-yet-defined
06052          * DUID types.
06053          *
06054          * In this case, they have to put in the complete value.
06055          *
06056          * This also works for existing DUID types of course. 
06057          */
06058         else if (token == NUMBER) {
06059                 duid_type_num = atoi(val);
06060 
06061                 token = next_token(&val, &len, cfile);
06062                 if (token != STRING) {
06063                         parse_warn(cfile, "identifier expected");
06064                         skip_to_semi(cfile);
06065                         return;
06066                 }
06067 
06068                 /*
06069                  * Save the DUID.
06070                  */
06071                 memset(&duid, 0, sizeof(duid));
06072                 duid.len = 2 + len;
06073                 if (!buffer_allocate(&duid.buffer, duid.len, MDL)) {
06074                         log_fatal("Out of memory storing DUID");
06075                 }
06076                 duid.data = (unsigned char *)duid.buffer->data;
06077                 putUShort(duid.buffer->data, duid_type_num);
06078                 memcpy(duid.buffer->data + 2, val, len);
06079 
06080                 set_server_duid(&duid);
06081                 data_string_forget(&duid, MDL);
06082         }
06083 
06084         /*
06085          * Anything else is an error.
06086          */
06087         else {
06088                 parse_warn(cfile, "DUID type of LLT, EN, or LL expected");
06089                 skip_to_semi(cfile);
06090                 return;
06091         }
06092 
06093         /*
06094          * Finally consume our trailing semicolon.
06095          */
06096         token = next_token(NULL, NULL, cfile);
06097         if (token != SEMI) {
06098                 parse_warn(cfile, "semicolon expected");
06099                 skip_to_semi(cfile);
06100         }
06101 }
06102 
06103 #endif /* DHCPv6 */
06104 

Generated on 5 Apr 2014 for ISC DHCP by  doxygen 1.6.1