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