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