1 /* $OpenBSD: clparse.c,v 1.18 2004/09/15 18:15:18 henning Exp $ */ 2 3 /* Parser for dhclient config and lease files... */ 4 5 /*- 6 * SPDX-License-Identifier: BSD-3-Clause 7 * 8 * Copyright (c) 1997 The Internet Software Consortium. 9 * All rights reserved. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 15 * 1. Redistributions of source code must retain the above copyright 16 * notice, this list of conditions and the following disclaimer. 17 * 2. Redistributions in binary form must reproduce the above copyright 18 * notice, this list of conditions and the following disclaimer in the 19 * documentation and/or other materials provided with the distribution. 20 * 3. Neither the name of The Internet Software Consortium nor the names 21 * of its contributors may be used to endorse or promote products derived 22 * from this software without specific prior written permission. 23 * 24 * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND 25 * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, 26 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 27 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 28 * DISCLAIMED. IN NO EVENT SHALL THE INTERNET SOFTWARE CONSORTIUM OR 29 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 30 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 31 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF 32 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 33 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 34 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 35 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 36 * SUCH DAMAGE. 37 * 38 * This software has been written for the Internet Software Consortium 39 * by Ted Lemon <mellon@fugue.com> in cooperation with Vixie 40 * Enterprises. To learn more about the Internet Software Consortium, 41 * see ``http://www.vix.com/isc''. To learn more about Vixie 42 * Enterprises, see ``http://www.vix.com''. 43 */ 44 45 #include <sys/cdefs.h> 46 #include "dhcpd.h" 47 #include "dhctoken.h" 48 49 struct client_config top_level_config; 50 static struct interface_info *dummy_interfaces; 51 52 static char client_script_name[] = "/sbin/dhclient-script"; 53 54 /* 55 * Options the user ignores must not be asked for either. 56 * This matters for the IPv6-Only Preferred option. 57 */ 58 static void 59 unrequest_ignored_options(struct client_config *config) 60 { 61 bool ignored[256] = {}; 62 int i, n; 63 64 for (i = 0; config->ignored_options[i] != 0; i++) 65 ignored[config->ignored_options[i]] = true; 66 67 for (i = n = 0; i < config->requested_option_count; i++) { 68 if (ignored[config->requested_options[i]]) 69 continue; 70 config->requested_options[n++] = config->requested_options[i]; 71 } 72 config->requested_option_count = n; 73 } 74 75 /* 76 * client-conf-file :== client-declarations EOF 77 * client-declarations :== <nil> 78 * | client-declaration 79 * | client-declarations client-declaration 80 */ 81 int 82 read_client_conf(void) 83 { 84 FILE *cfile; 85 char *val; 86 int token; 87 struct client_config *config; 88 89 new_parse(path_dhclient_conf); 90 91 /* Set up the initial dhcp option universe. */ 92 initialize_universes(); 93 94 /* Initialize the top level client configuration. */ 95 memset(&top_level_config, 0, sizeof(top_level_config)); 96 97 /* Set some defaults... */ 98 top_level_config.vlan_pcp = 0; 99 top_level_config.timeout = 60; 100 top_level_config.select_interval = 0; 101 top_level_config.reboot_timeout = 10; 102 top_level_config.retry_interval = 300; 103 top_level_config.backoff_cutoff = 15; 104 top_level_config.initial_interval = 3; 105 top_level_config.bootp_policy = ACCEPT; 106 top_level_config.script_name = client_script_name; 107 top_level_config.requested_options 108 [top_level_config.requested_option_count++] = DHO_SUBNET_MASK; 109 top_level_config.requested_options 110 [top_level_config.requested_option_count++] = DHO_BROADCAST_ADDRESS; 111 top_level_config.requested_options 112 [top_level_config.requested_option_count++] = DHO_TIME_OFFSET; 113 top_level_config.requested_options 114 [top_level_config.requested_option_count++] = DHO_CLASSLESS_ROUTES; 115 top_level_config.requested_options 116 [top_level_config.requested_option_count++] = DHO_ROUTERS; 117 top_level_config.requested_options 118 [top_level_config.requested_option_count++] = DHO_DOMAIN_NAME; 119 top_level_config.requested_options 120 [top_level_config.requested_option_count++] = 121 DHO_DOMAIN_NAME_SERVERS; 122 top_level_config.requested_options 123 [top_level_config.requested_option_count++] = DHO_HOST_NAME; 124 top_level_config.requested_options 125 [top_level_config.requested_option_count++] = DHO_DOMAIN_SEARCH; 126 top_level_config.requested_options 127 [top_level_config.requested_option_count++] = DHO_INTERFACE_MTU; 128 #ifdef INET6 129 /* 130 * RFC 8925 sec 3.2: The DHCPv4 client on an IPv4-requiring host MUST 131 * NOT include the IPv6-Only Preferred option code in the Parameter 132 * Request List. 133 */ 134 top_level_config.requested_options 135 [top_level_config.requested_option_count++] = DHO_IPV6_ONLY; 136 #endif 137 138 if ((cfile = fopen(path_dhclient_conf, "r")) != NULL) { 139 do { 140 token = peek_token(&val, cfile); 141 if (token == EOF) 142 break; 143 parse_client_statement(cfile, NULL, &top_level_config); 144 } while (1); 145 token = next_token(&val, cfile); /* Clear the peek buffer */ 146 fclose(cfile); 147 } 148 149 /* 150 * Set up state and config structures for clients that don't 151 * have per-interface configuration declarations. 152 */ 153 config = NULL; 154 if (!ifi->client) { 155 ifi->client = malloc(sizeof(struct client_state)); 156 if (!ifi->client) 157 error("no memory for client state."); 158 memset(ifi->client, 0, sizeof(*(ifi->client))); 159 } 160 if (!ifi->client->config) { 161 if (!config) { 162 config = malloc(sizeof(struct client_config)); 163 if (!config) 164 error("no memory for client config."); 165 memcpy(config, &top_level_config, 166 sizeof(top_level_config)); 167 } 168 ifi->client->config = config; 169 } 170 unrequest_ignored_options(ifi->client->config); 171 172 return (!warnings_occurred); 173 } 174 175 /* 176 * lease-file :== client-lease-statements EOF 177 * client-lease-statements :== <nil> 178 * | client-lease-statements LEASE client-lease-statement 179 */ 180 void 181 read_client_leases(void) 182 { 183 FILE *cfile; 184 char *val; 185 int token; 186 187 new_parse(path_dhclient_db); 188 189 /* Open the lease file. If we can't open it, just return - 190 we can safely trust the server to remember our state. */ 191 if ((cfile = fopen(path_dhclient_db, "r")) == NULL) 192 return; 193 do { 194 token = next_token(&val, cfile); 195 if (token == EOF) 196 break; 197 if (token != LEASE) { 198 warning("Corrupt lease file - possible data loss!"); 199 skip_to_semi(cfile); 200 break; 201 } else 202 parse_client_lease_statement(cfile, 0); 203 204 } while (1); 205 fclose(cfile); 206 } 207 208 /* 209 * client-declaration :== 210 * SEND option-decl | 211 * DEFAULT option-decl | 212 * SUPERSEDE option-decl | 213 * PREPEND option-decl | 214 * APPEND option-decl | 215 * hardware-declaration | 216 * REQUEST option-list | 217 * REQUIRE option-list | 218 * IGNORE option-list | 219 * TIMEOUT number | 220 * RETRY number | 221 * REBOOT number | 222 * SELECT_TIMEOUT number | 223 * SCRIPT string | 224 * interface-declaration | 225 * LEASE client-lease-statement | 226 * ALIAS client-lease-statement 227 */ 228 void 229 parse_client_statement(FILE *cfile, struct interface_info *ip, 230 struct client_config *config) 231 { 232 char *val; 233 struct option *option; 234 time_t tmp; 235 236 switch (next_token(&val, cfile)) { 237 case SEND: 238 parse_option_decl(cfile, &config->send_options[0]); 239 return; 240 case DEFAULT: 241 option = parse_option_decl(cfile, &config->defaults[0]); 242 if (option) 243 config->default_actions[option->code] = ACTION_DEFAULT; 244 return; 245 case SUPERSEDE: 246 option = parse_option_decl(cfile, &config->defaults[0]); 247 if (option) 248 config->default_actions[option->code] = 249 ACTION_SUPERSEDE; 250 return; 251 case APPEND: 252 option = parse_option_decl(cfile, &config->defaults[0]); 253 if (option) 254 config->default_actions[option->code] = ACTION_APPEND; 255 return; 256 case PREPEND: 257 option = parse_option_decl(cfile, &config->defaults[0]); 258 if (option) 259 config->default_actions[option->code] = ACTION_PREPEND; 260 return; 261 case MEDIA: 262 parse_string_list(cfile, &config->media, 1); 263 return; 264 case HARDWARE: 265 if (ip) 266 parse_hardware_param(cfile, &ip->hw_address); 267 else { 268 parse_warn("hardware address parameter %s", 269 "not allowed here."); 270 skip_to_semi(cfile); 271 } 272 return; 273 case REQUEST: 274 config->requested_option_count = 275 parse_option_list(cfile, config->requested_options); 276 return; 277 case REQUIRE: 278 memset(config->required_options, 0, 279 sizeof(config->required_options)); 280 parse_option_list(cfile, config->required_options); 281 return; 282 case IGNORE: 283 parse_option_list(cfile, config->ignored_options); 284 return; 285 case TIMEOUT: 286 parse_lease_time(cfile, &config->timeout); 287 return; 288 case RETRY: 289 parse_lease_time(cfile, &config->retry_interval); 290 return; 291 case SELECT_TIMEOUT: 292 parse_lease_time(cfile, &config->select_interval); 293 return; 294 case REBOOT: 295 parse_lease_time(cfile, &config->reboot_timeout); 296 return; 297 case VLAN_PCP: 298 parse_lease_time(cfile, &tmp); 299 config->vlan_pcp = (u_int)tmp; 300 return; 301 case BACKOFF_CUTOFF: 302 parse_lease_time(cfile, &config->backoff_cutoff); 303 return; 304 case INITIAL_INTERVAL: 305 parse_lease_time(cfile, &config->initial_interval); 306 return; 307 case SCRIPT: 308 config->script_name = parse_string(cfile); 309 return; 310 case INTERFACE: 311 if (ip) 312 parse_warn("nested interface declaration."); 313 parse_interface_declaration(cfile, config); 314 return; 315 case LEASE: 316 parse_client_lease_statement(cfile, 1); 317 return; 318 case ALIAS: 319 parse_client_lease_statement(cfile, 2); 320 return; 321 case REJECT: 322 parse_reject_statement(cfile, config); 323 return; 324 default: 325 break; 326 } 327 328 parse_warn("expecting a statement."); 329 skip_to_semi(cfile); 330 } 331 332 unsigned 333 parse_X(FILE *cfile, u_int8_t *buf, unsigned max) 334 { 335 int token; 336 char *val; 337 unsigned len; 338 339 token = peek_token(&val, cfile); 340 if (token == NUMBER_OR_NAME || token == NUMBER) { 341 len = 0; 342 do { 343 token = next_token(&val, cfile); 344 if (token != NUMBER && token != NUMBER_OR_NAME) { 345 parse_warn("expecting hexadecimal constant."); 346 skip_to_semi(cfile); 347 return (0); 348 } 349 convert_num(&buf[len], val, 16, 8); 350 if (len++ > max) { 351 parse_warn("hexadecimal constant too long."); 352 skip_to_semi(cfile); 353 return (0); 354 } 355 token = peek_token(&val, cfile); 356 if (token == COLON) 357 token = next_token(&val, cfile); 358 } while (token == COLON); 359 val = (char *)buf; 360 } else if (token == STRING) { 361 token = next_token(&val, cfile); 362 len = strlen(val); 363 if (len + 1 > max) { 364 parse_warn("string constant too long."); 365 skip_to_semi(cfile); 366 return (0); 367 } 368 memcpy(buf, val, len + 1); 369 } else { 370 parse_warn("expecting string or hexadecimal data"); 371 skip_to_semi(cfile); 372 return (0); 373 } 374 return (len); 375 } 376 377 /* 378 * option-list :== option_name | 379 * option_list COMMA option_name 380 */ 381 int 382 parse_option_list(FILE *cfile, u_int8_t *list) 383 { 384 int ix, i; 385 int token; 386 char *val; 387 388 ix = 0; 389 do { 390 token = next_token(&val, cfile); 391 if (!is_identifier(token)) { 392 parse_warn("expected option name."); 393 skip_to_semi(cfile); 394 return (0); 395 } 396 for (i = 0; i < 256; i++) 397 if (!strcasecmp(dhcp_options[i].name, val)) 398 break; 399 400 if (i == 256) { 401 parse_warn("%s: unexpected option name.", val); 402 skip_to_semi(cfile); 403 return (0); 404 } 405 list[ix++] = i; 406 if (ix == 256) { 407 parse_warn("%s: too many options.", val); 408 skip_to_semi(cfile); 409 return (0); 410 } 411 token = next_token(&val, cfile); 412 } while (token == COMMA); 413 if (token != SEMI) { 414 parse_warn("expecting semicolon."); 415 skip_to_semi(cfile); 416 return (0); 417 } 418 return (ix); 419 } 420 421 /* 422 * interface-declaration :== 423 * INTERFACE string LBRACE client-declarations RBRACE 424 */ 425 void 426 parse_interface_declaration(FILE *cfile, struct client_config *outer_config) 427 { 428 int token; 429 char *val; 430 struct interface_info *ip; 431 432 token = next_token(&val, cfile); 433 if (token != STRING) { 434 parse_warn("expecting interface name (in quotes)."); 435 skip_to_semi(cfile); 436 return; 437 } 438 439 ip = interface_or_dummy(val); 440 441 if (!ip->client) 442 make_client_state(ip); 443 444 if (!ip->client->config) 445 make_client_config(ip, outer_config); 446 447 token = next_token(&val, cfile); 448 if (token != LBRACE) { 449 parse_warn("expecting left brace."); 450 skip_to_semi(cfile); 451 return; 452 } 453 454 do { 455 token = peek_token(&val, cfile); 456 if (token == EOF) { 457 parse_warn("unterminated interface declaration."); 458 return; 459 } 460 if (token == RBRACE) 461 break; 462 parse_client_statement(cfile, ip, ip->client->config); 463 } while (1); 464 token = next_token(&val, cfile); 465 } 466 467 struct interface_info * 468 interface_or_dummy(char *name) 469 { 470 struct interface_info *ip; 471 472 /* Find the interface (if any) that matches the name. */ 473 if (!strcmp(ifi->name, name)) 474 return (ifi); 475 476 /* If it's not a real interface, see if it's on the dummy list. */ 477 for (ip = dummy_interfaces; ip; ip = ip->next) 478 if (!strcmp(ip->name, name)) 479 return (ip); 480 481 /* 482 * If we didn't find an interface, make a dummy interface as a 483 * placeholder. 484 */ 485 ip = malloc(sizeof(*ip)); 486 if (!ip) 487 error("Insufficient memory to record interface %s", name); 488 memset(ip, 0, sizeof(*ip)); 489 strlcpy(ip->name, name, IFNAMSIZ); 490 ip->next = dummy_interfaces; 491 dummy_interfaces = ip; 492 return (ip); 493 } 494 495 void 496 make_client_state(struct interface_info *ip) 497 { 498 ip->client = malloc(sizeof(*(ip->client))); 499 if (!ip->client) 500 error("no memory for state on %s", ip->name); 501 memset(ip->client, 0, sizeof(*(ip->client))); 502 } 503 504 void 505 make_client_config(struct interface_info *ip, struct client_config *config) 506 { 507 ip->client->config = malloc(sizeof(struct client_config)); 508 if (!ip->client->config) 509 error("no memory for config for %s", ip->name); 510 memset(ip->client->config, 0, sizeof(*(ip->client->config))); 511 memcpy(ip->client->config, config, sizeof(*config)); 512 } 513 514 /* 515 * client-lease-statement :== 516 * RBRACE client-lease-declarations LBRACE 517 * 518 * client-lease-declarations :== 519 * <nil> | 520 * client-lease-declaration | 521 * client-lease-declarations client-lease-declaration 522 */ 523 void 524 parse_client_lease_statement(FILE *cfile, int is_static) 525 { 526 struct client_lease *lease, *lp, *pl; 527 struct interface_info *ip; 528 int token; 529 char *val; 530 531 token = next_token(&val, cfile); 532 if (token != LBRACE) { 533 parse_warn("expecting left brace."); 534 skip_to_semi(cfile); 535 return; 536 } 537 538 lease = malloc(sizeof(struct client_lease)); 539 if (!lease) 540 error("no memory for lease."); 541 memset(lease, 0, sizeof(*lease)); 542 lease->is_static = is_static; 543 544 ip = NULL; 545 546 do { 547 token = peek_token(&val, cfile); 548 if (token == EOF) { 549 parse_warn("unterminated lease declaration."); 550 free_client_lease(lease); 551 return; 552 } 553 if (token == RBRACE) 554 break; 555 parse_client_lease_declaration(cfile, lease, &ip); 556 } while (1); 557 token = next_token(&val, cfile); 558 559 /* If the lease declaration didn't include an interface 560 * declaration that we recognized, it's of no use to us. 561 */ 562 if (!ip) { 563 free_client_lease(lease); 564 return; 565 } 566 567 /* Make sure there's a client state structure... */ 568 if (!ip->client) 569 make_client_state(ip); 570 571 /* If this is an alias lease, it doesn't need to be sorted in. */ 572 if (is_static == 2) { 573 ip->client->alias = lease; 574 return; 575 } 576 577 /* 578 * The new lease may supersede a lease that's not the active 579 * lease but is still on the lease list, so scan the lease list 580 * looking for a lease with the same address, and if we find it, 581 * toss it. 582 */ 583 pl = NULL; 584 for (lp = ip->client->leases; lp; lp = lp->next) { 585 if (lp->address.len == lease->address.len && 586 !memcmp(lp->address.iabuf, lease->address.iabuf, 587 lease->address.len)) { 588 if (pl) 589 pl->next = lp->next; 590 else 591 ip->client->leases = lp->next; 592 free_client_lease(lp); 593 break; 594 } 595 } 596 597 /* 598 * If this is a preloaded lease, just put it on the list of 599 * recorded leases - don't make it the active lease. 600 */ 601 if (is_static) { 602 lease->next = ip->client->leases; 603 ip->client->leases = lease; 604 return; 605 } 606 607 /* 608 * The last lease in the lease file on a particular interface is 609 * the active lease for that interface. Of course, we don't 610 * know what the last lease in the file is until we've parsed 611 * the whole file, so at this point, we assume that the lease we 612 * just parsed is the active lease for its interface. If 613 * there's already an active lease for the interface, and this 614 * lease is for the same ip address, then we just toss the old 615 * active lease and replace it with this one. If this lease is 616 * for a different address, then if the old active lease has 617 * expired, we dump it; if not, we put it on the list of leases 618 * for this interface which are still valid but no longer 619 * active. 620 */ 621 if (ip->client->active) { 622 if (ip->client->active->expiry < cur_time) 623 free_client_lease(ip->client->active); 624 else if (ip->client->active->address.len == 625 lease->address.len && 626 !memcmp(ip->client->active->address.iabuf, 627 lease->address.iabuf, lease->address.len)) 628 free_client_lease(ip->client->active); 629 else { 630 ip->client->active->next = ip->client->leases; 631 ip->client->leases = ip->client->active; 632 } 633 } 634 ip->client->active = lease; 635 636 /* Phew. */ 637 } 638 639 /* 640 * client-lease-declaration :== 641 * BOOTP | 642 * INTERFACE string | 643 * FIXED_ADDR ip_address | 644 * FILENAME string | 645 * SERVER_NAME string | 646 * OPTION option-decl | 647 * RENEW time-decl | 648 * REBIND time-decl | 649 * EXPIRE time-decl 650 */ 651 void 652 parse_client_lease_declaration(FILE *cfile, struct client_lease *lease, 653 struct interface_info **ipp) 654 { 655 int token; 656 char *val; 657 struct interface_info *ip; 658 659 switch (next_token(&val, cfile)) { 660 case BOOTP: 661 lease->is_bootp = 1; 662 break; 663 case INTERFACE: 664 token = next_token(&val, cfile); 665 if (token != STRING) { 666 parse_warn("expecting interface name (in quotes)."); 667 skip_to_semi(cfile); 668 return; 669 } 670 ip = interface_or_dummy(val); 671 *ipp = ip; 672 break; 673 case FIXED_ADDR: 674 if (!parse_ip_addr(cfile, &lease->address)) 675 return; 676 break; 677 case MEDIUM: 678 parse_string_list(cfile, &lease->medium, 0); 679 return; 680 case FILENAME: 681 lease->filename = parse_string(cfile); 682 return; 683 case NEXT_SERVER: 684 if (!parse_ip_addr(cfile, &lease->nextserver)) 685 return; 686 break; 687 case SERVER_NAME: 688 lease->server_name = parse_string(cfile); 689 return; 690 case RENEW: 691 lease->renewal = parse_date(cfile); 692 return; 693 case REBIND: 694 lease->rebind = parse_date(cfile); 695 return; 696 case EXPIRE: 697 lease->expiry = parse_date(cfile); 698 return; 699 case OPTION: 700 parse_option_decl(cfile, lease->options); 701 return; 702 default: 703 parse_warn("expecting lease declaration."); 704 skip_to_semi(cfile); 705 return; 706 } 707 token = next_token(&val, cfile); 708 if (token != SEMI) { 709 parse_warn("expecting semicolon."); 710 skip_to_semi(cfile); 711 } 712 } 713 714 struct option * 715 parse_option_decl(FILE *cfile, struct option_data *options) 716 { 717 char *val; 718 int token; 719 u_int8_t buf[4]; 720 u_int8_t hunkbuf[1024]; 721 unsigned hunkix = 0; 722 char *vendor; 723 const char *fmt; 724 struct universe *universe; 725 struct option *option; 726 struct iaddr ip_addr; 727 u_int8_t *dp; 728 unsigned len; 729 int nul_term = 0; 730 731 token = next_token(&val, cfile); 732 if (!is_identifier(token)) { 733 parse_warn("expecting identifier after option keyword."); 734 if (token != SEMI) 735 skip_to_semi(cfile); 736 return (NULL); 737 } 738 if ((vendor = strdup(val)) == NULL) 739 error("no memory for vendor information."); 740 741 token = peek_token(&val, cfile); 742 if (token == DOT) { 743 /* Go ahead and take the DOT token... */ 744 token = next_token(&val, cfile); 745 746 /* The next token should be an identifier... */ 747 token = next_token(&val, cfile); 748 if (!is_identifier(token)) { 749 parse_warn("expecting identifier after '.'"); 750 if (token != SEMI) 751 skip_to_semi(cfile); 752 free(vendor); 753 return (NULL); 754 } 755 756 /* Look up the option name hash table for the specified 757 vendor. */ 758 universe = ((struct universe *)hash_lookup(&universe_hash, 759 (unsigned char *)vendor, 0)); 760 /* If it's not there, we can't parse the rest of the 761 declaration. */ 762 if (!universe) { 763 parse_warn("no vendor named %s.", vendor); 764 skip_to_semi(cfile); 765 free(vendor); 766 return (NULL); 767 } 768 } else { 769 /* Use the default hash table, which contains all the 770 standard dhcp option names. */ 771 val = vendor; 772 universe = &dhcp_universe; 773 } 774 775 /* Look up the actual option info... */ 776 option = (struct option *)hash_lookup(universe->hash, 777 (unsigned char *)val, 0); 778 779 /* If we didn't get an option structure, it's an undefined option. */ 780 if (!option) { 781 if (val == vendor) 782 parse_warn("no option named %s", val); 783 else 784 parse_warn("no option named %s for vendor %s", 785 val, vendor); 786 skip_to_semi(cfile); 787 free(vendor); 788 return (NULL); 789 } 790 791 /* Free the initial identifier token. */ 792 free(vendor); 793 794 /* Parse the option data... */ 795 do { 796 for (fmt = option->format; *fmt; fmt++) { 797 if (*fmt == 'A') 798 break; 799 switch (*fmt) { 800 case 'X': 801 len = parse_X(cfile, &hunkbuf[hunkix], 802 sizeof(hunkbuf) - hunkix); 803 hunkix += len; 804 break; 805 case 't': /* Text string... */ 806 token = next_token(&val, cfile); 807 if (token != STRING) { 808 parse_warn("expecting string."); 809 skip_to_semi(cfile); 810 return (NULL); 811 } 812 len = strlen(val); 813 if (hunkix + len + 1 > sizeof(hunkbuf)) { 814 parse_warn("option data buffer %s", 815 "overflow"); 816 skip_to_semi(cfile); 817 return (NULL); 818 } 819 memcpy(&hunkbuf[hunkix], val, len + 1); 820 nul_term = 1; 821 hunkix += len; 822 break; 823 case 'I': /* IP address. */ 824 if (!parse_ip_addr(cfile, &ip_addr)) 825 return (NULL); 826 len = ip_addr.len; 827 dp = ip_addr.iabuf; 828 alloc: 829 if (hunkix + len > sizeof(hunkbuf)) { 830 parse_warn("option data buffer " 831 "overflow"); 832 skip_to_semi(cfile); 833 return (NULL); 834 } 835 memcpy(&hunkbuf[hunkix], dp, len); 836 hunkix += len; 837 break; 838 case 'L': /* Unsigned 32-bit integer... */ 839 case 'l': /* Signed 32-bit integer... */ 840 token = next_token(&val, cfile); 841 if (token != NUMBER) { 842 need_number: 843 parse_warn("expecting number."); 844 if (token != SEMI) 845 skip_to_semi(cfile); 846 return (NULL); 847 } 848 convert_num(buf, val, 0, 32); 849 len = 4; 850 dp = buf; 851 goto alloc; 852 case 's': /* Signed 16-bit integer. */ 853 case 'S': /* Unsigned 16-bit integer. */ 854 token = next_token(&val, cfile); 855 if (token != NUMBER) 856 goto need_number; 857 convert_num(buf, val, 0, 16); 858 len = 2; 859 dp = buf; 860 goto alloc; 861 case 'b': /* Signed 8-bit integer. */ 862 case 'B': /* Unsigned 8-bit integer. */ 863 token = next_token(&val, cfile); 864 if (token != NUMBER) 865 goto need_number; 866 convert_num(buf, val, 0, 8); 867 len = 1; 868 dp = buf; 869 goto alloc; 870 case 'f': /* Boolean flag. */ 871 token = next_token(&val, cfile); 872 if (!is_identifier(token)) { 873 parse_warn("expecting identifier."); 874 bad_flag: 875 if (token != SEMI) 876 skip_to_semi(cfile); 877 return (NULL); 878 } 879 if (!strcasecmp(val, "true") || 880 !strcasecmp(val, "on")) 881 buf[0] = 1; 882 else if (!strcasecmp(val, "false") || 883 !strcasecmp(val, "off")) 884 buf[0] = 0; 885 else { 886 parse_warn("expecting boolean."); 887 goto bad_flag; 888 } 889 len = 1; 890 dp = buf; 891 goto alloc; 892 default: 893 warning("Bad format %c in parse_option_param.", 894 *fmt); 895 skip_to_semi(cfile); 896 return (NULL); 897 } 898 } 899 token = next_token(&val, cfile); 900 } while (*fmt == 'A' && token == COMMA); 901 902 if (token != SEMI) { 903 parse_warn("semicolon expected."); 904 skip_to_semi(cfile); 905 return (NULL); 906 } 907 908 options[option->code].data = malloc(hunkix + nul_term); 909 if (!options[option->code].data) 910 error("out of memory allocating option data."); 911 memcpy(options[option->code].data, hunkbuf, hunkix + nul_term); 912 options[option->code].len = hunkix; 913 return (option); 914 } 915 916 void 917 parse_string_list(FILE *cfile, struct string_list **lp, int multiple) 918 { 919 int token; 920 char *val; 921 size_t valsize; 922 struct string_list *cur, *tmp; 923 924 /* Find the last medium in the media list. */ 925 if (*lp) 926 for (cur = *lp; cur->next; cur = cur->next) 927 ; /* nothing */ 928 else 929 cur = NULL; 930 931 do { 932 token = next_token(&val, cfile); 933 if (token != STRING) { 934 parse_warn("Expecting media options."); 935 skip_to_semi(cfile); 936 return; 937 } 938 939 valsize = strlen(val) + 1; 940 tmp = new_string_list(valsize); 941 if (tmp == NULL) 942 error("no memory for string list entry."); 943 memcpy(tmp->string, val, valsize); 944 tmp->next = NULL; 945 946 /* Store this medium at the end of the media list. */ 947 if (cur) 948 cur->next = tmp; 949 else 950 *lp = tmp; 951 cur = tmp; 952 953 token = next_token(&val, cfile); 954 } while (multiple && token == COMMA); 955 956 if (token != SEMI) { 957 parse_warn("expecting semicolon."); 958 skip_to_semi(cfile); 959 } 960 } 961 962 void 963 parse_reject_statement(FILE *cfile, struct client_config *config) 964 { 965 int token; 966 char *val; 967 struct iaddr addr; 968 struct iaddrlist *list; 969 970 do { 971 if (!parse_ip_addr(cfile, &addr)) { 972 parse_warn("expecting IP address."); 973 skip_to_semi(cfile); 974 return; 975 } 976 977 list = malloc(sizeof(struct iaddrlist)); 978 if (!list) 979 error("no memory for reject list!"); 980 981 list->addr = addr; 982 list->next = config->reject_list; 983 config->reject_list = list; 984 985 token = next_token(&val, cfile); 986 } while (token == COMMA); 987 988 if (token != SEMI) { 989 parse_warn("expecting semicolon."); 990 skip_to_semi(cfile); 991 } 992 } 993