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