client/clparse.c

Go to the documentation of this file.
00001 /* clparse.c
00002 
00003    Parser for dhclient config and lease files... */
00004 
00005 /*
00006  * Copyright (c) 2004-2014 by Internet Systems Consortium, Inc. ("ISC")
00007  * Copyright (c) 1996-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 
00029 #include "dhcpd.h"
00030 #include <errno.h>
00031 
00032 struct client_config top_level_config;
00033 
00034 #define NUM_DEFAULT_REQUESTED_OPTS      15
00035 struct option *default_requested_options[NUM_DEFAULT_REQUESTED_OPTS + 1];
00036 
00037 static void parse_client_default_duid(struct parse *cfile);
00038 static void parse_client6_lease_statement(struct parse *cfile);
00039 #ifdef DHCPv6
00040 static struct dhc6_ia *parse_client6_ia_na_statement(struct parse *cfile);
00041 static struct dhc6_ia *parse_client6_ia_ta_statement(struct parse *cfile);
00042 static struct dhc6_ia *parse_client6_ia_pd_statement(struct parse *cfile);
00043 static struct dhc6_addr *parse_client6_iaaddr_statement(struct parse *cfile);
00044 static struct dhc6_addr *parse_client6_iaprefix_statement(struct parse *cfile);
00045 #endif /* DHCPv6 */
00046 
00047 /* client-conf-file :== client-declarations END_OF_FILE
00048    client-declarations :== <nil>
00049                          | client-declaration
00050                          | client-declarations client-declaration */
00051 
00052 isc_result_t read_client_conf ()
00053 {
00054         struct client_config *config;
00055         struct interface_info *ip;
00056         isc_result_t status;
00057         unsigned code;
00058 
00059         /* 
00060          * TODO: LATER constant is very undescriptive. We should review it and
00061          * change it to something more descriptive or even better remove it
00062          * completely as it is currently not used.
00063          */
00064 #ifdef LATER
00065         struct parse *parse = NULL;
00066 #endif
00067 
00068         /* Initialize the default request list. */
00069         memset(default_requested_options, 0, sizeof(default_requested_options));
00070 
00071         /* 1 */
00072         code = DHO_SUBNET_MASK;
00073         option_code_hash_lookup(&default_requested_options[0],
00074                                 dhcp_universe.code_hash, &code, 0, MDL);
00075 
00076         /* 2 */
00077         code = DHO_BROADCAST_ADDRESS;
00078         option_code_hash_lookup(&default_requested_options[1],
00079                                 dhcp_universe.code_hash, &code, 0, MDL);
00080 
00081         /* 3 */
00082         code = DHO_TIME_OFFSET;
00083         option_code_hash_lookup(&default_requested_options[2],
00084                                 dhcp_universe.code_hash, &code, 0, MDL);
00085 
00086         /* 4 */
00087         /* The Classless Static Routes option code MUST appear in the parameter
00088      * request list prior to both the Router option code and the Static
00089      * Routes option code, if present. (RFC3442)
00090          */
00091         code = DHO_CLASSLESS_STATIC_ROUTES;
00092         option_code_hash_lookup(&default_requested_options[3],
00093                                 dhcp_universe.code_hash, &code, 0, MDL);
00094 
00095         /* 5 */
00096         code = DHO_DOMAIN_NAME;
00097         option_code_hash_lookup(&default_requested_options[4],
00098                                 dhcp_universe.code_hash, &code, 0, MDL);
00099 
00100         /* 6 */
00101         code = DHO_DOMAIN_NAME_SERVERS;
00102         option_code_hash_lookup(&default_requested_options[5],
00103                                 dhcp_universe.code_hash, &code, 0, MDL);
00104 
00105         /* 7 */
00106         code = DHO_HOST_NAME;
00107         option_code_hash_lookup(&default_requested_options[6],
00108                                 dhcp_universe.code_hash, &code, 0, MDL);
00109 
00110         /* 8 */
00111         code = D6O_NAME_SERVERS;
00112         option_code_hash_lookup(&default_requested_options[7],
00113                                 dhcpv6_universe.code_hash, &code, 0, MDL);
00114 
00115         /* 9 */
00116         code = D6O_DOMAIN_SEARCH;
00117         option_code_hash_lookup(&default_requested_options[8],
00118                                 dhcpv6_universe.code_hash, &code, 0, MDL);
00119 
00120         /* 10 */
00121         code = DHO_NIS_DOMAIN;
00122         option_code_hash_lookup(&default_requested_options[9],
00123                                 dhcp_universe.code_hash, &code, 0, MDL);
00124 
00125         /* 11 */
00126         code = DHO_NIS_SERVERS;
00127         option_code_hash_lookup(&default_requested_options[10],
00128                                 dhcp_universe.code_hash, &code, 0, MDL);
00129 
00130         /* 12 */
00131         code = DHO_NTP_SERVERS;
00132         option_code_hash_lookup(&default_requested_options[11],
00133                                 dhcp_universe.code_hash, &code, 0, MDL);
00134 
00135         /* 13 */
00136         code = DHO_INTERFACE_MTU;
00137         option_code_hash_lookup(&default_requested_options[12],
00138                                 dhcp_universe.code_hash, &code, 0, MDL);
00139 
00140         /* 14 */
00141         code = DHO_DOMAIN_SEARCH;
00142         option_code_hash_lookup(&default_requested_options[13],
00143                                 dhcp_universe.code_hash, &code, 0, MDL);
00144 
00145         /* 15 */
00146         code = DHO_ROUTERS;
00147         option_code_hash_lookup(&default_requested_options[14],
00148                                 dhcp_universe.code_hash, &code, 0, MDL);
00149 
00150         for (code = 0 ; code < NUM_DEFAULT_REQUESTED_OPTS ; code++) {
00151                 if (default_requested_options[code] == NULL)
00152                         log_fatal("Unable to find option definition for "
00153                                   "index %u during default parameter request "
00154                                   "assembly.", code);
00155         }
00156 
00157         /* Initialize the top level client configuration. */
00158         memset (&top_level_config, 0, sizeof top_level_config);
00159 
00160         /* Set some defaults... */
00161         top_level_config.timeout = 60;
00162         top_level_config.select_interval = 0;
00163         top_level_config.reboot_timeout = 10;
00164         top_level_config.retry_interval = 300;
00165         top_level_config.backoff_cutoff = 15;
00166         top_level_config.initial_interval = 3;
00167 
00168         /*
00169          * RFC 2131, section 4.4.1 specifies that the client SHOULD wait a
00170          * random time between 1 and 10 seconds. However, we choose to not
00171          * implement this default. If user is inclined to really have that
00172          * delay, he is welcome to do so, using 'initial-delay X;' parameter
00173          * in config file.
00174          */
00175         top_level_config.initial_delay = 0;
00176 
00177         top_level_config.bootp_policy = P_ACCEPT;
00178         top_level_config.script_name = path_dhclient_script;
00179         top_level_config.requested_options = default_requested_options;
00180         top_level_config.omapi_port = -1;
00181         top_level_config.do_forward_update = 1;
00182         /* Requested lease time, used by DHCPv6 (DHCPv4 uses the option cache)
00183          */
00184         top_level_config.requested_lease = 7200;
00185         top_level_config.bootp_broadcast_always = 0;
00186 
00187         group_allocate (&top_level_config.on_receipt, MDL);
00188         if (!top_level_config.on_receipt)
00189                 log_fatal ("no memory for top-level on_receipt group");
00190 
00191         group_allocate (&top_level_config.on_transmission, MDL);
00192         if (!top_level_config.on_transmission)
00193                 log_fatal ("no memory for top-level on_transmission group");
00194 
00195         status = read_client_conf_file (path_dhclient_conf,
00196                                         (struct interface_info *)0,
00197                                         &top_level_config);
00198 
00199         if (status != ISC_R_SUCCESS) {
00200                 ;
00201 #ifdef LATER
00202                 /* Set up the standard name service updater routine. */
00203                 status = new_parse(&parse, -1, default_client_config,
00204                                    sizeof(default_client_config) - 1,
00205                                    "default client configuration", 0);
00206                 if (status != ISC_R_SUCCESS)
00207                         log_fatal ("can't begin default client config!");
00208         }
00209 
00210         if (parse != NULL) {
00211                 do {
00212                         token = peek_token(&val, NULL, cfile);
00213                         if (token == END_OF_FILE)
00214                                 break;
00215                         parse_client_statement(cfile, NULL, &top_level_config);
00216                 } while (1);
00217                 end_parse(&parse);
00218 #endif
00219         }
00220 
00221         /* Set up state and config structures for clients that don't
00222            have per-interface configuration statements. */
00223         config = (struct client_config *)0;
00224         for (ip = interfaces; ip; ip = ip -> next) {
00225                 if (!ip -> client) {
00226                         ip -> client = (struct client_state *)
00227                                 dmalloc (sizeof (struct client_state), MDL);
00228                         if (!ip -> client)
00229                                 log_fatal ("no memory for client state.");
00230                         memset (ip -> client, 0, sizeof *(ip -> client));
00231                         ip -> client -> interface = ip;
00232                 }
00233 
00234                 if (!ip -> client -> config) {
00235                         if (!config) {
00236                                 config = (struct client_config *)
00237                                         dmalloc (sizeof (struct client_config),
00238                                                  MDL);
00239                                 if (!config)
00240                                     log_fatal ("no memory for client config.");
00241                                 memcpy (config, &top_level_config,
00242                                         sizeof top_level_config);
00243                         }
00244                         ip -> client -> config = config;
00245                 }
00246         }
00247         return status;
00248 }
00249 
00250 int read_client_conf_file (const char *name, struct interface_info *ip,
00251                            struct client_config *client)
00252 {
00253         int file;
00254         struct parse *cfile;
00255         const char *val;
00256         int token;
00257         isc_result_t status;
00258 
00259         if ((file = open (name, O_RDONLY | O_CLOEXEC)) < 0)
00260                 return uerr2isc (errno);
00261 
00262         cfile = NULL;
00263         status = new_parse(&cfile, file, NULL, 0, path_dhclient_conf, 0);
00264         if (status != ISC_R_SUCCESS || cfile == NULL)
00265                 return status;
00266 
00267         do {
00268                 token = peek_token (&val, (unsigned *)0, cfile);
00269                 if (token == END_OF_FILE)
00270                         break;
00271                 parse_client_statement (cfile, ip, client);
00272         } while (1);
00273         skip_token(&val, (unsigned *)0, cfile);
00274         status = (cfile -> warnings_occurred
00275                   ? DHCP_R_BADPARSE
00276                   : ISC_R_SUCCESS);
00277         end_parse (&cfile);
00278         return status;
00279 }
00280 
00281 
00282 /* lease-file :== client-lease-statements END_OF_FILE
00283    client-lease-statements :== <nil>
00284                      | client-lease-statements LEASE client-lease-statement */
00285 
00286 void read_client_leases ()
00287 {
00288         int file;
00289         isc_result_t status;
00290         struct parse *cfile;
00291         const char *val;
00292         int token;
00293 
00294         /* Open the lease file.   If we can't open it, just return -
00295            we can safely trust the server to remember our state. */
00296         if ((file = open (path_dhclient_db, O_RDONLY | O_CLOEXEC)) < 0)
00297                 return;
00298 
00299         cfile = NULL;
00300         status = new_parse(&cfile, file, NULL, 0, path_dhclient_db, 0);
00301         if (status != ISC_R_SUCCESS || cfile == NULL)
00302                 return;
00303 
00304         do {
00305                 token = next_token (&val, (unsigned *)0, cfile);
00306                 if (token == END_OF_FILE)
00307                         break;
00308 
00309                 switch (token) {
00310                       case DEFAULT_DUID:
00311                         parse_client_default_duid(cfile);
00312                         break;
00313 
00314                       case LEASE:
00315                         parse_client_lease_statement(cfile, 0);
00316                         break;
00317 
00318                       case LEASE6:
00319                         parse_client6_lease_statement(cfile);
00320                         break;
00321 
00322                       default:
00323                         log_error ("Corrupt lease file - possible data loss!");
00324                         skip_to_semi (cfile);
00325                         break;
00326                 }
00327         } while (1);
00328 
00329         end_parse (&cfile);
00330 }
00331 
00332 /* client-declaration :== 
00333         SEND option-decl |
00334         DEFAULT option-decl |
00335         SUPERSEDE option-decl |
00336         PREPEND option-decl |
00337         APPEND option-decl |
00338         hardware-declaration |
00339         ALSO REQUEST option-list |
00340         ALSO REQUIRE option-list |
00341         REQUEST option-list |
00342         REQUIRE option-list |
00343         TIMEOUT number |
00344         RETRY number |
00345         REBOOT number |
00346         SELECT_TIMEOUT number |
00347         SCRIPT string |
00348         VENDOR_SPACE string |
00349         interface-declaration |
00350         LEASE client-lease-statement |
00351         ALIAS client-lease-statement |
00352         KEY key-definition |
00353         BOOTP_BROADCAST_ALWAYS */
00354 
00355 void parse_client_statement (cfile, ip, config)
00356         struct parse *cfile;
00357         struct interface_info *ip;
00358         struct client_config *config;
00359 {
00360         int token;
00361         const char *val;
00362         struct option *option = NULL;
00363         struct executable_statement *stmt;
00364         int lose;
00365         char *name;
00366         enum policy policy;
00367         int known;
00368         int tmp, i;
00369         isc_result_t status;
00370         struct option ***append_list, **new_list, **cat_list;
00371 
00372         switch (peek_token (&val, (unsigned *)0, cfile)) {
00373               case INCLUDE:
00374                 skip_token(&val, (unsigned *)0, cfile);
00375                 token = next_token (&val, (unsigned *)0, cfile);
00376                 if (token != STRING) {
00377                         parse_warn (cfile, "filename string expected.");
00378                         skip_to_semi (cfile);
00379                 } else {
00380                         status = read_client_conf_file (val, ip, config);
00381                         if (status != ISC_R_SUCCESS)
00382                                 parse_warn (cfile, "%s: bad parse.", val);
00383                         parse_semi (cfile);
00384                 }
00385                 return;
00386                 
00387               case KEY:
00388                 skip_token(&val, (unsigned *)0, cfile);
00389                 if (ip) {
00390                         /* This may seem arbitrary, but there's a reason for
00391                            doing it: the authentication key database is not
00392                            scoped.  If we allow the user to declare a key other
00393                            than in the outer scope, the user is very likely to
00394                            believe that the key will only be used in that
00395                            scope.  If the user only wants the key to be used on
00396                            one interface, because it's known that the other
00397                            interface may be connected to an insecure net and
00398                            the secret key is considered sensitive, we don't
00399                            want to lull them into believing they've gotten
00400                            their way.   This is a bit contrived, but people
00401                            tend not to be entirely rational about security. */
00402                         parse_warn (cfile, "key definition not allowed here.");
00403                         skip_to_semi (cfile);
00404                         break;
00405                 }
00406                 parse_key (cfile);
00407                 return;
00408 
00409               case TOKEN_ALSO:
00410                 /* consume ALSO */
00411                 skip_token(&val, NULL, cfile);
00412 
00413                 /* consume type of ALSO list. */
00414                 token = next_token(&val, NULL, cfile);
00415 
00416                 if (token == REQUEST) {
00417                         append_list = &config->requested_options;
00418                 } else if (token == REQUIRE) {
00419                         append_list = &config->required_options;
00420                 } else {
00421                         parse_warn(cfile, "expected REQUEST or REQUIRE list");
00422                         skip_to_semi(cfile);
00423                         return;
00424                 }
00425 
00426                 /* If there is no list, cut the concat short. */
00427                 if (*append_list == NULL) {
00428                         parse_option_list(cfile, append_list);
00429                         return;
00430                 }
00431 
00432                 /* Count the length of the existing list. */
00433                 for (i = 0 ; (*append_list)[i] != NULL ; i++)
00434                         ; /* This space intentionally left blank. */
00435 
00436                 /* If there's no codes on the list, cut the concat short. */
00437                 if (i == 0) {
00438                         parse_option_list(cfile, append_list);
00439                         return;
00440                 }
00441 
00442                 tmp = parse_option_list(cfile, &new_list);
00443 
00444                 if (tmp == 0 || new_list == NULL)
00445                         return;
00446 
00447                 /* Allocate 'i + tmp' buckets plus a terminator. */
00448                 cat_list = dmalloc(sizeof(struct option *) * (i + tmp + 1),
00449                                    MDL);
00450 
00451                 if (cat_list == NULL) {
00452                         log_error("Unable to allocate memory for new "
00453                                   "request list.");
00454                         skip_to_semi(cfile);
00455                         return;
00456                 }
00457 
00458                 for (i = 0 ; (*append_list)[i] != NULL ; i++)
00459                         option_reference(&cat_list[i], (*append_list)[i], MDL);
00460 
00461                 tmp = i;
00462 
00463                 for (i = 0 ; new_list[i] != 0 ; i++)
00464                         option_reference(&cat_list[tmp++], new_list[i], MDL);
00465 
00466                 cat_list[tmp] = 0;
00467 
00468                 /* XXX: We cannot free the old list, because it may have been
00469                  * XXX: assigned from an outer configuration scope (or may be
00470                  * XXX: the static default setting).
00471                  */
00472                 *append_list = cat_list;
00473 
00474                 return;
00475 
00476                 /* REQUIRE can either start a policy statement or a
00477                    comma-separated list of names of required options. */
00478               case REQUIRE:
00479                 skip_token(&val, (unsigned *)0, cfile);
00480                 token = peek_token (&val, (unsigned *)0, cfile);
00481                 if (token == AUTHENTICATION) {
00482                         policy = P_REQUIRE;
00483                         goto do_policy;
00484                 }
00485                 parse_option_list (cfile, &config -> required_options);
00486                 return;
00487 
00488               case IGNORE:
00489                 skip_token(&val, (unsigned *)0, cfile);
00490                 policy = P_IGNORE;
00491                 goto do_policy;
00492 
00493               case ACCEPT:
00494                 skip_token(&val, (unsigned *)0, cfile);
00495                 policy = P_ACCEPT;
00496                 goto do_policy;
00497 
00498               case PREFER:
00499                 skip_token(&val, (unsigned *)0, cfile);
00500                 policy = P_PREFER;
00501                 goto do_policy;
00502 
00503               case DONT:
00504                 skip_token(&val, (unsigned *)0, cfile);
00505                 policy = P_DONT;
00506                 goto do_policy;
00507 
00508               do_policy:
00509                 token = next_token (&val, (unsigned *)0, cfile);
00510                 if (token == AUTHENTICATION) {
00511                         if (policy != P_PREFER &&
00512                             policy != P_REQUIRE &&
00513                             policy != P_DONT) {
00514                                 parse_warn (cfile,
00515                                             "invalid authentication policy.");
00516                                 skip_to_semi (cfile);
00517                                 return;
00518                         }
00519                         config -> auth_policy = policy;
00520                 } else if (token != TOKEN_BOOTP) {
00521                         if (policy != P_PREFER &&
00522                             policy != P_IGNORE &&
00523                             policy != P_ACCEPT) {
00524                                 parse_warn (cfile, "invalid bootp policy.");
00525                                 skip_to_semi (cfile);
00526                                 return;
00527                         }
00528                         config -> bootp_policy = policy;
00529                 } else {
00530                         parse_warn (cfile, "expecting a policy type.");
00531                         skip_to_semi (cfile);
00532                         return;
00533                 } 
00534                 break;
00535 
00536               case OPTION:
00537                 skip_token(&val, (unsigned *)0, cfile);
00538                 token = peek_token (&val, (unsigned *)0, cfile);
00539                 if (token == SPACE) {
00540                         if (ip) {
00541                                 parse_warn (cfile,
00542                                             "option space definitions %s",
00543                                             " may not be scoped.");
00544                                 skip_to_semi (cfile);
00545                                 break;
00546                         }
00547                         parse_option_space_decl (cfile);
00548                         return;
00549                 }
00550 
00551                 known = 0;
00552                 status = parse_option_name(cfile, 1, &known, &option);
00553                 if (status != ISC_R_SUCCESS || option == NULL)
00554                         return;
00555 
00556                 token = next_token (&val, (unsigned *)0, cfile);
00557                 if (token != CODE) {
00558                         parse_warn (cfile, "expecting \"code\" keyword.");
00559                         skip_to_semi (cfile);
00560                         option_dereference(&option, MDL);
00561                         return;
00562                 }
00563                 if (ip) {
00564                         parse_warn (cfile,
00565                                     "option definitions may only appear in %s",
00566                                     "the outermost scope.");
00567                         skip_to_semi (cfile);
00568                         option_dereference(&option, MDL);
00569                         return;
00570                 }
00571 
00572                 /*
00573                  * If the option was known, remove it from the code and name
00574                  * hash tables before redefining it.
00575                  */
00576                 if (known) {
00577                         option_name_hash_delete(option->universe->name_hash,
00578                                                 option->name, 0, MDL);
00579                         option_code_hash_delete(option->universe->code_hash,
00580                                                 &option->code, 0, MDL);
00581                 }
00582 
00583                 parse_option_code_definition(cfile, option);
00584                 option_dereference(&option, MDL);
00585                 return;
00586 
00587               case MEDIA:
00588                 skip_token(&val, (unsigned *)0, cfile);
00589                 parse_string_list (cfile, &config -> media, 1);
00590                 return;
00591 
00592               case HARDWARE:
00593                 skip_token(&val, (unsigned *)0, cfile);
00594                 if (ip) {
00595                         parse_hardware_param (cfile, &ip -> hw_address);
00596                 } else {
00597                         parse_warn (cfile, "hardware address parameter %s",
00598                                     "not allowed here.");
00599                         skip_to_semi (cfile);
00600                 }
00601                 return;
00602 
00603               case ANYCAST_MAC:
00604                 skip_token(&val, NULL, cfile);
00605                 if (ip != NULL) {
00606                         parse_hardware_param(cfile, &ip->anycast_mac_addr);
00607                 } else {
00608                         parse_warn(cfile, "anycast mac address parameter "
00609                                    "not allowed here.");
00610                         skip_to_semi (cfile);
00611                 }
00612                 return;
00613 
00614               case REQUEST:
00615                 skip_token(&val, (unsigned *)0, cfile);
00616                 if (config -> requested_options == default_requested_options)
00617                         config -> requested_options = NULL;
00618                 parse_option_list (cfile, &config -> requested_options);
00619                 return;
00620 
00621               case TIMEOUT:
00622                 skip_token(&val, (unsigned *)0, cfile);
00623                 parse_lease_time (cfile, &config -> timeout);
00624                 return;
00625 
00626               case RETRY:
00627                 skip_token(&val, (unsigned *)0, cfile);
00628                 parse_lease_time (cfile, &config -> retry_interval);
00629                 return;
00630 
00631               case SELECT_TIMEOUT:
00632                 skip_token(&val, (unsigned *)0, cfile);
00633                 parse_lease_time (cfile, &config -> select_interval);
00634                 return;
00635 
00636               case OMAPI:
00637                 skip_token(&val, (unsigned *)0, cfile);
00638                 token = next_token (&val, (unsigned *)0, cfile);
00639                 if (token != PORT) {
00640                         parse_warn (cfile,
00641                                     "unexpected omapi subtype: %s", val);
00642                         skip_to_semi (cfile);
00643                         return;
00644                 }
00645                 token = next_token (&val, (unsigned *)0, cfile);
00646                 if (token != NUMBER) {
00647                         parse_warn (cfile, "invalid port number: `%s'", val);
00648                         skip_to_semi (cfile);
00649                         return;
00650                 }
00651                 tmp = atoi (val);
00652                 if (tmp < 0 || tmp > 65535)
00653                         parse_warn (cfile, "invalid omapi port %d.", tmp);
00654                 else if (config != &top_level_config)
00655                         parse_warn (cfile,
00656                                     "omapi port only works at top level.");
00657                 else
00658                         config -> omapi_port = tmp;
00659                 parse_semi (cfile);
00660                 return;
00661                 
00662               case DO_FORWARD_UPDATE:
00663                 skip_token(&val, (unsigned *)0, cfile);
00664                 token = next_token (&val, (unsigned *)0, cfile);
00665                 if (!strcasecmp (val, "on") ||
00666                     !strcasecmp (val, "true"))
00667                         config -> do_forward_update = 1;
00668                 else if (!strcasecmp (val, "off") ||
00669                          !strcasecmp (val, "false"))
00670                         config -> do_forward_update = 0;
00671                 else {
00672                         parse_warn (cfile, "expecting boolean value.");
00673                         skip_to_semi (cfile);
00674                         return;
00675                 }
00676                 parse_semi (cfile);
00677                 return;
00678 
00679               case REBOOT:
00680                 skip_token(&val, (unsigned *)0, cfile);
00681                 parse_lease_time (cfile, &config -> reboot_timeout);
00682                 return;
00683 
00684               case BACKOFF_CUTOFF:
00685                 skip_token(&val, (unsigned *)0, cfile);
00686                 parse_lease_time (cfile, &config -> backoff_cutoff);
00687                 return;
00688 
00689               case INITIAL_INTERVAL:
00690                 skip_token(&val, (unsigned *)0, cfile);
00691                 parse_lease_time (cfile, &config -> initial_interval);
00692                 return;
00693 
00694               case INITIAL_DELAY:
00695                 skip_token(&val, (unsigned *)0, cfile);
00696                 parse_lease_time (cfile, &config -> initial_delay);
00697                 return;
00698 
00699               case SCRIPT:
00700                 skip_token(&val, (unsigned *)0, cfile);
00701                 parse_string (cfile, &config -> script_name, (unsigned *)0);
00702                 return;
00703 
00704               case VENDOR:
00705                 skip_token(&val, (unsigned *)0, cfile);
00706                 token = next_token (&val, (unsigned *)0, cfile);
00707                 if (token != OPTION) {
00708                         parse_warn (cfile, "expecting 'vendor option space'");
00709                         skip_to_semi (cfile);
00710                         return;
00711                 }
00712                 token = next_token (&val, (unsigned *)0, cfile);
00713                 if (token != SPACE) {
00714                         parse_warn (cfile, "expecting 'vendor option space'");
00715                         skip_to_semi (cfile);
00716                         return;
00717                 }
00718                 token = next_token (&val, (unsigned *)0, cfile);
00719                 if (!is_identifier (token)) {
00720                         parse_warn (cfile, "expecting an identifier.");
00721                         skip_to_semi (cfile);
00722                         return;
00723                 }
00724                 config -> vendor_space_name = dmalloc (strlen (val) + 1, MDL);
00725                 if (!config -> vendor_space_name)
00726                         log_fatal ("no memory for vendor option space name.");
00727                 strcpy (config -> vendor_space_name, val);
00728                 for (i = 0; i < universe_count; i++)
00729                         if (!strcmp (universes [i] -> name,
00730                                      config -> vendor_space_name))
00731                                 break;
00732                 if (i == universe_count) {
00733                         log_error ("vendor option space %s not found.",
00734                                    config -> vendor_space_name);
00735                 }
00736                 parse_semi (cfile);
00737                 return;
00738 
00739               case INTERFACE:
00740                 skip_token(&val, (unsigned *)0, cfile);
00741                 if (ip)
00742                         parse_warn (cfile, "nested interface declaration.");
00743                 parse_interface_declaration (cfile, config, (char *)0);
00744                 return;
00745 
00746               case PSEUDO:
00747                 skip_token(&val, (unsigned *)0, cfile);
00748                 token = next_token (&val, (unsigned *)0, cfile);
00749                 name = dmalloc (strlen (val) + 1, MDL);
00750                 if (!name)
00751                         log_fatal ("no memory for pseudo interface name");
00752                 strcpy (name, val);
00753                 parse_interface_declaration (cfile, config, name);
00754                 return;
00755                 
00756               case LEASE:
00757                 skip_token(&val, (unsigned *)0, cfile);
00758                 parse_client_lease_statement (cfile, 1);
00759                 return;
00760 
00761               case ALIAS:
00762                 skip_token(&val, (unsigned *)0, cfile);
00763                 parse_client_lease_statement (cfile, 2);
00764                 return;
00765 
00766               case REJECT:
00767                 skip_token(&val, (unsigned *)0, cfile);
00768                 parse_reject_statement (cfile, config);
00769                 return;
00770 
00771               case BOOTP_BROADCAST_ALWAYS:
00772                 token = next_token(&val, (unsigned*)0, cfile);
00773                 config -> bootp_broadcast_always = 1;
00774                 parse_semi (cfile);
00775                 return;
00776 
00777               default:
00778                 lose = 0;
00779                 stmt = (struct executable_statement *)0;
00780                 if (!parse_executable_statement (&stmt,
00781                                                  cfile, &lose, context_any)) {
00782                         if (!lose) {
00783                                 parse_warn (cfile, "expecting a statement.");
00784                                 skip_to_semi (cfile);
00785                         }
00786                 } else {
00787                         struct executable_statement **eptr, *sptr;
00788                         if (stmt &&
00789                             (stmt -> op == send_option_statement ||
00790                              (stmt -> op == on_statement &&
00791                               (stmt -> data.on.evtypes & ON_TRANSMISSION)))) {
00792                             eptr = &config -> on_transmission -> statements;
00793                             if (stmt -> op == on_statement) {
00794                                     sptr = (struct executable_statement *)0;
00795                                     executable_statement_reference
00796                                             (&sptr,
00797                                              stmt -> data.on.statements, MDL);
00798                                     executable_statement_dereference (&stmt,
00799                                                                       MDL);
00800                                     executable_statement_reference (&stmt,
00801                                                                     sptr,
00802                                                                     MDL);
00803                                     executable_statement_dereference (&sptr,
00804                                                                       MDL);
00805                             }
00806                         } else
00807                             eptr = &config -> on_receipt -> statements;
00808 
00809                         if (stmt) {
00810                                 for (; *eptr; eptr = &(*eptr) -> next)
00811                                         ;
00812                                 executable_statement_reference (eptr,
00813                                                                 stmt, MDL);
00814                         }
00815                         return;
00816                 }
00817                 break;
00818         }
00819         parse_semi (cfile);
00820 }
00821 
00822 /* option-list :== option_name |
00823                    option_list COMMA option_name */
00824 
00825 int
00826 parse_option_list(struct parse *cfile, struct option ***list)
00827 {
00828         int ix;
00829         int token;
00830         const char *val;
00831         pair p = (pair)0, q = (pair)0, r;
00832         struct option *option = NULL;
00833         isc_result_t status;
00834 
00835         ix = 0;
00836         do {
00837                 token = peek_token (&val, (unsigned *)0, cfile);
00838                 if (token == SEMI) {
00839                         token = next_token (&val, (unsigned *)0, cfile);
00840                         break;
00841                 }
00842                 if (!is_identifier (token)) {
00843                         parse_warn (cfile, "%s: expected option name.", val);
00844                         skip_token(&val, (unsigned *)0, cfile);
00845                         skip_to_semi (cfile);
00846                         return 0;
00847                 }
00848                 status = parse_option_name(cfile, 0, NULL, &option);
00849                 if (status != ISC_R_SUCCESS || option == NULL) {
00850                         parse_warn (cfile, "%s: expected option name.", val);
00851                         return 0;
00852                 }
00853                 r = new_pair (MDL);
00854                 if (!r)
00855                         log_fatal ("can't allocate pair for option code.");
00856                 /* XXX: we should probably carry a reference across this */
00857                 r->car = (caddr_t)option;
00858                 option_dereference(&option, MDL);
00859                 r -> cdr = (pair)0;
00860                 if (p)
00861                         q -> cdr = r;
00862                 else
00863                         p = r;
00864                 q = r;
00865                 ++ix;
00866                 token = next_token (&val, (unsigned *)0, cfile);
00867         } while (token == COMMA);
00868         if (token != SEMI) {
00869                 parse_warn (cfile, "expecting semicolon.");
00870                 skip_to_semi (cfile);
00871                 return 0;
00872         }
00873         /* XXX we can't free the list here, because we may have copied
00874            XXX it from an outer config state. */
00875         *list = NULL;
00876         if (ix) {
00877                 *list = dmalloc ((ix + 1) * sizeof(struct option *), MDL);
00878                 if (!*list)
00879                         log_error ("no memory for option list.");
00880                 else {
00881                         ix = 0;
00882                         for (q = p; q; q = q -> cdr)
00883                                 option_reference(&(*list)[ix++],
00884                                                  (struct option *)q->car, MDL);
00885                         (*list)[ix] = NULL;
00886                 }
00887                 while (p) {
00888                         q = p -> cdr;
00889                         free_pair (p, MDL);
00890                         p = q;
00891                 }
00892         }
00893 
00894         return ix;
00895 }
00896 
00897 /* interface-declaration :==
00898         INTERFACE string LBRACE client-declarations RBRACE */
00899 
00900 void parse_interface_declaration (cfile, outer_config, name)
00901         struct parse *cfile;
00902         struct client_config *outer_config;
00903         char *name;
00904 {
00905         int token;
00906         const char *val;
00907         struct client_state *client, **cp;
00908         struct interface_info *ip = (struct interface_info *)0;
00909 
00910         token = next_token (&val, (unsigned *)0, cfile);
00911         if (token != STRING) {
00912                 parse_warn (cfile, "expecting interface name (in quotes).");
00913                 skip_to_semi (cfile);
00914                 return;
00915         }
00916 
00917         if (!interface_or_dummy (&ip, val))
00918                 log_fatal ("Can't allocate interface %s.", val);
00919 
00920         /* If we were given a name, this is a pseudo-interface. */
00921         if (name) {
00922                 make_client_state (&client);
00923                 client -> name = name;
00924                 client -> interface = ip;
00925                 for (cp = &ip -> client; *cp; cp = &((*cp) -> next))
00926                         ;
00927                 *cp = client;
00928         } else {
00929                 if (!ip -> client) {
00930                         make_client_state (&ip -> client);
00931                         ip -> client -> interface = ip;
00932                 }
00933                 client = ip -> client;
00934         }
00935 
00936         if (!client -> config)
00937                 make_client_config (client, outer_config);
00938 
00939         ip -> flags &= ~INTERFACE_AUTOMATIC;
00940         interfaces_requested = 1;
00941 
00942         token = next_token (&val, (unsigned *)0, cfile);
00943         if (token != LBRACE) {
00944                 parse_warn (cfile, "expecting left brace.");
00945                 skip_to_semi (cfile);
00946                 return;
00947         }
00948 
00949         do {
00950                 token = peek_token (&val, (unsigned *)0, cfile);
00951                 if (token == END_OF_FILE) {
00952                         parse_warn (cfile,
00953                                     "unterminated interface declaration.");
00954                         return;
00955                 }
00956                 if (token == RBRACE)
00957                         break;
00958                 parse_client_statement (cfile, ip, client -> config);
00959         } while (1);
00960         skip_token(&val, (unsigned *)0, cfile);
00961 }
00962 
00963 int interface_or_dummy (struct interface_info **pi, const char *name)
00964 {
00965         struct interface_info *i;
00966         struct interface_info *ip = (struct interface_info *)0;
00967         isc_result_t status;
00968 
00969         /* Find the interface (if any) that matches the name. */
00970         for (i = interfaces; i; i = i -> next) {
00971                 if (!strcmp (i -> name, name)) {
00972                         interface_reference (&ip, i, MDL);
00973                         break;
00974                 }
00975         }
00976 
00977         /* If it's not a real interface, see if it's on the dummy list. */
00978         if (!ip) {
00979                 for (ip = dummy_interfaces; ip; ip = ip -> next) {
00980                         if (!strcmp (ip -> name, name)) {
00981                                 interface_reference (&ip, i, MDL);
00982                                 break;
00983                         }
00984                 }
00985         }
00986 
00987         /* If we didn't find an interface, make a dummy interface as
00988            a placeholder. */
00989         if (!ip) {
00990                 if ((status = interface_allocate (&ip, MDL)) != ISC_R_SUCCESS)
00991                         log_fatal ("Can't record interface %s: %s",
00992                                    name, isc_result_totext (status));
00993 
00994                 if (strlen(name) >= sizeof(ip->name)) {
00995                         interface_dereference(&ip, MDL);
00996                         return 0;
00997                 }
00998                 strcpy(ip->name, name);
00999 
01000                 if (dummy_interfaces) {
01001                         interface_reference (&ip -> next,
01002                                              dummy_interfaces, MDL);
01003                         interface_dereference (&dummy_interfaces, MDL);
01004                 }
01005                 interface_reference (&dummy_interfaces, ip, MDL);
01006         }
01007         if (pi)
01008                 status = interface_reference (pi, ip, MDL);
01009         else
01010                 status = ISC_R_FAILURE;
01011         interface_dereference (&ip, MDL);
01012         if (status != ISC_R_SUCCESS)
01013                 return 0;
01014         return 1;
01015 }
01016 
01017 void make_client_state (state)
01018         struct client_state **state;
01019 {
01020         *state = ((struct client_state *)dmalloc (sizeof **state, MDL));
01021         if (!*state)
01022                 log_fatal ("no memory for client state\n");
01023         memset (*state, 0, sizeof **state);
01024 }
01025 
01026 void make_client_config (client, config)
01027         struct client_state *client;
01028         struct client_config *config;
01029 {
01030         client -> config = (((struct client_config *)
01031                              dmalloc (sizeof (struct client_config), MDL)));
01032         if (!client -> config)
01033                 log_fatal ("no memory for client config\n");
01034         memcpy (client -> config, config, sizeof *config);
01035         if (!clone_group (&client -> config -> on_receipt,
01036                           config -> on_receipt, MDL) ||
01037             !clone_group (&client -> config -> on_transmission,
01038                           config -> on_transmission, MDL))
01039                 log_fatal ("no memory for client state groups.");
01040 }
01041 
01042 /* client-lease-statement :==
01043         LBRACE client-lease-declarations RBRACE
01044 
01045         client-lease-declarations :==
01046                 <nil> |
01047                 client-lease-declaration |
01048                 client-lease-declarations client-lease-declaration */
01049 
01050 
01051 void parse_client_lease_statement (cfile, is_static)
01052         struct parse *cfile;
01053         int is_static;
01054 {
01055         struct client_lease *lease, *lp, *pl, *next;
01056         struct interface_info *ip = (struct interface_info *)0;
01057         int token;
01058         const char *val;
01059         struct client_state *client = (struct client_state *)0;
01060 
01061         token = next_token (&val, (unsigned *)0, cfile);
01062         if (token != LBRACE) {
01063                 parse_warn (cfile, "expecting left brace.");
01064                 skip_to_semi (cfile);
01065                 return;
01066         }
01067 
01068         lease = ((struct client_lease *)
01069                  dmalloc (sizeof (struct client_lease), MDL));
01070         if (!lease)
01071                 log_fatal ("no memory for lease.\n");
01072         memset (lease, 0, sizeof *lease);
01073         lease -> is_static = is_static;
01074         if (!option_state_allocate (&lease -> options, MDL))
01075                 log_fatal ("no memory for lease options.\n");
01076 
01077         do {
01078                 token = peek_token (&val, (unsigned *)0, cfile);
01079                 if (token == END_OF_FILE) {
01080                         parse_warn (cfile, "unterminated lease declaration.");
01081                         return;
01082                 }
01083                 if (token == RBRACE)
01084                         break;
01085                 parse_client_lease_declaration (cfile, lease, &ip, &client);
01086         } while (1);
01087         skip_token(&val, (unsigned *)0, cfile);
01088 
01089         /* If the lease declaration didn't include an interface
01090            declaration that we recognized, it's of no use to us. */
01091         if (!ip) {
01092                 destroy_client_lease (lease);
01093                 return;
01094         }
01095 
01096         /* Make sure there's a client state structure... */
01097         if (!ip -> client) {
01098                 make_client_state (&ip -> client);
01099                 ip -> client -> interface = ip;
01100         }
01101         if (!client)
01102                 client = ip -> client;
01103 
01104         /* If this is an alias lease, it doesn't need to be sorted in. */
01105         if (is_static == 2) {
01106                 ip -> client -> alias = lease;
01107                 return;
01108         }
01109 
01110         /* The new lease may supersede a lease that's not the
01111            active lease but is still on the lease list, so scan the
01112            lease list looking for a lease with the same address, and
01113            if we find it, toss it. */
01114         pl = (struct client_lease *)0;
01115         for (lp = client -> leases; lp; lp = next) {
01116                 next = lp -> next;
01117                 if (lp -> address.len == lease -> address.len &&
01118                     !memcmp (lp -> address.iabuf, lease -> address.iabuf,
01119                              lease -> address.len)) {
01120                         if (pl)
01121                                 pl -> next = next;
01122                         else
01123                                 client -> leases = next;
01124                         destroy_client_lease (lp);
01125                         break;
01126                 } else
01127                         pl = lp;
01128         }
01129 
01130         /* If this is a preloaded lease, just put it on the list of recorded
01131            leases - don't make it the active lease. */
01132         if (is_static) {
01133                 lease -> next = client -> leases;
01134                 client -> leases = lease;
01135                 return;
01136         }
01137                 
01138         /* The last lease in the lease file on a particular interface is
01139            the active lease for that interface.    Of course, we don't know
01140            what the last lease in the file is until we've parsed the whole
01141            file, so at this point, we assume that the lease we just parsed
01142            is the active lease for its interface.   If there's already
01143            an active lease for the interface, and this lease is for the same
01144            ip address, then we just toss the old active lease and replace
01145            it with this one.   If this lease is for a different address,
01146            then if the old active lease has expired, we dump it; if not,
01147            we put it on the list of leases for this interface which are
01148            still valid but no longer active. */
01149         if (client -> active) {
01150                 if (client -> active -> expiry < cur_time)
01151                         destroy_client_lease (client -> active);
01152                 else if (client -> active -> address.len ==
01153                          lease -> address.len &&
01154                          !memcmp (client -> active -> address.iabuf,
01155                                   lease -> address.iabuf,
01156                                   lease -> address.len))
01157                         destroy_client_lease (client -> active);
01158                 else {
01159                         client -> active -> next = client -> leases;
01160                         client -> leases = client -> active;
01161                 }
01162         }
01163         client -> active = lease;
01164 
01165         /* phew. */
01166 }
01167 
01168 /* client-lease-declaration :==
01169         BOOTP |
01170         INTERFACE string |
01171         FIXED_ADDR ip_address |
01172         FILENAME string |
01173         SERVER_NAME string |
01174         OPTION option-decl |
01175         RENEW time-decl |
01176         REBIND time-decl |
01177         EXPIRE time-decl |
01178         KEY id */
01179 
01180 void parse_client_lease_declaration (cfile, lease, ipp, clientp)
01181         struct parse *cfile;
01182         struct client_lease *lease;
01183         struct interface_info **ipp;
01184         struct client_state **clientp;
01185 {
01186         int token;
01187         const char *val;
01188         struct interface_info *ip;
01189         struct option_cache *oc;
01190         struct client_state *client = (struct client_state *)0;
01191 
01192         switch (next_token (&val, (unsigned *)0, cfile)) {
01193               case KEY:
01194                 token = next_token (&val, (unsigned *)0, cfile);
01195                 if (token != STRING && !is_identifier (token)) {
01196                         parse_warn (cfile, "expecting key name.");
01197                         skip_to_semi (cfile);
01198                         break;
01199                 }
01200                 if (omapi_auth_key_lookup_name (&lease -> key, val) !=
01201                     ISC_R_SUCCESS)
01202                         parse_warn (cfile, "unknown key %s", val);
01203                 parse_semi (cfile);
01204                 break;
01205               case TOKEN_BOOTP:
01206                 lease -> is_bootp = 1;
01207                 break;
01208 
01209               case INTERFACE:
01210                 token = next_token (&val, (unsigned *)0, cfile);
01211                 if (token != STRING) {
01212                         parse_warn (cfile,
01213                                     "expecting interface name (in quotes).");
01214                         skip_to_semi (cfile);
01215                         break;
01216                 }
01217                 if (!interface_or_dummy (ipp, val))
01218                         log_fatal ("Can't allocate interface %s.", val);
01219                 break;
01220 
01221               case NAME:
01222                 token = next_token (&val, (unsigned *)0, cfile);
01223                 ip = *ipp;
01224                 if (!ip) {
01225                         parse_warn (cfile, "state name precedes interface.");
01226                         break;
01227                 }
01228                 for (client = ip -> client; client; client = client -> next)
01229                         if (client -> name && !strcmp (client -> name, val))
01230                                 break;
01231                 if (!client)
01232                         parse_warn (cfile,
01233                                     "lease specified for unknown pseudo.");
01234                 *clientp = client;
01235                 break;
01236 
01237               case FIXED_ADDR:
01238                 if (!parse_ip_addr (cfile, &lease -> address))
01239                         return;
01240                 break;
01241 
01242               case MEDIUM:
01243                 parse_string_list (cfile, &lease -> medium, 0);
01244                 return;
01245 
01246               case FILENAME:
01247                 parse_string (cfile, &lease -> filename, (unsigned *)0);
01248                 return;
01249 
01250               case SERVER_NAME:
01251                 parse_string (cfile, &lease -> server_name, (unsigned *)0);
01252                 return;
01253 
01254               case RENEW:
01255                 lease -> renewal = parse_date (cfile);
01256                 return;
01257 
01258               case REBIND:
01259                 lease -> rebind = parse_date (cfile);
01260                 return;
01261 
01262               case EXPIRE:
01263                 lease -> expiry = parse_date (cfile);
01264                 return;
01265 
01266               case OPTION:
01267                 oc = (struct option_cache *)0;
01268                 if (parse_option_decl (&oc, cfile)) {
01269                         save_option(oc->option->universe, lease->options, oc);
01270                         option_cache_dereference (&oc, MDL);
01271                 }
01272                 return;
01273 
01274               default:
01275                 parse_warn (cfile, "expecting lease declaration.");
01276                 skip_to_semi (cfile);
01277                 break;
01278         }
01279         token = next_token (&val, (unsigned *)0, cfile);
01280         if (token != SEMI) {
01281                 parse_warn (cfile, "expecting semicolon.");
01282                 skip_to_semi (cfile);
01283         }
01284 }
01285 
01286 /* Parse a default-duid ""; statement.
01287  */
01288 static void
01289 parse_client_default_duid(struct parse *cfile)
01290 {
01291         struct data_string new_duid;
01292         const char *val = NULL;
01293         unsigned len;
01294         int token;
01295 
01296         memset(&new_duid, 0, sizeof(new_duid));
01297 
01298         token = next_token(&val, &len, cfile);
01299         if (token != STRING) {
01300                 parse_warn(cfile, "Expected DUID string.");
01301                 skip_to_semi(cfile);
01302                 return;
01303         }
01304 
01305         if (len <= 2) {
01306                 parse_warn(cfile, "Invalid DUID contents.");
01307                 skip_to_semi(cfile);
01308                 return;
01309         }
01310 
01311         if (!buffer_allocate(&new_duid.buffer, len, MDL)) {
01312                 parse_warn(cfile, "Out of memory parsing default DUID.");
01313                 skip_to_semi(cfile);
01314                 return;
01315         }
01316         new_duid.data = new_duid.buffer->data;
01317         new_duid.len = len;
01318 
01319         memcpy(new_duid.buffer->data, val, len);
01320 
01321         /* Rotate the last entry into place. */
01322         if (default_duid.buffer != NULL)
01323                 data_string_forget(&default_duid, MDL);
01324         data_string_copy(&default_duid, &new_duid, MDL);
01325         data_string_forget(&new_duid, MDL);
01326 
01327         parse_semi(cfile);
01328 }
01329 
01330 /* Parse a lease6 {} construct.  The v6 client is a little different
01331  * than the v4 client today, in that it only retains one lease, the
01332  * active lease, and discards any less recent information.  It may
01333  * be useful in the future to cache additional information, but it
01334  * is not worth the effort for the moment.
01335  */
01336 static void
01337 parse_client6_lease_statement(struct parse *cfile)
01338 {
01339 #if !defined(DHCPv6)
01340         parse_warn(cfile, "No DHCPv6 support.");
01341         skip_to_semi(cfile);
01342 #else /* defined(DHCPv6) */
01343         struct option_cache *oc = NULL;
01344         struct dhc6_lease *lease;
01345         struct dhc6_ia **ia;
01346         struct client_state *client = NULL;
01347         struct interface_info *iface = NULL;
01348         struct data_string ds;
01349         const char *val;
01350         unsigned len;
01351         int token, has_ia, no_semi, has_name;
01352 
01353         token = next_token(NULL, NULL, cfile);
01354         if (token != LBRACE) {
01355                 parse_warn(cfile, "Expecting open curly brace.");
01356                 skip_to_semi(cfile);
01357                 return;
01358         }
01359 
01360         lease = dmalloc(sizeof(*lease), MDL);
01361         if (lease == NULL) {
01362                 parse_warn(cfile, "Unable to allocate lease state.");
01363                 skip_to_rbrace(cfile, 1);
01364                 return;
01365         }
01366 
01367         option_state_allocate(&lease->options, MDL);
01368         if (lease->options == NULL) {
01369                 parse_warn(cfile, "Unable to allocate option cache.");
01370                 skip_to_rbrace(cfile, 1);
01371                 dfree(lease, MDL);
01372                 return;
01373         }
01374 
01375         has_ia = 0;
01376         has_name = 0;
01377         ia = &lease->bindings;
01378         token = next_token(&val, NULL, cfile);
01379         while (token != RBRACE) {
01380                 no_semi = 0;
01381 
01382                 switch(token) {
01383                       case IA_NA:
01384                         *ia = parse_client6_ia_na_statement(cfile);
01385                         if (*ia != NULL) {
01386                                 ia = &(*ia)->next;
01387                                 has_ia = 1;
01388                         }
01389 
01390                         no_semi = 1;
01391 
01392                         break;
01393 
01394                       case IA_TA:
01395                         *ia = parse_client6_ia_ta_statement(cfile);
01396                         if (*ia != NULL) {
01397                                 ia = &(*ia)->next;
01398                                 has_ia = 1;
01399                         }
01400 
01401                         no_semi = 1;
01402 
01403                         break;
01404 
01405                       case IA_PD:
01406                         *ia = parse_client6_ia_pd_statement(cfile);
01407                         if (*ia != NULL) {
01408                                 ia = &(*ia)->next;
01409                                 has_ia = 1;
01410                         }
01411 
01412                         no_semi = 1;
01413 
01414                         break;
01415 
01416                       case INTERFACE:
01417                         if (iface != NULL) {
01418                                 parse_warn(cfile, "Multiple interface names?");
01419                                 skip_to_semi(cfile);
01420                                 no_semi = 1;
01421                                 break;
01422                         }
01423 
01424                         token = next_token(&val, &len, cfile);
01425                         if (token != STRING) {
01426                               strerror:
01427                                 parse_warn(cfile, "Expecting a string.");
01428                                 skip_to_semi(cfile);
01429                                 no_semi = 1;
01430                                 break;
01431                         }
01432 
01433                         for (iface = interfaces ; iface != NULL ;
01434                              iface = iface->next) {
01435                                 if (strcmp(iface->name, val) == 0)
01436                                         break;
01437                         }
01438 
01439                         if (iface == NULL) {
01440                                 parse_warn(cfile, "Unknown interface.");
01441                                 break;
01442                         }
01443 
01444                         break;
01445 
01446                       case NAME:
01447                         has_name = 1;
01448 
01449                         if (client != NULL) {
01450                                 parse_warn(cfile, "Multiple state names?");
01451                                 skip_to_semi(cfile);
01452                                 no_semi = 1;
01453                                 break;
01454                         }
01455 
01456                         if (iface == NULL) {
01457                                 parse_warn(cfile, "Client name without "
01458                                                   "interface.");
01459                                 skip_to_semi(cfile);
01460                                 no_semi = 1;
01461                                 break;
01462                         }
01463 
01464                         token = next_token(&val, &len, cfile);
01465                         if (token != STRING)
01466                                 goto strerror;
01467 
01468                         for (client = iface->client ; client != NULL ;
01469                              client = client->next) {
01470                                 if ((client->name != NULL) &&
01471                                     (strcmp(client->name, val) == 0))
01472                                         break;
01473                         }
01474 
01475                         if (client == NULL) {
01476                                 parse_warn(cfile, "Unknown client state %s.",
01477                                            val);
01478                                 break;
01479                         }
01480 
01481                         break;
01482 
01483                       case OPTION:
01484                         if (parse_option_decl(&oc, cfile)) {
01485                                 save_option(oc->option->universe,
01486                                             lease->options, oc);
01487                                 option_cache_dereference(&oc, MDL);
01488                         }
01489                         no_semi = 1;
01490                         break;
01491 
01492                       case TOKEN_RELEASED:
01493                       case TOKEN_ABANDONED:
01494                         lease->released = ISC_TRUE;
01495                         break;
01496 
01497                       default:
01498                         parse_warn(cfile, "Unexpected token, %s.", val);
01499                         no_semi = 1;
01500                         skip_to_semi(cfile);
01501                         break;
01502                 }
01503 
01504                 if (!no_semi)
01505                         parse_semi(cfile);
01506 
01507                 token = next_token(&val, NULL, cfile);
01508 
01509                 if (token == END_OF_FILE) {
01510                         parse_warn(cfile, "Unexpected end of file.");
01511                         break;
01512                 }
01513         }
01514 
01515         if (!has_ia) {
01516                 log_debug("Lease with no IA's discarded from lease db.");
01517                 dhc6_lease_destroy(&lease, MDL);
01518                 return;
01519         }
01520 
01521         if (iface == NULL)
01522                 parse_warn(cfile, "Lease has no interface designation.");
01523         else if (!has_name && (client == NULL)) {
01524                 for (client = iface->client ; client != NULL ;
01525                      client = client->next) {
01526                         if (client->name == NULL)
01527                                 break;
01528                 }
01529         }
01530 
01531         if (client == NULL) {
01532                 parse_warn(cfile, "No matching client state.");
01533                 dhc6_lease_destroy(&lease, MDL);
01534                 return;
01535         }
01536 
01537         /* Fetch Preference option from option cache. */
01538         memset(&ds, 0, sizeof(ds));
01539         oc = lookup_option(&dhcpv6_universe, lease->options, D6O_PREFERENCE);
01540         if ((oc != NULL) &&
01541             evaluate_option_cache(&ds, NULL, NULL, NULL, lease->options,
01542                                   NULL, &global_scope, oc, MDL)) {
01543                 if (ds.len != 1) {
01544                         log_error("Invalid length of DHCPv6 Preference option "
01545                                   "(%d != 1)", ds.len);
01546                         data_string_forget(&ds, MDL);
01547                         dhc6_lease_destroy(&lease, MDL);
01548                         return;
01549                 } else
01550                         lease->pref = ds.data[0];
01551 
01552                 data_string_forget(&ds, MDL);
01553         }
01554 
01555         /* Fetch server-id option from option cache. */
01556         oc = lookup_option(&dhcpv6_universe, lease->options, D6O_SERVERID);
01557         if ((oc == NULL) ||
01558             !evaluate_option_cache(&lease->server_id, NULL, NULL, NULL,
01559                                    lease->options, NULL, &global_scope, oc,
01560                                    MDL) ||
01561             (lease->server_id.len == 0)) {
01562                 /* This should be impossible... */
01563                 log_error("Invalid SERVERID option cache.");
01564                 dhc6_lease_destroy(&lease, MDL);
01565                 return;
01566         }
01567 
01568         if (client->active_lease != NULL)
01569                 dhc6_lease_destroy(&client->active_lease, MDL);
01570 
01571         client->active_lease = lease;
01572 #endif /* defined(DHCPv6) */
01573 }
01574 
01575 /* Parse an ia_na object from the client lease.
01576  */
01577 #ifdef DHCPv6
01578 static struct dhc6_ia *
01579 parse_client6_ia_na_statement(struct parse *cfile)
01580 {
01581         struct option_cache *oc = NULL;
01582         struct dhc6_ia *ia;
01583         struct dhc6_addr **addr;
01584         const char *val;
01585         int token, no_semi, len;
01586         u_int8_t buf[5];
01587 
01588         ia = dmalloc(sizeof(*ia), MDL);
01589         if (ia == NULL) {
01590                 parse_warn(cfile, "Out of memory allocating IA_NA state.");
01591                 skip_to_semi(cfile);
01592                 return NULL;
01593         }
01594         ia->ia_type = D6O_IA_NA;
01595 
01596         /* Get IAID. */
01597         len = parse_X(cfile, buf, 5);
01598         if (len == 4) {
01599                 memcpy(ia->iaid, buf, 4);
01600         } else {
01601                 parse_warn(cfile, "Expecting IAID of length 4, got %d.", len);
01602                 skip_to_semi(cfile);
01603                 dfree(ia, MDL);
01604                 return NULL;
01605         }
01606 
01607         token = next_token(NULL, NULL, cfile);
01608         if (token != LBRACE) {
01609                 parse_warn(cfile, "Expecting open curly brace.");
01610                 skip_to_semi(cfile);
01611                 dfree(ia, MDL);
01612                 return NULL;
01613         }
01614 
01615         option_state_allocate(&ia->options, MDL);
01616         if (ia->options == NULL) {
01617                 parse_warn(cfile, "Unable to allocate option state.");
01618                 skip_to_rbrace(cfile, 1);
01619                 dfree(ia, MDL);
01620                 return NULL;
01621         }
01622 
01623         addr = &ia->addrs;
01624         token = next_token(&val, NULL, cfile);
01625         while (token != RBRACE) {
01626                 no_semi = 0;
01627 
01628                 switch (token) {
01629                       case STARTS:
01630                         token = next_token(&val, NULL, cfile);
01631                         if (token == NUMBER) {
01632                                 ia->starts = atoi(val);
01633                         } else {
01634                                 parse_warn(cfile, "Expecting a number.");
01635                                 skip_to_semi(cfile);
01636                                 no_semi = 1;
01637                         }
01638                         break;
01639 
01640                       case RENEW:
01641                         token = next_token(&val, NULL, cfile);
01642                         if (token == NUMBER) {
01643                                 ia->renew = atoi(val);
01644                         } else {
01645                                 parse_warn(cfile, "Expecting a number.");
01646                                 skip_to_semi(cfile);
01647                                 no_semi = 1;
01648                         }
01649                         break;
01650 
01651                       case REBIND:
01652                         token = next_token(&val, NULL, cfile);
01653                         if (token == NUMBER) {
01654                                 ia->rebind = atoi(val);
01655                         } else {
01656                                 parse_warn(cfile, "Expecting a number.");
01657                                 skip_to_semi(cfile);
01658                                 no_semi = 1;
01659                         }
01660                         break;
01661 
01662                       case IAADDR:
01663                         *addr = parse_client6_iaaddr_statement(cfile);
01664 
01665                         if (*addr != NULL)
01666                                 addr = &(*addr)->next;
01667 
01668                         no_semi = 1;
01669 
01670                         break;
01671 
01672                       case OPTION:
01673                         if (parse_option_decl(&oc, cfile)) {
01674                                 save_option(oc->option->universe,
01675                                             ia->options, oc);
01676                                 option_cache_dereference(&oc, MDL);
01677                         }
01678                         no_semi = 1;
01679                         break;
01680 
01681                       default:
01682                         parse_warn(cfile, "Unexpected token.");
01683                         no_semi = 1;
01684                         skip_to_semi(cfile);
01685                         break;
01686                 }
01687 
01688                 if (!no_semi)
01689                         parse_semi(cfile);
01690 
01691                 token = next_token(&val, NULL, cfile);
01692 
01693                 if (token == END_OF_FILE) {
01694                         parse_warn(cfile, "Unexpected end of file.");
01695                         break;
01696                 }
01697         }
01698 
01699         return ia;
01700 }
01701 #endif /* DHCPv6 */
01702 
01703 /* Parse an ia_ta object from the client lease.
01704  */
01705 #ifdef DHCPv6
01706 static struct dhc6_ia *
01707 parse_client6_ia_ta_statement(struct parse *cfile)
01708 {
01709         struct option_cache *oc = NULL;
01710         struct dhc6_ia *ia;
01711         struct dhc6_addr **addr;
01712         const char *val;
01713         int token, no_semi, len;
01714         u_int8_t buf[5];
01715 
01716         ia = dmalloc(sizeof(*ia), MDL);
01717         if (ia == NULL) {
01718                 parse_warn(cfile, "Out of memory allocating IA_TA state.");
01719                 skip_to_semi(cfile);
01720                 return NULL;
01721         }
01722         ia->ia_type = D6O_IA_TA;
01723 
01724         /* Get IAID. */
01725         len = parse_X(cfile, buf, 5);
01726         if (len == 4) {
01727                 memcpy(ia->iaid, buf, 4);
01728         } else {
01729                 parse_warn(cfile, "Expecting IAID of length 4, got %d.", len);
01730                 skip_to_semi(cfile);
01731                 dfree(ia, MDL);
01732                 return NULL;
01733         }
01734 
01735         token = next_token(NULL, NULL, cfile);
01736         if (token != LBRACE) {
01737                 parse_warn(cfile, "Expecting open curly brace.");
01738                 skip_to_semi(cfile);
01739                 dfree(ia, MDL);
01740                 return NULL;
01741         }
01742 
01743         option_state_allocate(&ia->options, MDL);
01744         if (ia->options == NULL) {
01745                 parse_warn(cfile, "Unable to allocate option state.");
01746                 skip_to_rbrace(cfile, 1);
01747                 dfree(ia, MDL);
01748                 return NULL;
01749         }
01750 
01751         addr = &ia->addrs;
01752         token = next_token(&val, NULL, cfile);
01753         while (token != RBRACE) {
01754                 no_semi = 0;
01755 
01756                 switch (token) {
01757                       case STARTS:
01758                         token = next_token(&val, NULL, cfile);
01759                         if (token == NUMBER) {
01760                                 ia->starts = atoi(val);
01761                         } else {
01762                                 parse_warn(cfile, "Expecting a number.");
01763                                 skip_to_semi(cfile);
01764                                 no_semi = 1;
01765                         }
01766                         break;
01767 
01768                         /* No RENEW or REBIND */
01769 
01770                       case IAADDR:
01771                         *addr = parse_client6_iaaddr_statement(cfile);
01772 
01773                         if (*addr != NULL)
01774                                 addr = &(*addr)->next;
01775 
01776                         no_semi = 1;
01777 
01778                         break;
01779 
01780                       case OPTION:
01781                         if (parse_option_decl(&oc, cfile)) {
01782                                 save_option(oc->option->universe,
01783                                             ia->options, oc);
01784                                 option_cache_dereference(&oc, MDL);
01785                         }
01786                         no_semi = 1;
01787                         break;
01788 
01789                       default:
01790                         parse_warn(cfile, "Unexpected token.");
01791                         no_semi = 1;
01792                         skip_to_semi(cfile);
01793                         break;
01794                 }
01795 
01796                 if (!no_semi)
01797                         parse_semi(cfile);
01798 
01799                 token = next_token(&val, NULL, cfile);
01800 
01801                 if (token == END_OF_FILE) {
01802                         parse_warn(cfile, "Unexpected end of file.");
01803                         break;
01804                 }
01805         }
01806 
01807         return ia;
01808 }
01809 #endif /* DHCPv6 */
01810 
01811 /* Parse an ia_pd object from the client lease.
01812  */
01813 #ifdef DHCPv6
01814 static struct dhc6_ia *
01815 parse_client6_ia_pd_statement(struct parse *cfile)
01816 {
01817         struct option_cache *oc = NULL;
01818         struct dhc6_ia *ia;
01819         struct dhc6_addr **pref;
01820         const char *val;
01821         int token, no_semi, len;
01822         u_int8_t buf[5];
01823 
01824         ia = dmalloc(sizeof(*ia), MDL);
01825         if (ia == NULL) {
01826                 parse_warn(cfile, "Out of memory allocating IA_PD state.");
01827                 skip_to_semi(cfile);
01828                 return NULL;
01829         }
01830         ia->ia_type = D6O_IA_PD;
01831 
01832         /* Get IAID. */
01833         len = parse_X(cfile, buf, 5);
01834         if (len == 4) {
01835                 memcpy(ia->iaid, buf, 4);
01836         } else {
01837                 parse_warn(cfile, "Expecting IAID of length 4, got %d.", len);
01838                 skip_to_semi(cfile);
01839                 dfree(ia, MDL);
01840                 return NULL;
01841         }
01842 
01843         token = next_token(NULL, NULL, cfile);
01844         if (token != LBRACE) {
01845                 parse_warn(cfile, "Expecting open curly brace.");
01846                 skip_to_semi(cfile);
01847                 dfree(ia, MDL);
01848                 return NULL;
01849         }
01850 
01851         option_state_allocate(&ia->options, MDL);
01852         if (ia->options == NULL) {
01853                 parse_warn(cfile, "Unable to allocate option state.");
01854                 skip_to_rbrace(cfile, 1);
01855                 dfree(ia, MDL);
01856                 return NULL;
01857         }
01858 
01859         pref = &ia->addrs;
01860         token = next_token(&val, NULL, cfile);
01861         while (token != RBRACE) {
01862                 no_semi = 0;
01863 
01864                 switch (token) {
01865                       case STARTS:
01866                         token = next_token(&val, NULL, cfile);
01867                         if (token == NUMBER) {
01868                                 ia->starts = atoi(val);
01869                         } else {
01870                                 parse_warn(cfile, "Expecting a number.");
01871                                 skip_to_semi(cfile);
01872                                 no_semi = 1;
01873                         }
01874                         break;
01875 
01876                       case RENEW:
01877                         token = next_token(&val, NULL, cfile);
01878                         if (token == NUMBER) {
01879                                 ia->renew = atoi(val);
01880                         } else {
01881                                 parse_warn(cfile, "Expecting a number.");
01882                                 skip_to_semi(cfile);
01883                                 no_semi = 1;
01884                         }
01885                         break;
01886 
01887                       case REBIND:
01888                         token = next_token(&val, NULL, cfile);
01889                         if (token == NUMBER) {
01890                                 ia->rebind = atoi(val);
01891                         } else {
01892                                 parse_warn(cfile, "Expecting a number.");
01893                                 skip_to_semi(cfile);
01894                                 no_semi = 1;
01895                         }
01896                         break;
01897 
01898                       case IAPREFIX:
01899                         *pref = parse_client6_iaprefix_statement(cfile);
01900 
01901                         if (*pref != NULL)
01902                                 pref = &(*pref)->next;
01903 
01904                         no_semi = 1;
01905 
01906                         break;
01907 
01908                       case OPTION:
01909                         if (parse_option_decl(&oc, cfile)) {
01910                                 save_option(oc->option->universe,
01911                                             ia->options, oc);
01912                                 option_cache_dereference(&oc, MDL);
01913                         }
01914                         no_semi = 1;
01915                         break;
01916 
01917                       default:
01918                         parse_warn(cfile, "Unexpected token.");
01919                         no_semi = 1;
01920                         skip_to_semi(cfile);
01921                         break;
01922                 }
01923 
01924                 if (!no_semi)
01925                         parse_semi(cfile);
01926 
01927                 token = next_token(&val, NULL, cfile);
01928 
01929                 if (token == END_OF_FILE) {
01930                         parse_warn(cfile, "Unexpected end of file.");
01931                         break;
01932                 }
01933         }
01934 
01935         return ia;
01936 }
01937 #endif /* DHCPv6 */
01938 
01939 /* Parse an iaaddr {} structure. */
01940 #ifdef DHCPv6
01941 static struct dhc6_addr *
01942 parse_client6_iaaddr_statement(struct parse *cfile)
01943 {
01944         struct option_cache *oc = NULL;
01945         struct dhc6_addr *addr;
01946         const char *val;
01947         int token, no_semi;
01948 
01949         addr = dmalloc(sizeof(*addr), MDL);
01950         if (addr == NULL) {
01951                 parse_warn(cfile, "Unable to allocate IAADDR state.");
01952                 skip_to_semi(cfile);
01953                 return NULL;
01954         }
01955 
01956         /* Get IP address. */
01957         if (!parse_ip6_addr(cfile, &addr->address)) {
01958                 skip_to_semi(cfile);
01959                 dfree(addr, MDL);
01960                 return NULL;
01961         }
01962 
01963         token = next_token(NULL, NULL, cfile);
01964         if (token != LBRACE) {
01965                 parse_warn(cfile, "Expecting open curly bracket.");
01966                 skip_to_semi(cfile);
01967                 dfree(addr, MDL);
01968                 return NULL;
01969         }
01970 
01971         option_state_allocate(&addr->options, MDL);
01972         if (addr->options == NULL) {
01973                 parse_warn(cfile, "Unable to allocate option state.");
01974                 skip_to_semi(cfile);
01975                 dfree(addr, MDL);
01976                 return NULL;
01977         }
01978 
01979         token = next_token(&val, NULL, cfile);
01980         while (token != RBRACE) {
01981                 no_semi = 0;
01982 
01983                 switch (token) {
01984                       case STARTS:
01985                         token = next_token(&val, NULL, cfile);
01986                         if (token == NUMBER) {
01987                                 addr->starts = atoi(val);
01988                         } else {
01989                                 parse_warn(cfile, "Expecting a number.");
01990                                 skip_to_semi(cfile);
01991                                 no_semi = 1;
01992                         }
01993                         break;
01994 
01995                       case PREFERRED_LIFE:
01996                         token = next_token(&val, NULL, cfile);
01997                         if (token == NUMBER) {
01998                                 addr->preferred_life = atoi(val);
01999                         } else {
02000                                 parse_warn(cfile, "Expecting a number.");
02001                                 skip_to_semi(cfile);
02002                                 no_semi = 1;
02003                         }
02004                         break;
02005 
02006                       case MAX_LIFE:
02007                         token = next_token(&val, NULL, cfile);
02008                         if (token == NUMBER) {
02009                                 addr->max_life = atoi(val);
02010                         } else {
02011                                 parse_warn(cfile, "Expecting a number.");
02012                                 skip_to_semi(cfile);
02013                                 no_semi = 1;
02014                         }
02015                         break;
02016 
02017                       case OPTION:
02018                         if (parse_option_decl(&oc, cfile)) {
02019                                 save_option(oc->option->universe,
02020                                             addr->options, oc);
02021                                 option_cache_dereference(&oc, MDL);
02022                         }
02023                         no_semi = 1;
02024                         break;
02025 
02026                       default:
02027                         parse_warn(cfile, "Unexpected token.");
02028                         skip_to_rbrace(cfile, 1);
02029                         no_semi = 1;
02030                         break;
02031                 }
02032 
02033                 if (!no_semi)
02034                         parse_semi(cfile);
02035 
02036                 token = next_token(&val, NULL, cfile);
02037                 if (token == END_OF_FILE) {
02038                         parse_warn(cfile, "Unexpected end of file.");
02039                         break;
02040                 }
02041         }
02042 
02043         return addr;
02044 }
02045 #endif /* DHCPv6 */
02046 
02047 /* Parse an iaprefix {} structure. */
02048 #ifdef DHCPv6
02049 static struct dhc6_addr *
02050 parse_client6_iaprefix_statement(struct parse *cfile)
02051 {
02052         struct option_cache *oc = NULL;
02053         struct dhc6_addr *pref;
02054         const char *val;
02055         int token, no_semi;
02056 
02057         pref = dmalloc(sizeof(*pref), MDL);
02058         if (pref == NULL) {
02059                 parse_warn(cfile, "Unable to allocate IAPREFIX state.");
02060                 skip_to_semi(cfile);
02061                 return NULL;
02062         }
02063 
02064         /* Get IP prefix. */
02065         if (!parse_ip6_prefix(cfile, &pref->address, &pref->plen)) {
02066                 skip_to_semi(cfile);
02067                 dfree(pref, MDL);
02068                 return NULL;
02069         }
02070 
02071         token = next_token(NULL, NULL, cfile);
02072         if (token != LBRACE) {
02073                 parse_warn(cfile, "Expecting open curly bracket.");
02074                 skip_to_semi(cfile);
02075                 dfree(pref, MDL);
02076                 return NULL;
02077         }
02078 
02079         option_state_allocate(&pref->options, MDL);
02080         if (pref->options == NULL) {
02081                 parse_warn(cfile, "Unable to allocate option state.");
02082                 skip_to_semi(cfile);
02083                 dfree(pref, MDL);
02084                 return NULL;
02085         }
02086 
02087         token = next_token(&val, NULL, cfile);
02088         while (token != RBRACE) {
02089                 no_semi = 0;
02090 
02091                 switch (token) {
02092                       case STARTS:
02093                         token = next_token(&val, NULL, cfile);
02094                         if (token == NUMBER) {
02095                                 pref->starts = atoi(val);
02096                         } else {
02097                                 parse_warn(cfile, "Expecting a number.");
02098                                 skip_to_semi(cfile);
02099                                 no_semi = 1;
02100                         }
02101                         break;
02102 
02103                       case PREFERRED_LIFE:
02104                         token = next_token(&val, NULL, cfile);
02105                         if (token == NUMBER) {
02106                                 pref->preferred_life = atoi(val);
02107                         } else {
02108                                 parse_warn(cfile, "Expecting a number.");
02109                                 skip_to_semi(cfile);
02110                                 no_semi = 1;
02111                         }
02112                         break;
02113 
02114                       case MAX_LIFE:
02115                         token = next_token(&val, NULL, cfile);
02116                         if (token == NUMBER) {
02117                                 pref->max_life = atoi(val);
02118                         } else {
02119                                 parse_warn(cfile, "Expecting a number.");
02120                                 skip_to_semi(cfile);
02121                                 no_semi = 1;
02122                         }
02123                         break;
02124 
02125                       case OPTION:
02126                         if (parse_option_decl(&oc, cfile)) {
02127                                 save_option(oc->option->universe,
02128                                             pref->options, oc);
02129                                 option_cache_dereference(&oc, MDL);
02130                         }
02131                         no_semi = 1;
02132                         break;
02133 
02134                       default:
02135                         parse_warn(cfile, "Unexpected token.");
02136                         skip_to_rbrace(cfile, 1);
02137                         no_semi = 1;
02138                         break;
02139                 }
02140 
02141                 if (!no_semi)
02142                         parse_semi(cfile);
02143 
02144                 token = next_token(&val, NULL, cfile);
02145                 if (token == END_OF_FILE) {
02146                         parse_warn(cfile, "Unexpected end of file.");
02147                         break;
02148                 }
02149         }
02150 
02151         return pref;
02152 }
02153 #endif /* DHCPv6 */
02154 
02155 void parse_string_list (cfile, lp, multiple)
02156         struct parse *cfile;
02157         struct string_list **lp;
02158         int multiple;
02159 {
02160         int token;
02161         const char *val;
02162         struct string_list *cur, *tmp;
02163 
02164         /* Find the last medium in the media list. */
02165         if (*lp) {
02166                 for (cur = *lp; cur -> next; cur = cur -> next)
02167                         ;
02168         } else {
02169                 cur = (struct string_list *)0;
02170         }
02171 
02172         do {
02173                 token = next_token (&val, (unsigned *)0, cfile);
02174                 if (token != STRING) {
02175                         parse_warn (cfile, "Expecting media options.");
02176                         skip_to_semi (cfile);
02177                         return;
02178                 }
02179 
02180                 tmp = ((struct string_list *)
02181                        dmalloc (strlen (val) + sizeof (struct string_list),
02182                                 MDL));
02183                 if (!tmp)
02184                         log_fatal ("no memory for string list entry.");
02185 
02186                 strcpy (tmp -> string, val);
02187                 tmp -> next = (struct string_list *)0;
02188 
02189                 /* Store this medium at the end of the media list. */
02190                 if (cur)
02191                         cur -> next = tmp;
02192                 else
02193                         *lp = tmp;
02194                 cur = tmp;
02195 
02196                 token = next_token (&val, (unsigned *)0, cfile);
02197         } while (multiple && token == COMMA);
02198 
02199         if (token != SEMI) {
02200                 parse_warn (cfile, "expecting semicolon.");
02201                 skip_to_semi (cfile);
02202         }
02203 }
02204 
02205 void parse_reject_statement (cfile, config)
02206         struct parse *cfile;
02207         struct client_config *config;
02208 {
02209         int token;
02210         const char *val;
02211         struct iaddrmatch match;
02212         struct iaddrmatchlist *list;
02213         int i;
02214 
02215         do {
02216                 if (!parse_ip_addr_with_subnet (cfile, &match)) {
02217                         /* no warn: parser will have reported what's wrong */
02218                         skip_to_semi (cfile);
02219                         return;
02220                 }
02221 
02222                 /* check mask is not all zeros (because that would
02223                  * reject EVERY address).  This check could be
02224                  * simplified if we assume that the mask *always*
02225                  * represents a prefix .. but perhaps it might be
02226                  * useful to have a mask which is not a proper prefix
02227                  * (perhaps for ipv6?).  The following is almost as
02228                  * efficient as inspection of match.mask.iabuf[0] when
02229                  * it IS a true prefix, and is more general when it is
02230                  * not.
02231                  */
02232 
02233                 for (i=0 ; i < match.mask.len ; i++) {
02234                     if (match.mask.iabuf[i]) {
02235                         break;
02236                     }
02237                 }
02238 
02239                 if (i == match.mask.len) {
02240                     /* oops we found all zeros */
02241                     parse_warn(cfile, "zero-length prefix is not permitted "
02242                                       "for reject statement");
02243                     skip_to_semi(cfile);
02244                     return;
02245                 } 
02246 
02247                 list = dmalloc(sizeof(struct iaddrmatchlist), MDL);
02248                 if (!list)
02249                         log_fatal ("no memory for reject list!");
02250 
02251                 list->match = match;
02252                 list->next = config->reject_list;
02253                 config->reject_list = list;
02254 
02255                 token = next_token (&val, (unsigned *)0, cfile);
02256         } while (token == COMMA);
02257 
02258         if (token != SEMI) {
02259                 parse_warn (cfile, "expecting semicolon.");
02260                 skip_to_semi (cfile);
02261         }
02262 }       
02263 
02264 /* allow-deny-keyword :== BOOTP
02265                         | BOOTING
02266                         | DYNAMIC_BOOTP
02267                         | UNKNOWN_CLIENTS */
02268 
02269 int parse_allow_deny (oc, cfile, flag)
02270         struct option_cache **oc;
02271         struct parse *cfile;
02272         int flag;
02273 {
02274         parse_warn (cfile, "allow/deny/ignore not permitted here.");
02275         skip_to_semi (cfile);
02276         return 0;
02277 }

Generated on 5 Apr 2014 for ISC DHCP by  doxygen 1.6.1