Annotation of embedaddon/dhcp/client/clparse.c, revision 1.1
1.1 ! misho 1: /* clparse.c
! 2:
! 3: Parser for dhclient config and lease files... */
! 4:
! 5: /*
! 6: * Copyright (c) 2004-2011 by Internet Systems Consortium, Inc. ("ISC")
! 7: * Copyright (c) 1996-2003 by Internet Software Consortium
! 8: *
! 9: * Permission to use, copy, modify, and distribute this software for any
! 10: * purpose with or without fee is hereby granted, provided that the above
! 11: * copyright notice and this permission notice appear in all copies.
! 12: *
! 13: * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
! 14: * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
! 15: * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
! 16: * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
! 17: * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
! 18: * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
! 19: * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
! 20: *
! 21: * Internet Systems Consortium, Inc.
! 22: * 950 Charter Street
! 23: * Redwood City, CA 94063
! 24: * <info@isc.org>
! 25: * https://www.isc.org/
! 26: *
! 27: * This software has been written for Internet Systems Consortium
! 28: * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc.
! 29: * To learn more about Internet Systems Consortium, see
! 30: * ``https://www.isc.org/''. To learn more about Vixie Enterprises,
! 31: * see ``http://www.vix.com''. To learn more about Nominum, Inc., see
! 32: * ``http://www.nominum.com''.
! 33: */
! 34:
! 35: #include "dhcpd.h"
! 36: #include <errno.h>
! 37:
! 38: struct client_config top_level_config;
! 39:
! 40: #define NUM_DEFAULT_REQUESTED_OPTS 9
! 41: struct option *default_requested_options[NUM_DEFAULT_REQUESTED_OPTS + 1];
! 42:
! 43: static void parse_client_default_duid(struct parse *cfile);
! 44: static void parse_client6_lease_statement(struct parse *cfile);
! 45: #ifdef DHCPv6
! 46: static struct dhc6_ia *parse_client6_ia_na_statement(struct parse *cfile);
! 47: static struct dhc6_ia *parse_client6_ia_ta_statement(struct parse *cfile);
! 48: static struct dhc6_ia *parse_client6_ia_pd_statement(struct parse *cfile);
! 49: static struct dhc6_addr *parse_client6_iaaddr_statement(struct parse *cfile);
! 50: static struct dhc6_addr *parse_client6_iaprefix_statement(struct parse *cfile);
! 51: #endif /* DHCPv6 */
! 52:
! 53: /* client-conf-file :== client-declarations END_OF_FILE
! 54: client-declarations :== <nil>
! 55: | client-declaration
! 56: | client-declarations client-declaration */
! 57:
! 58: isc_result_t read_client_conf ()
! 59: {
! 60: struct client_config *config;
! 61: struct interface_info *ip;
! 62: struct parse *parse;
! 63: isc_result_t status;
! 64: unsigned code;
! 65:
! 66: /* Initialize the default request list. */
! 67: memset(default_requested_options, 0, sizeof(default_requested_options));
! 68:
! 69: /* 1 */
! 70: code = DHO_SUBNET_MASK;
! 71: option_code_hash_lookup(&default_requested_options[0],
! 72: dhcp_universe.code_hash, &code, 0, MDL);
! 73:
! 74: /* 2 */
! 75: code = DHO_BROADCAST_ADDRESS;
! 76: option_code_hash_lookup(&default_requested_options[1],
! 77: dhcp_universe.code_hash, &code, 0, MDL);
! 78:
! 79: /* 3 */
! 80: code = DHO_TIME_OFFSET;
! 81: option_code_hash_lookup(&default_requested_options[2],
! 82: dhcp_universe.code_hash, &code, 0, MDL);
! 83:
! 84: /* 4 */
! 85: code = DHO_ROUTERS;
! 86: option_code_hash_lookup(&default_requested_options[3],
! 87: dhcp_universe.code_hash, &code, 0, MDL);
! 88:
! 89: /* 5 */
! 90: code = DHO_DOMAIN_NAME;
! 91: option_code_hash_lookup(&default_requested_options[4],
! 92: dhcp_universe.code_hash, &code, 0, MDL);
! 93:
! 94: /* 6 */
! 95: code = DHO_DOMAIN_NAME_SERVERS;
! 96: option_code_hash_lookup(&default_requested_options[5],
! 97: dhcp_universe.code_hash, &code, 0, MDL);
! 98:
! 99: /* 7 */
! 100: code = DHO_HOST_NAME;
! 101: option_code_hash_lookup(&default_requested_options[6],
! 102: dhcp_universe.code_hash, &code, 0, MDL);
! 103:
! 104: /* 8 */
! 105: code = D6O_NAME_SERVERS;
! 106: option_code_hash_lookup(&default_requested_options[7],
! 107: dhcpv6_universe.code_hash, &code, 0, MDL);
! 108:
! 109: /* 9 */
! 110: code = D6O_DOMAIN_SEARCH;
! 111: option_code_hash_lookup(&default_requested_options[8],
! 112: dhcpv6_universe.code_hash, &code, 0, MDL);
! 113:
! 114: for (code = 0 ; code < NUM_DEFAULT_REQUESTED_OPTS ; code++) {
! 115: if (default_requested_options[code] == NULL)
! 116: log_fatal("Unable to find option definition for "
! 117: "index %u during default parameter request "
! 118: "assembly.", code);
! 119: }
! 120:
! 121: /* Initialize the top level client configuration. */
! 122: memset (&top_level_config, 0, sizeof top_level_config);
! 123:
! 124: /* Set some defaults... */
! 125: top_level_config.timeout = 60;
! 126: top_level_config.select_interval = 0;
! 127: top_level_config.reboot_timeout = 10;
! 128: top_level_config.retry_interval = 300;
! 129: top_level_config.backoff_cutoff = 15;
! 130: top_level_config.initial_interval = 3;
! 131:
! 132: /*
! 133: * RFC 2131, section 4.4.1 specifies that the client SHOULD wait a
! 134: * random time between 1 and 10 seconds. However, we choose to not
! 135: * implement this default. If user is inclined to really have that
! 136: * delay, he is welcome to do so, using 'initial-delay X;' parameter
! 137: * in config file.
! 138: */
! 139: top_level_config.initial_delay = 0;
! 140:
! 141: top_level_config.bootp_policy = P_ACCEPT;
! 142: top_level_config.script_name = path_dhclient_script;
! 143: top_level_config.requested_options = default_requested_options;
! 144: top_level_config.omapi_port = -1;
! 145: top_level_config.do_forward_update = 1;
! 146: /* Requested lease time, used by DHCPv6 (DHCPv4 uses the option cache)
! 147: */
! 148: top_level_config.requested_lease = 7200;
! 149:
! 150: group_allocate (&top_level_config.on_receipt, MDL);
! 151: if (!top_level_config.on_receipt)
! 152: log_fatal ("no memory for top-level on_receipt group");
! 153:
! 154: group_allocate (&top_level_config.on_transmission, MDL);
! 155: if (!top_level_config.on_transmission)
! 156: log_fatal ("no memory for top-level on_transmission group");
! 157:
! 158: status = read_client_conf_file (path_dhclient_conf,
! 159: (struct interface_info *)0,
! 160: &top_level_config);
! 161:
! 162: parse = NULL;
! 163: if (status != ISC_R_SUCCESS) {
! 164: ;
! 165: #ifdef LATER
! 166: /* Set up the standard name service updater routine. */
! 167: status = new_parse(&parse, -1, default_client_config,
! 168: sizeof(default_client_config) - 1,
! 169: "default client configuration", 0);
! 170: if (status != ISC_R_SUCCESS)
! 171: log_fatal ("can't begin default client config!");
! 172: }
! 173:
! 174: if (parse != NULL) {
! 175: do {
! 176: token = peek_token(&val, NULL, cfile);
! 177: if (token == END_OF_FILE)
! 178: break;
! 179: parse_client_statement(cfile, NULL, &top_level_config);
! 180: } while (1);
! 181: end_parse(&parse);
! 182: #endif
! 183: }
! 184:
! 185: /* Set up state and config structures for clients that don't
! 186: have per-interface configuration statements. */
! 187: config = (struct client_config *)0;
! 188: for (ip = interfaces; ip; ip = ip -> next) {
! 189: if (!ip -> client) {
! 190: ip -> client = (struct client_state *)
! 191: dmalloc (sizeof (struct client_state), MDL);
! 192: if (!ip -> client)
! 193: log_fatal ("no memory for client state.");
! 194: memset (ip -> client, 0, sizeof *(ip -> client));
! 195: ip -> client -> interface = ip;
! 196: }
! 197:
! 198: if (!ip -> client -> config) {
! 199: if (!config) {
! 200: config = (struct client_config *)
! 201: dmalloc (sizeof (struct client_config),
! 202: MDL);
! 203: if (!config)
! 204: log_fatal ("no memory for client config.");
! 205: memcpy (config, &top_level_config,
! 206: sizeof top_level_config);
! 207: }
! 208: ip -> client -> config = config;
! 209: }
! 210: }
! 211: return status;
! 212: }
! 213:
! 214: int read_client_conf_file (const char *name, struct interface_info *ip,
! 215: struct client_config *client)
! 216: {
! 217: int file;
! 218: struct parse *cfile;
! 219: const char *val;
! 220: int token;
! 221: isc_result_t status;
! 222:
! 223: if ((file = open (name, O_RDONLY)) < 0)
! 224: return uerr2isc (errno);
! 225:
! 226: cfile = NULL;
! 227: status = new_parse(&cfile, file, NULL, 0, path_dhclient_conf, 0);
! 228: if (status != ISC_R_SUCCESS || cfile == NULL)
! 229: return status;
! 230:
! 231: do {
! 232: token = peek_token (&val, (unsigned *)0, cfile);
! 233: if (token == END_OF_FILE)
! 234: break;
! 235: parse_client_statement (cfile, ip, client);
! 236: } while (1);
! 237: token = next_token (&val, (unsigned *)0, cfile);
! 238: status = (cfile -> warnings_occurred
! 239: ? ISC_R_BADPARSE
! 240: : ISC_R_SUCCESS);
! 241: end_parse (&cfile);
! 242: return status;
! 243: }
! 244:
! 245:
! 246: /* lease-file :== client-lease-statements END_OF_FILE
! 247: client-lease-statements :== <nil>
! 248: | client-lease-statements LEASE client-lease-statement */
! 249:
! 250: void read_client_leases ()
! 251: {
! 252: int file;
! 253: isc_result_t status;
! 254: struct parse *cfile;
! 255: const char *val;
! 256: int token;
! 257:
! 258: /* Open the lease file. If we can't open it, just return -
! 259: we can safely trust the server to remember our state. */
! 260: if ((file = open (path_dhclient_db, O_RDONLY)) < 0)
! 261: return;
! 262:
! 263: cfile = NULL;
! 264: status = new_parse(&cfile, file, NULL, 0, path_dhclient_db, 0);
! 265: if (status != ISC_R_SUCCESS || cfile == NULL)
! 266: return;
! 267:
! 268: do {
! 269: token = next_token (&val, (unsigned *)0, cfile);
! 270: if (token == END_OF_FILE)
! 271: break;
! 272:
! 273: switch (token) {
! 274: case DEFAULT_DUID:
! 275: parse_client_default_duid(cfile);
! 276: break;
! 277:
! 278: case LEASE:
! 279: parse_client_lease_statement(cfile, 0);
! 280: break;
! 281:
! 282: case LEASE6:
! 283: parse_client6_lease_statement(cfile);
! 284: break;
! 285:
! 286: default:
! 287: log_error ("Corrupt lease file - possible data loss!");
! 288: skip_to_semi (cfile);
! 289: break;
! 290: }
! 291: } while (1);
! 292:
! 293: end_parse (&cfile);
! 294: }
! 295:
! 296: /* client-declaration :==
! 297: SEND option-decl |
! 298: DEFAULT option-decl |
! 299: SUPERSEDE option-decl |
! 300: PREPEND option-decl |
! 301: APPEND option-decl |
! 302: hardware-declaration |
! 303: ALSO REQUEST option-list |
! 304: ALSO REQUIRE option-list |
! 305: REQUEST option-list |
! 306: REQUIRE option-list |
! 307: TIMEOUT number |
! 308: RETRY number |
! 309: REBOOT number |
! 310: SELECT_TIMEOUT number |
! 311: SCRIPT string |
! 312: VENDOR_SPACE string |
! 313: interface-declaration |
! 314: LEASE client-lease-statement |
! 315: ALIAS client-lease-statement |
! 316: KEY key-definition */
! 317:
! 318: void parse_client_statement (cfile, ip, config)
! 319: struct parse *cfile;
! 320: struct interface_info *ip;
! 321: struct client_config *config;
! 322: {
! 323: int token;
! 324: const char *val;
! 325: struct option *option = NULL;
! 326: struct executable_statement *stmt;
! 327: int lose;
! 328: char *name;
! 329: enum policy policy;
! 330: int known;
! 331: int tmp, i;
! 332: isc_result_t status;
! 333: struct option ***append_list, **new_list, **cat_list;
! 334:
! 335: switch (peek_token (&val, (unsigned *)0, cfile)) {
! 336: case INCLUDE:
! 337: next_token (&val, (unsigned *)0, cfile);
! 338: token = next_token (&val, (unsigned *)0, cfile);
! 339: if (token != STRING) {
! 340: parse_warn (cfile, "filename string expected.");
! 341: skip_to_semi (cfile);
! 342: } else {
! 343: status = read_client_conf_file (val, ip, config);
! 344: if (status != ISC_R_SUCCESS)
! 345: parse_warn (cfile, "%s: bad parse.", val);
! 346: parse_semi (cfile);
! 347: }
! 348: return;
! 349:
! 350: case KEY:
! 351: next_token (&val, (unsigned *)0, cfile);
! 352: if (ip) {
! 353: /* This may seem arbitrary, but there's a reason for
! 354: doing it: the authentication key database is not
! 355: scoped. If we allow the user to declare a key other
! 356: than in the outer scope, the user is very likely to
! 357: believe that the key will only be used in that
! 358: scope. If the user only wants the key to be used on
! 359: one interface, because it's known that the other
! 360: interface may be connected to an insecure net and
! 361: the secret key is considered sensitive, we don't
! 362: want to lull them into believing they've gotten
! 363: their way. This is a bit contrived, but people
! 364: tend not to be entirely rational about security. */
! 365: parse_warn (cfile, "key definition not allowed here.");
! 366: skip_to_semi (cfile);
! 367: break;
! 368: }
! 369: parse_key (cfile);
! 370: return;
! 371:
! 372: case TOKEN_ALSO:
! 373: /* consume ALSO */
! 374: next_token(&val, NULL, cfile);
! 375:
! 376: /* consume type of ALSO list. */
! 377: token = next_token(&val, NULL, cfile);
! 378:
! 379: if (token == REQUEST) {
! 380: append_list = &config->requested_options;
! 381: } else if (token == REQUIRE) {
! 382: append_list = &config->required_options;
! 383: } else {
! 384: parse_warn(cfile, "expected REQUEST or REQUIRE list");
! 385: skip_to_semi(cfile);
! 386: return;
! 387: }
! 388:
! 389: /* If there is no list, cut the concat short. */
! 390: if (*append_list == NULL) {
! 391: parse_option_list(cfile, append_list);
! 392: return;
! 393: }
! 394:
! 395: /* Count the length of the existing list. */
! 396: for (i = 0 ; (*append_list)[i] != NULL ; i++)
! 397: ; /* This space intentionally left blank. */
! 398:
! 399: /* If there's no codes on the list, cut the concat short. */
! 400: if (i == 0) {
! 401: parse_option_list(cfile, append_list);
! 402: return;
! 403: }
! 404:
! 405: tmp = parse_option_list(cfile, &new_list);
! 406:
! 407: if (tmp == 0 || new_list == NULL)
! 408: return;
! 409:
! 410: /* Allocate 'i + tmp' buckets plus a terminator. */
! 411: cat_list = dmalloc(sizeof(struct option *) * (i + tmp + 1),
! 412: MDL);
! 413:
! 414: if (cat_list == NULL) {
! 415: log_error("Unable to allocate memory for new "
! 416: "request list.");
! 417: skip_to_semi(cfile);
! 418: return;
! 419: }
! 420:
! 421: for (i = 0 ; (*append_list)[i] != NULL ; i++)
! 422: option_reference(&cat_list[i], (*append_list)[i], MDL);
! 423:
! 424: tmp = i;
! 425:
! 426: for (i = 0 ; new_list[i] != 0 ; i++)
! 427: option_reference(&cat_list[tmp++], new_list[i], MDL);
! 428:
! 429: cat_list[tmp] = 0;
! 430:
! 431: /* XXX: We cannot free the old list, because it may have been
! 432: * XXX: assigned from an outer configuration scope (or may be
! 433: * XXX: the static default setting).
! 434: */
! 435: *append_list = cat_list;
! 436:
! 437: return;
! 438:
! 439: /* REQUIRE can either start a policy statement or a
! 440: comma-separated list of names of required options. */
! 441: case REQUIRE:
! 442: next_token (&val, (unsigned *)0, cfile);
! 443: token = peek_token (&val, (unsigned *)0, cfile);
! 444: if (token == AUTHENTICATION) {
! 445: policy = P_REQUIRE;
! 446: goto do_policy;
! 447: }
! 448: parse_option_list (cfile, &config -> required_options);
! 449: return;
! 450:
! 451: case IGNORE:
! 452: next_token (&val, (unsigned *)0, cfile);
! 453: policy = P_IGNORE;
! 454: goto do_policy;
! 455:
! 456: case ACCEPT:
! 457: next_token (&val, (unsigned *)0, cfile);
! 458: policy = P_ACCEPT;
! 459: goto do_policy;
! 460:
! 461: case PREFER:
! 462: next_token (&val, (unsigned *)0, cfile);
! 463: policy = P_PREFER;
! 464: goto do_policy;
! 465:
! 466: case DONT:
! 467: next_token (&val, (unsigned *)0, cfile);
! 468: policy = P_DONT;
! 469: goto do_policy;
! 470:
! 471: do_policy:
! 472: token = next_token (&val, (unsigned *)0, cfile);
! 473: if (token == AUTHENTICATION) {
! 474: if (policy != P_PREFER &&
! 475: policy != P_REQUIRE &&
! 476: policy != P_DONT) {
! 477: parse_warn (cfile,
! 478: "invalid authentication policy.");
! 479: skip_to_semi (cfile);
! 480: return;
! 481: }
! 482: config -> auth_policy = policy;
! 483: } else if (token != TOKEN_BOOTP) {
! 484: if (policy != P_PREFER &&
! 485: policy != P_IGNORE &&
! 486: policy != P_ACCEPT) {
! 487: parse_warn (cfile, "invalid bootp policy.");
! 488: skip_to_semi (cfile);
! 489: return;
! 490: }
! 491: config -> bootp_policy = policy;
! 492: } else {
! 493: parse_warn (cfile, "expecting a policy type.");
! 494: skip_to_semi (cfile);
! 495: return;
! 496: }
! 497: break;
! 498:
! 499: case OPTION:
! 500: token = next_token (&val, (unsigned *)0, cfile);
! 501:
! 502: token = peek_token (&val, (unsigned *)0, cfile);
! 503: if (token == SPACE) {
! 504: if (ip) {
! 505: parse_warn (cfile,
! 506: "option space definitions %s",
! 507: " may not be scoped.");
! 508: skip_to_semi (cfile);
! 509: break;
! 510: }
! 511: parse_option_space_decl (cfile);
! 512: return;
! 513: }
! 514:
! 515: known = 0;
! 516: status = parse_option_name(cfile, 1, &known, &option);
! 517: if (status != ISC_R_SUCCESS || option == NULL)
! 518: return;
! 519:
! 520: token = next_token (&val, (unsigned *)0, cfile);
! 521: if (token != CODE) {
! 522: parse_warn (cfile, "expecting \"code\" keyword.");
! 523: skip_to_semi (cfile);
! 524: option_dereference(&option, MDL);
! 525: return;
! 526: }
! 527: if (ip) {
! 528: parse_warn (cfile,
! 529: "option definitions may only appear in %s",
! 530: "the outermost scope.");
! 531: skip_to_semi (cfile);
! 532: option_dereference(&option, MDL);
! 533: return;
! 534: }
! 535:
! 536: /*
! 537: * If the option was known, remove it from the code and name
! 538: * hash tables before redefining it.
! 539: */
! 540: if (known) {
! 541: option_name_hash_delete(option->universe->name_hash,
! 542: option->name, 0, MDL);
! 543: option_code_hash_delete(option->universe->code_hash,
! 544: &option->code, 0, MDL);
! 545: }
! 546:
! 547: parse_option_code_definition(cfile, option);
! 548: option_dereference(&option, MDL);
! 549: return;
! 550:
! 551: case MEDIA:
! 552: token = next_token (&val, (unsigned *)0, cfile);
! 553: parse_string_list (cfile, &config -> media, 1);
! 554: return;
! 555:
! 556: case HARDWARE:
! 557: token = next_token (&val, (unsigned *)0, cfile);
! 558: if (ip) {
! 559: parse_hardware_param (cfile, &ip -> hw_address);
! 560: } else {
! 561: parse_warn (cfile, "hardware address parameter %s",
! 562: "not allowed here.");
! 563: skip_to_semi (cfile);
! 564: }
! 565: return;
! 566:
! 567: case REQUEST:
! 568: token = next_token (&val, (unsigned *)0, cfile);
! 569: if (config -> requested_options == default_requested_options)
! 570: config -> requested_options = NULL;
! 571: parse_option_list (cfile, &config -> requested_options);
! 572: return;
! 573:
! 574: case TIMEOUT:
! 575: token = next_token (&val, (unsigned *)0, cfile);
! 576: parse_lease_time (cfile, &config -> timeout);
! 577: return;
! 578:
! 579: case RETRY:
! 580: token = next_token (&val, (unsigned *)0, cfile);
! 581: parse_lease_time (cfile, &config -> retry_interval);
! 582: return;
! 583:
! 584: case SELECT_TIMEOUT:
! 585: token = next_token (&val, (unsigned *)0, cfile);
! 586: parse_lease_time (cfile, &config -> select_interval);
! 587: return;
! 588:
! 589: case OMAPI:
! 590: token = next_token (&val, (unsigned *)0, cfile);
! 591: token = next_token (&val, (unsigned *)0, cfile);
! 592: if (token != PORT) {
! 593: parse_warn (cfile,
! 594: "unexpected omapi subtype: %s", val);
! 595: skip_to_semi (cfile);
! 596: return;
! 597: }
! 598: token = next_token (&val, (unsigned *)0, cfile);
! 599: if (token != NUMBER) {
! 600: parse_warn (cfile, "invalid port number: `%s'", val);
! 601: skip_to_semi (cfile);
! 602: return;
! 603: }
! 604: tmp = atoi (val);
! 605: if (tmp < 0 || tmp > 65535)
! 606: parse_warn (cfile, "invalid omapi port %d.", tmp);
! 607: else if (config != &top_level_config)
! 608: parse_warn (cfile,
! 609: "omapi port only works at top level.");
! 610: else
! 611: config -> omapi_port = tmp;
! 612: parse_semi (cfile);
! 613: return;
! 614:
! 615: case DO_FORWARD_UPDATE:
! 616: token = next_token (&val, (unsigned *)0, cfile);
! 617: token = next_token (&val, (unsigned *)0, cfile);
! 618: if (!strcasecmp (val, "on") ||
! 619: !strcasecmp (val, "true"))
! 620: config -> do_forward_update = 1;
! 621: else if (!strcasecmp (val, "off") ||
! 622: !strcasecmp (val, "false"))
! 623: config -> do_forward_update = 0;
! 624: else {
! 625: parse_warn (cfile, "expecting boolean value.");
! 626: skip_to_semi (cfile);
! 627: return;
! 628: }
! 629: parse_semi (cfile);
! 630: return;
! 631:
! 632: case REBOOT:
! 633: token = next_token (&val, (unsigned *)0, cfile);
! 634: parse_lease_time (cfile, &config -> reboot_timeout);
! 635: return;
! 636:
! 637: case BACKOFF_CUTOFF:
! 638: token = next_token (&val, (unsigned *)0, cfile);
! 639: parse_lease_time (cfile, &config -> backoff_cutoff);
! 640: return;
! 641:
! 642: case INITIAL_INTERVAL:
! 643: token = next_token (&val, (unsigned *)0, cfile);
! 644: parse_lease_time (cfile, &config -> initial_interval);
! 645: return;
! 646:
! 647: case INITIAL_DELAY:
! 648: token = next_token (&val, (unsigned *)0, cfile);
! 649: parse_lease_time (cfile, &config -> initial_delay);
! 650: return;
! 651:
! 652: case SCRIPT:
! 653: token = next_token (&val, (unsigned *)0, cfile);
! 654: parse_string (cfile, &config -> script_name, (unsigned *)0);
! 655: return;
! 656:
! 657: case VENDOR:
! 658: token = next_token (&val, (unsigned *)0, cfile);
! 659: token = next_token (&val, (unsigned *)0, cfile);
! 660: if (token != OPTION) {
! 661: parse_warn (cfile, "expecting 'vendor option space'");
! 662: skip_to_semi (cfile);
! 663: return;
! 664: }
! 665: token = next_token (&val, (unsigned *)0, cfile);
! 666: if (token != SPACE) {
! 667: parse_warn (cfile, "expecting 'vendor option space'");
! 668: skip_to_semi (cfile);
! 669: return;
! 670: }
! 671: token = next_token (&val, (unsigned *)0, cfile);
! 672: if (!is_identifier (token)) {
! 673: parse_warn (cfile, "expecting an identifier.");
! 674: skip_to_semi (cfile);
! 675: return;
! 676: }
! 677: config -> vendor_space_name = dmalloc (strlen (val) + 1, MDL);
! 678: if (!config -> vendor_space_name)
! 679: log_fatal ("no memory for vendor option space name.");
! 680: strcpy (config -> vendor_space_name, val);
! 681: for (i = 0; i < universe_count; i++)
! 682: if (!strcmp (universes [i] -> name,
! 683: config -> vendor_space_name))
! 684: break;
! 685: if (i == universe_count) {
! 686: log_error ("vendor option space %s not found.",
! 687: config -> vendor_space_name);
! 688: }
! 689: parse_semi (cfile);
! 690: return;
! 691:
! 692: case INTERFACE:
! 693: token = next_token (&val, (unsigned *)0, cfile);
! 694: if (ip)
! 695: parse_warn (cfile, "nested interface declaration.");
! 696: parse_interface_declaration (cfile, config, (char *)0);
! 697: return;
! 698:
! 699: case PSEUDO:
! 700: token = next_token (&val, (unsigned *)0, cfile);
! 701: token = next_token (&val, (unsigned *)0, cfile);
! 702: name = dmalloc (strlen (val) + 1, MDL);
! 703: if (!name)
! 704: log_fatal ("no memory for pseudo interface name");
! 705: strcpy (name, val);
! 706: parse_interface_declaration (cfile, config, name);
! 707: return;
! 708:
! 709: case LEASE:
! 710: token = next_token (&val, (unsigned *)0, cfile);
! 711: parse_client_lease_statement (cfile, 1);
! 712: return;
! 713:
! 714: case ALIAS:
! 715: token = next_token (&val, (unsigned *)0, cfile);
! 716: parse_client_lease_statement (cfile, 2);
! 717: return;
! 718:
! 719: case REJECT:
! 720: token = next_token (&val, (unsigned *)0, cfile);
! 721: parse_reject_statement (cfile, config);
! 722: return;
! 723:
! 724: default:
! 725: lose = 0;
! 726: stmt = (struct executable_statement *)0;
! 727: if (!parse_executable_statement (&stmt,
! 728: cfile, &lose, context_any)) {
! 729: if (!lose) {
! 730: parse_warn (cfile, "expecting a statement.");
! 731: skip_to_semi (cfile);
! 732: }
! 733: } else {
! 734: struct executable_statement **eptr, *sptr;
! 735: if (stmt &&
! 736: (stmt -> op == send_option_statement ||
! 737: (stmt -> op == on_statement &&
! 738: (stmt -> data.on.evtypes & ON_TRANSMISSION)))) {
! 739: eptr = &config -> on_transmission -> statements;
! 740: if (stmt -> op == on_statement) {
! 741: sptr = (struct executable_statement *)0;
! 742: executable_statement_reference
! 743: (&sptr,
! 744: stmt -> data.on.statements, MDL);
! 745: executable_statement_dereference (&stmt,
! 746: MDL);
! 747: executable_statement_reference (&stmt,
! 748: sptr,
! 749: MDL);
! 750: executable_statement_dereference (&sptr,
! 751: MDL);
! 752: }
! 753: } else
! 754: eptr = &config -> on_receipt -> statements;
! 755:
! 756: if (stmt) {
! 757: for (; *eptr; eptr = &(*eptr) -> next)
! 758: ;
! 759: executable_statement_reference (eptr,
! 760: stmt, MDL);
! 761: }
! 762: return;
! 763: }
! 764: break;
! 765: }
! 766: parse_semi (cfile);
! 767: }
! 768:
! 769: /* option-list :== option_name |
! 770: option_list COMMA option_name */
! 771:
! 772: int
! 773: parse_option_list(struct parse *cfile, struct option ***list)
! 774: {
! 775: int ix;
! 776: int token;
! 777: const char *val;
! 778: pair p = (pair)0, q = (pair)0, r;
! 779: struct option *option = NULL;
! 780: isc_result_t status;
! 781:
! 782: ix = 0;
! 783: do {
! 784: token = peek_token (&val, (unsigned *)0, cfile);
! 785: if (token == SEMI) {
! 786: token = next_token (&val, (unsigned *)0, cfile);
! 787: break;
! 788: }
! 789: if (!is_identifier (token)) {
! 790: parse_warn (cfile, "%s: expected option name.", val);
! 791: token = next_token (&val, (unsigned *)0, cfile);
! 792: skip_to_semi (cfile);
! 793: return 0;
! 794: }
! 795: status = parse_option_name(cfile, 0, NULL, &option);
! 796: if (status != ISC_R_SUCCESS || option == NULL) {
! 797: parse_warn (cfile, "%s: expected option name.", val);
! 798: return 0;
! 799: }
! 800: r = new_pair (MDL);
! 801: if (!r)
! 802: log_fatal ("can't allocate pair for option code.");
! 803: /* XXX: we should probably carry a reference across this */
! 804: r->car = (caddr_t)option;
! 805: option_dereference(&option, MDL);
! 806: r -> cdr = (pair)0;
! 807: if (p)
! 808: q -> cdr = r;
! 809: else
! 810: p = r;
! 811: q = r;
! 812: ++ix;
! 813: token = next_token (&val, (unsigned *)0, cfile);
! 814: } while (token == COMMA);
! 815: if (token != SEMI) {
! 816: parse_warn (cfile, "expecting semicolon.");
! 817: skip_to_semi (cfile);
! 818: return 0;
! 819: }
! 820: /* XXX we can't free the list here, because we may have copied
! 821: XXX it from an outer config state. */
! 822: *list = NULL;
! 823: if (ix) {
! 824: *list = dmalloc ((ix + 1) * sizeof(struct option *), MDL);
! 825: if (!*list)
! 826: log_error ("no memory for option list.");
! 827: else {
! 828: ix = 0;
! 829: for (q = p; q; q = q -> cdr)
! 830: option_reference(&(*list)[ix++],
! 831: (struct option *)q->car, MDL);
! 832: (*list)[ix] = NULL;
! 833: }
! 834: while (p) {
! 835: q = p -> cdr;
! 836: free_pair (p, MDL);
! 837: p = q;
! 838: }
! 839: }
! 840:
! 841: return ix;
! 842: }
! 843:
! 844: /* interface-declaration :==
! 845: INTERFACE string LBRACE client-declarations RBRACE */
! 846:
! 847: void parse_interface_declaration (cfile, outer_config, name)
! 848: struct parse *cfile;
! 849: struct client_config *outer_config;
! 850: char *name;
! 851: {
! 852: int token;
! 853: const char *val;
! 854: struct client_state *client, **cp;
! 855: struct interface_info *ip = (struct interface_info *)0;
! 856:
! 857: token = next_token (&val, (unsigned *)0, cfile);
! 858: if (token != STRING) {
! 859: parse_warn (cfile, "expecting interface name (in quotes).");
! 860: skip_to_semi (cfile);
! 861: return;
! 862: }
! 863:
! 864: if (!interface_or_dummy (&ip, val))
! 865: log_fatal ("Can't allocate interface %s.", val);
! 866:
! 867: /* If we were given a name, this is a pseudo-interface. */
! 868: if (name) {
! 869: make_client_state (&client);
! 870: client -> name = name;
! 871: client -> interface = ip;
! 872: for (cp = &ip -> client; *cp; cp = &((*cp) -> next))
! 873: ;
! 874: *cp = client;
! 875: } else {
! 876: if (!ip -> client) {
! 877: make_client_state (&ip -> client);
! 878: ip -> client -> interface = ip;
! 879: }
! 880: client = ip -> client;
! 881: }
! 882:
! 883: if (!client -> config)
! 884: make_client_config (client, outer_config);
! 885:
! 886: ip -> flags &= ~INTERFACE_AUTOMATIC;
! 887: interfaces_requested = 1;
! 888:
! 889: token = next_token (&val, (unsigned *)0, cfile);
! 890: if (token != LBRACE) {
! 891: parse_warn (cfile, "expecting left brace.");
! 892: skip_to_semi (cfile);
! 893: return;
! 894: }
! 895:
! 896: do {
! 897: token = peek_token (&val, (unsigned *)0, cfile);
! 898: if (token == END_OF_FILE) {
! 899: parse_warn (cfile,
! 900: "unterminated interface declaration.");
! 901: return;
! 902: }
! 903: if (token == RBRACE)
! 904: break;
! 905: parse_client_statement (cfile, ip, client -> config);
! 906: } while (1);
! 907: token = next_token (&val, (unsigned *)0, cfile);
! 908: }
! 909:
! 910: int interface_or_dummy (struct interface_info **pi, const char *name)
! 911: {
! 912: struct interface_info *i;
! 913: struct interface_info *ip = (struct interface_info *)0;
! 914: isc_result_t status;
! 915:
! 916: /* Find the interface (if any) that matches the name. */
! 917: for (i = interfaces; i; i = i -> next) {
! 918: if (!strcmp (i -> name, name)) {
! 919: interface_reference (&ip, i, MDL);
! 920: break;
! 921: }
! 922: }
! 923:
! 924: /* If it's not a real interface, see if it's on the dummy list. */
! 925: if (!ip) {
! 926: for (ip = dummy_interfaces; ip; ip = ip -> next) {
! 927: if (!strcmp (ip -> name, name)) {
! 928: interface_reference (&ip, i, MDL);
! 929: break;
! 930: }
! 931: }
! 932: }
! 933:
! 934: /* If we didn't find an interface, make a dummy interface as
! 935: a placeholder. */
! 936: if (!ip) {
! 937: if ((status = interface_allocate (&ip, MDL)) != ISC_R_SUCCESS)
! 938: log_fatal ("Can't record interface %s: %s",
! 939: name, isc_result_totext (status));
! 940:
! 941: if (strlen(name) >= sizeof(ip->name)) {
! 942: interface_dereference(&ip, MDL);
! 943: return 0;
! 944: }
! 945: strcpy(ip->name, name);
! 946:
! 947: if (dummy_interfaces) {
! 948: interface_reference (&ip -> next,
! 949: dummy_interfaces, MDL);
! 950: interface_dereference (&dummy_interfaces, MDL);
! 951: }
! 952: interface_reference (&dummy_interfaces, ip, MDL);
! 953: }
! 954: if (pi)
! 955: status = interface_reference (pi, ip, MDL);
! 956: else
! 957: status = ISC_R_FAILURE;
! 958: interface_dereference (&ip, MDL);
! 959: if (status != ISC_R_SUCCESS)
! 960: return 0;
! 961: return 1;
! 962: }
! 963:
! 964: void make_client_state (state)
! 965: struct client_state **state;
! 966: {
! 967: *state = ((struct client_state *)dmalloc (sizeof **state, MDL));
! 968: if (!*state)
! 969: log_fatal ("no memory for client state\n");
! 970: memset (*state, 0, sizeof **state);
! 971: }
! 972:
! 973: void make_client_config (client, config)
! 974: struct client_state *client;
! 975: struct client_config *config;
! 976: {
! 977: client -> config = (((struct client_config *)
! 978: dmalloc (sizeof (struct client_config), MDL)));
! 979: if (!client -> config)
! 980: log_fatal ("no memory for client config\n");
! 981: memcpy (client -> config, config, sizeof *config);
! 982: if (!clone_group (&client -> config -> on_receipt,
! 983: config -> on_receipt, MDL) ||
! 984: !clone_group (&client -> config -> on_transmission,
! 985: config -> on_transmission, MDL))
! 986: log_fatal ("no memory for client state groups.");
! 987: }
! 988:
! 989: /* client-lease-statement :==
! 990: LBRACE client-lease-declarations RBRACE
! 991:
! 992: client-lease-declarations :==
! 993: <nil> |
! 994: client-lease-declaration |
! 995: client-lease-declarations client-lease-declaration */
! 996:
! 997:
! 998: void parse_client_lease_statement (cfile, is_static)
! 999: struct parse *cfile;
! 1000: int is_static;
! 1001: {
! 1002: struct client_lease *lease, *lp, *pl, *next;
! 1003: struct interface_info *ip = (struct interface_info *)0;
! 1004: int token;
! 1005: const char *val;
! 1006: struct client_state *client = (struct client_state *)0;
! 1007:
! 1008: token = next_token (&val, (unsigned *)0, cfile);
! 1009: if (token != LBRACE) {
! 1010: parse_warn (cfile, "expecting left brace.");
! 1011: skip_to_semi (cfile);
! 1012: return;
! 1013: }
! 1014:
! 1015: lease = ((struct client_lease *)
! 1016: dmalloc (sizeof (struct client_lease), MDL));
! 1017: if (!lease)
! 1018: log_fatal ("no memory for lease.\n");
! 1019: memset (lease, 0, sizeof *lease);
! 1020: lease -> is_static = is_static;
! 1021: if (!option_state_allocate (&lease -> options, MDL))
! 1022: log_fatal ("no memory for lease options.\n");
! 1023:
! 1024: do {
! 1025: token = peek_token (&val, (unsigned *)0, cfile);
! 1026: if (token == END_OF_FILE) {
! 1027: parse_warn (cfile, "unterminated lease declaration.");
! 1028: return;
! 1029: }
! 1030: if (token == RBRACE)
! 1031: break;
! 1032: parse_client_lease_declaration (cfile, lease, &ip, &client);
! 1033: } while (1);
! 1034: token = next_token (&val, (unsigned *)0, cfile);
! 1035:
! 1036: /* If the lease declaration didn't include an interface
! 1037: declaration that we recognized, it's of no use to us. */
! 1038: if (!ip) {
! 1039: destroy_client_lease (lease);
! 1040: return;
! 1041: }
! 1042:
! 1043: /* Make sure there's a client state structure... */
! 1044: if (!ip -> client) {
! 1045: make_client_state (&ip -> client);
! 1046: ip -> client -> interface = ip;
! 1047: }
! 1048: if (!client)
! 1049: client = ip -> client;
! 1050:
! 1051: /* If this is an alias lease, it doesn't need to be sorted in. */
! 1052: if (is_static == 2) {
! 1053: ip -> client -> alias = lease;
! 1054: return;
! 1055: }
! 1056:
! 1057: /* The new lease may supersede a lease that's not the
! 1058: active lease but is still on the lease list, so scan the
! 1059: lease list looking for a lease with the same address, and
! 1060: if we find it, toss it. */
! 1061: pl = (struct client_lease *)0;
! 1062: for (lp = client -> leases; lp; lp = next) {
! 1063: next = lp -> next;
! 1064: if (lp -> address.len == lease -> address.len &&
! 1065: !memcmp (lp -> address.iabuf, lease -> address.iabuf,
! 1066: lease -> address.len)) {
! 1067: if (pl)
! 1068: pl -> next = next;
! 1069: else
! 1070: client -> leases = next;
! 1071: destroy_client_lease (lp);
! 1072: break;
! 1073: } else
! 1074: pl = lp;
! 1075: }
! 1076:
! 1077: /* If this is a preloaded lease, just put it on the list of recorded
! 1078: leases - don't make it the active lease. */
! 1079: if (is_static) {
! 1080: lease -> next = client -> leases;
! 1081: client -> leases = lease;
! 1082: return;
! 1083: }
! 1084:
! 1085: /* The last lease in the lease file on a particular interface is
! 1086: the active lease for that interface. Of course, we don't know
! 1087: what the last lease in the file is until we've parsed the whole
! 1088: file, so at this point, we assume that the lease we just parsed
! 1089: is the active lease for its interface. If there's already
! 1090: an active lease for the interface, and this lease is for the same
! 1091: ip address, then we just toss the old active lease and replace
! 1092: it with this one. If this lease is for a different address,
! 1093: then if the old active lease has expired, we dump it; if not,
! 1094: we put it on the list of leases for this interface which are
! 1095: still valid but no longer active. */
! 1096: if (client -> active) {
! 1097: if (client -> active -> expiry < cur_time)
! 1098: destroy_client_lease (client -> active);
! 1099: else if (client -> active -> address.len ==
! 1100: lease -> address.len &&
! 1101: !memcmp (client -> active -> address.iabuf,
! 1102: lease -> address.iabuf,
! 1103: lease -> address.len))
! 1104: destroy_client_lease (client -> active);
! 1105: else {
! 1106: client -> active -> next = client -> leases;
! 1107: client -> leases = client -> active;
! 1108: }
! 1109: }
! 1110: client -> active = lease;
! 1111:
! 1112: /* phew. */
! 1113: }
! 1114:
! 1115: /* client-lease-declaration :==
! 1116: BOOTP |
! 1117: INTERFACE string |
! 1118: FIXED_ADDR ip_address |
! 1119: FILENAME string |
! 1120: SERVER_NAME string |
! 1121: OPTION option-decl |
! 1122: RENEW time-decl |
! 1123: REBIND time-decl |
! 1124: EXPIRE time-decl |
! 1125: KEY id */
! 1126:
! 1127: void parse_client_lease_declaration (cfile, lease, ipp, clientp)
! 1128: struct parse *cfile;
! 1129: struct client_lease *lease;
! 1130: struct interface_info **ipp;
! 1131: struct client_state **clientp;
! 1132: {
! 1133: int token;
! 1134: const char *val;
! 1135: struct interface_info *ip;
! 1136: struct option_cache *oc;
! 1137: struct client_state *client = (struct client_state *)0;
! 1138:
! 1139: switch (next_token (&val, (unsigned *)0, cfile)) {
! 1140: case KEY:
! 1141: token = next_token (&val, (unsigned *)0, cfile);
! 1142: if (token != STRING && !is_identifier (token)) {
! 1143: parse_warn (cfile, "expecting key name.");
! 1144: skip_to_semi (cfile);
! 1145: break;
! 1146: }
! 1147: if (omapi_auth_key_lookup_name (&lease -> key, val) !=
! 1148: ISC_R_SUCCESS)
! 1149: parse_warn (cfile, "unknown key %s", val);
! 1150: parse_semi (cfile);
! 1151: break;
! 1152: case TOKEN_BOOTP:
! 1153: lease -> is_bootp = 1;
! 1154: break;
! 1155:
! 1156: case INTERFACE:
! 1157: token = next_token (&val, (unsigned *)0, cfile);
! 1158: if (token != STRING) {
! 1159: parse_warn (cfile,
! 1160: "expecting interface name (in quotes).");
! 1161: skip_to_semi (cfile);
! 1162: break;
! 1163: }
! 1164: if (!interface_or_dummy (ipp, val))
! 1165: log_fatal ("Can't allocate interface %s.", val);
! 1166: break;
! 1167:
! 1168: case NAME:
! 1169: token = next_token (&val, (unsigned *)0, cfile);
! 1170: ip = *ipp;
! 1171: if (!ip) {
! 1172: parse_warn (cfile, "state name precedes interface.");
! 1173: break;
! 1174: }
! 1175: for (client = ip -> client; client; client = client -> next)
! 1176: if (client -> name && !strcmp (client -> name, val))
! 1177: break;
! 1178: if (!client)
! 1179: parse_warn (cfile,
! 1180: "lease specified for unknown pseudo.");
! 1181: *clientp = client;
! 1182: break;
! 1183:
! 1184: case FIXED_ADDR:
! 1185: if (!parse_ip_addr (cfile, &lease -> address))
! 1186: return;
! 1187: break;
! 1188:
! 1189: case MEDIUM:
! 1190: parse_string_list (cfile, &lease -> medium, 0);
! 1191: return;
! 1192:
! 1193: case FILENAME:
! 1194: parse_string (cfile, &lease -> filename, (unsigned *)0);
! 1195: return;
! 1196:
! 1197: case SERVER_NAME:
! 1198: parse_string (cfile, &lease -> server_name, (unsigned *)0);
! 1199: return;
! 1200:
! 1201: case RENEW:
! 1202: lease -> renewal = parse_date (cfile);
! 1203: return;
! 1204:
! 1205: case REBIND:
! 1206: lease -> rebind = parse_date (cfile);
! 1207: return;
! 1208:
! 1209: case EXPIRE:
! 1210: lease -> expiry = parse_date (cfile);
! 1211: return;
! 1212:
! 1213: case OPTION:
! 1214: oc = (struct option_cache *)0;
! 1215: if (parse_option_decl (&oc, cfile)) {
! 1216: save_option(oc->option->universe, lease->options, oc);
! 1217: option_cache_dereference (&oc, MDL);
! 1218: }
! 1219: return;
! 1220:
! 1221: default:
! 1222: parse_warn (cfile, "expecting lease declaration.");
! 1223: skip_to_semi (cfile);
! 1224: break;
! 1225: }
! 1226: token = next_token (&val, (unsigned *)0, cfile);
! 1227: if (token != SEMI) {
! 1228: parse_warn (cfile, "expecting semicolon.");
! 1229: skip_to_semi (cfile);
! 1230: }
! 1231: }
! 1232:
! 1233: /* Parse a default-duid ""; statement.
! 1234: */
! 1235: static void
! 1236: parse_client_default_duid(struct parse *cfile)
! 1237: {
! 1238: struct data_string new_duid;
! 1239: const char *val = NULL;
! 1240: unsigned len;
! 1241: int token;
! 1242:
! 1243: memset(&new_duid, 0, sizeof(new_duid));
! 1244:
! 1245: token = next_token(&val, &len, cfile);
! 1246: if (token != STRING) {
! 1247: parse_warn(cfile, "Expected DUID string.");
! 1248: skip_to_semi(cfile);
! 1249: return;
! 1250: }
! 1251:
! 1252: if (len <= 2) {
! 1253: parse_warn(cfile, "Invalid DUID contents.");
! 1254: skip_to_semi(cfile);
! 1255: return;
! 1256: }
! 1257:
! 1258: if (!buffer_allocate(&new_duid.buffer, len, MDL)) {
! 1259: parse_warn(cfile, "Out of memory parsing default DUID.");
! 1260: skip_to_semi(cfile);
! 1261: return;
! 1262: }
! 1263: new_duid.data = new_duid.buffer->data;
! 1264: new_duid.len = len;
! 1265:
! 1266: memcpy(new_duid.buffer->data, val, len);
! 1267:
! 1268: /* Rotate the last entry into place. */
! 1269: if (default_duid.buffer != NULL)
! 1270: data_string_forget(&default_duid, MDL);
! 1271: data_string_copy(&default_duid, &new_duid, MDL);
! 1272: data_string_forget(&new_duid, MDL);
! 1273:
! 1274: parse_semi(cfile);
! 1275: }
! 1276:
! 1277: /* Parse a lease6 {} construct. The v6 client is a little different
! 1278: * than the v4 client today, in that it only retains one lease, the
! 1279: * active lease, and discards any less recent information. It may
! 1280: * be useful in the future to cache additional information, but it
! 1281: * is not worth the effort for the moment.
! 1282: */
! 1283: static void
! 1284: parse_client6_lease_statement(struct parse *cfile)
! 1285: {
! 1286: #if !defined(DHCPv6)
! 1287: parse_warn(cfile, "No DHCPv6 support.");
! 1288: skip_to_semi(cfile);
! 1289: #else /* defined(DHCPv6) */
! 1290: struct option_cache *oc = NULL;
! 1291: struct dhc6_lease *lease;
! 1292: struct dhc6_ia **ia;
! 1293: struct client_state *client = NULL;
! 1294: struct interface_info *iface = NULL;
! 1295: struct data_string ds;
! 1296: const char *val;
! 1297: unsigned len;
! 1298: int token, has_ia, no_semi, has_name;
! 1299:
! 1300: token = next_token(NULL, NULL, cfile);
! 1301: if (token != LBRACE) {
! 1302: parse_warn(cfile, "Expecting open curly brace.");
! 1303: skip_to_semi(cfile);
! 1304: return;
! 1305: }
! 1306:
! 1307: lease = dmalloc(sizeof(*lease), MDL);
! 1308: if (lease == NULL) {
! 1309: parse_warn(cfile, "Unable to allocate lease state.");
! 1310: skip_to_rbrace(cfile, 1);
! 1311: return;
! 1312: }
! 1313:
! 1314: option_state_allocate(&lease->options, MDL);
! 1315: if (lease->options == NULL) {
! 1316: parse_warn(cfile, "Unable to allocate option cache.");
! 1317: skip_to_rbrace(cfile, 1);
! 1318: dfree(lease, MDL);
! 1319: return;
! 1320: }
! 1321:
! 1322: has_ia = 0;
! 1323: has_name = 0;
! 1324: ia = &lease->bindings;
! 1325: token = next_token(&val, NULL, cfile);
! 1326: while (token != RBRACE) {
! 1327: no_semi = 0;
! 1328:
! 1329: switch(token) {
! 1330: case IA_NA:
! 1331: *ia = parse_client6_ia_na_statement(cfile);
! 1332: if (*ia != NULL) {
! 1333: ia = &(*ia)->next;
! 1334: has_ia = 1;
! 1335: }
! 1336:
! 1337: no_semi = 1;
! 1338:
! 1339: break;
! 1340:
! 1341: case IA_TA:
! 1342: *ia = parse_client6_ia_ta_statement(cfile);
! 1343: if (*ia != NULL) {
! 1344: ia = &(*ia)->next;
! 1345: has_ia = 1;
! 1346: }
! 1347:
! 1348: no_semi = 1;
! 1349:
! 1350: break;
! 1351:
! 1352: case IA_PD:
! 1353: *ia = parse_client6_ia_pd_statement(cfile);
! 1354: if (*ia != NULL) {
! 1355: ia = &(*ia)->next;
! 1356: has_ia = 1;
! 1357: }
! 1358:
! 1359: no_semi = 1;
! 1360:
! 1361: break;
! 1362:
! 1363: case INTERFACE:
! 1364: if (iface != NULL) {
! 1365: parse_warn(cfile, "Multiple interface names?");
! 1366: skip_to_semi(cfile);
! 1367: no_semi = 1;
! 1368: break;
! 1369: }
! 1370:
! 1371: token = next_token(&val, &len, cfile);
! 1372: if (token != STRING) {
! 1373: strerror:
! 1374: parse_warn(cfile, "Expecting a string.");
! 1375: skip_to_semi(cfile);
! 1376: no_semi = 1;
! 1377: break;
! 1378: }
! 1379:
! 1380: for (iface = interfaces ; iface != NULL ;
! 1381: iface = iface->next) {
! 1382: if (strcmp(iface->name, val) == 0)
! 1383: break;
! 1384: }
! 1385:
! 1386: if (iface == NULL) {
! 1387: parse_warn(cfile, "Unknown interface.");
! 1388: break;
! 1389: }
! 1390:
! 1391: break;
! 1392:
! 1393: case NAME:
! 1394: has_name = 1;
! 1395:
! 1396: if (client != NULL) {
! 1397: parse_warn(cfile, "Multiple state names?");
! 1398: skip_to_semi(cfile);
! 1399: no_semi = 1;
! 1400: break;
! 1401: }
! 1402:
! 1403: if (iface == NULL) {
! 1404: parse_warn(cfile, "Client name without "
! 1405: "interface.");
! 1406: skip_to_semi(cfile);
! 1407: no_semi = 1;
! 1408: break;
! 1409: }
! 1410:
! 1411: token = next_token(&val, &len, cfile);
! 1412: if (token != STRING)
! 1413: goto strerror;
! 1414:
! 1415: for (client = iface->client ; client != NULL ;
! 1416: client = client->next) {
! 1417: if ((client->name != NULL) &&
! 1418: (strcmp(client->name, val) == 0))
! 1419: break;
! 1420: }
! 1421:
! 1422: if (client == NULL) {
! 1423: parse_warn(cfile, "Unknown client state %s.",
! 1424: val);
! 1425: break;
! 1426: }
! 1427:
! 1428: break;
! 1429:
! 1430: case OPTION:
! 1431: if (parse_option_decl(&oc, cfile)) {
! 1432: save_option(oc->option->universe,
! 1433: lease->options, oc);
! 1434: option_cache_dereference(&oc, MDL);
! 1435: }
! 1436: no_semi = 1;
! 1437: break;
! 1438:
! 1439: case TOKEN_RELEASED:
! 1440: case TOKEN_ABANDONED:
! 1441: lease->released = ISC_TRUE;
! 1442: break;
! 1443:
! 1444: default:
! 1445: parse_warn(cfile, "Unexpected token, %s.", val);
! 1446: no_semi = 1;
! 1447: skip_to_semi(cfile);
! 1448: break;
! 1449: }
! 1450:
! 1451: if (!no_semi)
! 1452: parse_semi(cfile);
! 1453:
! 1454: token = next_token(&val, NULL, cfile);
! 1455:
! 1456: if (token == END_OF_FILE) {
! 1457: parse_warn(cfile, "Unexpected end of file.");
! 1458: break;
! 1459: }
! 1460: }
! 1461:
! 1462: if (!has_ia) {
! 1463: log_debug("Lease with no IA's discarded from lease db.");
! 1464: dhc6_lease_destroy(&lease, MDL);
! 1465: return;
! 1466: }
! 1467:
! 1468: if (iface == NULL)
! 1469: parse_warn(cfile, "Lease has no interface designation.");
! 1470: else if (!has_name && (client == NULL)) {
! 1471: for (client = iface->client ; client != NULL ;
! 1472: client = client->next) {
! 1473: if (client->name == NULL)
! 1474: break;
! 1475: }
! 1476: }
! 1477:
! 1478: if (client == NULL) {
! 1479: parse_warn(cfile, "No matching client state.");
! 1480: dhc6_lease_destroy(&lease, MDL);
! 1481: return;
! 1482: }
! 1483:
! 1484: /* Fetch Preference option from option cache. */
! 1485: memset(&ds, 0, sizeof(ds));
! 1486: oc = lookup_option(&dhcpv6_universe, lease->options, D6O_PREFERENCE);
! 1487: if ((oc != NULL) &&
! 1488: evaluate_option_cache(&ds, NULL, NULL, NULL, lease->options,
! 1489: NULL, &global_scope, oc, MDL)) {
! 1490: if (ds.len != 1) {
! 1491: log_error("Invalid length of DHCPv6 Preference option "
! 1492: "(%d != 1)", ds.len);
! 1493: data_string_forget(&ds, MDL);
! 1494: dhc6_lease_destroy(&lease, MDL);
! 1495: return;
! 1496: } else
! 1497: lease->pref = ds.data[0];
! 1498:
! 1499: data_string_forget(&ds, MDL);
! 1500: }
! 1501:
! 1502: /* Fetch server-id option from option cache. */
! 1503: oc = lookup_option(&dhcpv6_universe, lease->options, D6O_SERVERID);
! 1504: if ((oc == NULL) ||
! 1505: !evaluate_option_cache(&lease->server_id, NULL, NULL, NULL,
! 1506: lease->options, NULL, &global_scope, oc,
! 1507: MDL) ||
! 1508: (lease->server_id.len == 0)) {
! 1509: /* This should be impossible... */
! 1510: log_error("Invalid SERVERID option cache.");
! 1511: dhc6_lease_destroy(&lease, MDL);
! 1512: return;
! 1513: }
! 1514:
! 1515: if (client->active_lease != NULL)
! 1516: dhc6_lease_destroy(&client->active_lease, MDL);
! 1517:
! 1518: client->active_lease = lease;
! 1519: #endif /* defined(DHCPv6) */
! 1520: }
! 1521:
! 1522: /* Parse an ia_na object from the client lease.
! 1523: */
! 1524: #ifdef DHCPv6
! 1525: static struct dhc6_ia *
! 1526: parse_client6_ia_na_statement(struct parse *cfile)
! 1527: {
! 1528: struct option_cache *oc = NULL;
! 1529: struct dhc6_ia *ia;
! 1530: struct dhc6_addr **addr;
! 1531: const char *val;
! 1532: int token, no_semi, len;
! 1533: u_int8_t buf[5];
! 1534:
! 1535: ia = dmalloc(sizeof(*ia), MDL);
! 1536: if (ia == NULL) {
! 1537: parse_warn(cfile, "Out of memory allocating IA_NA state.");
! 1538: skip_to_semi(cfile);
! 1539: return NULL;
! 1540: }
! 1541: ia->ia_type = D6O_IA_NA;
! 1542:
! 1543: /* Get IAID. */
! 1544: len = parse_X(cfile, buf, 5);
! 1545: if (len == 4) {
! 1546: memcpy(ia->iaid, buf, 4);
! 1547: } else {
! 1548: parse_warn(cfile, "Expecting IAID of length 4, got %d.", len);
! 1549: skip_to_semi(cfile);
! 1550: dfree(ia, MDL);
! 1551: return NULL;
! 1552: }
! 1553:
! 1554: token = next_token(NULL, NULL, cfile);
! 1555: if (token != LBRACE) {
! 1556: parse_warn(cfile, "Expecting open curly brace.");
! 1557: skip_to_semi(cfile);
! 1558: dfree(ia, MDL);
! 1559: return NULL;
! 1560: }
! 1561:
! 1562: option_state_allocate(&ia->options, MDL);
! 1563: if (ia->options == NULL) {
! 1564: parse_warn(cfile, "Unable to allocate option state.");
! 1565: skip_to_rbrace(cfile, 1);
! 1566: dfree(ia, MDL);
! 1567: return NULL;
! 1568: }
! 1569:
! 1570: addr = &ia->addrs;
! 1571: token = next_token(&val, NULL, cfile);
! 1572: while (token != RBRACE) {
! 1573: no_semi = 0;
! 1574:
! 1575: switch (token) {
! 1576: case STARTS:
! 1577: token = next_token(&val, NULL, cfile);
! 1578: if (token == NUMBER) {
! 1579: ia->starts = atoi(val);
! 1580: } else {
! 1581: parse_warn(cfile, "Expecting a number.");
! 1582: skip_to_semi(cfile);
! 1583: no_semi = 1;
! 1584: }
! 1585: break;
! 1586:
! 1587: case RENEW:
! 1588: token = next_token(&val, NULL, cfile);
! 1589: if (token == NUMBER) {
! 1590: ia->renew = atoi(val);
! 1591: } else {
! 1592: parse_warn(cfile, "Expecting a number.");
! 1593: skip_to_semi(cfile);
! 1594: no_semi = 1;
! 1595: }
! 1596: break;
! 1597:
! 1598: case REBIND:
! 1599: token = next_token(&val, NULL, cfile);
! 1600: if (token == NUMBER) {
! 1601: ia->rebind = atoi(val);
! 1602: } else {
! 1603: parse_warn(cfile, "Expecting a number.");
! 1604: skip_to_semi(cfile);
! 1605: no_semi = 1;
! 1606: }
! 1607: break;
! 1608:
! 1609: case IAADDR:
! 1610: *addr = parse_client6_iaaddr_statement(cfile);
! 1611:
! 1612: if (*addr != NULL)
! 1613: addr = &(*addr)->next;
! 1614:
! 1615: no_semi = 1;
! 1616:
! 1617: break;
! 1618:
! 1619: case OPTION:
! 1620: if (parse_option_decl(&oc, cfile)) {
! 1621: save_option(oc->option->universe,
! 1622: ia->options, oc);
! 1623: option_cache_dereference(&oc, MDL);
! 1624: }
! 1625: no_semi = 1;
! 1626: break;
! 1627:
! 1628: default:
! 1629: parse_warn(cfile, "Unexpected token.");
! 1630: no_semi = 1;
! 1631: skip_to_semi(cfile);
! 1632: break;
! 1633: }
! 1634:
! 1635: if (!no_semi)
! 1636: parse_semi(cfile);
! 1637:
! 1638: token = next_token(&val, NULL, cfile);
! 1639:
! 1640: if (token == END_OF_FILE) {
! 1641: parse_warn(cfile, "Unexpected end of file.");
! 1642: break;
! 1643: }
! 1644: }
! 1645:
! 1646: return ia;
! 1647: }
! 1648: #endif /* DHCPv6 */
! 1649:
! 1650: /* Parse an ia_ta object from the client lease.
! 1651: */
! 1652: #ifdef DHCPv6
! 1653: static struct dhc6_ia *
! 1654: parse_client6_ia_ta_statement(struct parse *cfile)
! 1655: {
! 1656: struct option_cache *oc = NULL;
! 1657: struct dhc6_ia *ia;
! 1658: struct dhc6_addr **addr;
! 1659: const char *val;
! 1660: int token, no_semi, len;
! 1661: u_int8_t buf[5];
! 1662:
! 1663: ia = dmalloc(sizeof(*ia), MDL);
! 1664: if (ia == NULL) {
! 1665: parse_warn(cfile, "Out of memory allocating IA_TA state.");
! 1666: skip_to_semi(cfile);
! 1667: return NULL;
! 1668: }
! 1669: ia->ia_type = D6O_IA_TA;
! 1670:
! 1671: /* Get IAID. */
! 1672: len = parse_X(cfile, buf, 5);
! 1673: if (len == 4) {
! 1674: memcpy(ia->iaid, buf, 4);
! 1675: } else {
! 1676: parse_warn(cfile, "Expecting IAID of length 4, got %d.", len);
! 1677: skip_to_semi(cfile);
! 1678: dfree(ia, MDL);
! 1679: return NULL;
! 1680: }
! 1681:
! 1682: token = next_token(NULL, NULL, cfile);
! 1683: if (token != LBRACE) {
! 1684: parse_warn(cfile, "Expecting open curly brace.");
! 1685: skip_to_semi(cfile);
! 1686: dfree(ia, MDL);
! 1687: return NULL;
! 1688: }
! 1689:
! 1690: option_state_allocate(&ia->options, MDL);
! 1691: if (ia->options == NULL) {
! 1692: parse_warn(cfile, "Unable to allocate option state.");
! 1693: skip_to_rbrace(cfile, 1);
! 1694: dfree(ia, MDL);
! 1695: return NULL;
! 1696: }
! 1697:
! 1698: addr = &ia->addrs;
! 1699: token = next_token(&val, NULL, cfile);
! 1700: while (token != RBRACE) {
! 1701: no_semi = 0;
! 1702:
! 1703: switch (token) {
! 1704: case STARTS:
! 1705: token = next_token(&val, NULL, cfile);
! 1706: if (token == NUMBER) {
! 1707: ia->starts = atoi(val);
! 1708: } else {
! 1709: parse_warn(cfile, "Expecting a number.");
! 1710: skip_to_semi(cfile);
! 1711: no_semi = 1;
! 1712: }
! 1713: break;
! 1714:
! 1715: /* No RENEW or REBIND */
! 1716:
! 1717: case IAADDR:
! 1718: *addr = parse_client6_iaaddr_statement(cfile);
! 1719:
! 1720: if (*addr != NULL)
! 1721: addr = &(*addr)->next;
! 1722:
! 1723: no_semi = 1;
! 1724:
! 1725: break;
! 1726:
! 1727: case OPTION:
! 1728: if (parse_option_decl(&oc, cfile)) {
! 1729: save_option(oc->option->universe,
! 1730: ia->options, oc);
! 1731: option_cache_dereference(&oc, MDL);
! 1732: }
! 1733: no_semi = 1;
! 1734: break;
! 1735:
! 1736: default:
! 1737: parse_warn(cfile, "Unexpected token.");
! 1738: no_semi = 1;
! 1739: skip_to_semi(cfile);
! 1740: break;
! 1741: }
! 1742:
! 1743: if (!no_semi)
! 1744: parse_semi(cfile);
! 1745:
! 1746: token = next_token(&val, NULL, cfile);
! 1747:
! 1748: if (token == END_OF_FILE) {
! 1749: parse_warn(cfile, "Unexpected end of file.");
! 1750: break;
! 1751: }
! 1752: }
! 1753:
! 1754: return ia;
! 1755: }
! 1756: #endif /* DHCPv6 */
! 1757:
! 1758: /* Parse an ia_pd object from the client lease.
! 1759: */
! 1760: #ifdef DHCPv6
! 1761: static struct dhc6_ia *
! 1762: parse_client6_ia_pd_statement(struct parse *cfile)
! 1763: {
! 1764: struct option_cache *oc = NULL;
! 1765: struct dhc6_ia *ia;
! 1766: struct dhc6_addr **pref;
! 1767: const char *val;
! 1768: int token, no_semi, len;
! 1769: u_int8_t buf[5];
! 1770:
! 1771: ia = dmalloc(sizeof(*ia), MDL);
! 1772: if (ia == NULL) {
! 1773: parse_warn(cfile, "Out of memory allocating IA_PD state.");
! 1774: skip_to_semi(cfile);
! 1775: return NULL;
! 1776: }
! 1777: ia->ia_type = D6O_IA_PD;
! 1778:
! 1779: /* Get IAID. */
! 1780: len = parse_X(cfile, buf, 5);
! 1781: if (len == 4) {
! 1782: memcpy(ia->iaid, buf, 4);
! 1783: } else {
! 1784: parse_warn(cfile, "Expecting IAID of length 4, got %d.", len);
! 1785: skip_to_semi(cfile);
! 1786: dfree(ia, MDL);
! 1787: return NULL;
! 1788: }
! 1789:
! 1790: token = next_token(NULL, NULL, cfile);
! 1791: if (token != LBRACE) {
! 1792: parse_warn(cfile, "Expecting open curly brace.");
! 1793: skip_to_semi(cfile);
! 1794: dfree(ia, MDL);
! 1795: return NULL;
! 1796: }
! 1797:
! 1798: option_state_allocate(&ia->options, MDL);
! 1799: if (ia->options == NULL) {
! 1800: parse_warn(cfile, "Unable to allocate option state.");
! 1801: skip_to_rbrace(cfile, 1);
! 1802: dfree(ia, MDL);
! 1803: return NULL;
! 1804: }
! 1805:
! 1806: pref = &ia->addrs;
! 1807: token = next_token(&val, NULL, cfile);
! 1808: while (token != RBRACE) {
! 1809: no_semi = 0;
! 1810:
! 1811: switch (token) {
! 1812: case STARTS:
! 1813: token = next_token(&val, NULL, cfile);
! 1814: if (token == NUMBER) {
! 1815: ia->starts = atoi(val);
! 1816: } else {
! 1817: parse_warn(cfile, "Expecting a number.");
! 1818: skip_to_semi(cfile);
! 1819: no_semi = 1;
! 1820: }
! 1821: break;
! 1822:
! 1823: case RENEW:
! 1824: token = next_token(&val, NULL, cfile);
! 1825: if (token == NUMBER) {
! 1826: ia->renew = atoi(val);
! 1827: } else {
! 1828: parse_warn(cfile, "Expecting a number.");
! 1829: skip_to_semi(cfile);
! 1830: no_semi = 1;
! 1831: }
! 1832: break;
! 1833:
! 1834: case REBIND:
! 1835: token = next_token(&val, NULL, cfile);
! 1836: if (token == NUMBER) {
! 1837: ia->rebind = atoi(val);
! 1838: } else {
! 1839: parse_warn(cfile, "Expecting a number.");
! 1840: skip_to_semi(cfile);
! 1841: no_semi = 1;
! 1842: }
! 1843: break;
! 1844:
! 1845: case IAPREFIX:
! 1846: *pref = parse_client6_iaprefix_statement(cfile);
! 1847:
! 1848: if (*pref != NULL)
! 1849: pref = &(*pref)->next;
! 1850:
! 1851: no_semi = 1;
! 1852:
! 1853: break;
! 1854:
! 1855: case OPTION:
! 1856: if (parse_option_decl(&oc, cfile)) {
! 1857: save_option(oc->option->universe,
! 1858: ia->options, oc);
! 1859: option_cache_dereference(&oc, MDL);
! 1860: }
! 1861: no_semi = 1;
! 1862: break;
! 1863:
! 1864: default:
! 1865: parse_warn(cfile, "Unexpected token.");
! 1866: no_semi = 1;
! 1867: skip_to_semi(cfile);
! 1868: break;
! 1869: }
! 1870:
! 1871: if (!no_semi)
! 1872: parse_semi(cfile);
! 1873:
! 1874: token = next_token(&val, NULL, cfile);
! 1875:
! 1876: if (token == END_OF_FILE) {
! 1877: parse_warn(cfile, "Unexpected end of file.");
! 1878: break;
! 1879: }
! 1880: }
! 1881:
! 1882: return ia;
! 1883: }
! 1884: #endif /* DHCPv6 */
! 1885:
! 1886: /* Parse an iaaddr {} structure. */
! 1887: #ifdef DHCPv6
! 1888: static struct dhc6_addr *
! 1889: parse_client6_iaaddr_statement(struct parse *cfile)
! 1890: {
! 1891: struct option_cache *oc = NULL;
! 1892: struct dhc6_addr *addr;
! 1893: const char *val;
! 1894: int token, no_semi;
! 1895:
! 1896: addr = dmalloc(sizeof(*addr), MDL);
! 1897: if (addr == NULL) {
! 1898: parse_warn(cfile, "Unable to allocate IAADDR state.");
! 1899: skip_to_semi(cfile);
! 1900: return NULL;
! 1901: }
! 1902:
! 1903: /* Get IP address. */
! 1904: if (!parse_ip6_addr(cfile, &addr->address)) {
! 1905: skip_to_semi(cfile);
! 1906: dfree(addr, MDL);
! 1907: return NULL;
! 1908: }
! 1909:
! 1910: token = next_token(NULL, NULL, cfile);
! 1911: if (token != LBRACE) {
! 1912: parse_warn(cfile, "Expecting open curly bracket.");
! 1913: skip_to_semi(cfile);
! 1914: dfree(addr, MDL);
! 1915: return NULL;
! 1916: }
! 1917:
! 1918: option_state_allocate(&addr->options, MDL);
! 1919: if (addr->options == NULL) {
! 1920: parse_warn(cfile, "Unable to allocate option state.");
! 1921: skip_to_semi(cfile);
! 1922: dfree(addr, MDL);
! 1923: return NULL;
! 1924: }
! 1925:
! 1926: token = next_token(&val, NULL, cfile);
! 1927: while (token != RBRACE) {
! 1928: no_semi = 0;
! 1929:
! 1930: switch (token) {
! 1931: case STARTS:
! 1932: token = next_token(&val, NULL, cfile);
! 1933: if (token == NUMBER) {
! 1934: addr->starts = atoi(val);
! 1935: } else {
! 1936: parse_warn(cfile, "Expecting a number.");
! 1937: skip_to_semi(cfile);
! 1938: no_semi = 1;
! 1939: }
! 1940: break;
! 1941:
! 1942: case PREFERRED_LIFE:
! 1943: token = next_token(&val, NULL, cfile);
! 1944: if (token == NUMBER) {
! 1945: addr->preferred_life = atoi(val);
! 1946: } else {
! 1947: parse_warn(cfile, "Expecting a number.");
! 1948: skip_to_semi(cfile);
! 1949: no_semi = 1;
! 1950: }
! 1951: break;
! 1952:
! 1953: case MAX_LIFE:
! 1954: token = next_token(&val, NULL, cfile);
! 1955: if (token == NUMBER) {
! 1956: addr->max_life = atoi(val);
! 1957: } else {
! 1958: parse_warn(cfile, "Expecting a number.");
! 1959: skip_to_semi(cfile);
! 1960: no_semi = 1;
! 1961: }
! 1962: break;
! 1963:
! 1964: case OPTION:
! 1965: if (parse_option_decl(&oc, cfile)) {
! 1966: save_option(oc->option->universe,
! 1967: addr->options, oc);
! 1968: option_cache_dereference(&oc, MDL);
! 1969: }
! 1970: no_semi = 1;
! 1971: break;
! 1972:
! 1973: default:
! 1974: parse_warn(cfile, "Unexpected token.");
! 1975: skip_to_rbrace(cfile, 1);
! 1976: no_semi = 1;
! 1977: break;
! 1978: }
! 1979:
! 1980: if (!no_semi)
! 1981: parse_semi(cfile);
! 1982:
! 1983: token = next_token(&val, NULL, cfile);
! 1984: if (token == END_OF_FILE) {
! 1985: parse_warn(cfile, "Unexpected end of file.");
! 1986: break;
! 1987: }
! 1988: }
! 1989:
! 1990: return addr;
! 1991: }
! 1992: #endif /* DHCPv6 */
! 1993:
! 1994: /* Parse an iaprefix {} structure. */
! 1995: #ifdef DHCPv6
! 1996: static struct dhc6_addr *
! 1997: parse_client6_iaprefix_statement(struct parse *cfile)
! 1998: {
! 1999: struct option_cache *oc = NULL;
! 2000: struct dhc6_addr *pref;
! 2001: const char *val;
! 2002: int token, no_semi;
! 2003:
! 2004: pref = dmalloc(sizeof(*pref), MDL);
! 2005: if (pref == NULL) {
! 2006: parse_warn(cfile, "Unable to allocate IAPREFIX state.");
! 2007: skip_to_semi(cfile);
! 2008: return NULL;
! 2009: }
! 2010:
! 2011: /* Get IP prefix. */
! 2012: if (!parse_ip6_prefix(cfile, &pref->address, &pref->plen)) {
! 2013: skip_to_semi(cfile);
! 2014: dfree(pref, MDL);
! 2015: return NULL;
! 2016: }
! 2017:
! 2018: token = next_token(NULL, NULL, cfile);
! 2019: if (token != LBRACE) {
! 2020: parse_warn(cfile, "Expecting open curly bracket.");
! 2021: skip_to_semi(cfile);
! 2022: dfree(pref, MDL);
! 2023: return NULL;
! 2024: }
! 2025:
! 2026: option_state_allocate(&pref->options, MDL);
! 2027: if (pref->options == NULL) {
! 2028: parse_warn(cfile, "Unable to allocate option state.");
! 2029: skip_to_semi(cfile);
! 2030: dfree(pref, MDL);
! 2031: return NULL;
! 2032: }
! 2033:
! 2034: token = next_token(&val, NULL, cfile);
! 2035: while (token != RBRACE) {
! 2036: no_semi = 0;
! 2037:
! 2038: switch (token) {
! 2039: case STARTS:
! 2040: token = next_token(&val, NULL, cfile);
! 2041: if (token == NUMBER) {
! 2042: pref->starts = atoi(val);
! 2043: } else {
! 2044: parse_warn(cfile, "Expecting a number.");
! 2045: skip_to_semi(cfile);
! 2046: no_semi = 1;
! 2047: }
! 2048: break;
! 2049:
! 2050: case PREFERRED_LIFE:
! 2051: token = next_token(&val, NULL, cfile);
! 2052: if (token == NUMBER) {
! 2053: pref->preferred_life = atoi(val);
! 2054: } else {
! 2055: parse_warn(cfile, "Expecting a number.");
! 2056: skip_to_semi(cfile);
! 2057: no_semi = 1;
! 2058: }
! 2059: break;
! 2060:
! 2061: case MAX_LIFE:
! 2062: token = next_token(&val, NULL, cfile);
! 2063: if (token == NUMBER) {
! 2064: pref->max_life = atoi(val);
! 2065: } else {
! 2066: parse_warn(cfile, "Expecting a number.");
! 2067: skip_to_semi(cfile);
! 2068: no_semi = 1;
! 2069: }
! 2070: break;
! 2071:
! 2072: case OPTION:
! 2073: if (parse_option_decl(&oc, cfile)) {
! 2074: save_option(oc->option->universe,
! 2075: pref->options, oc);
! 2076: option_cache_dereference(&oc, MDL);
! 2077: }
! 2078: no_semi = 1;
! 2079: break;
! 2080:
! 2081: default:
! 2082: parse_warn(cfile, "Unexpected token.");
! 2083: skip_to_rbrace(cfile, 1);
! 2084: no_semi = 1;
! 2085: break;
! 2086: }
! 2087:
! 2088: if (!no_semi)
! 2089: parse_semi(cfile);
! 2090:
! 2091: token = next_token(&val, NULL, cfile);
! 2092: if (token == END_OF_FILE) {
! 2093: parse_warn(cfile, "Unexpected end of file.");
! 2094: break;
! 2095: }
! 2096: }
! 2097:
! 2098: return pref;
! 2099: }
! 2100: #endif /* DHCPv6 */
! 2101:
! 2102: void parse_string_list (cfile, lp, multiple)
! 2103: struct parse *cfile;
! 2104: struct string_list **lp;
! 2105: int multiple;
! 2106: {
! 2107: int token;
! 2108: const char *val;
! 2109: struct string_list *cur, *tmp;
! 2110:
! 2111: /* Find the last medium in the media list. */
! 2112: if (*lp) {
! 2113: for (cur = *lp; cur -> next; cur = cur -> next)
! 2114: ;
! 2115: } else {
! 2116: cur = (struct string_list *)0;
! 2117: }
! 2118:
! 2119: do {
! 2120: token = next_token (&val, (unsigned *)0, cfile);
! 2121: if (token != STRING) {
! 2122: parse_warn (cfile, "Expecting media options.");
! 2123: skip_to_semi (cfile);
! 2124: return;
! 2125: }
! 2126:
! 2127: tmp = ((struct string_list *)
! 2128: dmalloc (strlen (val) + sizeof (struct string_list),
! 2129: MDL));
! 2130: if (!tmp)
! 2131: log_fatal ("no memory for string list entry.");
! 2132:
! 2133: strcpy (tmp -> string, val);
! 2134: tmp -> next = (struct string_list *)0;
! 2135:
! 2136: /* Store this medium at the end of the media list. */
! 2137: if (cur)
! 2138: cur -> next = tmp;
! 2139: else
! 2140: *lp = tmp;
! 2141: cur = tmp;
! 2142:
! 2143: token = next_token (&val, (unsigned *)0, cfile);
! 2144: } while (multiple && token == COMMA);
! 2145:
! 2146: if (token != SEMI) {
! 2147: parse_warn (cfile, "expecting semicolon.");
! 2148: skip_to_semi (cfile);
! 2149: }
! 2150: }
! 2151:
! 2152: void parse_reject_statement (cfile, config)
! 2153: struct parse *cfile;
! 2154: struct client_config *config;
! 2155: {
! 2156: int token;
! 2157: const char *val;
! 2158: struct iaddrmatch match;
! 2159: struct iaddrmatchlist *list;
! 2160: int i;
! 2161:
! 2162: do {
! 2163: if (!parse_ip_addr_with_subnet (cfile, &match)) {
! 2164: /* no warn: parser will have reported what's wrong */
! 2165: skip_to_semi (cfile);
! 2166: return;
! 2167: }
! 2168:
! 2169: /* check mask is not all zeros (because that would
! 2170: * reject EVERY address). This check could be
! 2171: * simplified if we assume that the mask *always*
! 2172: * represents a prefix .. but perhaps it might be
! 2173: * useful to have a mask which is not a proper prefix
! 2174: * (perhaps for ipv6?). The following is almost as
! 2175: * efficient as inspection of match.mask.iabuf[0] when
! 2176: * it IS a true prefix, and is more general when it is
! 2177: * not.
! 2178: */
! 2179:
! 2180: for (i=0 ; i < match.mask.len ; i++) {
! 2181: if (match.mask.iabuf[i]) {
! 2182: break;
! 2183: }
! 2184: }
! 2185:
! 2186: if (i == match.mask.len) {
! 2187: /* oops we found all zeros */
! 2188: parse_warn(cfile, "zero-length prefix is not permitted "
! 2189: "for reject statement");
! 2190: skip_to_semi(cfile);
! 2191: return;
! 2192: }
! 2193:
! 2194: list = dmalloc(sizeof(struct iaddrmatchlist), MDL);
! 2195: if (!list)
! 2196: log_fatal ("no memory for reject list!");
! 2197:
! 2198: list->match = match;
! 2199: list->next = config->reject_list;
! 2200: config->reject_list = list;
! 2201:
! 2202: token = next_token (&val, (unsigned *)0, cfile);
! 2203: } while (token == COMMA);
! 2204:
! 2205: if (token != SEMI) {
! 2206: parse_warn (cfile, "expecting semicolon.");
! 2207: skip_to_semi (cfile);
! 2208: }
! 2209: }
! 2210:
! 2211: /* allow-deny-keyword :== BOOTP
! 2212: | BOOTING
! 2213: | DYNAMIC_BOOTP
! 2214: | UNKNOWN_CLIENTS */
! 2215:
! 2216: int parse_allow_deny (oc, cfile, flag)
! 2217: struct option_cache **oc;
! 2218: struct parse *cfile;
! 2219: int flag;
! 2220: {
! 2221: parse_warn (cfile, "allow/deny/ignore not permitted here.");
! 2222: skip_to_semi (cfile);
! 2223: return 0;
! 2224: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>