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