103 104 if ((cfile = fopen(path_dhclient_conf, "r")) != NULL) { 105 do { 106 token = peek_token(&val, cfile); 107 if (token == EOF) 108 break; 109 parse_client_statement(cfile, NULL, &top_level_config); 110 } while (1); 111 token = next_token(&val, cfile); /* Clear the peek buffer */ 112 fclose(cfile); 113 } 114 115 /* 116 * Set up state and config structures for clients that don't 117 * have per-interface configuration declarations. 118 */ 119 config = NULL; 120 if (!ifi->client) { 121 ifi->client = malloc(sizeof(struct client_state)); 122 if (!ifi->client) 123 error("no memory for client state."); 124 memset(ifi->client, 0, sizeof(*(ifi->client))); 125 } 126 if (!ifi->client->config) { 127 if (!config) { 128 config = malloc(sizeof(struct client_config)); 129 if (!config) 130 error("no memory for client config."); 131 memcpy(config, &top_level_config, 132 sizeof(top_level_config)); 133 } 134 ifi->client->config = config; 135 } 136 137 return (!warnings_occurred); 138} 139 140/* 141 * lease-file :== client-lease-statements EOF 142 * client-lease-statements :== <nil> 143 * | client-lease-statements LEASE client-lease-statement 144 */ 145void 146read_client_leases(void) 147{ 148 FILE *cfile; 149 char *val; 150 int token; 151 152 new_parse(path_dhclient_db); 153 154 /* Open the lease file. If we can't open it, just return - 155 we can safely trust the server to remember our state. */ 156 if ((cfile = fopen(path_dhclient_db, "r")) == NULL) 157 return; 158 do { 159 token = next_token(&val, cfile); 160 if (token == EOF) 161 break; 162 if (token != LEASE) { 163 warning("Corrupt lease file - possible data loss!"); 164 skip_to_semi(cfile); 165 break; 166 } else 167 parse_client_lease_statement(cfile, 0); 168 169 } while (1); 170 fclose(cfile); 171} 172 173/* 174 * client-declaration :== 175 * SEND option-decl | 176 * DEFAULT option-decl | 177 * SUPERSEDE option-decl | 178 * PREPEND option-decl | 179 * APPEND option-decl | 180 * hardware-declaration | 181 * REQUEST option-list | 182 * REQUIRE option-list | 183 * TIMEOUT number | 184 * RETRY number | 185 * REBOOT number | 186 * SELECT_TIMEOUT number | 187 * SCRIPT string | 188 * interface-declaration | 189 * LEASE client-lease-statement | 190 * ALIAS client-lease-statement 191 */ 192void 193parse_client_statement(FILE *cfile, struct interface_info *ip, 194 struct client_config *config) 195{ 196 int token; 197 char *val; 198 struct option *option; 199 200 switch (next_token(&val, cfile)) { 201 case SEND: 202 parse_option_decl(cfile, &config->send_options[0]); 203 return; 204 case DEFAULT: 205 option = parse_option_decl(cfile, &config->defaults[0]); 206 if (option) 207 config->default_actions[option->code] = ACTION_DEFAULT; 208 return; 209 case SUPERSEDE: 210 option = parse_option_decl(cfile, &config->defaults[0]); 211 if (option) 212 config->default_actions[option->code] = 213 ACTION_SUPERSEDE; 214 return; 215 case APPEND: 216 option = parse_option_decl(cfile, &config->defaults[0]); 217 if (option) 218 config->default_actions[option->code] = ACTION_APPEND; 219 return; 220 case PREPEND: 221 option = parse_option_decl(cfile, &config->defaults[0]); 222 if (option) 223 config->default_actions[option->code] = ACTION_PREPEND; 224 return; 225 case MEDIA: 226 parse_string_list(cfile, &config->media, 1); 227 return; 228 case HARDWARE: 229 if (ip) 230 parse_hardware_param(cfile, &ip->hw_address); 231 else { 232 parse_warn("hardware address parameter %s", 233 "not allowed here."); 234 skip_to_semi(cfile); 235 } 236 return; 237 case REQUEST: 238 config->requested_option_count = 239 parse_option_list(cfile, config->requested_options); 240 return; 241 case REQUIRE: 242 memset(config->required_options, 0, 243 sizeof(config->required_options)); 244 parse_option_list(cfile, config->required_options); 245 return; 246 case TIMEOUT: 247 parse_lease_time(cfile, &config->timeout); 248 return; 249 case RETRY: 250 parse_lease_time(cfile, &config->retry_interval); 251 return; 252 case SELECT_TIMEOUT: 253 parse_lease_time(cfile, &config->select_interval); 254 return; 255 case REBOOT: 256 parse_lease_time(cfile, &config->reboot_timeout); 257 return; 258 case BACKOFF_CUTOFF: 259 parse_lease_time(cfile, &config->backoff_cutoff); 260 return; 261 case INITIAL_INTERVAL: 262 parse_lease_time(cfile, &config->initial_interval); 263 return; 264 case SCRIPT: 265 config->script_name = parse_string(cfile); 266 return; 267 case INTERFACE: 268 if (ip) 269 parse_warn("nested interface declaration."); 270 parse_interface_declaration(cfile, config); 271 return; 272 case LEASE: 273 parse_client_lease_statement(cfile, 1); 274 return; 275 case ALIAS: 276 parse_client_lease_statement(cfile, 2); 277 return; 278 case REJECT: 279 parse_reject_statement(cfile, config); 280 return; 281 default: 282 parse_warn("expecting a statement."); 283 skip_to_semi(cfile); 284 break; 285 } 286 token = next_token(&val, cfile); 287 if (token != SEMI) { 288 parse_warn("semicolon expected."); 289 skip_to_semi(cfile); 290 } 291} 292 293int 294parse_X(FILE *cfile, u_int8_t *buf, int max) 295{ 296 int token; 297 char *val; 298 int len; 299 300 token = peek_token(&val, cfile); 301 if (token == NUMBER_OR_NAME || token == NUMBER) { 302 len = 0; 303 do { 304 token = next_token(&val, cfile); 305 if (token != NUMBER && token != NUMBER_OR_NAME) { 306 parse_warn("expecting hexadecimal constant."); 307 skip_to_semi(cfile); 308 return (0); 309 } 310 convert_num(&buf[len], val, 16, 8); 311 if (len++ > max) { 312 parse_warn("hexadecimal constant too long."); 313 skip_to_semi(cfile); 314 return (0); 315 } 316 token = peek_token(&val, cfile); 317 if (token == COLON) 318 token = next_token(&val, cfile); 319 } while (token == COLON); 320 val = (char *)buf; 321 } else if (token == STRING) { 322 token = next_token(&val, cfile); 323 len = strlen(val); 324 if (len + 1 > max) { 325 parse_warn("string constant too long."); 326 skip_to_semi(cfile); 327 return (0); 328 } 329 memcpy(buf, val, len + 1); 330 } else { 331 parse_warn("expecting string or hexadecimal data"); 332 skip_to_semi(cfile); 333 return (0); 334 } 335 return (len); 336} 337 338/* 339 * option-list :== option_name | 340 * option_list COMMA option_name 341 */ 342int 343parse_option_list(FILE *cfile, u_int8_t *list) 344{ 345 int ix, i; 346 int token; 347 char *val; 348 349 ix = 0; 350 do { 351 token = next_token(&val, cfile); 352 if (!is_identifier(token)) { 353 parse_warn("expected option name."); 354 skip_to_semi(cfile); 355 return (0); 356 } 357 for (i = 0; i < 256; i++) 358 if (!strcasecmp(dhcp_options[i].name, val)) 359 break; 360 361 if (i == 256) { 362 parse_warn("%s: unexpected option name.", val); 363 skip_to_semi(cfile); 364 return (0); 365 } 366 list[ix++] = i; 367 if (ix == 256) { 368 parse_warn("%s: too many options.", val); 369 skip_to_semi(cfile); 370 return (0); 371 } 372 token = next_token(&val, cfile); 373 } while (token == COMMA); 374 if (token != SEMI) { 375 parse_warn("expecting semicolon."); 376 skip_to_semi(cfile); 377 return (0); 378 } 379 return (ix); 380} 381 382/* 383 * interface-declaration :== 384 * INTERFACE string LBRACE client-declarations RBRACE 385 */ 386void 387parse_interface_declaration(FILE *cfile, struct client_config *outer_config) 388{ 389 int token; 390 char *val; 391 struct interface_info *ip; 392 393 token = next_token(&val, cfile); 394 if (token != STRING) { 395 parse_warn("expecting interface name (in quotes)."); 396 skip_to_semi(cfile); 397 return; 398 } 399 400 ip = interface_or_dummy(val); 401 402 if (!ip->client) 403 make_client_state(ip); 404 405 if (!ip->client->config) 406 make_client_config(ip, outer_config); 407 408 token = next_token(&val, cfile); 409 if (token != LBRACE) { 410 parse_warn("expecting left brace."); 411 skip_to_semi(cfile); 412 return; 413 } 414 415 do { 416 token = peek_token(&val, cfile); 417 if (token == EOF) { 418 parse_warn("unterminated interface declaration."); 419 return; 420 } 421 if (token == RBRACE) 422 break; 423 parse_client_statement(cfile, ip, ip->client->config); 424 } while (1); 425 token = next_token(&val, cfile); 426} 427 428struct interface_info * 429interface_or_dummy(char *name) 430{ 431 struct interface_info *ip; 432 433 /* Find the interface (if any) that matches the name. */ 434 if (!strcmp(ifi->name, name)) 435 return (ifi); 436 437 /* If it's not a real interface, see if it's on the dummy list. */ 438 for (ip = dummy_interfaces; ip; ip = ip->next) 439 if (!strcmp(ip->name, name)) 440 return (ip); 441 442 /* 443 * If we didn't find an interface, make a dummy interface as a 444 * placeholder. 445 */ 446 ip = malloc(sizeof(*ip)); 447 if (!ip) 448 error("Insufficient memory to record interface %s", name); 449 memset(ip, 0, sizeof(*ip)); 450 strlcpy(ip->name, name, IFNAMSIZ); 451 ip->next = dummy_interfaces; 452 dummy_interfaces = ip; 453 return (ip); 454} 455 456void 457make_client_state(struct interface_info *ip) 458{ 459 ip->client = malloc(sizeof(*(ip->client))); 460 if (!ip->client) 461 error("no memory for state on %s", ip->name); 462 memset(ip->client, 0, sizeof(*(ip->client))); 463} 464 465void 466make_client_config(struct interface_info *ip, struct client_config *config) 467{ 468 ip->client->config = malloc(sizeof(struct client_config)); 469 if (!ip->client->config) 470 error("no memory for config for %s", ip->name); 471 memset(ip->client->config, 0, sizeof(*(ip->client->config))); 472 memcpy(ip->client->config, config, sizeof(*config)); 473} 474 475/* 476 * client-lease-statement :== 477 * RBRACE client-lease-declarations LBRACE 478 * 479 * client-lease-declarations :== 480 * <nil> | 481 * client-lease-declaration | 482 * client-lease-declarations client-lease-declaration 483 */ 484void 485parse_client_lease_statement(FILE *cfile, int is_static) 486{ 487 struct client_lease *lease, *lp, *pl; 488 struct interface_info *ip; 489 int token; 490 char *val; 491 492 token = next_token(&val, cfile); 493 if (token != LBRACE) { 494 parse_warn("expecting left brace."); 495 skip_to_semi(cfile); 496 return; 497 } 498 499 lease = malloc(sizeof(struct client_lease)); 500 if (!lease) 501 error("no memory for lease."); 502 memset(lease, 0, sizeof(*lease)); 503 lease->is_static = is_static; 504 505 ip = NULL; 506 507 do { 508 token = peek_token(&val, cfile); 509 if (token == EOF) { 510 parse_warn("unterminated lease declaration."); 511 return; 512 } 513 if (token == RBRACE) 514 break; 515 parse_client_lease_declaration(cfile, lease, &ip); 516 } while (1); 517 token = next_token(&val, cfile); 518 519 /* If the lease declaration didn't include an interface 520 * declaration that we recognized, it's of no use to us. 521 */ 522 if (!ip) { 523 free_client_lease(lease); 524 return; 525 } 526 527 /* Make sure there's a client state structure... */ 528 if (!ip->client) 529 make_client_state(ip); 530 531 /* If this is an alias lease, it doesn't need to be sorted in. */ 532 if (is_static == 2) { 533 ip->client->alias = lease; 534 return; 535 } 536 537 /* 538 * The new lease may supersede a lease that's not the active 539 * lease but is still on the lease list, so scan the lease list 540 * looking for a lease with the same address, and if we find it, 541 * toss it. 542 */ 543 pl = NULL; 544 for (lp = ip->client->leases; lp; lp = lp->next) { 545 if (lp->address.len == lease->address.len && 546 !memcmp(lp->address.iabuf, lease->address.iabuf, 547 lease->address.len)) { 548 if (pl) 549 pl->next = lp->next; 550 else 551 ip->client->leases = lp->next; 552 free_client_lease(lp); 553 break; 554 } 555 } 556 557 /* 558 * If this is a preloaded lease, just put it on the list of 559 * recorded leases - don't make it the active lease. 560 */ 561 if (is_static) { 562 lease->next = ip->client->leases; 563 ip->client->leases = lease; 564 return; 565 } 566 567 /* 568 * The last lease in the lease file on a particular interface is 569 * the active lease for that interface. Of course, we don't 570 * know what the last lease in the file is until we've parsed 571 * the whole file, so at this point, we assume that the lease we 572 * just parsed is the active lease for its interface. If 573 * there's already an active lease for the interface, and this 574 * lease is for the same ip address, then we just toss the old 575 * active lease and replace it with this one. If this lease is 576 * for a different address, then if the old active lease has 577 * expired, we dump it; if not, we put it on the list of leases 578 * for this interface which are still valid but no longer 579 * active. 580 */ 581 if (ip->client->active) { 582 if (ip->client->active->expiry < cur_time) 583 free_client_lease(ip->client->active); 584 else if (ip->client->active->address.len == 585 lease->address.len && 586 !memcmp(ip->client->active->address.iabuf, 587 lease->address.iabuf, lease->address.len)) 588 free_client_lease(ip->client->active); 589 else { 590 ip->client->active->next = ip->client->leases; 591 ip->client->leases = ip->client->active; 592 } 593 } 594 ip->client->active = lease; 595 596 /* Phew. */ 597} 598 599/* 600 * client-lease-declaration :== 601 * BOOTP | 602 * INTERFACE string | 603 * FIXED_ADDR ip_address | 604 * FILENAME string | 605 * SERVER_NAME string | 606 * OPTION option-decl | 607 * RENEW time-decl | 608 * REBIND time-decl | 609 * EXPIRE time-decl 610 */ 611void 612parse_client_lease_declaration(FILE *cfile, struct client_lease *lease, 613 struct interface_info **ipp) 614{ 615 int token; 616 char *val; 617 struct interface_info *ip; 618 619 switch (next_token(&val, cfile)) { 620 case BOOTP: 621 lease->is_bootp = 1; 622 break; 623 case INTERFACE: 624 token = next_token(&val, cfile); 625 if (token != STRING) { 626 parse_warn("expecting interface name (in quotes)."); 627 skip_to_semi(cfile); 628 break; 629 } 630 ip = interface_or_dummy(val); 631 *ipp = ip; 632 break; 633 case FIXED_ADDR: 634 if (!parse_ip_addr(cfile, &lease->address)) 635 return; 636 break; 637 case MEDIUM: 638 parse_string_list(cfile, &lease->medium, 0); 639 return; 640 case FILENAME: 641 lease->filename = parse_string(cfile); 642 return; 643 case SERVER_NAME: 644 lease->server_name = parse_string(cfile); 645 return; 646 case RENEW: 647 lease->renewal = parse_date(cfile); 648 return; 649 case REBIND: 650 lease->rebind = parse_date(cfile); 651 return; 652 case EXPIRE: 653 lease->expiry = parse_date(cfile); 654 return; 655 case OPTION: 656 parse_option_decl(cfile, lease->options); 657 return; 658 default: 659 parse_warn("expecting lease declaration."); 660 skip_to_semi(cfile); 661 break; 662 } 663 token = next_token(&val, cfile); 664 if (token != SEMI) { 665 parse_warn("expecting semicolon."); 666 skip_to_semi(cfile); 667 } 668} 669 670struct option * 671parse_option_decl(FILE *cfile, struct option_data *options) 672{ 673 char *val; 674 int token; 675 u_int8_t buf[4]; 676 u_int8_t hunkbuf[1024]; 677 int hunkix = 0; 678 char *vendor; 679 char *fmt; 680 struct universe *universe; 681 struct option *option; 682 struct iaddr ip_addr; 683 u_int8_t *dp; 684 int len; 685 int nul_term = 0; 686 687 token = next_token(&val, cfile); 688 if (!is_identifier(token)) { 689 parse_warn("expecting identifier after option keyword."); 690 if (token != SEMI) 691 skip_to_semi(cfile); 692 return (NULL); 693 } 694 if ((vendor = strdup(val)) == NULL) 695 error("no memory for vendor information."); 696 697 token = peek_token(&val, cfile); 698 if (token == DOT) { 699 /* Go ahead and take the DOT token... */ 700 token = next_token(&val, cfile); 701 702 /* The next token should be an identifier... */ 703 token = next_token(&val, cfile); 704 if (!is_identifier(token)) { 705 parse_warn("expecting identifier after '.'"); 706 if (token != SEMI) 707 skip_to_semi(cfile); 708 return (NULL); 709 } 710 711 /* Look up the option name hash table for the specified 712 vendor. */ 713 universe = ((struct universe *)hash_lookup(&universe_hash, 714 (unsigned char *)vendor, 0)); 715 /* If it's not there, we can't parse the rest of the 716 declaration. */ 717 if (!universe) { 718 parse_warn("no vendor named %s.", vendor); 719 skip_to_semi(cfile); 720 return (NULL); 721 } 722 } else { 723 /* Use the default hash table, which contains all the 724 standard dhcp option names. */ 725 val = vendor; 726 universe = &dhcp_universe; 727 } 728 729 /* Look up the actual option info... */ 730 option = (struct option *)hash_lookup(universe->hash, 731 (unsigned char *)val, 0); 732 733 /* If we didn't get an option structure, it's an undefined option. */ 734 if (!option) { 735 if (val == vendor) 736 parse_warn("no option named %s", val); 737 else 738 parse_warn("no option named %s for vendor %s", 739 val, vendor); 740 skip_to_semi(cfile); 741 return (NULL); 742 } 743 744 /* Free the initial identifier token. */ 745 free(vendor); 746 747 /* Parse the option data... */ 748 do { 749 for (fmt = option->format; *fmt; fmt++) { 750 if (*fmt == 'A') 751 break; 752 switch (*fmt) { 753 case 'X': 754 len = parse_X(cfile, &hunkbuf[hunkix], 755 sizeof(hunkbuf) - hunkix); 756 hunkix += len; 757 break; 758 case 't': /* Text string... */ 759 token = next_token(&val, cfile); 760 if (token != STRING) { 761 parse_warn("expecting string."); 762 skip_to_semi(cfile); 763 return (NULL); 764 } 765 len = strlen(val); 766 if (hunkix + len + 1 > sizeof(hunkbuf)) { 767 parse_warn("option data buffer %s", 768 "overflow"); 769 skip_to_semi(cfile); 770 return (NULL); 771 } 772 memcpy(&hunkbuf[hunkix], val, len + 1); 773 nul_term = 1; 774 hunkix += len; 775 break; 776 case 'I': /* IP address. */ 777 if (!parse_ip_addr(cfile, &ip_addr)) 778 return (NULL); 779 len = ip_addr.len; 780 dp = ip_addr.iabuf; 781alloc: 782 if (hunkix + len > sizeof(hunkbuf)) { 783 parse_warn("option data buffer " 784 "overflow"); 785 skip_to_semi(cfile); 786 return (NULL); 787 } 788 memcpy(&hunkbuf[hunkix], dp, len); 789 hunkix += len; 790 break; 791 case 'L': /* Unsigned 32-bit integer... */ 792 case 'l': /* Signed 32-bit integer... */ 793 token = next_token(&val, cfile); 794 if (token != NUMBER) { 795need_number: 796 parse_warn("expecting number."); 797 if (token != SEMI) 798 skip_to_semi(cfile); 799 return (NULL); 800 } 801 convert_num(buf, val, 0, 32); 802 len = 4; 803 dp = buf; 804 goto alloc; 805 case 's': /* Signed 16-bit integer. */ 806 case 'S': /* Unsigned 16-bit integer. */ 807 token = next_token(&val, cfile); 808 if (token != NUMBER) 809 goto need_number; 810 convert_num(buf, val, 0, 16); 811 len = 2; 812 dp = buf; 813 goto alloc; 814 case 'b': /* Signed 8-bit integer. */ 815 case 'B': /* Unsigned 8-bit integer. */ 816 token = next_token(&val, cfile); 817 if (token != NUMBER) 818 goto need_number; 819 convert_num(buf, val, 0, 8); 820 len = 1; 821 dp = buf; 822 goto alloc; 823 case 'f': /* Boolean flag. */ 824 token = next_token(&val, cfile); 825 if (!is_identifier(token)) { 826 parse_warn("expecting identifier."); 827bad_flag: 828 if (token != SEMI) 829 skip_to_semi(cfile); 830 return (NULL); 831 } 832 if (!strcasecmp(val, "true") || 833 !strcasecmp(val, "on")) 834 buf[0] = 1; 835 else if (!strcasecmp(val, "false") || 836 !strcasecmp(val, "off")) 837 buf[0] = 0; 838 else { 839 parse_warn("expecting boolean."); 840 goto bad_flag; 841 } 842 len = 1; 843 dp = buf; 844 goto alloc; 845 default: 846 warning("Bad format %c in parse_option_param.", 847 *fmt); 848 skip_to_semi(cfile); 849 return (NULL); 850 } 851 } 852 token = next_token(&val, cfile); 853 } while (*fmt == 'A' && token == COMMA); 854 855 if (token != SEMI) { 856 parse_warn("semicolon expected."); 857 skip_to_semi(cfile); 858 return (NULL); 859 } 860 861 options[option->code].data = malloc(hunkix + nul_term); 862 if (!options[option->code].data) 863 error("out of memory allocating option data."); 864 memcpy(options[option->code].data, hunkbuf, hunkix + nul_term); 865 options[option->code].len = hunkix; 866 return (option); 867} 868 869void 870parse_string_list(FILE *cfile, struct string_list **lp, int multiple) 871{ 872 int token; 873 char *val; 874 struct string_list *cur, *tmp; 875 876 /* Find the last medium in the media list. */ 877 if (*lp) 878 for (cur = *lp; cur->next; cur = cur->next) 879 ; /* nothing */ 880 else 881 cur = NULL; 882 883 do { 884 token = next_token(&val, cfile); 885 if (token != STRING) { 886 parse_warn("Expecting media options."); 887 skip_to_semi(cfile); 888 return; 889 } 890 891 tmp = new_string_list(strlen(val) + 1); 892 if (tmp == NULL) 893 error("no memory for string list entry."); 894 strlcpy(tmp->string, val, strlen(val) + 1); 895 tmp->next = NULL; 896 897 /* Store this medium at the end of the media list. */ 898 if (cur) 899 cur->next = tmp; 900 else 901 *lp = tmp; 902 cur = tmp; 903 904 token = next_token(&val, cfile); 905 } while (multiple && token == COMMA); 906 907 if (token != SEMI) { 908 parse_warn("expecting semicolon."); 909 skip_to_semi(cfile); 910 } 911} 912 913void 914parse_reject_statement(FILE *cfile, struct client_config *config) 915{ 916 int token; 917 char *val; 918 struct iaddr addr; 919 struct iaddrlist *list; 920 921 do { 922 if (!parse_ip_addr(cfile, &addr)) { 923 parse_warn("expecting IP address."); 924 skip_to_semi(cfile); 925 return; 926 } 927 928 list = malloc(sizeof(struct iaddrlist)); 929 if (!list) 930 error("no memory for reject list!"); 931 932 list->addr = addr; 933 list->next = config->reject_list; 934 config->reject_list = list; 935 936 token = next_token(&val, cfile); 937 } while (token == COMMA); 938 939 if (token != SEMI) { 940 parse_warn("expecting semicolon."); 941 skip_to_semi(cfile); 942 } 943}
| 105 106 if ((cfile = fopen(path_dhclient_conf, "r")) != NULL) { 107 do { 108 token = peek_token(&val, cfile); 109 if (token == EOF) 110 break; 111 parse_client_statement(cfile, NULL, &top_level_config); 112 } while (1); 113 token = next_token(&val, cfile); /* Clear the peek buffer */ 114 fclose(cfile); 115 } 116 117 /* 118 * Set up state and config structures for clients that don't 119 * have per-interface configuration declarations. 120 */ 121 config = NULL; 122 if (!ifi->client) { 123 ifi->client = malloc(sizeof(struct client_state)); 124 if (!ifi->client) 125 error("no memory for client state."); 126 memset(ifi->client, 0, sizeof(*(ifi->client))); 127 } 128 if (!ifi->client->config) { 129 if (!config) { 130 config = malloc(sizeof(struct client_config)); 131 if (!config) 132 error("no memory for client config."); 133 memcpy(config, &top_level_config, 134 sizeof(top_level_config)); 135 } 136 ifi->client->config = config; 137 } 138 139 return (!warnings_occurred); 140} 141 142/* 143 * lease-file :== client-lease-statements EOF 144 * client-lease-statements :== <nil> 145 * | client-lease-statements LEASE client-lease-statement 146 */ 147void 148read_client_leases(void) 149{ 150 FILE *cfile; 151 char *val; 152 int token; 153 154 new_parse(path_dhclient_db); 155 156 /* Open the lease file. If we can't open it, just return - 157 we can safely trust the server to remember our state. */ 158 if ((cfile = fopen(path_dhclient_db, "r")) == NULL) 159 return; 160 do { 161 token = next_token(&val, cfile); 162 if (token == EOF) 163 break; 164 if (token != LEASE) { 165 warning("Corrupt lease file - possible data loss!"); 166 skip_to_semi(cfile); 167 break; 168 } else 169 parse_client_lease_statement(cfile, 0); 170 171 } while (1); 172 fclose(cfile); 173} 174 175/* 176 * client-declaration :== 177 * SEND option-decl | 178 * DEFAULT option-decl | 179 * SUPERSEDE option-decl | 180 * PREPEND option-decl | 181 * APPEND option-decl | 182 * hardware-declaration | 183 * REQUEST option-list | 184 * REQUIRE option-list | 185 * TIMEOUT number | 186 * RETRY number | 187 * REBOOT number | 188 * SELECT_TIMEOUT number | 189 * SCRIPT string | 190 * interface-declaration | 191 * LEASE client-lease-statement | 192 * ALIAS client-lease-statement 193 */ 194void 195parse_client_statement(FILE *cfile, struct interface_info *ip, 196 struct client_config *config) 197{ 198 int token; 199 char *val; 200 struct option *option; 201 202 switch (next_token(&val, cfile)) { 203 case SEND: 204 parse_option_decl(cfile, &config->send_options[0]); 205 return; 206 case DEFAULT: 207 option = parse_option_decl(cfile, &config->defaults[0]); 208 if (option) 209 config->default_actions[option->code] = ACTION_DEFAULT; 210 return; 211 case SUPERSEDE: 212 option = parse_option_decl(cfile, &config->defaults[0]); 213 if (option) 214 config->default_actions[option->code] = 215 ACTION_SUPERSEDE; 216 return; 217 case APPEND: 218 option = parse_option_decl(cfile, &config->defaults[0]); 219 if (option) 220 config->default_actions[option->code] = ACTION_APPEND; 221 return; 222 case PREPEND: 223 option = parse_option_decl(cfile, &config->defaults[0]); 224 if (option) 225 config->default_actions[option->code] = ACTION_PREPEND; 226 return; 227 case MEDIA: 228 parse_string_list(cfile, &config->media, 1); 229 return; 230 case HARDWARE: 231 if (ip) 232 parse_hardware_param(cfile, &ip->hw_address); 233 else { 234 parse_warn("hardware address parameter %s", 235 "not allowed here."); 236 skip_to_semi(cfile); 237 } 238 return; 239 case REQUEST: 240 config->requested_option_count = 241 parse_option_list(cfile, config->requested_options); 242 return; 243 case REQUIRE: 244 memset(config->required_options, 0, 245 sizeof(config->required_options)); 246 parse_option_list(cfile, config->required_options); 247 return; 248 case TIMEOUT: 249 parse_lease_time(cfile, &config->timeout); 250 return; 251 case RETRY: 252 parse_lease_time(cfile, &config->retry_interval); 253 return; 254 case SELECT_TIMEOUT: 255 parse_lease_time(cfile, &config->select_interval); 256 return; 257 case REBOOT: 258 parse_lease_time(cfile, &config->reboot_timeout); 259 return; 260 case BACKOFF_CUTOFF: 261 parse_lease_time(cfile, &config->backoff_cutoff); 262 return; 263 case INITIAL_INTERVAL: 264 parse_lease_time(cfile, &config->initial_interval); 265 return; 266 case SCRIPT: 267 config->script_name = parse_string(cfile); 268 return; 269 case INTERFACE: 270 if (ip) 271 parse_warn("nested interface declaration."); 272 parse_interface_declaration(cfile, config); 273 return; 274 case LEASE: 275 parse_client_lease_statement(cfile, 1); 276 return; 277 case ALIAS: 278 parse_client_lease_statement(cfile, 2); 279 return; 280 case REJECT: 281 parse_reject_statement(cfile, config); 282 return; 283 default: 284 parse_warn("expecting a statement."); 285 skip_to_semi(cfile); 286 break; 287 } 288 token = next_token(&val, cfile); 289 if (token != SEMI) { 290 parse_warn("semicolon expected."); 291 skip_to_semi(cfile); 292 } 293} 294 295int 296parse_X(FILE *cfile, u_int8_t *buf, int max) 297{ 298 int token; 299 char *val; 300 int len; 301 302 token = peek_token(&val, cfile); 303 if (token == NUMBER_OR_NAME || token == NUMBER) { 304 len = 0; 305 do { 306 token = next_token(&val, cfile); 307 if (token != NUMBER && token != NUMBER_OR_NAME) { 308 parse_warn("expecting hexadecimal constant."); 309 skip_to_semi(cfile); 310 return (0); 311 } 312 convert_num(&buf[len], val, 16, 8); 313 if (len++ > max) { 314 parse_warn("hexadecimal constant too long."); 315 skip_to_semi(cfile); 316 return (0); 317 } 318 token = peek_token(&val, cfile); 319 if (token == COLON) 320 token = next_token(&val, cfile); 321 } while (token == COLON); 322 val = (char *)buf; 323 } else if (token == STRING) { 324 token = next_token(&val, cfile); 325 len = strlen(val); 326 if (len + 1 > max) { 327 parse_warn("string constant too long."); 328 skip_to_semi(cfile); 329 return (0); 330 } 331 memcpy(buf, val, len + 1); 332 } else { 333 parse_warn("expecting string or hexadecimal data"); 334 skip_to_semi(cfile); 335 return (0); 336 } 337 return (len); 338} 339 340/* 341 * option-list :== option_name | 342 * option_list COMMA option_name 343 */ 344int 345parse_option_list(FILE *cfile, u_int8_t *list) 346{ 347 int ix, i; 348 int token; 349 char *val; 350 351 ix = 0; 352 do { 353 token = next_token(&val, cfile); 354 if (!is_identifier(token)) { 355 parse_warn("expected option name."); 356 skip_to_semi(cfile); 357 return (0); 358 } 359 for (i = 0; i < 256; i++) 360 if (!strcasecmp(dhcp_options[i].name, val)) 361 break; 362 363 if (i == 256) { 364 parse_warn("%s: unexpected option name.", val); 365 skip_to_semi(cfile); 366 return (0); 367 } 368 list[ix++] = i; 369 if (ix == 256) { 370 parse_warn("%s: too many options.", val); 371 skip_to_semi(cfile); 372 return (0); 373 } 374 token = next_token(&val, cfile); 375 } while (token == COMMA); 376 if (token != SEMI) { 377 parse_warn("expecting semicolon."); 378 skip_to_semi(cfile); 379 return (0); 380 } 381 return (ix); 382} 383 384/* 385 * interface-declaration :== 386 * INTERFACE string LBRACE client-declarations RBRACE 387 */ 388void 389parse_interface_declaration(FILE *cfile, struct client_config *outer_config) 390{ 391 int token; 392 char *val; 393 struct interface_info *ip; 394 395 token = next_token(&val, cfile); 396 if (token != STRING) { 397 parse_warn("expecting interface name (in quotes)."); 398 skip_to_semi(cfile); 399 return; 400 } 401 402 ip = interface_or_dummy(val); 403 404 if (!ip->client) 405 make_client_state(ip); 406 407 if (!ip->client->config) 408 make_client_config(ip, outer_config); 409 410 token = next_token(&val, cfile); 411 if (token != LBRACE) { 412 parse_warn("expecting left brace."); 413 skip_to_semi(cfile); 414 return; 415 } 416 417 do { 418 token = peek_token(&val, cfile); 419 if (token == EOF) { 420 parse_warn("unterminated interface declaration."); 421 return; 422 } 423 if (token == RBRACE) 424 break; 425 parse_client_statement(cfile, ip, ip->client->config); 426 } while (1); 427 token = next_token(&val, cfile); 428} 429 430struct interface_info * 431interface_or_dummy(char *name) 432{ 433 struct interface_info *ip; 434 435 /* Find the interface (if any) that matches the name. */ 436 if (!strcmp(ifi->name, name)) 437 return (ifi); 438 439 /* If it's not a real interface, see if it's on the dummy list. */ 440 for (ip = dummy_interfaces; ip; ip = ip->next) 441 if (!strcmp(ip->name, name)) 442 return (ip); 443 444 /* 445 * If we didn't find an interface, make a dummy interface as a 446 * placeholder. 447 */ 448 ip = malloc(sizeof(*ip)); 449 if (!ip) 450 error("Insufficient memory to record interface %s", name); 451 memset(ip, 0, sizeof(*ip)); 452 strlcpy(ip->name, name, IFNAMSIZ); 453 ip->next = dummy_interfaces; 454 dummy_interfaces = ip; 455 return (ip); 456} 457 458void 459make_client_state(struct interface_info *ip) 460{ 461 ip->client = malloc(sizeof(*(ip->client))); 462 if (!ip->client) 463 error("no memory for state on %s", ip->name); 464 memset(ip->client, 0, sizeof(*(ip->client))); 465} 466 467void 468make_client_config(struct interface_info *ip, struct client_config *config) 469{ 470 ip->client->config = malloc(sizeof(struct client_config)); 471 if (!ip->client->config) 472 error("no memory for config for %s", ip->name); 473 memset(ip->client->config, 0, sizeof(*(ip->client->config))); 474 memcpy(ip->client->config, config, sizeof(*config)); 475} 476 477/* 478 * client-lease-statement :== 479 * RBRACE client-lease-declarations LBRACE 480 * 481 * client-lease-declarations :== 482 * <nil> | 483 * client-lease-declaration | 484 * client-lease-declarations client-lease-declaration 485 */ 486void 487parse_client_lease_statement(FILE *cfile, int is_static) 488{ 489 struct client_lease *lease, *lp, *pl; 490 struct interface_info *ip; 491 int token; 492 char *val; 493 494 token = next_token(&val, cfile); 495 if (token != LBRACE) { 496 parse_warn("expecting left brace."); 497 skip_to_semi(cfile); 498 return; 499 } 500 501 lease = malloc(sizeof(struct client_lease)); 502 if (!lease) 503 error("no memory for lease."); 504 memset(lease, 0, sizeof(*lease)); 505 lease->is_static = is_static; 506 507 ip = NULL; 508 509 do { 510 token = peek_token(&val, cfile); 511 if (token == EOF) { 512 parse_warn("unterminated lease declaration."); 513 return; 514 } 515 if (token == RBRACE) 516 break; 517 parse_client_lease_declaration(cfile, lease, &ip); 518 } while (1); 519 token = next_token(&val, cfile); 520 521 /* If the lease declaration didn't include an interface 522 * declaration that we recognized, it's of no use to us. 523 */ 524 if (!ip) { 525 free_client_lease(lease); 526 return; 527 } 528 529 /* Make sure there's a client state structure... */ 530 if (!ip->client) 531 make_client_state(ip); 532 533 /* If this is an alias lease, it doesn't need to be sorted in. */ 534 if (is_static == 2) { 535 ip->client->alias = lease; 536 return; 537 } 538 539 /* 540 * The new lease may supersede a lease that's not the active 541 * lease but is still on the lease list, so scan the lease list 542 * looking for a lease with the same address, and if we find it, 543 * toss it. 544 */ 545 pl = NULL; 546 for (lp = ip->client->leases; lp; lp = lp->next) { 547 if (lp->address.len == lease->address.len && 548 !memcmp(lp->address.iabuf, lease->address.iabuf, 549 lease->address.len)) { 550 if (pl) 551 pl->next = lp->next; 552 else 553 ip->client->leases = lp->next; 554 free_client_lease(lp); 555 break; 556 } 557 } 558 559 /* 560 * If this is a preloaded lease, just put it on the list of 561 * recorded leases - don't make it the active lease. 562 */ 563 if (is_static) { 564 lease->next = ip->client->leases; 565 ip->client->leases = lease; 566 return; 567 } 568 569 /* 570 * The last lease in the lease file on a particular interface is 571 * the active lease for that interface. Of course, we don't 572 * know what the last lease in the file is until we've parsed 573 * the whole file, so at this point, we assume that the lease we 574 * just parsed is the active lease for its interface. If 575 * there's already an active lease for the interface, and this 576 * lease is for the same ip address, then we just toss the old 577 * active lease and replace it with this one. If this lease is 578 * for a different address, then if the old active lease has 579 * expired, we dump it; if not, we put it on the list of leases 580 * for this interface which are still valid but no longer 581 * active. 582 */ 583 if (ip->client->active) { 584 if (ip->client->active->expiry < cur_time) 585 free_client_lease(ip->client->active); 586 else if (ip->client->active->address.len == 587 lease->address.len && 588 !memcmp(ip->client->active->address.iabuf, 589 lease->address.iabuf, lease->address.len)) 590 free_client_lease(ip->client->active); 591 else { 592 ip->client->active->next = ip->client->leases; 593 ip->client->leases = ip->client->active; 594 } 595 } 596 ip->client->active = lease; 597 598 /* Phew. */ 599} 600 601/* 602 * client-lease-declaration :== 603 * BOOTP | 604 * INTERFACE string | 605 * FIXED_ADDR ip_address | 606 * FILENAME string | 607 * SERVER_NAME string | 608 * OPTION option-decl | 609 * RENEW time-decl | 610 * REBIND time-decl | 611 * EXPIRE time-decl 612 */ 613void 614parse_client_lease_declaration(FILE *cfile, struct client_lease *lease, 615 struct interface_info **ipp) 616{ 617 int token; 618 char *val; 619 struct interface_info *ip; 620 621 switch (next_token(&val, cfile)) { 622 case BOOTP: 623 lease->is_bootp = 1; 624 break; 625 case INTERFACE: 626 token = next_token(&val, cfile); 627 if (token != STRING) { 628 parse_warn("expecting interface name (in quotes)."); 629 skip_to_semi(cfile); 630 break; 631 } 632 ip = interface_or_dummy(val); 633 *ipp = ip; 634 break; 635 case FIXED_ADDR: 636 if (!parse_ip_addr(cfile, &lease->address)) 637 return; 638 break; 639 case MEDIUM: 640 parse_string_list(cfile, &lease->medium, 0); 641 return; 642 case FILENAME: 643 lease->filename = parse_string(cfile); 644 return; 645 case SERVER_NAME: 646 lease->server_name = parse_string(cfile); 647 return; 648 case RENEW: 649 lease->renewal = parse_date(cfile); 650 return; 651 case REBIND: 652 lease->rebind = parse_date(cfile); 653 return; 654 case EXPIRE: 655 lease->expiry = parse_date(cfile); 656 return; 657 case OPTION: 658 parse_option_decl(cfile, lease->options); 659 return; 660 default: 661 parse_warn("expecting lease declaration."); 662 skip_to_semi(cfile); 663 break; 664 } 665 token = next_token(&val, cfile); 666 if (token != SEMI) { 667 parse_warn("expecting semicolon."); 668 skip_to_semi(cfile); 669 } 670} 671 672struct option * 673parse_option_decl(FILE *cfile, struct option_data *options) 674{ 675 char *val; 676 int token; 677 u_int8_t buf[4]; 678 u_int8_t hunkbuf[1024]; 679 int hunkix = 0; 680 char *vendor; 681 char *fmt; 682 struct universe *universe; 683 struct option *option; 684 struct iaddr ip_addr; 685 u_int8_t *dp; 686 int len; 687 int nul_term = 0; 688 689 token = next_token(&val, cfile); 690 if (!is_identifier(token)) { 691 parse_warn("expecting identifier after option keyword."); 692 if (token != SEMI) 693 skip_to_semi(cfile); 694 return (NULL); 695 } 696 if ((vendor = strdup(val)) == NULL) 697 error("no memory for vendor information."); 698 699 token = peek_token(&val, cfile); 700 if (token == DOT) { 701 /* Go ahead and take the DOT token... */ 702 token = next_token(&val, cfile); 703 704 /* The next token should be an identifier... */ 705 token = next_token(&val, cfile); 706 if (!is_identifier(token)) { 707 parse_warn("expecting identifier after '.'"); 708 if (token != SEMI) 709 skip_to_semi(cfile); 710 return (NULL); 711 } 712 713 /* Look up the option name hash table for the specified 714 vendor. */ 715 universe = ((struct universe *)hash_lookup(&universe_hash, 716 (unsigned char *)vendor, 0)); 717 /* If it's not there, we can't parse the rest of the 718 declaration. */ 719 if (!universe) { 720 parse_warn("no vendor named %s.", vendor); 721 skip_to_semi(cfile); 722 return (NULL); 723 } 724 } else { 725 /* Use the default hash table, which contains all the 726 standard dhcp option names. */ 727 val = vendor; 728 universe = &dhcp_universe; 729 } 730 731 /* Look up the actual option info... */ 732 option = (struct option *)hash_lookup(universe->hash, 733 (unsigned char *)val, 0); 734 735 /* If we didn't get an option structure, it's an undefined option. */ 736 if (!option) { 737 if (val == vendor) 738 parse_warn("no option named %s", val); 739 else 740 parse_warn("no option named %s for vendor %s", 741 val, vendor); 742 skip_to_semi(cfile); 743 return (NULL); 744 } 745 746 /* Free the initial identifier token. */ 747 free(vendor); 748 749 /* Parse the option data... */ 750 do { 751 for (fmt = option->format; *fmt; fmt++) { 752 if (*fmt == 'A') 753 break; 754 switch (*fmt) { 755 case 'X': 756 len = parse_X(cfile, &hunkbuf[hunkix], 757 sizeof(hunkbuf) - hunkix); 758 hunkix += len; 759 break; 760 case 't': /* Text string... */ 761 token = next_token(&val, cfile); 762 if (token != STRING) { 763 parse_warn("expecting string."); 764 skip_to_semi(cfile); 765 return (NULL); 766 } 767 len = strlen(val); 768 if (hunkix + len + 1 > sizeof(hunkbuf)) { 769 parse_warn("option data buffer %s", 770 "overflow"); 771 skip_to_semi(cfile); 772 return (NULL); 773 } 774 memcpy(&hunkbuf[hunkix], val, len + 1); 775 nul_term = 1; 776 hunkix += len; 777 break; 778 case 'I': /* IP address. */ 779 if (!parse_ip_addr(cfile, &ip_addr)) 780 return (NULL); 781 len = ip_addr.len; 782 dp = ip_addr.iabuf; 783alloc: 784 if (hunkix + len > sizeof(hunkbuf)) { 785 parse_warn("option data buffer " 786 "overflow"); 787 skip_to_semi(cfile); 788 return (NULL); 789 } 790 memcpy(&hunkbuf[hunkix], dp, len); 791 hunkix += len; 792 break; 793 case 'L': /* Unsigned 32-bit integer... */ 794 case 'l': /* Signed 32-bit integer... */ 795 token = next_token(&val, cfile); 796 if (token != NUMBER) { 797need_number: 798 parse_warn("expecting number."); 799 if (token != SEMI) 800 skip_to_semi(cfile); 801 return (NULL); 802 } 803 convert_num(buf, val, 0, 32); 804 len = 4; 805 dp = buf; 806 goto alloc; 807 case 's': /* Signed 16-bit integer. */ 808 case 'S': /* Unsigned 16-bit integer. */ 809 token = next_token(&val, cfile); 810 if (token != NUMBER) 811 goto need_number; 812 convert_num(buf, val, 0, 16); 813 len = 2; 814 dp = buf; 815 goto alloc; 816 case 'b': /* Signed 8-bit integer. */ 817 case 'B': /* Unsigned 8-bit integer. */ 818 token = next_token(&val, cfile); 819 if (token != NUMBER) 820 goto need_number; 821 convert_num(buf, val, 0, 8); 822 len = 1; 823 dp = buf; 824 goto alloc; 825 case 'f': /* Boolean flag. */ 826 token = next_token(&val, cfile); 827 if (!is_identifier(token)) { 828 parse_warn("expecting identifier."); 829bad_flag: 830 if (token != SEMI) 831 skip_to_semi(cfile); 832 return (NULL); 833 } 834 if (!strcasecmp(val, "true") || 835 !strcasecmp(val, "on")) 836 buf[0] = 1; 837 else if (!strcasecmp(val, "false") || 838 !strcasecmp(val, "off")) 839 buf[0] = 0; 840 else { 841 parse_warn("expecting boolean."); 842 goto bad_flag; 843 } 844 len = 1; 845 dp = buf; 846 goto alloc; 847 default: 848 warning("Bad format %c in parse_option_param.", 849 *fmt); 850 skip_to_semi(cfile); 851 return (NULL); 852 } 853 } 854 token = next_token(&val, cfile); 855 } while (*fmt == 'A' && token == COMMA); 856 857 if (token != SEMI) { 858 parse_warn("semicolon expected."); 859 skip_to_semi(cfile); 860 return (NULL); 861 } 862 863 options[option->code].data = malloc(hunkix + nul_term); 864 if (!options[option->code].data) 865 error("out of memory allocating option data."); 866 memcpy(options[option->code].data, hunkbuf, hunkix + nul_term); 867 options[option->code].len = hunkix; 868 return (option); 869} 870 871void 872parse_string_list(FILE *cfile, struct string_list **lp, int multiple) 873{ 874 int token; 875 char *val; 876 struct string_list *cur, *tmp; 877 878 /* Find the last medium in the media list. */ 879 if (*lp) 880 for (cur = *lp; cur->next; cur = cur->next) 881 ; /* nothing */ 882 else 883 cur = NULL; 884 885 do { 886 token = next_token(&val, cfile); 887 if (token != STRING) { 888 parse_warn("Expecting media options."); 889 skip_to_semi(cfile); 890 return; 891 } 892 893 tmp = new_string_list(strlen(val) + 1); 894 if (tmp == NULL) 895 error("no memory for string list entry."); 896 strlcpy(tmp->string, val, strlen(val) + 1); 897 tmp->next = NULL; 898 899 /* Store this medium at the end of the media list. */ 900 if (cur) 901 cur->next = tmp; 902 else 903 *lp = tmp; 904 cur = tmp; 905 906 token = next_token(&val, cfile); 907 } while (multiple && token == COMMA); 908 909 if (token != SEMI) { 910 parse_warn("expecting semicolon."); 911 skip_to_semi(cfile); 912 } 913} 914 915void 916parse_reject_statement(FILE *cfile, struct client_config *config) 917{ 918 int token; 919 char *val; 920 struct iaddr addr; 921 struct iaddrlist *list; 922 923 do { 924 if (!parse_ip_addr(cfile, &addr)) { 925 parse_warn("expecting IP address."); 926 skip_to_semi(cfile); 927 return; 928 } 929 930 list = malloc(sizeof(struct iaddrlist)); 931 if (!list) 932 error("no memory for reject list!"); 933 934 list->addr = addr; 935 list->next = config->reject_list; 936 config->reject_list = list; 937 938 token = next_token(&val, cfile); 939 } while (token == COMMA); 940 941 if (token != SEMI) { 942 parse_warn("expecting semicolon."); 943 skip_to_semi(cfile); 944 } 945}
|