Annotation of embedaddon/dhcp/common/parse.c, revision 1.1
1.1 ! misho 1: /* parse.c
! 2:
! 3: Common parser code for dhcpd and dhclient. */
! 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: #include <syslog.h>
! 37:
! 38: /* Enumerations can be specified in option formats, and are used for
! 39: parsing, so we define the routines that manage them here. */
! 40:
! 41: struct enumeration *enumerations;
! 42:
! 43: void add_enumeration (struct enumeration *enumeration)
! 44: {
! 45: enumeration -> next = enumerations;
! 46: enumerations = enumeration;
! 47: }
! 48:
! 49: struct enumeration *find_enumeration (const char *name, int length)
! 50: {
! 51: struct enumeration *e;
! 52:
! 53: for (e = enumerations; e; e = e -> next)
! 54: if (strlen (e -> name) == length &&
! 55: !memcmp (e -> name, name, (unsigned)length))
! 56: return e;
! 57: return (struct enumeration *)0;
! 58: }
! 59:
! 60: struct enumeration_value *find_enumeration_value (const char *name,
! 61: int length,
! 62: unsigned *widthp,
! 63: const char *value)
! 64: {
! 65: struct enumeration *e;
! 66: int i;
! 67:
! 68: e = find_enumeration (name, length);
! 69: if (e) {
! 70: if (widthp != NULL)
! 71: *widthp = e->width;
! 72: for (i = 0; e -> values [i].name; i++) {
! 73: if (!strcmp (value, e -> values [i].name))
! 74: return &e -> values [i];
! 75: }
! 76: }
! 77: return (struct enumeration_value *)0;
! 78: }
! 79:
! 80: /* Skip to the semicolon ending the current statement. If we encounter
! 81: braces, the matching closing brace terminates the statement. If we
! 82: encounter a right brace but haven't encountered a left brace, return
! 83: leaving the brace in the token buffer for the caller. If we see a
! 84: semicolon and haven't seen a left brace, return. This lets us skip
! 85: over:
! 86:
! 87: statement;
! 88: statement foo bar { }
! 89: statement foo bar { statement { } }
! 90: statement}
! 91:
! 92: ...et cetera. */
! 93:
! 94: void skip_to_semi (cfile)
! 95: struct parse *cfile;
! 96: {
! 97: skip_to_rbrace (cfile, 0);
! 98: }
! 99:
! 100: void skip_to_rbrace (cfile, brace_count)
! 101: struct parse *cfile;
! 102: int brace_count;
! 103: {
! 104: enum dhcp_token token;
! 105: const char *val;
! 106:
! 107: #if defined (DEBUG_TOKEN)
! 108: log_error ("skip_to_rbrace: %d\n", brace_count);
! 109: #endif
! 110: do {
! 111: token = peek_token (&val, (unsigned *)0, cfile);
! 112: if (token == RBRACE) {
! 113: token = next_token (&val, (unsigned *)0, cfile);
! 114: if (brace_count) {
! 115: if (!--brace_count)
! 116: return;
! 117: } else
! 118: return;
! 119: } else if (token == LBRACE) {
! 120: brace_count++;
! 121: } else if (token == SEMI && !brace_count) {
! 122: token = next_token (&val, (unsigned *)0, cfile);
! 123: return;
! 124: } else if (token == EOL) {
! 125: /* EOL only happens when parsing /etc/resolv.conf,
! 126: and we treat it like a semicolon because the
! 127: resolv.conf file is line-oriented. */
! 128: token = next_token (&val, (unsigned *)0, cfile);
! 129: return;
! 130: }
! 131: token = next_token (&val, (unsigned *)0, cfile);
! 132: } while (token != END_OF_FILE);
! 133: }
! 134:
! 135: int parse_semi (cfile)
! 136: struct parse *cfile;
! 137: {
! 138: enum dhcp_token token;
! 139: const char *val;
! 140:
! 141: token = next_token (&val, (unsigned *)0, cfile);
! 142: if (token != SEMI) {
! 143: parse_warn (cfile, "semicolon expected.");
! 144: skip_to_semi (cfile);
! 145: return 0;
! 146: }
! 147: return 1;
! 148: }
! 149:
! 150: /* string-parameter :== STRING SEMI */
! 151:
! 152: int parse_string (cfile, sptr, lptr)
! 153: struct parse *cfile;
! 154: char **sptr;
! 155: unsigned *lptr;
! 156: {
! 157: const char *val;
! 158: enum dhcp_token token;
! 159: char *s;
! 160: unsigned len;
! 161:
! 162: token = next_token (&val, &len, cfile);
! 163: if (token != STRING) {
! 164: parse_warn (cfile, "expecting a string");
! 165: skip_to_semi (cfile);
! 166: return 0;
! 167: }
! 168: s = (char *)dmalloc (len + 1, MDL);
! 169: if (!s)
! 170: log_fatal ("no memory for string %s.", val);
! 171: memcpy (s, val, len + 1);
! 172:
! 173: if (!parse_semi (cfile)) {
! 174: dfree (s, MDL);
! 175: return 0;
! 176: }
! 177: if (sptr)
! 178: *sptr = s;
! 179: else
! 180: dfree (s, MDL);
! 181: if (lptr)
! 182: *lptr = len;
! 183: return 1;
! 184: }
! 185:
! 186: /*
! 187: * hostname :== IDENTIFIER
! 188: * | IDENTIFIER DOT
! 189: * | hostname DOT IDENTIFIER
! 190: */
! 191:
! 192: char *parse_host_name (cfile)
! 193: struct parse *cfile;
! 194: {
! 195: const char *val;
! 196: enum dhcp_token token;
! 197: unsigned len = 0;
! 198: char *s;
! 199: char *t;
! 200: pair c = (pair)0;
! 201: int ltid = 0;
! 202:
! 203: /* Read a dotted hostname... */
! 204: do {
! 205: /* Read a token, which should be an identifier. */
! 206: token = peek_token (&val, (unsigned *)0, cfile);
! 207: if (!is_identifier (token) && token != NUMBER)
! 208: break;
! 209: token = next_token (&val, (unsigned *)0, cfile);
! 210:
! 211: /* Store this identifier... */
! 212: if (!(s = (char *)dmalloc (strlen (val) + 1, MDL)))
! 213: log_fatal ("can't allocate temp space for hostname.");
! 214: strcpy (s, val);
! 215: c = cons ((caddr_t)s, c);
! 216: len += strlen (s) + 1;
! 217: /* Look for a dot; if it's there, keep going, otherwise
! 218: we're done. */
! 219: token = peek_token (&val, (unsigned *)0, cfile);
! 220: if (token == DOT) {
! 221: token = next_token (&val, (unsigned *)0, cfile);
! 222: ltid = 1;
! 223: } else
! 224: ltid = 0;
! 225: } while (token == DOT);
! 226:
! 227: /* Should be at least one token. */
! 228: if (!len)
! 229: return (char *)0;
! 230:
! 231: /* Assemble the hostname together into a string. */
! 232: if (!(s = (char *)dmalloc (len + ltid, MDL)))
! 233: log_fatal ("can't allocate space for hostname.");
! 234: t = s + len + ltid;
! 235: *--t = 0;
! 236: if (ltid)
! 237: *--t = '.';
! 238: while (c) {
! 239: pair cdr = c -> cdr;
! 240: unsigned l = strlen ((char *)(c -> car));
! 241: t -= l;
! 242: memcpy (t, (char *)(c -> car), l);
! 243: /* Free up temp space. */
! 244: dfree (c -> car, MDL);
! 245: dfree (c, MDL);
! 246: c = cdr;
! 247: if (t != s)
! 248: *--t = '.';
! 249: }
! 250: return s;
! 251: }
! 252:
! 253: /* ip-addr-or-hostname :== ip-address | hostname
! 254: ip-address :== NUMBER DOT NUMBER DOT NUMBER DOT NUMBER
! 255:
! 256: Parse an ip address or a hostname. If uniform is zero, put in
! 257: an expr_substring node to limit hostnames that evaluate to more
! 258: than one IP address.
! 259:
! 260: Note that RFC1123 permits hostnames to consist of all digits,
! 261: making it difficult to quickly disambiguate them from ip addresses.
! 262: */
! 263:
! 264: int parse_ip_addr_or_hostname (expr, cfile, uniform)
! 265: struct expression **expr;
! 266: struct parse *cfile;
! 267: int uniform;
! 268: {
! 269: const char *val;
! 270: enum dhcp_token token;
! 271: unsigned char addr [4];
! 272: unsigned len = sizeof addr;
! 273: char *name;
! 274: struct expression *x = (struct expression *)0;
! 275: int ipaddr = 0;
! 276:
! 277: token = peek_token (&val, (unsigned *)0, cfile);
! 278:
! 279: if (token == NUMBER) {
! 280: /*
! 281: * a hostname may be numeric, but domain names must
! 282: * start with a letter, so we can disambiguate by
! 283: * looking ahead a few tokens. we save the parse
! 284: * context first, and restore it after we know what
! 285: * we're dealing with.
! 286: */
! 287: save_parse_state(cfile);
! 288: (void) next_token(NULL, NULL, cfile);
! 289: if (next_token(NULL, NULL, cfile) == DOT &&
! 290: next_token(NULL, NULL, cfile) == NUMBER)
! 291: ipaddr = 1;
! 292: restore_parse_state(cfile);
! 293:
! 294: if (ipaddr &&
! 295: parse_numeric_aggregate (cfile, addr, &len, DOT, 10, 8))
! 296: return make_const_data (expr, addr, len, 0, 1, MDL);
! 297:
! 298: }
! 299:
! 300: if (is_identifier (token) || token == NUMBER) {
! 301: name = parse_host_name (cfile);
! 302: if (!name)
! 303: return 0;
! 304: if (!make_host_lookup (expr, name)) {
! 305: dfree(name, MDL);
! 306: return 0;
! 307: }
! 308: dfree(name, MDL);
! 309: if (!uniform) {
! 310: if (!make_limit (&x, *expr, 4))
! 311: return 0;
! 312: expression_dereference (expr, MDL);
! 313: *expr = x;
! 314: }
! 315: } else {
! 316: if (token != RBRACE && token != LBRACE)
! 317: token = next_token (&val, (unsigned *)0, cfile);
! 318: parse_warn (cfile, "%s (%d): expecting IP address or hostname",
! 319: val, token);
! 320: if (token != SEMI)
! 321: skip_to_semi (cfile);
! 322: return 0;
! 323: }
! 324:
! 325: return 1;
! 326: }
! 327:
! 328: /*
! 329: * ip-address :== NUMBER DOT NUMBER DOT NUMBER DOT NUMBER
! 330: */
! 331:
! 332: int parse_ip_addr (cfile, addr)
! 333: struct parse *cfile;
! 334: struct iaddr *addr;
! 335: {
! 336: addr -> len = 4;
! 337: if (parse_numeric_aggregate (cfile, addr -> iabuf,
! 338: &addr -> len, DOT, 10, 8))
! 339: return 1;
! 340: return 0;
! 341: }
! 342:
! 343: /*
! 344: * Return true if every character in the string is hexadecimal.
! 345: */
! 346: static int
! 347: is_hex_string(const char *s) {
! 348: while (*s != '\0') {
! 349: if (!isxdigit((int)*s)) {
! 350: return 0;
! 351: }
! 352: s++;
! 353: }
! 354: return 1;
! 355: }
! 356:
! 357: /*
! 358: * ip-address6 :== (complicated set of rules)
! 359: *
! 360: * See section 2.2 of RFC 1884 for details.
! 361: *
! 362: * We are lazy for this. We pull numbers, names, colons, and dots
! 363: * together and then throw the resulting string at the inet_pton()
! 364: * function.
! 365: */
! 366:
! 367: int
! 368: parse_ip6_addr(struct parse *cfile, struct iaddr *addr) {
! 369: enum dhcp_token token;
! 370: const char *val;
! 371: int val_len;
! 372:
! 373: char v6[sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255")];
! 374: int v6_len;
! 375:
! 376: /*
! 377: * First token is non-raw. This way we eat any whitespace before
! 378: * our IPv6 address begins, like one would expect.
! 379: */
! 380: token = peek_token(&val, NULL, cfile);
! 381:
! 382: /*
! 383: * Gather symbols.
! 384: */
! 385: v6_len = 0;
! 386: for (;;) {
! 387: if ((((token == NAME) || (token == NUMBER_OR_NAME)) &&
! 388: is_hex_string(val)) ||
! 389: (token == NUMBER) ||
! 390: (token == DOT) ||
! 391: (token == COLON)) {
! 392:
! 393: next_raw_token(&val, NULL, cfile);
! 394: val_len = strlen(val);
! 395: if ((v6_len + val_len) >= sizeof(v6)) {
! 396: parse_warn(cfile, "Invalid IPv6 address.");
! 397: skip_to_semi(cfile);
! 398: return 0;
! 399: }
! 400: memcpy(v6+v6_len, val, val_len);
! 401: v6_len += val_len;
! 402:
! 403: } else {
! 404: break;
! 405: }
! 406: token = peek_raw_token(&val, NULL, cfile);
! 407: }
! 408: v6[v6_len] = '\0';
! 409:
! 410: /*
! 411: * Use inet_pton() for actual work.
! 412: */
! 413: if (inet_pton(AF_INET6, v6, addr->iabuf) <= 0) {
! 414: parse_warn(cfile, "Invalid IPv6 address.");
! 415: skip_to_semi(cfile);
! 416: return 0;
! 417: }
! 418: addr->len = 16;
! 419: return 1;
! 420: }
! 421:
! 422: /*
! 423: * Same as parse_ip6_addr() above, but returns the value in the
! 424: * expression rather than in an address structure.
! 425: */
! 426: int
! 427: parse_ip6_addr_expr(struct expression **expr,
! 428: struct parse *cfile) {
! 429: struct iaddr addr;
! 430:
! 431: if (!parse_ip6_addr(cfile, &addr)) {
! 432: return 0;
! 433: }
! 434: return make_const_data(expr, addr.iabuf, addr.len, 0, 1, MDL);
! 435: }
! 436:
! 437: /*
! 438: * ip6-prefix :== ip6-address "/" NUMBER
! 439: */
! 440: int
! 441: parse_ip6_prefix(struct parse *cfile, struct iaddr *addr, u_int8_t *plen) {
! 442: enum dhcp_token token;
! 443: const char *val;
! 444: int n;
! 445:
! 446: if (!parse_ip6_addr(cfile, addr)) {
! 447: return 0;
! 448: }
! 449: token = next_token(&val, NULL, cfile);
! 450: if (token != SLASH) {
! 451: parse_warn(cfile, "Slash expected.");
! 452: if (token != SEMI)
! 453: skip_to_semi(cfile);
! 454: return 0;
! 455: }
! 456: token = next_token(&val, NULL, cfile);
! 457: if (token != NUMBER) {
! 458: parse_warn(cfile, "Number expected.");
! 459: if (token != SEMI)
! 460: skip_to_semi(cfile);
! 461: return 0;
! 462: }
! 463: n = atoi(val);
! 464: if ((n < 0) || (n > 128)) {
! 465: parse_warn(cfile, "Invalid IPv6 prefix length.");
! 466: skip_to_semi(cfile);
! 467: return 0;
! 468: }
! 469: if (!is_cidr_mask_valid(addr, n)) {
! 470: parse_warn(cfile, "network mask too short.");
! 471: skip_to_semi(cfile);
! 472: return 0;
! 473: }
! 474: *plen = n;
! 475: return 1;
! 476: }
! 477:
! 478: /*
! 479: * ip-address-with-subnet :== ip-address |
! 480: * ip-address "/" NUMBER
! 481: */
! 482:
! 483: int
! 484: parse_ip_addr_with_subnet(cfile, match)
! 485: struct parse *cfile;
! 486: struct iaddrmatch *match;
! 487: {
! 488: const char *val, *orig;
! 489: enum dhcp_token token;
! 490: int prefixlen;
! 491: int fflen;
! 492: unsigned char newval, warnmask=0;
! 493:
! 494: if (parse_ip_addr(cfile, &match->addr)) {
! 495: /* default to host mask */
! 496: prefixlen = match->addr.len * 8;
! 497:
! 498: token = peek_token(&val, NULL, cfile);
! 499:
! 500: if (token == SLASH) {
! 501: next_token(&val, NULL, cfile);
! 502: token = next_token(&val, NULL, cfile);
! 503:
! 504: if (token != NUMBER) {
! 505: parse_warn(cfile, "Invalid CIDR prefix length:"
! 506: " expecting a number.");
! 507: return 0;
! 508: }
! 509:
! 510: prefixlen = atoi(val);
! 511:
! 512: if (prefixlen < 0 ||
! 513: prefixlen > (match->addr.len * 8)) {
! 514: parse_warn(cfile, "subnet prefix is out of "
! 515: "range [0..%d].",
! 516: match->addr.len * 8);
! 517: return 0;
! 518: }
! 519: }
! 520:
! 521: /* construct a suitable mask field */
! 522:
! 523: /* copy length */
! 524: match->mask.len = match->addr.len;
! 525:
! 526: /* count of 0xff bytes in mask */
! 527: fflen = prefixlen / 8;
! 528:
! 529: /* set leading mask */
! 530: memset(match->mask.iabuf, 0xff, fflen);
! 531:
! 532: /* set zeroes */
! 533: if (fflen < match->mask.len) {
! 534: match->mask.iabuf[fflen] =
! 535: "\x00\x80\xc0\xe0\xf0\xf8\xfc\xfe"[prefixlen % 8];
! 536:
! 537: memset(match->mask.iabuf+fflen+1, 0x00,
! 538: match->mask.len - fflen - 1);
! 539:
! 540: /* AND-out insignificant bits from supplied netmask. */
! 541: orig = piaddr(match->addr);
! 542: do {
! 543: newval = match->addr.iabuf[fflen] &
! 544: match->mask.iabuf[fflen];
! 545:
! 546: if (newval != match->addr.iabuf[fflen]) {
! 547: warnmask = 1;
! 548: match->addr.iabuf[fflen] = newval;
! 549: }
! 550: } while (++fflen < match->mask.len);
! 551:
! 552: if (warnmask) {
! 553: log_error("Warning: Extraneous bits removed "
! 554: "in address component of %s/%d.",
! 555: orig, prefixlen);
! 556: log_error("New value: %s/%d.",
! 557: piaddr(match->addr), prefixlen);
! 558: }
! 559: }
! 560:
! 561: return 1;
! 562: }
! 563:
! 564: parse_warn(cfile,
! 565: "expecting ip-address or ip-address/prefixlen");
! 566:
! 567: return 0; /* let caller pick up pieces */
! 568: }
! 569:
! 570: /*
! 571: * hardware-parameter :== HARDWARE hardware-type colon-separated-hex-list SEMI
! 572: * hardware-type :== ETHERNET | TOKEN_RING | TOKEN_FDDI
! 573: */
! 574:
! 575: void parse_hardware_param (cfile, hardware)
! 576: struct parse *cfile;
! 577: struct hardware *hardware;
! 578: {
! 579: const char *val;
! 580: enum dhcp_token token;
! 581: unsigned hlen;
! 582: unsigned char *t;
! 583:
! 584: token = next_token (&val, (unsigned *)0, cfile);
! 585: switch (token) {
! 586: case ETHERNET:
! 587: hardware -> hbuf [0] = HTYPE_ETHER;
! 588: break;
! 589: case TOKEN_RING:
! 590: hardware -> hbuf [0] = HTYPE_IEEE802;
! 591: break;
! 592: case TOKEN_FDDI:
! 593: hardware -> hbuf [0] = HTYPE_FDDI;
! 594: break;
! 595: default:
! 596: if (!strncmp (val, "unknown-", 8)) {
! 597: hardware -> hbuf [0] = atoi (&val [8]);
! 598: } else {
! 599: parse_warn (cfile,
! 600: "expecting a network hardware type");
! 601: skip_to_semi (cfile);
! 602:
! 603: return;
! 604: }
! 605: }
! 606:
! 607: /* Parse the hardware address information. Technically,
! 608: it would make a lot of sense to restrict the length of the
! 609: data we'll accept here to the length of a particular hardware
! 610: address type. Unfortunately, there are some broken clients
! 611: out there that put bogus data in the chaddr buffer, and we accept
! 612: that data in the lease file rather than simply failing on such
! 613: clients. Yuck. */
! 614: hlen = 0;
! 615: token = peek_token (&val, (unsigned *)0, cfile);
! 616: if (token == SEMI) {
! 617: hardware -> hlen = 1;
! 618: goto out;
! 619: }
! 620: t = parse_numeric_aggregate (cfile, (unsigned char *)0, &hlen,
! 621: COLON, 16, 8);
! 622: if (!t) {
! 623: hardware -> hlen = 1;
! 624: return;
! 625: }
! 626: if (hlen + 1 > sizeof hardware -> hbuf) {
! 627: dfree (t, MDL);
! 628: parse_warn (cfile, "hardware address too long");
! 629: } else {
! 630: hardware -> hlen = hlen + 1;
! 631: memcpy ((unsigned char *)&hardware -> hbuf [1], t, hlen);
! 632: if (hlen + 1 < sizeof hardware -> hbuf)
! 633: memset (&hardware -> hbuf [hlen + 1], 0,
! 634: (sizeof hardware -> hbuf) - hlen - 1);
! 635: dfree (t, MDL);
! 636: }
! 637:
! 638: out:
! 639: token = next_token (&val, (unsigned *)0, cfile);
! 640: if (token != SEMI) {
! 641: parse_warn (cfile, "expecting semicolon.");
! 642: skip_to_semi (cfile);
! 643: }
! 644: }
! 645:
! 646: /* lease-time :== NUMBER SEMI */
! 647:
! 648: void parse_lease_time (cfile, timep)
! 649: struct parse *cfile;
! 650: TIME *timep;
! 651: {
! 652: const char *val;
! 653: enum dhcp_token token;
! 654: u_int32_t num;
! 655:
! 656: token = next_token (&val, (unsigned *)0, cfile);
! 657: if (token != NUMBER) {
! 658: parse_warn (cfile, "Expecting numeric lease time");
! 659: skip_to_semi (cfile);
! 660: return;
! 661: }
! 662: convert_num(cfile, (unsigned char *)&num, val, 10, 32);
! 663: /* Unswap the number - convert_num returns stuff in NBO. */
! 664: *timep = ntohl(num);
! 665:
! 666: parse_semi (cfile);
! 667: }
! 668:
! 669: /* No BNF for numeric aggregates - that's defined by the caller. What
! 670: this function does is to parse a sequence of numbers separated by
! 671: the token specified in separator. If max is zero, any number of
! 672: numbers will be parsed; otherwise, exactly max numbers are
! 673: expected. Base and size tell us how to internalize the numbers
! 674: once they've been tokenized. */
! 675:
! 676: unsigned char *parse_numeric_aggregate (cfile, buf,
! 677: max, separator, base, size)
! 678: struct parse *cfile;
! 679: unsigned char *buf;
! 680: unsigned *max;
! 681: int separator;
! 682: int base;
! 683: unsigned size;
! 684: {
! 685: const char *val;
! 686: enum dhcp_token token;
! 687: unsigned char *bufp = buf, *s, *t;
! 688: unsigned count = 0;
! 689: pair c = (pair)0;
! 690:
! 691: if (!bufp && *max) {
! 692: bufp = (unsigned char *)dmalloc (*max * size / 8, MDL);
! 693: if (!bufp)
! 694: log_fatal ("no space for numeric aggregate");
! 695: s = 0;
! 696: } else
! 697: s = bufp;
! 698:
! 699: do {
! 700: if (count) {
! 701: token = peek_token (&val, (unsigned *)0, cfile);
! 702: if (token != separator) {
! 703: if (!*max)
! 704: break;
! 705: if (token != RBRACE && token != LBRACE)
! 706: token = next_token (&val,
! 707: (unsigned *)0,
! 708: cfile);
! 709: parse_warn (cfile, "too few numbers.");
! 710: if (token != SEMI)
! 711: skip_to_semi (cfile);
! 712: return (unsigned char *)0;
! 713: }
! 714: token = next_token (&val, (unsigned *)0, cfile);
! 715: }
! 716: token = next_token (&val, (unsigned *)0, cfile);
! 717:
! 718: if (token == END_OF_FILE) {
! 719: parse_warn (cfile, "unexpected end of file");
! 720: break;
! 721: }
! 722:
! 723: /* Allow NUMBER_OR_NAME if base is 16. */
! 724: if (token != NUMBER &&
! 725: (base != 16 || token != NUMBER_OR_NAME)) {
! 726: parse_warn (cfile, "expecting numeric value.");
! 727: skip_to_semi (cfile);
! 728: return (unsigned char *)0;
! 729: }
! 730: /* If we can, convert the number now; otherwise, build
! 731: a linked list of all the numbers. */
! 732: if (s) {
! 733: convert_num (cfile, s, val, base, size);
! 734: s += size / 8;
! 735: } else {
! 736: t = (unsigned char *)dmalloc (strlen (val) + 1, MDL);
! 737: if (!t)
! 738: log_fatal ("no temp space for number.");
! 739: strcpy ((char *)t, val);
! 740: c = cons ((caddr_t)t, c);
! 741: }
! 742: } while (++count != *max);
! 743:
! 744: /* If we had to cons up a list, convert it now. */
! 745: if (c) {
! 746: bufp = (unsigned char *)dmalloc (count * size / 8, MDL);
! 747: if (!bufp)
! 748: log_fatal ("no space for numeric aggregate.");
! 749: s = bufp + count - size / 8;
! 750: *max = count;
! 751: }
! 752: while (c) {
! 753: pair cdr = c -> cdr;
! 754: convert_num (cfile, s, (char *)(c -> car), base, size);
! 755: s -= size / 8;
! 756: /* Free up temp space. */
! 757: dfree (c -> car, MDL);
! 758: dfree (c, MDL);
! 759: c = cdr;
! 760: }
! 761: return bufp;
! 762: }
! 763:
! 764: void convert_num (cfile, buf, str, base, size)
! 765: struct parse *cfile;
! 766: unsigned char *buf;
! 767: const char *str;
! 768: int base;
! 769: unsigned size;
! 770: {
! 771: const unsigned char *ptr = (const unsigned char *)str;
! 772: int negative = 0;
! 773: u_int32_t val = 0;
! 774: int tval;
! 775: int max;
! 776:
! 777: if (*ptr == '-') {
! 778: negative = 1;
! 779: ++ptr;
! 780: }
! 781:
! 782: /* If base wasn't specified, figure it out from the data. */
! 783: if (!base) {
! 784: if (ptr [0] == '0') {
! 785: if (ptr [1] == 'x') {
! 786: base = 16;
! 787: ptr += 2;
! 788: } else if (isascii (ptr [1]) && isdigit (ptr [1])) {
! 789: base = 8;
! 790: ptr += 1;
! 791: } else {
! 792: base = 10;
! 793: }
! 794: } else {
! 795: base = 10;
! 796: }
! 797: }
! 798:
! 799: do {
! 800: tval = *ptr++;
! 801: /* XXX assumes ASCII... */
! 802: if (tval >= 'a')
! 803: tval = tval - 'a' + 10;
! 804: else if (tval >= 'A')
! 805: tval = tval - 'A' + 10;
! 806: else if (tval >= '0')
! 807: tval -= '0';
! 808: else {
! 809: parse_warn (cfile, "Bogus number: %s.", str);
! 810: break;
! 811: }
! 812: if (tval >= base) {
! 813: parse_warn (cfile,
! 814: "Bogus number %s: digit %d not in base %d",
! 815: str, tval, base);
! 816: break;
! 817: }
! 818: val = val * base + tval;
! 819: } while (*ptr);
! 820:
! 821: if (negative)
! 822: max = (1 << (size - 1));
! 823: else
! 824: max = (1 << (size - 1)) + ((1 << (size - 1)) - 1);
! 825: if (val > max) {
! 826: switch (base) {
! 827: case 8:
! 828: parse_warn (cfile,
! 829: "%s%lo exceeds max (%d) for precision.",
! 830: negative ? "-" : "",
! 831: (unsigned long)val, max);
! 832: break;
! 833: case 16:
! 834: parse_warn (cfile,
! 835: "%s%lx exceeds max (%d) for precision.",
! 836: negative ? "-" : "",
! 837: (unsigned long)val, max);
! 838: break;
! 839: default:
! 840: parse_warn (cfile,
! 841: "%s%lu exceeds max (%d) for precision.",
! 842: negative ? "-" : "",
! 843: (unsigned long)val, max);
! 844: break;
! 845: }
! 846: }
! 847:
! 848: if (negative) {
! 849: switch (size) {
! 850: case 8:
! 851: *buf = -(unsigned long)val;
! 852: break;
! 853: case 16:
! 854: putShort (buf, -(long)val);
! 855: break;
! 856: case 32:
! 857: putLong (buf, -(long)val);
! 858: break;
! 859: default:
! 860: parse_warn (cfile,
! 861: "Unexpected integer size: %d\n", size);
! 862: break;
! 863: }
! 864: } else {
! 865: switch (size) {
! 866: case 8:
! 867: *buf = (u_int8_t)val;
! 868: break;
! 869: case 16:
! 870: putUShort (buf, (u_int16_t)val);
! 871: break;
! 872: case 32:
! 873: putULong (buf, val);
! 874: break;
! 875: default:
! 876: parse_warn (cfile,
! 877: "Unexpected integer size: %d\n", size);
! 878: break;
! 879: }
! 880: }
! 881: }
! 882:
! 883: /*
! 884: * date :== NUMBER NUMBER SLASH NUMBER SLASH NUMBER
! 885: * NUMBER COLON NUMBER COLON NUMBER |
! 886: * NUMBER NUMBER SLASH NUMBER SLASH NUMBER
! 887: * NUMBER COLON NUMBER COLON NUMBER NUMBER |
! 888: * EPOCH NUMBER |
! 889: * NEVER
! 890: *
! 891: * Dates are stored in UTC or with a timezone offset; first number is day
! 892: * of week; next is year/month/day; next is hours:minutes:seconds on a
! 893: * 24-hour clock, followed by the timezone offset in seconds, which is
! 894: * optional.
! 895: */
! 896:
! 897: /*
! 898: * just parse the date
! 899: * any trailing semi must be consumed by the caller of this routine
! 900: */
! 901: TIME
! 902: parse_date_core(cfile)
! 903: struct parse *cfile;
! 904: {
! 905: int guess;
! 906: int tzoff, wday, year, mon, mday, hour, min, sec;
! 907: const char *val;
! 908: enum dhcp_token token;
! 909: static int months[11] = { 31, 59, 90, 120, 151, 181,
! 910: 212, 243, 273, 304, 334 };
! 911:
! 912: /* "never", "epoch" or day of week */
! 913: token = peek_token(&val, NULL, cfile);
! 914: if (token == NEVER) {
! 915: token = next_token(&val, NULL, cfile); /* consume NEVER */
! 916: return(MAX_TIME);
! 917: }
! 918:
! 919: /* This indicates 'local' time format. */
! 920: if (token == EPOCH) {
! 921: token = next_token(&val, NULL, cfile); /* consume EPOCH */
! 922: token = peek_token(&val, NULL, cfile);
! 923:
! 924: if (token != NUMBER) {
! 925: if (token != SEMI)
! 926: token = next_token(&val, NULL, cfile);
! 927: parse_warn(cfile, "Seconds since epoch expected.");
! 928: return((TIME)0);
! 929: }
! 930:
! 931: token = next_token(&val, NULL, cfile); /* consume number */
! 932: guess = atoi(val);
! 933:
! 934: return((TIME)guess);
! 935: }
! 936:
! 937: if (token != NUMBER) {
! 938: if (token != SEMI)
! 939: token = next_token(&val, NULL, cfile);
! 940: parse_warn(cfile, "numeric day of week expected.");
! 941: return((TIME)0);
! 942: }
! 943: token = next_token(&val, NULL, cfile); /* consume day of week */
! 944: wday = atoi(val);
! 945:
! 946: /* Year... */
! 947: token = peek_token(&val, NULL, cfile);
! 948: if (token != NUMBER) {
! 949: if (token != SEMI)
! 950: token = next_token(&val, NULL, cfile);
! 951: parse_warn(cfile, "numeric year expected.");
! 952: return((TIME)0);
! 953: }
! 954: token = next_token(&val, NULL, cfile); /* consume year */
! 955:
! 956: /* Note: the following is not a Y2K bug - it's a Y1.9K bug. Until
! 957: somebody invents a time machine, I think we can safely disregard
! 958: it. This actually works around a stupid Y2K bug that was present
! 959: in a very early beta release of dhcpd. */
! 960: year = atoi(val);
! 961: if (year > 1900)
! 962: year -= 1900;
! 963:
! 964: /* Slash separating year from month... */
! 965: token = peek_token(&val, NULL, cfile);
! 966: if (token != SLASH) {
! 967: if (token != SEMI)
! 968: token = next_token(&val, NULL, cfile);
! 969: parse_warn(cfile,
! 970: "expected slash separating year from month.");
! 971: return((TIME)0);
! 972: }
! 973: token = next_token(&val, NULL, cfile); /* consume SLASH */
! 974:
! 975: /* Month... */
! 976: token = peek_token(&val, NULL, cfile);
! 977: if (token != NUMBER) {
! 978: if (token != SEMI)
! 979: token = next_token(&val, NULL, cfile);
! 980: parse_warn(cfile, "numeric month expected.");
! 981: return((TIME)0);
! 982: }
! 983: token = next_token(&val, NULL, cfile); /* consume month */
! 984: mon = atoi(val) - 1;
! 985:
! 986: /* Slash separating month from day... */
! 987: token = peek_token(&val, NULL, cfile);
! 988: if (token != SLASH) {
! 989: if (token != SEMI)
! 990: token = next_token(&val, NULL, cfile);
! 991: parse_warn(cfile,
! 992: "expected slash separating month from day.");
! 993: return((TIME)0);
! 994: }
! 995: token = next_token(&val, NULL, cfile); /* consume SLASH */
! 996:
! 997: /* Day of month... */
! 998: token = peek_token(&val, NULL, cfile);
! 999: if (token != NUMBER) {
! 1000: if (token != SEMI)
! 1001: token = next_token(&val, NULL, cfile);
! 1002: parse_warn(cfile, "numeric day of month expected.");
! 1003: return((TIME)0);
! 1004: }
! 1005: token = next_token(&val, NULL, cfile); /* consume day of month */
! 1006: mday = atoi(val);
! 1007:
! 1008: /* Hour... */
! 1009: token = peek_token(&val, NULL, cfile);
! 1010: if (token != NUMBER) {
! 1011: if (token != SEMI)
! 1012: token = next_token(&val, NULL, cfile);
! 1013: parse_warn(cfile, "numeric hour expected.");
! 1014: return((TIME)0);
! 1015: }
! 1016: token = next_token(&val, NULL, cfile); /* consume hour */
! 1017: hour = atoi(val);
! 1018:
! 1019: /* Colon separating hour from minute... */
! 1020: token = peek_token(&val, NULL, cfile);
! 1021: if (token != COLON) {
! 1022: if (token != SEMI)
! 1023: token = next_token(&val, NULL, cfile);
! 1024: parse_warn(cfile,
! 1025: "expected colon separating hour from minute.");
! 1026: return((TIME)0);
! 1027: }
! 1028: token = next_token(&val, NULL, cfile); /* consume colon */
! 1029:
! 1030: /* Minute... */
! 1031: token = peek_token(&val, NULL, cfile);
! 1032: if (token != NUMBER) {
! 1033: if (token != SEMI)
! 1034: token = next_token(&val, NULL, cfile);
! 1035: parse_warn(cfile, "numeric minute expected.");
! 1036: return((TIME)0);
! 1037: }
! 1038: token = next_token(&val, NULL, cfile); /* consume minute */
! 1039: min = atoi(val);
! 1040:
! 1041: /* Colon separating minute from second... */
! 1042: token = peek_token(&val, NULL, cfile);
! 1043: if (token != COLON) {
! 1044: if (token != SEMI)
! 1045: token = next_token(&val, NULL, cfile);
! 1046: parse_warn(cfile,
! 1047: "expected colon separating minute from second.");
! 1048: return((TIME)0);
! 1049: }
! 1050: token = next_token(&val, NULL, cfile); /* consume colon */
! 1051:
! 1052: /* Second... */
! 1053: token = peek_token(&val, NULL, cfile);
! 1054: if (token != NUMBER) {
! 1055: if (token != SEMI)
! 1056: token = next_token(&val, NULL, cfile);
! 1057: parse_warn(cfile, "numeric second expected.");
! 1058: return((TIME)0);
! 1059: }
! 1060: token = next_token(&val, NULL, cfile); /* consume second */
! 1061: sec = atoi(val);
! 1062:
! 1063: tzoff = 0;
! 1064: token = peek_token(&val, NULL, cfile);
! 1065: if (token == NUMBER) {
! 1066: token = next_token(&val, NULL, cfile); /* consume tzoff */
! 1067: tzoff = atoi(val);
! 1068: } else if (token != SEMI) {
! 1069: token = next_token(&val, NULL, cfile);
! 1070: parse_warn(cfile,
! 1071: "Time zone offset or semicolon expected.");
! 1072: return((TIME)0);
! 1073: }
! 1074:
! 1075: /* Guess the time value... */
! 1076: guess = ((((((365 * (year - 70) + /* Days in years since '70 */
! 1077: (year - 69) / 4 + /* Leap days since '70 */
! 1078: (mon /* Days in months this year */
! 1079: ? months [mon - 1]
! 1080: : 0) +
! 1081: (mon > 1 && /* Leap day this year */
! 1082: !((year - 72) & 3)) +
! 1083: mday - 1) * 24) + /* Day of month */
! 1084: hour) * 60) +
! 1085: min) * 60) + sec + tzoff;
! 1086:
! 1087: /* This guess could be wrong because of leap seconds or other
! 1088: weirdness we don't know about that the system does. For
! 1089: now, we're just going to accept the guess, but at some point
! 1090: it might be nice to do a successive approximation here to
! 1091: get an exact value. Even if the error is small, if the
! 1092: server is restarted frequently (and thus the lease database
! 1093: is reread), the error could accumulate into something
! 1094: significant. */
! 1095:
! 1096: return((TIME)guess);
! 1097: }
! 1098:
! 1099: /*
! 1100: * Wrapper to consume the semicolon after the date
! 1101: * :== date semi
! 1102: */
! 1103:
! 1104: TIME
! 1105: parse_date(cfile)
! 1106: struct parse *cfile;
! 1107: {
! 1108: TIME guess;
! 1109: guess = parse_date_core(cfile);
! 1110:
! 1111: /* Make sure the date ends in a semicolon... */
! 1112: if (!parse_semi(cfile))
! 1113: return((TIME)0);
! 1114: return(guess);
! 1115: }
! 1116:
! 1117:
! 1118:
! 1119: /*
! 1120: * option-name :== IDENTIFIER |
! 1121: IDENTIFIER . IDENTIFIER
! 1122: */
! 1123:
! 1124: isc_result_t
! 1125: parse_option_name (cfile, allocate, known, opt)
! 1126: struct parse *cfile;
! 1127: int allocate;
! 1128: int *known;
! 1129: struct option **opt;
! 1130: {
! 1131: const char *val;
! 1132: enum dhcp_token token;
! 1133: char *uname;
! 1134: struct universe *universe;
! 1135: struct option *option;
! 1136: unsigned code;
! 1137:
! 1138: if (opt == NULL)
! 1139: return ISC_R_INVALIDARG;
! 1140:
! 1141: token = next_token (&val, (unsigned *)0, cfile);
! 1142: if (!is_identifier (token)) {
! 1143: parse_warn (cfile,
! 1144: "expecting identifier after option keyword.");
! 1145: if (token != SEMI)
! 1146: skip_to_semi (cfile);
! 1147: return ISC_R_BADPARSE;
! 1148: }
! 1149: uname = dmalloc (strlen (val) + 1, MDL);
! 1150: if (!uname)
! 1151: log_fatal ("no memory for uname information.");
! 1152: strcpy (uname, val);
! 1153: token = peek_token (&val, (unsigned *)0, cfile);
! 1154: if (token == DOT) {
! 1155: /* Go ahead and take the DOT token... */
! 1156: token = next_token (&val, (unsigned *)0, cfile);
! 1157:
! 1158: /* The next token should be an identifier... */
! 1159: token = next_token (&val, (unsigned *)0, cfile);
! 1160: if (!is_identifier (token)) {
! 1161: parse_warn (cfile, "expecting identifier after '.'");
! 1162: if (token != SEMI)
! 1163: skip_to_semi (cfile);
! 1164: return ISC_R_BADPARSE;
! 1165: }
! 1166:
! 1167: /* Look up the option name hash table for the specified
! 1168: uname. */
! 1169: universe = (struct universe *)0;
! 1170: if (!universe_hash_lookup (&universe, universe_hash,
! 1171: uname, 0, MDL)) {
! 1172: parse_warn (cfile, "no option space named %s.", uname);
! 1173: skip_to_semi (cfile);
! 1174: return ISC_R_NOTFOUND;
! 1175: }
! 1176: } else {
! 1177: /* Use the default hash table, which contains all the
! 1178: standard dhcp option names. */
! 1179: val = uname;
! 1180: universe = &dhcp_universe;
! 1181: }
! 1182:
! 1183: /* Look up the actual option info... */
! 1184: option_name_hash_lookup(opt, universe->name_hash, val, 0, MDL);
! 1185: option = *opt;
! 1186:
! 1187: /* If we didn't get an option structure, it's an undefined option. */
! 1188: if (option) {
! 1189: if (known)
! 1190: *known = 1;
! 1191: /* If the option name is of the form unknown-[decimal], use
! 1192: * the trailing decimal value to find the option definition.
! 1193: * If there is no definition, construct one. This is to
! 1194: * support legacy use of unknown options in config files or
! 1195: * lease databases.
! 1196: */
! 1197: } else if (strncasecmp(val, "unknown-", 8) == 0) {
! 1198: code = atoi(val+8);
! 1199:
! 1200: /* Option code 0 is always illegal for us, thanks
! 1201: * to the option decoder.
! 1202: */
! 1203: if (code == 0 || code == universe->end) {
! 1204: parse_warn(cfile, "Option codes 0 and %u are illegal "
! 1205: "in the %s space.", universe->end,
! 1206: universe->name);
! 1207: skip_to_semi(cfile);
! 1208: dfree(uname, MDL);
! 1209: return ISC_R_FAILURE;
! 1210: }
! 1211:
! 1212: /* It's odd to think of unknown option codes as
! 1213: * being known, but this means we know what the
! 1214: * parsed name is talking about.
! 1215: */
! 1216: if (known)
! 1217: *known = 1;
! 1218:
! 1219: option_code_hash_lookup(opt, universe->code_hash,
! 1220: &code, 0, MDL);
! 1221: option = *opt;
! 1222:
! 1223: /* If we did not find an option of that code,
! 1224: * manufacture an unknown-xxx option definition.
! 1225: * Its single reference will ensure that it is
! 1226: * deleted once the option is recycled out of
! 1227: * existence (by the parent).
! 1228: */
! 1229: if (option == NULL) {
! 1230: option = new_option(val, MDL);
! 1231: option->universe = universe;
! 1232: option->code = code;
! 1233: option->format = default_option_format;
! 1234: option_reference(opt, option, MDL);
! 1235: } else
! 1236: log_info("option %s has been redefined as option %s. "
! 1237: "Please update your configs if neccessary.",
! 1238: val, option->name);
! 1239: /* If we've been told to allocate, that means that this
! 1240: * (might) be an option code definition, so we'll create
! 1241: * an option structure and return it for the parent to
! 1242: * decide.
! 1243: */
! 1244: } else if (allocate) {
! 1245: option = new_option(val, MDL);
! 1246: option -> universe = universe;
! 1247: option_reference(opt, option, MDL);
! 1248: } else {
! 1249: parse_warn(cfile, "no option named %s in space %s",
! 1250: val, universe->name);
! 1251: skip_to_semi (cfile);
! 1252: dfree(uname, MDL);
! 1253: return ISC_R_NOTFOUND;
! 1254: }
! 1255:
! 1256: /* Free the initial identifier token. */
! 1257: dfree (uname, MDL);
! 1258: return ISC_R_SUCCESS;
! 1259: }
! 1260:
! 1261: /* IDENTIFIER [WIDTHS] SEMI
! 1262: * WIDTHS ~= LENGTH WIDTH NUMBER
! 1263: * CODE WIDTH NUMBER
! 1264: */
! 1265:
! 1266: void parse_option_space_decl (cfile)
! 1267: struct parse *cfile;
! 1268: {
! 1269: int token;
! 1270: const char *val;
! 1271: struct universe **ua, *nu;
! 1272: char *nu_name;
! 1273: int tsize=1, lsize=1, hsize = 0;
! 1274:
! 1275: next_token (&val, (unsigned *)0, cfile); /* Discard the SPACE token,
! 1276: which was checked by the
! 1277: caller. */
! 1278: token = next_token (&val, (unsigned *)0, cfile);
! 1279: if (!is_identifier (token)) {
! 1280: parse_warn (cfile, "expecting identifier.");
! 1281: skip_to_semi (cfile);
! 1282: return;
! 1283: }
! 1284: nu = new_universe (MDL);
! 1285: if (!nu)
! 1286: log_fatal ("No memory for new option space.");
! 1287:
! 1288: /* Set up the server option universe... */
! 1289: nu_name = dmalloc (strlen (val) + 1, MDL);
! 1290: if (!nu_name)
! 1291: log_fatal ("No memory for new option space name.");
! 1292: strcpy (nu_name, val);
! 1293: nu -> name = nu_name;
! 1294:
! 1295: do {
! 1296: token = next_token(&val, NULL, cfile);
! 1297: switch(token) {
! 1298: case SEMI:
! 1299: break;
! 1300:
! 1301: case CODE:
! 1302: token = next_token(&val, NULL, cfile);
! 1303: if (token != WIDTH) {
! 1304: parse_warn(cfile, "expecting width token.");
! 1305: goto bad;
! 1306: }
! 1307:
! 1308: token = next_token(&val, NULL, cfile);
! 1309: if (token != NUMBER) {
! 1310: parse_warn(cfile, "expecting number 1, 2, 4.");
! 1311: goto bad;
! 1312: }
! 1313:
! 1314: tsize = atoi(val);
! 1315:
! 1316:
! 1317: switch (tsize) {
! 1318: case 1:
! 1319: if (!hsize)
! 1320: hsize = BYTE_NAME_HASH_SIZE;
! 1321: break;
! 1322: case 2:
! 1323: if (!hsize)
! 1324: hsize = WORD_NAME_HASH_SIZE;
! 1325: break;
! 1326: case 4:
! 1327: if (!hsize)
! 1328: hsize = QUAD_NAME_HASH_SIZE;
! 1329: break;
! 1330: default:
! 1331: parse_warn(cfile, "invalid code width (%d), "
! 1332: "expecting a 1, 2 or 4.",
! 1333: tsize);
! 1334: goto bad;
! 1335: }
! 1336: break;
! 1337:
! 1338: case LENGTH:
! 1339: token = next_token(&val, NULL, cfile);
! 1340: if (token != WIDTH) {
! 1341: parse_warn(cfile, "expecting width token.");
! 1342: goto bad;
! 1343: }
! 1344:
! 1345: token = next_token(&val, NULL, cfile);
! 1346: if (token != NUMBER) {
! 1347: parse_warn(cfile, "expecting number 1 or 2.");
! 1348: goto bad;
! 1349: }
! 1350:
! 1351: lsize = atoi(val);
! 1352: if (lsize != 1 && lsize != 2) {
! 1353: parse_warn(cfile, "invalid length width (%d) "
! 1354: "expecting 1 or 2.", lsize);
! 1355: goto bad;
! 1356: }
! 1357:
! 1358: break;
! 1359:
! 1360: case HASH:
! 1361: token = next_token(&val, NULL, cfile);
! 1362: if (token != SIZE) {
! 1363: parse_warn(cfile, "expecting size token.");
! 1364: goto bad;
! 1365: }
! 1366:
! 1367: token = next_token(&val, NULL, cfile);
! 1368: if (token != NUMBER) {
! 1369: parse_warn(cfile, "expecting a 10base number");
! 1370: goto bad;
! 1371: }
! 1372:
! 1373: /* (2^31)-1 is the highest Mersenne prime we should
! 1374: * probably allow...
! 1375: */
! 1376: hsize = atoi(val);
! 1377: if (hsize < 0 || hsize > 0x7FFFFFFF) {
! 1378: parse_warn(cfile, "invalid hash length: %d",
! 1379: hsize);
! 1380: goto bad;
! 1381: }
! 1382:
! 1383: break;
! 1384:
! 1385: default:
! 1386: parse_warn(cfile, "Unexpected token.");
! 1387: }
! 1388: } while (token != SEMI);
! 1389:
! 1390: if (!hsize)
! 1391: hsize = DEFAULT_SPACE_HASH_SIZE;
! 1392:
! 1393: nu -> lookup_func = lookup_hashed_option;
! 1394: nu -> option_state_dereference = hashed_option_state_dereference;
! 1395: nu -> foreach = hashed_option_space_foreach;
! 1396: nu -> save_func = save_hashed_option;
! 1397: nu -> delete_func = delete_hashed_option;
! 1398: nu -> encapsulate = hashed_option_space_encapsulate;
! 1399: nu -> decode = parse_option_buffer;
! 1400: nu -> length_size = lsize;
! 1401: nu -> tag_size = tsize;
! 1402: switch(tsize) {
! 1403: case 1:
! 1404: nu->get_tag = getUChar;
! 1405: nu->store_tag = putUChar;
! 1406: break;
! 1407: case 2:
! 1408: nu->get_tag = getUShort;
! 1409: nu->store_tag = putUShort;
! 1410: break;
! 1411: case 4:
! 1412: nu->get_tag = getULong;
! 1413: nu->store_tag = putULong;
! 1414: break;
! 1415: default:
! 1416: log_fatal("Impossible condition at %s:%d.", MDL);
! 1417: }
! 1418: switch(lsize) {
! 1419: case 0:
! 1420: nu->get_length = NULL;
! 1421: nu->store_length = NULL;
! 1422: break;
! 1423: case 1:
! 1424: nu->get_length = getUChar;
! 1425: nu->store_length = putUChar;
! 1426: break;
! 1427: case 2:
! 1428: nu->get_length = getUShort;
! 1429: nu->store_length = putUShort;
! 1430: break;
! 1431: default:
! 1432: log_fatal("Impossible condition at %s:%d.", MDL);
! 1433: }
! 1434: nu -> index = universe_count++;
! 1435: if (nu -> index >= universe_max) {
! 1436: ua = dmalloc (universe_max * 2 * sizeof *ua, MDL);
! 1437: if (!ua)
! 1438: log_fatal ("No memory to expand option space array.");
! 1439: memcpy (ua, universes, universe_max * sizeof *ua);
! 1440: universe_max *= 2;
! 1441: dfree (universes, MDL);
! 1442: universes = ua;
! 1443: }
! 1444: universes [nu -> index] = nu;
! 1445: if (!option_name_new_hash(&nu->name_hash, hsize, MDL) ||
! 1446: !option_code_new_hash(&nu->code_hash, hsize, MDL))
! 1447: log_fatal("Can't allocate %s option hash table.", nu->name);
! 1448: universe_hash_add (universe_hash, nu -> name, 0, nu, MDL);
! 1449: return;
! 1450:
! 1451: bad:
! 1452: dfree(nu_name, MDL);
! 1453: dfree(nu, MDL);
! 1454: }
! 1455:
! 1456: /* This is faked up to look good right now. Ideally, this should do a
! 1457: recursive parse and allow arbitrary data structure definitions, but for
! 1458: now it just allows you to specify a single type, an array of single types,
! 1459: a sequence of types, or an array of sequences of types.
! 1460:
! 1461: ocd :== NUMBER EQUALS ocsd SEMI
! 1462:
! 1463: ocsd :== ocsd_type |
! 1464: ocsd_type_sequence |
! 1465: ARRAY OF ocsd_simple_type_sequence
! 1466:
! 1467: ocsd_type_sequence :== LBRACE ocsd_types RBRACE
! 1468:
! 1469: ocsd_simple_type_sequence :== LBRACE ocsd_simple_types RBRACE
! 1470:
! 1471: ocsd_types :== ocsd_type |
! 1472: ocsd_types ocsd_type
! 1473:
! 1474: ocsd_type :== ocsd_simple_type |
! 1475: ARRAY OF ocsd_simple_type
! 1476:
! 1477: ocsd_simple_types :== ocsd_simple_type |
! 1478: ocsd_simple_types ocsd_simple_type
! 1479:
! 1480: ocsd_simple_type :== BOOLEAN |
! 1481: INTEGER NUMBER |
! 1482: SIGNED INTEGER NUMBER |
! 1483: UNSIGNED INTEGER NUMBER |
! 1484: IP-ADDRESS |
! 1485: TEXT |
! 1486: STRING |
! 1487: ENCAPSULATE identifier */
! 1488:
! 1489: int parse_option_code_definition (cfile, option)
! 1490: struct parse *cfile;
! 1491: struct option *option;
! 1492: {
! 1493: const char *val;
! 1494: enum dhcp_token token;
! 1495: struct option *oldopt;
! 1496: unsigned arrayp = 0;
! 1497: int recordp = 0;
! 1498: int no_more_in_record = 0;
! 1499: char tokbuf [128];
! 1500: unsigned tokix = 0;
! 1501: char type;
! 1502: int is_signed;
! 1503: char *s;
! 1504: int has_encapsulation = 0;
! 1505: struct universe *encapsulated;
! 1506:
! 1507: /* Parse the option code. */
! 1508: token = next_token (&val, (unsigned *)0, cfile);
! 1509: if (token != NUMBER) {
! 1510: parse_warn (cfile, "expecting option code number.");
! 1511: skip_to_semi (cfile);
! 1512: return 0;
! 1513: }
! 1514: option -> code = atoi (val);
! 1515:
! 1516: token = next_token (&val, (unsigned *)0, cfile);
! 1517: if (token != EQUAL) {
! 1518: parse_warn (cfile, "expecting \"=\"");
! 1519: skip_to_semi (cfile);
! 1520: return 0;
! 1521: }
! 1522:
! 1523: /* See if this is an array. */
! 1524: token = next_token (&val, (unsigned *)0, cfile);
! 1525: if (token == ARRAY) {
! 1526: token = next_token (&val, (unsigned *)0, cfile);
! 1527: if (token != OF) {
! 1528: parse_warn (cfile, "expecting \"of\".");
! 1529: skip_to_semi (cfile);
! 1530: return 0;
! 1531: }
! 1532: arrayp = 1;
! 1533: token = next_token (&val, (unsigned *)0, cfile);
! 1534: }
! 1535:
! 1536: if (token == LBRACE) {
! 1537: recordp = 1;
! 1538: token = next_token (&val, (unsigned *)0, cfile);
! 1539: }
! 1540:
! 1541: /* At this point we're expecting a data type. */
! 1542: next_type:
! 1543: if (has_encapsulation) {
! 1544: parse_warn (cfile,
! 1545: "encapsulate must always be the last item.");
! 1546: skip_to_semi (cfile);
! 1547: return 0;
! 1548: }
! 1549:
! 1550: switch (token) {
! 1551: case ARRAY:
! 1552: if (arrayp) {
! 1553: parse_warn (cfile, "no nested arrays.");
! 1554: skip_to_rbrace (cfile, recordp);
! 1555: if (recordp)
! 1556: skip_to_semi (cfile);
! 1557: return 0;
! 1558: }
! 1559: token = next_token (&val, (unsigned *)0, cfile);
! 1560: if (token != OF) {
! 1561: parse_warn (cfile, "expecting \"of\".");
! 1562: skip_to_semi (cfile);
! 1563: return 0;
! 1564: }
! 1565: arrayp = recordp + 1;
! 1566: token = next_token (&val, (unsigned *)0, cfile);
! 1567: if ((recordp) && (token == LBRACE)) {
! 1568: parse_warn (cfile,
! 1569: "only uniform array inside record.");
! 1570: skip_to_rbrace (cfile, recordp + 1);
! 1571: skip_to_semi (cfile);
! 1572: return 0;
! 1573: }
! 1574: goto next_type;
! 1575: case BOOLEAN:
! 1576: type = 'f';
! 1577: break;
! 1578: case INTEGER:
! 1579: is_signed = 1;
! 1580: parse_integer:
! 1581: token = next_token (&val, (unsigned *)0, cfile);
! 1582: if (token != NUMBER) {
! 1583: parse_warn (cfile, "expecting number.");
! 1584: skip_to_rbrace (cfile, recordp);
! 1585: if (recordp)
! 1586: skip_to_semi (cfile);
! 1587: return 0;
! 1588: }
! 1589: switch (atoi (val)) {
! 1590: case 8:
! 1591: type = is_signed ? 'b' : 'B';
! 1592: break;
! 1593: case 16:
! 1594: type = is_signed ? 's' : 'S';
! 1595: break;
! 1596: case 32:
! 1597: type = is_signed ? 'l' : 'L';
! 1598: break;
! 1599: default:
! 1600: parse_warn (cfile,
! 1601: "%s bit precision is not supported.", val);
! 1602: skip_to_rbrace (cfile, recordp);
! 1603: if (recordp)
! 1604: skip_to_semi (cfile);
! 1605: return 0;
! 1606: }
! 1607: break;
! 1608: case SIGNED:
! 1609: is_signed = 1;
! 1610: parse_signed:
! 1611: token = next_token (&val, (unsigned *)0, cfile);
! 1612: if (token != INTEGER) {
! 1613: parse_warn (cfile, "expecting \"integer\" keyword.");
! 1614: skip_to_rbrace (cfile, recordp);
! 1615: if (recordp)
! 1616: skip_to_semi (cfile);
! 1617: return 0;
! 1618: }
! 1619: goto parse_integer;
! 1620: case UNSIGNED:
! 1621: is_signed = 0;
! 1622: goto parse_signed;
! 1623:
! 1624: case IP_ADDRESS:
! 1625: type = 'I';
! 1626: break;
! 1627: case IP6_ADDRESS:
! 1628: type = '6';
! 1629: break;
! 1630: case DOMAIN_NAME:
! 1631: type = 'd';
! 1632: goto no_arrays;
! 1633: case DOMAIN_LIST:
! 1634: /* Consume optional compression indicator. */
! 1635: token = peek_token(&val, NULL, cfile);
! 1636: if (token == COMPRESSED) {
! 1637: token = next_token(&val, NULL, cfile);
! 1638: tokbuf[tokix++] = 'D';
! 1639: type = 'c';
! 1640: } else
! 1641: type = 'D';
! 1642: goto no_arrays;
! 1643: case TEXT:
! 1644: type = 't';
! 1645: no_arrays:
! 1646: if (arrayp) {
! 1647: parse_warn (cfile, "arrays of text strings not %s",
! 1648: "yet supported.");
! 1649: skip_to_rbrace (cfile, recordp);
! 1650: if (recordp)
! 1651: skip_to_semi (cfile);
! 1652: return 0;
! 1653: }
! 1654: no_more_in_record = 1;
! 1655: break;
! 1656: case STRING_TOKEN:
! 1657: type = 'X';
! 1658: goto no_arrays;
! 1659:
! 1660: case ENCAPSULATE:
! 1661: token = next_token (&val, (unsigned *)0, cfile);
! 1662: if (!is_identifier (token)) {
! 1663: parse_warn (cfile,
! 1664: "expecting option space identifier");
! 1665: skip_to_semi (cfile);
! 1666: return 0;
! 1667: }
! 1668: encapsulated = NULL;
! 1669: if (!universe_hash_lookup(&encapsulated, universe_hash,
! 1670: val, strlen(val), MDL)) {
! 1671: parse_warn(cfile, "unknown option space %s", val);
! 1672: skip_to_semi (cfile);
! 1673: return 0;
! 1674: }
! 1675: if (strlen (val) + tokix + 2 > sizeof (tokbuf))
! 1676: goto toobig;
! 1677: tokbuf [tokix++] = 'E';
! 1678: strcpy (&tokbuf [tokix], val);
! 1679: tokix += strlen (val);
! 1680: type = '.';
! 1681: has_encapsulation = 1;
! 1682: break;
! 1683:
! 1684: case ZEROLEN:
! 1685: type = 'Z';
! 1686: if (arrayp) {
! 1687: parse_warn (cfile, "array incompatible with zerolen.");
! 1688: skip_to_rbrace (cfile, recordp);
! 1689: if (recordp)
! 1690: skip_to_semi (cfile);
! 1691: return 0;
! 1692: }
! 1693: no_more_in_record = 1;
! 1694: break;
! 1695:
! 1696: default:
! 1697: parse_warn (cfile, "unknown data type %s", val);
! 1698: skip_to_rbrace (cfile, recordp);
! 1699: if (recordp)
! 1700: skip_to_semi (cfile);
! 1701: return 0;
! 1702: }
! 1703:
! 1704: if (tokix == sizeof tokbuf) {
! 1705: toobig:
! 1706: parse_warn (cfile, "too many types in record.");
! 1707: skip_to_rbrace (cfile, recordp);
! 1708: if (recordp)
! 1709: skip_to_semi (cfile);
! 1710: return 0;
! 1711: }
! 1712: tokbuf [tokix++] = type;
! 1713:
! 1714: if (recordp) {
! 1715: token = next_token (&val, (unsigned *)0, cfile);
! 1716: if (arrayp > recordp) {
! 1717: if (tokix == sizeof tokbuf) {
! 1718: parse_warn (cfile,
! 1719: "too many types in record.");
! 1720: skip_to_rbrace (cfile, 1);
! 1721: skip_to_semi (cfile);
! 1722: return 0;
! 1723: }
! 1724: arrayp = 0;
! 1725: tokbuf[tokix++] = 'a';
! 1726: }
! 1727: if (token == COMMA) {
! 1728: if (no_more_in_record) {
! 1729: parse_warn (cfile,
! 1730: "%s must be at end of record.",
! 1731: type == 't' ? "text" : "string");
! 1732: skip_to_rbrace (cfile, 1);
! 1733: if (recordp)
! 1734: skip_to_semi (cfile);
! 1735: return 0;
! 1736: }
! 1737: token = next_token (&val, (unsigned *)0, cfile);
! 1738: goto next_type;
! 1739: }
! 1740: if (token != RBRACE) {
! 1741: parse_warn (cfile, "expecting right brace.");
! 1742: skip_to_rbrace (cfile, 1);
! 1743: if (recordp)
! 1744: skip_to_semi (cfile);
! 1745: return 0;
! 1746: }
! 1747: }
! 1748: if (!parse_semi (cfile)) {
! 1749: parse_warn (cfile, "semicolon expected.");
! 1750: skip_to_semi (cfile);
! 1751: if (recordp)
! 1752: skip_to_semi (cfile);
! 1753: return 0;
! 1754: }
! 1755: if (has_encapsulation && arrayp) {
! 1756: parse_warn (cfile,
! 1757: "Arrays of encapsulations don't make sense.");
! 1758: return 0;
! 1759: }
! 1760: s = dmalloc(tokix + (arrayp ? 1 : 0) + 1, MDL);
! 1761: if (s == NULL) {
! 1762: log_fatal("no memory for option format.");
! 1763: }
! 1764: memcpy(s, tokbuf, tokix);
! 1765: if (arrayp) {
! 1766: s[tokix++] = (arrayp > recordp) ? 'a' : 'A';
! 1767: }
! 1768: s[tokix] = '\0';
! 1769:
! 1770: option -> format = s;
! 1771:
! 1772: oldopt = NULL;
! 1773: option_code_hash_lookup(&oldopt, option->universe->code_hash,
! 1774: &option->code, 0, MDL);
! 1775: if (oldopt != NULL) {
! 1776: /*
! 1777: * XXX: This illegalizes a configuration syntax that was
! 1778: * valid in 3.0.x, where multiple name->code mappings are
! 1779: * given, but only one code->name mapping survives. It is
! 1780: * unclear what can or should be done at this point, but it
! 1781: * seems best to retain 3.0.x behaviour for upgrades to go
! 1782: * smoothly.
! 1783: *
! 1784: option_name_hash_delete(option->universe->name_hash,
! 1785: oldopt->name, 0, MDL);
! 1786: */
! 1787: option_code_hash_delete(option->universe->code_hash,
! 1788: &oldopt->code, 0, MDL);
! 1789:
! 1790: option_dereference(&oldopt, MDL);
! 1791: }
! 1792: option_code_hash_add(option->universe->code_hash, &option->code, 0,
! 1793: option, MDL);
! 1794: option_name_hash_add(option->universe->name_hash, option->name, 0,
! 1795: option, MDL);
! 1796: if (has_encapsulation) {
! 1797: /* INSIST(tokbuf[0] == 'E'); */
! 1798: /* INSIST(encapsulated != NULL); */
! 1799: if (!option_code_hash_lookup(&encapsulated->enc_opt,
! 1800: option->universe->code_hash,
! 1801: &option->code, 0, MDL)) {
! 1802: log_fatal("error finding encapsulated option (%s:%d)",
! 1803: MDL);
! 1804: }
! 1805: }
! 1806: return 1;
! 1807: }
! 1808:
! 1809: /*
! 1810: * base64 :== NUMBER_OR_STRING
! 1811: */
! 1812:
! 1813: int parse_base64 (data, cfile)
! 1814: struct data_string *data;
! 1815: struct parse *cfile;
! 1816: {
! 1817: enum dhcp_token token;
! 1818: const char *val;
! 1819: int i, j, k;
! 1820: unsigned acc = 0;
! 1821: static unsigned char
! 1822: from64 [] = {64, 64, 64, 64, 64, 64, 64, 64, /* \"#$%&' */
! 1823: 64, 64, 64, 62, 64, 64, 64, 63, /* ()*+,-./ */
! 1824: 52, 53, 54, 55, 56, 57, 58, 59, /* 01234567 */
! 1825: 60, 61, 64, 64, 64, 64, 64, 64, /* 89:;<=>? */
! 1826: 64, 0, 1, 2, 3, 4, 5, 6, /* @ABCDEFG */
! 1827: 7, 8, 9, 10, 11, 12, 13, 14, /* HIJKLMNO */
! 1828: 15, 16, 17, 18, 19, 20, 21, 22, /* PQRSTUVW */
! 1829: 23, 24, 25, 64, 64, 64, 64, 64, /* XYZ[\]^_ */
! 1830: 64, 26, 27, 28, 29, 30, 31, 32, /* 'abcdefg */
! 1831: 33, 34, 35, 36, 37, 38, 39, 40, /* hijklmno */
! 1832: 41, 42, 43, 44, 45, 46, 47, 48, /* pqrstuvw */
! 1833: 49, 50, 51, 64, 64, 64, 64, 64}; /* xyz{|}~ */
! 1834: struct string_list *bufs = (struct string_list *)0,
! 1835: *last = (struct string_list *)0,
! 1836: *t;
! 1837: int cc = 0;
! 1838: int terminated = 0;
! 1839:
! 1840: /* It's possible for a + or a / to cause a base64 quantity to be
! 1841: tokenized into more than one token, so we have to parse them all
! 1842: in before decoding. */
! 1843: do {
! 1844: unsigned l;
! 1845:
! 1846: token = next_token (&val, &l, cfile);
! 1847: t = dmalloc (l + sizeof *t, MDL);
! 1848: if (!t)
! 1849: log_fatal ("no memory for base64 buffer.");
! 1850: memset (t, 0, (sizeof *t) - 1);
! 1851: memcpy (t -> string, val, l + 1);
! 1852: cc += l;
! 1853: if (last)
! 1854: last -> next = t;
! 1855: else
! 1856: bufs = t;
! 1857: last = t;
! 1858: token = peek_token (&val, (unsigned *)0, cfile);
! 1859: } while (token == NUMBER_OR_NAME || token == NAME || token == EQUAL ||
! 1860: token == NUMBER || token == PLUS || token == SLASH ||
! 1861: token == STRING);
! 1862:
! 1863: data -> len = cc;
! 1864: data -> len = (data -> len * 3) / 4;
! 1865: if (!buffer_allocate (&data -> buffer, data -> len, MDL)) {
! 1866: parse_warn (cfile, "can't allocate buffer for base64 data.");
! 1867: data -> len = 0;
! 1868: data -> data = (unsigned char *)0;
! 1869: return 0;
! 1870: }
! 1871:
! 1872: j = k = 0;
! 1873: for (t = bufs; t; t = t -> next) {
! 1874: for (i = 0; t -> string [i]; i++) {
! 1875: unsigned foo = t -> string [i];
! 1876: if (terminated && foo != '=') {
! 1877: parse_warn (cfile,
! 1878: "stuff after base64 '=' terminator: %s.",
! 1879: &t -> string [i]);
! 1880: goto bad;
! 1881: }
! 1882: if (foo < ' ' || foo > 'z') {
! 1883: bad64:
! 1884: parse_warn (cfile,
! 1885: "invalid base64 character %d.",
! 1886: t -> string [i]);
! 1887: bad:
! 1888: data_string_forget (data, MDL);
! 1889: goto out;
! 1890: }
! 1891: if (foo == '=')
! 1892: terminated = 1;
! 1893: else {
! 1894: foo = from64 [foo - ' '];
! 1895: if (foo == 64)
! 1896: goto bad64;
! 1897: acc = (acc << 6) + foo;
! 1898: switch (k % 4) {
! 1899: case 0:
! 1900: break;
! 1901: case 1:
! 1902: data -> buffer -> data [j++] = (acc >> 4);
! 1903: acc = acc & 0x0f;
! 1904: break;
! 1905:
! 1906: case 2:
! 1907: data -> buffer -> data [j++] = (acc >> 2);
! 1908: acc = acc & 0x03;
! 1909: break;
! 1910: case 3:
! 1911: data -> buffer -> data [j++] = acc;
! 1912: acc = 0;
! 1913: break;
! 1914: }
! 1915: }
! 1916: k++;
! 1917: }
! 1918: }
! 1919: if (k % 4) {
! 1920: if (acc) {
! 1921: parse_warn (cfile,
! 1922: "partial base64 value left over: %d.",
! 1923: acc);
! 1924: }
! 1925: }
! 1926: data -> len = j;
! 1927: data -> data = data -> buffer -> data;
! 1928: out:
! 1929: for (t = bufs; t; t = last) {
! 1930: last = t -> next;
! 1931: dfree (t, MDL);
! 1932: }
! 1933: if (data -> len)
! 1934: return 1;
! 1935: else
! 1936: return 0;
! 1937: }
! 1938:
! 1939:
! 1940: /*
! 1941: * colon-separated-hex-list :== NUMBER |
! 1942: * NUMBER COLON colon-separated-hex-list
! 1943: */
! 1944:
! 1945: int parse_cshl (data, cfile)
! 1946: struct data_string *data;
! 1947: struct parse *cfile;
! 1948: {
! 1949: u_int8_t ibuf [128];
! 1950: unsigned ilen = 0;
! 1951: unsigned tlen = 0;
! 1952: struct option_tag *sl = (struct option_tag *)0;
! 1953: struct option_tag *next, **last = &sl;
! 1954: enum dhcp_token token;
! 1955: const char *val;
! 1956: unsigned char *rvp;
! 1957:
! 1958: do {
! 1959: token = next_token (&val, (unsigned *)0, cfile);
! 1960: if (token != NUMBER && token != NUMBER_OR_NAME) {
! 1961: parse_warn (cfile, "expecting hexadecimal number.");
! 1962: skip_to_semi (cfile);
! 1963: for (; sl; sl = next) {
! 1964: next = sl -> next;
! 1965: dfree (sl, MDL);
! 1966: }
! 1967: return 0;
! 1968: }
! 1969: if (ilen == sizeof ibuf) {
! 1970: next = (struct option_tag *)
! 1971: dmalloc (ilen - 1 +
! 1972: sizeof (struct option_tag), MDL);
! 1973: if (!next)
! 1974: log_fatal ("no memory for string list.");
! 1975: memcpy (next -> data, ibuf, ilen);
! 1976: *last = next;
! 1977: last = &next -> next;
! 1978: tlen += ilen;
! 1979: ilen = 0;
! 1980: }
! 1981: convert_num (cfile, &ibuf [ilen++], val, 16, 8);
! 1982:
! 1983: token = peek_token (&val, (unsigned *)0, cfile);
! 1984: if (token != COLON)
! 1985: break;
! 1986: token = next_token (&val, (unsigned *)0, cfile);
! 1987: } while (1);
! 1988:
! 1989: if (!buffer_allocate (&data -> buffer, tlen + ilen, MDL))
! 1990: log_fatal ("no memory to store octet data.");
! 1991: data -> data = &data -> buffer -> data [0];
! 1992: data -> len = tlen + ilen;
! 1993: data -> terminated = 0;
! 1994:
! 1995: rvp = &data -> buffer -> data [0];
! 1996: while (sl) {
! 1997: next = sl -> next;
! 1998: memcpy (rvp, sl -> data, sizeof ibuf);
! 1999: rvp += sizeof ibuf;
! 2000: dfree (sl, MDL);
! 2001: sl = next;
! 2002: }
! 2003:
! 2004: memcpy (rvp, ibuf, ilen);
! 2005: return 1;
! 2006: }
! 2007:
! 2008: /*
! 2009: * executable-statements :== executable-statement executable-statements |
! 2010: * executable-statement
! 2011: *
! 2012: * executable-statement :==
! 2013: * IF if-statement |
! 2014: * ADD class-name SEMI |
! 2015: * BREAK SEMI |
! 2016: * OPTION option-parameter SEMI |
! 2017: * SUPERSEDE option-parameter SEMI |
! 2018: * PREPEND option-parameter SEMI |
! 2019: * APPEND option-parameter SEMI
! 2020: */
! 2021:
! 2022: int parse_executable_statements (statements, cfile, lose, case_context)
! 2023: struct executable_statement **statements;
! 2024: struct parse *cfile;
! 2025: int *lose;
! 2026: enum expression_context case_context;
! 2027: {
! 2028: struct executable_statement **next;
! 2029:
! 2030: next = statements;
! 2031: while (parse_executable_statement (next, cfile, lose, case_context))
! 2032: next = &((*next) -> next);
! 2033: if (!*lose)
! 2034: return 1;
! 2035: return 0;
! 2036: }
! 2037:
! 2038: int parse_executable_statement (result, cfile, lose, case_context)
! 2039: struct executable_statement **result;
! 2040: struct parse *cfile;
! 2041: int *lose;
! 2042: enum expression_context case_context;
! 2043: {
! 2044: #if defined(ENABLE_EXECUTE)
! 2045: unsigned len;
! 2046: struct expression **ep;
! 2047: #endif
! 2048: enum dhcp_token token;
! 2049: const char *val;
! 2050: struct class *cta;
! 2051: struct option *option=NULL;
! 2052: struct option_cache *cache;
! 2053: int known;
! 2054: int flag;
! 2055: int i;
! 2056: struct dns_zone *zone;
! 2057: isc_result_t status;
! 2058: char *s;
! 2059:
! 2060: token = peek_token (&val, (unsigned *)0, cfile);
! 2061: switch (token) {
! 2062: case DB_TIME_FORMAT:
! 2063: next_token(&val, NULL, cfile);
! 2064:
! 2065: token = next_token(&val, NULL, cfile);
! 2066: if (token == DEFAULT) {
! 2067: db_time_format = DEFAULT_TIME_FORMAT;
! 2068: } else if (token == LOCAL) {
! 2069: db_time_format = LOCAL_TIME_FORMAT;
! 2070: } else {
! 2071: parse_warn(cfile, "Expecting 'local' or 'default'.");
! 2072: if (token != SEMI)
! 2073: skip_to_semi(cfile);
! 2074: *lose = 1;
! 2075: return 0;
! 2076: }
! 2077:
! 2078: token = next_token(&val, NULL, cfile);
! 2079: if (token != SEMI) {
! 2080: parse_warn(cfile, "Expecting a semicolon.");
! 2081: *lose = 1;
! 2082: return 0;
! 2083: }
! 2084:
! 2085: /* We're done here. */
! 2086: return 1;
! 2087:
! 2088: case IF:
! 2089: next_token (&val, (unsigned *)0, cfile);
! 2090: return parse_if_statement (result, cfile, lose);
! 2091:
! 2092: case TOKEN_ADD:
! 2093: token = next_token (&val, (unsigned *)0, cfile);
! 2094: token = next_token (&val, (unsigned *)0, cfile);
! 2095: if (token != STRING) {
! 2096: parse_warn (cfile, "expecting class name.");
! 2097: skip_to_semi (cfile);
! 2098: *lose = 1;
! 2099: return 0;
! 2100: }
! 2101: cta = (struct class *)0;
! 2102: status = find_class (&cta, val, MDL);
! 2103: if (status != ISC_R_SUCCESS) {
! 2104: parse_warn (cfile, "class %s: %s",
! 2105: val, isc_result_totext (status));
! 2106: skip_to_semi (cfile);
! 2107: *lose = 1;
! 2108: return 0;
! 2109: }
! 2110: if (!parse_semi (cfile)) {
! 2111: *lose = 1;
! 2112: return 0;
! 2113: }
! 2114: if (!executable_statement_allocate (result, MDL))
! 2115: log_fatal ("no memory for new statement.");
! 2116: (*result) -> op = add_statement;
! 2117: (*result) -> data.add = cta;
! 2118: break;
! 2119:
! 2120: case BREAK:
! 2121: token = next_token (&val, (unsigned *)0, cfile);
! 2122: if (!parse_semi (cfile)) {
! 2123: *lose = 1;
! 2124: return 0;
! 2125: }
! 2126: if (!executable_statement_allocate (result, MDL))
! 2127: log_fatal ("no memory for new statement.");
! 2128: (*result) -> op = break_statement;
! 2129: break;
! 2130:
! 2131: case SEND:
! 2132: token = next_token (&val, (unsigned *)0, cfile);
! 2133: known = 0;
! 2134: status = parse_option_name (cfile, 0, &known, &option);
! 2135: if (status != ISC_R_SUCCESS || option == NULL) {
! 2136: *lose = 1;
! 2137: return 0;
! 2138: }
! 2139: status = parse_option_statement(result, cfile, 1, option,
! 2140: send_option_statement);
! 2141: option_dereference(&option, MDL);
! 2142: return status;
! 2143:
! 2144: case SUPERSEDE:
! 2145: case OPTION:
! 2146: token = next_token (&val, (unsigned *)0, cfile);
! 2147: known = 0;
! 2148: status = parse_option_name (cfile, 0, &known, &option);
! 2149: if (status != ISC_R_SUCCESS || option == NULL) {
! 2150: *lose = 1;
! 2151: return 0;
! 2152: }
! 2153: status = parse_option_statement(result, cfile, 1, option,
! 2154: supersede_option_statement);
! 2155: option_dereference(&option, MDL);
! 2156: return status;
! 2157:
! 2158: case ALLOW:
! 2159: flag = 1;
! 2160: goto pad;
! 2161: case DENY:
! 2162: flag = 0;
! 2163: goto pad;
! 2164: case IGNORE:
! 2165: flag = 2;
! 2166: pad:
! 2167: token = next_token (&val, (unsigned *)0, cfile);
! 2168: cache = (struct option_cache *)0;
! 2169: if (!parse_allow_deny (&cache, cfile, flag))
! 2170: return 0;
! 2171: if (!executable_statement_allocate (result, MDL))
! 2172: log_fatal ("no memory for new statement.");
! 2173: (*result) -> op = supersede_option_statement;
! 2174: (*result) -> data.option = cache;
! 2175: break;
! 2176:
! 2177: case DEFAULT:
! 2178: token = next_token (&val, (unsigned *)0, cfile);
! 2179: token = peek_token (&val, (unsigned *)0, cfile);
! 2180: if (token == COLON)
! 2181: goto switch_default;
! 2182: known = 0;
! 2183: status = parse_option_name (cfile, 0, &known, &option);
! 2184: if (status != ISC_R_SUCCESS || option == NULL) {
! 2185: *lose = 1;
! 2186: return 0;
! 2187: }
! 2188: status = parse_option_statement(result, cfile, 1, option,
! 2189: default_option_statement);
! 2190: option_dereference(&option, MDL);
! 2191: return status;
! 2192:
! 2193: case PREPEND:
! 2194: token = next_token (&val, (unsigned *)0, cfile);
! 2195: known = 0;
! 2196: status = parse_option_name (cfile, 0, &known, &option);
! 2197: if (status != ISC_R_SUCCESS || option == NULL) {
! 2198: *lose = 1;
! 2199: return 0;
! 2200: }
! 2201: status = parse_option_statement(result, cfile, 1, option,
! 2202: prepend_option_statement);
! 2203: option_dereference(&option, MDL);
! 2204: return status;
! 2205:
! 2206: case APPEND:
! 2207: token = next_token (&val, (unsigned *)0, cfile);
! 2208: known = 0;
! 2209: status = parse_option_name (cfile, 0, &known, &option);
! 2210: if (status != ISC_R_SUCCESS || option == NULL) {
! 2211: *lose = 1;
! 2212: return 0;
! 2213: }
! 2214: status = parse_option_statement(result, cfile, 1, option,
! 2215: append_option_statement);
! 2216: option_dereference(&option, MDL);
! 2217: return status;
! 2218:
! 2219: case ON:
! 2220: token = next_token (&val, (unsigned *)0, cfile);
! 2221: return parse_on_statement (result, cfile, lose);
! 2222:
! 2223: case SWITCH:
! 2224: token = next_token (&val, (unsigned *)0, cfile);
! 2225: return parse_switch_statement (result, cfile, lose);
! 2226:
! 2227: case CASE:
! 2228: token = next_token (&val, (unsigned *)0, cfile);
! 2229: if (case_context == context_any) {
! 2230: parse_warn (cfile,
! 2231: "case statement in inappropriate scope.");
! 2232: *lose = 1;
! 2233: skip_to_semi (cfile);
! 2234: return 0;
! 2235: }
! 2236: return parse_case_statement (result,
! 2237: cfile, lose, case_context);
! 2238:
! 2239: switch_default:
! 2240: token = next_token (&val, (unsigned *)0, cfile);
! 2241: if (case_context == context_any) {
! 2242: parse_warn (cfile, "switch default statement in %s",
! 2243: "inappropriate scope.");
! 2244:
! 2245: *lose = 1;
! 2246: return 0;
! 2247: } else {
! 2248: if (!executable_statement_allocate (result, MDL))
! 2249: log_fatal ("no memory for default statement.");
! 2250: (*result) -> op = default_statement;
! 2251: return 1;
! 2252: }
! 2253:
! 2254: case DEFINE:
! 2255: case TOKEN_SET:
! 2256: token = next_token (&val, (unsigned *)0, cfile);
! 2257: if (token == DEFINE)
! 2258: flag = 1;
! 2259: else
! 2260: flag = 0;
! 2261:
! 2262: token = next_token (&val, (unsigned *)0, cfile);
! 2263: if (token != NAME && token != NUMBER_OR_NAME) {
! 2264: parse_warn (cfile,
! 2265: "%s can't be a variable name", val);
! 2266: badset:
! 2267: skip_to_semi (cfile);
! 2268: *lose = 1;
! 2269: return 0;
! 2270: }
! 2271:
! 2272: if (!executable_statement_allocate (result, MDL))
! 2273: log_fatal ("no memory for set statement.");
! 2274: (*result) -> op = flag ? define_statement : set_statement;
! 2275: (*result) -> data.set.name = dmalloc (strlen (val) + 1, MDL);
! 2276: if (!(*result)->data.set.name)
! 2277: log_fatal ("can't allocate variable name");
! 2278: strcpy ((*result) -> data.set.name, val);
! 2279: token = next_token (&val, (unsigned *)0, cfile);
! 2280:
! 2281: if (token == LPAREN) {
! 2282: struct string_list *head, *cur, *new;
! 2283: struct expression *expr;
! 2284: head = cur = (struct string_list *)0;
! 2285: do {
! 2286: token = next_token (&val,
! 2287: (unsigned *)0, cfile);
! 2288: if (token == RPAREN)
! 2289: break;
! 2290: if (token != NAME && token != NUMBER_OR_NAME) {
! 2291: parse_warn (cfile,
! 2292: "expecting argument name");
! 2293: skip_to_rbrace (cfile, 0);
! 2294: *lose = 1;
! 2295: executable_statement_dereference
! 2296: (result, MDL);
! 2297: return 0;
! 2298: }
! 2299: new = ((struct string_list *)
! 2300: dmalloc (sizeof (struct string_list) +
! 2301: strlen (val), MDL));
! 2302: if (!new)
! 2303: log_fatal ("can't allocate string.");
! 2304: memset (new, 0, sizeof *new);
! 2305: strcpy (new -> string, val);
! 2306: if (cur) {
! 2307: cur -> next = new;
! 2308: cur = new;
! 2309: } else {
! 2310: head = cur = new;
! 2311: }
! 2312: token = next_token (&val,
! 2313: (unsigned *)0, cfile);
! 2314: } while (token == COMMA);
! 2315:
! 2316: if (token != RPAREN) {
! 2317: parse_warn (cfile, "expecting right paren.");
! 2318: badx:
! 2319: skip_to_semi (cfile);
! 2320: *lose = 1;
! 2321: executable_statement_dereference (result, MDL);
! 2322: return 0;
! 2323: }
! 2324:
! 2325: token = next_token (&val, (unsigned *)0, cfile);
! 2326: if (token != LBRACE) {
! 2327: parse_warn (cfile, "expecting left brace.");
! 2328: goto badx;
! 2329: }
! 2330:
! 2331: expr = (struct expression *)0;
! 2332: if (!(expression_allocate (&expr, MDL)))
! 2333: log_fatal ("can't allocate expression.");
! 2334: expr -> op = expr_function;
! 2335: if (!fundef_allocate (&expr -> data.func, MDL))
! 2336: log_fatal ("can't allocate fundef.");
! 2337: expr -> data.func -> args = head;
! 2338: (*result) -> data.set.expr = expr;
! 2339:
! 2340: if (!(parse_executable_statements
! 2341: (&expr -> data.func -> statements, cfile, lose,
! 2342: case_context))) {
! 2343: if (*lose)
! 2344: goto badx;
! 2345: }
! 2346:
! 2347: token = next_token (&val, (unsigned *)0, cfile);
! 2348: if (token != RBRACE) {
! 2349: parse_warn (cfile, "expecting rigt brace.");
! 2350: goto badx;
! 2351: }
! 2352: } else {
! 2353: if (token != EQUAL) {
! 2354: parse_warn (cfile,
! 2355: "expecting '=' in %s statement.",
! 2356: flag ? "define" : "set");
! 2357: goto badset;
! 2358: }
! 2359:
! 2360: if (!parse_expression (&(*result) -> data.set.expr,
! 2361: cfile, lose, context_any,
! 2362: (struct expression **)0,
! 2363: expr_none)) {
! 2364: if (!*lose)
! 2365: parse_warn (cfile,
! 2366: "expecting expression.");
! 2367: else
! 2368: *lose = 1;
! 2369: skip_to_semi (cfile);
! 2370: executable_statement_dereference (result, MDL);
! 2371: return 0;
! 2372: }
! 2373: if (!parse_semi (cfile)) {
! 2374: *lose = 1;
! 2375: executable_statement_dereference (result, MDL);
! 2376: return 0;
! 2377: }
! 2378: }
! 2379: break;
! 2380:
! 2381: case UNSET:
! 2382: token = next_token (&val, (unsigned *)0, cfile);
! 2383:
! 2384: token = next_token (&val, (unsigned *)0, cfile);
! 2385: if (token != NAME && token != NUMBER_OR_NAME) {
! 2386: parse_warn (cfile,
! 2387: "%s can't be a variable name", val);
! 2388: skip_to_semi (cfile);
! 2389: *lose = 1;
! 2390: return 0;
! 2391: }
! 2392:
! 2393: if (!executable_statement_allocate (result, MDL))
! 2394: log_fatal ("no memory for set statement.");
! 2395: (*result) -> op = unset_statement;
! 2396: (*result) -> data.unset = dmalloc (strlen (val) + 1, MDL);
! 2397: if (!(*result)->data.unset)
! 2398: log_fatal ("can't allocate variable name");
! 2399: strcpy ((*result) -> data.unset, val);
! 2400: if (!parse_semi (cfile)) {
! 2401: *lose = 1;
! 2402: executable_statement_dereference (result, MDL);
! 2403: return 0;
! 2404: }
! 2405: break;
! 2406:
! 2407: case EVAL:
! 2408: token = next_token (&val, (unsigned *)0, cfile);
! 2409:
! 2410: if (!executable_statement_allocate (result, MDL))
! 2411: log_fatal ("no memory for eval statement.");
! 2412: (*result) -> op = eval_statement;
! 2413:
! 2414: if (!parse_expression (&(*result) -> data.eval,
! 2415: cfile, lose, context_data, /* XXX */
! 2416: (struct expression **)0, expr_none)) {
! 2417: if (!*lose)
! 2418: parse_warn (cfile,
! 2419: "expecting data expression.");
! 2420: else
! 2421: *lose = 1;
! 2422: skip_to_semi (cfile);
! 2423: executable_statement_dereference (result, MDL);
! 2424: return 0;
! 2425: }
! 2426: if (!parse_semi (cfile)) {
! 2427: *lose = 1;
! 2428: executable_statement_dereference (result, MDL);
! 2429: }
! 2430: break;
! 2431:
! 2432: case EXECUTE:
! 2433: #ifdef ENABLE_EXECUTE
! 2434: token = next_token(&val, NULL, cfile);
! 2435:
! 2436: if (!executable_statement_allocate (result, MDL))
! 2437: log_fatal ("no memory for execute statement.");
! 2438: (*result)->op = execute_statement;
! 2439:
! 2440: token = next_token(&val, NULL, cfile);
! 2441: if (token != LPAREN) {
! 2442: parse_warn(cfile, "left parenthesis expected.");
! 2443: skip_to_semi(cfile);
! 2444: *lose = 1;
! 2445: return 0;
! 2446: }
! 2447:
! 2448: token = next_token(&val, &len, cfile);
! 2449: if (token != STRING) {
! 2450: parse_warn(cfile, "Expecting a quoted string.");
! 2451: skip_to_semi(cfile);
! 2452: *lose = 1;
! 2453: return 0;
! 2454: }
! 2455:
! 2456: (*result)->data.execute.command = dmalloc(len + 1, MDL);
! 2457: if ((*result)->data.execute.command == NULL)
! 2458: log_fatal("can't allocate command name");
! 2459: strcpy((*result)->data.execute.command, val);
! 2460:
! 2461: ep = &(*result)->data.execute.arglist;
! 2462: (*result)->data.execute.argc = 0;
! 2463:
! 2464: while((token = next_token(&val, NULL, cfile)) == COMMA) {
! 2465: if (!expression_allocate(ep, MDL))
! 2466: log_fatal ("can't allocate expression");
! 2467:
! 2468: if (!parse_data_expression (&(*ep) -> data.arg.val,
! 2469: cfile, lose)) {
! 2470: if (!*lose) {
! 2471: parse_warn (cfile,
! 2472: "expecting expression.");
! 2473: *lose = 1;
! 2474: }
! 2475: skip_to_semi(cfile);
! 2476: *lose = 1;
! 2477: return 0;
! 2478: }
! 2479: ep = &(*ep)->data.arg.next;
! 2480: (*result)->data.execute.argc++;
! 2481: }
! 2482:
! 2483: if (token != RPAREN) {
! 2484: parse_warn(cfile, "right parenthesis expected.");
! 2485: skip_to_semi(cfile);
! 2486: *lose = 1;
! 2487: return 0;
! 2488: }
! 2489:
! 2490: if (!parse_semi (cfile)) {
! 2491: *lose = 1;
! 2492: executable_statement_dereference (result, MDL);
! 2493: }
! 2494: #else /* ! ENABLE_EXECUTE */
! 2495: parse_warn(cfile, "define ENABLE_EXECUTE in site.h to "
! 2496: "enable execute(); expressions.");
! 2497: skip_to_semi(cfile);
! 2498: *lose = 1;
! 2499: return 0;
! 2500: #endif /* ENABLE_EXECUTE */
! 2501: break;
! 2502:
! 2503: case RETURN:
! 2504: token = next_token (&val, (unsigned *)0, cfile);
! 2505:
! 2506: if (!executable_statement_allocate (result, MDL))
! 2507: log_fatal ("no memory for return statement.");
! 2508: (*result) -> op = return_statement;
! 2509:
! 2510: if (!parse_expression (&(*result) -> data.retval,
! 2511: cfile, lose, context_data,
! 2512: (struct expression **)0, expr_none)) {
! 2513: if (!*lose)
! 2514: parse_warn (cfile,
! 2515: "expecting data expression.");
! 2516: else
! 2517: *lose = 1;
! 2518: skip_to_semi (cfile);
! 2519: executable_statement_dereference (result, MDL);
! 2520: return 0;
! 2521: }
! 2522: if (!parse_semi (cfile)) {
! 2523: *lose = 1;
! 2524: executable_statement_dereference (result, MDL);
! 2525: return 0;
! 2526: }
! 2527: break;
! 2528:
! 2529: case LOG:
! 2530: token = next_token (&val, (unsigned *)0, cfile);
! 2531:
! 2532: if (!executable_statement_allocate (result, MDL))
! 2533: log_fatal ("no memory for log statement.");
! 2534: (*result) -> op = log_statement;
! 2535:
! 2536: token = next_token (&val, (unsigned *)0, cfile);
! 2537: if (token != LPAREN) {
! 2538: parse_warn (cfile, "left parenthesis expected.");
! 2539: skip_to_semi (cfile);
! 2540: *lose = 1;
! 2541: return 0;
! 2542: }
! 2543:
! 2544: token = peek_token (&val, (unsigned *)0, cfile);
! 2545: i = 1;
! 2546: if (token == FATAL) {
! 2547: (*result) -> data.log.priority = log_priority_fatal;
! 2548: } else if (token == ERROR) {
! 2549: (*result) -> data.log.priority = log_priority_error;
! 2550: } else if (token == TOKEN_DEBUG) {
! 2551: (*result) -> data.log.priority = log_priority_debug;
! 2552: } else if (token == INFO) {
! 2553: (*result) -> data.log.priority = log_priority_info;
! 2554: } else {
! 2555: (*result) -> data.log.priority = log_priority_debug;
! 2556: i = 0;
! 2557: }
! 2558: if (i) {
! 2559: token = next_token (&val, (unsigned *)0, cfile);
! 2560: token = next_token (&val, (unsigned *)0, cfile);
! 2561: if (token != COMMA) {
! 2562: parse_warn (cfile, "comma expected.");
! 2563: skip_to_semi (cfile);
! 2564: *lose = 1;
! 2565: return 0;
! 2566: }
! 2567: }
! 2568:
! 2569: if (!(parse_data_expression
! 2570: (&(*result) -> data.log.expr, cfile, lose))) {
! 2571: skip_to_semi (cfile);
! 2572: *lose = 1;
! 2573: return 0;
! 2574: }
! 2575:
! 2576: token = next_token (&val, (unsigned *)0, cfile);
! 2577: if (token != RPAREN) {
! 2578: parse_warn (cfile, "right parenthesis expected.");
! 2579: skip_to_semi (cfile);
! 2580: *lose = 1;
! 2581: return 0;
! 2582: }
! 2583:
! 2584: token = next_token (&val, (unsigned *)0, cfile);
! 2585: if (token != SEMI) {
! 2586: parse_warn (cfile, "semicolon expected.");
! 2587: skip_to_semi (cfile);
! 2588: *lose = 1;
! 2589: return 0;
! 2590: }
! 2591: break;
! 2592:
! 2593: /* Not really a statement, but we parse it here anyway
! 2594: because it's appropriate for all DHCP agents with
! 2595: parsers. */
! 2596: case ZONE:
! 2597: token = next_token (&val, (unsigned *)0, cfile);
! 2598: zone = (struct dns_zone *)0;
! 2599: if (!dns_zone_allocate (&zone, MDL))
! 2600: log_fatal ("no memory for new zone.");
! 2601: zone -> name = parse_host_name (cfile);
! 2602: if (!zone -> name) {
! 2603: parse_warn (cfile, "expecting hostname.");
! 2604: badzone:
! 2605: *lose = 1;
! 2606: skip_to_semi (cfile);
! 2607: dns_zone_dereference (&zone, MDL);
! 2608: return 0;
! 2609: }
! 2610: i = strlen (zone -> name);
! 2611: if (zone -> name [i - 1] != '.') {
! 2612: s = dmalloc ((unsigned)i + 2, MDL);
! 2613: if (!s) {
! 2614: parse_warn (cfile, "no trailing '.' on zone");
! 2615: goto badzone;
! 2616: }
! 2617: strcpy (s, zone -> name);
! 2618: s [i] = '.';
! 2619: s [i + 1] = 0;
! 2620: dfree (zone -> name, MDL);
! 2621: zone -> name = s;
! 2622: }
! 2623: if (!parse_zone (zone, cfile))
! 2624: goto badzone;
! 2625: status = enter_dns_zone (zone);
! 2626: if (status != ISC_R_SUCCESS) {
! 2627: parse_warn (cfile, "dns zone key %s: %s",
! 2628: zone -> name, isc_result_totext (status));
! 2629: dns_zone_dereference (&zone, MDL);
! 2630: return 0;
! 2631: }
! 2632: dns_zone_dereference (&zone, MDL);
! 2633: return 1;
! 2634:
! 2635: /* Also not really a statement, but same idea as above. */
! 2636: case KEY:
! 2637: token = next_token (&val, (unsigned *)0, cfile);
! 2638: if (!parse_key (cfile)) {
! 2639: *lose = 1;
! 2640: return 0;
! 2641: }
! 2642: return 1;
! 2643:
! 2644: default:
! 2645: if (config_universe && is_identifier (token)) {
! 2646: option = (struct option *)0;
! 2647: option_name_hash_lookup(&option,
! 2648: config_universe->name_hash,
! 2649: val, 0, MDL);
! 2650: if (option) {
! 2651: token = next_token (&val,
! 2652: (unsigned *)0, cfile);
! 2653: status = parse_option_statement
! 2654: (result, cfile, 1, option,
! 2655: supersede_option_statement);
! 2656: option_dereference(&option, MDL);
! 2657: return status;
! 2658: }
! 2659: }
! 2660:
! 2661: if (token == NUMBER_OR_NAME || token == NAME) {
! 2662: /* This is rather ugly. Since function calls are
! 2663: data expressions, fake up an eval statement. */
! 2664: if (!executable_statement_allocate (result, MDL))
! 2665: log_fatal ("no memory for eval statement.");
! 2666: (*result) -> op = eval_statement;
! 2667:
! 2668: if (!parse_expression (&(*result) -> data.eval,
! 2669: cfile, lose, context_data,
! 2670: (struct expression **)0,
! 2671: expr_none)) {
! 2672: if (!*lose)
! 2673: parse_warn (cfile, "expecting "
! 2674: "function call.");
! 2675: else
! 2676: *lose = 1;
! 2677: skip_to_semi (cfile);
! 2678: executable_statement_dereference (result, MDL);
! 2679: return 0;
! 2680: }
! 2681: if (!parse_semi (cfile)) {
! 2682: *lose = 1;
! 2683: executable_statement_dereference (result, MDL);
! 2684: return 0;
! 2685: }
! 2686: break;
! 2687: }
! 2688:
! 2689: *lose = 0;
! 2690: return 0;
! 2691: }
! 2692:
! 2693: return 1;
! 2694: }
! 2695:
! 2696: /* zone-statements :== zone-statement |
! 2697: zone-statement zone-statements
! 2698: zone-statement :==
! 2699: PRIMARY ip-addresses SEMI |
! 2700: SECONDARY ip-addresses SEMI |
! 2701: key-reference SEMI
! 2702: ip-addresses :== ip-addr-or-hostname |
! 2703: ip-addr-or-hostname COMMA ip-addresses
! 2704: key-reference :== KEY STRING |
! 2705: KEY identifier */
! 2706:
! 2707: int parse_zone (struct dns_zone *zone, struct parse *cfile)
! 2708: {
! 2709: int token;
! 2710: const char *val;
! 2711: char *key_name;
! 2712: struct option_cache *oc;
! 2713: int done = 0;
! 2714:
! 2715: token = next_token (&val, (unsigned *)0, cfile);
! 2716: if (token != LBRACE) {
! 2717: parse_warn (cfile, "expecting left brace");
! 2718: return 0;
! 2719: }
! 2720:
! 2721: do {
! 2722: token = peek_token (&val, (unsigned *)0, cfile);
! 2723: switch (token) {
! 2724: case PRIMARY:
! 2725: if (zone -> primary) {
! 2726: parse_warn (cfile,
! 2727: "more than one primary.");
! 2728: skip_to_semi (cfile);
! 2729: return 0;
! 2730: }
! 2731: if (!option_cache_allocate (&zone -> primary, MDL))
! 2732: log_fatal ("can't allocate primary option cache.");
! 2733: oc = zone -> primary;
! 2734: goto consemup;
! 2735:
! 2736: case SECONDARY:
! 2737: if (zone -> secondary) {
! 2738: parse_warn (cfile, "more than one secondary.");
! 2739: skip_to_semi (cfile);
! 2740: return 0;
! 2741: }
! 2742: if (!option_cache_allocate (&zone -> secondary, MDL))
! 2743: log_fatal ("can't allocate secondary.");
! 2744: oc = zone -> secondary;
! 2745: consemup:
! 2746: token = next_token (&val, (unsigned *)0, cfile);
! 2747: do {
! 2748: struct expression *expr = (struct expression *)0;
! 2749: if (!parse_ip_addr_or_hostname (&expr, cfile, 0)) {
! 2750: parse_warn (cfile,
! 2751: "expecting IP addr or hostname.");
! 2752: skip_to_semi (cfile);
! 2753: return 0;
! 2754: }
! 2755: if (oc -> expression) {
! 2756: struct expression *old =
! 2757: (struct expression *)0;
! 2758: expression_reference (&old,
! 2759: oc -> expression,
! 2760: MDL);
! 2761: expression_dereference (&oc -> expression,
! 2762: MDL);
! 2763: if (!make_concat (&oc -> expression,
! 2764: old, expr))
! 2765: log_fatal ("no memory for concat.");
! 2766: expression_dereference (&expr, MDL);
! 2767: expression_dereference (&old, MDL);
! 2768: } else {
! 2769: expression_reference (&oc -> expression,
! 2770: expr, MDL);
! 2771: expression_dereference (&expr, MDL);
! 2772: }
! 2773: token = next_token (&val, (unsigned *)0, cfile);
! 2774: } while (token == COMMA);
! 2775: if (token != SEMI) {
! 2776: parse_warn (cfile, "expecting semicolon.");
! 2777: skip_to_semi (cfile);
! 2778: return 0;
! 2779: }
! 2780: break;
! 2781:
! 2782: case KEY:
! 2783: token = next_token (&val, (unsigned *)0, cfile);
! 2784: token = peek_token (&val, (unsigned *)0, cfile);
! 2785: if (token == STRING) {
! 2786: token = next_token (&val, (unsigned *)0, cfile);
! 2787: key_name = (char *)0;
! 2788: } else {
! 2789: key_name = parse_host_name (cfile);
! 2790: if (!key_name) {
! 2791: parse_warn (cfile, "expecting key name.");
! 2792: skip_to_semi (cfile);
! 2793: return 0;
! 2794: }
! 2795: val = key_name;
! 2796: }
! 2797: if (omapi_auth_key_lookup_name (&zone -> key, val) !=
! 2798: ISC_R_SUCCESS)
! 2799: parse_warn (cfile, "unknown key %s", val);
! 2800: if (key_name)
! 2801: dfree (key_name, MDL);
! 2802: if (!parse_semi (cfile))
! 2803: return 0;
! 2804: break;
! 2805:
! 2806: default:
! 2807: done = 1;
! 2808: break;
! 2809: }
! 2810: } while (!done);
! 2811:
! 2812: token = next_token (&val, (unsigned *)0, cfile);
! 2813: if (token != RBRACE) {
! 2814: parse_warn (cfile, "expecting right brace.");
! 2815: return 0;
! 2816: }
! 2817: return 1;
! 2818: }
! 2819:
! 2820: /* key-statements :== key-statement |
! 2821: key-statement key-statements
! 2822: key-statement :==
! 2823: ALGORITHM host-name SEMI |
! 2824: secret-definition SEMI
! 2825: secret-definition :== SECRET base64val |
! 2826: SECRET STRING */
! 2827:
! 2828: int parse_key (struct parse *cfile)
! 2829: {
! 2830: int token;
! 2831: const char *val;
! 2832: int done = 0;
! 2833: struct auth_key *key;
! 2834: struct data_string ds;
! 2835: isc_result_t status;
! 2836: char *s;
! 2837:
! 2838: key = (struct auth_key *)0;
! 2839: if (omapi_auth_key_new (&key, MDL) != ISC_R_SUCCESS)
! 2840: log_fatal ("no memory for key");
! 2841:
! 2842: token = peek_token (&val, (unsigned *)0, cfile);
! 2843: if (token == STRING) {
! 2844: token = next_token (&val, (unsigned *)0, cfile);
! 2845: key -> name = dmalloc (strlen (val) + 1, MDL);
! 2846: if (!key -> name)
! 2847: log_fatal ("no memory for key name.");
! 2848: strcpy (key -> name, val);
! 2849:
! 2850: } else {
! 2851: key -> name = parse_host_name (cfile);
! 2852: if (!key -> name) {
! 2853: parse_warn (cfile, "expecting key name.");
! 2854: skip_to_semi (cfile);
! 2855: goto bad;
! 2856: }
! 2857: }
! 2858:
! 2859: token = next_token (&val, (unsigned *)0, cfile);
! 2860: if (token != LBRACE) {
! 2861: parse_warn (cfile, "expecting left brace");
! 2862: goto bad;
! 2863: }
! 2864:
! 2865: do {
! 2866: token = next_token (&val, (unsigned *)0, cfile);
! 2867: switch (token) {
! 2868: case ALGORITHM:
! 2869: if (key -> algorithm) {
! 2870: parse_warn (cfile,
! 2871: "key %s: too many algorithms",
! 2872: key -> name);
! 2873: goto rbad;
! 2874: }
! 2875: key -> algorithm = parse_host_name (cfile);
! 2876: if (!key -> algorithm) {
! 2877: parse_warn (cfile,
! 2878: "expecting key algorithm name.");
! 2879: goto rbad;
! 2880: }
! 2881: if (!parse_semi (cfile))
! 2882: goto rbad;
! 2883: /* If the algorithm name isn't an FQDN, tack on
! 2884: the .SIG-ALG.REG.NET. domain. */
! 2885: s = strrchr (key -> algorithm, '.');
! 2886: if (!s) {
! 2887: static char add [] = ".SIG-ALG.REG.INT.";
! 2888: s = dmalloc (strlen (key -> algorithm) +
! 2889: sizeof (add), MDL);
! 2890: if (!s) {
! 2891: log_error ("no memory for key %s.",
! 2892: "algorithm");
! 2893: goto rbad;
! 2894: }
! 2895: strcpy (s, key -> algorithm);
! 2896: strcat (s, add);
! 2897: dfree (key -> algorithm, MDL);
! 2898: key -> algorithm = s;
! 2899: } else if (s [1]) {
! 2900: /* If there is no trailing '.', hack one in. */
! 2901: s = dmalloc (strlen (key -> algorithm) + 2, MDL);
! 2902: if (!s) {
! 2903: log_error ("no memory for key %s.",
! 2904: key -> algorithm);
! 2905: goto rbad;
! 2906: }
! 2907: strcpy (s, key -> algorithm);
! 2908: strcat (s, ".");
! 2909: dfree (key -> algorithm, MDL);
! 2910: key -> algorithm = s;
! 2911: }
! 2912: break;
! 2913:
! 2914: case SECRET:
! 2915: if (key -> key) {
! 2916: parse_warn (cfile, "key %s: too many secrets",
! 2917: key -> name);
! 2918: goto rbad;
! 2919: }
! 2920:
! 2921: memset (&ds, 0, sizeof(ds));
! 2922: if (!parse_base64 (&ds, cfile))
! 2923: goto rbad;
! 2924: status = omapi_data_string_new (&key -> key, ds.len,
! 2925: MDL);
! 2926: if (status != ISC_R_SUCCESS)
! 2927: goto rbad;
! 2928: memcpy (key -> key -> value,
! 2929: ds.buffer -> data, ds.len);
! 2930: data_string_forget (&ds, MDL);
! 2931:
! 2932: if (!parse_semi (cfile))
! 2933: goto rbad;
! 2934: break;
! 2935:
! 2936: default:
! 2937: done = 1;
! 2938: break;
! 2939: }
! 2940: } while (!done);
! 2941: if (token != RBRACE) {
! 2942: parse_warn (cfile, "expecting right brace.");
! 2943: goto rbad;
! 2944: }
! 2945: /* Allow the BIND 8 syntax, which has a semicolon after each
! 2946: closing brace. */
! 2947: token = peek_token (&val, (unsigned *)0, cfile);
! 2948: if (token == SEMI)
! 2949: token = next_token (&val, (unsigned *)0, cfile);
! 2950:
! 2951: /* Remember the key. */
! 2952: status = omapi_auth_key_enter (key);
! 2953: if (status != ISC_R_SUCCESS) {
! 2954: parse_warn (cfile, "tsig key %s: %s",
! 2955: key -> name, isc_result_totext (status));
! 2956: goto bad;
! 2957: }
! 2958: omapi_auth_key_dereference (&key, MDL);
! 2959: return 1;
! 2960:
! 2961: rbad:
! 2962: skip_to_rbrace (cfile, 1);
! 2963: bad:
! 2964: omapi_auth_key_dereference (&key, MDL);
! 2965: return 0;
! 2966: }
! 2967:
! 2968: /*
! 2969: * on-statement :== event-types LBRACE executable-statements RBRACE
! 2970: * event-types :== event-type OR event-types |
! 2971: * event-type
! 2972: * event-type :== EXPIRY | COMMIT | RELEASE
! 2973: */
! 2974:
! 2975: int parse_on_statement (result, cfile, lose)
! 2976: struct executable_statement **result;
! 2977: struct parse *cfile;
! 2978: int *lose;
! 2979: {
! 2980: enum dhcp_token token;
! 2981: const char *val;
! 2982:
! 2983: if (!executable_statement_allocate (result, MDL))
! 2984: log_fatal ("no memory for new statement.");
! 2985: (*result) -> op = on_statement;
! 2986:
! 2987: do {
! 2988: token = next_token (&val, (unsigned *)0, cfile);
! 2989: switch (token) {
! 2990: case EXPIRY:
! 2991: (*result) -> data.on.evtypes |= ON_EXPIRY;
! 2992: break;
! 2993:
! 2994: case COMMIT:
! 2995: (*result) -> data.on.evtypes |= ON_COMMIT;
! 2996: break;
! 2997:
! 2998: case RELEASE:
! 2999: (*result) -> data.on.evtypes |= ON_RELEASE;
! 3000: break;
! 3001:
! 3002: case TRANSMISSION:
! 3003: (*result) -> data.on.evtypes |= ON_TRANSMISSION;
! 3004: break;
! 3005:
! 3006: default:
! 3007: parse_warn (cfile, "expecting a lease event type");
! 3008: skip_to_semi (cfile);
! 3009: *lose = 1;
! 3010: executable_statement_dereference (result, MDL);
! 3011: return 0;
! 3012: }
! 3013: token = next_token (&val, (unsigned *)0, cfile);
! 3014: } while (token == OR);
! 3015:
! 3016: /* Semicolon means no statements. */
! 3017: if (token == SEMI)
! 3018: return 1;
! 3019:
! 3020: if (token != LBRACE) {
! 3021: parse_warn (cfile, "left brace expected.");
! 3022: skip_to_semi (cfile);
! 3023: *lose = 1;
! 3024: executable_statement_dereference (result, MDL);
! 3025: return 0;
! 3026: }
! 3027: if (!parse_executable_statements (&(*result) -> data.on.statements,
! 3028: cfile, lose, context_any)) {
! 3029: if (*lose) {
! 3030: /* Try to even things up. */
! 3031: do {
! 3032: token = next_token (&val,
! 3033: (unsigned *)0, cfile);
! 3034: } while (token != END_OF_FILE && token != RBRACE);
! 3035: executable_statement_dereference (result, MDL);
! 3036: return 0;
! 3037: }
! 3038: }
! 3039: token = next_token (&val, (unsigned *)0, cfile);
! 3040: if (token != RBRACE) {
! 3041: parse_warn (cfile, "right brace expected.");
! 3042: skip_to_semi (cfile);
! 3043: *lose = 1;
! 3044: executable_statement_dereference (result, MDL);
! 3045: return 0;
! 3046: }
! 3047: return 1;
! 3048: }
! 3049:
! 3050: /*
! 3051: * switch-statement :== LPAREN expr RPAREN LBRACE executable-statements RBRACE
! 3052: *
! 3053: */
! 3054:
! 3055: int parse_switch_statement (result, cfile, lose)
! 3056: struct executable_statement **result;
! 3057: struct parse *cfile;
! 3058: int *lose;
! 3059: {
! 3060: enum dhcp_token token;
! 3061: const char *val;
! 3062:
! 3063: if (!executable_statement_allocate (result, MDL))
! 3064: log_fatal ("no memory for new statement.");
! 3065: (*result) -> op = switch_statement;
! 3066:
! 3067: token = next_token (&val, (unsigned *)0, cfile);
! 3068: if (token != LPAREN) {
! 3069: parse_warn (cfile, "expecting left brace.");
! 3070: pfui:
! 3071: *lose = 1;
! 3072: skip_to_semi (cfile);
! 3073: gnorf:
! 3074: executable_statement_dereference (result, MDL);
! 3075: return 0;
! 3076: }
! 3077:
! 3078: if (!parse_expression (&(*result) -> data.s_switch.expr,
! 3079: cfile, lose, context_data_or_numeric,
! 3080: (struct expression **)0, expr_none)) {
! 3081: if (!*lose) {
! 3082: parse_warn (cfile,
! 3083: "expecting data or numeric expression.");
! 3084: goto pfui;
! 3085: }
! 3086: goto gnorf;
! 3087: }
! 3088:
! 3089: token = next_token (&val, (unsigned *)0, cfile);
! 3090: if (token != RPAREN) {
! 3091: parse_warn (cfile, "right paren expected.");
! 3092: goto pfui;
! 3093: }
! 3094:
! 3095: token = next_token (&val, (unsigned *)0, cfile);
! 3096: if (token != LBRACE) {
! 3097: parse_warn (cfile, "left brace expected.");
! 3098: goto pfui;
! 3099: }
! 3100: if (!(parse_executable_statements
! 3101: (&(*result) -> data.s_switch.statements, cfile, lose,
! 3102: (is_data_expression ((*result) -> data.s_switch.expr)
! 3103: ? context_data : context_numeric)))) {
! 3104: if (*lose) {
! 3105: skip_to_rbrace (cfile, 1);
! 3106: executable_statement_dereference (result, MDL);
! 3107: return 0;
! 3108: }
! 3109: }
! 3110: token = next_token (&val, (unsigned *)0, cfile);
! 3111: if (token != RBRACE) {
! 3112: parse_warn (cfile, "right brace expected.");
! 3113: goto pfui;
! 3114: }
! 3115: return 1;
! 3116: }
! 3117:
! 3118: /*
! 3119: * case-statement :== CASE expr COLON
! 3120: *
! 3121: */
! 3122:
! 3123: int parse_case_statement (result, cfile, lose, case_context)
! 3124: struct executable_statement **result;
! 3125: struct parse *cfile;
! 3126: int *lose;
! 3127: enum expression_context case_context;
! 3128: {
! 3129: enum dhcp_token token;
! 3130: const char *val;
! 3131:
! 3132: if (!executable_statement_allocate (result, MDL))
! 3133: log_fatal ("no memory for new statement.");
! 3134: (*result) -> op = case_statement;
! 3135:
! 3136: if (!parse_expression (&(*result) -> data.c_case,
! 3137: cfile, lose, case_context,
! 3138: (struct expression **)0, expr_none))
! 3139: {
! 3140: if (!*lose) {
! 3141: parse_warn (cfile, "expecting %s expression.",
! 3142: (case_context == context_data
! 3143: ? "data" : "numeric"));
! 3144: }
! 3145: pfui:
! 3146: *lose = 1;
! 3147: skip_to_semi (cfile);
! 3148: executable_statement_dereference (result, MDL);
! 3149: return 0;
! 3150: }
! 3151:
! 3152: token = next_token (&val, (unsigned *)0, cfile);
! 3153: if (token != COLON) {
! 3154: parse_warn (cfile, "colon expected.");
! 3155: goto pfui;
! 3156: }
! 3157: return 1;
! 3158: }
! 3159:
! 3160: /*
! 3161: * if-statement :== boolean-expression LBRACE executable-statements RBRACE
! 3162: * else-statement
! 3163: *
! 3164: * else-statement :== <null> |
! 3165: * ELSE LBRACE executable-statements RBRACE |
! 3166: * ELSE IF if-statement |
! 3167: * ELSIF if-statement
! 3168: */
! 3169:
! 3170: int parse_if_statement (result, cfile, lose)
! 3171: struct executable_statement **result;
! 3172: struct parse *cfile;
! 3173: int *lose;
! 3174: {
! 3175: enum dhcp_token token;
! 3176: const char *val;
! 3177: int parenp;
! 3178:
! 3179: if (!executable_statement_allocate (result, MDL))
! 3180: log_fatal ("no memory for if statement.");
! 3181:
! 3182: (*result) -> op = if_statement;
! 3183:
! 3184: token = peek_token (&val, (unsigned *)0, cfile);
! 3185: if (token == LPAREN) {
! 3186: parenp = 1;
! 3187: next_token (&val, (unsigned *)0, cfile);
! 3188: } else
! 3189: parenp = 0;
! 3190:
! 3191:
! 3192: if (!parse_boolean_expression (&(*result) -> data.ie.expr,
! 3193: cfile, lose)) {
! 3194: if (!*lose)
! 3195: parse_warn (cfile, "boolean expression expected.");
! 3196: executable_statement_dereference (result, MDL);
! 3197: *lose = 1;
! 3198: return 0;
! 3199: }
! 3200: #if defined (DEBUG_EXPRESSION_PARSE)
! 3201: print_expression ("if condition", (*result) -> data.ie.expr);
! 3202: #endif
! 3203: if (parenp) {
! 3204: token = next_token (&val, (unsigned *)0, cfile);
! 3205: if (token != RPAREN) {
! 3206: parse_warn (cfile, "expecting right paren.");
! 3207: *lose = 1;
! 3208: executable_statement_dereference (result, MDL);
! 3209: return 0;
! 3210: }
! 3211: }
! 3212: token = next_token (&val, (unsigned *)0, cfile);
! 3213: if (token != LBRACE) {
! 3214: parse_warn (cfile, "left brace expected.");
! 3215: skip_to_semi (cfile);
! 3216: *lose = 1;
! 3217: executable_statement_dereference (result, MDL);
! 3218: return 0;
! 3219: }
! 3220: if (!parse_executable_statements (&(*result) -> data.ie.tc,
! 3221: cfile, lose, context_any)) {
! 3222: if (*lose) {
! 3223: /* Try to even things up. */
! 3224: do {
! 3225: token = next_token (&val,
! 3226: (unsigned *)0, cfile);
! 3227: } while (token != END_OF_FILE && token != RBRACE);
! 3228: executable_statement_dereference (result, MDL);
! 3229: return 0;
! 3230: }
! 3231: }
! 3232: token = next_token (&val, (unsigned *)0, cfile);
! 3233: if (token != RBRACE) {
! 3234: parse_warn (cfile, "right brace expected.");
! 3235: skip_to_semi (cfile);
! 3236: *lose = 1;
! 3237: executable_statement_dereference (result, MDL);
! 3238: return 0;
! 3239: }
! 3240: token = peek_token (&val, (unsigned *)0, cfile);
! 3241: if (token == ELSE) {
! 3242: token = next_token (&val, (unsigned *)0, cfile);
! 3243: token = peek_token (&val, (unsigned *)0, cfile);
! 3244: if (token == IF) {
! 3245: token = next_token (&val, (unsigned *)0, cfile);
! 3246: if (!parse_if_statement (&(*result) -> data.ie.fc,
! 3247: cfile, lose)) {
! 3248: if (!*lose)
! 3249: parse_warn (cfile,
! 3250: "expecting if statement");
! 3251: executable_statement_dereference (result, MDL);
! 3252: *lose = 1;
! 3253: return 0;
! 3254: }
! 3255: } else if (token != LBRACE) {
! 3256: parse_warn (cfile, "left brace or if expected.");
! 3257: skip_to_semi (cfile);
! 3258: *lose = 1;
! 3259: executable_statement_dereference (result, MDL);
! 3260: return 0;
! 3261: } else {
! 3262: token = next_token (&val, (unsigned *)0, cfile);
! 3263: if (!(parse_executable_statements
! 3264: (&(*result) -> data.ie.fc,
! 3265: cfile, lose, context_any))) {
! 3266: executable_statement_dereference (result, MDL);
! 3267: return 0;
! 3268: }
! 3269: token = next_token (&val, (unsigned *)0, cfile);
! 3270: if (token != RBRACE) {
! 3271: parse_warn (cfile, "right brace expected.");
! 3272: skip_to_semi (cfile);
! 3273: *lose = 1;
! 3274: executable_statement_dereference (result, MDL);
! 3275: return 0;
! 3276: }
! 3277: }
! 3278: } else if (token == ELSIF) {
! 3279: token = next_token (&val, (unsigned *)0, cfile);
! 3280: if (!parse_if_statement (&(*result) -> data.ie.fc,
! 3281: cfile, lose)) {
! 3282: if (!*lose)
! 3283: parse_warn (cfile,
! 3284: "expecting conditional.");
! 3285: executable_statement_dereference (result, MDL);
! 3286: *lose = 1;
! 3287: return 0;
! 3288: }
! 3289: } else
! 3290: (*result) -> data.ie.fc = (struct executable_statement *)0;
! 3291:
! 3292: return 1;
! 3293: }
! 3294:
! 3295: /*
! 3296: * boolean_expression :== CHECK STRING |
! 3297: * NOT boolean-expression |
! 3298: * data-expression EQUAL data-expression |
! 3299: * data-expression BANG EQUAL data-expression |
! 3300: * data-expression REGEX_MATCH data-expression |
! 3301: * boolean-expression AND boolean-expression |
! 3302: * boolean-expression OR boolean-expression
! 3303: * EXISTS OPTION-NAME
! 3304: */
! 3305:
! 3306: int parse_boolean_expression (expr, cfile, lose)
! 3307: struct expression **expr;
! 3308: struct parse *cfile;
! 3309: int *lose;
! 3310: {
! 3311: /* Parse an expression... */
! 3312: if (!parse_expression (expr, cfile, lose, context_boolean,
! 3313: (struct expression **)0, expr_none))
! 3314: return 0;
! 3315:
! 3316: if (!is_boolean_expression (*expr) &&
! 3317: (*expr) -> op != expr_variable_reference &&
! 3318: (*expr) -> op != expr_funcall) {
! 3319: parse_warn (cfile, "Expecting a boolean expression.");
! 3320: *lose = 1;
! 3321: expression_dereference (expr, MDL);
! 3322: return 0;
! 3323: }
! 3324: return 1;
! 3325: }
! 3326:
! 3327: /* boolean :== ON SEMI | OFF SEMI | TRUE SEMI | FALSE SEMI */
! 3328:
! 3329: int parse_boolean (cfile)
! 3330: struct parse *cfile;
! 3331: {
! 3332: enum dhcp_token token;
! 3333: const char *val;
! 3334: int rv;
! 3335:
! 3336: token = next_token (&val, (unsigned *)0, cfile);
! 3337: if (!strcasecmp (val, "true")
! 3338: || !strcasecmp (val, "on"))
! 3339: rv = 1;
! 3340: else if (!strcasecmp (val, "false")
! 3341: || !strcasecmp (val, "off"))
! 3342: rv = 0;
! 3343: else {
! 3344: parse_warn (cfile,
! 3345: "boolean value (true/false/on/off) expected");
! 3346: skip_to_semi (cfile);
! 3347: return 0;
! 3348: }
! 3349: parse_semi (cfile);
! 3350: return rv;
! 3351: }
! 3352:
! 3353:
! 3354: /*
! 3355: * data_expression :== SUBSTRING LPAREN data-expression COMMA
! 3356: * numeric-expression COMMA
! 3357: * numeric-expression RPAREN |
! 3358: * CONCAT LPAREN data-expression COMMA
! 3359: * data-expression RPAREN
! 3360: * SUFFIX LPAREN data_expression COMMA
! 3361: * numeric-expression RPAREN |
! 3362: * LCASE LPAREN data_expression RPAREN |
! 3363: * UCASE LPAREN data_expression RPAREN |
! 3364: * OPTION option_name |
! 3365: * HARDWARE |
! 3366: * PACKET LPAREN numeric-expression COMMA
! 3367: * numeric-expression RPAREN |
! 3368: * STRING |
! 3369: * colon_separated_hex_list
! 3370: */
! 3371:
! 3372: int parse_data_expression (expr, cfile, lose)
! 3373: struct expression **expr;
! 3374: struct parse *cfile;
! 3375: int *lose;
! 3376: {
! 3377: /* Parse an expression... */
! 3378: if (!parse_expression (expr, cfile, lose, context_data,
! 3379: (struct expression **)0, expr_none))
! 3380: return 0;
! 3381:
! 3382: if (!is_data_expression (*expr) &&
! 3383: (*expr) -> op != expr_variable_reference &&
! 3384: (*expr) -> op != expr_funcall) {
! 3385: expression_dereference (expr, MDL);
! 3386: parse_warn (cfile, "Expecting a data expression.");
! 3387: *lose = 1;
! 3388: return 0;
! 3389: }
! 3390: return 1;
! 3391: }
! 3392:
! 3393: /*
! 3394: * numeric-expression :== EXTRACT_INT LPAREN data-expression
! 3395: * COMMA number RPAREN |
! 3396: * NUMBER
! 3397: */
! 3398:
! 3399: int parse_numeric_expression (expr, cfile, lose)
! 3400: struct expression **expr;
! 3401: struct parse *cfile;
! 3402: int *lose;
! 3403: {
! 3404: /* Parse an expression... */
! 3405: if (!parse_expression (expr, cfile, lose, context_numeric,
! 3406: (struct expression **)0, expr_none))
! 3407: return 0;
! 3408:
! 3409: if (!is_numeric_expression (*expr) &&
! 3410: (*expr) -> op != expr_variable_reference &&
! 3411: (*expr) -> op != expr_funcall) {
! 3412: expression_dereference (expr, MDL);
! 3413: parse_warn (cfile, "Expecting a numeric expression.");
! 3414: *lose = 1;
! 3415: return 0;
! 3416: }
! 3417: return 1;
! 3418: }
! 3419:
! 3420: /*
! 3421: * dns-expression :==
! 3422: * UPDATE LPAREN ns-class COMMA ns-type COMMA data-expression COMMA
! 3423: * data-expression COMMA numeric-expression RPAREN
! 3424: * DELETE LPAREN ns-class COMMA ns-type COMMA data-expression COMMA
! 3425: * data-expression RPAREN
! 3426: * EXISTS LPAREN ns-class COMMA ns-type COMMA data-expression COMMA
! 3427: * data-expression RPAREN
! 3428: * NOT EXISTS LPAREN ns-class COMMA ns-type COMMA data-expression COMMA
! 3429: * data-expression RPAREN
! 3430: * ns-class :== IN | CHAOS | HS | NUMBER
! 3431: * ns-type :== A | PTR | MX | TXT | NUMBER
! 3432: */
! 3433:
! 3434: int parse_dns_expression (expr, cfile, lose)
! 3435: struct expression **expr;
! 3436: struct parse *cfile;
! 3437: int *lose;
! 3438: {
! 3439: /* Parse an expression... */
! 3440: if (!parse_expression (expr, cfile, lose, context_dns,
! 3441: (struct expression **)0, expr_none))
! 3442: return 0;
! 3443:
! 3444: if (!is_dns_expression (*expr) &&
! 3445: (*expr) -> op != expr_variable_reference &&
! 3446: (*expr) -> op != expr_funcall) {
! 3447: expression_dereference (expr, MDL);
! 3448: parse_warn (cfile, "Expecting a dns update subexpression.");
! 3449: *lose = 1;
! 3450: return 0;
! 3451: }
! 3452: return 1;
! 3453: }
! 3454:
! 3455: /* Parse a subexpression that does not contain a binary operator. */
! 3456:
! 3457: int parse_non_binary (expr, cfile, lose, context)
! 3458: struct expression **expr;
! 3459: struct parse *cfile;
! 3460: int *lose;
! 3461: enum expression_context context;
! 3462: {
! 3463: enum dhcp_token token;
! 3464: const char *val;
! 3465: struct collection *col;
! 3466: struct expression *nexp, **ep;
! 3467: int known;
! 3468: enum expr_op opcode;
! 3469: const char *s;
! 3470: char *cptr;
! 3471: unsigned long u;
! 3472: isc_result_t status;
! 3473: unsigned len;
! 3474:
! 3475: token = peek_token (&val, (unsigned *)0, cfile);
! 3476:
! 3477: /* Check for unary operators... */
! 3478: switch (token) {
! 3479: case CHECK:
! 3480: token = next_token (&val, (unsigned *)0, cfile);
! 3481: token = next_token (&val, (unsigned *)0, cfile);
! 3482: if (token != STRING) {
! 3483: parse_warn (cfile, "string expected.");
! 3484: skip_to_semi (cfile);
! 3485: *lose = 1;
! 3486: return 0;
! 3487: }
! 3488: for (col = collections; col; col = col -> next)
! 3489: if (!strcmp (col -> name, val))
! 3490: break;
! 3491: if (!col) {
! 3492: parse_warn (cfile, "unknown collection.");
! 3493: *lose = 1;
! 3494: return 0;
! 3495: }
! 3496: if (!expression_allocate (expr, MDL))
! 3497: log_fatal ("can't allocate expression");
! 3498: (*expr) -> op = expr_check;
! 3499: (*expr) -> data.check = col;
! 3500: break;
! 3501:
! 3502: case TOKEN_NOT:
! 3503: token = next_token (&val, (unsigned *)0, cfile);
! 3504: if (context == context_dns) {
! 3505: token = peek_token (&val, (unsigned *)0, cfile);
! 3506: goto not_exists;
! 3507: }
! 3508: if (!expression_allocate (expr, MDL))
! 3509: log_fatal ("can't allocate expression");
! 3510: (*expr) -> op = expr_not;
! 3511: if (!parse_non_binary (&(*expr) -> data.not,
! 3512: cfile, lose, context_boolean)) {
! 3513: if (!*lose) {
! 3514: parse_warn (cfile, "expression expected");
! 3515: skip_to_semi (cfile);
! 3516: }
! 3517: *lose = 1;
! 3518: expression_dereference (expr, MDL);
! 3519: return 0;
! 3520: }
! 3521: if (!is_boolean_expression ((*expr) -> data.not)) {
! 3522: *lose = 1;
! 3523: parse_warn (cfile, "boolean expression expected");
! 3524: skip_to_semi (cfile);
! 3525: expression_dereference (expr, MDL);
! 3526: return 0;
! 3527: }
! 3528: break;
! 3529:
! 3530: case LPAREN:
! 3531: token = next_token (&val, (unsigned *)0, cfile);
! 3532: if (!parse_expression (expr, cfile, lose, context,
! 3533: (struct expression **)0, expr_none)) {
! 3534: if (!*lose) {
! 3535: parse_warn (cfile, "expression expected");
! 3536: skip_to_semi (cfile);
! 3537: }
! 3538: *lose = 1;
! 3539: return 0;
! 3540: }
! 3541: token = next_token (&val, (unsigned *)0, cfile);
! 3542: if (token != RPAREN) {
! 3543: *lose = 1;
! 3544: parse_warn (cfile, "right paren expected");
! 3545: skip_to_semi (cfile);
! 3546: return 0;
! 3547: }
! 3548: break;
! 3549:
! 3550: case EXISTS:
! 3551: if (context == context_dns)
! 3552: goto ns_exists;
! 3553: token = next_token (&val, (unsigned *)0, cfile);
! 3554: if (!expression_allocate (expr, MDL))
! 3555: log_fatal ("can't allocate expression");
! 3556: (*expr) -> op = expr_exists;
! 3557: known = 0;
! 3558: /* Pass reference directly to expression structure. */
! 3559: status = parse_option_name(cfile, 0, &known,
! 3560: &(*expr)->data.option);
! 3561: if (status != ISC_R_SUCCESS ||
! 3562: (*expr)->data.option == NULL) {
! 3563: *lose = 1;
! 3564: expression_dereference (expr, MDL);
! 3565: return 0;
! 3566: }
! 3567: break;
! 3568:
! 3569: case STATIC:
! 3570: token = next_token (&val, (unsigned *)0, cfile);
! 3571: if (!expression_allocate (expr, MDL))
! 3572: log_fatal ("can't allocate expression");
! 3573: (*expr) -> op = expr_static;
! 3574: break;
! 3575:
! 3576: case KNOWN:
! 3577: token = next_token (&val, (unsigned *)0, cfile);
! 3578: if (!expression_allocate (expr, MDL))
! 3579: log_fatal ("can't allocate expression");
! 3580: (*expr) -> op = expr_known;
! 3581: break;
! 3582:
! 3583: case SUBSTRING:
! 3584: token = next_token (&val, (unsigned *)0, cfile);
! 3585: if (!expression_allocate (expr, MDL))
! 3586: log_fatal ("can't allocate expression");
! 3587: (*expr) -> op = expr_substring;
! 3588:
! 3589: token = next_token (&val, (unsigned *)0, cfile);
! 3590: if (token != LPAREN) {
! 3591: nolparen:
! 3592: expression_dereference (expr, MDL);
! 3593: parse_warn (cfile, "left parenthesis expected.");
! 3594: *lose = 1;
! 3595: return 0;
! 3596: }
! 3597:
! 3598: if (!parse_data_expression (&(*expr) -> data.substring.expr,
! 3599: cfile, lose)) {
! 3600: nodata:
! 3601: expression_dereference (expr, MDL);
! 3602: if (!*lose) {
! 3603: parse_warn (cfile,
! 3604: "expecting data expression.");
! 3605: skip_to_semi (cfile);
! 3606: *lose = 1;
! 3607: }
! 3608: return 0;
! 3609: }
! 3610:
! 3611: token = next_token (&val, (unsigned *)0, cfile);
! 3612: if (token != COMMA) {
! 3613: nocomma:
! 3614: expression_dereference (expr, MDL);
! 3615: parse_warn (cfile, "comma expected.");
! 3616: *lose = 1;
! 3617:
! 3618: return 0;
! 3619: }
! 3620:
! 3621: if (!parse_numeric_expression
! 3622: (&(*expr) -> data.substring.offset,cfile, lose)) {
! 3623: nonum:
! 3624: if (!*lose) {
! 3625: parse_warn (cfile,
! 3626: "expecting numeric expression.");
! 3627: skip_to_semi (cfile);
! 3628: *lose = 1;
! 3629: }
! 3630: expression_dereference (expr, MDL);
! 3631: return 0;
! 3632: }
! 3633:
! 3634: token = next_token (&val, (unsigned *)0, cfile);
! 3635: if (token != COMMA)
! 3636: goto nocomma;
! 3637:
! 3638: if (!parse_numeric_expression
! 3639: (&(*expr) -> data.substring.len, cfile, lose))
! 3640: goto nonum;
! 3641:
! 3642: token = next_token (&val, (unsigned *)0, cfile);
! 3643: if (token != RPAREN) {
! 3644: norparen:
! 3645: parse_warn (cfile, "right parenthesis expected.");
! 3646: *lose = 1;
! 3647: expression_dereference (expr, MDL);
! 3648: return 0;
! 3649: }
! 3650: break;
! 3651:
! 3652: case SUFFIX:
! 3653: token = next_token (&val, (unsigned *)0, cfile);
! 3654: if (!expression_allocate (expr, MDL))
! 3655: log_fatal ("can't allocate expression");
! 3656: (*expr) -> op = expr_suffix;
! 3657:
! 3658: token = next_token (&val, (unsigned *)0, cfile);
! 3659: if (token != LPAREN)
! 3660: goto nolparen;
! 3661:
! 3662: if (!parse_data_expression (&(*expr) -> data.suffix.expr,
! 3663: cfile, lose))
! 3664: goto nodata;
! 3665:
! 3666: token = next_token (&val, (unsigned *)0, cfile);
! 3667: if (token != COMMA)
! 3668: goto nocomma;
! 3669:
! 3670: if (!parse_numeric_expression (&(*expr) -> data.suffix.len,
! 3671: cfile, lose))
! 3672: goto nonum;
! 3673:
! 3674: token = next_token (&val, (unsigned *)0, cfile);
! 3675: if (token != RPAREN)
! 3676: goto norparen;
! 3677: break;
! 3678:
! 3679: case LCASE:
! 3680: token = next_token(&val, (unsigned *)0, cfile);
! 3681: if (!expression_allocate(expr, MDL))
! 3682: log_fatal ("can't allocate expression");
! 3683: (*expr)->op = expr_lcase;
! 3684:
! 3685: token = next_token(&val, (unsigned *)0, cfile);
! 3686: if (token != LPAREN)
! 3687: goto nolparen;
! 3688:
! 3689: if (!parse_data_expression(&(*expr)->data.lcase, cfile, lose))
! 3690: goto nodata;
! 3691:
! 3692: token = next_token(&val, (unsigned *)0, cfile);
! 3693: if (token != RPAREN)
! 3694: goto norparen;
! 3695: break;
! 3696:
! 3697: case UCASE:
! 3698: token = next_token(&val, (unsigned *)0, cfile);
! 3699: if (!expression_allocate(expr, MDL))
! 3700: log_fatal ("can't allocate expression");
! 3701: (*expr)->op = expr_ucase;
! 3702:
! 3703: token = next_token (&val, (unsigned *)0, cfile);
! 3704: if (token != LPAREN)
! 3705: goto nolparen;
! 3706:
! 3707: if (!parse_data_expression(&(*expr)->data.ucase,
! 3708: cfile, lose))
! 3709: goto nodata;
! 3710:
! 3711: token = next_token(&val, (unsigned *)0, cfile);
! 3712: if (token != RPAREN)
! 3713: goto norparen;
! 3714: break;
! 3715:
! 3716: case CONCAT:
! 3717: token = next_token (&val, (unsigned *)0, cfile);
! 3718: if (!expression_allocate (expr, MDL))
! 3719: log_fatal ("can't allocate expression");
! 3720: (*expr) -> op = expr_concat;
! 3721:
! 3722: token = next_token (&val, (unsigned *)0, cfile);
! 3723: if (token != LPAREN)
! 3724: goto nolparen;
! 3725:
! 3726: if (!parse_data_expression (&(*expr) -> data.concat [0],
! 3727: cfile, lose))
! 3728: goto nodata;
! 3729:
! 3730: token = next_token (&val, (unsigned *)0, cfile);
! 3731: if (token != COMMA)
! 3732: goto nocomma;
! 3733:
! 3734: concat_another:
! 3735: if (!parse_data_expression (&(*expr) -> data.concat [1],
! 3736: cfile, lose))
! 3737: goto nodata;
! 3738:
! 3739: token = next_token (&val, (unsigned *)0, cfile);
! 3740:
! 3741: if (token == COMMA) {
! 3742: nexp = (struct expression *)0;
! 3743: if (!expression_allocate (&nexp, MDL))
! 3744: log_fatal ("can't allocate at CONCAT2");
! 3745: nexp -> op = expr_concat;
! 3746: expression_reference (&nexp -> data.concat [0],
! 3747: *expr, MDL);
! 3748: expression_dereference (expr, MDL);
! 3749: expression_reference (expr, nexp, MDL);
! 3750: expression_dereference (&nexp, MDL);
! 3751: goto concat_another;
! 3752: }
! 3753:
! 3754: if (token != RPAREN)
! 3755: goto norparen;
! 3756: break;
! 3757:
! 3758: case BINARY_TO_ASCII:
! 3759: token = next_token (&val, (unsigned *)0, cfile);
! 3760: if (!expression_allocate (expr, MDL))
! 3761: log_fatal ("can't allocate expression");
! 3762: (*expr) -> op = expr_binary_to_ascii;
! 3763:
! 3764: token = next_token (&val, (unsigned *)0, cfile);
! 3765: if (token != LPAREN)
! 3766: goto nolparen;
! 3767:
! 3768: if (!parse_numeric_expression (&(*expr) -> data.b2a.base,
! 3769: cfile, lose))
! 3770: goto nodata;
! 3771:
! 3772: token = next_token (&val, (unsigned *)0, cfile);
! 3773: if (token != COMMA)
! 3774: goto nocomma;
! 3775:
! 3776: if (!parse_numeric_expression (&(*expr) -> data.b2a.width,
! 3777: cfile, lose))
! 3778: goto nodata;
! 3779:
! 3780: token = next_token (&val, (unsigned *)0, cfile);
! 3781: if (token != COMMA)
! 3782: goto nocomma;
! 3783:
! 3784: if (!parse_data_expression (&(*expr) -> data.b2a.separator,
! 3785: cfile, lose))
! 3786: goto nodata;
! 3787:
! 3788: token = next_token (&val, (unsigned *)0, cfile);
! 3789: if (token != COMMA)
! 3790: goto nocomma;
! 3791:
! 3792: if (!parse_data_expression (&(*expr) -> data.b2a.buffer,
! 3793: cfile, lose))
! 3794: goto nodata;
! 3795:
! 3796: token = next_token (&val, (unsigned *)0, cfile);
! 3797: if (token != RPAREN)
! 3798: goto norparen;
! 3799: break;
! 3800:
! 3801: case REVERSE:
! 3802: token = next_token (&val, (unsigned *)0, cfile);
! 3803: if (!expression_allocate (expr, MDL))
! 3804: log_fatal ("can't allocate expression");
! 3805: (*expr) -> op = expr_reverse;
! 3806:
! 3807: token = next_token (&val, (unsigned *)0, cfile);
! 3808: if (token != LPAREN)
! 3809: goto nolparen;
! 3810:
! 3811: if (!(parse_numeric_expression
! 3812: (&(*expr) -> data.reverse.width, cfile, lose)))
! 3813: goto nodata;
! 3814:
! 3815: token = next_token (&val, (unsigned *)0, cfile);
! 3816: if (token != COMMA)
! 3817: goto nocomma;
! 3818:
! 3819: if (!(parse_data_expression
! 3820: (&(*expr) -> data.reverse.buffer, cfile, lose)))
! 3821: goto nodata;
! 3822:
! 3823: token = next_token (&val, (unsigned *)0, cfile);
! 3824: if (token != RPAREN)
! 3825: goto norparen;
! 3826: break;
! 3827:
! 3828: case PICK:
! 3829: /* pick (a, b, c) actually produces an internal representation
! 3830: that looks like pick (a, pick (b, pick (c, nil))). */
! 3831: token = next_token (&val, (unsigned *)0, cfile);
! 3832: if (!(expression_allocate (expr, MDL)))
! 3833: log_fatal ("can't allocate expression");
! 3834:
! 3835: token = next_token (&val, (unsigned *)0, cfile);
! 3836: if (token != LPAREN)
! 3837: goto nolparen;
! 3838:
! 3839: nexp = (struct expression *)0;
! 3840: expression_reference (&nexp, *expr, MDL);
! 3841: do {
! 3842: nexp -> op = expr_pick_first_value;
! 3843: if (!(parse_data_expression
! 3844: (&nexp -> data.pick_first_value.car,
! 3845: cfile, lose)))
! 3846: goto nodata;
! 3847:
! 3848: token = next_token (&val, (unsigned *)0, cfile);
! 3849: if (token == COMMA) {
! 3850: struct expression *foo = (struct expression *)0;
! 3851: if (!expression_allocate (&foo, MDL))
! 3852: log_fatal ("can't allocate expr");
! 3853: expression_reference
! 3854: (&nexp -> data.pick_first_value.cdr, foo, MDL);
! 3855: expression_dereference (&nexp, MDL);
! 3856: expression_reference (&nexp, foo, MDL);
! 3857: expression_dereference (&foo, MDL);
! 3858: }
! 3859: } while (token == COMMA);
! 3860: expression_dereference (&nexp, MDL);
! 3861:
! 3862: if (token != RPAREN)
! 3863: goto norparen;
! 3864: break;
! 3865:
! 3866: /* dns-update and dns-delete are present for historical
! 3867: purposes, but are deprecated in favor of ns-update
! 3868: in combination with update, delete, exists and not
! 3869: exists. */
! 3870: case DNS_UPDATE:
! 3871: case DNS_DELETE:
! 3872: #if !defined (NSUPDATE)
! 3873: parse_warn (cfile,
! 3874: "Please rebuild dhcpd with --with-nsupdate.");
! 3875: #endif
! 3876: token = next_token (&val, (unsigned *)0, cfile);
! 3877: if (token == DNS_UPDATE)
! 3878: opcode = expr_ns_add;
! 3879: else
! 3880: opcode = expr_ns_delete;
! 3881:
! 3882: token = next_token (&val, (unsigned *)0, cfile);
! 3883: if (token != LPAREN)
! 3884: goto nolparen;
! 3885:
! 3886: token = next_token (&val, (unsigned *)0, cfile);
! 3887: if (token != STRING) {
! 3888: parse_warn (cfile,
! 3889: "parse_expression: expecting string.");
! 3890: badnsupdate:
! 3891: skip_to_semi (cfile);
! 3892: *lose = 1;
! 3893: return 0;
! 3894: }
! 3895:
! 3896: if (!strcasecmp (val, "a"))
! 3897: u = T_A;
! 3898: else if (!strcasecmp (val, "aaaa"))
! 3899: u = T_AAAA;
! 3900: else if (!strcasecmp (val, "ptr"))
! 3901: u = T_PTR;
! 3902: else if (!strcasecmp (val, "mx"))
! 3903: u = T_MX;
! 3904: else if (!strcasecmp (val, "cname"))
! 3905: u = T_CNAME;
! 3906: else if (!strcasecmp (val, "TXT"))
! 3907: u = T_TXT;
! 3908: else {
! 3909: parse_warn (cfile, "unexpected rrtype: %s", val);
! 3910: goto badnsupdate;
! 3911: }
! 3912:
! 3913: s = (opcode == expr_ns_add
! 3914: ? "old-dns-update"
! 3915: : "old-dns-delete");
! 3916: cptr = dmalloc (strlen (s) + 1, MDL);
! 3917: if (!cptr)
! 3918: log_fatal ("can't allocate name for %s", s);
! 3919: strcpy (cptr, s);
! 3920: if (!expression_allocate (expr, MDL))
! 3921: log_fatal ("can't allocate expression");
! 3922: (*expr) -> op = expr_funcall;
! 3923: (*expr) -> data.funcall.name = cptr;
! 3924:
! 3925: /* Fake up a function call. */
! 3926: ep = &(*expr) -> data.funcall.arglist;
! 3927: if (!expression_allocate (ep, MDL))
! 3928: log_fatal ("can't allocate expression");
! 3929: (*ep) -> op = expr_arg;
! 3930: if (!make_const_int (&(*ep) -> data.arg.val, u))
! 3931: log_fatal ("can't allocate rrtype value.");
! 3932:
! 3933: token = next_token (&val, (unsigned *)0, cfile);
! 3934: if (token != COMMA)
! 3935: goto nocomma;
! 3936: ep = &((*ep) -> data.arg.next);
! 3937: if (!expression_allocate (ep, MDL))
! 3938: log_fatal ("can't allocate expression");
! 3939: (*ep) -> op = expr_arg;
! 3940: if (!(parse_data_expression (&(*ep) -> data.arg.val,
! 3941: cfile, lose)))
! 3942: goto nodata;
! 3943:
! 3944: token = next_token (&val, (unsigned *)0, cfile);
! 3945: if (token != COMMA)
! 3946: goto nocomma;
! 3947:
! 3948: ep = &((*ep) -> data.arg.next);
! 3949: if (!expression_allocate (ep, MDL))
! 3950: log_fatal ("can't allocate expression");
! 3951: (*ep) -> op = expr_arg;
! 3952: if (!(parse_data_expression (&(*ep) -> data.arg.val,
! 3953: cfile, lose)))
! 3954: goto nodata;
! 3955:
! 3956: if (opcode == expr_ns_add) {
! 3957: token = next_token (&val, (unsigned *)0, cfile);
! 3958: if (token != COMMA)
! 3959: goto nocomma;
! 3960:
! 3961: ep = &((*ep) -> data.arg.next);
! 3962: if (!expression_allocate (ep, MDL))
! 3963: log_fatal ("can't allocate expression");
! 3964: (*ep) -> op = expr_arg;
! 3965: if (!(parse_numeric_expression (&(*ep) -> data.arg.val,
! 3966: cfile, lose))) {
! 3967: parse_warn (cfile,
! 3968: "expecting numeric expression.");
! 3969: goto badnsupdate;
! 3970: }
! 3971: }
! 3972:
! 3973: token = next_token (&val, (unsigned *)0, cfile);
! 3974: if (token != RPAREN)
! 3975: goto norparen;
! 3976: break;
! 3977:
! 3978: case NS_UPDATE:
! 3979: #if !defined (NSUPDATE)
! 3980: parse_warn (cfile,
! 3981: "Please rebuild dhcpd with --with-nsupdate.");
! 3982: #endif
! 3983: token = next_token (&val, (unsigned *)0, cfile);
! 3984: if (!expression_allocate (expr, MDL))
! 3985: log_fatal ("can't allocate expression");
! 3986:
! 3987: token = next_token (&val, (unsigned *)0, cfile);
! 3988: if (token != LPAREN)
! 3989: goto nolparen;
! 3990:
! 3991: nexp = *expr;
! 3992: do {
! 3993: nexp -> op = expr_dns_transaction;
! 3994: if (!(parse_dns_expression
! 3995: (&nexp -> data.dns_transaction.car,
! 3996: cfile, lose)))
! 3997: {
! 3998: if (!*lose)
! 3999: parse_warn
! 4000: (cfile,
! 4001: "expecting dns expression.");
! 4002: expression_dereference (expr, MDL);
! 4003: *lose = 1;
! 4004: return 0;
! 4005: }
! 4006:
! 4007: token = next_token (&val, (unsigned *)0, cfile);
! 4008:
! 4009: if (token == COMMA) {
! 4010: if (!(expression_allocate
! 4011: (&nexp -> data.dns_transaction.cdr,
! 4012: MDL)))
! 4013: log_fatal
! 4014: ("can't allocate expression");
! 4015: nexp = nexp -> data.dns_transaction.cdr;
! 4016: }
! 4017: } while (token == COMMA);
! 4018:
! 4019: if (token != RPAREN)
! 4020: goto norparen;
! 4021: break;
! 4022:
! 4023: /* NOT EXISTS is special cased above... */
! 4024: not_exists:
! 4025: token = peek_token (&val, (unsigned *)0, cfile);
! 4026: if (token != EXISTS) {
! 4027: parse_warn (cfile, "expecting DNS prerequisite.");
! 4028: *lose = 1;
! 4029: return 0;
! 4030: }
! 4031: opcode = expr_ns_not_exists;
! 4032: goto nsupdatecode;
! 4033: case TOKEN_ADD:
! 4034: opcode = expr_ns_add;
! 4035: goto nsupdatecode;
! 4036: case TOKEN_DELETE:
! 4037: opcode = expr_ns_delete;
! 4038: goto nsupdatecode;
! 4039: ns_exists:
! 4040: opcode = expr_ns_exists;
! 4041: nsupdatecode:
! 4042: token = next_token (&val, (unsigned *)0, cfile);
! 4043:
! 4044: #if !defined (NSUPDATE)
! 4045: parse_warn (cfile,
! 4046: "Please rebuild dhcpd with --with-nsupdate.");
! 4047: #endif
! 4048: if (!expression_allocate (expr, MDL))
! 4049: log_fatal ("can't allocate expression");
! 4050: (*expr) -> op = opcode;
! 4051:
! 4052: token = next_token (&val, (unsigned *)0, cfile);
! 4053: if (token != LPAREN)
! 4054: goto nolparen;
! 4055:
! 4056: token = next_token (&val, (unsigned *)0, cfile);
! 4057: if (!is_identifier (token) && token != NUMBER) {
! 4058: parse_warn (cfile, "expecting identifier or number.");
! 4059: badnsop:
! 4060: expression_dereference (expr, MDL);
! 4061: skip_to_semi (cfile);
! 4062: *lose = 1;
! 4063: return 0;
! 4064: }
! 4065:
! 4066: if (token == NUMBER)
! 4067: (*expr) -> data.ns_add.rrclass = atoi (val);
! 4068: else if (!strcasecmp (val, "in"))
! 4069: (*expr) -> data.ns_add.rrclass = C_IN;
! 4070: else if (!strcasecmp (val, "chaos"))
! 4071: (*expr) -> data.ns_add.rrclass = C_CHAOS;
! 4072: else if (!strcasecmp (val, "hs"))
! 4073: (*expr) -> data.ns_add.rrclass = C_HS;
! 4074: else {
! 4075: parse_warn (cfile, "unexpected rrclass: %s", val);
! 4076: goto badnsop;
! 4077: }
! 4078:
! 4079: token = next_token (&val, (unsigned *)0, cfile);
! 4080: if (token != COMMA)
! 4081: goto nocomma;
! 4082:
! 4083: token = next_token (&val, (unsigned *)0, cfile);
! 4084: if (!is_identifier (token) && token != NUMBER) {
! 4085: parse_warn (cfile, "expecting identifier or number.");
! 4086: goto badnsop;
! 4087: }
! 4088:
! 4089: if (token == NUMBER)
! 4090: (*expr) -> data.ns_add.rrtype = atoi (val);
! 4091: else if (!strcasecmp (val, "a"))
! 4092: (*expr) -> data.ns_add.rrtype = T_A;
! 4093: else if (!strcasecmp (val, "aaaa"))
! 4094: (*expr) -> data.ns_add.rrtype = T_AAAA;
! 4095: else if (!strcasecmp (val, "ptr"))
! 4096: (*expr) -> data.ns_add.rrtype = T_PTR;
! 4097: else if (!strcasecmp (val, "mx"))
! 4098: (*expr) -> data.ns_add.rrtype = T_MX;
! 4099: else if (!strcasecmp (val, "cname"))
! 4100: (*expr) -> data.ns_add.rrtype = T_CNAME;
! 4101: else if (!strcasecmp (val, "TXT"))
! 4102: (*expr) -> data.ns_add.rrtype = T_TXT;
! 4103: else {
! 4104: parse_warn (cfile, "unexpected rrtype: %s", val);
! 4105: goto badnsop;
! 4106: }
! 4107:
! 4108: token = next_token (&val, (unsigned *)0, cfile);
! 4109: if (token != COMMA)
! 4110: goto nocomma;
! 4111:
! 4112: if (!(parse_data_expression
! 4113: (&(*expr) -> data.ns_add.rrname, cfile, lose)))
! 4114: goto nodata;
! 4115:
! 4116: token = next_token (&val, (unsigned *)0, cfile);
! 4117: if (token != COMMA)
! 4118: goto nocomma;
! 4119:
! 4120: if (!(parse_data_expression
! 4121: (&(*expr) -> data.ns_add.rrdata, cfile, lose)))
! 4122: goto nodata;
! 4123:
! 4124: if (opcode == expr_ns_add) {
! 4125: token = next_token (&val, (unsigned *)0, cfile);
! 4126: if (token != COMMA)
! 4127: goto nocomma;
! 4128:
! 4129: if (!(parse_numeric_expression
! 4130: (&(*expr) -> data.ns_add.ttl, cfile,
! 4131: lose))) {
! 4132: if (!*lose)
! 4133: parse_warn (cfile,
! 4134: "expecting numeric expression.");
! 4135: goto badnsupdate;
! 4136: }
! 4137: }
! 4138:
! 4139: token = next_token (&val, (unsigned *)0, cfile);
! 4140: if (token != RPAREN)
! 4141: goto norparen;
! 4142: break;
! 4143:
! 4144: case OPTION:
! 4145: case CONFIG_OPTION:
! 4146: if (!expression_allocate (expr, MDL))
! 4147: log_fatal ("can't allocate expression");
! 4148: (*expr) -> op = (token == OPTION
! 4149: ? expr_option
! 4150: : expr_config_option);
! 4151: token = next_token (&val, (unsigned *)0, cfile);
! 4152: known = 0;
! 4153: /* Pass reference directly to expression structure. */
! 4154: status = parse_option_name(cfile, 0, &known,
! 4155: &(*expr)->data.option);
! 4156: if (status != ISC_R_SUCCESS ||
! 4157: (*expr)->data.option == NULL) {
! 4158: *lose = 1;
! 4159: expression_dereference (expr, MDL);
! 4160: return 0;
! 4161: }
! 4162: break;
! 4163:
! 4164: case HARDWARE:
! 4165: token = next_token (&val, (unsigned *)0, cfile);
! 4166: if (!expression_allocate (expr, MDL))
! 4167: log_fatal ("can't allocate expression");
! 4168: (*expr) -> op = expr_hardware;
! 4169: break;
! 4170:
! 4171: case LEASED_ADDRESS:
! 4172: token = next_token (&val, (unsigned *)0, cfile);
! 4173: if (!expression_allocate (expr, MDL))
! 4174: log_fatal ("can't allocate expression");
! 4175: (*expr) -> op = expr_leased_address;
! 4176: break;
! 4177:
! 4178: case CLIENT_STATE:
! 4179: token = next_token (&val, (unsigned *)0, cfile);
! 4180: if (!expression_allocate (expr, MDL))
! 4181: log_fatal ("can't allocate expression");
! 4182: (*expr) -> op = expr_client_state;
! 4183: break;
! 4184:
! 4185: case FILENAME:
! 4186: token = next_token (&val, (unsigned *)0, cfile);
! 4187: if (!expression_allocate (expr, MDL))
! 4188: log_fatal ("can't allocate expression");
! 4189: (*expr) -> op = expr_filename;
! 4190: break;
! 4191:
! 4192: case SERVER_NAME:
! 4193: token = next_token (&val, (unsigned *)0, cfile);
! 4194: if (!expression_allocate (expr, MDL))
! 4195: log_fatal ("can't allocate expression");
! 4196: (*expr) -> op = expr_sname;
! 4197: break;
! 4198:
! 4199: case LEASE_TIME:
! 4200: token = next_token (&val, (unsigned *)0, cfile);
! 4201: if (!expression_allocate (expr, MDL))
! 4202: log_fatal ("can't allocate expression");
! 4203: (*expr) -> op = expr_lease_time;
! 4204: break;
! 4205:
! 4206: case TOKEN_NULL:
! 4207: token = next_token (&val, (unsigned *)0, cfile);
! 4208: if (!expression_allocate (expr, MDL))
! 4209: log_fatal ("can't allocate expression");
! 4210: (*expr) -> op = expr_null;
! 4211: break;
! 4212:
! 4213: case HOST_DECL_NAME:
! 4214: token = next_token (&val, (unsigned *)0, cfile);
! 4215: if (!expression_allocate (expr, MDL))
! 4216: log_fatal ("can't allocate expression");
! 4217: (*expr) -> op = expr_host_decl_name;
! 4218: break;
! 4219:
! 4220: case UPDATED_DNS_RR:
! 4221: token = next_token (&val, (unsigned *)0, cfile);
! 4222:
! 4223: token = next_token (&val, (unsigned *)0, cfile);
! 4224: if (token != LPAREN)
! 4225: goto nolparen;
! 4226:
! 4227: token = next_token (&val, (unsigned *)0, cfile);
! 4228: if (token != STRING) {
! 4229: parse_warn (cfile, "expecting string.");
! 4230: bad_rrtype:
! 4231: *lose = 1;
! 4232: return 0;
! 4233: }
! 4234: if (!strcasecmp (val, "a"))
! 4235: s = "ddns-fwd-name";
! 4236: else if (!strcasecmp (val, "ptr"))
! 4237: s = "ddns-rev-name";
! 4238: else {
! 4239: parse_warn (cfile, "invalid DNS rrtype: %s", val);
! 4240: goto bad_rrtype;
! 4241: }
! 4242:
! 4243: token = next_token (&val, (unsigned *)0, cfile);
! 4244: if (token != RPAREN)
! 4245: goto norparen;
! 4246:
! 4247: if (!expression_allocate (expr, MDL))
! 4248: log_fatal ("can't allocate expression");
! 4249: (*expr) -> op = expr_variable_reference;
! 4250: (*expr) -> data.variable =
! 4251: dmalloc (strlen (s) + 1, MDL);
! 4252: if (!(*expr) -> data.variable)
! 4253: log_fatal ("can't allocate variable name.");
! 4254: strcpy ((*expr) -> data.variable, s);
! 4255: break;
! 4256:
! 4257: case PACKET:
! 4258: token = next_token (&val, (unsigned *)0, cfile);
! 4259: if (!expression_allocate (expr, MDL))
! 4260: log_fatal ("can't allocate expression");
! 4261: (*expr) -> op = expr_packet;
! 4262:
! 4263: token = next_token (&val, (unsigned *)0, cfile);
! 4264: if (token != LPAREN)
! 4265: goto nolparen;
! 4266:
! 4267: if (!parse_numeric_expression (&(*expr) -> data.packet.offset,
! 4268: cfile, lose))
! 4269: goto nonum;
! 4270:
! 4271: token = next_token (&val, (unsigned *)0, cfile);
! 4272: if (token != COMMA)
! 4273: goto nocomma;
! 4274:
! 4275: if (!parse_numeric_expression (&(*expr) -> data.packet.len,
! 4276: cfile, lose))
! 4277: goto nonum;
! 4278:
! 4279: token = next_token (&val, (unsigned *)0, cfile);
! 4280: if (token != RPAREN)
! 4281: goto norparen;
! 4282: break;
! 4283:
! 4284: case STRING:
! 4285: token = next_token (&val, &len, cfile);
! 4286: if (!make_const_data (expr, (const unsigned char *)val,
! 4287: len, 1, 1, MDL))
! 4288: log_fatal ("can't make constant string expression.");
! 4289: break;
! 4290:
! 4291: case EXTRACT_INT:
! 4292: token = next_token (&val, (unsigned *)0, cfile);
! 4293: token = next_token (&val, (unsigned *)0, cfile);
! 4294: if (token != LPAREN) {
! 4295: parse_warn (cfile, "left parenthesis expected.");
! 4296: *lose = 1;
! 4297: return 0;
! 4298: }
! 4299:
! 4300: if (!expression_allocate (expr, MDL))
! 4301: log_fatal ("can't allocate expression");
! 4302:
! 4303: if (!parse_data_expression (&(*expr) -> data.extract_int,
! 4304: cfile, lose)) {
! 4305: if (!*lose) {
! 4306: parse_warn (cfile,
! 4307: "expecting data expression.");
! 4308: skip_to_semi (cfile);
! 4309: *lose = 1;
! 4310: }
! 4311: expression_dereference (expr, MDL);
! 4312: return 0;
! 4313: }
! 4314:
! 4315: token = next_token (&val, (unsigned *)0, cfile);
! 4316: if (token != COMMA) {
! 4317: parse_warn (cfile, "comma expected.");
! 4318: *lose = 1;
! 4319: expression_dereference (expr, MDL);
! 4320: return 0;
! 4321: }
! 4322:
! 4323: token = next_token (&val, (unsigned *)0, cfile);
! 4324: if (token != NUMBER) {
! 4325: parse_warn (cfile, "number expected.");
! 4326: *lose = 1;
! 4327: expression_dereference (expr, MDL);
! 4328: return 0;
! 4329: }
! 4330: switch (atoi (val)) {
! 4331: case 8:
! 4332: (*expr) -> op = expr_extract_int8;
! 4333: break;
! 4334:
! 4335: case 16:
! 4336: (*expr) -> op = expr_extract_int16;
! 4337: break;
! 4338:
! 4339: case 32:
! 4340: (*expr) -> op = expr_extract_int32;
! 4341: break;
! 4342:
! 4343: default:
! 4344: parse_warn (cfile,
! 4345: "unsupported integer size %d", atoi (val));
! 4346: *lose = 1;
! 4347: skip_to_semi (cfile);
! 4348: expression_dereference (expr, MDL);
! 4349: return 0;
! 4350: }
! 4351:
! 4352: token = next_token (&val, (unsigned *)0, cfile);
! 4353: if (token != RPAREN) {
! 4354: parse_warn (cfile, "right parenthesis expected.");
! 4355: *lose = 1;
! 4356: expression_dereference (expr, MDL);
! 4357: return 0;
! 4358: }
! 4359: break;
! 4360:
! 4361: case ENCODE_INT:
! 4362: token = next_token (&val, (unsigned *)0, cfile);
! 4363: token = next_token (&val, (unsigned *)0, cfile);
! 4364: if (token != LPAREN) {
! 4365: parse_warn (cfile, "left parenthesis expected.");
! 4366: *lose = 1;
! 4367: return 0;
! 4368: }
! 4369:
! 4370: if (!expression_allocate (expr, MDL))
! 4371: log_fatal ("can't allocate expression");
! 4372:
! 4373: if (!parse_numeric_expression (&(*expr) -> data.encode_int,
! 4374: cfile, lose)) {
! 4375: parse_warn (cfile, "expecting numeric expression.");
! 4376: skip_to_semi (cfile);
! 4377: *lose = 1;
! 4378: expression_dereference (expr, MDL);
! 4379: return 0;
! 4380: }
! 4381:
! 4382: token = next_token (&val, (unsigned *)0, cfile);
! 4383: if (token != COMMA) {
! 4384: parse_warn (cfile, "comma expected.");
! 4385: *lose = 1;
! 4386: expression_dereference (expr, MDL);
! 4387: return 0;
! 4388: }
! 4389:
! 4390: token = next_token (&val, (unsigned *)0, cfile);
! 4391: if (token != NUMBER) {
! 4392: parse_warn (cfile, "number expected.");
! 4393: *lose = 1;
! 4394: expression_dereference (expr, MDL);
! 4395: return 0;
! 4396: }
! 4397: switch (atoi (val)) {
! 4398: case 8:
! 4399: (*expr) -> op = expr_encode_int8;
! 4400: break;
! 4401:
! 4402: case 16:
! 4403: (*expr) -> op = expr_encode_int16;
! 4404: break;
! 4405:
! 4406: case 32:
! 4407: (*expr) -> op = expr_encode_int32;
! 4408: break;
! 4409:
! 4410: default:
! 4411: parse_warn (cfile,
! 4412: "unsupported integer size %d", atoi (val));
! 4413: *lose = 1;
! 4414: skip_to_semi (cfile);
! 4415: expression_dereference (expr, MDL);
! 4416: return 0;
! 4417: }
! 4418:
! 4419: token = next_token (&val, (unsigned *)0, cfile);
! 4420: if (token != RPAREN) {
! 4421: parse_warn (cfile, "right parenthesis expected.");
! 4422: *lose = 1;
! 4423: expression_dereference (expr, MDL);
! 4424: return 0;
! 4425: }
! 4426: break;
! 4427:
! 4428: case NUMBER:
! 4429: /* If we're in a numeric context, this should just be a
! 4430: number, by itself. */
! 4431: if (context == context_numeric ||
! 4432: context == context_data_or_numeric) {
! 4433: next_token (&val, (unsigned *)0, cfile);
! 4434: if (!expression_allocate (expr, MDL))
! 4435: log_fatal ("can't allocate expression");
! 4436: (*expr) -> op = expr_const_int;
! 4437: (*expr) -> data.const_int = atoi (val);
! 4438: break;
! 4439: }
! 4440:
! 4441: case NUMBER_OR_NAME:
! 4442: if (!expression_allocate (expr, MDL))
! 4443: log_fatal ("can't allocate expression");
! 4444:
! 4445: (*expr) -> op = expr_const_data;
! 4446: if (!parse_cshl (&(*expr) -> data.const_data, cfile)) {
! 4447: expression_dereference (expr, MDL);
! 4448: return 0;
! 4449: }
! 4450: break;
! 4451:
! 4452: case NS_FORMERR:
! 4453: known = FORMERR;
! 4454: goto ns_const;
! 4455: ns_const:
! 4456: token = next_token (&val, (unsigned *)0, cfile);
! 4457: if (!expression_allocate (expr, MDL))
! 4458: log_fatal ("can't allocate expression");
! 4459: (*expr) -> op = expr_const_int;
! 4460: (*expr) -> data.const_int = known;
! 4461: break;
! 4462:
! 4463: case NS_NOERROR:
! 4464: known = ISC_R_SUCCESS;
! 4465: goto ns_const;
! 4466:
! 4467: case NS_NOTAUTH:
! 4468: known = ISC_R_NOTAUTH;
! 4469: goto ns_const;
! 4470:
! 4471: case NS_NOTIMP:
! 4472: known = ISC_R_NOTIMPLEMENTED;
! 4473: goto ns_const;
! 4474:
! 4475: case NS_NOTZONE:
! 4476: known = ISC_R_NOTZONE;
! 4477: goto ns_const;
! 4478:
! 4479: case NS_NXDOMAIN:
! 4480: known = ISC_R_NXDOMAIN;
! 4481: goto ns_const;
! 4482:
! 4483: case NS_NXRRSET:
! 4484: known = ISC_R_NXRRSET;
! 4485: goto ns_const;
! 4486:
! 4487: case NS_REFUSED:
! 4488: known = ISC_R_REFUSED;
! 4489: goto ns_const;
! 4490:
! 4491: case NS_SERVFAIL:
! 4492: known = ISC_R_SERVFAIL;
! 4493: goto ns_const;
! 4494:
! 4495: case NS_YXDOMAIN:
! 4496: known = ISC_R_YXDOMAIN;
! 4497: goto ns_const;
! 4498:
! 4499: case NS_YXRRSET:
! 4500: known = ISC_R_YXRRSET;
! 4501: goto ns_const;
! 4502:
! 4503: case BOOTING:
! 4504: known = S_INIT;
! 4505: goto ns_const;
! 4506:
! 4507: case REBOOT:
! 4508: known = S_REBOOTING;
! 4509: goto ns_const;
! 4510:
! 4511: case SELECT:
! 4512: known = S_SELECTING;
! 4513: goto ns_const;
! 4514:
! 4515: case REQUEST:
! 4516: known = S_REQUESTING;
! 4517: goto ns_const;
! 4518:
! 4519: case BOUND:
! 4520: known = S_BOUND;
! 4521: goto ns_const;
! 4522:
! 4523: case RENEW:
! 4524: known = S_RENEWING;
! 4525: goto ns_const;
! 4526:
! 4527: case REBIND:
! 4528: known = S_REBINDING;
! 4529: goto ns_const;
! 4530:
! 4531: case DEFINED:
! 4532: token = next_token (&val, (unsigned *)0, cfile);
! 4533: token = next_token (&val, (unsigned *)0, cfile);
! 4534: if (token != LPAREN)
! 4535: goto nolparen;
! 4536:
! 4537: token = next_token (&val, (unsigned *)0, cfile);
! 4538: if (token != NAME && token != NUMBER_OR_NAME) {
! 4539: parse_warn (cfile, "%s can't be a variable name", val);
! 4540: skip_to_semi (cfile);
! 4541: *lose = 1;
! 4542: return 0;
! 4543: }
! 4544:
! 4545: if (!expression_allocate (expr, MDL))
! 4546: log_fatal ("can't allocate expression");
! 4547: (*expr) -> op = expr_variable_exists;
! 4548: (*expr) -> data.variable = dmalloc (strlen (val) + 1, MDL);
! 4549: if (!(*expr)->data.variable)
! 4550: log_fatal ("can't allocate variable name");
! 4551: strcpy ((*expr) -> data.variable, val);
! 4552: token = next_token (&val, (unsigned *)0, cfile);
! 4553: if (token != RPAREN)
! 4554: goto norparen;
! 4555: break;
! 4556:
! 4557: case GETHOSTBYNAME:
! 4558: token = next_token(&val, NULL, cfile);
! 4559:
! 4560: token = next_token(NULL, NULL, cfile);
! 4561: if (token != LPAREN)
! 4562: goto nolparen;
! 4563:
! 4564: /* The argument is a quoted string. */
! 4565: token = next_token(&val, NULL, cfile);
! 4566: if (token != STRING) {
! 4567: parse_warn(cfile, "Expecting quoted literal: "
! 4568: "\"foo.example.com\"");
! 4569: skip_to_semi(cfile);
! 4570: *lose = 1;
! 4571: return 0;
! 4572: }
! 4573: if (!make_host_lookup(expr, val))
! 4574: log_fatal("Error creating gethostbyname() internal "
! 4575: "record. (%s:%d)", MDL);
! 4576:
! 4577: token = next_token(NULL, NULL, cfile);
! 4578: if (token != RPAREN)
! 4579: goto norparen;
! 4580: break;
! 4581:
! 4582: /* Not a valid start to an expression... */
! 4583: default:
! 4584: if (token != NAME && token != NUMBER_OR_NAME)
! 4585: return 0;
! 4586:
! 4587: token = next_token (&val, (unsigned *)0, cfile);
! 4588:
! 4589: /* Save the name of the variable being referenced. */
! 4590: cptr = dmalloc (strlen (val) + 1, MDL);
! 4591: if (!cptr)
! 4592: log_fatal ("can't allocate variable name");
! 4593: strcpy (cptr, val);
! 4594:
! 4595: /* Simple variable reference, as far as we can tell. */
! 4596: token = peek_token (&val, (unsigned *)0, cfile);
! 4597: if (token != LPAREN) {
! 4598: if (!expression_allocate (expr, MDL))
! 4599: log_fatal ("can't allocate expression");
! 4600: (*expr) -> op = expr_variable_reference;
! 4601: (*expr) -> data.variable = cptr;
! 4602: break;
! 4603: }
! 4604:
! 4605: token = next_token (&val, (unsigned *)0, cfile);
! 4606: if (!expression_allocate (expr, MDL))
! 4607: log_fatal ("can't allocate expression");
! 4608: (*expr) -> op = expr_funcall;
! 4609: (*expr) -> data.funcall.name = cptr;
! 4610:
! 4611: /* Now parse the argument list. */
! 4612: ep = &(*expr) -> data.funcall.arglist;
! 4613: do {
! 4614: if (!expression_allocate (ep, MDL))
! 4615: log_fatal ("can't allocate expression");
! 4616: (*ep) -> op = expr_arg;
! 4617: if (!parse_expression (&(*ep) -> data.arg.val,
! 4618: cfile, lose, context_any,
! 4619: (struct expression **)0,
! 4620: expr_none)) {
! 4621: if (!*lose) {
! 4622: parse_warn (cfile,
! 4623: "expecting expression.");
! 4624: *lose = 1;
! 4625: }
! 4626: skip_to_semi (cfile);
! 4627: expression_dereference (expr, MDL);
! 4628: return 0;
! 4629: }
! 4630: ep = &((*ep) -> data.arg.next);
! 4631: token = next_token (&val, (unsigned *)0, cfile);
! 4632: } while (token == COMMA);
! 4633: if (token != RPAREN) {
! 4634: parse_warn (cfile, "Right parenthesis expected.");
! 4635: skip_to_semi (cfile);
! 4636: *lose = 1;
! 4637: expression_dereference (expr, MDL);
! 4638: return 0;
! 4639: }
! 4640: break;
! 4641: }
! 4642: return 1;
! 4643: }
! 4644:
! 4645: /* Parse an expression. */
! 4646:
! 4647: int parse_expression (expr, cfile, lose, context, plhs, binop)
! 4648: struct expression **expr;
! 4649: struct parse *cfile;
! 4650: int *lose;
! 4651: enum expression_context context;
! 4652: struct expression **plhs;
! 4653: enum expr_op binop;
! 4654: {
! 4655: enum dhcp_token token;
! 4656: const char *val;
! 4657: struct expression *rhs = (struct expression *)0, *tmp;
! 4658: struct expression *lhs = (struct expression *)0;
! 4659: enum expr_op next_op;
! 4660: enum expression_context
! 4661: lhs_context = context_any,
! 4662: rhs_context = context_any;
! 4663:
! 4664: /* Consume the left hand side we were passed. */
! 4665: if (plhs) {
! 4666: expression_reference (&lhs, *plhs, MDL);
! 4667: expression_dereference (plhs, MDL);
! 4668: }
! 4669:
! 4670: new_rhs:
! 4671: if (!parse_non_binary (&rhs, cfile, lose, context)) {
! 4672: /* If we already have a left-hand side, then it's not
! 4673: okay for there not to be a right-hand side here, so
! 4674: we need to flag it as an error. */
! 4675: if (lhs) {
! 4676: if (!*lose) {
! 4677: parse_warn (cfile,
! 4678: "expecting right-hand side.");
! 4679: *lose = 1;
! 4680: skip_to_semi (cfile);
! 4681: }
! 4682: expression_dereference (&lhs, MDL);
! 4683: }
! 4684: return 0;
! 4685: }
! 4686:
! 4687: /* At this point, rhs contains either an entire subexpression,
! 4688: or at least a left-hand-side. If we do not see a binary token
! 4689: as the next token, we're done with the expression. */
! 4690:
! 4691: token = peek_token (&val, (unsigned *)0, cfile);
! 4692: switch (token) {
! 4693: case BANG:
! 4694: token = next_token (&val, (unsigned *)0, cfile);
! 4695: token = peek_token (&val, (unsigned *)0, cfile);
! 4696: if (token != EQUAL) {
! 4697: parse_warn (cfile, "! in boolean context without =");
! 4698: *lose = 1;
! 4699: skip_to_semi (cfile);
! 4700: if (lhs)
! 4701: expression_dereference (&lhs, MDL);
! 4702: return 0;
! 4703: }
! 4704: next_op = expr_not_equal;
! 4705: context = expression_context (rhs);
! 4706: break;
! 4707:
! 4708: case EQUAL:
! 4709: next_op = expr_equal;
! 4710: context = expression_context (rhs);
! 4711: break;
! 4712:
! 4713: case TILDE:
! 4714: #ifdef HAVE_REGEX_H
! 4715: token = next_token(&val, NULL, cfile);
! 4716: token = peek_token(&val, NULL, cfile);
! 4717:
! 4718: if (token == TILDE)
! 4719: next_op = expr_iregex_match;
! 4720: else if (token == EQUAL)
! 4721: next_op = expr_regex_match;
! 4722: else {
! 4723: parse_warn(cfile, "expecting ~= or ~~ operator");
! 4724: *lose = 1;
! 4725: skip_to_semi(cfile);
! 4726: if (lhs)
! 4727: expression_dereference(&lhs, MDL);
! 4728: return 0;
! 4729: }
! 4730:
! 4731: context = expression_context(rhs);
! 4732: #else
! 4733: parse_warn(cfile, "No support for regex operator.");
! 4734: *lose = 1;
! 4735: skip_to_semi(cfile);
! 4736: if (lhs != NULL)
! 4737: expression_dereference(&lhs, MDL);
! 4738: return 0;
! 4739: #endif
! 4740: break;
! 4741:
! 4742: case AND:
! 4743: next_op = expr_and;
! 4744: context = expression_context (rhs);
! 4745: break;
! 4746:
! 4747: case OR:
! 4748: next_op = expr_or;
! 4749: context = expression_context (rhs);
! 4750: break;
! 4751:
! 4752: case PLUS:
! 4753: next_op = expr_add;
! 4754: context = expression_context (rhs);
! 4755: break;
! 4756:
! 4757: case MINUS:
! 4758: next_op = expr_subtract;
! 4759: context = expression_context (rhs);
! 4760: break;
! 4761:
! 4762: case SLASH:
! 4763: next_op = expr_divide;
! 4764: context = expression_context (rhs);
! 4765: break;
! 4766:
! 4767: case ASTERISK:
! 4768: next_op = expr_multiply;
! 4769: context = expression_context (rhs);
! 4770: break;
! 4771:
! 4772: case PERCENT:
! 4773: next_op = expr_remainder;
! 4774: context = expression_context (rhs);
! 4775: break;
! 4776:
! 4777: case AMPERSAND:
! 4778: next_op = expr_binary_and;
! 4779: context = expression_context (rhs);
! 4780: break;
! 4781:
! 4782: case PIPE:
! 4783: next_op = expr_binary_or;
! 4784: context = expression_context (rhs);
! 4785: break;
! 4786:
! 4787: case CARET:
! 4788: next_op = expr_binary_xor;
! 4789: context = expression_context (rhs);
! 4790: break;
! 4791:
! 4792: default:
! 4793: next_op = expr_none;
! 4794: }
! 4795:
! 4796: /* If we have no lhs yet, we just parsed it. */
! 4797: if (!lhs) {
! 4798: /* If there was no operator following what we just parsed,
! 4799: then we're done - return it. */
! 4800: if (next_op == expr_none) {
! 4801: *expr = rhs;
! 4802: return 1;
! 4803: }
! 4804: lhs = rhs;
! 4805: rhs = (struct expression *)0;
! 4806: binop = next_op;
! 4807: next_token (&val, (unsigned *)0, cfile);
! 4808: goto new_rhs;
! 4809: }
! 4810:
! 4811: /* If the next binary operator is of greater precedence than the
! 4812: * current operator, then rhs we have parsed so far is actually
! 4813: * the lhs of the next operator. To get this value, we have to
! 4814: * recurse.
! 4815: */
! 4816: if (binop != expr_none && next_op != expr_none &&
! 4817: op_precedence (binop, next_op) < 0) {
! 4818:
! 4819: /* Eat the subexpression operator token, which we pass to
! 4820: * parse_expression...we only peek()'d earlier.
! 4821: */
! 4822: token = next_token (&val, (unsigned *)0, cfile);
! 4823:
! 4824: /* Continue parsing of the right hand side with that token. */
! 4825: tmp = rhs;
! 4826: rhs = (struct expression *)0;
! 4827: if (!parse_expression (&rhs, cfile, lose, op_context (next_op),
! 4828: &tmp, next_op)) {
! 4829: if (!*lose) {
! 4830: parse_warn (cfile,
! 4831: "expecting a subexpression");
! 4832: *lose = 1;
! 4833: }
! 4834: return 0;
! 4835: }
! 4836: next_op = expr_none;
! 4837: }
! 4838:
! 4839: if (binop != expr_none) {
! 4840: rhs_context = expression_context(rhs);
! 4841: lhs_context = expression_context(lhs);
! 4842:
! 4843: if ((rhs_context != context_any) && (lhs_context != context_any) &&
! 4844: (rhs_context != lhs_context)) {
! 4845: parse_warn (cfile, "illegal expression relating different types");
! 4846: skip_to_semi (cfile);
! 4847: expression_dereference (&rhs, MDL);
! 4848: expression_dereference (&lhs, MDL);
! 4849: *lose = 1;
! 4850: return 0;
! 4851: }
! 4852:
! 4853: switch(binop) {
! 4854: case expr_not_equal:
! 4855: case expr_equal:
! 4856: if ((rhs_context != context_data_or_numeric) &&
! 4857: (rhs_context != context_data) &&
! 4858: (rhs_context != context_numeric) &&
! 4859: (rhs_context != context_any)) {
! 4860: parse_warn (cfile, "expecting data/numeric expression");
! 4861: skip_to_semi (cfile);
! 4862: expression_dereference (&rhs, MDL);
! 4863: *lose = 1;
! 4864: return 0;
! 4865: }
! 4866: break;
! 4867:
! 4868: case expr_regex_match:
! 4869: #ifdef HAVE_REGEX_H
! 4870: if (expression_context(rhs) != context_data) {
! 4871: parse_warn(cfile, "expecting data expression");
! 4872: skip_to_semi(cfile);
! 4873: expression_dereference(&rhs, MDL);
! 4874: *lose = 1;
! 4875: return 0;
! 4876: }
! 4877: #else
! 4878: /* It should not be possible to attempt to parse the right
! 4879: * hand side of an operator there is no support for.
! 4880: */
! 4881: log_fatal("Impossible condition at %s:%d.", MDL);
! 4882: #endif
! 4883: break;
! 4884:
! 4885: case expr_and:
! 4886: case expr_or:
! 4887: if ((rhs_context != context_boolean) &&
! 4888: (rhs_context != context_any)) {
! 4889: parse_warn (cfile, "expecting boolean expressions");
! 4890: skip_to_semi (cfile);
! 4891: expression_dereference (&rhs, MDL);
! 4892: *lose = 1;
! 4893: return 0;
! 4894: }
! 4895: break;
! 4896:
! 4897: case expr_add:
! 4898: case expr_subtract:
! 4899: case expr_divide:
! 4900: case expr_multiply:
! 4901: case expr_remainder:
! 4902: case expr_binary_and:
! 4903: case expr_binary_or:
! 4904: case expr_binary_xor:
! 4905: if ((rhs_context != context_numeric) &&
! 4906: (rhs_context != context_any)) {
! 4907: parse_warn (cfile, "expecting numeric expressions");
! 4908: skip_to_semi (cfile);
! 4909: expression_dereference (&rhs, MDL);
! 4910: *lose = 1;
! 4911: return 0;
! 4912: }
! 4913: break;
! 4914:
! 4915: default:
! 4916: break;
! 4917: }
! 4918: }
! 4919:
! 4920: /* Now, if we didn't find a binary operator, we're done parsing
! 4921: this subexpression, so combine it with the preceding binary
! 4922: operator and return the result. */
! 4923: if (next_op == expr_none) {
! 4924: if (!expression_allocate (expr, MDL))
! 4925: log_fatal ("Can't allocate expression!");
! 4926:
! 4927: (*expr) -> op = binop;
! 4928: /* All the binary operators' data union members
! 4929: are the same, so we'll cheat and use the member
! 4930: for the equals operator. */
! 4931: (*expr) -> data.equal [0] = lhs;
! 4932: (*expr) -> data.equal [1] = rhs;
! 4933: return 1;
! 4934: }
! 4935:
! 4936: /* Eat the operator token - we now know it was a binary operator... */
! 4937: token = next_token (&val, (unsigned *)0, cfile);
! 4938:
! 4939: /* Now combine the LHS and the RHS using binop. */
! 4940: tmp = (struct expression *)0;
! 4941: if (!expression_allocate (&tmp, MDL))
! 4942: log_fatal ("No memory for equal precedence combination.");
! 4943:
! 4944: /* Store the LHS and RHS. */
! 4945: tmp -> data.equal [0] = lhs;
! 4946: tmp -> data.equal [1] = rhs;
! 4947: tmp -> op = binop;
! 4948:
! 4949: lhs = tmp;
! 4950: tmp = (struct expression *)0;
! 4951: rhs = (struct expression *)0;
! 4952:
! 4953: /* Recursions don't return until we have parsed the end of the
! 4954: expression, so if we recursed earlier, we can now return what
! 4955: we got. */
! 4956: if (next_op == expr_none) {
! 4957: *expr = lhs;
! 4958: return 1;
! 4959: }
! 4960:
! 4961: binop = next_op;
! 4962: goto new_rhs;
! 4963: }
! 4964:
! 4965:
! 4966: int parse_option_data (expr, cfile, lookups, option)
! 4967: struct expression **expr;
! 4968: struct parse *cfile;
! 4969: int lookups;
! 4970: struct option *option;
! 4971: {
! 4972: const char *val;
! 4973: const char *fmt = NULL;
! 4974: struct expression *tmp;
! 4975: enum dhcp_token token;
! 4976:
! 4977: do {
! 4978: /*
! 4979: * Set a flag if this is an array of a simple type (i.e.,
! 4980: * not an array of pairs of IP addresses, or something like
! 4981: * that.
! 4982: */
! 4983: int uniform = 0;
! 4984:
! 4985: and_again:
! 4986: /* Set fmt to start of format for 'A' and one char back
! 4987: * for 'a'.
! 4988: */
! 4989: if ((fmt != NULL) && (fmt != option->format) && (*fmt == 'a'))
! 4990: fmt -= 1;
! 4991: else if ((fmt == NULL) || (*fmt == 'A'))
! 4992: fmt = option->format;
! 4993:
! 4994: /* 'a' means always uniform */
! 4995: if ((fmt[0] != 'Z') && (tolower((unsigned char)fmt[1]) == 'a'))
! 4996: uniform = 1;
! 4997:
! 4998: do {
! 4999: if ((*fmt == 'A') || (*fmt == 'a'))
! 5000: break;
! 5001: if (*fmt == 'o') {
! 5002: /* consume the optional flag */
! 5003: fmt++;
! 5004: continue;
! 5005: }
! 5006:
! 5007: if (fmt[1] == 'o') {
! 5008: /*
! 5009: * A value for the current format is
! 5010: * optional - check to see if the next
! 5011: * token is a semi-colon if so we don't
! 5012: * need to parse it and doing so would
! 5013: * consume the semi-colon which our
! 5014: * caller is expecting to parse
! 5015: */
! 5016: token = peek_token(&val, (unsigned *)0,
! 5017: cfile);
! 5018: if (token == SEMI) {
! 5019: fmt++;
! 5020: continue;
! 5021: }
! 5022: }
! 5023:
! 5024: tmp = *expr;
! 5025: *expr = NULL;
! 5026:
! 5027: if (!parse_option_token(expr, cfile, &fmt, tmp,
! 5028: uniform, lookups)) {
! 5029: if (fmt [1] != 'o') {
! 5030: if (tmp)
! 5031: expression_dereference (&tmp,
! 5032: MDL);
! 5033: return 0;
! 5034: }
! 5035: *expr = tmp;
! 5036: tmp = NULL;
! 5037: }
! 5038: if (tmp)
! 5039: expression_dereference (&tmp, MDL);
! 5040:
! 5041: fmt++;
! 5042: } while (*fmt != '\0');
! 5043:
! 5044: if ((*fmt == 'A') || (*fmt == 'a')) {
! 5045: token = peek_token (&val, (unsigned *)0, cfile);
! 5046: /* Comma means: continue with next element in array */
! 5047: if (token == COMMA) {
! 5048: token = next_token (&val,
! 5049: (unsigned *)0, cfile);
! 5050: continue;
! 5051: }
! 5052: /* no comma: end of array.
! 5053: 'A' or end of string means: leave the loop */
! 5054: if ((*fmt == 'A') || (fmt[1] == '\0'))
! 5055: break;
! 5056: /* 'a' means: go on with next char */
! 5057: if (*fmt == 'a') {
! 5058: fmt++;
! 5059: goto and_again;
! 5060: }
! 5061: }
! 5062: } while ((*fmt == 'A') || (*fmt == 'a'));
! 5063:
! 5064: return 1;
! 5065: }
! 5066:
! 5067: /* option-statement :== identifier DOT identifier <syntax> SEMI
! 5068: | identifier <syntax> SEMI
! 5069:
! 5070: Option syntax is handled specially through format strings, so it
! 5071: would be painful to come up with BNF for it. However, it always
! 5072: starts as above and ends in a SEMI. */
! 5073:
! 5074: int parse_option_statement (result, cfile, lookups, option, op)
! 5075: struct executable_statement **result;
! 5076: struct parse *cfile;
! 5077: int lookups;
! 5078: struct option *option;
! 5079: enum statement_op op;
! 5080: {
! 5081: const char *val;
! 5082: enum dhcp_token token;
! 5083: struct expression *expr = (struct expression *)0;
! 5084: int lose;
! 5085:
! 5086: token = peek_token (&val, (unsigned *)0, cfile);
! 5087: if ((token == SEMI) && (option->format[0] != 'Z')) {
! 5088: /* Eat the semicolon... */
! 5089: /*
! 5090: * XXXSK: I'm not sure why we should ever get here, but we
! 5091: * do during our startup. This confuses things if
! 5092: * we are parsing a zero-length option, so don't
! 5093: * eat the semicolon token in that case.
! 5094: */
! 5095: token = next_token (&val, (unsigned *)0, cfile);
! 5096: } else if (token == EQUAL) {
! 5097: /* Eat the equals sign. */
! 5098: token = next_token (&val, (unsigned *)0, cfile);
! 5099:
! 5100: /* Parse a data expression and use its value for the data. */
! 5101: if (!parse_data_expression (&expr, cfile, &lose)) {
! 5102: /* In this context, we must have an executable
! 5103: statement, so if we found something else, it's
! 5104: still an error. */
! 5105: if (!lose) {
! 5106: parse_warn (cfile,
! 5107: "expecting a data expression.");
! 5108: skip_to_semi (cfile);
! 5109: }
! 5110: return 0;
! 5111: }
! 5112: } else {
! 5113: if (! parse_option_data(&expr, cfile, lookups, option))
! 5114: return 0;
! 5115: }
! 5116:
! 5117: if (!parse_semi (cfile))
! 5118: return 0;
! 5119: if (!executable_statement_allocate (result, MDL))
! 5120: log_fatal ("no memory for option statement.");
! 5121:
! 5122: (*result)->op = op;
! 5123: if (expr && !option_cache (&(*result)->data.option,
! 5124: NULL, expr, option, MDL))
! 5125: log_fatal ("no memory for option cache");
! 5126:
! 5127: if (expr)
! 5128: expression_dereference (&expr, MDL);
! 5129:
! 5130: return 1;
! 5131: }
! 5132:
! 5133: int parse_option_token (rv, cfile, fmt, expr, uniform, lookups)
! 5134: struct expression **rv;
! 5135: struct parse *cfile;
! 5136: const char **fmt;
! 5137: struct expression *expr;
! 5138: int uniform;
! 5139: int lookups;
! 5140: {
! 5141: const char *val;
! 5142: enum dhcp_token token;
! 5143: struct expression *t = (struct expression *)0;
! 5144: unsigned char buf [4];
! 5145: unsigned len;
! 5146: struct iaddr addr;
! 5147: int compress;
! 5148: isc_boolean_t freeval = ISC_FALSE;
! 5149: const char *f, *g;
! 5150: struct enumeration_value *e;
! 5151:
! 5152: switch (**fmt) {
! 5153: case 'U':
! 5154: token = next_token (&val, &len, cfile);
! 5155: if (!is_identifier (token)) {
! 5156: if ((*fmt) [1] != 'o') {
! 5157: parse_warn (cfile, "expecting identifier.");
! 5158: if (token != SEMI)
! 5159: skip_to_semi (cfile);
! 5160: }
! 5161: return 0;
! 5162: }
! 5163: if (!make_const_data (&t, (const unsigned char *)val,
! 5164: len, 1, 1, MDL))
! 5165: log_fatal ("No memory for %s", val);
! 5166: break;
! 5167:
! 5168: case 'E':
! 5169: g = strchr (*fmt, '.');
! 5170: if (!g) {
! 5171: parse_warn (cfile,
! 5172: "malformed encapsulation format (bug!)");
! 5173: skip_to_semi (cfile);
! 5174: return 0;
! 5175: }
! 5176: *fmt = g;
! 5177: case 'X':
! 5178: token = peek_token (&val, (unsigned *)0, cfile);
! 5179: if (token == NUMBER_OR_NAME || token == NUMBER) {
! 5180: if (!expression_allocate (&t, MDL))
! 5181: return 0;
! 5182: if (!parse_cshl (&t -> data.const_data, cfile)) {
! 5183: expression_dereference (&t, MDL);
! 5184: return 0;
! 5185: }
! 5186: t -> op = expr_const_data;
! 5187: } else {
! 5188: token = next_token (&val, &len, cfile);
! 5189:
! 5190: if(token == STRING) {
! 5191: if (!make_const_data (&t,
! 5192: (const unsigned char *)val,
! 5193: len, 1, 1, MDL))
! 5194: log_fatal ("No memory for \"%s\"", val);
! 5195: } else {
! 5196: if ((*fmt) [1] != 'o') {
! 5197: parse_warn (cfile, "expecting string "
! 5198: "or hexadecimal data.");
! 5199: skip_to_semi (cfile);
! 5200: }
! 5201: return 0;
! 5202: }
! 5203: }
! 5204: break;
! 5205:
! 5206: case 'D': /* Domain list... */
! 5207: if ((*fmt)[1] == 'c') {
! 5208: compress = 1;
! 5209: /* Skip the compress-flag atom. */
! 5210: (*fmt)++;
! 5211: } else
! 5212: compress = 0;
! 5213:
! 5214: t = parse_domain_list(cfile, compress);
! 5215:
! 5216: if (!t) {
! 5217: if ((*fmt)[1] != 'o')
! 5218: skip_to_semi(cfile);
! 5219: return 0;
! 5220: }
! 5221:
! 5222: break;
! 5223:
! 5224: case 'd': /* Domain name... */
! 5225: val = parse_host_name (cfile);
! 5226: if (!val) {
! 5227: parse_warn (cfile, "not a valid domain name.");
! 5228: skip_to_semi (cfile);
! 5229: return 0;
! 5230: }
! 5231: len = strlen (val);
! 5232: freeval = ISC_TRUE;
! 5233: goto make_string;
! 5234:
! 5235: case 't': /* Text string... */
! 5236: token = next_token (&val, &len, cfile);
! 5237: if (token != STRING && !is_identifier (token)) {
! 5238: if ((*fmt) [1] != 'o') {
! 5239: parse_warn (cfile, "expecting string.");
! 5240: if (token != SEMI)
! 5241: skip_to_semi (cfile);
! 5242: }
! 5243: return 0;
! 5244: }
! 5245: make_string:
! 5246: if (!make_const_data (&t, (const unsigned char *)val,
! 5247: len, 1, 1, MDL))
! 5248: log_fatal ("No memory for concatenation");
! 5249: if (freeval == ISC_TRUE) {
! 5250: dfree((char *)val, MDL);
! 5251: freeval = ISC_FALSE;
! 5252: }
! 5253: break;
! 5254:
! 5255: case 'N':
! 5256: f = (*fmt) + 1;
! 5257: g = strchr (*fmt, '.');
! 5258: if (!g) {
! 5259: parse_warn (cfile, "malformed %s (bug!)",
! 5260: "enumeration format");
! 5261: foo:
! 5262: skip_to_semi (cfile);
! 5263: return 0;
! 5264: }
! 5265: *fmt = g;
! 5266: token = next_token (&val, (unsigned *)0, cfile);
! 5267: if (!is_identifier (token)) {
! 5268: parse_warn (cfile,
! 5269: "identifier expected");
! 5270: goto foo;
! 5271: }
! 5272: e = find_enumeration_value (f, (*fmt) - f, &len, val);
! 5273: if (!e) {
! 5274: parse_warn (cfile, "unknown value");
! 5275: goto foo;
! 5276: }
! 5277: if (!make_const_data (&t, &e -> value, len, 0, 1, MDL))
! 5278: return 0;
! 5279: break;
! 5280:
! 5281: case 'I': /* IP address or hostname. */
! 5282: if (lookups) {
! 5283: if (!parse_ip_addr_or_hostname (&t, cfile, uniform))
! 5284: return 0;
! 5285: } else {
! 5286: if (!parse_ip_addr (cfile, &addr))
! 5287: return 0;
! 5288: if (!make_const_data (&t, addr.iabuf, addr.len,
! 5289: 0, 1, MDL))
! 5290: return 0;
! 5291: }
! 5292: break;
! 5293:
! 5294: case '6': /* IPv6 address. */
! 5295: if (!parse_ip6_addr(cfile, &addr)) {
! 5296: return 0;
! 5297: }
! 5298: if (!make_const_data(&t, addr.iabuf, addr.len, 0, 1, MDL)) {
! 5299: return 0;
! 5300: }
! 5301: break;
! 5302:
! 5303: case 'T': /* Lease interval. */
! 5304: token = next_token (&val, (unsigned *)0, cfile);
! 5305: if (token != INFINITE)
! 5306: goto check_number;
! 5307: putLong (buf, -1);
! 5308: if (!make_const_data (&t, buf, 4, 0, 1, MDL))
! 5309: return 0;
! 5310: break;
! 5311:
! 5312: case 'L': /* Unsigned 32-bit integer... */
! 5313: case 'l': /* Signed 32-bit integer... */
! 5314: token = next_token (&val, (unsigned *)0, cfile);
! 5315: check_number:
! 5316: if ((token != NUMBER) && (token != NUMBER_OR_NAME)) {
! 5317: need_number:
! 5318: if ((*fmt) [1] != 'o') {
! 5319: parse_warn (cfile, "expecting number.");
! 5320: if (token != SEMI)
! 5321: skip_to_semi (cfile);
! 5322: }
! 5323: return 0;
! 5324: }
! 5325: convert_num (cfile, buf, val, 0, 32);
! 5326: if (!make_const_data (&t, buf, 4, 0, 1, MDL))
! 5327: return 0;
! 5328: break;
! 5329:
! 5330: case 's': /* Signed 16-bit integer. */
! 5331: case 'S': /* Unsigned 16-bit integer. */
! 5332: token = next_token (&val, (unsigned *)0, cfile);
! 5333: if ((token != NUMBER) && (token != NUMBER_OR_NAME))
! 5334: goto need_number;
! 5335: convert_num (cfile, buf, val, 0, 16);
! 5336: if (!make_const_data (&t, buf, 2, 0, 1, MDL))
! 5337: return 0;
! 5338: break;
! 5339:
! 5340: case 'b': /* Signed 8-bit integer. */
! 5341: case 'B': /* Unsigned 8-bit integer. */
! 5342: token = next_token (&val, (unsigned *)0, cfile);
! 5343: if ((token != NUMBER) && (token != NUMBER_OR_NAME))
! 5344: goto need_number;
! 5345: convert_num (cfile, buf, val, 0, 8);
! 5346: if (!make_const_data (&t, buf, 1, 0, 1, MDL))
! 5347: return 0;
! 5348: break;
! 5349:
! 5350: case 'f': /* Boolean flag. */
! 5351: token = next_token (&val, (unsigned *)0, cfile);
! 5352: if (!is_identifier (token)) {
! 5353: if ((*fmt) [1] != 'o')
! 5354: parse_warn (cfile, "expecting identifier.");
! 5355: bad_flag:
! 5356: if ((*fmt) [1] != 'o') {
! 5357: if (token != SEMI)
! 5358: skip_to_semi (cfile);
! 5359: }
! 5360: return 0;
! 5361: }
! 5362: if (!strcasecmp (val, "true")
! 5363: || !strcasecmp (val, "on"))
! 5364: buf [0] = 1;
! 5365: else if (!strcasecmp (val, "false")
! 5366: || !strcasecmp (val, "off"))
! 5367: buf [0] = 0;
! 5368: else if (!strcasecmp (val, "ignore"))
! 5369: buf [0] = 2;
! 5370: else {
! 5371: if ((*fmt) [1] != 'o')
! 5372: parse_warn (cfile, "expecting boolean.");
! 5373: goto bad_flag;
! 5374: }
! 5375: if (!make_const_data (&t, buf, 1, 0, 1, MDL))
! 5376: return 0;
! 5377: break;
! 5378:
! 5379: case 'Z': /* Zero-length option. */
! 5380: token = peek_token (&val, (unsigned *)0, cfile);
! 5381: if (token != SEMI) {
! 5382: parse_warn(cfile, "semicolon expected.");
! 5383: skip_to_semi(cfile);
! 5384: }
! 5385: buf[0] = '\0';
! 5386: if (!make_const_data(&t, /* expression */
! 5387: buf, /* buffer */
! 5388: 0, /* length */
! 5389: 0, /* terminated */
! 5390: 1, /* allocate */
! 5391: MDL))
! 5392: return 0;
! 5393: break;
! 5394:
! 5395: default:
! 5396: parse_warn (cfile, "Bad format '%c' in parse_option_token.",
! 5397: **fmt);
! 5398: skip_to_semi (cfile);
! 5399: return 0;
! 5400: }
! 5401: if (expr) {
! 5402: if (!make_concat (rv, expr, t))
! 5403: return 0;
! 5404: } else
! 5405: expression_reference (rv, t, MDL);
! 5406: expression_dereference (&t, MDL);
! 5407: return 1;
! 5408: }
! 5409:
! 5410: int parse_option_decl (oc, cfile)
! 5411: struct option_cache **oc;
! 5412: struct parse *cfile;
! 5413: {
! 5414: const char *val;
! 5415: int token;
! 5416: u_int8_t buf [4];
! 5417: u_int8_t hunkbuf [1024];
! 5418: unsigned hunkix = 0;
! 5419: const char *fmt, *f;
! 5420: struct option *option=NULL;
! 5421: struct iaddr ip_addr;
! 5422: u_int8_t *dp;
! 5423: const u_int8_t *cdp;
! 5424: unsigned len;
! 5425: int nul_term = 0;
! 5426: struct buffer *bp;
! 5427: int known = 0;
! 5428: int compress;
! 5429: struct expression *express = NULL;
! 5430: struct enumeration_value *e;
! 5431: isc_result_t status;
! 5432:
! 5433: status = parse_option_name (cfile, 0, &known, &option);
! 5434: if (status != ISC_R_SUCCESS || option == NULL)
! 5435: return 0;
! 5436:
! 5437: /* Parse the option data... */
! 5438: do {
! 5439: for (fmt = option -> format; *fmt; fmt++) {
! 5440: if (*fmt == 'A')
! 5441: break;
! 5442: if (*fmt == 'o' && fmt != option -> format)
! 5443: continue;
! 5444: switch (*fmt) {
! 5445: case 'E':
! 5446: fmt = strchr (fmt, '.');
! 5447: if (!fmt) {
! 5448: parse_warn (cfile,
! 5449: "malformed %s (bug!)",
! 5450: "encapsulation format");
! 5451: goto parse_exit;
! 5452: }
! 5453: case 'X':
! 5454: len = parse_X (cfile, &hunkbuf [hunkix],
! 5455: sizeof hunkbuf - hunkix);
! 5456: hunkix += len;
! 5457: break;
! 5458:
! 5459: case 't': /* Text string... */
! 5460: token = peek_token (&val,
! 5461: &len, cfile);
! 5462: if (token == SEMI && fmt[1] == 'o') {
! 5463: fmt++;
! 5464: break;
! 5465: }
! 5466: token = next_token (&val,
! 5467: &len, cfile);
! 5468: if (token != STRING) {
! 5469: parse_warn (cfile,
! 5470: "expecting string.");
! 5471: goto parse_exit;
! 5472: }
! 5473: if (hunkix + len + 1 > sizeof hunkbuf) {
! 5474: parse_warn (cfile,
! 5475: "option data buffer %s",
! 5476: "overflow");
! 5477: goto parse_exit;
! 5478: }
! 5479: memcpy (&hunkbuf [hunkix], val, len + 1);
! 5480: nul_term = 1;
! 5481: hunkix += len;
! 5482: break;
! 5483:
! 5484: case 'D':
! 5485: if (fmt[1] == 'c') {
! 5486: compress = 1;
! 5487: fmt++;
! 5488: } else
! 5489: compress = 0;
! 5490:
! 5491: express = parse_domain_list(cfile, compress);
! 5492:
! 5493: if (express == NULL)
! 5494: goto exit;
! 5495:
! 5496: if (express->op != expr_const_data) {
! 5497: parse_warn(cfile, "unexpected "
! 5498: "expression");
! 5499: goto parse_exit;
! 5500: }
! 5501:
! 5502: len = express->data.const_data.len;
! 5503: cdp = express->data.const_data.data;
! 5504:
! 5505: if ((hunkix + len) > sizeof(hunkbuf)) {
! 5506: parse_warn(cfile, "option data buffer "
! 5507: "overflow");
! 5508: goto parse_exit;
! 5509: }
! 5510: memcpy(&hunkbuf[hunkix], cdp, len);
! 5511: hunkix += len;
! 5512:
! 5513: expression_dereference(&express, MDL);
! 5514: break;
! 5515:
! 5516: case 'N':
! 5517: f = fmt + 1;
! 5518: fmt = strchr (fmt, '.');
! 5519: if (!fmt) {
! 5520: parse_warn (cfile,
! 5521: "malformed %s (bug!)",
! 5522: "enumeration format");
! 5523: goto parse_exit;
! 5524: }
! 5525: token = next_token (&val,
! 5526: (unsigned *)0, cfile);
! 5527: if (!is_identifier (token)) {
! 5528: parse_warn (cfile,
! 5529: "identifier expected");
! 5530: goto parse_exit;
! 5531: }
! 5532: e = find_enumeration_value (f, fmt - f,
! 5533: &len, val);
! 5534: if (!e) {
! 5535: parse_warn (cfile,
! 5536: "unknown value");
! 5537: goto parse_exit;
! 5538: }
! 5539: dp = &e -> value;
! 5540: goto alloc;
! 5541:
! 5542: case '6':
! 5543: if (!parse_ip6_addr(cfile, &ip_addr))
! 5544: goto exit;
! 5545: len = ip_addr.len;
! 5546: dp = ip_addr.iabuf;
! 5547: goto alloc;
! 5548:
! 5549: case 'I': /* IP address. */
! 5550: if (!parse_ip_addr (cfile, &ip_addr))
! 5551: goto exit;
! 5552: len = ip_addr.len;
! 5553: dp = ip_addr.iabuf;
! 5554:
! 5555: alloc:
! 5556: if (hunkix + len > sizeof hunkbuf) {
! 5557: parse_warn (cfile,
! 5558: "option data buffer %s",
! 5559: "overflow");
! 5560: goto parse_exit;
! 5561: }
! 5562: memcpy (&hunkbuf [hunkix], dp, len);
! 5563: hunkix += len;
! 5564: break;
! 5565:
! 5566: case 'L': /* Unsigned 32-bit integer... */
! 5567: case 'l': /* Signed 32-bit integer... */
! 5568: token = next_token (&val,
! 5569: (unsigned *)0, cfile);
! 5570: if ((token != NUMBER) &&
! 5571: (token != NUMBER_OR_NAME)) {
! 5572: need_number:
! 5573: parse_warn (cfile,
! 5574: "expecting number.");
! 5575: if (token != SEMI)
! 5576: goto parse_exit;
! 5577: else
! 5578: goto exit;
! 5579: }
! 5580: convert_num (cfile, buf, val, 0, 32);
! 5581: len = 4;
! 5582: dp = buf;
! 5583: goto alloc;
! 5584:
! 5585: case 's': /* Signed 16-bit integer. */
! 5586: case 'S': /* Unsigned 16-bit integer. */
! 5587: token = next_token (&val,
! 5588: (unsigned *)0, cfile);
! 5589: if ((token != NUMBER) &&
! 5590: (token != NUMBER_OR_NAME))
! 5591: goto need_number;
! 5592: convert_num (cfile, buf, val, 0, 16);
! 5593: len = 2;
! 5594: dp = buf;
! 5595: goto alloc;
! 5596:
! 5597: case 'b': /* Signed 8-bit integer. */
! 5598: case 'B': /* Unsigned 8-bit integer. */
! 5599: token = next_token (&val,
! 5600: (unsigned *)0, cfile);
! 5601: if ((token != NUMBER) &&
! 5602: (token != NUMBER_OR_NAME))
! 5603: goto need_number;
! 5604: convert_num (cfile, buf, val, 0, 8);
! 5605: len = 1;
! 5606: dp = buf;
! 5607: goto alloc;
! 5608:
! 5609: case 'f': /* Boolean flag. */
! 5610: token = next_token (&val,
! 5611: (unsigned *)0, cfile);
! 5612: if (!is_identifier (token)) {
! 5613: parse_warn (cfile,
! 5614: "expecting identifier.");
! 5615: bad_flag:
! 5616: if (token != SEMI)
! 5617: goto parse_exit;
! 5618: else
! 5619: goto exit;
! 5620: }
! 5621: if (!strcasecmp (val, "true")
! 5622: || !strcasecmp (val, "on"))
! 5623: buf [0] = 1;
! 5624: else if (!strcasecmp (val, "false")
! 5625: || !strcasecmp (val, "off"))
! 5626: buf [0] = 0;
! 5627: else {
! 5628: parse_warn (cfile,
! 5629: "expecting boolean.");
! 5630: goto bad_flag;
! 5631: }
! 5632: len = 1;
! 5633: dp = buf;
! 5634: goto alloc;
! 5635:
! 5636: case 'Z': /* Zero-length option */
! 5637: token = next_token(&val, (unsigned *)0, cfile);
! 5638: if (token != SEMI) {
! 5639: parse_warn(cfile,
! 5640: "semicolon expected.");
! 5641: goto parse_exit;
! 5642: }
! 5643: len = 0;
! 5644: buf[0] = '\0';
! 5645: break;
! 5646:
! 5647: default:
! 5648: log_error ("parse_option_param: Bad format %c",
! 5649: *fmt);
! 5650: goto parse_exit;
! 5651: }
! 5652: }
! 5653: token = next_token (&val, (unsigned *)0, cfile);
! 5654: } while (*fmt == 'A' && token == COMMA);
! 5655:
! 5656: if (token != SEMI) {
! 5657: parse_warn (cfile, "semicolon expected.");
! 5658: goto parse_exit;
! 5659: }
! 5660:
! 5661: bp = (struct buffer *)0;
! 5662: if (!buffer_allocate (&bp, hunkix + nul_term, MDL))
! 5663: log_fatal ("no memory to store option declaration.");
! 5664: if (!bp -> data)
! 5665: log_fatal ("out of memory allocating option data.");
! 5666: memcpy (bp -> data, hunkbuf, hunkix + nul_term);
! 5667:
! 5668: if (!option_cache_allocate (oc, MDL))
! 5669: log_fatal ("out of memory allocating option cache.");
! 5670:
! 5671: (*oc) -> data.buffer = bp;
! 5672: (*oc) -> data.data = &bp -> data [0];
! 5673: (*oc) -> data.terminated = nul_term;
! 5674: (*oc) -> data.len = hunkix;
! 5675: option_reference(&(*oc)->option, option, MDL);
! 5676: option_dereference(&option, MDL);
! 5677: return 1;
! 5678:
! 5679: parse_exit:
! 5680: if (express != NULL)
! 5681: expression_dereference(&express, MDL);
! 5682: skip_to_semi (cfile);
! 5683: exit:
! 5684: option_dereference(&option, MDL);
! 5685:
! 5686: return 0;
! 5687: }
! 5688:
! 5689: /* Consider merging parse_cshl into this. */
! 5690:
! 5691: int parse_X (cfile, buf, max)
! 5692: struct parse *cfile;
! 5693: u_int8_t *buf;
! 5694: unsigned max;
! 5695: {
! 5696: int token;
! 5697: const char *val;
! 5698: unsigned len;
! 5699:
! 5700: token = peek_token (&val, (unsigned *)0, cfile);
! 5701: if (token == NUMBER_OR_NAME || token == NUMBER) {
! 5702: len = 0;
! 5703: do {
! 5704: token = next_token (&val, (unsigned *)0, cfile);
! 5705: if (token != NUMBER && token != NUMBER_OR_NAME) {
! 5706: parse_warn (cfile,
! 5707: "expecting hexadecimal constant.");
! 5708: skip_to_semi (cfile);
! 5709: return 0;
! 5710: }
! 5711: convert_num (cfile, &buf [len], val, 16, 8);
! 5712: if (len++ > max) {
! 5713: parse_warn (cfile,
! 5714: "hexadecimal constant too long.");
! 5715: skip_to_semi (cfile);
! 5716: return 0;
! 5717: }
! 5718: token = peek_token (&val, (unsigned *)0, cfile);
! 5719: if (token == COLON)
! 5720: token = next_token (&val,
! 5721: (unsigned *)0, cfile);
! 5722: } while (token == COLON);
! 5723: val = (char *)buf;
! 5724: } else if (token == STRING) {
! 5725: token = next_token (&val, &len, cfile);
! 5726: if (len + 1 > max) {
! 5727: parse_warn (cfile, "string constant too long.");
! 5728: skip_to_semi (cfile);
! 5729: return 0;
! 5730: }
! 5731: memcpy (buf, val, len + 1);
! 5732: } else {
! 5733: parse_warn (cfile, "expecting string or hexadecimal data");
! 5734: skip_to_semi (cfile);
! 5735: return 0;
! 5736: }
! 5737: return len;
! 5738: }
! 5739:
! 5740: int parse_warn (struct parse *cfile, const char *fmt, ...)
! 5741: {
! 5742: va_list list;
! 5743: char lexbuf [256];
! 5744: char mbuf [1024];
! 5745: char fbuf [1024];
! 5746: unsigned i, lix;
! 5747:
! 5748: do_percentm (mbuf, fmt);
! 5749: /* %Audit% This is log output. %2004.06.17,Safe%
! 5750: * If we truncate we hope the user can get a hint from the log.
! 5751: */
! 5752: snprintf (fbuf, sizeof fbuf, "%s line %d: %s",
! 5753: cfile -> tlname, cfile -> lexline, mbuf);
! 5754:
! 5755: va_start (list, fmt);
! 5756: vsnprintf (mbuf, sizeof mbuf, fbuf, list);
! 5757: va_end (list);
! 5758:
! 5759: lix = 0;
! 5760: for (i = 0;
! 5761: cfile -> token_line [i] && i < (cfile -> lexchar - 1); i++) {
! 5762: if (lix < (sizeof lexbuf) - 1)
! 5763: lexbuf [lix++] = ' ';
! 5764: if (cfile -> token_line [i] == '\t') {
! 5765: for (; lix < (sizeof lexbuf) - 1 && (lix & 7); lix++)
! 5766: lexbuf [lix] = ' ';
! 5767: }
! 5768: }
! 5769: lexbuf [lix] = 0;
! 5770:
! 5771: #ifndef DEBUG
! 5772: syslog (log_priority | LOG_ERR, "%s", mbuf);
! 5773: syslog (log_priority | LOG_ERR, "%s", cfile -> token_line);
! 5774: if (cfile -> lexchar < 81)
! 5775: syslog (log_priority | LOG_ERR, "%s^", lexbuf);
! 5776: #endif
! 5777:
! 5778: if (log_perror) {
! 5779: IGNORE_RET (write (STDERR_FILENO, mbuf, strlen (mbuf)));
! 5780: IGNORE_RET (write (STDERR_FILENO, "\n", 1));
! 5781: IGNORE_RET (write (STDERR_FILENO, cfile -> token_line,
! 5782: strlen (cfile -> token_line)));
! 5783: IGNORE_RET (write (STDERR_FILENO, "\n", 1));
! 5784: if (cfile -> lexchar < 81)
! 5785: IGNORE_RET (write (STDERR_FILENO, lexbuf, lix));
! 5786: IGNORE_RET (write (STDERR_FILENO, "^\n", 2));
! 5787: }
! 5788:
! 5789: cfile -> warnings_occurred = 1;
! 5790:
! 5791: return 0;
! 5792: }
! 5793:
! 5794: struct expression *
! 5795: parse_domain_list(struct parse *cfile, int compress)
! 5796: {
! 5797: const char *val;
! 5798: enum dhcp_token token = SEMI;
! 5799: struct expression *t = NULL;
! 5800: unsigned len, clen = 0;
! 5801: int result;
! 5802: unsigned char compbuf[256 * NS_MAXCDNAME];
! 5803: const unsigned char *dnptrs[256], **lastdnptr;
! 5804:
! 5805: memset(compbuf, 0, sizeof(compbuf));
! 5806: memset(dnptrs, 0, sizeof(dnptrs));
! 5807: dnptrs[0] = compbuf;
! 5808: lastdnptr = &dnptrs[255];
! 5809:
! 5810: do {
! 5811: /* Consume the COMMA token if peeked. */
! 5812: if (token == COMMA)
! 5813: next_token(&val, NULL, cfile);
! 5814:
! 5815: /* Get next (or first) value. */
! 5816: token = next_token(&val, &len, cfile);
! 5817:
! 5818: if (token != STRING) {
! 5819: parse_warn(cfile, "Expecting a domain string.");
! 5820: return NULL;
! 5821: }
! 5822:
! 5823: /* If compression pointers are enabled, compress. If not,
! 5824: * just pack the names in series into the buffer.
! 5825: */
! 5826: if (compress) {
! 5827: result = MRns_name_compress(val, compbuf + clen,
! 5828: sizeof(compbuf) - clen,
! 5829: dnptrs, lastdnptr);
! 5830:
! 5831: if (result < 0) {
! 5832: parse_warn(cfile, "Error compressing domain "
! 5833: "list: %m");
! 5834: return NULL;
! 5835: }
! 5836:
! 5837: clen += result;
! 5838: } else {
! 5839: result = MRns_name_pton(val, compbuf + clen,
! 5840: sizeof(compbuf) - clen);
! 5841:
! 5842: /* result == 1 means the input was fully qualified.
! 5843: * result == 0 means the input wasn't.
! 5844: * result == -1 means bad things.
! 5845: */
! 5846: if (result < 0) {
! 5847: parse_warn(cfile, "Error assembling domain "
! 5848: "list: %m");
! 5849: return NULL;
! 5850: }
! 5851:
! 5852: /*
! 5853: * We need to figure out how many bytes to increment
! 5854: * our buffer pointer since pton doesn't tell us.
! 5855: */
! 5856: while (compbuf[clen] != 0)
! 5857: clen += compbuf[clen] + 1;
! 5858:
! 5859: /* Count the last label (0). */
! 5860: clen++;
! 5861: }
! 5862:
! 5863: if (clen > sizeof(compbuf))
! 5864: log_fatal("Impossible error at %s:%d", MDL);
! 5865:
! 5866: token = peek_token(&val, NULL, cfile);
! 5867: } while (token == COMMA);
! 5868:
! 5869: if (!make_const_data(&t, compbuf, clen, 1, 1, MDL))
! 5870: log_fatal("No memory for domain list object.");
! 5871:
! 5872: return t;
! 5873: }
! 5874:
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>