1 /* $OpenBSD: confpars.c,v 1.20 2010/04/02 17:03:58 zinovik 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 enter_subnet(subnet); 742 743 if (!parse_lbrace(cfile)) 744 return; 745 746 do { 747 token = peek_token(&val, cfile); 748 if (token == '}') { 749 token = next_token(&val, cfile); 750 break; 751 } else if (token == EOF) { 752 token = next_token(&val, cfile); 753 parse_warn("unexpected end of file"); 754 break; 755 } 756 declaration = parse_statement(cfile, subnet->group, 757 SUBNET_DECL, NULL, declaration); 758 } while (1); 759 760 /* If this subnet supports dynamic bootp, flag it so in the 761 shared_network containing it. */ 762 if (subnet->group->dynamic_bootp) 763 share->group->dynamic_bootp = 1; 764 765 /* Add the subnet to the list of subnets in this shared net. */ 766 if (!share->subnets) 767 share->subnets = subnet; 768 else { 769 u = NULL; 770 for (t = share->subnets; t; t = t->next_sibling) { 771 if (subnet_inner_than(subnet, t, 0)) { 772 if (u) 773 u->next_sibling = subnet; 774 else 775 share->subnets = subnet; 776 subnet->next_sibling = t; 777 return; 778 } 779 u = t; 780 } 781 u->next_sibling = subnet; 782 } 783 } 784 785 /* group-declaration :== RBRACE parameters declarations LBRACE */ 786 787 void parse_group_declaration(cfile, group) 788 FILE *cfile; 789 struct group *group; 790 { 791 char *val; 792 int token; 793 struct group *g; 794 int declaration = 0; 795 796 g = clone_group(group, "parse_group_declaration"); 797 798 if (!parse_lbrace(cfile)) { 799 free(g); 800 return; 801 } 802 803 do { 804 token = peek_token(&val, cfile); 805 if (token == '}') { 806 token = next_token(&val, cfile); 807 break; 808 } else if (token == EOF) { 809 token = next_token(&val, cfile); 810 parse_warn("unexpected end of file"); 811 break; 812 } 813 declaration = parse_statement(cfile, g, GROUP_DECL, NULL, 814 declaration); 815 } while (1); 816 } 817 818 /* ip-addr-or-hostname :== ip-address | hostname 819 ip-address :== NUMBER DOT NUMBER DOT NUMBER DOT NUMBER 820 821 Parse an ip address or a hostname. If uniform is zero, put in 822 a TREE_LIMIT node to catch hostnames that evaluate to more than 823 one IP address. */ 824 825 struct tree *parse_ip_addr_or_hostname(cfile, uniform) 826 FILE *cfile; 827 int uniform; 828 { 829 char *val; 830 int token; 831 unsigned char addr[4]; 832 int len = sizeof addr; 833 char *name; 834 struct tree *rv; 835 struct hostent *h; 836 837 token = peek_token(&val, cfile); 838 if (is_identifier(token)) { 839 name = parse_host_name(cfile); 840 if (!name) 841 return NULL; 842 h = gethostbyname(name); 843 if (h == NULL) { 844 parse_warn("%s (%d): could not resolve hostname", 845 val, token); 846 return NULL; 847 } 848 rv = tree_const(h->h_addr_list[0], h->h_length); 849 if (!uniform) 850 rv = tree_limit(rv, 4); 851 } else if (token == TOK_NUMBER) { 852 if (!parse_numeric_aggregate(cfile, addr, &len, '.', 10, 8)) 853 return NULL; 854 rv = tree_const(addr, len); 855 } else { 856 if (token != '{' && token != '}') 857 token = next_token(&val, cfile); 858 parse_warn("%s (%d): expecting IP address or hostname", 859 val, token); 860 if (token != ';') 861 skip_to_semi(cfile); 862 return NULL; 863 } 864 865 return rv; 866 } 867 868 869 /* fixed-addr-parameter :== ip-addrs-or-hostnames SEMI 870 ip-addrs-or-hostnames :== ip-addr-or-hostname 871 | ip-addrs-or-hostnames ip-addr-or-hostname */ 872 873 struct tree_cache *parse_fixed_addr_param(cfile) 874 FILE *cfile; 875 { 876 char *val; 877 int token; 878 struct tree *tree = NULL; 879 struct tree *tmp; 880 881 do { 882 tmp = parse_ip_addr_or_hostname(cfile, 0); 883 if (tree) 884 tree = tree_concat(tree, tmp); 885 else 886 tree = tmp; 887 token = peek_token(&val, cfile); 888 if (token == ',') 889 token = next_token(&val, cfile); 890 } while (token == ','); 891 892 if (!parse_semi(cfile)) 893 return NULL; 894 return tree_cache(tree); 895 } 896 897 /* option_parameter :== identifier DOT identifier <syntax> SEMI 898 | identifier <syntax> SEMI 899 900 Option syntax is handled specially through format strings, so it 901 would be painful to come up with BNF for it. However, it always 902 starts as above and ends in a SEMI. */ 903 904 void parse_option_param(cfile, group) 905 FILE *cfile; 906 struct group *group; 907 { 908 char *val; 909 int token; 910 unsigned char buf[4]; 911 char *vendor; 912 char *fmt; 913 struct universe *universe; 914 struct option *option; 915 struct tree *tree = NULL; 916 struct tree *t; 917 918 token = next_token(&val, cfile); 919 if (!is_identifier(token)) { 920 parse_warn("expecting identifier after option keyword."); 921 if (token != ';') 922 skip_to_semi(cfile); 923 return; 924 } 925 vendor = strdup(val); 926 if (vendor == NULL) 927 error("no memory for vendor token."); 928 token = peek_token(&val, cfile); 929 if (token == '.') { 930 /* Go ahead and take the DOT token... */ 931 token = next_token(&val, cfile); 932 933 /* The next token should be an identifier... */ 934 token = next_token(&val, cfile); 935 if (!is_identifier(token)) { 936 parse_warn("expecting identifier after '.'"); 937 if (token != ';') 938 skip_to_semi(cfile); 939 free(vendor); 940 return; 941 } 942 943 /* Look up the option name hash table for the specified 944 vendor. */ 945 universe = ((struct universe *)hash_lookup(&universe_hash, 946 (unsigned char *)vendor, 0)); 947 /* If it's not there, we can't parse the rest of the 948 declaration. */ 949 if (!universe) { 950 parse_warn("no vendor named %s.", vendor); 951 skip_to_semi(cfile); 952 free(vendor); 953 return; 954 } 955 } else { 956 /* Use the default hash table, which contains all the 957 standard dhcp option names. */ 958 val = vendor; 959 universe = &dhcp_universe; 960 } 961 962 /* Look up the actual option info... */ 963 option = (struct option *)hash_lookup(universe->hash, 964 (unsigned char *)val, 0); 965 966 /* If we didn't get an option structure, it's an undefined option. */ 967 if (!option) { 968 if (val == vendor) 969 parse_warn("no option named %s", val); 970 else 971 parse_warn("no option named %s for vendor %s", 972 val, vendor); 973 skip_to_semi(cfile); 974 free(vendor); 975 return; 976 } 977 978 /* Free the initial identifier token. */ 979 free(vendor); 980 981 /* Parse the option data... */ 982 do { 983 /* Set a flag if this is an array of a simple type (i.e., 984 not an array of pairs of IP addresses, or something 985 like that. */ 986 int uniform = option->format[1] == 'A'; 987 988 for (fmt = option->format; *fmt; fmt++) { 989 if (*fmt == 'A') 990 break; 991 switch (*fmt) { 992 case 'X': 993 token = peek_token(&val, cfile); 994 if (token == TOK_NUMBER_OR_NAME || 995 token == TOK_NUMBER) { 996 do { 997 token = next_token 998 (&val, cfile); 999 if (token != TOK_NUMBER && 1000 token != TOK_NUMBER_OR_NAME) { 1001 parse_warn("expecting " 1002 "number."); 1003 if (token != ';') 1004 skip_to_semi( 1005 cfile); 1006 return; 1007 } 1008 convert_num(buf, val, 16, 8); 1009 tree = tree_concat(tree, 1010 tree_const(buf, 1)); 1011 token = peek_token(&val, cfile); 1012 if (token == ':') 1013 token = next_token(&val, 1014 cfile); 1015 } while (token == ':'); 1016 } else if (token == TOK_STRING) { 1017 token = next_token(&val, cfile); 1018 tree = tree_concat(tree, 1019 tree_const((unsigned char *)val, 1020 strlen(val))); 1021 } else { 1022 parse_warn("expecting string %s.", 1023 "or hexadecimal data"); 1024 skip_to_semi(cfile); 1025 return; 1026 } 1027 break; 1028 1029 case 't': /* Text string... */ 1030 token = next_token(&val, cfile); 1031 if (token != TOK_STRING 1032 && !is_identifier(token)) { 1033 parse_warn("expecting string."); 1034 if (token != ';') 1035 skip_to_semi(cfile); 1036 return; 1037 } 1038 tree = tree_concat(tree, 1039 tree_const((unsigned char *)val, 1040 strlen(val))); 1041 break; 1042 1043 case 'I': /* IP address or hostname. */ 1044 t = parse_ip_addr_or_hostname(cfile, uniform); 1045 if (!t) 1046 return; 1047 tree = tree_concat(tree, t); 1048 break; 1049 1050 case 'L': /* Unsigned 32-bit integer... */ 1051 case 'l': /* Signed 32-bit integer... */ 1052 token = next_token(&val, cfile); 1053 if (token != TOK_NUMBER) { 1054 parse_warn("expecting number."); 1055 if (token != ';') 1056 skip_to_semi(cfile); 1057 return; 1058 } 1059 convert_num(buf, val, 0, 32); 1060 tree = tree_concat(tree, tree_const(buf, 4)); 1061 break; 1062 case 's': /* Signed 16-bit integer. */ 1063 case 'S': /* Unsigned 16-bit integer. */ 1064 token = next_token(&val, cfile); 1065 if (token != TOK_NUMBER) { 1066 parse_warn("expecting number."); 1067 if (token != ';') 1068 skip_to_semi(cfile); 1069 return; 1070 } 1071 convert_num(buf, val, 0, 16); 1072 tree = tree_concat(tree, tree_const(buf, 2)); 1073 break; 1074 case 'b': /* Signed 8-bit integer. */ 1075 case 'B': /* Unsigned 8-bit integer. */ 1076 token = next_token(&val, cfile); 1077 if (token != TOK_NUMBER) { 1078 parse_warn("expecting number."); 1079 if (token != ';') 1080 skip_to_semi(cfile); 1081 return; 1082 } 1083 convert_num(buf, val, 0, 8); 1084 tree = tree_concat(tree, tree_const(buf, 1)); 1085 break; 1086 case 'f': /* Boolean flag. */ 1087 token = next_token(&val, cfile); 1088 if (!is_identifier(token)) { 1089 parse_warn("expecting identifier."); 1090 if (token != ';') 1091 skip_to_semi(cfile); 1092 return; 1093 } 1094 if (!strcasecmp(val, "true") 1095 || !strcasecmp(val, "on")) 1096 buf[0] = 1; 1097 else if (!strcasecmp(val, "false") 1098 || !strcasecmp(val, "off")) 1099 buf[0] = 0; 1100 else { 1101 parse_warn("expecting boolean."); 1102 if (token != ';') 1103 skip_to_semi(cfile); 1104 return; 1105 } 1106 tree = tree_concat(tree, tree_const(buf, 1)); 1107 break; 1108 default: 1109 warning("Bad format %c in parse_option_param.", 1110 *fmt); 1111 skip_to_semi(cfile); 1112 return; 1113 } 1114 } 1115 if (*fmt == 'A') { 1116 token = peek_token(&val, cfile); 1117 if (token == ',') { 1118 token = next_token(&val, cfile); 1119 continue; 1120 } 1121 break; 1122 } 1123 } while (*fmt == 'A'); 1124 1125 token = next_token(&val, cfile); 1126 if (token != ';') { 1127 parse_warn("semicolon expected."); 1128 skip_to_semi(cfile); 1129 return; 1130 } 1131 group->options[option->code] = tree_cache(tree); 1132 } 1133 1134 /* lease_declaration :== LEASE ip_address LBRACE lease_parameters RBRACE 1135 1136 lease_parameters :== <nil> 1137 | lease_parameter 1138 | lease_parameters lease_parameter 1139 1140 lease_parameter :== STARTS date 1141 | ENDS date 1142 | TIMESTAMP date 1143 | HARDWARE hardware-parameter 1144 | UID hex_numbers SEMI 1145 | HOSTNAME hostname SEMI 1146 | CLIENT_HOSTNAME hostname SEMI 1147 | CLASS identifier SEMI 1148 | DYNAMIC_BOOTP SEMI */ 1149 1150 struct lease * 1151 parse_lease_declaration(FILE *cfile) 1152 { 1153 char *val; 1154 int token; 1155 unsigned char addr[4]; 1156 int len = sizeof addr; 1157 int seenmask = 0; 1158 int seenbit; 1159 char tbuf[32]; 1160 static struct lease lease; 1161 1162 /* Zap the lease structure... */ 1163 memset(&lease, 0, sizeof lease); 1164 1165 /* Get the address for which the lease has been issued. */ 1166 if (!parse_numeric_aggregate(cfile, addr, &len, '.', 10, 8)) 1167 return NULL; 1168 memcpy(lease.ip_addr.iabuf, addr, len); 1169 lease.ip_addr.len = len; 1170 1171 if (!parse_lbrace(cfile)) 1172 return NULL; 1173 1174 do { 1175 token = next_token(&val, cfile); 1176 if (token == '}') 1177 break; 1178 else if (token == EOF) { 1179 parse_warn("unexpected end of file"); 1180 break; 1181 } 1182 strlcpy(tbuf, val, sizeof tbuf); 1183 1184 /* Parse any of the times associated with the lease. */ 1185 if (token == TOK_STARTS || token == TOK_ENDS || token == TOK_TIMESTAMP) { 1186 time_t t; 1187 t = parse_date(cfile); 1188 switch (token) { 1189 case TOK_STARTS: 1190 seenbit = 1; 1191 lease.starts = t; 1192 break; 1193 1194 case TOK_ENDS: 1195 seenbit = 2; 1196 lease.ends = t; 1197 break; 1198 1199 case TOK_TIMESTAMP: 1200 seenbit = 4; 1201 lease.timestamp = t; 1202 break; 1203 1204 default: 1205 /*NOTREACHED*/ 1206 seenbit = 0; 1207 break; 1208 } 1209 } else { 1210 switch (token) { 1211 /* Colon-separated hexadecimal octets... */ 1212 case TOK_UID: 1213 seenbit = 8; 1214 token = peek_token(&val, cfile); 1215 if (token == TOK_STRING) { 1216 token = next_token(&val, cfile); 1217 lease.uid_len = strlen(val); 1218 lease.uid = (unsigned char *) 1219 malloc(lease.uid_len); 1220 if (!lease.uid) { 1221 warning("no space for uid"); 1222 return NULL; 1223 } 1224 memcpy(lease.uid, val, lease.uid_len); 1225 parse_semi(cfile); 1226 } else { 1227 lease.uid_len = 0; 1228 lease.uid = 1229 parse_numeric_aggregate(cfile, 1230 NULL, &lease.uid_len, ':', 16, 8); 1231 if (!lease.uid) { 1232 warning("no space for uid"); 1233 return NULL; 1234 } 1235 if (lease.uid_len == 0) { 1236 lease.uid = NULL; 1237 parse_warn("zero-length uid"); 1238 seenbit = 0; 1239 break; 1240 } 1241 } 1242 if (!lease.uid) 1243 error("No memory for lease uid"); 1244 break; 1245 1246 case TOK_CLASS: 1247 seenbit = 32; 1248 token = next_token(&val, cfile); 1249 if (!is_identifier(token)) { 1250 if (token != ';') 1251 skip_to_semi(cfile); 1252 return NULL; 1253 } 1254 /* for now, we aren't using this. */ 1255 break; 1256 1257 case TOK_HARDWARE: 1258 seenbit = 64; 1259 parse_hardware_param(cfile, 1260 &lease.hardware_addr); 1261 break; 1262 1263 case TOK_DYNAMIC_BOOTP: 1264 seenbit = 128; 1265 lease.flags |= BOOTP_LEASE; 1266 break; 1267 1268 case TOK_ABANDONED: 1269 seenbit = 256; 1270 lease.flags |= ABANDONED_LEASE; 1271 break; 1272 1273 case TOK_HOSTNAME: 1274 seenbit = 512; 1275 token = peek_token(&val, cfile); 1276 if (token == TOK_STRING) 1277 lease.hostname = parse_string(cfile); 1278 else 1279 lease.hostname = 1280 parse_host_name(cfile); 1281 if (!lease.hostname) { 1282 seenbit = 0; 1283 return NULL; 1284 } 1285 break; 1286 1287 case TOK_CLIENT_HOSTNAME: 1288 seenbit = 1024; 1289 token = peek_token(&val, cfile); 1290 if (token == TOK_STRING) 1291 lease.client_hostname = 1292 parse_string(cfile); 1293 else 1294 lease.client_hostname = 1295 parse_host_name(cfile); 1296 break; 1297 1298 default: 1299 skip_to_semi(cfile); 1300 seenbit = 0; 1301 return NULL; 1302 } 1303 1304 if (token != TOK_HARDWARE && token != TOK_STRING) { 1305 token = next_token(&val, cfile); 1306 if (token != ';') { 1307 parse_warn("semicolon expected."); 1308 skip_to_semi(cfile); 1309 return NULL; 1310 } 1311 } 1312 } 1313 if (seenmask & seenbit) { 1314 parse_warn("Too many %s parameters in lease %s\n", 1315 tbuf, piaddr(lease.ip_addr)); 1316 } else 1317 seenmask |= seenbit; 1318 1319 } while (1); 1320 return &lease; 1321 } 1322 1323 /* 1324 * address-range-declaration :== ip-address ip-address SEMI 1325 * | DYNAMIC_BOOTP ip-address ip-address SEMI 1326 */ 1327 void 1328 parse_address_range(FILE *cfile, struct subnet *subnet) 1329 { 1330 struct iaddr low, high; 1331 unsigned char addr[4]; 1332 int len = sizeof addr, token, dynamic = 0; 1333 char *val; 1334 1335 if ((token = peek_token(&val, cfile)) == TOK_DYNAMIC_BOOTP) { 1336 token = next_token(&val, cfile); 1337 subnet->group->dynamic_bootp = dynamic = 1; 1338 } 1339 1340 /* Get the bottom address in the range... */ 1341 if (!parse_numeric_aggregate(cfile, addr, &len, '.', 10, 8)) 1342 return; 1343 memcpy(low.iabuf, addr, len); 1344 low.len = len; 1345 1346 /* Only one address? */ 1347 token = peek_token(&val, cfile); 1348 if (token == ';') 1349 high = low; 1350 else { 1351 /* Get the top address in the range... */ 1352 if (!parse_numeric_aggregate(cfile, addr, &len, '.', 10, 8)) 1353 return; 1354 memcpy(high.iabuf, addr, len); 1355 high.len = len; 1356 } 1357 1358 token = next_token(&val, cfile); 1359 if (token != ';') { 1360 parse_warn("semicolon expected."); 1361 skip_to_semi(cfile); 1362 return; 1363 } 1364 1365 /* Create the new address range... */ 1366 new_address_range(low, high, subnet, dynamic); 1367 } 1368