1 /* $OpenBSD: confpars.c,v 1.23 2014/07/09 13:42:24 yasuoka Exp $ */ 2 3 /* 4 * Copyright (c) 1995, 1996, 1997 The Internet Software Consortium. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. Neither the name of The Internet Software Consortium nor the names 17 * of its contributors may be used to endorse or promote products derived 18 * from this software without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND 21 * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, 22 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 23 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 24 * DISCLAIMED. IN NO EVENT SHALL THE INTERNET SOFTWARE CONSORTIUM OR 25 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 26 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 27 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF 28 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 29 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 30 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 31 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 * SUCH DAMAGE. 33 * 34 * This software has been written for the Internet Software Consortium 35 * by Ted Lemon <mellon@fugue.com> in cooperation with Vixie 36 * Enterprises. To learn more about the Internet Software Consortium, 37 * see ``http://www.vix.com/isc''. To learn more about Vixie 38 * Enterprises, see ``http://www.vix.com''. 39 */ 40 41 #include "dhcpd.h" 42 #include "dhctoken.h" 43 44 /* conf-file :== parameters declarations EOF 45 parameters :== <nil> | parameter | parameters parameter 46 declarations :== <nil> | declaration | declarations declaration */ 47 48 int 49 readconf(void) 50 { 51 FILE *cfile; 52 char *val; 53 int token; 54 int declaration = 0; 55 56 new_parse(path_dhcpd_conf); 57 58 /* Set up the initial dhcp option universe. */ 59 initialize_universes(); 60 61 /* Set up the global defaults... */ 62 root_group.default_lease_time = 43200; /* 12 hours. */ 63 root_group.max_lease_time = 86400; /* 24 hours. */ 64 root_group.bootp_lease_cutoff = MAX_TIME; 65 root_group.boot_unknown_clients = 1; 66 root_group.allow_bootp = 1; 67 root_group.allow_booting = 1; 68 root_group.authoritative = 1; 69 70 if ((cfile = fopen(path_dhcpd_conf, "r")) == NULL) 71 error("Can't open %s: %m", path_dhcpd_conf); 72 73 do { 74 token = peek_token(&val, cfile); 75 if (token == EOF) 76 break; 77 declaration = parse_statement(cfile, &root_group, 78 ROOT_GROUP, 79 NULL, 80 declaration); 81 } while (1); 82 token = next_token(&val, cfile); /* Clear the peek buffer */ 83 fclose(cfile); 84 85 return !warnings_occurred; 86 } 87 88 /* lease-file :== lease-declarations EOF 89 lease-statments :== <nil> 90 | lease-declaration 91 | lease-declarations lease-declaration 92 */ 93 void 94 read_leases(void) 95 { 96 FILE *cfile; 97 char *val; 98 int token; 99 100 new_parse(path_dhcpd_db); 101 102 /* Open the lease file. If we can't open it, fail. The reason 103 for this is that although on initial startup, the absence of 104 a lease file is perfectly benign, if dhcpd has been running 105 and this file is absent, it means that dhcpd tried and failed 106 to rewrite the lease database. If we proceed and the 107 problem which caused the rewrite to fail has been fixed, but no 108 human has corrected the database problem, then we are left 109 thinking that no leases have been assigned to anybody, which 110 could create severe network chaos. */ 111 if ((cfile = fopen(path_dhcpd_db, "r")) == NULL) { 112 warning("Can't open lease database %s: %m -- %s", 113 path_dhcpd_db, 114 "check for failed database rewrite attempt!"); 115 warning("Please read the dhcpd.leases manual page if you"); 116 error("don't know what to do about this."); 117 } 118 119 do { 120 token = next_token(&val, cfile); 121 if (token == EOF) 122 break; 123 if (token != TOK_LEASE) { 124 warning("Corrupt lease file - possible data loss!"); 125 skip_to_semi(cfile); 126 } else { 127 struct lease *lease; 128 lease = parse_lease_declaration(cfile); 129 if (lease) 130 enter_lease(lease); 131 else 132 parse_warn("possibly corrupt lease file"); 133 } 134 135 } while (1); 136 fclose(cfile); 137 } 138 139 /* statement :== parameter | declaration 140 141 parameter :== timestamp 142 | DEFAULT_LEASE_TIME lease_time 143 | MAX_LEASE_TIME lease_time 144 | DYNAMIC_BOOTP_LEASE_CUTOFF date 145 | DYNAMIC_BOOTP_LEASE_LENGTH lease_time 146 | BOOT_UNKNOWN_CLIENTS boolean 147 | GET_LEASE_HOSTNAMES boolean 148 | USE_HOST_DECL_NAME boolean 149 | NEXT_SERVER ip-addr-or-hostname SEMI 150 | option_parameter 151 | SERVER-IDENTIFIER ip-addr-or-hostname SEMI 152 | FILENAME string-parameter 153 | SERVER_NAME string-parameter 154 | hardware-parameter 155 | fixed-address-parameter 156 | ALLOW allow-deny-keyword 157 | DENY allow-deny-keyword 158 | USE_LEASE_ADDR_FOR_DEFAULT_ROUTE boolean 159 160 declaration :== host-declaration 161 | group-declaration 162 | shared-network-declaration 163 | subnet-declaration 164 | VENDOR_CLASS class-declaration 165 | USER_CLASS class-declaration 166 | RANGE address-range-declaration */ 167 168 int parse_statement(cfile, group, type, host_decl, declaration) 169 FILE *cfile; 170 struct group *group; 171 int type; 172 struct host_decl *host_decl; 173 int declaration; 174 { 175 int token; 176 char *val; 177 struct shared_network *share; 178 char *n; 179 struct tree *tree; 180 struct tree_cache *cache; 181 struct hardware hardware; 182 183 switch (next_token(&val, cfile)) { 184 case TOK_HOST: 185 if (type != HOST_DECL) 186 parse_host_declaration(cfile, group); 187 else { 188 parse_warn("host declarations not allowed here."); 189 skip_to_semi(cfile); 190 } 191 return 1; 192 193 case TOK_GROUP: 194 if (type != HOST_DECL) 195 parse_group_declaration(cfile, group); 196 else { 197 parse_warn("host declarations not allowed here."); 198 skip_to_semi(cfile); 199 } 200 return 1; 201 202 case TOK_TIMESTAMP: 203 break; 204 205 case TOK_SHARED_NETWORK: 206 if (type == SHARED_NET_DECL || 207 type == HOST_DECL || 208 type == SUBNET_DECL) { 209 parse_warn("shared-network parameters not %s.", 210 "allowed here"); 211 skip_to_semi(cfile); 212 break; 213 } 214 215 parse_shared_net_declaration(cfile, group); 216 return 1; 217 218 case TOK_SUBNET: 219 if (type == HOST_DECL || type == SUBNET_DECL) { 220 parse_warn("subnet declarations not allowed here."); 221 skip_to_semi(cfile); 222 return 1; 223 } 224 225 /* If we're in a subnet declaration, just do the parse. */ 226 if (group->shared_network) { 227 parse_subnet_declaration(cfile, 228 group->shared_network); 229 break; 230 } 231 232 /* Otherwise, cons up a fake shared network structure 233 and populate it with the lone subnet... */ 234 235 share = calloc(1, sizeof(struct shared_network)); 236 if (!share) 237 error("No memory for shared subnet"); 238 share->group = clone_group(group, "parse_statement:subnet"); 239 share->group->shared_network = share; 240 241 parse_subnet_declaration(cfile, share); 242 243 /* share->subnets is the subnet we just parsed. */ 244 if (share->subnets) { 245 share->interface = 246 share->subnets->interface; 247 248 /* Make the shared network name from network number. */ 249 n = piaddr(share->subnets->net); 250 share->name = strdup(n); 251 if (share->name == NULL) 252 error("no memory for subnet name"); 253 254 /* Copy the authoritative parameter from the subnet, 255 since there is no opportunity to declare it here. */ 256 share->group->authoritative = 257 share->subnets->group->authoritative; 258 enter_shared_network(share); 259 } 260 return 1; 261 262 case TOK_VENDOR_CLASS: 263 parse_class_declaration(cfile, group, 0); 264 return 1; 265 266 case TOK_USER_CLASS: 267 parse_class_declaration(cfile, group, 1); 268 return 1; 269 270 case TOK_DEFAULT_LEASE_TIME: 271 parse_lease_time(cfile, &group->default_lease_time); 272 break; 273 274 case TOK_MAX_LEASE_TIME: 275 parse_lease_time(cfile, &group->max_lease_time); 276 break; 277 278 case TOK_DYNAMIC_BOOTP_LEASE_CUTOFF: 279 group->bootp_lease_cutoff = parse_date(cfile); 280 break; 281 282 case TOK_DYNAMIC_BOOTP_LEASE_LENGTH: 283 parse_lease_time(cfile, &group->bootp_lease_length); 284 break; 285 286 case TOK_BOOT_UNKNOWN_CLIENTS: 287 if (type == HOST_DECL) 288 parse_warn("boot-unknown-clients not allowed here."); 289 group->boot_unknown_clients = parse_boolean(cfile); 290 break; 291 292 case TOK_GET_LEASE_HOSTNAMES: 293 if (type == HOST_DECL) 294 parse_warn("get-lease-hostnames not allowed here."); 295 group->get_lease_hostnames = parse_boolean(cfile); 296 break; 297 298 case TOK_ALWAYS_REPLY_RFC1048: 299 group->always_reply_rfc1048 = parse_boolean(cfile); 300 break; 301 302 case TOK_USE_HOST_DECL_NAMES: 303 if (type == HOST_DECL) 304 parse_warn("use-host-decl-names not allowed here."); 305 group->use_host_decl_names = parse_boolean(cfile); 306 break; 307 308 case TOK_USE_LEASE_ADDR_FOR_DEFAULT_ROUTE: 309 group->use_lease_addr_for_default_route = 310 parse_boolean(cfile); 311 break; 312 313 case TOK_TOKEN_NOT: 314 token = next_token(&val, cfile); 315 switch (token) { 316 case TOK_AUTHORITATIVE: 317 if (type == HOST_DECL) 318 parse_warn("authority makes no sense here."); 319 group->authoritative = 0; 320 parse_semi(cfile); 321 break; 322 default: 323 parse_warn("expecting assertion"); 324 skip_to_semi(cfile); 325 break; 326 } 327 break; 328 329 case TOK_AUTHORITATIVE: 330 if (type == HOST_DECL) 331 parse_warn("authority makes no sense here."); 332 group->authoritative = 1; 333 parse_semi(cfile); 334 break; 335 336 case TOK_NEXT_SERVER: 337 tree = parse_ip_addr_or_hostname(cfile, 0); 338 if (!tree) 339 break; 340 cache = tree_cache(tree); 341 if (!tree_evaluate (cache)) 342 error("next-server is not known"); 343 group->next_server.len = 4; 344 memcpy(group->next_server.iabuf, 345 cache->value, group->next_server.len); 346 parse_semi(cfile); 347 break; 348 349 case TOK_OPTION: 350 parse_option_param(cfile, group); 351 break; 352 353 case TOK_SERVER_IDENTIFIER: 354 tree = parse_ip_addr_or_hostname(cfile, 0); 355 if (!tree) 356 return declaration; 357 group->options[DHO_DHCP_SERVER_IDENTIFIER] = tree_cache(tree); 358 token = next_token(&val, cfile); 359 break; 360 361 case TOK_FILENAME: 362 group->filename = parse_string(cfile); 363 break; 364 365 case TOK_SERVER_NAME: 366 group->server_name = parse_string(cfile); 367 break; 368 369 case TOK_HARDWARE: 370 parse_hardware_param(cfile, &hardware); 371 if (host_decl) 372 host_decl->interface = hardware; 373 else 374 parse_warn("hardware address parameter %s", 375 "not allowed here."); 376 break; 377 378 case TOK_FIXED_ADDR: 379 cache = parse_fixed_addr_param(cfile); 380 if (host_decl) 381 host_decl->fixed_addr = cache; 382 else 383 parse_warn("fixed-address parameter not %s", 384 "allowed here."); 385 break; 386 387 case TOK_RANGE: 388 if (type != SUBNET_DECL || !group->subnet) { 389 parse_warn("range declaration not allowed here."); 390 skip_to_semi(cfile); 391 return declaration; 392 } 393 parse_address_range(cfile, group->subnet); 394 return declaration; 395 396 case TOK_ALLOW: 397 parse_allow_deny(cfile, group, 1); 398 break; 399 400 case TOK_DENY: 401 parse_allow_deny(cfile, group, 0); 402 break; 403 404 default: 405 if (declaration) 406 parse_warn("expecting a declaration."); 407 else 408 parse_warn("expecting a parameter or declaration."); 409 skip_to_semi(cfile); 410 return declaration; 411 } 412 413 if (declaration) { 414 parse_warn("parameters not allowed after first declaration."); 415 return 1; 416 } 417 418 return 0; 419 } 420 421 /* allow-deny-keyword :== BOOTP 422 | BOOTING 423 | DYNAMIC_BOOTP 424 | UNKNOWN_CLIENTS */ 425 426 void parse_allow_deny(cfile, group, flag) 427 FILE *cfile; 428 struct group *group; 429 int flag; 430 { 431 int token; 432 char *val; 433 434 token = next_token(&val, cfile); 435 switch (token) { 436 case TOK_BOOTP: 437 group->allow_bootp = flag; 438 break; 439 440 case TOK_BOOTING: 441 group->allow_booting = flag; 442 break; 443 444 case TOK_DYNAMIC_BOOTP: 445 group->dynamic_bootp = flag; 446 break; 447 448 case TOK_UNKNOWN_CLIENTS: 449 group->boot_unknown_clients = flag; 450 break; 451 452 default: 453 parse_warn("expecting allow/deny key"); 454 skip_to_semi(cfile); 455 return; 456 } 457 parse_semi(cfile); 458 } 459 460 /* boolean :== ON SEMI | OFF SEMI | TRUE SEMI | FALSE SEMI */ 461 462 int 463 parse_boolean(FILE *cfile) 464 { 465 char *val; 466 int rv; 467 468 next_token(&val, cfile); 469 if (!strcasecmp (val, "true") || !strcasecmp (val, "on")) 470 rv = 1; 471 else if (!strcasecmp (val, "false") || !strcasecmp (val, "off")) 472 rv = 0; 473 else { 474 parse_warn("boolean value (true/false/on/off) expected"); 475 skip_to_semi(cfile); 476 return 0; 477 } 478 parse_semi(cfile); 479 return rv; 480 } 481 482 /* Expect a left brace; if there isn't one, skip over the rest of the 483 statement and return zero; otherwise, return 1. */ 484 485 int 486 parse_lbrace(FILE *cfile) 487 { 488 int token; 489 char *val; 490 491 token = next_token(&val, cfile); 492 if (token != '{') { 493 parse_warn("expecting left brace."); 494 skip_to_semi(cfile); 495 return 0; 496 } 497 return 1; 498 } 499 500 501 /* host-declaration :== hostname '{' parameters declarations '}' */ 502 503 void parse_host_declaration(cfile, group) 504 FILE *cfile; 505 struct group *group; 506 { 507 char *val; 508 int token; 509 struct host_decl *host; 510 char *name = parse_host_name(cfile); 511 int declaration = 0; 512 513 if (!name) 514 return; 515 516 host = calloc(1, sizeof (struct host_decl)); 517 if (!host) 518 error("can't allocate host decl struct %s.", name); 519 520 host->name = name; 521 host->group = clone_group(group, "parse_host_declaration"); 522 523 if (!parse_lbrace(cfile)) { 524 free(host->name); 525 free(host->group); 526 free(host); 527 return; 528 } 529 530 do { 531 token = peek_token(&val, cfile); 532 if (token == '}') { 533 token = next_token(&val, cfile); 534 break; 535 } 536 if (token == EOF) { 537 token = next_token(&val, cfile); 538 parse_warn("unexpected end of file"); 539 break; 540 } 541 declaration = parse_statement(cfile, host->group, 542 HOST_DECL, host, declaration); 543 } while (1); 544 545 if (!host->group->options[DHO_HOST_NAME] && 546 host->group->use_host_decl_names) { 547 host->group->options[DHO_HOST_NAME] = 548 new_tree_cache("parse_host_declaration"); 549 if (!host->group->options[DHO_HOST_NAME]) 550 error("can't allocate a tree cache for hostname."); 551 host->group->options[DHO_HOST_NAME]->len = 552 strlen(name); 553 host->group->options[DHO_HOST_NAME]->value = 554 (unsigned char *)name; 555 host->group->options[DHO_HOST_NAME]->buf_size = 556 host->group->options[DHO_HOST_NAME]->len; 557 host->group->options[DHO_HOST_NAME]->timeout = -1; 558 host->group->options[DHO_HOST_NAME]->tree = 559 NULL; 560 } 561 562 enter_host(host); 563 } 564 565 /* class-declaration :== STRING '{' parameters declarations '}' 566 */ 567 568 void parse_class_declaration(cfile, group, type) 569 FILE *cfile; 570 struct group *group; 571 int type; 572 { 573 char *val; 574 int token; 575 struct class *class; 576 int declaration = 0; 577 578 token = next_token(&val, cfile); 579 if (token != TOK_STRING) { 580 parse_warn("Expecting class name"); 581 skip_to_semi(cfile); 582 return; 583 } 584 585 class = add_class (type, val); 586 if (!class) 587 error("No memory for class %s.", val); 588 class->group = clone_group(group, "parse_class_declaration"); 589 590 if (!parse_lbrace(cfile)) { 591 free(class->name); 592 free(class->group); 593 free(class); 594 return; 595 } 596 597 do { 598 token = peek_token(&val, cfile); 599 if (token == '}') { 600 token = next_token(&val, cfile); 601 break; 602 } else if (token == EOF) { 603 token = next_token(&val, cfile); 604 parse_warn("unexpected end of file"); 605 break; 606 } else { 607 declaration = parse_statement(cfile, class->group, 608 CLASS_DECL, NULL, declaration); 609 } 610 } while (1); 611 } 612 613 /* shared-network-declaration :== 614 hostname LBRACE declarations parameters RBRACE */ 615 616 void parse_shared_net_declaration(cfile, group) 617 FILE *cfile; 618 struct group *group; 619 { 620 char *val; 621 int token; 622 struct shared_network *share; 623 char *name; 624 int declaration = 0; 625 626 share = calloc(1, sizeof(struct shared_network)); 627 if (!share) 628 error("No memory for shared subnet"); 629 share->leases = NULL; 630 share->last_lease = NULL; 631 share->insertion_point = NULL; 632 share->next = NULL; 633 share->interface = NULL; 634 share->group = clone_group(group, "parse_shared_net_declaration"); 635 share->group->shared_network = share; 636 637 /* Get the name of the shared network... */ 638 token = peek_token(&val, cfile); 639 if (token == TOK_STRING) { 640 token = next_token(&val, cfile); 641 642 if (val[0] == 0) { 643 parse_warn("zero-length shared network name"); 644 val = "<no-name-given>"; 645 } 646 name = strdup(val); 647 if (name == NULL) 648 error("no memory for shared network name"); 649 } else { 650 name = parse_host_name(cfile); 651 if (!name) { 652 free(share->group); 653 free(share); 654 return; 655 } 656 } 657 share->name = name; 658 659 if (!parse_lbrace(cfile)) { 660 free(share->group); 661 free(share->name); 662 free(share); 663 return; 664 } 665 666 do { 667 token = peek_token(&val, cfile); 668 if (token == '}') { 669 token = next_token(&val, cfile); 670 if (!share->subnets) { 671 free(share->group); 672 free(share->name); 673 free(share); 674 parse_warn("empty shared-network decl"); 675 return; 676 } 677 enter_shared_network(share); 678 return; 679 } else if (token == EOF) { 680 token = next_token(&val, cfile); 681 parse_warn("unexpected end of file"); 682 break; 683 } 684 685 declaration = parse_statement(cfile, share->group, 686 SHARED_NET_DECL, NULL, declaration); 687 } while (1); 688 } 689 690 /* subnet-declaration :== 691 net NETMASK netmask RBRACE parameters declarations LBRACE */ 692 693 void parse_subnet_declaration(cfile, share) 694 FILE *cfile; 695 struct shared_network *share; 696 { 697 char *val; 698 int token; 699 struct subnet *subnet, *t, *u; 700 struct iaddr iaddr; 701 unsigned char addr[4]; 702 int len = sizeof addr; 703 int declaration = 0; 704 705 subnet = calloc(1, sizeof(struct subnet)); 706 if (!subnet) 707 error("No memory for new subnet"); 708 subnet->shared_network = share; 709 subnet->group = clone_group(share->group, "parse_subnet_declaration"); 710 subnet->group->subnet = subnet; 711 712 /* Get the network number... */ 713 if (!parse_numeric_aggregate(cfile, addr, &len, '.', 10, 8)) { 714 free(subnet->group); 715 free(subnet); 716 return; 717 } 718 memcpy(iaddr.iabuf, addr, len); 719 iaddr.len = len; 720 subnet->net = iaddr; 721 722 token = next_token(&val, cfile); 723 if (token != TOK_NETMASK) { 724 free(subnet->group); 725 free(subnet); 726 parse_warn("Expecting netmask"); 727 skip_to_semi(cfile); 728 return; 729 } 730 731 /* Get the netmask... */ 732 if (!parse_numeric_aggregate(cfile, addr, &len, '.', 10, 8)) { 733 free(subnet->group); 734 free(subnet); 735 return; 736 } 737 memcpy(iaddr.iabuf, addr, len); 738 iaddr.len = len; 739 subnet->netmask = iaddr; 740 741 /* Save only the subnet number. */ 742 subnet->net = subnet_number(subnet->net, subnet->netmask); 743 744 enter_subnet(subnet); 745 746 if (!parse_lbrace(cfile)) 747 return; 748 749 do { 750 token = peek_token(&val, cfile); 751 if (token == '}') { 752 token = next_token(&val, cfile); 753 break; 754 } else if (token == EOF) { 755 token = next_token(&val, cfile); 756 parse_warn("unexpected end of file"); 757 break; 758 } 759 declaration = parse_statement(cfile, subnet->group, 760 SUBNET_DECL, NULL, declaration); 761 } while (1); 762 763 /* If this subnet supports dynamic bootp, flag it so in the 764 shared_network containing it. */ 765 if (subnet->group->dynamic_bootp) 766 share->group->dynamic_bootp = 1; 767 768 /* Add the subnet to the list of subnets in this shared net. */ 769 if (!share->subnets) 770 share->subnets = subnet; 771 else { 772 u = NULL; 773 for (t = share->subnets; t; t = t->next_sibling) { 774 if (subnet_inner_than(subnet, t, 0)) { 775 if (u) 776 u->next_sibling = subnet; 777 else 778 share->subnets = subnet; 779 subnet->next_sibling = t; 780 return; 781 } 782 u = t; 783 } 784 u->next_sibling = subnet; 785 } 786 } 787 788 /* group-declaration :== RBRACE parameters declarations LBRACE */ 789 790 void parse_group_declaration(cfile, group) 791 FILE *cfile; 792 struct group *group; 793 { 794 char *val; 795 int token; 796 struct group *g; 797 int declaration = 0; 798 799 g = clone_group(group, "parse_group_declaration"); 800 801 if (!parse_lbrace(cfile)) { 802 free(g); 803 return; 804 } 805 806 do { 807 token = peek_token(&val, cfile); 808 if (token == '}') { 809 token = next_token(&val, cfile); 810 break; 811 } else if (token == EOF) { 812 token = next_token(&val, cfile); 813 parse_warn("unexpected end of file"); 814 break; 815 } 816 declaration = parse_statement(cfile, g, GROUP_DECL, NULL, 817 declaration); 818 } while (1); 819 } 820 821 /* cidr :== ip-address "/" bit-count 822 * ip-address :== NUMBER [ DOT NUMBER [ DOT NUMBER [ DOT NUMBER ] ] ] 823 * bit-count :== 0..32 824 */ 825 int 826 parse_cidr(FILE *cfile, unsigned char *addr, unsigned char *prefix) 827 { 828 char *val; 829 int token; 830 int len = 4; 831 832 token = peek_token(&val, cfile); 833 834 if (!parse_numeric_aggregate(cfile, addr, &len, '.', 10, 8)) { 835 parse_warn("Expecting CIDR subnet"); 836 goto nocidr; 837 } 838 839 token = next_token(&val, cfile); 840 if (token != '/') { 841 parse_warn("Expecting '/'"); 842 goto nocidr; 843 } 844 845 *prefix = 0; 846 token = next_token(&val, cfile); 847 if (token == TOK_NUMBER) 848 convert_num(prefix, val, 10, 8); 849 850 if (token != TOK_NUMBER || *prefix > 32) { 851 parse_warn("Expecting CIDR prefix length, got '%s'", val); 852 goto nocidr; 853 } 854 855 return 1; 856 857 nocidr: 858 if (token != ';') 859 skip_to_semi(cfile); 860 return 0; 861 } 862 863 /* ip-addr-or-hostname :== ip-address | hostname 864 ip-address :== NUMBER DOT NUMBER DOT NUMBER DOT NUMBER 865 866 Parse an ip address or a hostname. If uniform is zero, put in 867 a TREE_LIMIT node to catch hostnames that evaluate to more than 868 one IP address. */ 869 870 struct tree *parse_ip_addr_or_hostname(cfile, uniform) 871 FILE *cfile; 872 int uniform; 873 { 874 char *val; 875 int token; 876 unsigned char addr[4]; 877 int len = sizeof addr; 878 char *name; 879 struct tree *rv; 880 struct hostent *h; 881 882 token = peek_token(&val, cfile); 883 if (is_identifier(token)) { 884 name = parse_host_name(cfile); 885 if (!name) 886 return NULL; 887 h = gethostbyname(name); 888 if (h == NULL) { 889 parse_warn("%s (%d): could not resolve hostname", 890 val, token); 891 return NULL; 892 } 893 rv = tree_const(h->h_addr_list[0], h->h_length); 894 if (!uniform) 895 rv = tree_limit(rv, 4); 896 } else if (token == TOK_NUMBER) { 897 if (!parse_numeric_aggregate(cfile, addr, &len, '.', 10, 8)) 898 return NULL; 899 rv = tree_const(addr, len); 900 } else { 901 if (token != '{' && token != '}') 902 token = next_token(&val, cfile); 903 parse_warn("%s (%d): expecting IP address or hostname", 904 val, token); 905 if (token != ';') 906 skip_to_semi(cfile); 907 return NULL; 908 } 909 910 return rv; 911 } 912 913 914 /* fixed-addr-parameter :== ip-addrs-or-hostnames SEMI 915 ip-addrs-or-hostnames :== ip-addr-or-hostname 916 | ip-addrs-or-hostnames ip-addr-or-hostname */ 917 918 struct tree_cache *parse_fixed_addr_param(cfile) 919 FILE *cfile; 920 { 921 char *val; 922 int token; 923 struct tree *tree = NULL; 924 struct tree *tmp; 925 926 do { 927 tmp = parse_ip_addr_or_hostname(cfile, 0); 928 if (tree) 929 tree = tree_concat(tree, tmp); 930 else 931 tree = tmp; 932 token = peek_token(&val, cfile); 933 if (token == ',') 934 token = next_token(&val, cfile); 935 } while (token == ','); 936 937 if (!parse_semi(cfile)) 938 return NULL; 939 return tree_cache(tree); 940 } 941 942 /* option_parameter :== identifier DOT identifier <syntax> SEMI 943 | identifier <syntax> SEMI 944 945 Option syntax is handled specially through format strings, so it 946 would be painful to come up with BNF for it. However, it always 947 starts as above and ends in a SEMI. */ 948 949 void parse_option_param(cfile, group) 950 FILE *cfile; 951 struct group *group; 952 { 953 char *val; 954 int token; 955 unsigned char buf[4]; 956 unsigned char cprefix; 957 char *vendor; 958 char *fmt; 959 struct universe *universe; 960 struct option *option; 961 struct tree *tree = NULL; 962 struct tree *t; 963 964 token = next_token(&val, cfile); 965 if (!is_identifier(token)) { 966 parse_warn("expecting identifier after option keyword."); 967 if (token != ';') 968 skip_to_semi(cfile); 969 return; 970 } 971 vendor = strdup(val); 972 if (vendor == NULL) 973 error("no memory for vendor token."); 974 token = peek_token(&val, cfile); 975 if (token == '.') { 976 /* Go ahead and take the DOT token... */ 977 token = next_token(&val, cfile); 978 979 /* The next token should be an identifier... */ 980 token = next_token(&val, cfile); 981 if (!is_identifier(token)) { 982 parse_warn("expecting identifier after '.'"); 983 if (token != ';') 984 skip_to_semi(cfile); 985 free(vendor); 986 return; 987 } 988 989 /* Look up the option name hash table for the specified 990 vendor. */ 991 universe = ((struct universe *)hash_lookup(&universe_hash, 992 (unsigned char *)vendor, 0)); 993 /* If it's not there, we can't parse the rest of the 994 declaration. */ 995 if (!universe) { 996 parse_warn("no vendor named %s.", vendor); 997 skip_to_semi(cfile); 998 free(vendor); 999 return; 1000 } 1001 } else { 1002 /* Use the default hash table, which contains all the 1003 standard dhcp option names. */ 1004 val = vendor; 1005 universe = &dhcp_universe; 1006 } 1007 1008 /* Look up the actual option info... */ 1009 option = (struct option *)hash_lookup(universe->hash, 1010 (unsigned char *)val, 0); 1011 1012 /* If we didn't get an option structure, it's an undefined option. */ 1013 if (!option) { 1014 if (val == vendor) 1015 parse_warn("no option named %s", val); 1016 else 1017 parse_warn("no option named %s for vendor %s", 1018 val, vendor); 1019 skip_to_semi(cfile); 1020 free(vendor); 1021 return; 1022 } 1023 1024 /* Free the initial identifier token. */ 1025 free(vendor); 1026 1027 /* Parse the option data... */ 1028 do { 1029 /* Set a flag if this is an array of a simple type (i.e., 1030 not an array of pairs of IP addresses, or something 1031 like that. */ 1032 int uniform = option->format[1] == 'A'; 1033 1034 for (fmt = option->format; *fmt; fmt++) { 1035 if (*fmt == 'A') 1036 break; 1037 switch (*fmt) { 1038 case 'X': 1039 token = peek_token(&val, cfile); 1040 if (token == TOK_NUMBER_OR_NAME || 1041 token == TOK_NUMBER) { 1042 do { 1043 token = next_token 1044 (&val, cfile); 1045 if (token != TOK_NUMBER && 1046 token != TOK_NUMBER_OR_NAME) { 1047 parse_warn("expecting " 1048 "number."); 1049 if (token != ';') 1050 skip_to_semi( 1051 cfile); 1052 return; 1053 } 1054 convert_num(buf, val, 16, 8); 1055 tree = tree_concat(tree, 1056 tree_const(buf, 1)); 1057 token = peek_token(&val, cfile); 1058 if (token == ':') 1059 token = next_token(&val, 1060 cfile); 1061 } while (token == ':'); 1062 } else if (token == TOK_STRING) { 1063 token = next_token(&val, cfile); 1064 tree = tree_concat(tree, 1065 tree_const((unsigned char *)val, 1066 strlen(val))); 1067 } else { 1068 parse_warn("expecting string %s.", 1069 "or hexadecimal data"); 1070 skip_to_semi(cfile); 1071 return; 1072 } 1073 break; 1074 1075 case 't': /* Text string... */ 1076 token = next_token(&val, cfile); 1077 if (token != TOK_STRING 1078 && !is_identifier(token)) { 1079 parse_warn("expecting string."); 1080 if (token != ';') 1081 skip_to_semi(cfile); 1082 return; 1083 } 1084 tree = tree_concat(tree, 1085 tree_const((unsigned char *)val, 1086 strlen(val))); 1087 break; 1088 1089 case 'I': /* IP address or hostname. */ 1090 t = parse_ip_addr_or_hostname(cfile, uniform); 1091 if (!t) 1092 return; 1093 tree = tree_concat(tree, t); 1094 break; 1095 1096 case 'L': /* Unsigned 32-bit integer... */ 1097 case 'l': /* Signed 32-bit integer... */ 1098 token = next_token(&val, cfile); 1099 if (token != TOK_NUMBER) { 1100 parse_warn("expecting number."); 1101 if (token != ';') 1102 skip_to_semi(cfile); 1103 return; 1104 } 1105 convert_num(buf, val, 0, 32); 1106 tree = tree_concat(tree, tree_const(buf, 4)); 1107 break; 1108 case 's': /* Signed 16-bit integer. */ 1109 case 'S': /* Unsigned 16-bit integer. */ 1110 token = next_token(&val, cfile); 1111 if (token != TOK_NUMBER) { 1112 parse_warn("expecting number."); 1113 if (token != ';') 1114 skip_to_semi(cfile); 1115 return; 1116 } 1117 convert_num(buf, val, 0, 16); 1118 tree = tree_concat(tree, tree_const(buf, 2)); 1119 break; 1120 case 'b': /* Signed 8-bit integer. */ 1121 case 'B': /* Unsigned 8-bit integer. */ 1122 token = next_token(&val, cfile); 1123 if (token != TOK_NUMBER) { 1124 parse_warn("expecting number."); 1125 if (token != ';') 1126 skip_to_semi(cfile); 1127 return; 1128 } 1129 convert_num(buf, val, 0, 8); 1130 tree = tree_concat(tree, tree_const(buf, 1)); 1131 break; 1132 case 'f': /* Boolean flag. */ 1133 token = next_token(&val, cfile); 1134 if (!is_identifier(token)) { 1135 parse_warn("expecting identifier."); 1136 if (token != ';') 1137 skip_to_semi(cfile); 1138 return; 1139 } 1140 if (!strcasecmp(val, "true") 1141 || !strcasecmp(val, "on")) 1142 buf[0] = 1; 1143 else if (!strcasecmp(val, "false") 1144 || !strcasecmp(val, "off")) 1145 buf[0] = 0; 1146 else { 1147 parse_warn("expecting boolean."); 1148 if (token != ';') 1149 skip_to_semi(cfile); 1150 return; 1151 } 1152 tree = tree_concat(tree, tree_const(buf, 1)); 1153 break; 1154 case 'C': 1155 if (!parse_cidr(cfile, buf, &cprefix)) 1156 return; 1157 tree = tree_concat(tree, tree_const(&cprefix, 1158 sizeof(cprefix))); 1159 if (cprefix > 0) 1160 tree = tree_concat(tree, tree_const(buf, 1161 (cprefix + 7) / 8)); 1162 break; 1163 default: 1164 warning("Bad format %c in parse_option_param.", 1165 *fmt); 1166 skip_to_semi(cfile); 1167 return; 1168 } 1169 } 1170 if (*fmt == 'A') { 1171 token = peek_token(&val, cfile); 1172 if (token == ',') { 1173 token = next_token(&val, cfile); 1174 continue; 1175 } 1176 break; 1177 } 1178 } while (*fmt == 'A'); 1179 1180 token = next_token(&val, cfile); 1181 if (token != ';') { 1182 parse_warn("semicolon expected."); 1183 skip_to_semi(cfile); 1184 return; 1185 } 1186 group->options[option->code] = tree_cache(tree); 1187 } 1188 1189 /* lease_declaration :== LEASE ip_address LBRACE lease_parameters RBRACE 1190 1191 lease_parameters :== <nil> 1192 | lease_parameter 1193 | lease_parameters lease_parameter 1194 1195 lease_parameter :== STARTS date 1196 | ENDS date 1197 | TIMESTAMP date 1198 | HARDWARE hardware-parameter 1199 | UID hex_numbers SEMI 1200 | HOSTNAME hostname SEMI 1201 | CLIENT_HOSTNAME hostname SEMI 1202 | CLASS identifier SEMI 1203 | DYNAMIC_BOOTP SEMI */ 1204 1205 struct lease * 1206 parse_lease_declaration(FILE *cfile) 1207 { 1208 char *val; 1209 int token; 1210 unsigned char addr[4]; 1211 int len = sizeof addr; 1212 int seenmask = 0; 1213 int seenbit; 1214 char tbuf[32]; 1215 static struct lease lease; 1216 1217 /* Zap the lease structure... */ 1218 memset(&lease, 0, sizeof lease); 1219 1220 /* Get the address for which the lease has been issued. */ 1221 if (!parse_numeric_aggregate(cfile, addr, &len, '.', 10, 8)) 1222 return NULL; 1223 memcpy(lease.ip_addr.iabuf, addr, len); 1224 lease.ip_addr.len = len; 1225 1226 if (!parse_lbrace(cfile)) 1227 return NULL; 1228 1229 do { 1230 token = next_token(&val, cfile); 1231 if (token == '}') 1232 break; 1233 else if (token == EOF) { 1234 parse_warn("unexpected end of file"); 1235 break; 1236 } 1237 strlcpy(tbuf, val, sizeof tbuf); 1238 1239 /* Parse any of the times associated with the lease. */ 1240 if (token == TOK_STARTS || token == TOK_ENDS || token == TOK_TIMESTAMP) { 1241 time_t t; 1242 t = parse_date(cfile); 1243 switch (token) { 1244 case TOK_STARTS: 1245 seenbit = 1; 1246 lease.starts = t; 1247 break; 1248 1249 case TOK_ENDS: 1250 seenbit = 2; 1251 lease.ends = t; 1252 break; 1253 1254 case TOK_TIMESTAMP: 1255 seenbit = 4; 1256 lease.timestamp = t; 1257 break; 1258 1259 default: 1260 /*NOTREACHED*/ 1261 seenbit = 0; 1262 break; 1263 } 1264 } else { 1265 switch (token) { 1266 /* Colon-separated hexadecimal octets... */ 1267 case TOK_UID: 1268 seenbit = 8; 1269 token = peek_token(&val, cfile); 1270 if (token == TOK_STRING) { 1271 token = next_token(&val, cfile); 1272 lease.uid_len = strlen(val); 1273 lease.uid = (unsigned char *) 1274 malloc(lease.uid_len); 1275 if (!lease.uid) { 1276 warning("no space for uid"); 1277 return NULL; 1278 } 1279 memcpy(lease.uid, val, lease.uid_len); 1280 parse_semi(cfile); 1281 } else { 1282 lease.uid_len = 0; 1283 lease.uid = 1284 parse_numeric_aggregate(cfile, 1285 NULL, &lease.uid_len, ':', 16, 8); 1286 if (!lease.uid) { 1287 warning("no space for uid"); 1288 return NULL; 1289 } 1290 if (lease.uid_len == 0) { 1291 lease.uid = NULL; 1292 parse_warn("zero-length uid"); 1293 seenbit = 0; 1294 break; 1295 } 1296 } 1297 if (!lease.uid) 1298 error("No memory for lease uid"); 1299 break; 1300 1301 case TOK_CLASS: 1302 seenbit = 32; 1303 token = next_token(&val, cfile); 1304 if (!is_identifier(token)) { 1305 if (token != ';') 1306 skip_to_semi(cfile); 1307 return NULL; 1308 } 1309 /* for now, we aren't using this. */ 1310 break; 1311 1312 case TOK_HARDWARE: 1313 seenbit = 64; 1314 parse_hardware_param(cfile, 1315 &lease.hardware_addr); 1316 break; 1317 1318 case TOK_DYNAMIC_BOOTP: 1319 seenbit = 128; 1320 lease.flags |= BOOTP_LEASE; 1321 break; 1322 1323 case TOK_ABANDONED: 1324 seenbit = 256; 1325 lease.flags |= ABANDONED_LEASE; 1326 break; 1327 1328 case TOK_HOSTNAME: 1329 seenbit = 512; 1330 token = peek_token(&val, cfile); 1331 if (token == TOK_STRING) 1332 lease.hostname = parse_string(cfile); 1333 else 1334 lease.hostname = 1335 parse_host_name(cfile); 1336 if (!lease.hostname) { 1337 seenbit = 0; 1338 return NULL; 1339 } 1340 break; 1341 1342 case TOK_CLIENT_HOSTNAME: 1343 seenbit = 1024; 1344 token = peek_token(&val, cfile); 1345 if (token == TOK_STRING) 1346 lease.client_hostname = 1347 parse_string(cfile); 1348 else 1349 lease.client_hostname = 1350 parse_host_name(cfile); 1351 break; 1352 1353 default: 1354 skip_to_semi(cfile); 1355 seenbit = 0; 1356 return NULL; 1357 } 1358 1359 if (token != TOK_HARDWARE && token != TOK_STRING) { 1360 token = next_token(&val, cfile); 1361 if (token != ';') { 1362 parse_warn("semicolon expected."); 1363 skip_to_semi(cfile); 1364 return NULL; 1365 } 1366 } 1367 } 1368 if (seenmask & seenbit) { 1369 parse_warn("Too many %s parameters in lease %s\n", 1370 tbuf, piaddr(lease.ip_addr)); 1371 } else 1372 seenmask |= seenbit; 1373 1374 } while (1); 1375 return &lease; 1376 } 1377 1378 /* 1379 * address-range-declaration :== ip-address ip-address SEMI 1380 * | DYNAMIC_BOOTP ip-address ip-address SEMI 1381 */ 1382 void 1383 parse_address_range(FILE *cfile, struct subnet *subnet) 1384 { 1385 struct iaddr low, high; 1386 unsigned char addr[4]; 1387 int len = sizeof addr, token, dynamic = 0; 1388 char *val; 1389 1390 if ((token = peek_token(&val, cfile)) == TOK_DYNAMIC_BOOTP) { 1391 token = next_token(&val, cfile); 1392 subnet->group->dynamic_bootp = dynamic = 1; 1393 } 1394 1395 /* Get the bottom address in the range... */ 1396 if (!parse_numeric_aggregate(cfile, addr, &len, '.', 10, 8)) 1397 return; 1398 memcpy(low.iabuf, addr, len); 1399 low.len = len; 1400 1401 /* Only one address? */ 1402 token = peek_token(&val, cfile); 1403 if (token == ';') 1404 high = low; 1405 else { 1406 /* Get the top address in the range... */ 1407 if (!parse_numeric_aggregate(cfile, addr, &len, '.', 10, 8)) 1408 return; 1409 memcpy(high.iabuf, addr, len); 1410 high.len = len; 1411 } 1412 1413 token = next_token(&val, cfile); 1414 if (token != ';') { 1415 parse_warn("semicolon expected."); 1416 skip_to_semi(cfile); 1417 return; 1418 } 1419 1420 /* Create the new address range... */ 1421 new_address_range(low, high, subnet, dynamic); 1422 } 1423