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