Annotation of embedaddon/dhcp/server/confpars.c, revision 1.1
1.1 ! misho 1: /* confpars.c
! 2:
! 3: Parser for dhcpd config file... */
! 4:
! 5: /*
! 6: * Copyright (c) 2004-2010 by Internet Systems Consortium, Inc. ("ISC")
! 7: * Copyright (c) 1995-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:
! 37: static unsigned char global_host_once = 1;
! 38: static unsigned char dhcpv6_class_once = 1;
! 39:
! 40: static int parse_binding_value(struct parse *cfile,
! 41: struct binding_value *value);
! 42:
! 43: #if defined (TRACING)
! 44: trace_type_t *trace_readconf_type;
! 45: trace_type_t *trace_readleases_type;
! 46:
! 47: void parse_trace_setup ()
! 48: {
! 49: trace_readconf_type = trace_type_register ("readconf", (void *)0,
! 50: trace_conf_input,
! 51: trace_conf_stop, MDL);
! 52: trace_readleases_type = trace_type_register ("readleases", (void *)0,
! 53: trace_conf_input,
! 54: trace_conf_stop, MDL);
! 55: }
! 56: #endif
! 57:
! 58: /* conf-file :== parameters declarations END_OF_FILE
! 59: parameters :== <nil> | parameter | parameters parameter
! 60: declarations :== <nil> | declaration | declarations declaration */
! 61:
! 62: isc_result_t readconf ()
! 63: {
! 64: return read_conf_file (path_dhcpd_conf, root_group, ROOT_GROUP, 0);
! 65: }
! 66:
! 67: isc_result_t read_conf_file (const char *filename, struct group *group,
! 68: int group_type, int leasep)
! 69: {
! 70: int file;
! 71: struct parse *cfile;
! 72: isc_result_t status;
! 73: #if defined (TRACING)
! 74: char *fbuf, *dbuf;
! 75: off_t flen;
! 76: int result;
! 77: unsigned tflen, ulen;
! 78: trace_type_t *ttype;
! 79:
! 80: if (leasep)
! 81: ttype = trace_readleases_type;
! 82: else
! 83: ttype = trace_readconf_type;
! 84:
! 85: /* If we're in playback, we need to snarf the contents of the
! 86: named file out of the playback file rather than trying to
! 87: open and read it. */
! 88: if (trace_playback ()) {
! 89: dbuf = (char *)0;
! 90: tflen = 0;
! 91: status = trace_get_file (ttype, filename, &tflen, &dbuf);
! 92: if (status != ISC_R_SUCCESS)
! 93: return status;
! 94: ulen = tflen;
! 95:
! 96: /* What we get back is filename\0contents, where contents is
! 97: terminated just by the length. So we figure out the length
! 98: of the filename, and subtract that and the NUL from the
! 99: total length to get the length of the contents of the file.
! 100: We make fbuf a pointer to the contents of the file, and
! 101: leave dbuf as it is so we can free it later. */
! 102: tflen = strlen (dbuf);
! 103: ulen = ulen - tflen - 1;
! 104: fbuf = dbuf + tflen + 1;
! 105: goto memfile;
! 106: }
! 107: #endif
! 108:
! 109: if ((file = open (filename, O_RDONLY)) < 0) {
! 110: if (leasep) {
! 111: log_error ("Can't open lease database %s: %m --",
! 112: path_dhcpd_db);
! 113: log_error (" check for failed database %s!",
! 114: "rewrite attempt");
! 115: log_error ("Please read the dhcpd.leases manual%s",
! 116: " page if you");
! 117: log_fatal ("don't know what to do about this.");
! 118: } else {
! 119: log_fatal ("Can't open %s: %m", filename);
! 120: }
! 121: }
! 122:
! 123: cfile = (struct parse *)0;
! 124: #if defined (TRACING)
! 125: flen = lseek (file, (off_t)0, SEEK_END);
! 126: if (flen < 0) {
! 127: boom:
! 128: log_fatal ("Can't lseek on %s: %m", filename);
! 129: }
! 130: if (lseek (file, (off_t)0, SEEK_SET) < 0)
! 131: goto boom;
! 132: /* Can't handle files greater than 2^31-1. */
! 133: if (flen > 0x7FFFFFFFUL)
! 134: log_fatal ("%s: file is too long to buffer.", filename);
! 135: ulen = flen;
! 136:
! 137: /* Allocate a buffer that will be what's written to the tracefile,
! 138: and also will be what we parse from. */
! 139: tflen = strlen (filename);
! 140: dbuf = dmalloc (ulen + tflen + 1, MDL);
! 141: if (!dbuf)
! 142: log_fatal ("No memory for %s (%d bytes)",
! 143: filename, ulen);
! 144:
! 145: /* Copy the name into the beginning, nul-terminated. */
! 146: strcpy (dbuf, filename);
! 147:
! 148: /* Load the file in after the NUL. */
! 149: fbuf = dbuf + tflen + 1;
! 150: result = read (file, fbuf, ulen);
! 151: if (result < 0)
! 152: log_fatal ("Can't read in %s: %m", filename);
! 153: if (result != ulen)
! 154: log_fatal ("%s: short read of %d bytes instead of %d.",
! 155: filename, ulen, result);
! 156: close (file);
! 157: memfile:
! 158: /* If we're recording, write out the filename and file contents. */
! 159: if (trace_record ())
! 160: trace_write_packet (ttype, ulen + tflen + 1, dbuf, MDL);
! 161: status = new_parse(&cfile, -1, fbuf, ulen, filename, 0); /* XXX */
! 162: #else
! 163: status = new_parse(&cfile, file, NULL, 0, filename, 0);
! 164: #endif
! 165: if (status != ISC_R_SUCCESS || cfile == NULL)
! 166: return status;
! 167:
! 168: if (leasep)
! 169: status = lease_file_subparse (cfile);
! 170: else
! 171: status = conf_file_subparse (cfile, group, group_type);
! 172: end_parse (&cfile);
! 173: #if defined (TRACING)
! 174: dfree (dbuf, MDL);
! 175: #endif
! 176: return status;
! 177: }
! 178:
! 179: #if defined (TRACING)
! 180: void trace_conf_input (trace_type_t *ttype, unsigned len, char *data)
! 181: {
! 182: char *fbuf;
! 183: unsigned flen;
! 184: unsigned tflen;
! 185: struct parse *cfile = (struct parse *)0;
! 186: static int postconf_initialized;
! 187: static int leaseconf_initialized;
! 188: isc_result_t status;
! 189:
! 190: /* Do what's done above, except that we don't have to read in the
! 191: data, because it's already been read for us. */
! 192: tflen = strlen (data);
! 193: flen = len - tflen - 1;
! 194: fbuf = data + tflen + 1;
! 195:
! 196: /* If we're recording, write out the filename and file contents. */
! 197: if (trace_record ())
! 198: trace_write_packet (ttype, len, data, MDL);
! 199:
! 200: status = new_parse(&cfile, -1, fbuf, flen, data, 0);
! 201: if (status == ISC_R_SUCCESS || cfile != NULL) {
! 202: if (ttype == trace_readleases_type)
! 203: lease_file_subparse (cfile);
! 204: else
! 205: conf_file_subparse (cfile, root_group, ROOT_GROUP);
! 206: end_parse (&cfile);
! 207: }
! 208:
! 209: /* Postconfiguration needs to be done after the config file
! 210: has been loaded. */
! 211: if (!postconf_initialized && ttype == trace_readconf_type) {
! 212: postconf_initialization (0);
! 213: postconf_initialized = 1;
! 214: }
! 215:
! 216: if (!leaseconf_initialized && ttype == trace_readleases_type) {
! 217: db_startup (0);
! 218: leaseconf_initialized = 1;
! 219: postdb_startup ();
! 220: }
! 221: }
! 222:
! 223: void trace_conf_stop (trace_type_t *ttype) { }
! 224: #endif
! 225:
! 226: /* conf-file :== parameters declarations END_OF_FILE
! 227: parameters :== <nil> | parameter | parameters parameter
! 228: declarations :== <nil> | declaration | declarations declaration */
! 229:
! 230: isc_result_t conf_file_subparse (struct parse *cfile, struct group *group,
! 231: int group_type)
! 232: {
! 233: const char *val;
! 234: enum dhcp_token token;
! 235: int declaration = 0;
! 236: int status;
! 237:
! 238: do {
! 239: token = peek_token (&val, (unsigned *)0, cfile);
! 240: if (token == END_OF_FILE)
! 241: break;
! 242: declaration = parse_statement (cfile, group, group_type,
! 243: (struct host_decl *)0,
! 244: declaration);
! 245: } while (1);
! 246: token = next_token (&val, (unsigned *)0, cfile);
! 247:
! 248: status = cfile -> warnings_occurred ? ISC_R_BADPARSE : ISC_R_SUCCESS;
! 249: return status;
! 250: }
! 251:
! 252: /* lease-file :== lease-declarations END_OF_FILE
! 253: lease-statements :== <nil>
! 254: | lease-declaration
! 255: | lease-declarations lease-declaration */
! 256:
! 257: isc_result_t lease_file_subparse (struct parse *cfile)
! 258: {
! 259: const char *val;
! 260: enum dhcp_token token;
! 261: isc_result_t status;
! 262:
! 263: do {
! 264: token = next_token (&val, (unsigned *)0, cfile);
! 265: if (token == END_OF_FILE)
! 266: break;
! 267: if (token == LEASE) {
! 268: struct lease *lease = (struct lease *)0;
! 269: if (parse_lease_declaration (&lease, cfile)) {
! 270: enter_lease (lease);
! 271: lease_dereference (&lease, MDL);
! 272: } else
! 273: parse_warn (cfile,
! 274: "possibly corrupt lease file");
! 275: } else if (token == IA_NA) {
! 276: parse_ia_na_declaration(cfile);
! 277: } else if (token == IA_TA) {
! 278: parse_ia_ta_declaration(cfile);
! 279: } else if (token == IA_PD) {
! 280: parse_ia_pd_declaration(cfile);
! 281: } else if (token == CLASS) {
! 282: parse_class_declaration(0, cfile, root_group,
! 283: CLASS_TYPE_CLASS);
! 284: } else if (token == SUBCLASS) {
! 285: parse_class_declaration(0, cfile, root_group,
! 286: CLASS_TYPE_SUBCLASS);
! 287: } else if (token == HOST) {
! 288: parse_host_declaration (cfile, root_group);
! 289: } else if (token == GROUP) {
! 290: parse_group_declaration (cfile, root_group);
! 291: #if defined (FAILOVER_PROTOCOL)
! 292: } else if (token == FAILOVER) {
! 293: parse_failover_state_declaration
! 294: (cfile, (dhcp_failover_state_t *)0);
! 295: #endif
! 296: #ifdef DHCPv6
! 297: } else if (token == SERVER_DUID) {
! 298: parse_server_duid(cfile);
! 299: #endif /* DHCPv6 */
! 300: } else {
! 301: log_error ("Corrupt lease file - possible data loss!");
! 302: skip_to_semi (cfile);
! 303: }
! 304:
! 305: } while (1);
! 306:
! 307: status = cfile -> warnings_occurred ? ISC_R_BADPARSE : ISC_R_SUCCESS;
! 308: return status;
! 309: }
! 310:
! 311: /* statement :== parameter | declaration
! 312:
! 313: parameter :== DEFAULT_LEASE_TIME lease_time
! 314: | MAX_LEASE_TIME lease_time
! 315: | DYNAMIC_BOOTP_LEASE_CUTOFF date
! 316: | DYNAMIC_BOOTP_LEASE_LENGTH lease_time
! 317: | BOOT_UNKNOWN_CLIENTS boolean
! 318: | ONE_LEASE_PER_CLIENT boolean
! 319: | GET_LEASE_HOSTNAMES boolean
! 320: | USE_HOST_DECL_NAME boolean
! 321: | NEXT_SERVER ip-addr-or-hostname SEMI
! 322: | option_parameter
! 323: | SERVER-IDENTIFIER ip-addr-or-hostname SEMI
! 324: | FILENAME string-parameter
! 325: | SERVER_NAME string-parameter
! 326: | hardware-parameter
! 327: | fixed-address-parameter
! 328: | ALLOW allow-deny-keyword
! 329: | DENY allow-deny-keyword
! 330: | USE_LEASE_ADDR_FOR_DEFAULT_ROUTE boolean
! 331: | AUTHORITATIVE
! 332: | NOT AUTHORITATIVE
! 333:
! 334: declaration :== host-declaration
! 335: | group-declaration
! 336: | shared-network-declaration
! 337: | subnet-declaration
! 338: | VENDOR_CLASS class-declaration
! 339: | USER_CLASS class-declaration
! 340: | RANGE address-range-declaration */
! 341:
! 342: int parse_statement (cfile, group, type, host_decl, declaration)
! 343: struct parse *cfile;
! 344: struct group *group;
! 345: int type;
! 346: struct host_decl *host_decl;
! 347: int declaration;
! 348: {
! 349: enum dhcp_token token;
! 350: const char *val;
! 351: struct shared_network *share;
! 352: char *n;
! 353: struct hardware hardware;
! 354: struct executable_statement *et, *ep;
! 355: struct option *option = NULL;
! 356: struct option_cache *cache;
! 357: int lose;
! 358: int known;
! 359: isc_result_t status;
! 360: unsigned code;
! 361:
! 362: token = peek_token (&val, (unsigned *)0, cfile);
! 363:
! 364: switch (token) {
! 365: case INCLUDE:
! 366: next_token (&val, (unsigned *)0, cfile);
! 367: token = next_token (&val, (unsigned *)0, cfile);
! 368: if (token != STRING) {
! 369: parse_warn (cfile, "filename string expected.");
! 370: skip_to_semi (cfile);
! 371: } else {
! 372: status = read_conf_file (val, group, type, 0);
! 373: if (status != ISC_R_SUCCESS)
! 374: parse_warn (cfile, "%s: bad parse.", val);
! 375: parse_semi (cfile);
! 376: }
! 377: return 1;
! 378:
! 379: case HOST:
! 380: next_token (&val, (unsigned *)0, cfile);
! 381: if (type != HOST_DECL && type != CLASS_DECL) {
! 382: if (global_host_once &&
! 383: (type == SUBNET_DECL || type == SHARED_NET_DECL)) {
! 384: global_host_once = 0;
! 385: log_error("WARNING: Host declarations are "
! 386: "global. They are not limited to "
! 387: "the scope you declared them in.");
! 388: }
! 389:
! 390: parse_host_declaration (cfile, group);
! 391: } else {
! 392: parse_warn (cfile,
! 393: "host declarations not allowed here.");
! 394: skip_to_semi (cfile);
! 395: }
! 396: return 1;
! 397:
! 398: case GROUP:
! 399: next_token (&val, (unsigned *)0, cfile);
! 400: if (type != HOST_DECL && type != CLASS_DECL)
! 401: parse_group_declaration (cfile, group);
! 402: else {
! 403: parse_warn (cfile,
! 404: "group declarations not allowed here.");
! 405: skip_to_semi (cfile);
! 406: }
! 407: return 1;
! 408:
! 409: case SHARED_NETWORK:
! 410: next_token (&val, (unsigned *)0, cfile);
! 411: if (type == SHARED_NET_DECL ||
! 412: type == HOST_DECL ||
! 413: type == SUBNET_DECL ||
! 414: type == CLASS_DECL) {
! 415: parse_warn (cfile, "shared-network parameters not %s.",
! 416: "allowed here");
! 417: skip_to_semi (cfile);
! 418: break;
! 419: }
! 420:
! 421: parse_shared_net_declaration (cfile, group);
! 422: return 1;
! 423:
! 424: case SUBNET:
! 425: case SUBNET6:
! 426: next_token (&val, (unsigned *)0, cfile);
! 427: if (type == HOST_DECL || type == SUBNET_DECL ||
! 428: type == CLASS_DECL) {
! 429: parse_warn (cfile,
! 430: "subnet declarations not allowed here.");
! 431: skip_to_semi (cfile);
! 432: return 1;
! 433: }
! 434:
! 435: /* If we're in a subnet declaration, just do the parse. */
! 436: if (group->shared_network != NULL) {
! 437: if (token == SUBNET) {
! 438: parse_subnet_declaration(cfile,
! 439: group->shared_network);
! 440: } else {
! 441: parse_subnet6_declaration(cfile,
! 442: group->shared_network);
! 443: }
! 444: break;
! 445: }
! 446:
! 447: /*
! 448: * Otherwise, cons up a fake shared network structure
! 449: * and populate it with the lone subnet...because the
! 450: * intention most likely is to refer to the entire link
! 451: * by shorthand, any configuration inside the subnet is
! 452: * actually placed in the shared-network's group.
! 453: */
! 454:
! 455: share = NULL;
! 456: status = shared_network_allocate (&share, MDL);
! 457: if (status != ISC_R_SUCCESS)
! 458: log_fatal ("Can't allocate shared subnet: %s",
! 459: isc_result_totext (status));
! 460: if (!clone_group (&share -> group, group, MDL))
! 461: log_fatal ("Can't allocate group for shared net");
! 462: shared_network_reference (&share -> group -> shared_network,
! 463: share, MDL);
! 464:
! 465: /*
! 466: * This is an implicit shared network, not explicit in
! 467: * the config.
! 468: */
! 469: share->flags |= SHARED_IMPLICIT;
! 470:
! 471: if (token == SUBNET) {
! 472: parse_subnet_declaration(cfile, share);
! 473: } else {
! 474: parse_subnet6_declaration(cfile, share);
! 475: }
! 476:
! 477: /* share -> subnets is the subnet we just parsed. */
! 478: if (share->subnets) {
! 479: interface_reference(&share->interface,
! 480: share->subnets->interface,
! 481: MDL);
! 482:
! 483: /* Make the shared network name from network number. */
! 484: if (token == SUBNET) {
! 485: n = piaddrmask(&share->subnets->net,
! 486: &share->subnets->netmask);
! 487: } else {
! 488: n = piaddrcidr(&share->subnets->net,
! 489: share->subnets->prefix_len);
! 490: }
! 491:
! 492: share->name = strdup(n);
! 493:
! 494: if (share->name == NULL)
! 495: log_fatal("Out of memory allocating default "
! 496: "shared network name (\"%s\").", n);
! 497:
! 498: /* Copy the authoritative parameter from the subnet,
! 499: since there is no opportunity to declare it here. */
! 500: share->group->authoritative =
! 501: share->subnets->group->authoritative;
! 502: enter_shared_network(share);
! 503: }
! 504: shared_network_dereference(&share, MDL);
! 505: return 1;
! 506:
! 507: case VENDOR_CLASS:
! 508: next_token (&val, (unsigned *)0, cfile);
! 509: if (type == CLASS_DECL) {
! 510: parse_warn (cfile,
! 511: "class declarations not allowed here.");
! 512: skip_to_semi (cfile);
! 513: break;
! 514: }
! 515: parse_class_declaration(NULL, cfile, group, CLASS_TYPE_VENDOR);
! 516: return 1;
! 517:
! 518: case USER_CLASS:
! 519: next_token (&val, (unsigned *)0, cfile);
! 520: if (type == CLASS_DECL) {
! 521: parse_warn (cfile,
! 522: "class declarations not allowed here.");
! 523: skip_to_semi (cfile);
! 524: break;
! 525: }
! 526: parse_class_declaration(NULL, cfile, group, CLASS_TYPE_USER);
! 527: return 1;
! 528:
! 529: case CLASS:
! 530: next_token (&val, (unsigned *)0, cfile);
! 531: if (type == CLASS_DECL) {
! 532: parse_warn (cfile,
! 533: "class declarations not allowed here.");
! 534: skip_to_semi (cfile);
! 535: break;
! 536: }
! 537: parse_class_declaration(NULL, cfile, group, CLASS_TYPE_CLASS);
! 538: return 1;
! 539:
! 540: case SUBCLASS:
! 541: next_token (&val, (unsigned *)0, cfile);
! 542: if (type == CLASS_DECL) {
! 543: parse_warn (cfile,
! 544: "class declarations not allowed here.");
! 545: skip_to_semi (cfile);
! 546: break;
! 547: }
! 548: parse_class_declaration(NULL, cfile, group,
! 549: CLASS_TYPE_SUBCLASS);
! 550: return 1;
! 551:
! 552: case HARDWARE:
! 553: next_token (&val, (unsigned *)0, cfile);
! 554: #ifdef DHCPv6
! 555: if (local_family == AF_INET6) {
! 556: parse_warn(cfile, "You can not use a hardware "
! 557: "parameter for DHCPv6 hosts. "
! 558: "Use the host-identifier parameter "
! 559: "instead.");
! 560: skip_to_semi(cfile);
! 561: break;
! 562: }
! 563: #endif /* DHCPv6 */
! 564: memset (&hardware, 0, sizeof hardware);
! 565: if (host_decl && memcmp(&hardware, &(host_decl->interface),
! 566: sizeof(hardware)) != 0) {
! 567: parse_warn(cfile, "Host %s hardware address already "
! 568: "configured.", host_decl->name);
! 569: break;
! 570: }
! 571:
! 572: parse_hardware_param (cfile, &hardware);
! 573: if (host_decl)
! 574: host_decl -> interface = hardware;
! 575: else
! 576: parse_warn (cfile, "hardware address parameter %s",
! 577: "not allowed here.");
! 578: break;
! 579:
! 580: case FIXED_ADDR:
! 581: case FIXED_ADDR6:
! 582: next_token(&val, NULL, cfile);
! 583: cache = NULL;
! 584: if (parse_fixed_addr_param(&cache, cfile, token)) {
! 585: if (host_decl) {
! 586: if (host_decl->fixed_addr) {
! 587: option_cache_dereference(&cache, MDL);
! 588: parse_warn(cfile,
! 589: "Only one fixed address "
! 590: "declaration per host.");
! 591: } else {
! 592: host_decl->fixed_addr = cache;
! 593: }
! 594: } else {
! 595: parse_warn(cfile,
! 596: "fixed-address parameter not "
! 597: "allowed here.");
! 598: option_cache_dereference(&cache, MDL);
! 599: }
! 600: }
! 601: break;
! 602:
! 603: case POOL:
! 604: next_token (&val, (unsigned *)0, cfile);
! 605: if (type == POOL_DECL) {
! 606: parse_warn (cfile, "pool declared within pool.");
! 607: skip_to_semi(cfile);
! 608: } else if (type != SUBNET_DECL && type != SHARED_NET_DECL) {
! 609: parse_warn (cfile, "pool declared outside of network");
! 610: skip_to_semi(cfile);
! 611: } else
! 612: parse_pool_statement (cfile, group, type);
! 613:
! 614: return declaration;
! 615:
! 616: case RANGE:
! 617: next_token (&val, (unsigned *)0, cfile);
! 618: if (type != SUBNET_DECL || !group -> subnet) {
! 619: parse_warn (cfile,
! 620: "range declaration not allowed here.");
! 621: skip_to_semi (cfile);
! 622: return declaration;
! 623: }
! 624: parse_address_range (cfile, group, type, (struct pool *)0,
! 625: (struct lease **)0);
! 626: return declaration;
! 627:
! 628: #ifdef DHCPv6
! 629: case RANGE6:
! 630: next_token(NULL, NULL, cfile);
! 631: if ((type != SUBNET_DECL) || (group->subnet == NULL)) {
! 632: parse_warn (cfile,
! 633: "range6 declaration not allowed here.");
! 634: skip_to_semi(cfile);
! 635: return declaration;
! 636: }
! 637: parse_address_range6(cfile, group);
! 638: return declaration;
! 639:
! 640: case PREFIX6:
! 641: next_token(NULL, NULL, cfile);
! 642: if ((type != SUBNET_DECL) || (group->subnet == NULL)) {
! 643: parse_warn (cfile,
! 644: "prefix6 declaration not allowed here.");
! 645: skip_to_semi(cfile);
! 646: return declaration;
! 647: }
! 648: parse_prefix6(cfile, group);
! 649: return declaration;
! 650:
! 651: case FIXED_PREFIX6:
! 652: next_token(&val, NULL, cfile);
! 653: if (!host_decl) {
! 654: parse_warn (cfile,
! 655: "fixed-prefix6 declaration not "
! 656: "allowed here.");
! 657: skip_to_semi(cfile);
! 658: break;
! 659: }
! 660: parse_fixed_prefix6(cfile, host_decl);
! 661: break;
! 662:
! 663: #endif /* DHCPv6 */
! 664:
! 665: case TOKEN_NOT:
! 666: token = next_token (&val, (unsigned *)0, cfile);
! 667: token = next_token (&val, (unsigned *)0, cfile);
! 668: switch (token) {
! 669: case AUTHORITATIVE:
! 670: group -> authoritative = 0;
! 671: goto authoritative;
! 672: default:
! 673: parse_warn (cfile, "expecting assertion");
! 674: skip_to_semi (cfile);
! 675: break;
! 676: }
! 677: break;
! 678: case AUTHORITATIVE:
! 679: token = next_token (&val, (unsigned *)0, cfile);
! 680: group -> authoritative = 1;
! 681: authoritative:
! 682: if (type == HOST_DECL)
! 683: parse_warn (cfile, "authority makes no sense here.");
! 684: parse_semi (cfile);
! 685: break;
! 686:
! 687: /* "server-identifier" is a special hack, equivalent to
! 688: "option dhcp-server-identifier". */
! 689: case SERVER_IDENTIFIER:
! 690: code = DHO_DHCP_SERVER_IDENTIFIER;
! 691: if (!option_code_hash_lookup(&option, dhcp_universe.code_hash,
! 692: &code, 0, MDL))
! 693: log_fatal("Server identifier not in hash (%s:%d).",
! 694: MDL);
! 695: token = next_token (&val, (unsigned *)0, cfile);
! 696: goto finish_option;
! 697:
! 698: case OPTION:
! 699: token = next_token (&val, (unsigned *)0, cfile);
! 700: token = peek_token (&val, (unsigned *)0, cfile);
! 701: if (token == SPACE) {
! 702: if (type != ROOT_GROUP) {
! 703: parse_warn (cfile,
! 704: "option space definitions %s",
! 705: "may not be scoped.");
! 706: skip_to_semi (cfile);
! 707: break;
! 708: }
! 709: parse_option_space_decl (cfile);
! 710: return declaration;
! 711: }
! 712:
! 713: known = 0;
! 714: status = parse_option_name(cfile, 1, &known, &option);
! 715: if (status == ISC_R_SUCCESS) {
! 716: token = peek_token (&val, (unsigned *)0, cfile);
! 717: if (token == CODE) {
! 718: if (type != ROOT_GROUP) {
! 719: parse_warn (cfile,
! 720: "option definitions%s",
! 721: " may not be scoped.");
! 722: skip_to_semi (cfile);
! 723: option_dereference(&option, MDL);
! 724: break;
! 725: }
! 726: next_token (&val, (unsigned *)0, cfile);
! 727:
! 728: /*
! 729: * If the option was known, remove it from the
! 730: * code and name hashes before redefining it.
! 731: */
! 732: if (known) {
! 733: option_name_hash_delete(
! 734: option->universe->name_hash,
! 735: option->name, 0, MDL);
! 736: option_code_hash_delete(
! 737: option->universe->code_hash,
! 738: &option->code, 0, MDL);
! 739: }
! 740:
! 741: parse_option_code_definition(cfile, option);
! 742: option_dereference(&option, MDL);
! 743: return declaration;
! 744: }
! 745:
! 746: /* If this wasn't an option code definition, don't
! 747: allow an unknown option. */
! 748: if (!known) {
! 749: parse_warn (cfile, "unknown option %s.%s",
! 750: option -> universe -> name,
! 751: option -> name);
! 752: skip_to_semi (cfile);
! 753: option_dereference(&option, MDL);
! 754: return declaration;
! 755: }
! 756:
! 757: /*
! 758: * If the configuration attempts to define on option
! 759: * that we ignore, then warn about it now.
! 760: *
! 761: * In DHCPv4 we do not use dhcp-renewal-time or
! 762: * dhcp-rebinding-time, but we use these in DHCPv6.
! 763: *
! 764: * XXX: We may want to include a "blacklist" of
! 765: * options we ignore in the future, as a table.
! 766: */
! 767: if ((option->code == DHO_DHCP_LEASE_TIME) ||
! 768: ((local_family != AF_INET6) &&
! 769: ((option->code == DHO_DHCP_RENEWAL_TIME) ||
! 770: (option->code == DHO_DHCP_REBINDING_TIME))))
! 771: {
! 772: log_error("WARNING: server ignoring option %s "
! 773: "in configuration file.",
! 774: option->name);
! 775: }
! 776:
! 777: finish_option:
! 778: et = (struct executable_statement *)0;
! 779: if (!parse_option_statement
! 780: (&et, cfile, 1, option,
! 781: supersede_option_statement))
! 782: return declaration;
! 783: option_dereference(&option, MDL);
! 784: goto insert_statement;
! 785: } else
! 786: return declaration;
! 787:
! 788: break;
! 789:
! 790: case FAILOVER:
! 791: if (type != ROOT_GROUP && type != SHARED_NET_DECL) {
! 792: parse_warn (cfile, "failover peers may only be %s",
! 793: "defined in shared-network");
! 794: log_error ("declarations and the outer scope.");
! 795: skip_to_semi (cfile);
! 796: break;
! 797: }
! 798: token = next_token (&val, (unsigned *)0, cfile);
! 799: #if defined (FAILOVER_PROTOCOL)
! 800: parse_failover_peer (cfile, group, type);
! 801: #else
! 802: parse_warn (cfile, "No failover support.");
! 803: skip_to_semi (cfile);
! 804: #endif
! 805: break;
! 806:
! 807: #ifdef DHCPv6
! 808: case SERVER_DUID:
! 809: parse_server_duid_conf(cfile);
! 810: break;
! 811: #endif /* DHCPv6 */
! 812:
! 813: default:
! 814: et = (struct executable_statement *)0;
! 815: lose = 0;
! 816: if (!parse_executable_statement (&et, cfile, &lose,
! 817: context_any)) {
! 818: if (!lose) {
! 819: if (declaration)
! 820: parse_warn (cfile,
! 821: "expecting a declaration");
! 822: else
! 823: parse_warn (cfile,
! 824: "expecting a parameter %s",
! 825: "or declaration");
! 826: skip_to_semi (cfile);
! 827: }
! 828: return declaration;
! 829: }
! 830: if (!et)
! 831: return declaration;
! 832: insert_statement:
! 833: if (group -> statements) {
! 834: int multi = 0;
! 835:
! 836: /* If this set of statements is only referenced
! 837: by this group, just add the current statement
! 838: to the end of the chain. */
! 839: for (ep = group -> statements; ep -> next;
! 840: ep = ep -> next)
! 841: if (ep -> refcnt > 1) /* XXX */
! 842: multi = 1;
! 843: if (!multi) {
! 844: executable_statement_reference (&ep -> next,
! 845: et, MDL);
! 846: executable_statement_dereference (&et, MDL);
! 847: return declaration;
! 848: }
! 849:
! 850: /* Otherwise, make a parent chain, and put the
! 851: current group statements first and the new
! 852: statement in the next pointer. */
! 853: ep = (struct executable_statement *)0;
! 854: if (!executable_statement_allocate (&ep, MDL))
! 855: log_fatal ("No memory for statements.");
! 856: ep -> op = statements_statement;
! 857: executable_statement_reference (&ep -> data.statements,
! 858: group -> statements,
! 859: MDL);
! 860: executable_statement_reference (&ep -> next, et, MDL);
! 861: executable_statement_dereference (&group -> statements,
! 862: MDL);
! 863: executable_statement_reference (&group -> statements,
! 864: ep, MDL);
! 865: executable_statement_dereference (&ep, MDL);
! 866: } else {
! 867: executable_statement_reference (&group -> statements,
! 868: et, MDL);
! 869: }
! 870: executable_statement_dereference (&et, MDL);
! 871: return declaration;
! 872: }
! 873:
! 874: return 0;
! 875: }
! 876:
! 877: #if defined (FAILOVER_PROTOCOL)
! 878: void parse_failover_peer (cfile, group, type)
! 879: struct parse *cfile;
! 880: struct group *group;
! 881: int type;
! 882: {
! 883: enum dhcp_token token;
! 884: const char *val;
! 885: dhcp_failover_state_t *peer;
! 886: u_int32_t *tp;
! 887: char *name;
! 888: u_int32_t split;
! 889: u_int8_t hba [32];
! 890: unsigned hba_len = sizeof hba;
! 891: int i;
! 892: struct expression *expr;
! 893: isc_result_t status;
! 894: dhcp_failover_config_t *cp;
! 895:
! 896: token = next_token (&val, (unsigned *)0, cfile);
! 897: if (token != PEER) {
! 898: parse_warn (cfile, "expecting \"peer\"");
! 899: skip_to_semi (cfile);
! 900: return;
! 901: }
! 902:
! 903: token = next_token (&val, (unsigned *)0, cfile);
! 904: if (is_identifier (token) || token == STRING) {
! 905: name = dmalloc (strlen (val) + 1, MDL);
! 906: if (!name)
! 907: log_fatal ("no memory for peer name %s", name);
! 908: strcpy (name, val);
! 909: } else {
! 910: parse_warn (cfile, "expecting failover peer name.");
! 911: skip_to_semi (cfile);
! 912: return;
! 913: }
! 914:
! 915: /* See if there's a peer declaration by this name. */
! 916: peer = (dhcp_failover_state_t *)0;
! 917: find_failover_peer (&peer, name, MDL);
! 918:
! 919: token = next_token (&val, (unsigned *)0, cfile);
! 920: if (token == SEMI) {
! 921: dfree (name, MDL);
! 922: if (type != SHARED_NET_DECL)
! 923: parse_warn (cfile, "failover peer reference not %s",
! 924: "in shared-network declaration");
! 925: else {
! 926: if (!peer) {
! 927: parse_warn (cfile, "reference to unknown%s%s",
! 928: " failover peer ", name);
! 929: return;
! 930: }
! 931: dhcp_failover_state_reference
! 932: (&group -> shared_network -> failover_peer,
! 933: peer, MDL);
! 934: }
! 935: dhcp_failover_state_dereference (&peer, MDL);
! 936: return;
! 937: } else if (token == STATE) {
! 938: if (!peer) {
! 939: parse_warn (cfile, "state declaration for unknown%s%s",
! 940: " failover peer ", name);
! 941: return;
! 942: }
! 943: parse_failover_state_declaration (cfile, peer);
! 944: dhcp_failover_state_dereference (&peer, MDL);
! 945: return;
! 946: } else if (token != LBRACE) {
! 947: parse_warn (cfile, "expecting left brace");
! 948: skip_to_semi (cfile);
! 949: }
! 950:
! 951: /* Make sure this isn't a redeclaration. */
! 952: if (peer) {
! 953: parse_warn (cfile, "redeclaration of failover peer %s", name);
! 954: skip_to_rbrace (cfile, 1);
! 955: dhcp_failover_state_dereference (&peer, MDL);
! 956: return;
! 957: }
! 958:
! 959: status = dhcp_failover_state_allocate (&peer, MDL);
! 960: if (status != ISC_R_SUCCESS)
! 961: log_fatal ("Can't allocate failover peer %s: %s",
! 962: name, isc_result_totext (status));
! 963:
! 964: /* Save the name. */
! 965: peer -> name = name;
! 966:
! 967: do {
! 968: cp = &peer -> me;
! 969: peer:
! 970: token = next_token (&val, (unsigned *)0, cfile);
! 971: switch (token) {
! 972: case RBRACE:
! 973: break;
! 974:
! 975: case PRIMARY:
! 976: peer -> i_am = primary;
! 977: break;
! 978:
! 979: case SECONDARY:
! 980: peer -> i_am = secondary;
! 981: if (peer -> hba)
! 982: parse_warn (cfile,
! 983: "secondary may not define %s",
! 984: "load balance settings.");
! 985: break;
! 986:
! 987: case PEER:
! 988: cp = &peer -> partner;
! 989: goto peer;
! 990:
! 991: case ADDRESS:
! 992: expr = (struct expression *)0;
! 993: if (!parse_ip_addr_or_hostname (&expr, cfile, 0)) {
! 994: skip_to_rbrace (cfile, 1);
! 995: dhcp_failover_state_dereference (&peer, MDL);
! 996: return;
! 997: }
! 998: option_cache (&cp -> address,
! 999: (struct data_string *)0, expr,
! 1000: (struct option *)0, MDL);
! 1001: expression_dereference (&expr, MDL);
! 1002: break;
! 1003:
! 1004: case PORT:
! 1005: token = next_token (&val, (unsigned *)0, cfile);
! 1006: if (token != NUMBER) {
! 1007: parse_warn (cfile, "expecting number");
! 1008: skip_to_rbrace (cfile, 1);
! 1009: }
! 1010: cp -> port = atoi (val);
! 1011: break;
! 1012:
! 1013: case MAX_LEASE_MISBALANCE:
! 1014: tp = &peer->max_lease_misbalance;
! 1015: goto parse_idle;
! 1016:
! 1017: case MAX_LEASE_OWNERSHIP:
! 1018: tp = &peer->max_lease_ownership;
! 1019: goto parse_idle;
! 1020:
! 1021: case MAX_BALANCE:
! 1022: tp = &peer->max_balance;
! 1023: goto parse_idle;
! 1024:
! 1025: case MIN_BALANCE:
! 1026: tp = &peer->min_balance;
! 1027: goto parse_idle;
! 1028:
! 1029: case MAX_RESPONSE_DELAY:
! 1030: tp = &cp -> max_response_delay;
! 1031: parse_idle:
! 1032: token = next_token (&val, (unsigned *)0, cfile);
! 1033: if (token != NUMBER) {
! 1034: parse_warn (cfile, "expecting number.");
! 1035: skip_to_rbrace (cfile, 1);
! 1036: dhcp_failover_state_dereference (&peer, MDL);
! 1037: return;
! 1038: }
! 1039: *tp = atoi (val);
! 1040: break;
! 1041:
! 1042: case MAX_UNACKED_UPDATES:
! 1043: tp = &cp -> max_flying_updates;
! 1044: goto parse_idle;
! 1045:
! 1046: case MCLT:
! 1047: tp = &peer -> mclt;
! 1048: goto parse_idle;
! 1049:
! 1050: case HBA:
! 1051: hba_len = 32;
! 1052: if (peer -> i_am == secondary)
! 1053: parse_warn (cfile,
! 1054: "secondary may not define %s",
! 1055: "load balance settings.");
! 1056: if (!parse_numeric_aggregate (cfile, hba, &hba_len,
! 1057: COLON, 16, 8)) {
! 1058: skip_to_rbrace (cfile, 1);
! 1059: dhcp_failover_state_dereference (&peer, MDL);
! 1060: return;
! 1061: }
! 1062: if (hba_len != 32) {
! 1063: parse_warn (cfile,
! 1064: "HBA must be exactly 32 bytes.");
! 1065: dfree (hba, MDL);
! 1066: break;
! 1067: }
! 1068: make_hba:
! 1069: peer -> hba = dmalloc (32, MDL);
! 1070: if (!peer -> hba) {
! 1071: dfree (peer -> name, MDL);
! 1072: dfree (peer, MDL);
! 1073: }
! 1074: memcpy (peer -> hba, hba, 32);
! 1075: break;
! 1076:
! 1077: case SPLIT:
! 1078: token = next_token (&val, (unsigned *)0, cfile);
! 1079: if (peer -> i_am == secondary)
! 1080: parse_warn (cfile,
! 1081: "secondary may not define %s",
! 1082: "load balance settings.");
! 1083: if (token != NUMBER) {
! 1084: parse_warn (cfile, "expecting number");
! 1085: skip_to_rbrace (cfile, 1);
! 1086: dhcp_failover_state_dereference (&peer, MDL);
! 1087: return;
! 1088: }
! 1089: split = atoi (val);
! 1090: if (split > 255) {
! 1091: parse_warn (cfile, "split must be < 256");
! 1092: } else {
! 1093: memset (hba, 0, sizeof hba);
! 1094: for (i = 0; i < split; i++) {
! 1095: if (i < split)
! 1096: hba [i / 8] |= (1 << (i & 7));
! 1097: }
! 1098: goto make_hba;
! 1099: }
! 1100: break;
! 1101:
! 1102: case LOAD:
! 1103: token = next_token (&val, (unsigned *)0, cfile);
! 1104: if (token != BALANCE) {
! 1105: parse_warn (cfile, "expecting 'balance'");
! 1106: badload:
! 1107: skip_to_rbrace (cfile, 1);
! 1108: break;
! 1109: }
! 1110: token = next_token (&val, (unsigned *)0, cfile);
! 1111: if (token != TOKEN_MAX) {
! 1112: parse_warn (cfile, "expecting 'max'");
! 1113: goto badload;
! 1114: }
! 1115: token = next_token (&val, (unsigned *)0, cfile);
! 1116: if (token != SECONDS) {
! 1117: parse_warn (cfile, "expecting 'secs'");
! 1118: goto badload;
! 1119: }
! 1120: token = next_token (&val, (unsigned *)0, cfile);
! 1121: if (token != NUMBER) {
! 1122: parse_warn (cfile, "expecting number");
! 1123: goto badload;
! 1124: }
! 1125: peer -> load_balance_max_secs = atoi (val);
! 1126: break;
! 1127:
! 1128: default:
! 1129: parse_warn (cfile,
! 1130: "invalid statement in peer declaration");
! 1131: skip_to_rbrace (cfile, 1);
! 1132: dhcp_failover_state_dereference (&peer, MDL);
! 1133: return;
! 1134: }
! 1135: if (token != RBRACE && !parse_semi (cfile)) {
! 1136: skip_to_rbrace (cfile, 1);
! 1137: dhcp_failover_state_dereference (&peer, MDL);
! 1138: return;
! 1139: }
! 1140: } while (token != RBRACE);
! 1141:
! 1142: /* me.address can be null; the failover link initiate code tries to
! 1143: * derive a reasonable address to use.
! 1144: */
! 1145: if (!peer -> partner.address)
! 1146: parse_warn (cfile, "peer address may not be omitted");
! 1147:
! 1148: /* XXX - when/if we get a port number assigned, just set as default */
! 1149: if (!peer -> me.port)
! 1150: parse_warn (cfile, "local port may not be omitted");
! 1151: if (!peer -> partner.port)
! 1152: parse_warn (cfile, "peer port may not be omitted");
! 1153:
! 1154: if (peer -> i_am == primary) {
! 1155: if (!peer -> hba) {
! 1156: parse_warn (cfile,
! 1157: "primary failover server must have hba or split.");
! 1158: } else if (!peer -> mclt) {
! 1159: parse_warn (cfile,
! 1160: "primary failover server must have mclt.");
! 1161: }
! 1162: }
! 1163:
! 1164: if (!peer->max_lease_misbalance)
! 1165: peer->max_lease_misbalance = DEFAULT_MAX_LEASE_MISBALANCE;
! 1166: if (!peer->max_lease_ownership)
! 1167: peer->max_lease_ownership = DEFAULT_MAX_LEASE_OWNERSHIP;
! 1168: if (!peer->max_balance)
! 1169: peer->max_balance = DEFAULT_MAX_BALANCE_TIME;
! 1170: if (!peer->min_balance)
! 1171: peer->min_balance = DEFAULT_MIN_BALANCE_TIME;
! 1172: if (!peer->me.max_flying_updates)
! 1173: peer->me.max_flying_updates = DEFAULT_MAX_FLYING_UPDATES;
! 1174: if (!peer->me.max_response_delay)
! 1175: peer->me.max_response_delay = DEFAULT_MAX_RESPONSE_DELAY;
! 1176:
! 1177: if (type == SHARED_NET_DECL)
! 1178: group->shared_network->failover_peer = peer;
! 1179:
! 1180: /* Set the initial state. */
! 1181: if (peer -> i_am == primary) {
! 1182: peer -> me.state = recover;
! 1183: peer -> me.stos = cur_time;
! 1184: peer -> partner.state = unknown_state;
! 1185: peer -> partner.stos = cur_time;
! 1186: } else {
! 1187: peer -> me.state = recover;
! 1188: peer -> me.stos = cur_time;
! 1189: peer -> partner.state = unknown_state;
! 1190: peer -> partner.stos = cur_time;
! 1191: }
! 1192:
! 1193: status = enter_failover_peer (peer);
! 1194: if (status != ISC_R_SUCCESS)
! 1195: parse_warn (cfile, "failover peer %s: %s",
! 1196: peer -> name, isc_result_totext (status));
! 1197: dhcp_failover_state_dereference (&peer, MDL);
! 1198: }
! 1199:
! 1200: void parse_failover_state_declaration (struct parse *cfile,
! 1201: dhcp_failover_state_t *peer)
! 1202: {
! 1203: enum dhcp_token token;
! 1204: const char *val;
! 1205: char *name;
! 1206: dhcp_failover_state_t *state;
! 1207: dhcp_failover_config_t *cp;
! 1208:
! 1209: if (!peer) {
! 1210: token = next_token (&val, (unsigned *)0, cfile);
! 1211: if (token != PEER) {
! 1212: parse_warn (cfile, "expecting \"peer\"");
! 1213: skip_to_semi (cfile);
! 1214: return;
! 1215: }
! 1216:
! 1217: token = next_token (&val, (unsigned *)0, cfile);
! 1218: if (is_identifier (token) || token == STRING) {
! 1219: name = dmalloc (strlen (val) + 1, MDL);
! 1220: if (!name)
! 1221: log_fatal ("failover peer name %s: no memory",
! 1222: name);
! 1223: strcpy (name, val);
! 1224: } else {
! 1225: parse_warn (cfile, "expecting failover peer name.");
! 1226: skip_to_semi (cfile);
! 1227: return;
! 1228: }
! 1229:
! 1230: /* See if there's a peer declaration by this name. */
! 1231: state = (dhcp_failover_state_t *)0;
! 1232: find_failover_peer (&state, name, MDL);
! 1233: if (!state) {
! 1234: parse_warn (cfile, "unknown failover peer: %s", name);
! 1235: skip_to_semi (cfile);
! 1236: return;
! 1237: }
! 1238:
! 1239: token = next_token (&val, (unsigned *)0, cfile);
! 1240: if (token != STATE) {
! 1241: parse_warn (cfile, "expecting 'state'");
! 1242: if (token != SEMI)
! 1243: skip_to_semi (cfile);
! 1244: return;
! 1245: }
! 1246: } else {
! 1247: state = (dhcp_failover_state_t *)0;
! 1248: dhcp_failover_state_reference (&state, peer, MDL);
! 1249: }
! 1250: token = next_token (&val, (unsigned *)0, cfile);
! 1251: if (token != LBRACE) {
! 1252: parse_warn (cfile, "expecting left brace");
! 1253: if (token != SEMI)
! 1254: skip_to_semi (cfile);
! 1255: dhcp_failover_state_dereference (&state, MDL);
! 1256: return;
! 1257: }
! 1258: do {
! 1259: token = next_token (&val, (unsigned *)0, cfile);
! 1260: switch (token) {
! 1261: case RBRACE:
! 1262: break;
! 1263: case MY:
! 1264: cp = &state -> me;
! 1265: do_state:
! 1266: token = next_token (&val, (unsigned *)0, cfile);
! 1267: if (token != STATE) {
! 1268: parse_warn (cfile, "expecting 'state'");
! 1269: goto bogus;
! 1270: }
! 1271: parse_failover_state (cfile,
! 1272: &cp -> state, &cp -> stos);
! 1273: break;
! 1274:
! 1275: case PARTNER:
! 1276: cp = &state -> partner;
! 1277: goto do_state;
! 1278:
! 1279: case MCLT:
! 1280: if (state -> i_am == primary) {
! 1281: parse_warn (cfile,
! 1282: "mclt not valid for primary");
! 1283: goto bogus;
! 1284: }
! 1285: token = next_token (&val, (unsigned *)0, cfile);
! 1286: if (token != NUMBER) {
! 1287: parse_warn (cfile, "expecting a number.");
! 1288: goto bogus;
! 1289: }
! 1290: state -> mclt = atoi (val);
! 1291: parse_semi (cfile);
! 1292: break;
! 1293:
! 1294: default:
! 1295: parse_warn (cfile, "expecting state setting.");
! 1296: bogus:
! 1297: skip_to_rbrace (cfile, 1);
! 1298: dhcp_failover_state_dereference (&state, MDL);
! 1299: return;
! 1300: }
! 1301: } while (token != RBRACE);
! 1302: dhcp_failover_state_dereference (&state, MDL);
! 1303: }
! 1304:
! 1305: void parse_failover_state (cfile, state, stos)
! 1306: struct parse *cfile;
! 1307: enum failover_state *state;
! 1308: TIME *stos;
! 1309: {
! 1310: enum dhcp_token token;
! 1311: const char *val;
! 1312: enum failover_state state_in;
! 1313: TIME stos_in;
! 1314:
! 1315: token = next_token (&val, (unsigned *)0, cfile);
! 1316: switch (token) {
! 1317: case UNKNOWN_STATE:
! 1318: state_in = unknown_state;
! 1319: break;
! 1320:
! 1321: case PARTNER_DOWN:
! 1322: state_in = partner_down;
! 1323: break;
! 1324:
! 1325: case NORMAL:
! 1326: state_in = normal;
! 1327: break;
! 1328:
! 1329: case COMMUNICATIONS_INTERRUPTED:
! 1330: state_in = communications_interrupted;
! 1331: break;
! 1332:
! 1333: case CONFLICT_DONE:
! 1334: state_in = conflict_done;
! 1335: break;
! 1336:
! 1337: case RESOLUTION_INTERRUPTED:
! 1338: state_in = resolution_interrupted;
! 1339: break;
! 1340:
! 1341: case POTENTIAL_CONFLICT:
! 1342: state_in = potential_conflict;
! 1343: break;
! 1344:
! 1345: case RECOVER:
! 1346: state_in = recover;
! 1347: break;
! 1348:
! 1349: case RECOVER_WAIT:
! 1350: state_in = recover_wait;
! 1351: break;
! 1352:
! 1353: case RECOVER_DONE:
! 1354: state_in = recover_done;
! 1355: break;
! 1356:
! 1357: case SHUTDOWN:
! 1358: state_in = shut_down;
! 1359: break;
! 1360:
! 1361: case PAUSED:
! 1362: state_in = paused;
! 1363: break;
! 1364:
! 1365: case STARTUP:
! 1366: state_in = startup;
! 1367: break;
! 1368:
! 1369: default:
! 1370: parse_warn (cfile, "unknown failover state");
! 1371: skip_to_semi (cfile);
! 1372: return;
! 1373: }
! 1374:
! 1375: token = next_token (&val, (unsigned *)0, cfile);
! 1376: if (token == SEMI) {
! 1377: stos_in = cur_time;
! 1378: } else {
! 1379: if (token != AT) {
! 1380: parse_warn (cfile, "expecting \"at\"");
! 1381: skip_to_semi (cfile);
! 1382: return;
! 1383: }
! 1384:
! 1385: stos_in = parse_date (cfile);
! 1386: if (!stos_in)
! 1387: return;
! 1388: }
! 1389:
! 1390: /* Now that we've apparently gotten a clean parse, we
! 1391: can trust that this is a state that was fully committed to
! 1392: disk, so we can install it. */
! 1393: *stos = stos_in;
! 1394: *state = state_in;
! 1395: }
! 1396: #endif /* defined (FAILOVER_PROTOCOL) */
! 1397:
! 1398: /* Permit_list_match returns 1 if every element of the permit list in lhs
! 1399: also appears in rhs. Note that this doesn't by itself mean that the
! 1400: two lists are equal - to check for equality, permit_list_match has to
! 1401: return 1 with (list1, list2) and with (list2, list1). */
! 1402:
! 1403: int permit_list_match (struct permit *lhs, struct permit *rhs)
! 1404: {
! 1405: struct permit *plp, *prp;
! 1406: int matched;
! 1407:
! 1408: if (!lhs)
! 1409: return 1;
! 1410: if (!rhs)
! 1411: return 0;
! 1412: for (plp = lhs; plp; plp = plp -> next) {
! 1413: matched = 0;
! 1414: for (prp = rhs; prp; prp = prp -> next) {
! 1415: if (prp -> type == plp -> type &&
! 1416: (prp -> type != permit_class ||
! 1417: prp -> class == plp -> class)) {
! 1418: matched = 1;
! 1419: break;
! 1420: }
! 1421: }
! 1422: if (!matched)
! 1423: return 0;
! 1424: }
! 1425: return 1;
! 1426: }
! 1427:
! 1428: void parse_pool_statement (cfile, group, type)
! 1429: struct parse *cfile;
! 1430: struct group *group;
! 1431: int type;
! 1432: {
! 1433: enum dhcp_token token;
! 1434: const char *val;
! 1435: int done = 0;
! 1436: struct pool *pool, **p, *pp;
! 1437: struct permit *permit;
! 1438: struct permit **permit_head;
! 1439: int declaration = 0;
! 1440: isc_result_t status;
! 1441: struct lease *lpchain = (struct lease *)0, *lp;
! 1442: TIME t;
! 1443: int is_allow = 0;
! 1444:
! 1445: pool = (struct pool *)0;
! 1446: status = pool_allocate (&pool, MDL);
! 1447: if (status != ISC_R_SUCCESS)
! 1448: log_fatal ("no memory for pool: %s",
! 1449: isc_result_totext (status));
! 1450:
! 1451: if (type == SUBNET_DECL)
! 1452: shared_network_reference (&pool -> shared_network,
! 1453: group -> subnet -> shared_network,
! 1454: MDL);
! 1455: else if (type == SHARED_NET_DECL)
! 1456: shared_network_reference (&pool -> shared_network,
! 1457: group -> shared_network, MDL);
! 1458: else {
! 1459: parse_warn(cfile, "Dynamic pools are only valid inside "
! 1460: "subnet or shared-network statements.");
! 1461: skip_to_semi(cfile);
! 1462: return;
! 1463: }
! 1464:
! 1465: if (pool->shared_network == NULL ||
! 1466: !clone_group(&pool->group, pool->shared_network->group, MDL))
! 1467: log_fatal("can't clone pool group.");
! 1468:
! 1469: #if defined (FAILOVER_PROTOCOL)
! 1470: /* Inherit the failover peer from the shared network. */
! 1471: if (pool -> shared_network -> failover_peer)
! 1472: dhcp_failover_state_reference
! 1473: (&pool -> failover_peer,
! 1474: pool -> shared_network -> failover_peer, MDL);
! 1475: #endif
! 1476:
! 1477: if (!parse_lbrace (cfile)) {
! 1478: pool_dereference (&pool, MDL);
! 1479: return;
! 1480: }
! 1481:
! 1482: do {
! 1483: token = peek_token (&val, (unsigned *)0, cfile);
! 1484: switch (token) {
! 1485: case TOKEN_NO:
! 1486: next_token (&val, (unsigned *)0, cfile);
! 1487: token = next_token (&val, (unsigned *)0, cfile);
! 1488: if (token != FAILOVER ||
! 1489: (token = next_token (&val, (unsigned *)0,
! 1490: cfile)) != PEER) {
! 1491: parse_warn (cfile,
! 1492: "expecting \"failover peer\".");
! 1493: skip_to_semi (cfile);
! 1494: continue;
! 1495: }
! 1496: #if defined (FAILOVER_PROTOCOL)
! 1497: if (pool -> failover_peer)
! 1498: dhcp_failover_state_dereference
! 1499: (&pool -> failover_peer, MDL);
! 1500: #endif
! 1501: break;
! 1502:
! 1503: #if defined (FAILOVER_PROTOCOL)
! 1504: case FAILOVER:
! 1505: next_token (&val, (unsigned *)0, cfile);
! 1506: token = next_token (&val, (unsigned *)0, cfile);
! 1507: if (token != PEER) {
! 1508: parse_warn (cfile, "expecting 'peer'.");
! 1509: skip_to_semi (cfile);
! 1510: break;
! 1511: }
! 1512: token = next_token (&val, (unsigned *)0, cfile);
! 1513: if (token != STRING) {
! 1514: parse_warn (cfile, "expecting string.");
! 1515: skip_to_semi (cfile);
! 1516: break;
! 1517: }
! 1518: if (pool -> failover_peer)
! 1519: dhcp_failover_state_dereference
! 1520: (&pool -> failover_peer, MDL);
! 1521: status = find_failover_peer (&pool -> failover_peer,
! 1522: val, MDL);
! 1523: if (status != ISC_R_SUCCESS)
! 1524: parse_warn (cfile,
! 1525: "failover peer %s: %s", val,
! 1526: isc_result_totext (status));
! 1527: else
! 1528: pool -> failover_peer -> pool_count++;
! 1529: parse_semi (cfile);
! 1530: break;
! 1531: #endif
! 1532:
! 1533: case RANGE:
! 1534: next_token (&val, (unsigned *)0, cfile);
! 1535: parse_address_range (cfile, group, type,
! 1536: pool, &lpchain);
! 1537: break;
! 1538: case ALLOW:
! 1539: permit_head = &pool -> permit_list;
! 1540: /* remember the clause which leads to get_permit */
! 1541: is_allow = 1;
! 1542: get_permit:
! 1543: permit = new_permit (MDL);
! 1544: if (!permit)
! 1545: log_fatal ("no memory for permit");
! 1546: next_token (&val, (unsigned *)0, cfile);
! 1547: token = next_token (&val, (unsigned *)0, cfile);
! 1548: switch (token) {
! 1549: case UNKNOWN:
! 1550: permit -> type = permit_unknown_clients;
! 1551: get_clients:
! 1552: if (next_token (&val, (unsigned *)0,
! 1553: cfile) != CLIENTS) {
! 1554: parse_warn (cfile,
! 1555: "expecting \"clients\"");
! 1556: skip_to_semi (cfile);
! 1557: free_permit (permit, MDL);
! 1558: continue;
! 1559: }
! 1560: break;
! 1561:
! 1562: case KNOWN_CLIENTS:
! 1563: permit -> type = permit_known_clients;
! 1564: break;
! 1565:
! 1566: case UNKNOWN_CLIENTS:
! 1567: permit -> type = permit_unknown_clients;
! 1568: break;
! 1569:
! 1570: case KNOWN:
! 1571: permit -> type = permit_known_clients;
! 1572: goto get_clients;
! 1573:
! 1574: case AUTHENTICATED:
! 1575: permit -> type = permit_authenticated_clients;
! 1576: goto get_clients;
! 1577:
! 1578: case UNAUTHENTICATED:
! 1579: permit -> type =
! 1580: permit_unauthenticated_clients;
! 1581: goto get_clients;
! 1582:
! 1583: case ALL:
! 1584: permit -> type = permit_all_clients;
! 1585: goto get_clients;
! 1586: break;
! 1587:
! 1588: case DYNAMIC:
! 1589: permit -> type = permit_dynamic_bootp_clients;
! 1590: if (next_token (&val, (unsigned *)0,
! 1591: cfile) != TOKEN_BOOTP) {
! 1592: parse_warn (cfile,
! 1593: "expecting \"bootp\"");
! 1594: skip_to_semi (cfile);
! 1595: free_permit (permit, MDL);
! 1596: continue;
! 1597: }
! 1598: goto get_clients;
! 1599:
! 1600: case MEMBERS:
! 1601: if (next_token (&val, (unsigned *)0,
! 1602: cfile) != OF) {
! 1603: parse_warn (cfile, "expecting \"of\"");
! 1604: skip_to_semi (cfile);
! 1605: free_permit (permit, MDL);
! 1606: continue;
! 1607: }
! 1608: if (next_token (&val, (unsigned *)0,
! 1609: cfile) != STRING) {
! 1610: parse_warn (cfile,
! 1611: "expecting class name.");
! 1612: skip_to_semi (cfile);
! 1613: free_permit (permit, MDL);
! 1614: continue;
! 1615: }
! 1616: permit -> type = permit_class;
! 1617: permit -> class = (struct class *)0;
! 1618: find_class (&permit -> class, val, MDL);
! 1619: if (!permit -> class)
! 1620: parse_warn (cfile,
! 1621: "no such class: %s", val);
! 1622: break;
! 1623:
! 1624: case AFTER:
! 1625: if (pool->valid_from || pool->valid_until) {
! 1626: parse_warn(cfile,
! 1627: "duplicate \"after\" clause.");
! 1628: skip_to_semi(cfile);
! 1629: free_permit(permit, MDL);
! 1630: continue;
! 1631: }
! 1632: t = parse_date_core(cfile);
! 1633: permit->type = permit_after;
! 1634: permit->after = t;
! 1635: if (is_allow) {
! 1636: pool->valid_from = t;
! 1637: } else {
! 1638: pool->valid_until = t;
! 1639: }
! 1640: break;
! 1641:
! 1642: default:
! 1643: parse_warn (cfile, "expecting permit type.");
! 1644: skip_to_semi (cfile);
! 1645: break;
! 1646: }
! 1647: while (*permit_head)
! 1648: permit_head = &((*permit_head) -> next);
! 1649: *permit_head = permit;
! 1650: parse_semi (cfile);
! 1651: break;
! 1652:
! 1653: case DENY:
! 1654: permit_head = &pool -> prohibit_list;
! 1655: /* remember the clause which leads to get_permit */
! 1656: is_allow = 0;
! 1657: goto get_permit;
! 1658:
! 1659: case RBRACE:
! 1660: next_token (&val, (unsigned *)0, cfile);
! 1661: done = 1;
! 1662: break;
! 1663:
! 1664: case END_OF_FILE:
! 1665: /*
! 1666: * We can get to END_OF_FILE if, for instance,
! 1667: * the parse_statement() reads all available tokens
! 1668: * and leaves us at the end.
! 1669: */
! 1670: parse_warn(cfile, "unexpected end of file");
! 1671: goto cleanup;
! 1672:
! 1673: default:
! 1674: declaration = parse_statement (cfile, pool -> group,
! 1675: POOL_DECL,
! 1676: (struct host_decl *)0,
! 1677: declaration);
! 1678: break;
! 1679: }
! 1680: } while (!done);
! 1681:
! 1682: /* See if there's already a pool into which we can merge this one. */
! 1683: for (pp = pool -> shared_network -> pools; pp; pp = pp -> next) {
! 1684: if (pp -> group -> statements != pool -> group -> statements)
! 1685: continue;
! 1686: #if defined (FAILOVER_PROTOCOL)
! 1687: if (pool -> failover_peer != pp -> failover_peer)
! 1688: continue;
! 1689: #endif
! 1690: if (!permit_list_match (pp -> permit_list,
! 1691: pool -> permit_list) ||
! 1692: !permit_list_match (pool -> permit_list,
! 1693: pp -> permit_list) ||
! 1694: !permit_list_match (pp -> prohibit_list,
! 1695: pool -> prohibit_list) ||
! 1696: !permit_list_match (pool -> prohibit_list,
! 1697: pp -> prohibit_list))
! 1698: continue;
! 1699:
! 1700: /* Okay, we can merge these two pools. All we have to
! 1701: do is fix up the leases, which all point to their pool. */
! 1702: for (lp = lpchain; lp; lp = lp -> next) {
! 1703: pool_dereference (&lp -> pool, MDL);
! 1704: pool_reference (&lp -> pool, pp, MDL);
! 1705: }
! 1706: break;
! 1707: }
! 1708:
! 1709: /* If we didn't succeed in merging this pool into another, put
! 1710: it on the list. */
! 1711: if (!pp) {
! 1712: p = &pool -> shared_network -> pools;
! 1713: for (; *p; p = &((*p) -> next))
! 1714: ;
! 1715: pool_reference (p, pool, MDL);
! 1716: }
! 1717:
! 1718: /* Don't allow a pool declaration with no addresses, since it is
! 1719: probably a configuration error. */
! 1720: if (!lpchain) {
! 1721: parse_warn (cfile, "Pool declaration with no address range.");
! 1722: log_error ("Pool declarations must always contain at least");
! 1723: log_error ("one range statement.");
! 1724: }
! 1725:
! 1726: cleanup:
! 1727: /* Dereference the lease chain. */
! 1728: lp = (struct lease *)0;
! 1729: while (lpchain) {
! 1730: lease_reference (&lp, lpchain, MDL);
! 1731: lease_dereference (&lpchain, MDL);
! 1732: if (lp -> next) {
! 1733: lease_reference (&lpchain, lp -> next, MDL);
! 1734: lease_dereference (&lp -> next, MDL);
! 1735: lease_dereference (&lp, MDL);
! 1736: }
! 1737: }
! 1738: pool_dereference (&pool, MDL);
! 1739: }
! 1740:
! 1741: /* Expect a left brace; if there isn't one, skip over the rest of the
! 1742: statement and return zero; otherwise, return 1. */
! 1743:
! 1744: int parse_lbrace (cfile)
! 1745: struct parse *cfile;
! 1746: {
! 1747: enum dhcp_token token;
! 1748: const char *val;
! 1749:
! 1750: token = next_token (&val, (unsigned *)0, cfile);
! 1751: if (token != LBRACE) {
! 1752: parse_warn (cfile, "expecting left brace.");
! 1753: skip_to_semi (cfile);
! 1754: return 0;
! 1755: }
! 1756: return 1;
! 1757: }
! 1758:
! 1759:
! 1760: /* host-declaration :== hostname RBRACE parameters declarations LBRACE */
! 1761:
! 1762: void parse_host_declaration (cfile, group)
! 1763: struct parse *cfile;
! 1764: struct group *group;
! 1765: {
! 1766: const char *val;
! 1767: enum dhcp_token token;
! 1768: struct host_decl *host;
! 1769: char *name;
! 1770: int declaration = 0;
! 1771: int dynamicp = 0;
! 1772: int deleted = 0;
! 1773: isc_result_t status;
! 1774: int known;
! 1775: struct option *option;
! 1776: struct expression *expr = NULL;
! 1777:
! 1778: name = parse_host_name (cfile);
! 1779: if (!name) {
! 1780: parse_warn (cfile, "expecting a name for host declaration.");
! 1781: skip_to_semi (cfile);
! 1782: return;
! 1783: }
! 1784:
! 1785: host = (struct host_decl *)0;
! 1786: status = host_allocate (&host, MDL);
! 1787: if (status != ISC_R_SUCCESS)
! 1788: log_fatal ("can't allocate host decl struct %s: %s",
! 1789: name, isc_result_totext (status));
! 1790: host -> name = name;
! 1791: if (!clone_group (&host -> group, group, MDL)) {
! 1792: log_fatal ("can't clone group for host %s", name);
! 1793: boom:
! 1794: host_dereference (&host, MDL);
! 1795: return;
! 1796: }
! 1797:
! 1798: if (!parse_lbrace (cfile))
! 1799: goto boom;
! 1800:
! 1801: do {
! 1802: token = peek_token (&val, (unsigned *)0, cfile);
! 1803: if (token == RBRACE) {
! 1804: token = next_token (&val, (unsigned *)0, cfile);
! 1805: break;
! 1806: }
! 1807: if (token == END_OF_FILE) {
! 1808: token = next_token (&val, (unsigned *)0, cfile);
! 1809: parse_warn (cfile, "unexpected end of file");
! 1810: break;
! 1811: }
! 1812: /* If the host declaration was created by the server,
! 1813: remember to save it. */
! 1814: if (token == DYNAMIC) {
! 1815: dynamicp = 1;
! 1816: token = next_token (&val, (unsigned *)0, cfile);
! 1817: if (!parse_semi (cfile))
! 1818: break;
! 1819: continue;
! 1820: }
! 1821: /* If the host declaration was created by the server,
! 1822: remember to save it. */
! 1823: if (token == TOKEN_DELETED) {
! 1824: deleted = 1;
! 1825: token = next_token (&val, (unsigned *)0, cfile);
! 1826: if (!parse_semi (cfile))
! 1827: break;
! 1828: continue;
! 1829: }
! 1830:
! 1831: if (token == GROUP) {
! 1832: struct group_object *go;
! 1833: token = next_token (&val, (unsigned *)0, cfile);
! 1834: token = next_token (&val, (unsigned *)0, cfile);
! 1835: if (token != STRING && !is_identifier (token)) {
! 1836: parse_warn (cfile,
! 1837: "expecting string or identifier.");
! 1838: skip_to_rbrace (cfile, 1);
! 1839: break;
! 1840: }
! 1841: go = (struct group_object *)0;
! 1842: if (!group_hash_lookup (&go, group_name_hash,
! 1843: val, strlen (val), MDL)) {
! 1844: parse_warn (cfile, "unknown group %s in host %s",
! 1845: val, host -> name);
! 1846: } else {
! 1847: if (host -> named_group)
! 1848: group_object_dereference
! 1849: (&host -> named_group, MDL);
! 1850: group_object_reference (&host -> named_group,
! 1851: go, MDL);
! 1852: group_object_dereference (&go, MDL);
! 1853: }
! 1854: if (!parse_semi (cfile))
! 1855: break;
! 1856: continue;
! 1857: }
! 1858:
! 1859: if (token == UID) {
! 1860: const char *s;
! 1861: unsigned char *t = 0;
! 1862: unsigned len;
! 1863:
! 1864: token = next_token (&val, (unsigned *)0, cfile);
! 1865: data_string_forget (&host -> client_identifier, MDL);
! 1866:
! 1867: if (host->client_identifier.len != 0) {
! 1868: parse_warn(cfile, "Host %s already has a "
! 1869: "client identifier.",
! 1870: host->name);
! 1871: break;
! 1872: }
! 1873:
! 1874: /* See if it's a string or a cshl. */
! 1875: token = peek_token (&val, (unsigned *)0, cfile);
! 1876: if (token == STRING) {
! 1877: token = next_token (&val, &len, cfile);
! 1878: s = val;
! 1879: host -> client_identifier.terminated = 1;
! 1880: } else {
! 1881: len = 0;
! 1882: t = parse_numeric_aggregate
! 1883: (cfile,
! 1884: (unsigned char *)0, &len, ':', 16, 8);
! 1885: if (!t) {
! 1886: parse_warn (cfile,
! 1887: "expecting hex list.");
! 1888: skip_to_semi (cfile);
! 1889: }
! 1890: s = (const char *)t;
! 1891: }
! 1892: if (!buffer_allocate
! 1893: (&host -> client_identifier.buffer,
! 1894: len + host -> client_identifier.terminated, MDL))
! 1895: log_fatal ("no memory for uid for host %s.",
! 1896: host -> name);
! 1897: host -> client_identifier.data =
! 1898: host -> client_identifier.buffer -> data;
! 1899: host -> client_identifier.len = len;
! 1900: memcpy (host -> client_identifier.buffer -> data, s,
! 1901: len + host -> client_identifier.terminated);
! 1902: if (t)
! 1903: dfree (t, MDL);
! 1904:
! 1905: if (!parse_semi (cfile))
! 1906: break;
! 1907: continue;
! 1908: }
! 1909:
! 1910: if (token == HOST_IDENTIFIER) {
! 1911: if (host->host_id_option != NULL) {
! 1912: parse_warn(cfile,
! 1913: "only one host-identifier allowed "
! 1914: "per host");
! 1915: skip_to_rbrace(cfile, 1);
! 1916: break;
! 1917: }
! 1918: next_token(&val, NULL, cfile);
! 1919: token = next_token(&val, NULL, cfile);
! 1920: if (token != OPTION) {
! 1921: parse_warn(cfile,
! 1922: "host-identifier must be an option");
! 1923: skip_to_rbrace(cfile, 1);
! 1924: break;
! 1925: }
! 1926: known = 0;
! 1927: option = NULL;
! 1928: status = parse_option_name(cfile, 1, &known, &option);
! 1929: if ((status != ISC_R_SUCCESS) || (option == NULL)) {
! 1930: break;
! 1931: }
! 1932: if (!known) {
! 1933: parse_warn(cfile, "unknown option %s.%s",
! 1934: option->universe->name,
! 1935: option->name);
! 1936: skip_to_rbrace(cfile, 1);
! 1937: break;
! 1938: }
! 1939:
! 1940: if (! parse_option_data(&expr, cfile, 1, option)) {
! 1941: skip_to_rbrace(cfile, 1);
! 1942: option_dereference(&option, MDL);
! 1943: break;
! 1944: }
! 1945:
! 1946: if (!parse_semi(cfile)) {
! 1947: skip_to_rbrace(cfile, 1);
! 1948: expression_dereference(&expr, MDL);
! 1949: option_dereference(&option, MDL);
! 1950: break;
! 1951: }
! 1952:
! 1953: option_reference(&host->host_id_option, option, MDL);
! 1954: option_dereference(&option, MDL);
! 1955: data_string_copy(&host->host_id,
! 1956: &expr->data.const_data, MDL);
! 1957: expression_dereference(&expr, MDL);
! 1958: continue;
! 1959: }
! 1960:
! 1961: declaration = parse_statement(cfile, host->group, HOST_DECL,
! 1962: host, declaration);
! 1963: } while (1);
! 1964:
! 1965: if (deleted) {
! 1966: struct host_decl *hp = (struct host_decl *)0;
! 1967: if (host_hash_lookup (&hp, host_name_hash,
! 1968: (unsigned char *)host -> name,
! 1969: strlen (host -> name), MDL)) {
! 1970: delete_host (hp, 0);
! 1971: host_dereference (&hp, MDL);
! 1972: }
! 1973: } else {
! 1974: if (host -> named_group && host -> named_group -> group) {
! 1975: if (host -> group -> statements ||
! 1976: (host -> group -> authoritative !=
! 1977: host -> named_group -> group -> authoritative)) {
! 1978: if (host -> group -> next)
! 1979: group_dereference (&host -> group -> next,
! 1980: MDL);
! 1981: group_reference (&host -> group -> next,
! 1982: host -> named_group -> group,
! 1983: MDL);
! 1984: } else {
! 1985: group_dereference (&host -> group, MDL);
! 1986: group_reference (&host -> group,
! 1987: host -> named_group -> group,
! 1988: MDL);
! 1989: }
! 1990: }
! 1991:
! 1992: if (dynamicp)
! 1993: host -> flags |= HOST_DECL_DYNAMIC;
! 1994: else
! 1995: host -> flags |= HOST_DECL_STATIC;
! 1996:
! 1997: status = enter_host (host, dynamicp, 0);
! 1998: if (status != ISC_R_SUCCESS)
! 1999: parse_warn (cfile, "host %s: %s", host -> name,
! 2000: isc_result_totext (status));
! 2001: }
! 2002: host_dereference (&host, MDL);
! 2003: }
! 2004:
! 2005: /* class-declaration :== STRING LBRACE parameters declarations RBRACE
! 2006: */
! 2007:
! 2008: int parse_class_declaration (cp, cfile, group, type)
! 2009: struct class **cp;
! 2010: struct parse *cfile;
! 2011: struct group *group;
! 2012: int type;
! 2013: {
! 2014: const char *val;
! 2015: enum dhcp_token token;
! 2016: struct class *class = (struct class *)0, *pc = (struct class *)0;
! 2017: int declaration = 0;
! 2018: int lose = 0;
! 2019: struct data_string data;
! 2020: char *name;
! 2021: const char *tname;
! 2022: struct executable_statement *stmt = (struct executable_statement *)0;
! 2023: int new = 1;
! 2024: isc_result_t status = ISC_R_FAILURE;
! 2025: int matchedonce = 0;
! 2026: int submatchedonce = 0;
! 2027: unsigned code;
! 2028:
! 2029: if (dhcpv6_class_once && local_family == AF_INET6) {
! 2030: dhcpv6_class_once = 0;
! 2031: log_error("WARNING: class declarations are not supported "
! 2032: "for DHCPv6.");
! 2033: }
! 2034:
! 2035: token = next_token (&val, (unsigned *)0, cfile);
! 2036: if (token != STRING) {
! 2037: parse_warn (cfile, "Expecting class name");
! 2038: skip_to_semi (cfile);
! 2039: return 0;
! 2040: }
! 2041:
! 2042: /* See if there's already a class with the specified name. */
! 2043: find_class (&pc, val, MDL);
! 2044:
! 2045: /* If it is a class, we're updating it. If it's any of the other
! 2046: * types (subclass, vendor or user class), the named class is a
! 2047: * reference to the parent class so its mandatory.
! 2048: */
! 2049: if (pc && (type == CLASS_TYPE_CLASS)) {
! 2050: class_reference(&class, pc, MDL);
! 2051: new = 0;
! 2052: class_dereference(&pc, MDL);
! 2053: } else if (!pc && (type != CLASS_TYPE_CLASS)) {
! 2054: parse_warn(cfile, "no class named %s", val);
! 2055: skip_to_semi(cfile);
! 2056: return 0;
! 2057: }
! 2058:
! 2059: /* The old vendor-class and user-class declarations had an implicit
! 2060: match. We don't do the implicit match anymore. Instead, for
! 2061: backward compatibility, we have an implicit-vendor-class and an
! 2062: implicit-user-class. vendor-class and user-class declarations
! 2063: are turned into subclasses of the implicit classes, and the
! 2064: submatch expression of the implicit classes extracts the contents of
! 2065: the vendor class or user class. */
! 2066: if ((type == CLASS_TYPE_VENDOR) || (type == CLASS_TYPE_USER)) {
! 2067: data.len = strlen (val);
! 2068: data.buffer = (struct buffer *)0;
! 2069: if (!buffer_allocate (&data.buffer, data.len + 1, MDL))
! 2070: log_fatal ("no memory for class name.");
! 2071: data.data = &data.buffer -> data [0];
! 2072: data.terminated = 1;
! 2073:
! 2074: tname = type ? "implicit-vendor-class" : "implicit-user-class";
! 2075: } else if (type == CLASS_TYPE_CLASS) {
! 2076: tname = val;
! 2077: } else {
! 2078: tname = (const char *)0;
! 2079: }
! 2080:
! 2081: if (tname) {
! 2082: name = dmalloc (strlen (tname) + 1, MDL);
! 2083: if (!name)
! 2084: log_fatal ("No memory for class name %s.", tname);
! 2085: strcpy (name, val);
! 2086: } else
! 2087: name = (char *)0;
! 2088:
! 2089: /* If this is a straight subclass, parse the hash string. */
! 2090: if (type == CLASS_TYPE_SUBCLASS) {
! 2091: token = peek_token (&val, (unsigned *)0, cfile);
! 2092: if (token == STRING) {
! 2093: token = next_token (&val, &data.len, cfile);
! 2094: data.buffer = (struct buffer *)0;
! 2095: if (!buffer_allocate (&data.buffer,
! 2096: data.len + 1, MDL)) {
! 2097: if (pc)
! 2098: class_dereference (&pc, MDL);
! 2099:
! 2100: return 0;
! 2101: }
! 2102: data.terminated = 1;
! 2103: data.data = &data.buffer -> data [0];
! 2104: memcpy ((char *)data.buffer -> data, val,
! 2105: data.len + 1);
! 2106: } else if (token == NUMBER_OR_NAME || token == NUMBER) {
! 2107: memset (&data, 0, sizeof data);
! 2108: if (!parse_cshl (&data, cfile)) {
! 2109: if (pc)
! 2110: class_dereference (&pc, MDL);
! 2111: return 0;
! 2112: }
! 2113: } else {
! 2114: parse_warn (cfile, "Expecting string or hex list.");
! 2115: if (pc)
! 2116: class_dereference (&pc, MDL);
! 2117: return 0;
! 2118: }
! 2119: }
! 2120:
! 2121: /* See if there's already a class in the hash table matching the
! 2122: hash data. */
! 2123: if (type != CLASS_TYPE_CLASS)
! 2124: class_hash_lookup (&class, pc -> hash,
! 2125: (const char *)data.data, data.len, MDL);
! 2126:
! 2127: /* If we didn't find an existing class, allocate a new one. */
! 2128: if (!class) {
! 2129: /* Allocate the class structure... */
! 2130: status = class_allocate (&class, MDL);
! 2131: if (pc) {
! 2132: group_reference (&class -> group, pc -> group, MDL);
! 2133: class_reference (&class -> superclass, pc, MDL);
! 2134: class -> lease_limit = pc -> lease_limit;
! 2135: if (class -> lease_limit) {
! 2136: class -> billed_leases =
! 2137: dmalloc (class -> lease_limit *
! 2138: sizeof (struct lease *), MDL);
! 2139: if (!class -> billed_leases)
! 2140: log_fatal ("no memory for billing");
! 2141: memset (class -> billed_leases, 0,
! 2142: (class -> lease_limit *
! 2143: sizeof class -> billed_leases));
! 2144: }
! 2145: data_string_copy (&class -> hash_string, &data, MDL);
! 2146: if (!pc -> hash &&
! 2147: !class_new_hash (&pc->hash, SCLASS_HASH_SIZE, MDL))
! 2148: log_fatal ("No memory for subclass hash.");
! 2149: class_hash_add (pc -> hash,
! 2150: (const char *)class -> hash_string.data,
! 2151: class -> hash_string.len,
! 2152: (void *)class, MDL);
! 2153: } else {
! 2154: if (class->group)
! 2155: group_dereference(&class->group, MDL);
! 2156: if (!clone_group (&class -> group, group, MDL))
! 2157: log_fatal ("no memory to clone class group.");
! 2158: }
! 2159:
! 2160: /* If this is an implicit vendor or user class, add a
! 2161: statement that causes the vendor or user class ID to
! 2162: be sent back in the reply. */
! 2163: if (type == CLASS_TYPE_VENDOR || type == CLASS_TYPE_USER) {
! 2164: stmt = (struct executable_statement *)0;
! 2165: if (!executable_statement_allocate (&stmt, MDL))
! 2166: log_fatal ("no memory for class statement.");
! 2167: stmt -> op = supersede_option_statement;
! 2168: if (option_cache_allocate (&stmt -> data.option,
! 2169: MDL)) {
! 2170: stmt -> data.option -> data = data;
! 2171: code = (type == CLASS_TYPE_VENDOR)
! 2172: ? DHO_VENDOR_CLASS_IDENTIFIER
! 2173: : DHO_USER_CLASS;
! 2174: option_code_hash_lookup(
! 2175: &stmt->data.option->option,
! 2176: dhcp_universe.code_hash,
! 2177: &code, 0, MDL);
! 2178: }
! 2179: class -> statements = stmt;
! 2180: }
! 2181:
! 2182: /* Save the name, if there is one. */
! 2183: if (class->name != NULL)
! 2184: dfree(class->name, MDL);
! 2185: class->name = name;
! 2186: }
! 2187:
! 2188: if (type != CLASS_TYPE_CLASS)
! 2189: data_string_forget(&data, MDL);
! 2190:
! 2191: /* Spawned classes don't have to have their own settings. */
! 2192: if (class -> superclass) {
! 2193: token = peek_token (&val, (unsigned *)0, cfile);
! 2194: if (token == SEMI) {
! 2195: next_token (&val, (unsigned *)0, cfile);
! 2196: if (cp)
! 2197: status = class_reference (cp, class, MDL);
! 2198: class_dereference (&class, MDL);
! 2199: if (pc)
! 2200: class_dereference (&pc, MDL);
! 2201: return cp ? (status == ISC_R_SUCCESS) : 1;
! 2202: }
! 2203: /* Give the subclass its own group. */
! 2204: if (!clone_group (&class -> group, class -> group, MDL))
! 2205: log_fatal ("can't clone class group.");
! 2206:
! 2207: }
! 2208:
! 2209: if (!parse_lbrace (cfile)) {
! 2210: class_dereference (&class, MDL);
! 2211: if (pc)
! 2212: class_dereference (&pc, MDL);
! 2213: return 0;
! 2214: }
! 2215:
! 2216: do {
! 2217: token = peek_token (&val, (unsigned *)0, cfile);
! 2218: if (token == RBRACE) {
! 2219: token = next_token (&val, (unsigned *)0, cfile);
! 2220: break;
! 2221: } else if (token == END_OF_FILE) {
! 2222: token = next_token (&val, (unsigned *)0, cfile);
! 2223: parse_warn (cfile, "unexpected end of file");
! 2224: break;
! 2225: } else if (token == DYNAMIC) {
! 2226: class->flags |= CLASS_DECL_DYNAMIC;
! 2227: token = next_token (&val, (unsigned *)0, cfile);
! 2228: if (!parse_semi (cfile))
! 2229: break;
! 2230: continue;
! 2231: } else if (token == TOKEN_DELETED) {
! 2232: class->flags |= CLASS_DECL_DELETED;
! 2233: token = next_token (&val, (unsigned *)0, cfile);
! 2234: if (!parse_semi (cfile))
! 2235: break;
! 2236: continue;
! 2237: } else if (token == MATCH) {
! 2238: if (pc) {
! 2239: parse_warn (cfile,
! 2240: "invalid match in subclass.");
! 2241: skip_to_semi (cfile);
! 2242: break;
! 2243: }
! 2244: token = next_token (&val, (unsigned *)0, cfile);
! 2245: token = peek_token (&val, (unsigned *)0, cfile);
! 2246: if (token != IF)
! 2247: goto submatch;
! 2248: token = next_token (&val, (unsigned *)0, cfile);
! 2249: if (matchedonce) {
! 2250: parse_warn(cfile, "A class may only have "
! 2251: "one 'match if' clause.");
! 2252: skip_to_semi(cfile);
! 2253: break;
! 2254: }
! 2255: matchedonce = 1;
! 2256: if (class->expr)
! 2257: expression_dereference(&class->expr, MDL);
! 2258: if (!parse_boolean_expression (&class->expr, cfile,
! 2259: &lose)) {
! 2260: if (!lose) {
! 2261: parse_warn (cfile,
! 2262: "expecting boolean expr.");
! 2263: skip_to_semi (cfile);
! 2264: }
! 2265: } else {
! 2266: #if defined (DEBUG_EXPRESSION_PARSE)
! 2267: print_expression ("class match",
! 2268: class -> expr);
! 2269: #endif
! 2270: parse_semi (cfile);
! 2271: }
! 2272: } else if (token == SPAWN) {
! 2273: token = next_token (&val, (unsigned *)0, cfile);
! 2274: if (pc) {
! 2275: parse_warn (cfile,
! 2276: "invalid spawn in subclass.");
! 2277: skip_to_semi (cfile);
! 2278: break;
! 2279: }
! 2280: class -> spawning = 1;
! 2281: token = next_token (&val, (unsigned *)0, cfile);
! 2282: if (token != WITH) {
! 2283: parse_warn (cfile,
! 2284: "expecting with after spawn");
! 2285: skip_to_semi (cfile);
! 2286: break;
! 2287: }
! 2288: submatch:
! 2289: if (submatchedonce) {
! 2290: parse_warn (cfile,
! 2291: "can't override existing %s.",
! 2292: "submatch/spawn");
! 2293: skip_to_semi (cfile);
! 2294: break;
! 2295: }
! 2296: submatchedonce = 1;
! 2297: if (class->submatch)
! 2298: expression_dereference(&class->submatch, MDL);
! 2299: if (!parse_data_expression (&class -> submatch,
! 2300: cfile, &lose)) {
! 2301: if (!lose) {
! 2302: parse_warn (cfile,
! 2303: "expecting data expr.");
! 2304: skip_to_semi (cfile);
! 2305: }
! 2306: } else {
! 2307: #if defined (DEBUG_EXPRESSION_PARSE)
! 2308: print_expression ("class submatch",
! 2309: class -> submatch);
! 2310: #endif
! 2311: parse_semi (cfile);
! 2312: }
! 2313: } else if (token == LEASE) {
! 2314: next_token (&val, (unsigned *)0, cfile);
! 2315: token = next_token (&val, (unsigned *)0, cfile);
! 2316: if (token != LIMIT) {
! 2317: parse_warn (cfile, "expecting \"limit\"");
! 2318: if (token != SEMI)
! 2319: skip_to_semi (cfile);
! 2320: break;
! 2321: }
! 2322: token = next_token (&val, (unsigned *)0, cfile);
! 2323: if (token != NUMBER) {
! 2324: parse_warn (cfile, "expecting a number");
! 2325: if (token != SEMI)
! 2326: skip_to_semi (cfile);
! 2327: break;
! 2328: }
! 2329: class -> lease_limit = atoi (val);
! 2330: if (class->billed_leases)
! 2331: dfree(class->billed_leases, MDL);
! 2332: class -> billed_leases =
! 2333: dmalloc (class -> lease_limit *
! 2334: sizeof (struct lease *), MDL);
! 2335: if (!class -> billed_leases)
! 2336: log_fatal ("no memory for billed leases.");
! 2337: memset (class -> billed_leases, 0,
! 2338: (class -> lease_limit *
! 2339: sizeof class -> billed_leases));
! 2340: have_billing_classes = 1;
! 2341: parse_semi (cfile);
! 2342: } else {
! 2343: declaration = parse_statement (cfile, class -> group,
! 2344: CLASS_DECL,
! 2345: (struct host_decl *)0,
! 2346: declaration);
! 2347: }
! 2348: } while (1);
! 2349:
! 2350: if (class->flags & CLASS_DECL_DELETED) {
! 2351: if (type == CLASS_TYPE_CLASS) {
! 2352: struct class *theclass = NULL;
! 2353:
! 2354: status = find_class(&theclass, class->name, MDL);
! 2355: if (status == ISC_R_SUCCESS) {
! 2356: delete_class(theclass, 0);
! 2357: class_dereference(&theclass, MDL);
! 2358: }
! 2359: } else {
! 2360: class_hash_delete(pc->hash,
! 2361: (char *)class->hash_string.data,
! 2362: class->hash_string.len, MDL);
! 2363: }
! 2364: } else if (type == CLASS_TYPE_CLASS && new) {
! 2365: if (!collections -> classes)
! 2366: class_reference (&collections -> classes, class, MDL);
! 2367: else {
! 2368: struct class *c;
! 2369: for (c = collections -> classes;
! 2370: c -> nic; c = c -> nic)
! 2371: ;
! 2372: class_reference (&c -> nic, class, MDL);
! 2373: }
! 2374: }
! 2375:
! 2376: if (cp) /* should always be 0??? */
! 2377: status = class_reference (cp, class, MDL);
! 2378: class_dereference (&class, MDL);
! 2379: if (pc)
! 2380: class_dereference (&pc, MDL);
! 2381: return cp ? (status == ISC_R_SUCCESS) : 1;
! 2382: }
! 2383:
! 2384: /* shared-network-declaration :==
! 2385: hostname LBRACE declarations parameters RBRACE */
! 2386:
! 2387: void parse_shared_net_declaration (cfile, group)
! 2388: struct parse *cfile;
! 2389: struct group *group;
! 2390: {
! 2391: const char *val;
! 2392: enum dhcp_token token;
! 2393: struct shared_network *share;
! 2394: char *name;
! 2395: int declaration = 0;
! 2396: isc_result_t status;
! 2397:
! 2398: share = (struct shared_network *)0;
! 2399: status = shared_network_allocate (&share, MDL);
! 2400: if (status != ISC_R_SUCCESS)
! 2401: log_fatal ("Can't allocate shared subnet: %s",
! 2402: isc_result_totext (status));
! 2403: clone_group (&share -> group, group, MDL);
! 2404: shared_network_reference (&share -> group -> shared_network,
! 2405: share, MDL);
! 2406:
! 2407: /* Get the name of the shared network... */
! 2408: token = peek_token (&val, (unsigned *)0, cfile);
! 2409: if (token == STRING) {
! 2410: token = next_token (&val, (unsigned *)0, cfile);
! 2411:
! 2412: if (val [0] == 0) {
! 2413: parse_warn (cfile, "zero-length shared network name");
! 2414: val = "<no-name-given>";
! 2415: }
! 2416: name = dmalloc (strlen (val) + 1, MDL);
! 2417: if (!name)
! 2418: log_fatal ("no memory for shared network name");
! 2419: strcpy (name, val);
! 2420: } else {
! 2421: name = parse_host_name (cfile);
! 2422: if (!name) {
! 2423: parse_warn (cfile,
! 2424: "expecting a name for shared-network");
! 2425: skip_to_semi (cfile);
! 2426: shared_network_dereference (&share, MDL);
! 2427: return;
! 2428: }
! 2429: }
! 2430: share -> name = name;
! 2431:
! 2432: if (!parse_lbrace (cfile)) {
! 2433: shared_network_dereference (&share, MDL);
! 2434: return;
! 2435: }
! 2436:
! 2437: do {
! 2438: token = peek_token (&val, (unsigned *)0, cfile);
! 2439: if (token == RBRACE) {
! 2440: token = next_token (&val, (unsigned *)0, cfile);
! 2441: if (!share -> subnets)
! 2442: parse_warn (cfile,
! 2443: "empty shared-network decl");
! 2444: else
! 2445: enter_shared_network (share);
! 2446: shared_network_dereference (&share, MDL);
! 2447: return;
! 2448: } else if (token == END_OF_FILE) {
! 2449: token = next_token (&val, (unsigned *)0, cfile);
! 2450: parse_warn (cfile, "unexpected end of file");
! 2451: break;
! 2452: } else if (token == INTERFACE) {
! 2453: token = next_token (&val, (unsigned *)0, cfile);
! 2454: token = next_token (&val, (unsigned *)0, cfile);
! 2455: new_shared_network_interface (cfile, share, val);
! 2456: if (!parse_semi (cfile))
! 2457: break;
! 2458: continue;
! 2459: }
! 2460:
! 2461: declaration = parse_statement (cfile, share -> group,
! 2462: SHARED_NET_DECL,
! 2463: (struct host_decl *)0,
! 2464: declaration);
! 2465: } while (1);
! 2466: shared_network_dereference (&share, MDL);
! 2467: }
! 2468:
! 2469:
! 2470: static int
! 2471: common_subnet_parsing(struct parse *cfile,
! 2472: struct shared_network *share,
! 2473: struct subnet *subnet) {
! 2474: enum dhcp_token token;
! 2475: struct subnet *t, *u;
! 2476: const char *val;
! 2477: int declaration = 0;
! 2478:
! 2479: enter_subnet(subnet);
! 2480:
! 2481: if (!parse_lbrace(cfile)) {
! 2482: subnet_dereference(&subnet, MDL);
! 2483: return 0;
! 2484: }
! 2485:
! 2486: do {
! 2487: token = peek_token(&val, NULL, cfile);
! 2488: if (token == RBRACE) {
! 2489: token = next_token(&val, NULL, cfile);
! 2490: break;
! 2491: } else if (token == END_OF_FILE) {
! 2492: token = next_token(&val, NULL, cfile);
! 2493: parse_warn (cfile, "unexpected end of file");
! 2494: break;
! 2495: } else if (token == INTERFACE) {
! 2496: token = next_token(&val, NULL, cfile);
! 2497: token = next_token(&val, NULL, cfile);
! 2498: new_shared_network_interface(cfile, share, val);
! 2499: if (!parse_semi(cfile))
! 2500: break;
! 2501: continue;
! 2502: }
! 2503: declaration = parse_statement(cfile, subnet->group,
! 2504: SUBNET_DECL,
! 2505: NULL,
! 2506: declaration);
! 2507: } while (1);
! 2508:
! 2509: /* Add the subnet to the list of subnets in this shared net. */
! 2510: if (share->subnets == NULL) {
! 2511: subnet_reference(&share->subnets, subnet, MDL);
! 2512: } else {
! 2513: u = NULL;
! 2514: for (t = share->subnets; t->next_sibling; t = t->next_sibling) {
! 2515: if (subnet_inner_than(subnet, t, 0)) {
! 2516: subnet_reference(&subnet->next_sibling, t, MDL);
! 2517: if (u) {
! 2518: subnet_dereference(&u->next_sibling,
! 2519: MDL);
! 2520: subnet_reference(&u->next_sibling,
! 2521: subnet, MDL);
! 2522: } else {
! 2523: subnet_dereference(&share->subnets,
! 2524: MDL);
! 2525: subnet_reference(&share->subnets,
! 2526: subnet, MDL);
! 2527: }
! 2528: subnet_dereference(&subnet, MDL);
! 2529: return 1;
! 2530: }
! 2531: u = t;
! 2532: }
! 2533: subnet_reference(&t->next_sibling, subnet, MDL);
! 2534: }
! 2535: subnet_dereference(&subnet, MDL);
! 2536: return 1;
! 2537: }
! 2538:
! 2539: /* subnet-declaration :==
! 2540: net NETMASK netmask RBRACE parameters declarations LBRACE */
! 2541:
! 2542: void parse_subnet_declaration (cfile, share)
! 2543: struct parse *cfile;
! 2544: struct shared_network *share;
! 2545: {
! 2546: const char *val;
! 2547: enum dhcp_token token;
! 2548: struct subnet *subnet;
! 2549: struct iaddr iaddr;
! 2550: unsigned char addr [4];
! 2551: unsigned len = sizeof addr;
! 2552: isc_result_t status;
! 2553:
! 2554: subnet = (struct subnet *)0;
! 2555: status = subnet_allocate (&subnet, MDL);
! 2556: if (status != ISC_R_SUCCESS)
! 2557: log_fatal ("Allocation of new subnet failed: %s",
! 2558: isc_result_totext (status));
! 2559: shared_network_reference (&subnet -> shared_network, share, MDL);
! 2560:
! 2561: /*
! 2562: * If our parent shared network was implicitly created by the software,
! 2563: * and not explicitly configured by the user, then we actually put all
! 2564: * configuration scope in the parent (the shared network and subnet
! 2565: * share the same {}-level scope).
! 2566: *
! 2567: * Otherwise, we clone the parent group and continue as normal.
! 2568: */
! 2569: if (share->flags & SHARED_IMPLICIT) {
! 2570: group_reference(&subnet->group, share->group, MDL);
! 2571: } else {
! 2572: if (!clone_group(&subnet->group, share->group, MDL)) {
! 2573: log_fatal("Allocation of group for new subnet failed.");
! 2574: }
! 2575: }
! 2576: subnet_reference (&subnet -> group -> subnet, subnet, MDL);
! 2577:
! 2578: /* Get the network number... */
! 2579: if (!parse_numeric_aggregate (cfile, addr, &len, DOT, 10, 8)) {
! 2580: subnet_dereference (&subnet, MDL);
! 2581: return;
! 2582: }
! 2583: memcpy (iaddr.iabuf, addr, len);
! 2584: iaddr.len = len;
! 2585: subnet -> net = iaddr;
! 2586:
! 2587: token = next_token (&val, (unsigned *)0, cfile);
! 2588: if (token != NETMASK) {
! 2589: parse_warn (cfile, "Expecting netmask");
! 2590: skip_to_semi (cfile);
! 2591: return;
! 2592: }
! 2593:
! 2594: /* Get the netmask... */
! 2595: if (!parse_numeric_aggregate (cfile, addr, &len, DOT, 10, 8)) {
! 2596: subnet_dereference (&subnet, MDL);
! 2597: return;
! 2598: }
! 2599: memcpy (iaddr.iabuf, addr, len);
! 2600: iaddr.len = len;
! 2601: subnet -> netmask = iaddr;
! 2602:
! 2603: /* Validate the network number/netmask pair. */
! 2604: if (host_addr (subnet -> net, subnet -> netmask)) {
! 2605: char *maskstr;
! 2606:
! 2607: maskstr = strdup (piaddr (subnet -> netmask));
! 2608: parse_warn (cfile,
! 2609: "subnet %s netmask %s: bad subnet number/mask combination.",
! 2610: piaddr (subnet -> net), maskstr);
! 2611: free(maskstr);
! 2612: subnet_dereference (&subnet, MDL);
! 2613: skip_to_semi (cfile);
! 2614: return;
! 2615: }
! 2616:
! 2617: common_subnet_parsing(cfile, share, subnet);
! 2618: }
! 2619:
! 2620: /* subnet6-declaration :==
! 2621: net / bits RBRACE parameters declarations LBRACE */
! 2622:
! 2623: void
! 2624: parse_subnet6_declaration(struct parse *cfile, struct shared_network *share) {
! 2625: #if !defined(DHCPv6)
! 2626: parse_warn(cfile, "No DHCPv6 support.");
! 2627: skip_to_semi(cfile);
! 2628: #else /* defined(DHCPv6) */
! 2629: struct subnet *subnet;
! 2630: isc_result_t status;
! 2631: enum dhcp_token token;
! 2632: const char *val;
! 2633: char *endp;
! 2634: int ofs;
! 2635: const static int mask[] = { 0x00, 0x80, 0xC0, 0xE0,
! 2636: 0xF0, 0xF8, 0xFC, 0xFE };
! 2637: struct iaddr iaddr;
! 2638:
! 2639: if (local_family != AF_INET6) {
! 2640: parse_warn(cfile, "subnet6 statement is only supported "
! 2641: "in DHCPv6 mode.");
! 2642: skip_to_semi(cfile);
! 2643: return;
! 2644: }
! 2645:
! 2646: subnet = NULL;
! 2647: status = subnet_allocate(&subnet, MDL);
! 2648: if (status != ISC_R_SUCCESS) {
! 2649: log_fatal("Allocation of new subnet failed: %s",
! 2650: isc_result_totext(status));
! 2651: }
! 2652: shared_network_reference(&subnet->shared_network, share, MDL);
! 2653:
! 2654: /*
! 2655: * If our parent shared network was implicitly created by the software,
! 2656: * and not explicitly configured by the user, then we actually put all
! 2657: * configuration scope in the parent (the shared network and subnet
! 2658: * share the same {}-level scope).
! 2659: *
! 2660: * Otherwise, we clone the parent group and continue as normal.
! 2661: */
! 2662: if (share->flags & SHARED_IMPLICIT) {
! 2663: group_reference(&subnet->group, share->group, MDL);
! 2664: } else {
! 2665: if (!clone_group(&subnet->group, share->group, MDL)) {
! 2666: log_fatal("Allocation of group for new subnet failed.");
! 2667: }
! 2668: }
! 2669: subnet_reference(&subnet->group->subnet, subnet, MDL);
! 2670:
! 2671: if (!parse_ip6_addr(cfile, &subnet->net)) {
! 2672: subnet_dereference(&subnet, MDL);
! 2673: return;
! 2674: }
! 2675:
! 2676: token = next_token(&val, NULL, cfile);
! 2677: if (token != SLASH) {
! 2678: parse_warn(cfile, "Expecting a '/'.");
! 2679: skip_to_semi(cfile);
! 2680: return;
! 2681: }
! 2682:
! 2683: token = next_token(&val, NULL, cfile);
! 2684: if (token != NUMBER) {
! 2685: parse_warn(cfile, "Expecting a number.");
! 2686: skip_to_semi(cfile);
! 2687: return;
! 2688: }
! 2689:
! 2690: subnet->prefix_len = strtol(val, &endp, 10);
! 2691: if ((subnet->prefix_len < 0) ||
! 2692: (subnet->prefix_len > 128) ||
! 2693: (*endp != '\0')) {
! 2694: parse_warn(cfile, "Expecting a number between 0 and 128.");
! 2695: skip_to_semi(cfile);
! 2696: return;
! 2697: }
! 2698:
! 2699: if (!is_cidr_mask_valid(&subnet->net, subnet->prefix_len)) {
! 2700: parse_warn(cfile, "New subnet mask too short.");
! 2701: skip_to_semi(cfile);
! 2702: return;
! 2703: }
! 2704:
! 2705: /*
! 2706: * Create a netmask.
! 2707: */
! 2708: subnet->netmask.len = 16;
! 2709: ofs = subnet->prefix_len / 8;
! 2710: if (ofs < subnet->netmask.len) {
! 2711: subnet->netmask.iabuf[ofs] = mask[subnet->prefix_len % 8];
! 2712: }
! 2713: while (--ofs >= 0) {
! 2714: subnet->netmask.iabuf[ofs] = 0xFF;
! 2715: }
! 2716:
! 2717: /* Validate the network number/netmask pair. */
! 2718: iaddr = subnet_number(subnet->net, subnet->netmask);
! 2719: if (memcmp(&iaddr, &subnet->net, 16) != 0) {
! 2720: parse_warn(cfile,
! 2721: "subnet %s/%d: prefix not long enough for address.",
! 2722: piaddr(subnet->net), subnet->prefix_len);
! 2723: subnet_dereference(&subnet, MDL);
! 2724: skip_to_semi(cfile);
! 2725: return;
! 2726: }
! 2727:
! 2728: if (!common_subnet_parsing(cfile, share, subnet)) {
! 2729: return;
! 2730: }
! 2731: #endif /* defined(DHCPv6) */
! 2732: }
! 2733:
! 2734: /* group-declaration :== RBRACE parameters declarations LBRACE */
! 2735:
! 2736: void parse_group_declaration (cfile, group)
! 2737: struct parse *cfile;
! 2738: struct group *group;
! 2739: {
! 2740: const char *val;
! 2741: enum dhcp_token token;
! 2742: struct group *g;
! 2743: int declaration = 0;
! 2744: struct group_object *t;
! 2745: isc_result_t status;
! 2746: char *name = NULL;
! 2747: int deletedp = 0;
! 2748: int dynamicp = 0;
! 2749: int staticp = 0;
! 2750:
! 2751: g = (struct group *)0;
! 2752: if (!clone_group (&g, group, MDL))
! 2753: log_fatal ("no memory for explicit group.");
! 2754:
! 2755: token = peek_token (&val, (unsigned *)0, cfile);
! 2756: if (is_identifier (token) || token == STRING) {
! 2757: next_token (&val, (unsigned *)0, cfile);
! 2758:
! 2759: name = dmalloc (strlen (val) + 1, MDL);
! 2760: if (!name)
! 2761: log_fatal ("no memory for group decl name %s", val);
! 2762: strcpy (name, val);
! 2763: }
! 2764:
! 2765: if (!parse_lbrace (cfile)) {
! 2766: group_dereference (&g, MDL);
! 2767: return;
! 2768: }
! 2769:
! 2770: do {
! 2771: token = peek_token (&val, (unsigned *)0, cfile);
! 2772: if (token == RBRACE) {
! 2773: token = next_token (&val, (unsigned *)0, cfile);
! 2774: break;
! 2775: } else if (token == END_OF_FILE) {
! 2776: token = next_token (&val, (unsigned *)0, cfile);
! 2777: parse_warn (cfile, "unexpected end of file");
! 2778: break;
! 2779: } else if (token == TOKEN_DELETED) {
! 2780: token = next_token (&val, (unsigned *)0, cfile);
! 2781: parse_semi (cfile);
! 2782: deletedp = 1;
! 2783: } else if (token == DYNAMIC) {
! 2784: token = next_token (&val, (unsigned *)0, cfile);
! 2785: parse_semi (cfile);
! 2786: dynamicp = 1;
! 2787: } else if (token == STATIC) {
! 2788: token = next_token (&val, (unsigned *)0, cfile);
! 2789: parse_semi (cfile);
! 2790: staticp = 1;
! 2791: }
! 2792: declaration = parse_statement (cfile, g, GROUP_DECL,
! 2793: (struct host_decl *)0,
! 2794: declaration);
! 2795: } while (1);
! 2796:
! 2797: if (name) {
! 2798: if (deletedp) {
! 2799: if (group_name_hash) {
! 2800: t = (struct group_object *)0;
! 2801: if (group_hash_lookup (&t, group_name_hash,
! 2802: name,
! 2803: strlen (name), MDL)) {
! 2804: delete_group (t, 0);
! 2805: }
! 2806: }
! 2807: } else {
! 2808: t = (struct group_object *)0;
! 2809: status = group_object_allocate (&t, MDL);
! 2810: if (status != ISC_R_SUCCESS)
! 2811: log_fatal ("no memory for group decl %s: %s",
! 2812: val, isc_result_totext (status));
! 2813: group_reference (&t -> group, g, MDL);
! 2814: t -> name = name;
! 2815: t -> flags = ((staticp ? GROUP_OBJECT_STATIC : 0) |
! 2816: (dynamicp ? GROUP_OBJECT_DYNAMIC : 0) |
! 2817: (deletedp ? GROUP_OBJECT_DELETED : 0));
! 2818: supersede_group (t, 0);
! 2819: }
! 2820: if (t)
! 2821: group_object_dereference (&t, MDL);
! 2822: }
! 2823: }
! 2824:
! 2825: /* fixed-addr-parameter :== ip-addrs-or-hostnames SEMI
! 2826: ip-addrs-or-hostnames :== ip-addr-or-hostname
! 2827: | ip-addrs-or-hostnames ip-addr-or-hostname */
! 2828:
! 2829: int
! 2830: parse_fixed_addr_param(struct option_cache **oc,
! 2831: struct parse *cfile,
! 2832: enum dhcp_token type) {
! 2833: int parse_ok;
! 2834: const char *val;
! 2835: enum dhcp_token token;
! 2836: struct expression *expr = NULL;
! 2837: struct expression *tmp, *new;
! 2838: int status;
! 2839:
! 2840: do {
! 2841: tmp = NULL;
! 2842: if (type == FIXED_ADDR) {
! 2843: parse_ok = parse_ip_addr_or_hostname(&tmp, cfile, 1);
! 2844: } else {
! 2845: /* INSIST(type == FIXED_ADDR6); */
! 2846: parse_ok = parse_ip6_addr_expr(&tmp, cfile);
! 2847: }
! 2848: if (parse_ok) {
! 2849: if (expr != NULL) {
! 2850: new = NULL;
! 2851: status = make_concat(&new, expr, tmp);
! 2852: expression_dereference(&expr, MDL);
! 2853: expression_dereference(&tmp, MDL);
! 2854: if (!status) {
! 2855: return 0;
! 2856: }
! 2857: expr = new;
! 2858: } else {
! 2859: expr = tmp;
! 2860: }
! 2861: } else {
! 2862: if (expr != NULL) {
! 2863: expression_dereference (&expr, MDL);
! 2864: }
! 2865: return 0;
! 2866: }
! 2867: token = peek_token(&val, NULL, cfile);
! 2868: if (token == COMMA) {
! 2869: token = next_token(&val, NULL, cfile);
! 2870: }
! 2871: } while (token == COMMA);
! 2872:
! 2873: if (!parse_semi(cfile)) {
! 2874: if (expr) {
! 2875: expression_dereference (&expr, MDL);
! 2876: }
! 2877: return 0;
! 2878: }
! 2879:
! 2880: status = option_cache(oc, NULL, expr, NULL, MDL);
! 2881: expression_dereference(&expr, MDL);
! 2882: return status;
! 2883: }
! 2884:
! 2885: /* lease_declaration :== LEASE ip_address LBRACE lease_parameters RBRACE
! 2886:
! 2887: lease_parameters :== <nil>
! 2888: | lease_parameter
! 2889: | lease_parameters lease_parameter
! 2890:
! 2891: lease_parameter :== STARTS date
! 2892: | ENDS date
! 2893: | TIMESTAMP date
! 2894: | HARDWARE hardware-parameter
! 2895: | UID hex_numbers SEMI
! 2896: | HOSTNAME hostname SEMI
! 2897: | CLIENT_HOSTNAME hostname SEMI
! 2898: | CLASS identifier SEMI
! 2899: | DYNAMIC_BOOTP SEMI */
! 2900:
! 2901: int parse_lease_declaration (struct lease **lp, struct parse *cfile)
! 2902: {
! 2903: const char *val;
! 2904: enum dhcp_token token;
! 2905: unsigned char addr [4];
! 2906: unsigned len = sizeof addr;
! 2907: int seenmask = 0;
! 2908: int seenbit;
! 2909: char tbuf [32];
! 2910: struct lease *lease;
! 2911: struct executable_statement *on;
! 2912: int lose;
! 2913: TIME t;
! 2914: int noequal, newbinding;
! 2915: struct binding *binding;
! 2916: struct binding_value *nv;
! 2917: isc_result_t status;
! 2918: struct option_cache *oc;
! 2919: pair *p;
! 2920: binding_state_t new_state;
! 2921: unsigned buflen = 0;
! 2922: struct class *class;
! 2923:
! 2924: lease = (struct lease *)0;
! 2925: status = lease_allocate (&lease, MDL);
! 2926: if (status != ISC_R_SUCCESS)
! 2927: return 0;
! 2928:
! 2929: /* Get the address for which the lease has been issued. */
! 2930: if (!parse_numeric_aggregate (cfile, addr, &len, DOT, 10, 8)) {
! 2931: lease_dereference (&lease, MDL);
! 2932: return 0;
! 2933: }
! 2934: memcpy (lease -> ip_addr.iabuf, addr, len);
! 2935: lease -> ip_addr.len = len;
! 2936:
! 2937: if (!parse_lbrace (cfile)) {
! 2938: lease_dereference (&lease, MDL);
! 2939: return 0;
! 2940: }
! 2941:
! 2942: do {
! 2943: token = next_token (&val, (unsigned *)0, cfile);
! 2944: if (token == RBRACE)
! 2945: break;
! 2946: else if (token == END_OF_FILE) {
! 2947: parse_warn (cfile, "unexpected end of file");
! 2948: break;
! 2949: }
! 2950: strncpy (tbuf, val, sizeof tbuf);
! 2951: tbuf [(sizeof tbuf) - 1] = 0;
! 2952:
! 2953: /* Parse any of the times associated with the lease. */
! 2954: switch (token) {
! 2955: case STARTS:
! 2956: case ENDS:
! 2957: case TIMESTAMP:
! 2958: case TSTP:
! 2959: case TSFP:
! 2960: case ATSFP:
! 2961: case CLTT:
! 2962: t = parse_date (cfile);
! 2963: switch (token) {
! 2964: case STARTS:
! 2965: seenbit = 1;
! 2966: lease -> starts = t;
! 2967: break;
! 2968:
! 2969: case ENDS:
! 2970: seenbit = 2;
! 2971: lease -> ends = t;
! 2972: break;
! 2973:
! 2974: case TSTP:
! 2975: seenbit = 65536;
! 2976: lease -> tstp = t;
! 2977: break;
! 2978:
! 2979: case TSFP:
! 2980: seenbit = 131072;
! 2981: lease -> tsfp = t;
! 2982: break;
! 2983:
! 2984: case ATSFP:
! 2985: seenbit = 262144;
! 2986: lease->atsfp = t;
! 2987: break;
! 2988:
! 2989: case CLTT:
! 2990: seenbit = 524288;
! 2991: lease -> cltt = t;
! 2992: break;
! 2993:
! 2994: default: /* for gcc, we'll never get here. */
! 2995: log_fatal ("Impossible error at %s:%d.", MDL);
! 2996: return 0;
! 2997: }
! 2998: break;
! 2999:
! 3000: /* Colon-separated hexadecimal octets... */
! 3001: case UID:
! 3002: seenbit = 8;
! 3003: token = peek_token (&val, (unsigned *)0, cfile);
! 3004: if (token == STRING) {
! 3005: unsigned char *tuid;
! 3006: token = next_token (&val, &buflen, cfile);
! 3007: if (buflen < sizeof lease -> uid_buf) {
! 3008: tuid = lease -> uid_buf;
! 3009: lease -> uid_max =
! 3010: sizeof lease -> uid_buf;
! 3011: } else {
! 3012: tuid = ((unsigned char *)
! 3013: dmalloc (buflen, MDL));
! 3014: if (!tuid) {
! 3015: log_error ("no space for uid");
! 3016: lease_dereference (&lease,
! 3017: MDL);
! 3018: return 0;
! 3019: }
! 3020: lease -> uid_max = buflen;
! 3021: }
! 3022: lease -> uid_len = buflen;
! 3023: memcpy (tuid, val, lease -> uid_len);
! 3024: lease -> uid = tuid;
! 3025: } else {
! 3026: buflen = 0;
! 3027: lease -> uid = (parse_numeric_aggregate
! 3028: (cfile, (unsigned char *)0,
! 3029: &buflen, ':', 16, 8));
! 3030: if (!lease -> uid) {
! 3031: lease_dereference (&lease, MDL);
! 3032: return 0;
! 3033: }
! 3034: lease -> uid_len = buflen;
! 3035: lease -> uid_max = buflen;
! 3036: if (lease -> uid_len == 0) {
! 3037: lease -> uid = (unsigned char *)0;
! 3038: parse_warn (cfile, "zero-length uid");
! 3039: seenbit = 0;
! 3040: parse_semi (cfile);
! 3041: break;
! 3042: }
! 3043: }
! 3044: parse_semi (cfile);
! 3045: if (!lease -> uid) {
! 3046: log_fatal ("No memory for lease uid");
! 3047: }
! 3048: break;
! 3049:
! 3050: case CLASS:
! 3051: seenbit = 32;
! 3052: token = next_token (&val, (unsigned *)0, cfile);
! 3053: if (!is_identifier (token)) {
! 3054: if (token != SEMI)
! 3055: skip_to_rbrace (cfile, 1);
! 3056: lease_dereference (&lease, MDL);
! 3057: return 0;
! 3058: }
! 3059: parse_semi (cfile);
! 3060: /* for now, we aren't using this. */
! 3061: break;
! 3062:
! 3063: case HARDWARE:
! 3064: seenbit = 64;
! 3065: parse_hardware_param (cfile,
! 3066: &lease -> hardware_addr);
! 3067: break;
! 3068:
! 3069: case TOKEN_RESERVED:
! 3070: seenbit = 0;
! 3071: lease->flags |= RESERVED_LEASE;
! 3072: parse_semi(cfile);
! 3073: break;
! 3074:
! 3075: case DYNAMIC_BOOTP:
! 3076: seenbit = 0;
! 3077: lease -> flags |= BOOTP_LEASE;
! 3078: parse_semi (cfile);
! 3079: break;
! 3080:
! 3081: /* XXX: Reverse compatibility? */
! 3082: case TOKEN_ABANDONED:
! 3083: seenbit = 256;
! 3084: lease -> binding_state = FTS_ABANDONED;
! 3085: lease -> next_binding_state = FTS_ABANDONED;
! 3086: parse_semi (cfile);
! 3087: break;
! 3088:
! 3089: case TOKEN_NEXT:
! 3090: seenbit = 128;
! 3091: token = next_token (&val, (unsigned *)0, cfile);
! 3092: if (token != BINDING) {
! 3093: parse_warn (cfile, "expecting 'binding'");
! 3094: skip_to_semi (cfile);
! 3095: break;
! 3096: }
! 3097: goto do_binding_state;
! 3098:
! 3099: case BINDING:
! 3100: seenbit = 256;
! 3101:
! 3102: do_binding_state:
! 3103: token = next_token (&val, (unsigned *)0, cfile);
! 3104: if (token != STATE) {
! 3105: parse_warn (cfile, "expecting 'state'");
! 3106: skip_to_semi (cfile);
! 3107: break;
! 3108: }
! 3109: token = next_token (&val, (unsigned *)0, cfile);
! 3110: switch (token) {
! 3111: case TOKEN_ABANDONED:
! 3112: new_state = FTS_ABANDONED;
! 3113: break;
! 3114: case TOKEN_FREE:
! 3115: new_state = FTS_FREE;
! 3116: break;
! 3117: case TOKEN_ACTIVE:
! 3118: new_state = FTS_ACTIVE;
! 3119: break;
! 3120: case TOKEN_EXPIRED:
! 3121: new_state = FTS_EXPIRED;
! 3122: break;
! 3123: case TOKEN_RELEASED:
! 3124: new_state = FTS_RELEASED;
! 3125: break;
! 3126: case TOKEN_RESET:
! 3127: new_state = FTS_RESET;
! 3128: break;
! 3129: case TOKEN_BACKUP:
! 3130: new_state = FTS_BACKUP;
! 3131: break;
! 3132:
! 3133: /* RESERVED and BOOTP states preserved for
! 3134: * compatibleness with older versions.
! 3135: */
! 3136: case TOKEN_RESERVED:
! 3137: new_state = FTS_ACTIVE;
! 3138: lease->flags |= RESERVED_LEASE;
! 3139: break;
! 3140: case TOKEN_BOOTP:
! 3141: new_state = FTS_ACTIVE;
! 3142: lease->flags |= BOOTP_LEASE;
! 3143: break;
! 3144:
! 3145: default:
! 3146: parse_warn (cfile,
! 3147: "%s: expecting a binding state.",
! 3148: val);
! 3149: skip_to_semi (cfile);
! 3150: return 0;
! 3151: }
! 3152:
! 3153: if (seenbit == 256) {
! 3154: lease -> binding_state = new_state;
! 3155:
! 3156: /* If no next binding state is specified, it's
! 3157: the same as the current state. */
! 3158: if (!(seenmask & 128))
! 3159: lease -> next_binding_state = new_state;
! 3160: } else
! 3161: lease -> next_binding_state = new_state;
! 3162:
! 3163: parse_semi (cfile);
! 3164: break;
! 3165:
! 3166: case CLIENT_HOSTNAME:
! 3167: seenbit = 1024;
! 3168: token = peek_token (&val, (unsigned *)0, cfile);
! 3169: if (token == STRING) {
! 3170: if (!parse_string (cfile,
! 3171: &lease -> client_hostname,
! 3172: (unsigned *)0)) {
! 3173: lease_dereference (&lease, MDL);
! 3174: return 0;
! 3175: }
! 3176: } else {
! 3177: lease -> client_hostname =
! 3178: parse_host_name (cfile);
! 3179: if (lease -> client_hostname)
! 3180: parse_semi (cfile);
! 3181: else {
! 3182: parse_warn (cfile,
! 3183: "expecting a hostname.");
! 3184: skip_to_semi (cfile);
! 3185: lease_dereference (&lease, MDL);
! 3186: return 0;
! 3187: }
! 3188: }
! 3189: break;
! 3190:
! 3191: case BILLING:
! 3192: seenbit = 2048;
! 3193: class = (struct class *)0;
! 3194: token = next_token (&val, (unsigned *)0, cfile);
! 3195: if (token == CLASS) {
! 3196: token = next_token (&val,
! 3197: (unsigned *)0, cfile);
! 3198: if (token != STRING) {
! 3199: parse_warn (cfile, "expecting string");
! 3200: if (token != SEMI)
! 3201: skip_to_semi (cfile);
! 3202: token = BILLING;
! 3203: break;
! 3204: }
! 3205: if (lease -> billing_class)
! 3206: class_dereference (&lease -> billing_class,
! 3207: MDL);
! 3208: find_class (&class, val, MDL);
! 3209: if (!class)
! 3210: parse_warn (cfile,
! 3211: "unknown class %s", val);
! 3212: parse_semi (cfile);
! 3213: } else if (token == SUBCLASS) {
! 3214: if (lease -> billing_class)
! 3215: class_dereference (&lease -> billing_class,
! 3216: MDL);
! 3217: parse_class_declaration(&class, cfile, NULL,
! 3218: CLASS_TYPE_SUBCLASS);
! 3219: } else {
! 3220: parse_warn (cfile, "expecting \"class\"");
! 3221: if (token != SEMI)
! 3222: skip_to_semi (cfile);
! 3223: }
! 3224: if (class) {
! 3225: class_reference (&lease -> billing_class,
! 3226: class, MDL);
! 3227: class_dereference (&class, MDL);
! 3228: }
! 3229: break;
! 3230:
! 3231: case ON:
! 3232: on = (struct executable_statement *)0;
! 3233: lose = 0;
! 3234: if (!parse_on_statement (&on, cfile, &lose)) {
! 3235: skip_to_rbrace (cfile, 1);
! 3236: lease_dereference (&lease, MDL);
! 3237: return 0;
! 3238: }
! 3239: seenbit = 0;
! 3240: if ((on -> data.on.evtypes & ON_EXPIRY) &&
! 3241: on -> data.on.statements) {
! 3242: seenbit |= 16384;
! 3243: executable_statement_reference
! 3244: (&lease -> on_expiry,
! 3245: on -> data.on.statements, MDL);
! 3246: }
! 3247: if ((on -> data.on.evtypes & ON_RELEASE) &&
! 3248: on -> data.on.statements) {
! 3249: seenbit |= 32768;
! 3250: executable_statement_reference
! 3251: (&lease -> on_release,
! 3252: on -> data.on.statements, MDL);
! 3253: }
! 3254: executable_statement_dereference (&on, MDL);
! 3255: break;
! 3256:
! 3257: case OPTION:
! 3258: case SUPERSEDE:
! 3259: noequal = 0;
! 3260: seenbit = 0;
! 3261: oc = (struct option_cache *)0;
! 3262: if (parse_option_decl (&oc, cfile)) {
! 3263: if (oc -> option -> universe !=
! 3264: &agent_universe) {
! 3265: parse_warn (cfile,
! 3266: "agent option expected.");
! 3267: option_cache_dereference (&oc, MDL);
! 3268: break;
! 3269: }
! 3270: if (!lease -> agent_options &&
! 3271: !(option_chain_head_allocate
! 3272: (&lease -> agent_options, MDL))) {
! 3273: log_error ("no memory to stash agent option");
! 3274: break;
! 3275: }
! 3276: for (p = &lease -> agent_options -> first;
! 3277: *p; p = &((*p) -> cdr))
! 3278: ;
! 3279: *p = cons (0, 0);
! 3280: option_cache_reference (((struct option_cache **)
! 3281: &((*p) -> car)), oc, MDL);
! 3282: option_cache_dereference (&oc, MDL);
! 3283: }
! 3284: break;
! 3285:
! 3286: case TOKEN_SET:
! 3287: noequal = 0;
! 3288:
! 3289: token = next_token (&val, (unsigned *)0, cfile);
! 3290: if (token != NAME && token != NUMBER_OR_NAME) {
! 3291: parse_warn (cfile,
! 3292: "%s can't be a variable name",
! 3293: val);
! 3294: badset:
! 3295: skip_to_semi (cfile);
! 3296: lease_dereference (&lease, MDL);
! 3297: return 0;
! 3298: }
! 3299:
! 3300: seenbit = 0;
! 3301: special_set:
! 3302: if (lease -> scope)
! 3303: binding = find_binding (lease -> scope, val);
! 3304: else
! 3305: binding = (struct binding *)0;
! 3306:
! 3307: if (!binding) {
! 3308: if (!lease -> scope)
! 3309: if (!(binding_scope_allocate
! 3310: (&lease -> scope, MDL)))
! 3311: log_fatal ("no memory for scope");
! 3312: binding = dmalloc (sizeof *binding, MDL);
! 3313: if (!binding)
! 3314: log_fatal ("No memory for lease %s.",
! 3315: "binding");
! 3316: memset (binding, 0, sizeof *binding);
! 3317: binding -> name =
! 3318: dmalloc (strlen (val) + 1, MDL);
! 3319: if (!binding -> name)
! 3320: log_fatal ("No memory for binding %s.",
! 3321: "name");
! 3322: strcpy (binding -> name, val);
! 3323: newbinding = 1;
! 3324: } else {
! 3325: newbinding = 0;
! 3326: }
! 3327:
! 3328: nv = NULL;
! 3329: if (!binding_value_allocate(&nv, MDL))
! 3330: log_fatal("no memory for binding value.");
! 3331:
! 3332: if (!noequal) {
! 3333: token = next_token (&val, (unsigned *)0, cfile);
! 3334: if (token != EQUAL) {
! 3335: parse_warn (cfile,
! 3336: "expecting '=' in set statement.");
! 3337: goto badset;
! 3338: }
! 3339: }
! 3340:
! 3341: if (!parse_binding_value(cfile, nv)) {
! 3342: binding_value_dereference(&nv, MDL);
! 3343: lease_dereference(&lease, MDL);
! 3344: return 0;
! 3345: }
! 3346:
! 3347: if (newbinding) {
! 3348: binding_value_reference(&binding->value,
! 3349: nv, MDL);
! 3350: binding->next = lease->scope->bindings;
! 3351: lease->scope->bindings = binding;
! 3352: } else {
! 3353: binding_value_dereference(&binding->value, MDL);
! 3354: binding_value_reference(&binding->value,
! 3355: nv, MDL);
! 3356: }
! 3357:
! 3358: binding_value_dereference(&nv, MDL);
! 3359: parse_semi(cfile);
! 3360: break;
! 3361:
! 3362: /* case NAME: */
! 3363: default:
! 3364: if (!strcasecmp (val, "ddns-fwd-name")) {
! 3365: seenbit = 4096;
! 3366: noequal = 1;
! 3367: goto special_set;
! 3368: } else if (!strcasecmp (val, "ddns-rev-name")) {
! 3369: seenbit = 8192;
! 3370: noequal = 1;
! 3371: goto special_set;
! 3372: } else
! 3373: parse_warn(cfile, "Unexpected configuration "
! 3374: "directive.");
! 3375: skip_to_semi (cfile);
! 3376: seenbit = 0;
! 3377: lease_dereference (&lease, MDL);
! 3378: return 0;
! 3379: }
! 3380:
! 3381: if (seenmask & seenbit) {
! 3382: parse_warn (cfile,
! 3383: "Too many %s parameters in lease %s\n",
! 3384: tbuf, piaddr (lease -> ip_addr));
! 3385: } else
! 3386: seenmask |= seenbit;
! 3387:
! 3388: } while (1);
! 3389:
! 3390: /* If no binding state is specified, make one up. */
! 3391: if (!(seenmask & 256)) {
! 3392: if (lease -> ends > cur_time ||
! 3393: lease -> on_expiry || lease -> on_release)
! 3394: lease -> binding_state = FTS_ACTIVE;
! 3395: #if defined (FAILOVER_PROTOCOL)
! 3396: else if (lease -> pool && lease -> pool -> failover_peer)
! 3397: lease -> binding_state = FTS_EXPIRED;
! 3398: #endif
! 3399: else
! 3400: lease -> binding_state = FTS_FREE;
! 3401: if (lease -> binding_state == FTS_ACTIVE) {
! 3402: #if defined (FAILOVER_PROTOCOL)
! 3403: if (lease -> pool && lease -> pool -> failover_peer)
! 3404: lease -> next_binding_state = FTS_EXPIRED;
! 3405: else
! 3406: #endif
! 3407: lease -> next_binding_state = FTS_FREE;
! 3408: } else
! 3409: lease -> next_binding_state = lease -> binding_state;
! 3410: }
! 3411:
! 3412: if (!(seenmask & 65536))
! 3413: lease -> tstp = lease -> ends;
! 3414:
! 3415: lease_reference (lp, lease, MDL);
! 3416: lease_dereference (&lease, MDL);
! 3417: return 1;
! 3418: }
! 3419:
! 3420: /* Parse the right side of a 'binding value'.
! 3421: *
! 3422: * set foo = "bar"; is a string
! 3423: * set foo = false; is a boolean
! 3424: * set foo = %31; is a numeric value.
! 3425: */
! 3426: static int
! 3427: parse_binding_value(struct parse *cfile, struct binding_value *value)
! 3428: {
! 3429: struct data_string *data;
! 3430: unsigned char *s;
! 3431: const char *val;
! 3432: unsigned buflen;
! 3433: int token;
! 3434:
! 3435: if ((cfile == NULL) || (value == NULL))
! 3436: log_fatal("Invalid arguments at %s:%d.", MDL);
! 3437:
! 3438: token = peek_token(&val, NULL, cfile);
! 3439: if (token == STRING) {
! 3440: token = next_token(&val, &buflen, cfile);
! 3441:
! 3442: value->type = binding_data;
! 3443: value->value.data.len = buflen;
! 3444:
! 3445: data = &value->value.data;
! 3446:
! 3447: if (!buffer_allocate(&data->buffer, buflen + 1, MDL))
! 3448: log_fatal ("No memory for binding.");
! 3449:
! 3450: memcpy(data->buffer->data, val, buflen + 1);
! 3451:
! 3452: data->data = data->buffer->data;
! 3453: data->terminated = 1;
! 3454: } else if (token == NUMBER_OR_NAME) {
! 3455: value->type = binding_data;
! 3456:
! 3457: data = &value->value.data;
! 3458: s = parse_numeric_aggregate(cfile, NULL, &data->len,
! 3459: ':', 16, 8);
! 3460: if (s == NULL) {
! 3461: skip_to_semi(cfile);
! 3462: return 0;
! 3463: }
! 3464:
! 3465: if (data->len) {
! 3466: if (!buffer_allocate(&data->buffer, data->len + 1,
! 3467: MDL))
! 3468: log_fatal("No memory for binding.");
! 3469:
! 3470: memcpy(data->buffer->data, s, data->len);
! 3471: data->data = data->buffer->data;
! 3472:
! 3473: dfree (s, MDL);
! 3474: }
! 3475: } else if (token == PERCENT) {
! 3476: token = next_token(&val, NULL, cfile);
! 3477: token = next_token(&val, NULL, cfile);
! 3478: if (token != NUMBER) {
! 3479: parse_warn(cfile, "expecting decimal number.");
! 3480: if (token != SEMI)
! 3481: skip_to_semi(cfile);
! 3482: return 0;
! 3483: }
! 3484: value->type = binding_numeric;
! 3485: value->value.intval = atol(val);
! 3486: } else if (token == NAME) {
! 3487: token = next_token(&val, NULL, cfile);
! 3488: value->type = binding_boolean;
! 3489: if (!strcasecmp(val, "true"))
! 3490: value->value.boolean = 1;
! 3491: else if (!strcasecmp(val, "false"))
! 3492: value->value.boolean = 0;
! 3493: else {
! 3494: parse_warn(cfile, "expecting true or false");
! 3495: if (token != SEMI)
! 3496: skip_to_semi(cfile);
! 3497: return 0;
! 3498: }
! 3499: } else {
! 3500: parse_warn (cfile, "expecting a constant value.");
! 3501: if (token != SEMI)
! 3502: skip_to_semi (cfile);
! 3503: return 0;
! 3504: }
! 3505:
! 3506: return 1;
! 3507: }
! 3508:
! 3509: /* address-range-declaration :== ip-address ip-address SEMI
! 3510: | DYNAMIC_BOOTP ip-address ip-address SEMI */
! 3511:
! 3512: void parse_address_range (cfile, group, type, inpool, lpchain)
! 3513: struct parse *cfile;
! 3514: struct group *group;
! 3515: int type;
! 3516: struct pool *inpool;
! 3517: struct lease **lpchain;
! 3518: {
! 3519: struct iaddr low, high, net;
! 3520: unsigned char addr [4];
! 3521: unsigned len = sizeof addr;
! 3522: enum dhcp_token token;
! 3523: const char *val;
! 3524: int dynamic = 0;
! 3525: struct subnet *subnet;
! 3526: struct shared_network *share;
! 3527: struct pool *pool;
! 3528: isc_result_t status;
! 3529:
! 3530: if ((token = peek_token (&val,
! 3531: (unsigned *)0, cfile)) == DYNAMIC_BOOTP) {
! 3532: token = next_token (&val, (unsigned *)0, cfile);
! 3533: dynamic = 1;
! 3534: }
! 3535:
! 3536: /* Get the bottom address in the range... */
! 3537: if (!parse_numeric_aggregate (cfile, addr, &len, DOT, 10, 8))
! 3538: return;
! 3539: memcpy (low.iabuf, addr, len);
! 3540: low.len = len;
! 3541:
! 3542: /* Only one address? */
! 3543: token = peek_token (&val, (unsigned *)0, cfile);
! 3544: if (token == SEMI)
! 3545: high = low;
! 3546: else {
! 3547: /* Get the top address in the range... */
! 3548: if (!parse_numeric_aggregate (cfile, addr, &len, DOT, 10, 8))
! 3549: return;
! 3550: memcpy (high.iabuf, addr, len);
! 3551: high.len = len;
! 3552: }
! 3553:
! 3554: token = next_token (&val, (unsigned *)0, cfile);
! 3555: if (token != SEMI) {
! 3556: parse_warn (cfile, "semicolon expected.");
! 3557: skip_to_semi (cfile);
! 3558: return;
! 3559: }
! 3560:
! 3561: if (type == SUBNET_DECL) {
! 3562: subnet = group -> subnet;
! 3563: share = subnet -> shared_network;
! 3564: } else {
! 3565: share = group -> shared_network;
! 3566: for (subnet = share -> subnets;
! 3567: subnet; subnet = subnet -> next_sibling) {
! 3568: net = subnet_number (low, subnet -> netmask);
! 3569: if (addr_eq (net, subnet -> net))
! 3570: break;
! 3571: }
! 3572: if (!subnet) {
! 3573: parse_warn (cfile, "address range not on network %s",
! 3574: group -> shared_network -> name);
! 3575: log_error ("Be sure to place pool statement after %s",
! 3576: "related subnet declarations.");
! 3577: return;
! 3578: }
! 3579: }
! 3580:
! 3581: if (!inpool) {
! 3582: struct pool *last = (struct pool *)0;
! 3583:
! 3584: /* If we're permitting dynamic bootp for this range,
! 3585: then look for a pool with an empty prohibit list and
! 3586: a permit list with one entry that permits all clients. */
! 3587: for (pool = share -> pools; pool; pool = pool -> next) {
! 3588: if ((!dynamic && !pool -> permit_list &&
! 3589: pool -> prohibit_list &&
! 3590: !pool -> prohibit_list -> next &&
! 3591: (pool -> prohibit_list -> type ==
! 3592: permit_dynamic_bootp_clients)) ||
! 3593: (dynamic && !pool -> prohibit_list &&
! 3594: pool -> permit_list &&
! 3595: !pool -> permit_list -> next &&
! 3596: (pool -> permit_list -> type ==
! 3597: permit_all_clients))) {
! 3598: break;
! 3599: }
! 3600: last = pool;
! 3601: }
! 3602:
! 3603: /* If we didn't get a pool, make one. */
! 3604: if (!pool) {
! 3605: struct permit *p;
! 3606: status = pool_allocate (&pool, MDL);
! 3607: if (status != ISC_R_SUCCESS)
! 3608: log_fatal ("no memory for ad-hoc pool: %s",
! 3609: isc_result_totext (status));
! 3610: p = new_permit (MDL);
! 3611: if (!p)
! 3612: log_fatal ("no memory for ad-hoc permit.");
! 3613:
! 3614: /* Dynamic pools permit all clients. Otherwise
! 3615: we prohibit BOOTP clients. */
! 3616: if (dynamic) {
! 3617: p -> type = permit_all_clients;
! 3618: pool -> permit_list = p;
! 3619: } else {
! 3620: p -> type = permit_dynamic_bootp_clients;
! 3621: pool -> prohibit_list = p;
! 3622: }
! 3623:
! 3624: if (share -> pools)
! 3625: pool_reference (&last -> next, pool, MDL);
! 3626: else
! 3627: pool_reference (&share -> pools, pool, MDL);
! 3628: shared_network_reference (&pool -> shared_network,
! 3629: share, MDL);
! 3630: if (!clone_group (&pool -> group, share -> group, MDL))
! 3631: log_fatal ("no memory for anon pool group.");
! 3632: } else {
! 3633: pool = (struct pool *)0;
! 3634: if (last)
! 3635: pool_reference (&pool, last, MDL);
! 3636: else
! 3637: pool_reference (&pool, share -> pools, MDL);
! 3638: }
! 3639: } else {
! 3640: pool = (struct pool *)0;
! 3641: pool_reference (&pool, inpool, MDL);
! 3642: }
! 3643:
! 3644: #if defined (FAILOVER_PROTOCOL)
! 3645: if (pool -> failover_peer && dynamic) {
! 3646: /* Doctor, do you think I'm overly sensitive
! 3647: about getting bug reports I can't fix? */
! 3648: parse_warn (cfile, "dynamic-bootp flag is %s",
! 3649: "not permitted for address");
! 3650: log_error ("range declarations where there is a failover");
! 3651: log_error ("peer in scope. If you wish to declare an");
! 3652: log_error ("address range from which dynamic bootp leases");
! 3653: log_error ("can be allocated, please declare it within a");
! 3654: log_error ("pool declaration that also contains the \"no");
! 3655: log_error ("failover\" statement. The failover protocol");
! 3656: log_error ("itself does not permit dynamic bootp - this");
! 3657: log_error ("is not a limitation specific to the ISC DHCP");
! 3658: log_error ("server. Please don't ask me to defend this");
! 3659: log_error ("until you have read and really tried %s",
! 3660: "to understand");
! 3661: log_error ("the failover protocol specification.");
! 3662:
! 3663: /* We don't actually bomb at this point - instead,
! 3664: we let parse_lease_file notice the error and
! 3665: bomb at that point - it's easier. */
! 3666: }
! 3667: #endif /* FAILOVER_PROTOCOL */
! 3668:
! 3669: /* Create the new address range... */
! 3670: new_address_range (cfile, low, high, subnet, pool, lpchain);
! 3671: pool_dereference (&pool, MDL);
! 3672: }
! 3673:
! 3674: #ifdef DHCPv6
! 3675: static void
! 3676: add_ipv6_pool_to_subnet(struct subnet *subnet, u_int16_t type,
! 3677: struct iaddr *lo_addr, int bits, int units) {
! 3678: struct ipv6_pool *pool;
! 3679: struct shared_network *share;
! 3680: struct in6_addr tmp_in6_addr;
! 3681: int num_pools;
! 3682: struct ipv6_pool **tmp;
! 3683:
! 3684: share = subnet->shared_network;
! 3685:
! 3686: /*
! 3687: * Create our pool.
! 3688: */
! 3689: if (lo_addr->len != sizeof(tmp_in6_addr)) {
! 3690: log_fatal("Internal error: Attempt to add non-IPv6 address "
! 3691: "to IPv6 shared network.");
! 3692: }
! 3693: memcpy(&tmp_in6_addr, lo_addr->iabuf, sizeof(tmp_in6_addr));
! 3694: pool = NULL;
! 3695: if (ipv6_pool_allocate(&pool, type, &tmp_in6_addr,
! 3696: bits, units, MDL) != ISC_R_SUCCESS) {
! 3697: log_fatal("Out of memory");
! 3698: }
! 3699:
! 3700: /*
! 3701: * Add to our global IPv6 pool set.
! 3702: */
! 3703: if (add_ipv6_pool(pool) != ISC_R_SUCCESS) {
! 3704: log_fatal ("Out of memory");
! 3705: }
! 3706:
! 3707: /*
! 3708: * Link the pool to its network.
! 3709: */
! 3710: pool->subnet = NULL;
! 3711: subnet_reference(&pool->subnet, subnet, MDL);
! 3712: pool->shared_network = NULL;
! 3713: shared_network_reference(&pool->shared_network, share, MDL);
! 3714:
! 3715: /*
! 3716: * Increase our array size for ipv6_pools in the shared_network.
! 3717: */
! 3718: if (share->ipv6_pools == NULL) {
! 3719: num_pools = 0;
! 3720: } else {
! 3721: num_pools = 0;
! 3722: while (share->ipv6_pools[num_pools] != NULL) {
! 3723: num_pools++;
! 3724: }
! 3725: }
! 3726: tmp = dmalloc(sizeof(struct ipv6_pool *) * (num_pools + 2), MDL);
! 3727: if (tmp == NULL) {
! 3728: log_fatal("Out of memory");
! 3729: }
! 3730: if (num_pools > 0) {
! 3731: memcpy(tmp, share->ipv6_pools,
! 3732: sizeof(struct ipv6_pool *) * num_pools);
! 3733: }
! 3734: if (share->ipv6_pools != NULL) {
! 3735: dfree(share->ipv6_pools, MDL);
! 3736: }
! 3737: share->ipv6_pools = tmp;
! 3738:
! 3739: /*
! 3740: * Record this pool in our array of pools for this shared network.
! 3741: */
! 3742: ipv6_pool_reference(&share->ipv6_pools[num_pools], pool, MDL);
! 3743: share->ipv6_pools[num_pools+1] = NULL;
! 3744: }
! 3745:
! 3746: /* address-range6-declaration :== ip-address6 ip-address6 SEMI
! 3747: | ip-address6 SLASH number SEMI
! 3748: | ip-address6 [SLASH number] TEMPORARY SEMI */
! 3749:
! 3750: void
! 3751: parse_address_range6(struct parse *cfile, struct group *group) {
! 3752: struct iaddr lo, hi;
! 3753: int bits;
! 3754: enum dhcp_token token;
! 3755: const char *val;
! 3756: struct iaddrcidrnetlist *nets;
! 3757: struct iaddrcidrnetlist *p;
! 3758: u_int16_t type = D6O_IA_NA;
! 3759:
! 3760: if (local_family != AF_INET6) {
! 3761: parse_warn(cfile, "range6 statement is only supported "
! 3762: "in DHCPv6 mode.");
! 3763: skip_to_semi(cfile);
! 3764: return;
! 3765: }
! 3766:
! 3767: /* This is enforced by the caller, this is just a sanity check. */
! 3768: if (group->subnet == NULL)
! 3769: log_fatal("Impossible condition at %s:%d.", MDL);
! 3770:
! 3771: /*
! 3772: * Read starting address.
! 3773: */
! 3774: if (!parse_ip6_addr(cfile, &lo)) {
! 3775: return;
! 3776: }
! 3777:
! 3778: /*
! 3779: * See if we we're using range or CIDR notation or TEMPORARY
! 3780: */
! 3781: token = peek_token(&val, NULL, cfile);
! 3782: if (token == SLASH) {
! 3783: /*
! 3784: * '/' means CIDR notation, so read the bits we want.
! 3785: */
! 3786: next_token(NULL, NULL, cfile);
! 3787: token = next_token(&val, NULL, cfile);
! 3788: if (token != NUMBER) {
! 3789: parse_warn(cfile, "expecting number");
! 3790: skip_to_semi(cfile);
! 3791: return;
! 3792: }
! 3793: bits = atoi(val);
! 3794: if ((bits < 0) || (bits > 128)) {
! 3795: parse_warn(cfile, "networks have 0 to 128 bits");
! 3796: skip_to_semi(cfile);
! 3797: return;
! 3798: }
! 3799: if (!is_cidr_mask_valid(&lo, bits)) {
! 3800: parse_warn(cfile, "network mask too short");
! 3801: skip_to_semi(cfile);
! 3802: return;
! 3803: }
! 3804:
! 3805: /*
! 3806: * can be temporary (RFC 4941 like)
! 3807: */
! 3808: token = peek_token(&val, NULL, cfile);
! 3809: if (token == TEMPORARY) {
! 3810: if (bits < 64)
! 3811: parse_warn(cfile, "temporary mask too short");
! 3812: if (bits == 128)
! 3813: parse_warn(cfile, "temporary singleton?");
! 3814: token = next_token(NULL, NULL, cfile);
! 3815: type = D6O_IA_TA;
! 3816: }
! 3817:
! 3818: add_ipv6_pool_to_subnet(group->subnet, type, &lo,
! 3819: bits, 128);
! 3820:
! 3821: } else if (token == TEMPORARY) {
! 3822: /*
! 3823: * temporary (RFC 4941)
! 3824: */
! 3825: type = D6O_IA_TA;
! 3826: next_token(NULL, NULL, cfile);
! 3827: bits = 64;
! 3828: if (!is_cidr_mask_valid(&lo, bits)) {
! 3829: parse_warn(cfile, "network mask too short");
! 3830: skip_to_semi(cfile);
! 3831: return;
! 3832: }
! 3833:
! 3834: add_ipv6_pool_to_subnet(group->subnet, type, &lo,
! 3835: bits, 128);
! 3836: } else {
! 3837: /*
! 3838: * No '/', so we are looking for the end address of
! 3839: * the IPv6 pool.
! 3840: */
! 3841: if (!parse_ip6_addr(cfile, &hi)) {
! 3842: return;
! 3843: }
! 3844:
! 3845: /*
! 3846: * Convert our range to a set of CIDR networks.
! 3847: */
! 3848: nets = NULL;
! 3849: if (range2cidr(&nets, &lo, &hi) != ISC_R_SUCCESS) {
! 3850: log_fatal("Error converting range to CIDR networks");
! 3851: }
! 3852:
! 3853: for (p=nets; p != NULL; p=p->next) {
! 3854: add_ipv6_pool_to_subnet(group->subnet, type,
! 3855: &p->cidrnet.lo_addr,
! 3856: p->cidrnet.bits, 128);
! 3857: }
! 3858:
! 3859: free_iaddrcidrnetlist(&nets);
! 3860: }
! 3861:
! 3862: token = next_token(NULL, NULL, cfile);
! 3863: if (token != SEMI) {
! 3864: parse_warn(cfile, "semicolon expected.");
! 3865: skip_to_semi(cfile);
! 3866: return;
! 3867: }
! 3868: }
! 3869:
! 3870: /* prefix6-declaration :== ip-address6 ip-address6 SLASH number SEMI */
! 3871:
! 3872: void
! 3873: parse_prefix6(struct parse *cfile, struct group *group) {
! 3874: struct iaddr lo, hi;
! 3875: int bits;
! 3876: enum dhcp_token token;
! 3877: const char *val;
! 3878: struct iaddrcidrnetlist *nets;
! 3879: struct iaddrcidrnetlist *p;
! 3880:
! 3881: if (local_family != AF_INET6) {
! 3882: parse_warn(cfile, "prefix6 statement is only supported "
! 3883: "in DHCPv6 mode.");
! 3884: skip_to_semi(cfile);
! 3885: return;
! 3886: }
! 3887:
! 3888: /* This is enforced by the caller, so it's just a sanity check. */
! 3889: if (group->subnet == NULL)
! 3890: log_fatal("Impossible condition at %s:%d.", MDL);
! 3891:
! 3892: /*
! 3893: * Read starting and ending address.
! 3894: */
! 3895: if (!parse_ip6_addr(cfile, &lo)) {
! 3896: return;
! 3897: }
! 3898: if (!parse_ip6_addr(cfile, &hi)) {
! 3899: return;
! 3900: }
! 3901:
! 3902: /*
! 3903: * Next is '/' number ';'.
! 3904: */
! 3905: token = next_token(NULL, NULL, cfile);
! 3906: if (token != SLASH) {
! 3907: parse_warn(cfile, "expecting '/'");
! 3908: if (token != SEMI)
! 3909: skip_to_semi(cfile);
! 3910: return;
! 3911: }
! 3912: token = next_token(&val, NULL, cfile);
! 3913: if (token != NUMBER) {
! 3914: parse_warn(cfile, "expecting number");
! 3915: if (token != SEMI)
! 3916: skip_to_semi(cfile);
! 3917: return;
! 3918: }
! 3919: bits = atoi(val);
! 3920: if ((bits <= 0) || (bits >= 128)) {
! 3921: parse_warn(cfile, "networks have 0 to 128 bits (exclusive)");
! 3922: return;
! 3923: }
! 3924: if (!is_cidr_mask_valid(&lo, bits) ||
! 3925: !is_cidr_mask_valid(&hi, bits)) {
! 3926: parse_warn(cfile, "network mask too short");
! 3927: return;
! 3928: }
! 3929: token = next_token(NULL, NULL, cfile);
! 3930: if (token != SEMI) {
! 3931: parse_warn(cfile, "semicolon expected.");
! 3932: skip_to_semi(cfile);
! 3933: return;
! 3934: }
! 3935:
! 3936: /*
! 3937: * Convert our range to a set of CIDR networks.
! 3938: */
! 3939: nets = NULL;
! 3940: if (range2cidr(&nets, &lo, &hi) != ISC_R_SUCCESS) {
! 3941: log_fatal("Error converting prefix to CIDR");
! 3942: }
! 3943:
! 3944: for (p = nets; p != NULL; p = p->next) {
! 3945: /* Normalize and check. */
! 3946: if (p->cidrnet.bits == 128) {
! 3947: p->cidrnet.bits = bits;
! 3948: }
! 3949: if (p->cidrnet.bits > bits) {
! 3950: parse_warn(cfile, "impossible mask length");
! 3951: continue;
! 3952: }
! 3953: add_ipv6_pool_to_subnet(group->subnet, D6O_IA_PD,
! 3954: &p->cidrnet.lo_addr,
! 3955: p->cidrnet.bits, bits);
! 3956: }
! 3957:
! 3958: free_iaddrcidrnetlist(&nets);
! 3959: }
! 3960:
! 3961: /* fixed-prefix6 :== ip6-address SLASH number SEMI */
! 3962:
! 3963: void
! 3964: parse_fixed_prefix6(struct parse *cfile, struct host_decl *host_decl) {
! 3965: struct iaddrcidrnetlist *ia, **h;
! 3966: enum dhcp_token token;
! 3967: const char *val;
! 3968:
! 3969: /*
! 3970: * Get the head of the fixed-prefix list.
! 3971: */
! 3972: h = &host_decl->fixed_prefix;
! 3973:
! 3974: /*
! 3975: * Walk to the end.
! 3976: */
! 3977: while (*h != NULL) {
! 3978: h = &((*h)->next);
! 3979: }
! 3980:
! 3981: /*
! 3982: * Allocate a new iaddrcidrnetlist structure.
! 3983: */
! 3984: ia = dmalloc(sizeof(*ia), MDL);
! 3985: if (!ia) {
! 3986: log_fatal("Out of memory");
! 3987: }
! 3988:
! 3989: /*
! 3990: * Parse it.
! 3991: */
! 3992: if (!parse_ip6_addr(cfile, &ia->cidrnet.lo_addr)) {
! 3993: dfree(ia, MDL);
! 3994: return;
! 3995: }
! 3996: token = next_token(NULL, NULL, cfile);
! 3997: if (token != SLASH) {
! 3998: dfree(ia, MDL);
! 3999: parse_warn(cfile, "expecting '/'");
! 4000: if (token != SEMI)
! 4001: skip_to_semi(cfile);
! 4002: return;
! 4003: }
! 4004: token = next_token(&val, NULL, cfile);
! 4005: if (token != NUMBER) {
! 4006: dfree(ia, MDL);
! 4007: parse_warn(cfile, "expecting number");
! 4008: if (token != SEMI)
! 4009: skip_to_semi(cfile);
! 4010: return;
! 4011: }
! 4012: token = next_token(NULL, NULL, cfile);
! 4013: if (token != SEMI) {
! 4014: dfree(ia, MDL);
! 4015: parse_warn(cfile, "semicolon expected.");
! 4016: skip_to_semi(cfile);
! 4017: return;
! 4018: }
! 4019:
! 4020: /*
! 4021: * Fill it.
! 4022: */
! 4023: ia->cidrnet.bits = atoi(val);
! 4024: if ((ia->cidrnet.bits < 0) || (ia->cidrnet.bits > 128)) {
! 4025: dfree(ia, MDL);
! 4026: parse_warn(cfile, "networks have 0 to 128 bits");
! 4027: return;
! 4028: }
! 4029: if (!is_cidr_mask_valid(&ia->cidrnet.lo_addr, ia->cidrnet.bits)) {
! 4030: dfree(ia, MDL);
! 4031: parse_warn(cfile, "network mask too short");
! 4032: return;
! 4033: }
! 4034:
! 4035: /*
! 4036: * Store it.
! 4037: */
! 4038: *h = ia;
! 4039: return;
! 4040: }
! 4041: #endif /* DHCPv6 */
! 4042:
! 4043: /* allow-deny-keyword :== BOOTP
! 4044: | BOOTING
! 4045: | DYNAMIC_BOOTP
! 4046: | UNKNOWN_CLIENTS */
! 4047:
! 4048: int parse_allow_deny (oc, cfile, flag)
! 4049: struct option_cache **oc;
! 4050: struct parse *cfile;
! 4051: int flag;
! 4052: {
! 4053: enum dhcp_token token;
! 4054: const char *val;
! 4055: unsigned char rf = flag;
! 4056: unsigned code;
! 4057: struct option *option = NULL;
! 4058: struct expression *data = (struct expression *)0;
! 4059: int status;
! 4060:
! 4061: if (!make_const_data (&data, &rf, 1, 0, 1, MDL))
! 4062: return 0;
! 4063:
! 4064: token = next_token (&val, (unsigned *)0, cfile);
! 4065: switch (token) {
! 4066: case TOKEN_BOOTP:
! 4067: code = SV_ALLOW_BOOTP;
! 4068: break;
! 4069:
! 4070: case BOOTING:
! 4071: code = SV_ALLOW_BOOTING;
! 4072: break;
! 4073:
! 4074: case DYNAMIC_BOOTP:
! 4075: code = SV_DYNAMIC_BOOTP;
! 4076: break;
! 4077:
! 4078: case UNKNOWN_CLIENTS:
! 4079: code = SV_BOOT_UNKNOWN_CLIENTS;
! 4080: break;
! 4081:
! 4082: case DUPLICATES:
! 4083: code = SV_DUPLICATES;
! 4084: break;
! 4085:
! 4086: case DECLINES:
! 4087: code= SV_DECLINES;
! 4088: break;
! 4089:
! 4090: case CLIENT_UPDATES:
! 4091: code = SV_CLIENT_UPDATES;
! 4092: break;
! 4093:
! 4094: case LEASEQUERY:
! 4095: code = SV_LEASEQUERY;
! 4096: break;
! 4097:
! 4098: default:
! 4099: parse_warn (cfile, "expecting allow/deny key");
! 4100: skip_to_semi (cfile);
! 4101: return 0;
! 4102: }
! 4103: /* Reference on option is passed to option cache. */
! 4104: if (!option_code_hash_lookup(&option, server_universe.code_hash,
! 4105: &code, 0, MDL))
! 4106: log_fatal("Unable to find server option %u (%s:%d).",
! 4107: code, MDL);
! 4108: status = option_cache(oc, NULL, data, option, MDL);
! 4109: expression_dereference (&data, MDL);
! 4110: parse_semi (cfile);
! 4111: return status;
! 4112: }
! 4113:
! 4114: void
! 4115: parse_ia_na_declaration(struct parse *cfile) {
! 4116: #if !defined(DHCPv6)
! 4117: parse_warn(cfile, "No DHCPv6 support.");
! 4118: skip_to_semi(cfile);
! 4119: #else /* defined(DHCPv6) */
! 4120: enum dhcp_token token;
! 4121: struct ia_xx *ia;
! 4122: const char *val;
! 4123: struct ia_xx *old_ia;
! 4124: unsigned int len;
! 4125: u_int32_t iaid;
! 4126: struct iaddr iaddr;
! 4127: binding_state_t state;
! 4128: u_int32_t prefer;
! 4129: u_int32_t valid;
! 4130: TIME end_time;
! 4131: struct iasubopt *iaaddr;
! 4132: struct ipv6_pool *pool;
! 4133: char addr_buf[sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255")];
! 4134: isc_boolean_t newbinding;
! 4135: struct binding_scope *scope=NULL;
! 4136: struct binding *bnd;
! 4137: struct binding_value *nv=NULL;
! 4138:
! 4139: if (local_family != AF_INET6) {
! 4140: parse_warn(cfile, "IA_NA is only supported in DHCPv6 mode.");
! 4141: skip_to_semi(cfile);
! 4142: return;
! 4143: }
! 4144:
! 4145: token = next_token(&val, &len, cfile);
! 4146: if (token != STRING) {
! 4147: parse_warn(cfile, "corrupt lease file; "
! 4148: "expecting an iaid+ia_na string");
! 4149: skip_to_semi(cfile);
! 4150: return;
! 4151: }
! 4152: if (len < 5) {
! 4153: parse_warn(cfile, "corrupt lease file; "
! 4154: "iaid+ia_na string too short");
! 4155: skip_to_semi(cfile);
! 4156: return;
! 4157: }
! 4158:
! 4159: memcpy(&iaid, val, 4);
! 4160: ia = NULL;
! 4161: if (ia_allocate(&ia, iaid, val+4, len-4, MDL) != ISC_R_SUCCESS) {
! 4162: log_fatal("Out of memory.");
! 4163: }
! 4164: ia->ia_type = D6O_IA_NA;
! 4165:
! 4166: token = next_token(&val, NULL, cfile);
! 4167: if (token != LBRACE) {
! 4168: parse_warn(cfile, "corrupt lease file; expecting left brace");
! 4169: skip_to_semi(cfile);
! 4170: return;
! 4171: }
! 4172:
! 4173: for (;;) {
! 4174: token = next_token(&val, NULL, cfile);
! 4175: if (token == RBRACE) break;
! 4176:
! 4177: if (token == CLTT) {
! 4178: ia->cltt = parse_date (cfile);
! 4179: continue;
! 4180: }
! 4181:
! 4182: if (token != IAADDR) {
! 4183: parse_warn(cfile, "corrupt lease file; "
! 4184: "expecting IAADDR or right brace");
! 4185: skip_to_semi(cfile);
! 4186: return;
! 4187: }
! 4188:
! 4189: if (!parse_ip6_addr(cfile, &iaddr)) {
! 4190: parse_warn(cfile, "corrupt lease file; "
! 4191: "expecting IPv6 address");
! 4192: skip_to_semi(cfile);
! 4193: return;
! 4194: }
! 4195:
! 4196: token = next_token(&val, NULL, cfile);
! 4197: if (token != LBRACE) {
! 4198: parse_warn(cfile, "corrupt lease file; "
! 4199: "expecting left brace");
! 4200: skip_to_semi(cfile);
! 4201: return;
! 4202: }
! 4203:
! 4204: state = FTS_LAST+1;
! 4205: prefer = valid = 0;
! 4206: end_time = -1;
! 4207: for (;;) {
! 4208: token = next_token(&val, NULL, cfile);
! 4209: if (token == RBRACE) break;
! 4210:
! 4211: switch(token) {
! 4212: /* Lease binding state. */
! 4213: case BINDING:
! 4214: token = next_token(&val, NULL, cfile);
! 4215: if (token != STATE) {
! 4216: parse_warn(cfile, "corrupt lease file; "
! 4217: "expecting state");
! 4218: skip_to_semi(cfile);
! 4219: return;
! 4220: }
! 4221: token = next_token(&val, NULL, cfile);
! 4222: switch (token) {
! 4223: case TOKEN_ABANDONED:
! 4224: state = FTS_ABANDONED;
! 4225: break;
! 4226: case TOKEN_FREE:
! 4227: state = FTS_FREE;
! 4228: break;
! 4229: case TOKEN_ACTIVE:
! 4230: state = FTS_ACTIVE;
! 4231: break;
! 4232: case TOKEN_EXPIRED:
! 4233: state = FTS_EXPIRED;
! 4234: break;
! 4235: case TOKEN_RELEASED:
! 4236: state = FTS_RELEASED;
! 4237: break;
! 4238: default:
! 4239: parse_warn(cfile,
! 4240: "corrupt lease "
! 4241: "file; "
! 4242: "expecting a "
! 4243: "binding state.");
! 4244: skip_to_semi(cfile);
! 4245: return;
! 4246: }
! 4247:
! 4248: token = next_token(&val, NULL, cfile);
! 4249: if (token != SEMI) {
! 4250: parse_warn(cfile, "corrupt lease file; "
! 4251: "expecting "
! 4252: "semicolon.");
! 4253: }
! 4254: break;
! 4255:
! 4256: /* Lease preferred lifetime. */
! 4257: case PREFERRED_LIFE:
! 4258: token = next_token(&val, NULL, cfile);
! 4259: if (token != NUMBER) {
! 4260: parse_warn(cfile, "%s is not a valid "
! 4261: "preferred time",
! 4262: val);
! 4263: skip_to_semi(cfile);
! 4264: continue;
! 4265: }
! 4266: prefer = atoi (val);
! 4267:
! 4268: /*
! 4269: * Currently we peek for the semi-colon to
! 4270: * allow processing of older lease files that
! 4271: * don't have the semi-colon. Eventually we
! 4272: * should remove the peeking code.
! 4273: */
! 4274: token = peek_token(&val, NULL, cfile);
! 4275: if (token == SEMI) {
! 4276: token = next_token(&val, NULL, cfile);
! 4277: } else {
! 4278: parse_warn(cfile,
! 4279: "corrupt lease file; "
! 4280: "expecting semicolon.");
! 4281: }
! 4282: break;
! 4283:
! 4284: /* Lease valid lifetime. */
! 4285: case MAX_LIFE:
! 4286: token = next_token(&val, NULL, cfile);
! 4287: if (token != NUMBER) {
! 4288: parse_warn(cfile, "%s is not a valid "
! 4289: "max time",
! 4290: val);
! 4291: skip_to_semi(cfile);
! 4292: continue;
! 4293: }
! 4294: valid = atoi (val);
! 4295:
! 4296: /*
! 4297: * Currently we peek for the semi-colon to
! 4298: * allow processing of older lease files that
! 4299: * don't have the semi-colon. Eventually we
! 4300: * should remove the peeking code.
! 4301: */
! 4302: token = peek_token(&val, NULL, cfile);
! 4303: if (token == SEMI) {
! 4304: token = next_token(&val, NULL, cfile);
! 4305: } else {
! 4306: parse_warn(cfile,
! 4307: "corrupt lease file; "
! 4308: "expecting semicolon.");
! 4309: }
! 4310: break;
! 4311:
! 4312: /* Lease expiration time. */
! 4313: case ENDS:
! 4314: end_time = parse_date(cfile);
! 4315: break;
! 4316:
! 4317: /* Lease binding scopes. */
! 4318: case TOKEN_SET:
! 4319: token = next_token(&val, NULL, cfile);
! 4320: if ((token != NAME) &&
! 4321: (token != NUMBER_OR_NAME)) {
! 4322: parse_warn(cfile, "%s is not a valid "
! 4323: "variable name",
! 4324: val);
! 4325: skip_to_semi(cfile);
! 4326: continue;
! 4327: }
! 4328:
! 4329: if (scope != NULL)
! 4330: bnd = find_binding(scope, val);
! 4331: else {
! 4332: if (!binding_scope_allocate(&scope,
! 4333: MDL)) {
! 4334: log_fatal("Out of memory for "
! 4335: "lease binding "
! 4336: "scope.");
! 4337: }
! 4338:
! 4339: bnd = NULL;
! 4340: }
! 4341:
! 4342: if (bnd == NULL) {
! 4343: bnd = dmalloc(sizeof(*bnd),
! 4344: MDL);
! 4345: if (bnd == NULL) {
! 4346: log_fatal("No memory for "
! 4347: "lease binding.");
! 4348: }
! 4349:
! 4350: bnd->name = dmalloc(strlen(val) + 1,
! 4351: MDL);
! 4352: if (bnd->name == NULL) {
! 4353: log_fatal("No memory for "
! 4354: "binding name.");
! 4355: }
! 4356: strcpy(bnd->name, val);
! 4357:
! 4358: newbinding = ISC_TRUE;
! 4359: } else {
! 4360: newbinding = ISC_FALSE;
! 4361: }
! 4362:
! 4363: if (!binding_value_allocate(&nv, MDL)) {
! 4364: log_fatal("no memory for binding "
! 4365: "value.");
! 4366: }
! 4367:
! 4368: token = next_token(NULL, NULL, cfile);
! 4369: if (token != EQUAL) {
! 4370: parse_warn(cfile, "expecting '=' in "
! 4371: "set statement.");
! 4372: goto binding_err;
! 4373: }
! 4374:
! 4375: if (!parse_binding_value(cfile, nv)) {
! 4376: binding_err:
! 4377: binding_value_dereference(&nv, MDL);
! 4378: binding_scope_dereference(&scope, MDL);
! 4379: return;
! 4380: }
! 4381:
! 4382: if (newbinding) {
! 4383: binding_value_reference(&bnd->value,
! 4384: nv, MDL);
! 4385: bnd->next = scope->bindings;
! 4386: scope->bindings = bnd;
! 4387: } else {
! 4388: binding_value_dereference(&bnd->value,
! 4389: MDL);
! 4390: binding_value_reference(&bnd->value,
! 4391: nv, MDL);
! 4392: }
! 4393:
! 4394: binding_value_dereference(&nv, MDL);
! 4395: parse_semi(cfile);
! 4396: break;
! 4397:
! 4398: default:
! 4399: parse_warn(cfile, "corrupt lease file; "
! 4400: "expecting ia_na contents, "
! 4401: "got '%s'", val);
! 4402: skip_to_semi(cfile);
! 4403: continue;
! 4404: }
! 4405: }
! 4406:
! 4407: if (state == FTS_LAST+1) {
! 4408: parse_warn(cfile, "corrupt lease file; "
! 4409: "missing state in iaaddr");
! 4410: return;
! 4411: }
! 4412: if (end_time == -1) {
! 4413: parse_warn(cfile, "corrupt lease file; "
! 4414: "missing end time in iaaddr");
! 4415: return;
! 4416: }
! 4417:
! 4418: iaaddr = NULL;
! 4419: if (iasubopt_allocate(&iaaddr, MDL) != ISC_R_SUCCESS) {
! 4420: log_fatal("Out of memory.");
! 4421: }
! 4422: memcpy(&iaaddr->addr, iaddr.iabuf, sizeof(iaaddr->addr));
! 4423: iaaddr->plen = 0;
! 4424: iaaddr->state = state;
! 4425: iaaddr->prefer = prefer;
! 4426: iaaddr->valid = valid;
! 4427: if (iaaddr->state == FTS_RELEASED)
! 4428: iaaddr->hard_lifetime_end_time = end_time;
! 4429:
! 4430: if (scope != NULL) {
! 4431: binding_scope_reference(&iaaddr->scope, scope, MDL);
! 4432: binding_scope_dereference(&scope, MDL);
! 4433: }
! 4434:
! 4435: /* add to our various structures */
! 4436: ia_add_iasubopt(ia, iaaddr, MDL);
! 4437: ia_reference(&iaaddr->ia, ia, MDL);
! 4438: pool = NULL;
! 4439: if (find_ipv6_pool(&pool, D6O_IA_NA,
! 4440: &iaaddr->addr) != ISC_R_SUCCESS) {
! 4441: inet_ntop(AF_INET6, &iaaddr->addr,
! 4442: addr_buf, sizeof(addr_buf));
! 4443: parse_warn(cfile, "no pool found for address %s",
! 4444: addr_buf);
! 4445: return;
! 4446: }
! 4447: add_lease6(pool, iaaddr, end_time);
! 4448: ipv6_pool_dereference(&pool, MDL);
! 4449: iasubopt_dereference(&iaaddr, MDL);
! 4450: }
! 4451:
! 4452: /*
! 4453: * If we have an existing record for this IA_NA, remove it.
! 4454: */
! 4455: old_ia = NULL;
! 4456: if (ia_hash_lookup(&old_ia, ia_na_active,
! 4457: (unsigned char *)ia->iaid_duid.data,
! 4458: ia->iaid_duid.len, MDL)) {
! 4459: ia_hash_delete(ia_na_active,
! 4460: (unsigned char *)ia->iaid_duid.data,
! 4461: ia->iaid_duid.len, MDL);
! 4462: ia_dereference(&old_ia, MDL);
! 4463: }
! 4464:
! 4465: /*
! 4466: * If we have addresses, add this, otherwise don't bother.
! 4467: */
! 4468: if (ia->num_iasubopt > 0) {
! 4469: ia_hash_add(ia_na_active,
! 4470: (unsigned char *)ia->iaid_duid.data,
! 4471: ia->iaid_duid.len, ia, MDL);
! 4472: }
! 4473: ia_dereference(&ia, MDL);
! 4474: #endif /* defined(DHCPv6) */
! 4475: }
! 4476:
! 4477: void
! 4478: parse_ia_ta_declaration(struct parse *cfile) {
! 4479: #if !defined(DHCPv6)
! 4480: parse_warn(cfile, "No DHCPv6 support.");
! 4481: skip_to_semi(cfile);
! 4482: #else /* defined(DHCPv6) */
! 4483: enum dhcp_token token;
! 4484: struct ia_xx *ia;
! 4485: const char *val;
! 4486: struct ia_xx *old_ia;
! 4487: unsigned int len;
! 4488: u_int32_t iaid;
! 4489: struct iaddr iaddr;
! 4490: binding_state_t state;
! 4491: u_int32_t prefer;
! 4492: u_int32_t valid;
! 4493: TIME end_time;
! 4494: struct iasubopt *iaaddr;
! 4495: struct ipv6_pool *pool;
! 4496: char addr_buf[sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255")];
! 4497: isc_boolean_t newbinding;
! 4498: struct binding_scope *scope=NULL;
! 4499: struct binding *bnd;
! 4500: struct binding_value *nv=NULL;
! 4501:
! 4502: if (local_family != AF_INET6) {
! 4503: parse_warn(cfile, "IA_TA is only supported in DHCPv6 mode.");
! 4504: skip_to_semi(cfile);
! 4505: return;
! 4506: }
! 4507:
! 4508: token = next_token(&val, &len, cfile);
! 4509: if (token != STRING) {
! 4510: parse_warn(cfile, "corrupt lease file; "
! 4511: "expecting an iaid+ia_ta string");
! 4512: skip_to_semi(cfile);
! 4513: return;
! 4514: }
! 4515: if (len < 5) {
! 4516: parse_warn(cfile, "corrupt lease file; "
! 4517: "iaid+ia_ta string too short");
! 4518: skip_to_semi(cfile);
! 4519: return;
! 4520: }
! 4521:
! 4522: memcpy(&iaid, val, 4);
! 4523: ia = NULL;
! 4524: if (ia_allocate(&ia, iaid, val+4, len-4, MDL) != ISC_R_SUCCESS) {
! 4525: log_fatal("Out of memory.");
! 4526: }
! 4527: ia->ia_type = D6O_IA_TA;
! 4528:
! 4529: token = next_token(&val, NULL, cfile);
! 4530: if (token != LBRACE) {
! 4531: parse_warn(cfile, "corrupt lease file; expecting left brace");
! 4532: skip_to_semi(cfile);
! 4533: return;
! 4534: }
! 4535:
! 4536: for (;;) {
! 4537: token = next_token(&val, NULL, cfile);
! 4538: if (token == RBRACE) break;
! 4539:
! 4540: if (token == CLTT) {
! 4541: ia->cltt = parse_date (cfile);
! 4542: continue;
! 4543: }
! 4544:
! 4545: if (token != IAADDR) {
! 4546: parse_warn(cfile, "corrupt lease file; "
! 4547: "expecting IAADDR or right brace");
! 4548: skip_to_semi(cfile);
! 4549: return;
! 4550: }
! 4551:
! 4552: if (!parse_ip6_addr(cfile, &iaddr)) {
! 4553: parse_warn(cfile, "corrupt lease file; "
! 4554: "expecting IPv6 address");
! 4555: skip_to_semi(cfile);
! 4556: return;
! 4557: }
! 4558:
! 4559: token = next_token(&val, NULL, cfile);
! 4560: if (token != LBRACE) {
! 4561: parse_warn(cfile, "corrupt lease file; "
! 4562: "expecting left brace");
! 4563: skip_to_semi(cfile);
! 4564: return;
! 4565: }
! 4566:
! 4567: state = FTS_LAST+1;
! 4568: prefer = valid = 0;
! 4569: end_time = -1;
! 4570: for (;;) {
! 4571: token = next_token(&val, NULL, cfile);
! 4572: if (token == RBRACE) break;
! 4573:
! 4574: switch(token) {
! 4575: /* Lease binding state. */
! 4576: case BINDING:
! 4577: token = next_token(&val, NULL, cfile);
! 4578: if (token != STATE) {
! 4579: parse_warn(cfile, "corrupt lease file; "
! 4580: "expecting state");
! 4581: skip_to_semi(cfile);
! 4582: return;
! 4583: }
! 4584: token = next_token(&val, NULL, cfile);
! 4585: switch (token) {
! 4586: case TOKEN_ABANDONED:
! 4587: state = FTS_ABANDONED;
! 4588: break;
! 4589: case TOKEN_FREE:
! 4590: state = FTS_FREE;
! 4591: break;
! 4592: case TOKEN_ACTIVE:
! 4593: state = FTS_ACTIVE;
! 4594: break;
! 4595: case TOKEN_EXPIRED:
! 4596: state = FTS_EXPIRED;
! 4597: break;
! 4598: case TOKEN_RELEASED:
! 4599: state = FTS_RELEASED;
! 4600: break;
! 4601: default:
! 4602: parse_warn(cfile,
! 4603: "corrupt lease "
! 4604: "file; "
! 4605: "expecting a "
! 4606: "binding state.");
! 4607: skip_to_semi(cfile);
! 4608: return;
! 4609: }
! 4610:
! 4611: token = next_token(&val, NULL, cfile);
! 4612: if (token != SEMI) {
! 4613: parse_warn(cfile, "corrupt lease file; "
! 4614: "expecting "
! 4615: "semicolon.");
! 4616: }
! 4617: break;
! 4618:
! 4619: /* Lease preferred lifetime. */
! 4620: case PREFERRED_LIFE:
! 4621: token = next_token(&val, NULL, cfile);
! 4622: if (token != NUMBER) {
! 4623: parse_warn(cfile, "%s is not a valid "
! 4624: "preferred time",
! 4625: val);
! 4626: skip_to_semi(cfile);
! 4627: continue;
! 4628: }
! 4629: prefer = atoi (val);
! 4630:
! 4631: /*
! 4632: * Currently we peek for the semi-colon to
! 4633: * allow processing of older lease files that
! 4634: * don't have the semi-colon. Eventually we
! 4635: * should remove the peeking code.
! 4636: */
! 4637: token = peek_token(&val, NULL, cfile);
! 4638: if (token == SEMI) {
! 4639: token = next_token(&val, NULL, cfile);
! 4640: } else {
! 4641: parse_warn(cfile,
! 4642: "corrupt lease file; "
! 4643: "expecting semicolon.");
! 4644: }
! 4645: break;
! 4646:
! 4647: /* Lease valid lifetime. */
! 4648: case MAX_LIFE:
! 4649: token = next_token(&val, NULL, cfile);
! 4650: if (token != NUMBER) {
! 4651: parse_warn(cfile, "%s is not a valid "
! 4652: "max time",
! 4653: val);
! 4654: skip_to_semi(cfile);
! 4655: continue;
! 4656: }
! 4657: valid = atoi (val);
! 4658:
! 4659: /*
! 4660: * Currently we peek for the semi-colon to
! 4661: * allow processing of older lease files that
! 4662: * don't have the semi-colon. Eventually we
! 4663: * should remove the peeking code.
! 4664: */
! 4665: token = peek_token(&val, NULL, cfile);
! 4666: if (token == SEMI) {
! 4667: token = next_token(&val, NULL, cfile);
! 4668: } else {
! 4669: parse_warn(cfile,
! 4670: "corrupt lease file; "
! 4671: "expecting semicolon.");
! 4672: }
! 4673: break;
! 4674:
! 4675: /* Lease expiration time. */
! 4676: case ENDS:
! 4677: end_time = parse_date(cfile);
! 4678: break;
! 4679:
! 4680: /* Lease binding scopes. */
! 4681: case TOKEN_SET:
! 4682: token = next_token(&val, NULL, cfile);
! 4683: if ((token != NAME) &&
! 4684: (token != NUMBER_OR_NAME)) {
! 4685: parse_warn(cfile, "%s is not a valid "
! 4686: "variable name",
! 4687: val);
! 4688: skip_to_semi(cfile);
! 4689: continue;
! 4690: }
! 4691:
! 4692: if (scope != NULL)
! 4693: bnd = find_binding(scope, val);
! 4694: else {
! 4695: if (!binding_scope_allocate(&scope,
! 4696: MDL)) {
! 4697: log_fatal("Out of memory for "
! 4698: "lease binding "
! 4699: "scope.");
! 4700: }
! 4701:
! 4702: bnd = NULL;
! 4703: }
! 4704:
! 4705: if (bnd == NULL) {
! 4706: bnd = dmalloc(sizeof(*bnd),
! 4707: MDL);
! 4708: if (bnd == NULL) {
! 4709: log_fatal("No memory for "
! 4710: "lease binding.");
! 4711: }
! 4712:
! 4713: bnd->name = dmalloc(strlen(val) + 1,
! 4714: MDL);
! 4715: if (bnd->name == NULL) {
! 4716: log_fatal("No memory for "
! 4717: "binding name.");
! 4718: }
! 4719: strcpy(bnd->name, val);
! 4720:
! 4721: newbinding = ISC_TRUE;
! 4722: } else {
! 4723: newbinding = ISC_FALSE;
! 4724: }
! 4725:
! 4726: if (!binding_value_allocate(&nv, MDL)) {
! 4727: log_fatal("no memory for binding "
! 4728: "value.");
! 4729: }
! 4730:
! 4731: token = next_token(NULL, NULL, cfile);
! 4732: if (token != EQUAL) {
! 4733: parse_warn(cfile, "expecting '=' in "
! 4734: "set statement.");
! 4735: goto binding_err;
! 4736: }
! 4737:
! 4738: if (!parse_binding_value(cfile, nv)) {
! 4739: binding_err:
! 4740: binding_value_dereference(&nv, MDL);
! 4741: binding_scope_dereference(&scope, MDL);
! 4742: return;
! 4743: }
! 4744:
! 4745: if (newbinding) {
! 4746: binding_value_reference(&bnd->value,
! 4747: nv, MDL);
! 4748: bnd->next = scope->bindings;
! 4749: scope->bindings = bnd;
! 4750: } else {
! 4751: binding_value_dereference(&bnd->value,
! 4752: MDL);
! 4753: binding_value_reference(&bnd->value,
! 4754: nv, MDL);
! 4755: }
! 4756:
! 4757: binding_value_dereference(&nv, MDL);
! 4758: parse_semi(cfile);
! 4759: break;
! 4760:
! 4761: default:
! 4762: parse_warn(cfile, "corrupt lease file; "
! 4763: "expecting ia_ta contents, "
! 4764: "got '%s'", val);
! 4765: skip_to_semi(cfile);
! 4766: continue;
! 4767: }
! 4768: }
! 4769:
! 4770: if (state == FTS_LAST+1) {
! 4771: parse_warn(cfile, "corrupt lease file; "
! 4772: "missing state in iaaddr");
! 4773: return;
! 4774: }
! 4775: if (end_time == -1) {
! 4776: parse_warn(cfile, "corrupt lease file; "
! 4777: "missing end time in iaaddr");
! 4778: return;
! 4779: }
! 4780:
! 4781: iaaddr = NULL;
! 4782: if (iasubopt_allocate(&iaaddr, MDL) != ISC_R_SUCCESS) {
! 4783: log_fatal("Out of memory.");
! 4784: }
! 4785: memcpy(&iaaddr->addr, iaddr.iabuf, sizeof(iaaddr->addr));
! 4786: iaaddr->plen = 0;
! 4787: iaaddr->state = state;
! 4788: iaaddr->prefer = prefer;
! 4789: iaaddr->valid = valid;
! 4790: if (iaaddr->state == FTS_RELEASED)
! 4791: iaaddr->hard_lifetime_end_time = end_time;
! 4792:
! 4793: if (scope != NULL) {
! 4794: binding_scope_reference(&iaaddr->scope, scope, MDL);
! 4795: binding_scope_dereference(&scope, MDL);
! 4796: }
! 4797:
! 4798: /* add to our various structures */
! 4799: ia_add_iasubopt(ia, iaaddr, MDL);
! 4800: ia_reference(&iaaddr->ia, ia, MDL);
! 4801: pool = NULL;
! 4802: if (find_ipv6_pool(&pool, D6O_IA_TA,
! 4803: &iaaddr->addr) != ISC_R_SUCCESS) {
! 4804: inet_ntop(AF_INET6, &iaaddr->addr,
! 4805: addr_buf, sizeof(addr_buf));
! 4806: parse_warn(cfile, "no pool found for address %s",
! 4807: addr_buf);
! 4808: return;
! 4809: }
! 4810: add_lease6(pool, iaaddr, end_time);
! 4811: ipv6_pool_dereference(&pool, MDL);
! 4812: iasubopt_dereference(&iaaddr, MDL);
! 4813: }
! 4814:
! 4815: /*
! 4816: * If we have an existing record for this IA_TA, remove it.
! 4817: */
! 4818: old_ia = NULL;
! 4819: if (ia_hash_lookup(&old_ia, ia_ta_active,
! 4820: (unsigned char *)ia->iaid_duid.data,
! 4821: ia->iaid_duid.len, MDL)) {
! 4822: ia_hash_delete(ia_ta_active,
! 4823: (unsigned char *)ia->iaid_duid.data,
! 4824: ia->iaid_duid.len, MDL);
! 4825: ia_dereference(&old_ia, MDL);
! 4826: }
! 4827:
! 4828: /*
! 4829: * If we have addresses, add this, otherwise don't bother.
! 4830: */
! 4831: if (ia->num_iasubopt > 0) {
! 4832: ia_hash_add(ia_ta_active,
! 4833: (unsigned char *)ia->iaid_duid.data,
! 4834: ia->iaid_duid.len, ia, MDL);
! 4835: }
! 4836: ia_dereference(&ia, MDL);
! 4837: #endif /* defined(DHCPv6) */
! 4838: }
! 4839:
! 4840: void
! 4841: parse_ia_pd_declaration(struct parse *cfile) {
! 4842: #if !defined(DHCPv6)
! 4843: parse_warn(cfile, "No DHCPv6 support.");
! 4844: skip_to_semi(cfile);
! 4845: #else /* defined(DHCPv6) */
! 4846: enum dhcp_token token;
! 4847: struct ia_xx *ia;
! 4848: const char *val;
! 4849: struct ia_xx *old_ia;
! 4850: unsigned int len;
! 4851: u_int32_t iaid;
! 4852: struct iaddr iaddr;
! 4853: u_int8_t plen;
! 4854: binding_state_t state;
! 4855: u_int32_t prefer;
! 4856: u_int32_t valid;
! 4857: TIME end_time;
! 4858: struct iasubopt *iapref;
! 4859: struct ipv6_pool *pool;
! 4860: char addr_buf[sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255")];
! 4861: isc_boolean_t newbinding;
! 4862: struct binding_scope *scope=NULL;
! 4863: struct binding *bnd;
! 4864: struct binding_value *nv=NULL;
! 4865:
! 4866: if (local_family != AF_INET6) {
! 4867: parse_warn(cfile, "IA_PD is only supported in DHCPv6 mode.");
! 4868: skip_to_semi(cfile);
! 4869: return;
! 4870: }
! 4871:
! 4872: token = next_token(&val, &len, cfile);
! 4873: if (token != STRING) {
! 4874: parse_warn(cfile, "corrupt lease file; "
! 4875: "expecting an iaid+ia_pd string");
! 4876: skip_to_semi(cfile);
! 4877: return;
! 4878: }
! 4879: if (len < 5) {
! 4880: parse_warn(cfile, "corrupt lease file; "
! 4881: "iaid+ia_pd string too short");
! 4882: skip_to_semi(cfile);
! 4883: return;
! 4884: }
! 4885:
! 4886: memcpy(&iaid, val, 4);
! 4887: ia = NULL;
! 4888: if (ia_allocate(&ia, iaid, val+4, len-4, MDL) != ISC_R_SUCCESS) {
! 4889: log_fatal("Out of memory.");
! 4890: }
! 4891: ia->ia_type = D6O_IA_PD;
! 4892:
! 4893: token = next_token(&val, NULL, cfile);
! 4894: if (token != LBRACE) {
! 4895: parse_warn(cfile, "corrupt lease file; expecting left brace");
! 4896: skip_to_semi(cfile);
! 4897: return;
! 4898: }
! 4899:
! 4900: for (;;) {
! 4901: token = next_token(&val, NULL, cfile);
! 4902: if (token == RBRACE) break;
! 4903:
! 4904: if (token == CLTT) {
! 4905: ia->cltt = parse_date (cfile);
! 4906: continue;
! 4907: }
! 4908:
! 4909: if (token != IAPREFIX) {
! 4910: parse_warn(cfile, "corrupt lease file; expecting "
! 4911: "IAPREFIX or right brace");
! 4912: skip_to_semi(cfile);
! 4913: return;
! 4914: }
! 4915:
! 4916: if (!parse_ip6_prefix(cfile, &iaddr, &plen)) {
! 4917: parse_warn(cfile, "corrupt lease file; "
! 4918: "expecting IPv6 prefix");
! 4919: skip_to_semi(cfile);
! 4920: return;
! 4921: }
! 4922:
! 4923: token = next_token(&val, NULL, cfile);
! 4924: if (token != LBRACE) {
! 4925: parse_warn(cfile, "corrupt lease file; "
! 4926: "expecting left brace");
! 4927: skip_to_semi(cfile);
! 4928: return;
! 4929: }
! 4930:
! 4931: state = FTS_LAST+1;
! 4932: prefer = valid = 0;
! 4933: end_time = -1;
! 4934: for (;;) {
! 4935: token = next_token(&val, NULL, cfile);
! 4936: if (token == RBRACE) break;
! 4937:
! 4938: switch(token) {
! 4939: /* Prefix binding state. */
! 4940: case BINDING:
! 4941: token = next_token(&val, NULL, cfile);
! 4942: if (token != STATE) {
! 4943: parse_warn(cfile, "corrupt lease file; "
! 4944: "expecting state");
! 4945: skip_to_semi(cfile);
! 4946: return;
! 4947: }
! 4948: token = next_token(&val, NULL, cfile);
! 4949: switch (token) {
! 4950: case TOKEN_ABANDONED:
! 4951: state = FTS_ABANDONED;
! 4952: break;
! 4953: case TOKEN_FREE:
! 4954: state = FTS_FREE;
! 4955: break;
! 4956: case TOKEN_ACTIVE:
! 4957: state = FTS_ACTIVE;
! 4958: break;
! 4959: case TOKEN_EXPIRED:
! 4960: state = FTS_EXPIRED;
! 4961: break;
! 4962: case TOKEN_RELEASED:
! 4963: state = FTS_RELEASED;
! 4964: break;
! 4965: default:
! 4966: parse_warn(cfile,
! 4967: "corrupt lease "
! 4968: "file; "
! 4969: "expecting a "
! 4970: "binding state.");
! 4971: skip_to_semi(cfile);
! 4972: return;
! 4973: }
! 4974:
! 4975: token = next_token(&val, NULL, cfile);
! 4976: if (token != SEMI) {
! 4977: parse_warn(cfile, "corrupt lease file; "
! 4978: "expecting "
! 4979: "semicolon.");
! 4980: }
! 4981: break;
! 4982:
! 4983: /* Lease preferred lifetime. */
! 4984: case PREFERRED_LIFE:
! 4985: token = next_token(&val, NULL, cfile);
! 4986: if (token != NUMBER) {
! 4987: parse_warn(cfile, "%s is not a valid "
! 4988: "preferred time",
! 4989: val);
! 4990: skip_to_semi(cfile);
! 4991: continue;
! 4992: }
! 4993: prefer = atoi (val);
! 4994:
! 4995: /*
! 4996: * Currently we peek for the semi-colon to
! 4997: * allow processing of older lease files that
! 4998: * don't have the semi-colon. Eventually we
! 4999: * should remove the peeking code.
! 5000: */
! 5001: token = peek_token(&val, NULL, cfile);
! 5002: if (token == SEMI) {
! 5003: token = next_token(&val, NULL, cfile);
! 5004: } else {
! 5005: parse_warn(cfile,
! 5006: "corrupt lease file; "
! 5007: "expecting semicolon.");
! 5008: }
! 5009: break;
! 5010:
! 5011: /* Lease valid lifetime. */
! 5012: case MAX_LIFE:
! 5013: token = next_token(&val, NULL, cfile);
! 5014: if (token != NUMBER) {
! 5015: parse_warn(cfile, "%s is not a valid "
! 5016: "max time",
! 5017: val);
! 5018: skip_to_semi(cfile);
! 5019: continue;
! 5020: }
! 5021: valid = atoi (val);
! 5022:
! 5023: /*
! 5024: * Currently we peek for the semi-colon to
! 5025: * allow processing of older lease files that
! 5026: * don't have the semi-colon. Eventually we
! 5027: * should remove the peeking code.
! 5028: */
! 5029: token = peek_token(&val, NULL, cfile);
! 5030: if (token == SEMI) {
! 5031: token = next_token(&val, NULL, cfile);
! 5032: } else {
! 5033: parse_warn(cfile,
! 5034: "corrupt lease file; "
! 5035: "expecting semicolon.");
! 5036: }
! 5037: break;
! 5038:
! 5039: /* Prefix expiration time. */
! 5040: case ENDS:
! 5041: end_time = parse_date(cfile);
! 5042: break;
! 5043:
! 5044: /* Prefix binding scopes. */
! 5045: case TOKEN_SET:
! 5046: token = next_token(&val, NULL, cfile);
! 5047: if ((token != NAME) &&
! 5048: (token != NUMBER_OR_NAME)) {
! 5049: parse_warn(cfile, "%s is not a valid "
! 5050: "variable name",
! 5051: val);
! 5052: skip_to_semi(cfile);
! 5053: continue;
! 5054: }
! 5055:
! 5056: if (scope != NULL)
! 5057: bnd = find_binding(scope, val);
! 5058: else {
! 5059: if (!binding_scope_allocate(&scope,
! 5060: MDL)) {
! 5061: log_fatal("Out of memory for "
! 5062: "lease binding "
! 5063: "scope.");
! 5064: }
! 5065:
! 5066: bnd = NULL;
! 5067: }
! 5068:
! 5069: if (bnd == NULL) {
! 5070: bnd = dmalloc(sizeof(*bnd),
! 5071: MDL);
! 5072: if (bnd == NULL) {
! 5073: log_fatal("No memory for "
! 5074: "prefix binding.");
! 5075: }
! 5076:
! 5077: bnd->name = dmalloc(strlen(val) + 1,
! 5078: MDL);
! 5079: if (bnd->name == NULL) {
! 5080: log_fatal("No memory for "
! 5081: "binding name.");
! 5082: }
! 5083: strcpy(bnd->name, val);
! 5084:
! 5085: newbinding = ISC_TRUE;
! 5086: } else {
! 5087: newbinding = ISC_FALSE;
! 5088: }
! 5089:
! 5090: if (!binding_value_allocate(&nv, MDL)) {
! 5091: log_fatal("no memory for binding "
! 5092: "value.");
! 5093: }
! 5094:
! 5095: token = next_token(NULL, NULL, cfile);
! 5096: if (token != EQUAL) {
! 5097: parse_warn(cfile, "expecting '=' in "
! 5098: "set statement.");
! 5099: goto binding_err;
! 5100: }
! 5101:
! 5102: if (!parse_binding_value(cfile, nv)) {
! 5103: binding_err:
! 5104: binding_value_dereference(&nv, MDL);
! 5105: binding_scope_dereference(&scope, MDL);
! 5106: return;
! 5107: }
! 5108:
! 5109: if (newbinding) {
! 5110: binding_value_reference(&bnd->value,
! 5111: nv, MDL);
! 5112: bnd->next = scope->bindings;
! 5113: scope->bindings = bnd;
! 5114: } else {
! 5115: binding_value_dereference(&bnd->value,
! 5116: MDL);
! 5117: binding_value_reference(&bnd->value,
! 5118: nv, MDL);
! 5119: }
! 5120:
! 5121: binding_value_dereference(&nv, MDL);
! 5122: parse_semi(cfile);
! 5123: break;
! 5124:
! 5125: default:
! 5126: parse_warn(cfile, "corrupt lease file; "
! 5127: "expecting ia_pd contents, "
! 5128: "got '%s'", val);
! 5129: skip_to_semi(cfile);
! 5130: continue;
! 5131: }
! 5132: }
! 5133:
! 5134: if (state == FTS_LAST+1) {
! 5135: parse_warn(cfile, "corrupt lease file; "
! 5136: "missing state in iaprefix");
! 5137: return;
! 5138: }
! 5139: if (end_time == -1) {
! 5140: parse_warn(cfile, "corrupt lease file; "
! 5141: "missing end time in iaprefix");
! 5142: return;
! 5143: }
! 5144:
! 5145: iapref = NULL;
! 5146: if (iasubopt_allocate(&iapref, MDL) != ISC_R_SUCCESS) {
! 5147: log_fatal("Out of memory.");
! 5148: }
! 5149: memcpy(&iapref->addr, iaddr.iabuf, sizeof(iapref->addr));
! 5150: iapref->plen = plen;
! 5151: iapref->state = state;
! 5152: iapref->prefer = prefer;
! 5153: iapref->valid = valid;
! 5154: if (iapref->state == FTS_RELEASED)
! 5155: iapref->hard_lifetime_end_time = end_time;
! 5156:
! 5157: if (scope != NULL) {
! 5158: binding_scope_reference(&iapref->scope, scope, MDL);
! 5159: binding_scope_dereference(&scope, MDL);
! 5160: }
! 5161:
! 5162: /* add to our various structures */
! 5163: ia_add_iasubopt(ia, iapref, MDL);
! 5164: ia_reference(&iapref->ia, ia, MDL);
! 5165: pool = NULL;
! 5166: if (find_ipv6_pool(&pool, D6O_IA_PD,
! 5167: &iapref->addr) != ISC_R_SUCCESS) {
! 5168: inet_ntop(AF_INET6, &iapref->addr,
! 5169: addr_buf, sizeof(addr_buf));
! 5170: parse_warn(cfile, "no pool found for address %s",
! 5171: addr_buf);
! 5172: return;
! 5173: }
! 5174: add_lease6(pool, iapref, end_time);
! 5175: ipv6_pool_dereference(&pool, MDL);
! 5176: iasubopt_dereference(&iapref, MDL);
! 5177: }
! 5178:
! 5179: /*
! 5180: * If we have an existing record for this IA_PD, remove it.
! 5181: */
! 5182: old_ia = NULL;
! 5183: if (ia_hash_lookup(&old_ia, ia_pd_active,
! 5184: (unsigned char *)ia->iaid_duid.data,
! 5185: ia->iaid_duid.len, MDL)) {
! 5186: ia_hash_delete(ia_pd_active,
! 5187: (unsigned char *)ia->iaid_duid.data,
! 5188: ia->iaid_duid.len, MDL);
! 5189: ia_dereference(&old_ia, MDL);
! 5190: }
! 5191:
! 5192: /*
! 5193: * If we have prefixes, add this, otherwise don't bother.
! 5194: */
! 5195: if (ia->num_iasubopt > 0) {
! 5196: ia_hash_add(ia_pd_active,
! 5197: (unsigned char *)ia->iaid_duid.data,
! 5198: ia->iaid_duid.len, ia, MDL);
! 5199: }
! 5200: ia_dereference(&ia, MDL);
! 5201: #endif /* defined(DHCPv6) */
! 5202: }
! 5203:
! 5204: #ifdef DHCPv6
! 5205: /*
! 5206: * When we parse a server-duid statement in a lease file, we are
! 5207: * looking at the saved server DUID from a previous run. In this case
! 5208: * we expect it to be followed by the binary representation of the
! 5209: * DUID stored in a string:
! 5210: *
! 5211: * server-duid "\000\001\000\001\015\221\034JRT\000\0224Y";
! 5212: */
! 5213: void
! 5214: parse_server_duid(struct parse *cfile) {
! 5215: enum dhcp_token token;
! 5216: const char *val;
! 5217: unsigned int len;
! 5218: struct data_string duid;
! 5219:
! 5220: token = next_token(&val, &len, cfile);
! 5221: if (token != STRING) {
! 5222: parse_warn(cfile, "corrupt lease file; expecting a DUID");
! 5223: skip_to_semi(cfile);
! 5224: return;
! 5225: }
! 5226:
! 5227: memset(&duid, 0, sizeof(duid));
! 5228: duid.len = len;
! 5229: if (!buffer_allocate(&duid.buffer, duid.len, MDL)) {
! 5230: log_fatal("Out of memory storing DUID");
! 5231: }
! 5232: duid.data = (unsigned char *)duid.buffer->data;
! 5233: memcpy(duid.buffer->data, val, len);
! 5234:
! 5235: set_server_duid(&duid);
! 5236:
! 5237: data_string_forget(&duid, MDL);
! 5238:
! 5239: token = next_token(&val, &len, cfile);
! 5240: if (token != SEMI) {
! 5241: parse_warn(cfile, "corrupt lease file; expecting a semicolon");
! 5242: skip_to_semi(cfile);
! 5243: return;
! 5244: }
! 5245: }
! 5246:
! 5247: /*
! 5248: * When we parse a server-duid statement in a config file, we will
! 5249: * have the type of the server DUID to generate, and possibly the
! 5250: * actual value defined.
! 5251: *
! 5252: * server-duid llt;
! 5253: * server-duid llt ethernet|ieee802|fddi 213982198 00:16:6F:49:7D:9B;
! 5254: * server-duid ll;
! 5255: * server-duid ll ethernet|ieee802|fddi 00:16:6F:49:7D:9B;
! 5256: * server-duid en 2495 "enterprise-specific-identifier-1234";
! 5257: */
! 5258: void
! 5259: parse_server_duid_conf(struct parse *cfile) {
! 5260: enum dhcp_token token;
! 5261: const char *val;
! 5262: unsigned int len;
! 5263: u_int32_t enterprise_number;
! 5264: int ll_type;
! 5265: struct data_string ll_addr;
! 5266: u_int32_t llt_time;
! 5267: struct data_string duid;
! 5268: int duid_type_num;
! 5269:
! 5270: /*
! 5271: * Consume the SERVER_DUID token.
! 5272: */
! 5273: token = next_token(NULL, NULL, cfile);
! 5274:
! 5275: /*
! 5276: * Obtain the DUID type.
! 5277: */
! 5278: token = next_token(&val, NULL, cfile);
! 5279:
! 5280: /*
! 5281: * Enterprise is the easiest - enterprise number and raw data
! 5282: * are required.
! 5283: */
! 5284: if (token == EN) {
! 5285: /*
! 5286: * Get enterprise number and identifier.
! 5287: */
! 5288: token = next_token(&val, NULL, cfile);
! 5289: if (token != NUMBER) {
! 5290: parse_warn(cfile, "enterprise number expected");
! 5291: skip_to_semi(cfile);
! 5292: return;
! 5293: }
! 5294: enterprise_number = atoi(val);
! 5295:
! 5296: token = next_token(&val, &len, cfile);
! 5297: if (token != STRING) {
! 5298: parse_warn(cfile, "identifier expected");
! 5299: skip_to_semi(cfile);
! 5300: return;
! 5301: }
! 5302:
! 5303: /*
! 5304: * Save the DUID.
! 5305: */
! 5306: memset(&duid, 0, sizeof(duid));
! 5307: duid.len = 2 + 4 + len;
! 5308: if (!buffer_allocate(&duid.buffer, duid.len, MDL)) {
! 5309: log_fatal("Out of memory storing DUID");
! 5310: }
! 5311: duid.data = (unsigned char *)duid.buffer->data;
! 5312: putUShort(duid.buffer->data, DUID_EN);
! 5313: putULong(duid.buffer->data + 2, enterprise_number);
! 5314: memcpy(duid.buffer->data + 6, val, len);
! 5315:
! 5316: set_server_duid(&duid);
! 5317: data_string_forget(&duid, MDL);
! 5318: }
! 5319:
! 5320: /*
! 5321: * Next easiest is the link-layer DUID. It consists only of
! 5322: * the LL directive, or optionally the specific value to use.
! 5323: *
! 5324: * If we have LL only, then we set the type. If we have the
! 5325: * value, then we set the actual DUID.
! 5326: */
! 5327: else if (token == LL) {
! 5328: if (peek_token(NULL, NULL, cfile) == SEMI) {
! 5329: set_server_duid_type(DUID_LL);
! 5330: } else {
! 5331: /*
! 5332: * Get our hardware type and address.
! 5333: */
! 5334: token = next_token(NULL, NULL, cfile);
! 5335: switch (token) {
! 5336: case ETHERNET:
! 5337: ll_type = HTYPE_ETHER;
! 5338: break;
! 5339: case TOKEN_RING:
! 5340: ll_type = HTYPE_IEEE802;
! 5341: break;
! 5342: case TOKEN_FDDI:
! 5343: ll_type = HTYPE_FDDI;
! 5344: break;
! 5345: default:
! 5346: parse_warn(cfile, "hardware type expected");
! 5347: skip_to_semi(cfile);
! 5348: return;
! 5349: }
! 5350: memset(&ll_addr, 0, sizeof(ll_addr));
! 5351: if (!parse_cshl(&ll_addr, cfile)) {
! 5352: return;
! 5353: }
! 5354:
! 5355: /*
! 5356: * Save the DUID.
! 5357: */
! 5358: memset(&duid, 0, sizeof(duid));
! 5359: duid.len = 2 + 2 + ll_addr.len;
! 5360: if (!buffer_allocate(&duid.buffer, duid.len, MDL)) {
! 5361: log_fatal("Out of memory storing DUID");
! 5362: }
! 5363: duid.data = (unsigned char *)duid.buffer->data;
! 5364: putUShort(duid.buffer->data, DUID_LL);
! 5365: putULong(duid.buffer->data + 2, ll_type);
! 5366: memcpy(duid.buffer->data + 4,
! 5367: ll_addr.data, ll_addr.len);
! 5368:
! 5369: set_server_duid(&duid);
! 5370: data_string_forget(&duid, MDL);
! 5371: data_string_forget(&ll_addr, MDL);
! 5372: }
! 5373: }
! 5374:
! 5375: /*
! 5376: * Finally the link-layer DUID plus time. It consists only of
! 5377: * the LLT directive, or optionally the specific value to use.
! 5378: *
! 5379: * If we have LLT only, then we set the type. If we have the
! 5380: * value, then we set the actual DUID.
! 5381: */
! 5382: else if (token == LLT) {
! 5383: if (peek_token(NULL, NULL, cfile) == SEMI) {
! 5384: set_server_duid_type(DUID_LLT);
! 5385: } else {
! 5386: /*
! 5387: * Get our hardware type, timestamp, and address.
! 5388: */
! 5389: token = next_token(NULL, NULL, cfile);
! 5390: switch (token) {
! 5391: case ETHERNET:
! 5392: ll_type = HTYPE_ETHER;
! 5393: break;
! 5394: case TOKEN_RING:
! 5395: ll_type = HTYPE_IEEE802;
! 5396: break;
! 5397: case TOKEN_FDDI:
! 5398: ll_type = HTYPE_FDDI;
! 5399: break;
! 5400: default:
! 5401: parse_warn(cfile, "hardware type expected");
! 5402: skip_to_semi(cfile);
! 5403: return;
! 5404: }
! 5405:
! 5406: token = next_token(&val, NULL, cfile);
! 5407: if (token != NUMBER) {
! 5408: parse_warn(cfile, "timestamp expected");
! 5409: skip_to_semi(cfile);
! 5410: return;
! 5411: }
! 5412: llt_time = atoi(val);
! 5413:
! 5414: memset(&ll_addr, 0, sizeof(ll_addr));
! 5415: if (!parse_cshl(&ll_addr, cfile)) {
! 5416: return;
! 5417: }
! 5418:
! 5419: /*
! 5420: * Save the DUID.
! 5421: */
! 5422: memset(&duid, 0, sizeof(duid));
! 5423: duid.len = 2 + 2 + 4 + ll_addr.len;
! 5424: if (!buffer_allocate(&duid.buffer, duid.len, MDL)) {
! 5425: log_fatal("Out of memory storing DUID");
! 5426: }
! 5427: duid.data = (unsigned char *)duid.buffer->data;
! 5428: putUShort(duid.buffer->data, DUID_LLT);
! 5429: putULong(duid.buffer->data + 2, ll_type);
! 5430: putULong(duid.buffer->data + 4, llt_time);
! 5431: memcpy(duid.buffer->data + 8,
! 5432: ll_addr.data, ll_addr.len);
! 5433:
! 5434: set_server_duid(&duid);
! 5435: data_string_forget(&duid, MDL);
! 5436: data_string_forget(&ll_addr, MDL);
! 5437: }
! 5438: }
! 5439:
! 5440: /*
! 5441: * If users want they can use a number for DUID types.
! 5442: * This is useful for supporting future, not-yet-defined
! 5443: * DUID types.
! 5444: *
! 5445: * In this case, they have to put in the complete value.
! 5446: *
! 5447: * This also works for existing DUID types of course.
! 5448: */
! 5449: else if (token == NUMBER) {
! 5450: duid_type_num = atoi(val);
! 5451:
! 5452: token = next_token(&val, &len, cfile);
! 5453: if (token != STRING) {
! 5454: parse_warn(cfile, "identifier expected");
! 5455: skip_to_semi(cfile);
! 5456: return;
! 5457: }
! 5458:
! 5459: /*
! 5460: * Save the DUID.
! 5461: */
! 5462: memset(&duid, 0, sizeof(duid));
! 5463: duid.len = 2 + len;
! 5464: if (!buffer_allocate(&duid.buffer, duid.len, MDL)) {
! 5465: log_fatal("Out of memory storing DUID");
! 5466: }
! 5467: duid.data = (unsigned char *)duid.buffer->data;
! 5468: putUShort(duid.buffer->data, duid_type_num);
! 5469: memcpy(duid.buffer->data + 2, val, len);
! 5470:
! 5471: set_server_duid(&duid);
! 5472: data_string_forget(&duid, MDL);
! 5473: }
! 5474:
! 5475: /*
! 5476: * Anything else is an error.
! 5477: */
! 5478: else {
! 5479: parse_warn(cfile, "DUID type of LLT, EN, or LL expected");
! 5480: skip_to_semi(cfile);
! 5481: return;
! 5482: }
! 5483:
! 5484: /*
! 5485: * Finally consume our trailing semicolon.
! 5486: */
! 5487: token = next_token(NULL, NULL, cfile);
! 5488: if (token != SEMI) {
! 5489: parse_warn(cfile, "semicolon expected");
! 5490: skip_to_semi(cfile);
! 5491: }
! 5492: }
! 5493:
! 5494: #endif /* DHCPv6 */
! 5495:
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>