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