1 /************************************************************************ 2 Copyright 1988, 1991 by Carnegie Mellon University 3 4 All Rights Reserved 5 6 Permission to use, copy, modify, and distribute this software and its 7 documentation for any purpose and without fee is hereby granted, provided 8 that the above copyright notice appear in all copies and that both that 9 copyright notice and this permission notice appear in supporting 10 documentation, and that the name of Carnegie Mellon University not be used 11 in advertising or publicity pertaining to distribution of the software 12 without specific, written prior permission. 13 14 CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS 15 SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. 16 IN NO EVENT SHALL CMU BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL 17 DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR 18 PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS 19 ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS 20 SOFTWARE. 21 ************************************************************************/ 22 23 #include <sys/cdefs.h> 24 #ifndef lint 25 __RCSID("$NetBSD: readfile.c,v 1.21 2019/02/03 03:19:30 mrg Exp $"); 26 #endif 27 28 29 /* 30 * bootpd configuration file reading code. 31 * 32 * The routines in this file deal with reading, interpreting, and storing 33 * the information found in the bootpd configuration file (usually 34 * /etc/bootptab). 35 */ 36 37 38 #include <sys/types.h> 39 #include <sys/stat.h> 40 #include <sys/file.h> 41 #include <sys/time.h> 42 #include <netinet/in.h> 43 44 #include <errno.h> 45 #include <stdlib.h> 46 #include <stdio.h> 47 #include <string.h> 48 #include <strings.h> 49 #include <time.h> 50 #include <ctype.h> 51 #include <assert.h> 52 #include <syslog.h> 53 54 #include "bootp.h" 55 #include "hash.h" 56 #include "hwaddr.h" 57 #include "lookup.h" 58 #include "readfile.h" 59 #include "report.h" 60 #include "tzone.h" 61 #include "bootpd.h" 62 63 #define HASHTABLESIZE 257 /* Hash table size (prime) */ 64 65 /* Non-standard hardware address type (see bootp.h) */ 66 #define HTYPE_DIRECT 0 67 68 /* Error codes returned by eval_symbol: */ 69 #define SUCCESS 0 70 #define E_END_OF_ENTRY (-1) 71 #define E_SYNTAX_ERROR (-2) 72 #define E_UNKNOWN_SYMBOL (-3) 73 #define E_BAD_IPADDR (-4) 74 #define E_BAD_HWADDR (-5) 75 #define E_BAD_LONGWORD (-6) 76 #define E_BAD_HWATYPE (-7) 77 #define E_BAD_PATHNAME (-8) 78 #define E_BAD_VALUE (-9) 79 80 /* Tag idendities. */ 81 #define SYM_NULL 0 82 #define SYM_BOOTFILE 1 83 #define SYM_COOKIE_SERVER 2 84 #define SYM_DOMAIN_SERVER 3 85 #define SYM_GATEWAY 4 86 #define SYM_HWADDR 5 87 #define SYM_HOMEDIR 6 88 #define SYM_HTYPE 7 89 #define SYM_IMPRESS_SERVER 8 90 #define SYM_IPADDR 9 91 #define SYM_LOG_SERVER 10 92 #define SYM_LPR_SERVER 11 93 #define SYM_NAME_SERVER 12 94 #define SYM_RLP_SERVER 13 95 #define SYM_SUBNET_MASK 14 96 #define SYM_TIME_OFFSET 15 97 #define SYM_TIME_SERVER 16 98 #define SYM_VENDOR_MAGIC 17 99 #define SYM_SIMILAR_ENTRY 18 100 #define SYM_NAME_SWITCH 19 101 #define SYM_BOOTSIZE 20 102 #define SYM_BOOT_SERVER 22 103 #define SYM_TFTPDIR 23 104 #define SYM_DUMP_FILE 24 105 #define SYM_DOMAIN_NAME 25 106 #define SYM_SWAP_SERVER 26 107 #define SYM_ROOT_PATH 27 108 #define SYM_EXTEN_FILE 28 109 #define SYM_REPLY_ADDR 29 110 #define SYM_NIS_DOMAIN 30 /* RFC 1533 */ 111 #define SYM_NIS_SERVER 31 /* RFC 1533 */ 112 #define SYM_NTP_SERVER 32 /* RFC 1533 */ 113 #define SYM_EXEC_FILE 33 /* YORK_EX_OPTION */ 114 #define SYM_MSG_SIZE 34 115 #define SYM_MIN_WAIT 35 116 /* XXX - Add new tags here */ 117 118 #define OP_ADDITION 1 /* Operations on tags */ 119 #define OP_DELETION 2 120 #define OP_BOOLEAN 3 121 122 #define MAXINADDRS 16 /* Max size of an IP address list */ 123 #define MAXBUFLEN 256 /* Max temp buffer space */ 124 #define MAXENTRYLEN 2048 /* Max size of an entire entry */ 125 126 128 129 /* 130 * Structure used to map a configuration-file symbol (such as "ds") to a 131 * unique integer. 132 */ 133 134 struct symbolmap { 135 const char *symbol; 136 int symbolcode; 137 }; 138 139 140 struct htypename { 141 const char *name; 142 byte htype; 143 }; 144 145 146 PRIVATE int nhosts; /* Number of hosts (/w hw or IP address) */ 147 PRIVATE int nentries; /* Total number of entries */ 148 PRIVATE int32 modtime = 0; /* Last modification time of bootptab */ 149 PRIVATE char *current_hostname; /* Name of the current entry. */ 150 PRIVATE char current_tagname[8]; 151 152 /* 153 * List of symbolic names used in the bootptab file. The order and actual 154 * values of the symbol codes (SYM_. . .) are unimportant, but they must 155 * all be unique. 156 */ 157 158 PRIVATE struct symbolmap symbol_list[] = { 159 {"bf", SYM_BOOTFILE}, 160 {"bs", SYM_BOOTSIZE}, 161 {"cs", SYM_COOKIE_SERVER}, 162 {"df", SYM_DUMP_FILE}, 163 {"dn", SYM_DOMAIN_NAME}, 164 {"ds", SYM_DOMAIN_SERVER}, 165 {"ef", SYM_EXTEN_FILE}, 166 {"ex", SYM_EXEC_FILE}, /* YORK_EX_OPTION */ 167 {"gw", SYM_GATEWAY}, 168 {"ha", SYM_HWADDR}, 169 {"hd", SYM_HOMEDIR}, 170 {"hn", SYM_NAME_SWITCH}, 171 {"ht", SYM_HTYPE}, 172 {"im", SYM_IMPRESS_SERVER}, 173 {"ip", SYM_IPADDR}, 174 {"lg", SYM_LOG_SERVER}, 175 {"lp", SYM_LPR_SERVER}, 176 {"ms", SYM_MSG_SIZE}, 177 {"mw", SYM_MIN_WAIT}, 178 {"ns", SYM_NAME_SERVER}, 179 {"nt", SYM_NTP_SERVER}, 180 {"ra", SYM_REPLY_ADDR}, 181 {"rl", SYM_RLP_SERVER}, 182 {"rp", SYM_ROOT_PATH}, 183 {"sa", SYM_BOOT_SERVER}, 184 {"sm", SYM_SUBNET_MASK}, 185 {"sw", SYM_SWAP_SERVER}, 186 {"tc", SYM_SIMILAR_ENTRY}, 187 {"td", SYM_TFTPDIR}, 188 {"to", SYM_TIME_OFFSET}, 189 {"ts", SYM_TIME_SERVER}, 190 {"vm", SYM_VENDOR_MAGIC}, 191 {"yd", SYM_NIS_DOMAIN}, 192 {"ys", SYM_NIS_SERVER}, 193 /* XXX - Add new tags here */ 194 }; 195 196 197 /* 198 * List of symbolic names for hardware types. Name translates into 199 * hardware type code listed with it. Names must begin with a letter 200 * and must be all lowercase. This is searched linearly, so put 201 * commonly-used entries near the beginning. 202 */ 203 204 PRIVATE struct htypename htnamemap[] = { 205 {"ethernet", HTYPE_ETHERNET}, 206 {"ethernet3", HTYPE_EXP_ETHERNET}, 207 {"ether", HTYPE_ETHERNET}, 208 {"ether3", HTYPE_EXP_ETHERNET}, 209 {"ieee802", HTYPE_IEEE802}, 210 {"tr", HTYPE_IEEE802}, 211 {"token-ring", HTYPE_IEEE802}, 212 {"pronet", HTYPE_PRONET}, 213 {"chaos", HTYPE_CHAOS}, 214 {"arcnet", HTYPE_ARCNET}, 215 {"ax.25", HTYPE_AX25}, 216 {"direct", HTYPE_DIRECT}, 217 {"serial", HTYPE_DIRECT}, 218 {"slip", HTYPE_DIRECT}, 219 {"ppp", HTYPE_DIRECT} 220 }; 221 222 223 224 /* 225 * Externals and forward declarations. 226 */ 227 228 boolean nmcmp(hash_datum *, hash_datum *); 229 230 PRIVATE void 231 adjust(char **); 232 PRIVATE void 233 del_string(struct shared_string *); 234 PRIVATE void 235 del_bindata(struct shared_bindata *); 236 PRIVATE void 237 del_iplist(struct in_addr_list *); 238 PRIVATE void 239 eat_whitespace(char **); 240 PRIVATE int 241 eval_symbol(char **, struct host *); 242 PRIVATE void 243 fill_defaults(struct host *, char **); 244 PRIVATE void 245 free_host(hash_datum *); 246 PRIVATE struct in_addr_list * 247 get_addresses(char **); 248 PRIVATE struct shared_string * 249 get_shared_string(char **); 250 PRIVATE char * 251 get_string(char **, char *, u_int *); 252 PRIVATE u_int32 253 get_u_long(char **); 254 PRIVATE boolean 255 goodname(char *); 256 PRIVATE boolean 257 hwinscmp(hash_datum *, hash_datum *); 258 PRIVATE int 259 interp_byte(char **, byte *); 260 PRIVATE void 261 makelower(char *); 262 PRIVATE boolean 263 nullcmp(hash_datum *, hash_datum *); 264 PRIVATE int 265 process_entry(struct host *, char *); 266 PRIVATE int 267 process_generic(char **, struct shared_bindata **, u_int); 268 PRIVATE byte * 269 prs_haddr(char **, u_int); 270 PRIVATE int 271 prs_inetaddr(char **, u_int32 *); 272 PRIVATE void 273 read_entry(FILE *, char *, u_int *); 274 PRIVATE char * 275 smalloc(u_int); 276 277 278 280 /* 281 * Vendor magic cookies for CMU and RFC1048 282 */ 283 u_char vm_cmu[4] = VM_CMU; 284 u_char vm_rfc1048[4] = VM_RFC1048; 285 286 /* 287 * Main hash tables 288 */ 289 hash_tbl *hwhashtable; 290 hash_tbl *iphashtable; 291 hash_tbl *nmhashtable; 292 293 /* 294 * Allocate hash tables for hardware address, ip address, and hostname 295 * (shared by bootpd and bootpef) 296 */ 297 void 298 rdtab_init(void) 299 { 300 hwhashtable = hash_Init(HASHTABLESIZE); 301 iphashtable = hash_Init(HASHTABLESIZE); 302 nmhashtable = hash_Init(HASHTABLESIZE); 303 if (!(hwhashtable && iphashtable && nmhashtable)) { 304 report(LOG_ERR, "Unable to allocate hash tables."); 305 exit(1); 306 } 307 } 308 309 311 /* 312 * Read bootptab database file. Avoid rereading the file if the 313 * write date hasn't changed since the last time we read it. 314 */ 315 316 void 317 readtab(int force) 318 { 319 struct host *hp; 320 FILE *fp; 321 struct stat st; 322 unsigned hashcode, buflen; 323 static char buffer[MAXENTRYLEN]; 324 325 /* 326 * Check the last modification time. 327 */ 328 if (stat(bootptab, &st) < 0) { 329 report(LOG_ERR, "stat on \"%s\": %s", 330 bootptab, get_errmsg()); 331 return; 332 } 333 #ifdef DEBUG 334 if (debug > 3) { 335 char timestr[28]; 336 strlcpy(timestr, ctime(&(st.st_mtime)), sizeof(timestr)); 337 /* zap the newline */ 338 timestr[24] = '\0'; 339 report(LOG_INFO, "bootptab mtime: %s", 340 timestr); 341 } 342 #endif 343 if ((force == 0) && 344 (st.st_mtime == modtime) && 345 st.st_nlink) { 346 /* 347 * hasn't been modified or deleted yet. 348 */ 349 return; 350 } 351 if (debug) 352 report(LOG_INFO, "reading %s\"%s\"", 353 (modtime != 0L) ? "new " : "", 354 bootptab); 355 356 /* 357 * Open bootptab file. 358 */ 359 if ((fp = fopen(bootptab, "r")) == NULL) { 360 report(LOG_ERR, "error opening \"%s\": %s", bootptab, get_errmsg()); 361 return; 362 } 363 /* 364 * Record file modification time. 365 */ 366 if (fstat(fileno(fp), &st) < 0) { 367 report(LOG_ERR, "fstat: %s", get_errmsg()); 368 fclose(fp); 369 return; 370 } 371 modtime = st.st_mtime; 372 373 /* 374 * Entirely erase all hash tables. 375 */ 376 hash_Reset(hwhashtable, free_host); 377 hash_Reset(iphashtable, free_host); 378 hash_Reset(nmhashtable, free_host); 379 380 nhosts = 0; 381 nentries = 0; 382 while (TRUE) { 383 buflen = sizeof(buffer); 384 read_entry(fp, buffer, &buflen); 385 if (buflen == 0) { /* More entries? */ 386 break; 387 } 388 hp = (struct host *) smalloc(sizeof(struct host)); 389 bzero((char *) hp, sizeof(*hp)); 390 /* the link count it zero */ 391 392 /* 393 * Get individual info 394 */ 395 if (process_entry(hp, buffer) < 0) { 396 hp->linkcount = 1; 397 free_host((hash_datum *) hp); 398 continue; 399 } 400 /* 401 * If this is not a dummy entry, and the IP or HW 402 * address is not yet set, try to get them here. 403 * Dummy entries have . as first char of name. 404 */ 405 if (goodname(hp->hostname->string)) { 406 char *hn = hp->hostname->string; 407 u_int32 value; 408 if (hp->flags.iaddr == 0) { 409 if (lookup_ipa(hn, &value)) { 410 report(LOG_ERR, "can not get IP addr for %s", hn); 411 report(LOG_ERR, "(dummy names should start with '.')"); 412 } else { 413 hp->iaddr.s_addr = value; 414 hp->flags.iaddr = TRUE; 415 } 416 } 417 /* Set default subnet mask. */ 418 if (hp->flags.subnet_mask == 0) { 419 if (lookup_netmask(hp->iaddr.s_addr, &value)) { 420 report(LOG_ERR, "can not get netmask for %s", hn); 421 } else { 422 hp->subnet_mask.s_addr = value; 423 hp->flags.subnet_mask = TRUE; 424 } 425 } 426 } 427 if (hp->flags.iaddr) { 428 nhosts++; 429 } 430 /* Register by HW addr if known. */ 431 if (hp->flags.htype && hp->flags.haddr) { 432 /* We will either insert it or free it. */ 433 hp->linkcount++; 434 hashcode = hash_HashFunction(hp->haddr, haddrlength(hp->htype)); 435 if (hash_Insert(hwhashtable, hashcode, hwinscmp, hp, hp) < 0) { 436 report(LOG_NOTICE, "duplicate %s address: %s", 437 netname(hp->htype), 438 haddrtoa(hp->haddr, haddrlength(hp->htype))); 439 free_host((hash_datum *) hp); 440 continue; 441 } 442 } 443 /* Register by IP addr if known. */ 444 if (hp->flags.iaddr) { 445 hashcode = hash_HashFunction((u_char *) & (hp->iaddr.s_addr), 4); 446 if (hash_Insert(iphashtable, hashcode, nullcmp, hp, hp) < 0) { 447 report(LOG_ERR, 448 "hash_Insert() failed on IP address insertion"); 449 } else { 450 /* Just inserted the host struct in a new hash list. */ 451 hp->linkcount++; 452 } 453 } 454 /* Register by Name (always known) */ 455 hashcode = hash_HashFunction((u_char *) hp->hostname->string, 456 strlen(hp->hostname->string)); 457 if (hash_Insert(nmhashtable, hashcode, nullcmp, 458 hp->hostname->string, hp) < 0) { 459 report(LOG_ERR, 460 "hash_Insert() failed on insertion of hostname: \"%s\"", 461 hp->hostname->string); 462 } else { 463 /* Just inserted the host struct in a new hash list. */ 464 hp->linkcount++; 465 } 466 467 nentries++; 468 } 469 470 fclose(fp); 471 if (debug) 472 report(LOG_INFO, "read %d entries (%d hosts) from \"%s\"", 473 nentries, nhosts, bootptab); 474 return; 475 } 476 477 479 480 /* 481 * Read an entire host entry from the file pointed to by "fp" and insert it 482 * into the memory pointed to by "buffer". Leading whitespace and comments 483 * starting with "#" are ignored (removed). Backslashes (\) always quote 484 * the next character except that newlines preceded by a backslash cause 485 * line-continuation onto the next line. The entry is terminated by a 486 * newline character which is not preceded by a backslash. Sequences 487 * surrounded by double quotes are taken literally (including newlines, but 488 * not backslashes). 489 * 490 * The "bufsiz" parameter points to an unsigned int which specifies the 491 * maximum permitted buffer size. Upon return, this value will be replaced 492 * with the actual length of the entry (not including the null terminator). 493 * 494 * This code is a little scary. . . . I don't like using gotos in C 495 * either, but I first wrote this as an FSM diagram and gotos seemed like 496 * the easiest way to implement it. Maybe later I'll clean it up. 497 */ 498 499 PRIVATE void 500 read_entry(FILE *fp, char *buffer, unsigned int *bufsiz) 501 { 502 int c; 503 unsigned int length; 504 505 length = 0; 506 507 /* 508 * Eat whitespace, blank lines, and comment lines. 509 */ 510 top: 511 c = fgetc(fp); 512 if (c < 0) { 513 goto done; /* Exit if end-of-file */ 514 } 515 if (isspace(c)) { 516 goto top; /* Skip over whitespace */ 517 } 518 if (c == '#') { 519 while (TRUE) { /* Eat comments after # */ 520 c = fgetc(fp); 521 if (c < 0) { 522 goto done; /* Exit if end-of-file */ 523 } 524 if (c == '\n') { 525 goto top; /* Try to read the next line */ 526 } 527 } 528 } 529 ungetc(c, fp); /* Other character, push it back to reprocess it */ 530 531 532 /* 533 * Now we're actually reading a data entry. Get each character and 534 * assemble it into the data buffer, processing special characters like 535 * double quotes (") and backslashes (\). 536 */ 537 538 mainloop: 539 c = fgetc(fp); 540 switch (c) { 541 case EOF: 542 case '\n': 543 goto done; /* Exit on EOF or newline */ 544 case '\\': 545 c = fgetc(fp); /* Backslash, read a new character */ 546 if (c < 0) { 547 goto done; /* Exit on EOF */ 548 } 549 *buffer++ = c; /* Store the literal character */ 550 length++; 551 if (length < *bufsiz - 1) { 552 goto mainloop; 553 } else { 554 goto done; 555 } 556 case '"': 557 *buffer++ = '"'; /* Store double-quote */ 558 length++; 559 if (length >= *bufsiz - 1) { 560 goto done; 561 } 562 while (TRUE) { /* Special quote processing loop */ 563 c = fgetc(fp); 564 switch (c) { 565 case EOF: 566 goto done; /* Exit on EOF . . . */ 567 case '"': 568 *buffer++ = '"';/* Store matching quote */ 569 length++; 570 if (length < *bufsiz - 1) { 571 goto mainloop; /* And continue main loop */ 572 } else { 573 goto done; 574 } 575 case '\\': 576 if ((c = fgetc(fp)) < 0) { /* Backslash */ 577 goto done; /* EOF. . . .*/ 578 } /* else fall through */ 579 default: 580 *buffer++ = c; /* Other character, store it */ 581 length++; 582 if (length >= *bufsiz - 1) { 583 goto done; 584 } 585 } 586 } 587 case ':': 588 *buffer++ = c; /* Store colons */ 589 length++; 590 if (length >= *bufsiz - 1) { 591 goto done; 592 } 593 do { /* But remove whitespace after them */ 594 c = fgetc(fp); 595 if ((c < 0) || (c == '\n')) { 596 goto done; 597 } 598 } while (isspace(c)); /* Skip whitespace */ 599 600 if (c == '\\') { /* Backslash quotes next character */ 601 c = fgetc(fp); 602 if (c < 0) { 603 goto done; 604 } 605 if (c == '\n') { 606 goto top; /* Backslash-newline continuation */ 607 } 608 } 609 /* fall through if "other" character */ 610 /* FALLTHROUGH */ 611 default: 612 *buffer++ = c; /* Store other characters */ 613 length++; 614 if (length >= *bufsiz - 1) { 615 goto done; 616 } 617 } 618 goto mainloop; /* Keep going */ 619 620 done: 621 *buffer = '\0'; /* Terminate string */ 622 *bufsiz = length; /* Tell the caller its length */ 623 } 624 625 627 628 /* 629 * Parse out all the various tags and parameters in the host entry pointed 630 * to by "src". Stuff all the data into the appropriate fields of the 631 * host structure pointed to by "host". If there is any problem with the 632 * entry, an error message is reported via report(), no further processing 633 * is done, and -1 is returned. Successful calls return 0. 634 * 635 * (Some errors probably shouldn't be so completely fatal. . . .) 636 */ 637 638 PRIVATE int 639 process_entry(struct host *host, char *src) 640 { 641 int retval; 642 const char *msg; 643 644 if (!host || *src == '\0') { 645 return -1; 646 } 647 host->hostname = get_shared_string(&src); 648 #if 0 649 /* Be more liberal for the benefit of dummy tag names. */ 650 if (!goodname(host->hostname->string)) { 651 report(LOG_ERR, "bad hostname: \"%s\"", host->hostname->string); 652 del_string(host->hostname); 653 return -1; 654 } 655 #endif 656 current_hostname = host->hostname->string; 657 adjust(&src); 658 while (TRUE) { 659 retval = eval_symbol(&src, host); 660 if (retval == SUCCESS) { 661 adjust(&src); 662 continue; 663 } 664 if (retval == E_END_OF_ENTRY) { 665 /* The default subnet mask is set in readtab() */ 666 return 0; 667 } 668 /* Some kind of error. */ 669 switch (retval) { 670 case E_SYNTAX_ERROR: 671 msg = "bad syntax"; 672 break; 673 case E_UNKNOWN_SYMBOL: 674 msg = "unknown symbol"; 675 break; 676 case E_BAD_IPADDR: 677 msg = "bad INET address"; 678 break; 679 case E_BAD_HWADDR: 680 msg = "bad hardware address"; 681 break; 682 case E_BAD_LONGWORD: 683 msg = "bad longword value"; 684 break; 685 case E_BAD_HWATYPE: 686 msg = "bad HW address type"; 687 break; 688 case E_BAD_PATHNAME: 689 msg = "bad pathname (need leading '/')"; 690 break; 691 case E_BAD_VALUE: 692 msg = "bad value"; 693 break; 694 default: 695 msg = "unknown error"; 696 break; 697 } /* switch */ 698 report(LOG_ERR, "in entry named \"%s\", symbol \"%s\": %s", 699 current_hostname, current_tagname, msg); 700 return -1; 701 } 702 } 703 704 706 /* 707 * Macros for use in the function below: 708 */ 709 710 /* Parse one INET address stored directly in MEMBER. */ 711 #define PARSE_IA1(MEMBER) do \ 712 { \ 713 if (optype == OP_BOOLEAN) \ 714 return E_SYNTAX_ERROR; \ 715 hp->flags.MEMBER = FALSE; \ 716 if (optype == OP_ADDITION) { \ 717 if (prs_inetaddr(symbol, &value) < 0) \ 718 return E_BAD_IPADDR; \ 719 hp->MEMBER.s_addr = value; \ 720 hp->flags.MEMBER = TRUE; \ 721 } \ 722 } while (0) 723 724 /* Parse a list of INET addresses pointed to by MEMBER */ 725 #define PARSE_IAL(MEMBER) do \ 726 { \ 727 if (optype == OP_BOOLEAN) \ 728 return E_SYNTAX_ERROR; \ 729 if (hp->flags.MEMBER) { \ 730 hp->flags.MEMBER = FALSE; \ 731 assert(hp->MEMBER); \ 732 del_iplist(hp->MEMBER); \ 733 hp->MEMBER = NULL; \ 734 } \ 735 if (optype == OP_ADDITION) { \ 736 hp->MEMBER = get_addresses(symbol); \ 737 if (hp->MEMBER == NULL) \ 738 return E_SYNTAX_ERROR; \ 739 hp->flags.MEMBER = TRUE; \ 740 } \ 741 } while (0) 742 743 /* Parse a shared string pointed to by MEMBER */ 744 #define PARSE_STR(MEMBER) do \ 745 { \ 746 if (optype == OP_BOOLEAN) \ 747 return E_SYNTAX_ERROR; \ 748 if (hp->flags.MEMBER) { \ 749 hp->flags.MEMBER = FALSE; \ 750 assert(hp->MEMBER); \ 751 del_string(hp->MEMBER); \ 752 hp->MEMBER = NULL; \ 753 } \ 754 if (optype == OP_ADDITION) { \ 755 hp->MEMBER = get_shared_string(symbol); \ 756 if (hp->MEMBER == NULL) \ 757 return E_SYNTAX_ERROR; \ 758 hp->flags.MEMBER = TRUE; \ 759 } \ 760 } while (0) 761 762 /* Parse an integer value for MEMBER */ 763 #define PARSE_INT(MEMBER) do \ 764 { \ 765 if (optype == OP_BOOLEAN) \ 766 return E_SYNTAX_ERROR; \ 767 hp->flags.MEMBER = FALSE; \ 768 if (optype == OP_ADDITION) { \ 769 value = get_u_long(symbol); \ 770 hp->MEMBER = value; \ 771 hp->flags.MEMBER = TRUE; \ 772 } \ 773 } while (0) 774 775 /* 776 * Evaluate the two-character tag symbol pointed to by "symbol" and place 777 * the data in the structure pointed to by "hp". The pointer pointed to 778 * by "symbol" is updated to point past the source string (but may not 779 * point to the next tag entry). 780 * 781 * Obviously, this need a few more comments. . . . 782 */ 783 PRIVATE int 784 eval_symbol(char **symbol, struct host *hp) 785 { 786 char tmpstr[MAXSTRINGLEN]; 787 byte *tmphaddr; 788 struct symbolmap *symbolptr; 789 u_int32 value; 790 int32 ltimeoff; 791 int i, numsymbols; 792 unsigned len; 793 int optype; /* Indicates boolean, addition, or deletion */ 794 795 eat_whitespace(symbol); 796 797 /* Make sure this is set before returning. */ 798 current_tagname[0] = (*symbol)[0]; 799 current_tagname[1] = (*symbol)[1]; 800 current_tagname[2] = 0; 801 802 if ((*symbol)[0] == '\0') { 803 return E_END_OF_ENTRY; 804 } 805 if ((*symbol)[0] == ':') { 806 return SUCCESS; 807 } 808 if ((*symbol)[0] == 'T') { /* generic symbol */ 809 (*symbol)++; 810 value = get_u_long(symbol); 811 snprintf(current_tagname, sizeof(current_tagname), 812 "T%d", value); 813 eat_whitespace(symbol); 814 if ((*symbol)[0] != '=') { 815 return E_SYNTAX_ERROR; 816 } 817 (*symbol)++; 818 if (!(hp->generic)) { 819 hp->generic = (struct shared_bindata *) 820 smalloc(sizeof(struct shared_bindata)); 821 } 822 if (process_generic(symbol, &(hp->generic), (byte) (value & 0xFF))) 823 return E_SYNTAX_ERROR; 824 hp->flags.generic = TRUE; 825 return SUCCESS; 826 } 827 /* 828 * Determine the type of operation to be done on this symbol 829 */ 830 switch ((*symbol)[2]) { 831 case '=': 832 optype = OP_ADDITION; 833 break; 834 case '@': 835 optype = OP_DELETION; 836 break; 837 case ':': 838 case '\0': 839 optype = OP_BOOLEAN; 840 break; 841 default: 842 return E_SYNTAX_ERROR; 843 } 844 845 symbolptr = symbol_list; 846 numsymbols = sizeof(symbol_list) / sizeof(struct symbolmap); 847 for (i = 0; i < numsymbols; i++) { 848 if (((symbolptr->symbol)[0] == (*symbol)[0]) && 849 ((symbolptr->symbol)[1] == (*symbol)[1])) { 850 break; 851 } 852 symbolptr++; 853 } 854 if (i >= numsymbols) { 855 return E_UNKNOWN_SYMBOL; 856 } 857 /* 858 * Skip past the = or @ character (to point to the data) if this 859 * isn't a boolean operation. For boolean operations, just skip 860 * over the two-character tag symbol (and nothing else. . . .). 861 */ 862 (*symbol) += (optype == OP_BOOLEAN) ? 2 : 3; 863 864 eat_whitespace(symbol); 865 866 /* The cases below are in order by symbolcode value. */ 867 switch (symbolptr->symbolcode) { 868 869 case SYM_BOOTFILE: 870 PARSE_STR(bootfile); 871 break; 872 873 case SYM_COOKIE_SERVER: 874 PARSE_IAL(cookie_server); 875 break; 876 877 case SYM_DOMAIN_SERVER: 878 PARSE_IAL(domain_server); 879 break; 880 881 case SYM_GATEWAY: 882 PARSE_IAL(gateway); 883 break; 884 885 case SYM_HWADDR: 886 if (optype == OP_BOOLEAN) 887 return E_SYNTAX_ERROR; 888 hp->flags.haddr = FALSE; 889 if (optype == OP_ADDITION) { 890 /* Default the HW type to Ethernet */ 891 if (hp->flags.htype == 0) { 892 hp->flags.htype = TRUE; 893 hp->htype = HTYPE_ETHERNET; 894 } 895 tmphaddr = prs_haddr(symbol, hp->htype); 896 if (!tmphaddr) 897 return E_BAD_HWADDR; 898 bcopy(tmphaddr, hp->haddr, haddrlength(hp->htype)); 899 hp->flags.haddr = TRUE; 900 } 901 break; 902 903 case SYM_HOMEDIR: 904 PARSE_STR(homedir); 905 break; 906 907 case SYM_HTYPE: 908 if (optype == OP_BOOLEAN) 909 return E_SYNTAX_ERROR; 910 hp->flags.htype = FALSE; 911 if (optype == OP_ADDITION) { 912 value = 0L; /* Assume an illegal value */ 913 eat_whitespace(symbol); 914 if (isdigit((unsigned char)**symbol)) { 915 value = get_u_long(symbol); 916 } else { 917 len = sizeof(tmpstr); 918 (void) get_string(symbol, tmpstr, &len); 919 makelower(tmpstr); 920 numsymbols = sizeof(htnamemap) / 921 sizeof(struct htypename); 922 for (i = 0; i < numsymbols; i++) { 923 if (!strcmp(htnamemap[i].name, tmpstr)) { 924 break; 925 } 926 } 927 if (i < numsymbols) { 928 value = htnamemap[i].htype; 929 } 930 } 931 if (value >= hwinfocnt) { 932 return E_BAD_HWATYPE; 933 } 934 hp->htype = (byte) (value & 0xFF); 935 hp->flags.htype = TRUE; 936 } 937 break; 938 939 case SYM_IMPRESS_SERVER: 940 PARSE_IAL(impress_server); 941 break; 942 943 case SYM_IPADDR: 944 PARSE_IA1(iaddr); 945 break; 946 947 case SYM_LOG_SERVER: 948 PARSE_IAL(log_server); 949 break; 950 951 case SYM_LPR_SERVER: 952 PARSE_IAL(lpr_server); 953 break; 954 955 case SYM_NAME_SERVER: 956 PARSE_IAL(name_server); 957 break; 958 959 case SYM_RLP_SERVER: 960 PARSE_IAL(rlp_server); 961 break; 962 963 case SYM_SUBNET_MASK: 964 PARSE_IA1(subnet_mask); 965 break; 966 967 case SYM_TIME_OFFSET: 968 if (optype == OP_BOOLEAN) 969 return E_SYNTAX_ERROR; 970 hp->flags.time_offset = FALSE; 971 if (optype == OP_ADDITION) { 972 len = sizeof(tmpstr); 973 (void) get_string(symbol, tmpstr, &len); 974 if (!strncmp(tmpstr, "auto", 4)) { 975 hp->time_offset = secondswest; 976 } else { 977 if (sscanf(tmpstr, "%d", <imeoff) != 1) 978 return E_BAD_LONGWORD; 979 hp->time_offset = ltimeoff; 980 } 981 hp->flags.time_offset = TRUE; 982 } 983 break; 984 985 case SYM_TIME_SERVER: 986 PARSE_IAL(time_server); 987 break; 988 989 case SYM_VENDOR_MAGIC: 990 if (optype == OP_BOOLEAN) 991 return E_SYNTAX_ERROR; 992 hp->flags.vm_cookie = FALSE; 993 if (optype == OP_ADDITION) { 994 if (strncmp(*symbol, "auto", 4)) { 995 /* The string is not "auto" */ 996 if (!strncmp(*symbol, "rfc", 3)) { 997 bcopy(vm_rfc1048, hp->vm_cookie, 4); 998 } else if (!strncmp(*symbol, "cmu", 3)) { 999 bcopy(vm_cmu, hp->vm_cookie, 4); 1000 } else { 1001 if (!isdigit((unsigned char)**symbol)) 1002 return E_BAD_IPADDR; 1003 if (prs_inetaddr(symbol, &value) < 0) 1004 return E_BAD_IPADDR; 1005 bcopy(&value, hp->vm_cookie, 4); 1006 } 1007 hp->flags.vm_cookie = TRUE; 1008 } 1009 } 1010 break; 1011 1012 case SYM_SIMILAR_ENTRY: 1013 switch (optype) { 1014 case OP_ADDITION: 1015 fill_defaults(hp, symbol); 1016 break; 1017 default: 1018 return E_SYNTAX_ERROR; 1019 } 1020 break; 1021 1022 case SYM_NAME_SWITCH: 1023 switch (optype) { 1024 case OP_ADDITION: 1025 return E_SYNTAX_ERROR; 1026 case OP_DELETION: 1027 hp->flags.send_name = FALSE; 1028 hp->flags.name_switch = FALSE; 1029 break; 1030 case OP_BOOLEAN: 1031 hp->flags.send_name = TRUE; 1032 hp->flags.name_switch = TRUE; 1033 break; 1034 } 1035 break; 1036 1037 case SYM_BOOTSIZE: 1038 switch (optype) { 1039 case OP_ADDITION: 1040 if (!strncmp(*symbol, "auto", 4)) { 1041 hp->flags.bootsize = TRUE; 1042 hp->flags.bootsize_auto = TRUE; 1043 } else { 1044 hp->bootsize = (unsigned int) get_u_long(symbol); 1045 hp->flags.bootsize = TRUE; 1046 hp->flags.bootsize_auto = FALSE; 1047 } 1048 break; 1049 case OP_DELETION: 1050 hp->flags.bootsize = FALSE; 1051 break; 1052 case OP_BOOLEAN: 1053 hp->flags.bootsize = TRUE; 1054 hp->flags.bootsize_auto = TRUE; 1055 break; 1056 } 1057 break; 1058 1059 case SYM_BOOT_SERVER: 1060 PARSE_IA1(bootserver); 1061 break; 1062 1063 case SYM_TFTPDIR: 1064 PARSE_STR(tftpdir); 1065 if ((hp->tftpdir != NULL) && 1066 (hp->tftpdir->string[0] != '/')) 1067 return E_BAD_PATHNAME; 1068 break; 1069 1070 case SYM_DUMP_FILE: 1071 PARSE_STR(dump_file); 1072 break; 1073 1074 case SYM_DOMAIN_NAME: 1075 PARSE_STR(domain_name); 1076 break; 1077 1078 case SYM_SWAP_SERVER: 1079 PARSE_IA1(swap_server); 1080 break; 1081 1082 case SYM_ROOT_PATH: 1083 PARSE_STR(root_path); 1084 break; 1085 1086 case SYM_EXTEN_FILE: 1087 PARSE_STR(exten_file); 1088 break; 1089 1090 case SYM_REPLY_ADDR: 1091 PARSE_IA1(reply_addr); 1092 break; 1093 1094 case SYM_NIS_DOMAIN: 1095 PARSE_STR(nis_domain); 1096 break; 1097 1098 case SYM_NIS_SERVER: 1099 PARSE_IAL(nis_server); 1100 break; 1101 1102 case SYM_NTP_SERVER: 1103 PARSE_IAL(ntp_server); 1104 break; 1105 1106 #ifdef YORK_EX_OPTION 1107 case SYM_EXEC_FILE: 1108 PARSE_STR(exec_file); 1109 break; 1110 #endif 1111 1112 case SYM_MSG_SIZE: 1113 PARSE_INT(msg_size); 1114 if (hp->msg_size < BP_MINPKTSZ || 1115 hp->msg_size > MAX_MSG_SIZE) 1116 return E_BAD_VALUE; 1117 break; 1118 1119 case SYM_MIN_WAIT: 1120 PARSE_INT(min_wait); 1121 if (hp->min_wait == 0) 1122 return E_BAD_VALUE; 1123 break; 1124 1125 /* XXX - Add new tags here */ 1126 1127 default: 1128 return E_UNKNOWN_SYMBOL; 1129 1130 } /* switch symbolcode */ 1131 1132 return SUCCESS; 1133 } 1134 #undef PARSE_IA1 1135 #undef PARSE_IAL 1136 #undef PARSE_STR 1137 1138 1140 1141 1142 /* 1143 * Read a string from the buffer indirectly pointed to through "src" and 1144 * move it into the buffer pointed to by "dest". A pointer to the maximum 1145 * allowable length of the string (including null-terminator) is passed as 1146 * "length". The actual length of the string which was read is returned in 1147 * the unsigned integer pointed to by "length". This value is the same as 1148 * that which would be returned by applying the strlen() function on the 1149 * destination string (i.e the terminating null is not counted as a 1150 * character). Trailing whitespace is removed from the string. For 1151 * convenience, the function returns the new value of "dest". 1152 * 1153 * The string is read until the maximum number of characters, an unquoted 1154 * colon (:), or a null character is read. The return string in "dest" is 1155 * null-terminated. 1156 */ 1157 1158 PRIVATE char * 1159 get_string(char **src, char *dest, unsigned int *length) 1160 { 1161 int n, len, quoteflag; 1162 1163 quoteflag = FALSE; 1164 n = 0; 1165 len = *length - 1; 1166 while ((n < len) && (**src)) { 1167 if (!quoteflag && (**src == ':')) { 1168 break; 1169 } 1170 if (**src == '"') { 1171 (*src)++; 1172 quoteflag = !quoteflag; 1173 continue; 1174 } 1175 if (**src == '\\') { 1176 (*src)++; 1177 if (!**src) { 1178 break; 1179 } 1180 } 1181 *dest++ = *(*src)++; 1182 n++; 1183 } 1184 1185 /* 1186 * Remove that troublesome trailing whitespace. . . 1187 */ 1188 while ((n > 0) && isspace((unsigned char)dest[-1])) { 1189 dest--; 1190 n--; 1191 } 1192 1193 *dest = '\0'; 1194 *length = n; 1195 return dest; 1196 } 1197 1198 1200 1201 /* 1202 * Read the string indirectly pointed to by "src", update the caller's 1203 * pointer, and return a pointer to a malloc'ed shared_string structure 1204 * containing the string. 1205 * 1206 * The string is read using the same rules as get_string() above. 1207 */ 1208 1209 PRIVATE struct shared_string * 1210 get_shared_string(char **src) 1211 { 1212 char retstring[MAXSTRINGLEN]; 1213 struct shared_string *s; 1214 unsigned length; 1215 1216 length = sizeof(retstring); 1217 (void) get_string(src, retstring, &length); 1218 1219 s = (struct shared_string *) smalloc(sizeof(struct shared_string) + 1220 length + 1); 1221 s->linkcount = 1; 1222 memcpy(s->string, retstring, length + 1); 1223 1224 return s; 1225 } 1226 1227 1229 1230 /* 1231 * Load RFC1048 generic information directly into a memory buffer. 1232 * 1233 * "src" indirectly points to the ASCII representation of the generic data. 1234 * "dest" points to a string structure which is updated to point to a new 1235 * string with the new data appended to the old string. The old string is 1236 * freed. 1237 * 1238 * The given tag value is inserted with the new data. 1239 * 1240 * The data may be represented as either a stream of hexadecimal numbers 1241 * representing bytes (any or all bytes may optionally start with '0x' and 1242 * be separated with periods ".") or as a quoted string of ASCII 1243 * characters (the quotes are required). 1244 */ 1245 1246 PRIVATE int 1247 process_generic(char **src, struct shared_bindata **dest, u_int tagvalue) 1248 { 1249 byte tmpbuf[MAXBUFLEN]; 1250 byte *str; 1251 struct shared_bindata *bdata; 1252 u_int newlength, oldlength; 1253 1254 str = tmpbuf; 1255 *str++ = (tagvalue & 0xFF); /* Store tag value */ 1256 str++; /* Skip over length field */ 1257 if ((*src)[0] == '"') { /* ASCII data */ 1258 newlength = sizeof(tmpbuf) - 2; /* Set maximum allowed length */ 1259 (void) get_string(src, (char *) str, &newlength); 1260 /* Do NOT include the terminating null. */ 1261 } else { /* Numeric data */ 1262 newlength = 0; 1263 while (newlength < sizeof(tmpbuf) - 2) { 1264 if (interp_byte(src, str++) < 0) 1265 break; 1266 newlength++; 1267 if (**src == '.') { 1268 (*src)++; 1269 } 1270 } 1271 } 1272 if ((*src)[0] != ':') 1273 return -1; 1274 1275 tmpbuf[1] = (newlength & 0xFF); 1276 oldlength = ((*dest)->length); 1277 bdata = (struct shared_bindata *) smalloc(sizeof(struct shared_bindata) 1278 + oldlength + newlength + 1); 1279 if (oldlength > 0) { 1280 bcopy((*dest)->data, bdata->data, oldlength); 1281 } 1282 bcopy(tmpbuf, bdata->data + oldlength, newlength + 2); 1283 bdata->length = oldlength + newlength + 2; 1284 bdata->linkcount = 1; 1285 del_bindata(*dest); 1286 *dest = bdata; 1287 return 0; 1288 } 1289 1290 1292 1293 /* 1294 * Verify that the given string makes sense as a hostname (according to 1295 * Appendix 1, page 29 of RFC882). 1296 * 1297 * Return TRUE for good names, FALSE otherwise. 1298 */ 1299 1300 PRIVATE boolean 1301 goodname(char *hostname) 1302 { 1303 do { 1304 if (!isalpha((unsigned char)*hostname++)) { /* First character must be a letter */ 1305 return FALSE; 1306 } 1307 while (isalnum((unsigned char)*hostname) || 1308 (*hostname == '-') || 1309 (*hostname == '_') ) 1310 { 1311 hostname++; /* Alphanumeric or a hyphen */ 1312 } 1313 if (!isalnum((unsigned char)hostname[-1])) { /* Last must be alphanumeric */ 1314 return FALSE; 1315 } 1316 if (*hostname == '\0') {/* Done? */ 1317 return TRUE; 1318 } 1319 } while (*hostname++ == '.'); /* Dot, loop for next label */ 1320 1321 return FALSE; /* If it's not a dot, lose */ 1322 } 1323 1324 1326 1327 /* 1328 * Null compare function -- always returns FALSE so an element is always 1329 * inserted into a hash table (i.e. there is never a collision with an 1330 * existing element). 1331 */ 1332 1333 PRIVATE boolean 1334 nullcmp(hash_datum *d1, hash_datum *d2) 1335 { 1336 return FALSE; 1337 } 1338 1339 1340 /* 1341 * Function for comparing a string with the hostname field of a host 1342 * structure. 1343 */ 1344 1345 boolean 1346 nmcmp(hash_datum *d1, hash_datum *d2) 1347 { 1348 char *name = (char *) d1; /* XXX - OK? */ 1349 struct host *hp = (struct host *) d2; 1350 1351 return !strcmp(name, hp->hostname->string); 1352 } 1353 1354 1355 /* 1356 * Compare function to determine whether two hardware addresses are 1357 * equivalent. Returns TRUE if "host1" and "host2" are equivalent, FALSE 1358 * otherwise. 1359 * 1360 * If the hardware addresses of "host1" and "host2" are identical, but 1361 * they are on different IP subnets, this function returns FALSE. 1362 * 1363 * This function is used when inserting elements into the hardware address 1364 * hash table. 1365 */ 1366 1367 PRIVATE boolean 1368 hwinscmp(hash_datum *d1, hash_datum *d2) 1369 { 1370 struct host *host1 = (struct host *) d1; 1371 struct host *host2 = (struct host *) d2; 1372 1373 if (host1->htype != host2->htype) { 1374 return FALSE; 1375 } 1376 if (bcmp(host1->haddr, host2->haddr, haddrlength(host1->htype))) { 1377 return FALSE; 1378 } 1379 /* XXX - Is the subnet_mask field set yet? */ 1380 if ((host1->subnet_mask.s_addr) == (host2->subnet_mask.s_addr)) { 1381 if (((host1->iaddr.s_addr) & (host1->subnet_mask.s_addr)) != 1382 ((host2->iaddr.s_addr) & (host2->subnet_mask.s_addr))) 1383 { 1384 return FALSE; 1385 } 1386 } 1387 return TRUE; 1388 } 1389 1390 1392 /* 1393 * Macros for use in the function below: 1394 */ 1395 1396 #define DUP_COPY(MEMBER) do \ 1397 { \ 1398 if (!hp->flags.MEMBER) { \ 1399 if ((hp->flags.MEMBER = hp2->flags.MEMBER) != 0) { \ 1400 hp->MEMBER = hp2->MEMBER; \ 1401 } \ 1402 } \ 1403 } while (0) 1404 1405 #define DUP_LINK(MEMBER) do \ 1406 { \ 1407 if (!hp->flags.MEMBER) { \ 1408 if ((hp->flags.MEMBER = hp2->flags.MEMBER) != 0) { \ 1409 assert(hp2->MEMBER); \ 1410 hp->MEMBER = hp2->MEMBER; \ 1411 (hp->MEMBER->linkcount)++; \ 1412 } \ 1413 } \ 1414 } while (0) 1415 1416 /* 1417 * Process the "similar entry" symbol. 1418 * 1419 * The host specified as the value of the "tc" symbol is used as a template 1420 * for the current host entry. Symbol values not explicitly set in the 1421 * current host entry are inferred from the template entry. 1422 */ 1423 PRIVATE void 1424 fill_defaults(struct host *hp, char **src) 1425 { 1426 unsigned int tlen, hashcode; 1427 struct host *hp2; 1428 char tstring[MAXSTRINGLEN]; 1429 1430 tlen = sizeof(tstring); 1431 (void) get_string(src, tstring, &tlen); 1432 hashcode = hash_HashFunction((u_char *) tstring, tlen); 1433 hp2 = (struct host *) hash_Lookup(nmhashtable, hashcode, nmcmp, tstring); 1434 1435 if (hp2 == NULL) { 1436 report(LOG_ERR, "can't find tc=\"%s\"", tstring); 1437 return; 1438 } 1439 DUP_LINK(bootfile); 1440 DUP_LINK(cookie_server); 1441 DUP_LINK(domain_server); 1442 DUP_LINK(gateway); 1443 /* haddr not copied */ 1444 DUP_LINK(homedir); 1445 DUP_COPY(htype); 1446 1447 DUP_LINK(impress_server); 1448 /* iaddr not copied */ 1449 DUP_LINK(log_server); 1450 DUP_LINK(lpr_server); 1451 DUP_LINK(name_server); 1452 DUP_LINK(rlp_server); 1453 1454 DUP_COPY(subnet_mask); 1455 DUP_COPY(time_offset); 1456 DUP_LINK(time_server); 1457 1458 if (!hp->flags.vm_cookie) { 1459 if ((hp->flags.vm_cookie = hp2->flags.vm_cookie)) { 1460 bcopy(hp2->vm_cookie, hp->vm_cookie, 4); 1461 } 1462 } 1463 if (!hp->flags.name_switch) { 1464 if ((hp->flags.name_switch = hp2->flags.name_switch)) { 1465 hp->flags.send_name = hp2->flags.send_name; 1466 } 1467 } 1468 if (!hp->flags.bootsize) { 1469 if ((hp->flags.bootsize = hp2->flags.bootsize)) { 1470 hp->flags.bootsize_auto = hp2->flags.bootsize_auto; 1471 hp->bootsize = hp2->bootsize; 1472 } 1473 } 1474 DUP_COPY(bootserver); 1475 1476 DUP_LINK(tftpdir); 1477 DUP_LINK(dump_file); 1478 DUP_LINK(domain_name); 1479 1480 DUP_COPY(swap_server); 1481 DUP_LINK(root_path); 1482 DUP_LINK(exten_file); 1483 1484 DUP_COPY(reply_addr); 1485 1486 DUP_LINK(nis_domain); 1487 DUP_LINK(nis_server); 1488 DUP_LINK(ntp_server); 1489 1490 #ifdef YORK_EX_OPTION 1491 DUP_LINK(exec_file); 1492 #endif 1493 1494 DUP_COPY(msg_size); 1495 DUP_COPY(min_wait); 1496 1497 /* XXX - Add new tags here */ 1498 1499 DUP_LINK(generic); 1500 1501 } 1502 #undef DUP_COPY 1503 #undef DUP_LINK 1504 1505 1507 1508 /* 1509 * This function adjusts the caller's pointer to point just past the 1510 * first-encountered colon. If it runs into a null character, it leaves 1511 * the pointer pointing to it. 1512 */ 1513 1514 PRIVATE void 1515 adjust(char **s) 1516 { 1517 char *t; 1518 1519 t = *s; 1520 while (*t && (*t != ':')) { 1521 t++; 1522 } 1523 if (*t) { 1524 t++; 1525 } 1526 *s = t; 1527 } 1528 1529 1530 1531 1532 /* 1533 * This function adjusts the caller's pointer to point to the first 1534 * non-whitespace character. If it runs into a null character, it leaves 1535 * the pointer pointing to it. 1536 */ 1537 1538 PRIVATE void 1539 eat_whitespace(char **s) 1540 { 1541 char *t; 1542 1543 t = *s; 1544 while (*t && isspace((unsigned char)*t)) { 1545 t++; 1546 } 1547 *s = t; 1548 } 1549 1550 1551 1552 /* 1553 * This function converts the given string to all lowercase. 1554 */ 1555 1556 PRIVATE void 1557 makelower(char *s) 1558 { 1559 while (*s) { 1560 if (isupper((unsigned char)*s)) { 1561 *s = tolower((unsigned char)*s); 1562 } 1563 s++; 1564 } 1565 } 1566 1567 1569 1570 /* 1571 * 1572 * N O T E : 1573 * 1574 * In many of the functions which follow, a parameter such as "src" or 1575 * "symbol" is passed as a pointer to a pointer to something. This is 1576 * done for the purpose of letting the called function update the 1577 * caller's copy of the parameter (i.e. to effect call-by-reference 1578 * parameter passing). The value of the actual parameter is only used 1579 * to locate the real parameter of interest and then update this indirect 1580 * parameter. 1581 * 1582 * I'm sure somebody out there won't like this. . . . 1583 * (Yea, because it usually makes code slower... -gwr) 1584 * 1585 */ 1586 1587 1589 1590 /* 1591 * "src" points to a character pointer which points to an ASCII string of 1592 * whitespace-separated IP addresses. A pointer to an in_addr_list 1593 * structure containing the list of addresses is returned. NULL is 1594 * returned if no addresses were found at all. The pointer pointed to by 1595 * "src" is updated to point to the first non-address (illegal) character. 1596 */ 1597 1598 PRIVATE struct in_addr_list * 1599 get_addresses(char **src) 1600 { 1601 __aligned(4) struct in_addr tmpaddrlist[MAXINADDRS]; 1602 struct in_addr_list *result; 1603 unsigned addrcount, totalsize, address; 1604 1605 for (address = 0, addrcount = 0; addrcount < MAXINADDRS; addrcount++) { 1606 while (isspace((unsigned char)**src) || (**src == ',')) { 1607 (*src)++; 1608 } 1609 if (!**src) { /* Quit if nothing more */ 1610 break; 1611 } 1612 if (prs_inetaddr(src, &tmpaddrlist[address].s_addr) < 0) { 1613 break; 1614 } 1615 address++; /* Point to next address slot */ 1616 } 1617 if (addrcount < 1) { 1618 result = NULL; 1619 } else { 1620 totalsize = sizeof(struct in_addr_list) 1621 + (addrcount - 1) * sizeof(struct in_addr); 1622 result = (struct in_addr_list *) smalloc(totalsize); 1623 result->linkcount = 1; 1624 result->addrcount = addrcount; 1625 for (address = 0; address < addrcount; ++address) 1626 result->addr[address] = tmpaddrlist[address]; 1627 } 1628 return result; 1629 } 1630 1631 1633 1634 /* 1635 * prs_inetaddr(src, result) 1636 * 1637 * "src" is a value-result parameter; the pointer it points to is updated 1638 * to point to the next data position. "result" points to an unsigned long 1639 * in which an address is returned. 1640 * 1641 * This function parses the IP address string in ASCII "dot notation" pointed 1642 * to by (*src) and places the result (in network byte order) in the unsigned 1643 * long pointed to by "result". For malformed addresses, -1 is returned, 1644 * (*src) points to the first illegal character, and the unsigned long pointed 1645 * to by "result" is unchanged. Successful calls return 0. 1646 */ 1647 1648 PRIVATE int 1649 prs_inetaddr(char **src, u_int32 *result) 1650 { 1651 char tmpstr[MAXSTRINGLEN]; 1652 u_int32 value; 1653 u_int32 parts[4], *pp; 1654 int n; 1655 char *s, *t; 1656 1657 #if 1 /* XXX - experimental */ 1658 /* Leading alpha char causes IP addr lookup. */ 1659 if (isalpha((unsigned char)**src)) { 1660 /* Lookup IP address. */ 1661 s = *src; 1662 t = tmpstr; 1663 while ((isalnum((unsigned char)*s) || (*s == '.') || 1664 (*s == '-') || (*s == '_') ) && 1665 (t < &tmpstr[MAXSTRINGLEN - 1]) ) 1666 *t++ = *s++; 1667 *t = '\0'; 1668 *src = s; 1669 1670 n = lookup_ipa(tmpstr, result); 1671 if (n < 0) 1672 report(LOG_ERR, "can not get IP addr for %s", tmpstr); 1673 return n; 1674 } 1675 #endif 1676 1677 /* 1678 * Parse an address in Internet format: 1679 * a.b.c.d 1680 * a.b.c (with c treated as 16-bits) 1681 * a.b (with b treated as 24 bits) 1682 */ 1683 pp = parts; 1684 loop: 1685 /* If it's not a digit, return error. */ 1686 if (!isdigit((unsigned char)**src)) 1687 return -1; 1688 *pp++ = get_u_long(src); 1689 if (**src == '.') { 1690 if (pp < (parts + 4)) { 1691 (*src)++; 1692 goto loop; 1693 } 1694 return (-1); 1695 } 1696 #if 0 1697 /* This is handled by the caller. */ 1698 if (**src && !((unsigned char)isspace(**src) || (**src == ':'))) { 1699 return (-1); 1700 } 1701 #endif 1702 1703 /* 1704 * Construct the address according to 1705 * the number of parts specified. 1706 */ 1707 n = pp - parts; 1708 switch (n) { 1709 case 1: /* a -- 32 bits */ 1710 value = parts[0]; 1711 break; 1712 case 2: /* a.b -- 8.24 bits */ 1713 value = (parts[0] << 24) | (parts[1] & 0xFFFFFF); 1714 break; 1715 case 3: /* a.b.c -- 8.8.16 bits */ 1716 value = (parts[0] << 24) | ((parts[1] & 0xFF) << 16) | 1717 (parts[2] & 0xFFFF); 1718 break; 1719 case 4: /* a.b.c.d -- 8.8.8.8 bits */ 1720 value = (parts[0] << 24) | ((parts[1] & 0xFF) << 16) | 1721 ((parts[2] & 0xFF) << 8) | (parts[3] & 0xFF); 1722 break; 1723 default: 1724 return (-1); 1725 } 1726 *result = htonl(value); 1727 return (0); 1728 } 1729 1730 1732 1733 /* 1734 * "src" points to a pointer which in turn points to a hexadecimal ASCII 1735 * string. This string is interpreted as a hardware address and returned 1736 * as a pointer to the actual hardware address, represented as an array of 1737 * bytes. 1738 * 1739 * The ASCII string must have the proper number of digits for the specified 1740 * hardware type (e.g. twelve digits for a 48-bit Ethernet address). 1741 * Two-digit sequences (bytes) may be separated with periods (.) and/or 1742 * prefixed with '0x' for readability, but this is not required. 1743 * 1744 * For bad addresses, the pointer which "src" points to is updated to point 1745 * to the start of the first two-digit sequence which was bad, and the 1746 * function returns a NULL pointer. 1747 */ 1748 1749 PRIVATE byte * 1750 prs_haddr(char **src, u_int htype) 1751 { 1752 static byte haddr[MAXHADDRLEN]; 1753 byte *hap; 1754 char tmpstr[MAXSTRINGLEN]; 1755 u_int tmplen; 1756 unsigned hal; 1757 char *p; 1758 1759 hal = haddrlength(htype); /* Get length of this address type */ 1760 if (hal <= 0) { 1761 report(LOG_ERR, "Invalid addr type for HW addr parse"); 1762 return NULL; 1763 } 1764 tmplen = sizeof(tmpstr); 1765 get_string(src, tmpstr, &tmplen); 1766 p = tmpstr; 1767 1768 #if 1 /* XXX - experimental */ 1769 /* If it's a valid host name, try to lookup the HW address. */ 1770 if (goodname(p)) { 1771 /* Lookup Hardware Address for hostname. */ 1772 if ((hap = lookup_hwa(p, htype)) != NULL) 1773 return hap; /* success */ 1774 report(LOG_ERR, "Add 0x prefix if hex value starts with A-F"); 1775 /* OK, assume it must be numeric. */ 1776 } 1777 #endif 1778 1779 hap = haddr; 1780 while (hap < haddr + hal) { 1781 if ((*p == '.') || (*p == ':')) 1782 p++; 1783 if (interp_byte(&p, hap++) < 0) { 1784 return NULL; 1785 } 1786 } 1787 return haddr; 1788 } 1789 1790 1792 1793 /* 1794 * "src" is a pointer to a character pointer which in turn points to a 1795 * hexadecimal ASCII representation of a byte. This byte is read, the 1796 * character pointer is updated, and the result is deposited into the 1797 * byte pointed to by "retbyte". 1798 * 1799 * The usual '0x' notation is allowed but not required. The number must be 1800 * a two digit hexadecimal number. If the number is invalid, "src" and 1801 * "retbyte" are left untouched and -1 is returned as the function value. 1802 * Successful calls return 0. 1803 */ 1804 1805 PRIVATE int 1806 interp_byte(char **src, byte *retbyte) 1807 { 1808 int v; 1809 1810 if ((*src)[0] == '0' && 1811 ((*src)[1] == 'x' || 1812 (*src)[1] == 'X')) { 1813 (*src) += 2; /* allow 0x for hex, but don't require it */ 1814 } 1815 if (!isxdigit((unsigned char)(*src)[0]) || !isxdigit((unsigned char)(*src)[1])) { 1816 return -1; 1817 } 1818 if (sscanf(*src, "%2x", &v) != 1) { 1819 return -1; 1820 } 1821 (*src) += 2; 1822 *retbyte = (byte) (v & 0xFF); 1823 return 0; 1824 } 1825 1826 1828 1829 /* 1830 * The parameter "src" points to a character pointer which points to an 1831 * ASCII string representation of an unsigned number. The number is 1832 * returned as an unsigned long and the character pointer is updated to 1833 * point to the first illegal character. 1834 */ 1835 1836 PRIVATE u_int32 1837 get_u_long(char **src) 1838 { 1839 u_int32 value, base; 1840 char c; 1841 1842 /* 1843 * Collect number up to first illegal character. Values are specified 1844 * as for C: 0x=hex, 0=octal, other=decimal. 1845 */ 1846 value = 0; 1847 base = 10; 1848 if (**src == '0') { 1849 base = 8; 1850 (*src)++; 1851 } 1852 if (**src == 'x' || **src == 'X') { 1853 base = 16; 1854 (*src)++; 1855 } 1856 while ((c = **src)) { 1857 if (isdigit((unsigned char)c)) { 1858 value = (value * base) + (c - '0'); 1859 (*src)++; 1860 continue; 1861 } 1862 if (base == 16 && isxdigit((unsigned char)c)) { 1863 value = (value << 4) + ((c & ~32) + 10 - 'A'); 1864 (*src)++; 1865 continue; 1866 } 1867 break; 1868 } 1869 return value; 1870 } 1871 1872 1874 1875 /* 1876 * Routines for deletion of data associated with the main data structure. 1877 */ 1878 1879 1880 /* 1881 * Frees the entire host data structure given. Does nothing if the passed 1882 * pointer is NULL. 1883 */ 1884 1885 PRIVATE void 1886 free_host(hash_datum *hmp) 1887 { 1888 struct host *hostptr = (struct host *) hmp; 1889 if (hostptr == NULL) 1890 return; 1891 assert(hostptr->linkcount > 0); 1892 if (--(hostptr->linkcount)) 1893 return; /* Still has references */ 1894 del_iplist(hostptr->cookie_server); 1895 del_iplist(hostptr->domain_server); 1896 del_iplist(hostptr->gateway); 1897 del_iplist(hostptr->impress_server); 1898 del_iplist(hostptr->log_server); 1899 del_iplist(hostptr->lpr_server); 1900 del_iplist(hostptr->name_server); 1901 del_iplist(hostptr->rlp_server); 1902 del_iplist(hostptr->time_server); 1903 del_iplist(hostptr->nis_server); 1904 del_iplist(hostptr->ntp_server); 1905 1906 /* 1907 * XXX - Add new tags here 1908 * (if the value is an IP list) 1909 */ 1910 1911 del_string(hostptr->hostname); 1912 del_string(hostptr->homedir); 1913 del_string(hostptr->bootfile); 1914 del_string(hostptr->tftpdir); 1915 del_string(hostptr->root_path); 1916 del_string(hostptr->domain_name); 1917 del_string(hostptr->dump_file); 1918 del_string(hostptr->exten_file); 1919 del_string(hostptr->nis_domain); 1920 1921 #ifdef YORK_EX_OPTION 1922 del_string(hostptr->exec_file); 1923 #endif 1924 1925 /* 1926 * XXX - Add new tags here 1927 * (if it is a shared string) 1928 */ 1929 1930 del_bindata(hostptr->generic); 1931 free((char *) hostptr); 1932 } 1933 1934 1936 1937 /* 1938 * Decrements the linkcount on the given IP address data structure. If the 1939 * linkcount goes to zero, the memory associated with the data is freed. 1940 */ 1941 1942 PRIVATE void 1943 del_iplist(struct in_addr_list *iplist) 1944 { 1945 if (iplist) { 1946 if (!(--(iplist->linkcount))) { 1947 free((char *) iplist); 1948 } 1949 } 1950 } 1951 1952 1953 1954 /* 1955 * Decrements the linkcount on a string data structure. If the count 1956 * goes to zero, the memory associated with the string is freed. Does 1957 * nothing if the passed pointer is NULL. 1958 */ 1959 1960 PRIVATE void 1961 del_string(struct shared_string *stringptr) 1962 { 1963 if (stringptr) { 1964 if (!(--(stringptr->linkcount))) { 1965 free((char *) stringptr); 1966 } 1967 } 1968 } 1969 1970 1971 1972 /* 1973 * Decrements the linkcount on a shared_bindata data structure. If the 1974 * count goes to zero, the memory associated with the data is freed. Does 1975 * nothing if the passed pointer is NULL. 1976 */ 1977 1978 PRIVATE void 1979 del_bindata(struct shared_bindata *dataptr) 1980 { 1981 if (dataptr) { 1982 if (!(--(dataptr->linkcount))) { 1983 free((char *) dataptr); 1984 } 1985 } 1986 } 1987 1988 1990 1991 1992 /* smalloc() -- safe malloc() 1993 * 1994 * Always returns a valid pointer (if it returns at all). The allocated 1995 * memory is initialized to all zeros. If malloc() returns an error, a 1996 * message is printed using the report() function and the program aborts 1997 * with a status of 1. 1998 */ 1999 2000 PRIVATE char * 2001 smalloc(unsigned int nbytes) 2002 { 2003 char *retvalue; 2004 2005 retvalue = malloc(nbytes); 2006 if (!retvalue) { 2007 report(LOG_ERR, "malloc() failure -- exiting"); 2008 exit(1); 2009 } 2010 bzero(retvalue, nbytes); 2011 return retvalue; 2012 } 2013 2014 2016 /* 2017 * Compare function to determine whether two hardware addresses are 2018 * equivalent. Returns TRUE if "host1" and "host2" are equivalent, FALSE 2019 * otherwise. 2020 * 2021 * This function is used when retrieving elements from the hardware address 2022 * hash table. 2023 */ 2024 2025 boolean 2026 hwlookcmp(hash_datum *d1, hash_datum *d2) 2027 { 2028 struct host *host1 = (struct host *) d1; 2029 struct host *host2 = (struct host *) d2; 2030 2031 if (host1->htype != host2->htype) { 2032 return FALSE; 2033 } 2034 if (bcmp(host1->haddr, host2->haddr, haddrlength(host1->htype))) { 2035 return FALSE; 2036 } 2037 return TRUE; 2038 } 2039 2040 2041 /* 2042 * Compare function for doing IP address hash table lookup. 2043 */ 2044 2045 boolean 2046 iplookcmp(hash_datum *d1, hash_datum *d2) 2047 { 2048 struct host *host1 = (struct host *) d1; 2049 struct host *host2 = (struct host *) d2; 2050 2051 return (host1->iaddr.s_addr == host2->iaddr.s_addr); 2052 } 2053 2054 /* 2055 * Local Variables: 2056 * tab-width: 4 2057 * c-indent-level: 4 2058 * c-argdecl-indent: 4 2059 * c-continued-statement-offset: 4 2060 * c-continued-brace-offset: -4 2061 * c-label-offset: -4 2062 * c-brace-offset: 0 2063 * End: 2064 */ 2065