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