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: readfile.c,v 1.4 1997/02/22 14:21:09 peter Exp $ 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 snprintf(current_tagname, sizeof(current_tagname), 821 "T%d", (int)value); 822 eat_whitespace(symbol); 823 if ((*symbol)[0] != '=') { 824 return E_SYNTAX_ERROR; 825 } 826 (*symbol)++; 827 if (!(hp->generic)) { 828 hp->generic = (struct shared_bindata *) 829 smalloc(sizeof(struct shared_bindata)); 830 } 831 if (process_generic(symbol, &(hp->generic), (byte) (value & 0xFF))) 832 return E_SYNTAX_ERROR; 833 hp->flags.generic = TRUE; 834 return SUCCESS; 835 } 836 /* 837 * Determine the type of operation to be done on this symbol 838 */ 839 switch ((*symbol)[2]) { 840 case '=': 841 optype = OP_ADDITION; 842 break; 843 case '@': 844 optype = OP_DELETION; 845 break; 846 case ':': 847 case '\0': 848 optype = OP_BOOLEAN; 849 break; 850 default: 851 return E_SYNTAX_ERROR; 852 } 853 854 symbolptr = symbol_list; 855 numsymbols = sizeof(symbol_list) / sizeof(struct symbolmap); 856 for (i = 0; i < numsymbols; i++) { 857 if (((symbolptr->symbol)[0] == (*symbol)[0]) && 858 ((symbolptr->symbol)[1] == (*symbol)[1])) { 859 break; 860 } 861 symbolptr++; 862 } 863 if (i >= numsymbols) { 864 return E_UNKNOWN_SYMBOL; 865 } 866 /* 867 * Skip past the = or @ character (to point to the data) if this 868 * isn't a boolean operation. For boolean operations, just skip 869 * over the two-character tag symbol (and nothing else. . . .). 870 */ 871 (*symbol) += (optype == OP_BOOLEAN) ? 2 : 3; 872 873 eat_whitespace(symbol); 874 875 /* The cases below are in order by symbolcode value. */ 876 switch (symbolptr->symbolcode) { 877 878 case SYM_BOOTFILE: 879 PARSE_STR(bootfile); 880 break; 881 882 case SYM_COOKIE_SERVER: 883 PARSE_IAL(cookie_server); 884 break; 885 886 case SYM_DOMAIN_SERVER: 887 PARSE_IAL(domain_server); 888 break; 889 890 case SYM_GATEWAY: 891 PARSE_IAL(gateway); 892 break; 893 894 case SYM_HWADDR: 895 if (optype == OP_BOOLEAN) 896 return E_SYNTAX_ERROR; 897 hp->flags.haddr = FALSE; 898 if (optype == OP_ADDITION) { 899 /* Default the HW type to Ethernet */ 900 if (hp->flags.htype == 0) { 901 hp->flags.htype = TRUE; 902 hp->htype = HTYPE_ETHERNET; 903 } 904 tmphaddr = prs_haddr(symbol, hp->htype); 905 if (!tmphaddr) 906 return E_BAD_HWADDR; 907 bcopy(tmphaddr, hp->haddr, haddrlength(hp->htype)); 908 hp->flags.haddr = TRUE; 909 } 910 break; 911 912 case SYM_HOMEDIR: 913 PARSE_STR(homedir); 914 break; 915 916 case SYM_HTYPE: 917 if (optype == OP_BOOLEAN) 918 return E_SYNTAX_ERROR; 919 hp->flags.htype = FALSE; 920 if (optype == OP_ADDITION) { 921 value = 0L; /* Assume an illegal value */ 922 eat_whitespace(symbol); 923 if (isdigit(**symbol)) { 924 value = get_u_long(symbol); 925 } else { 926 len = sizeof(tmpstr); 927 (void) get_string(symbol, tmpstr, &len); 928 makelower(tmpstr); 929 numsymbols = sizeof(htnamemap) / 930 sizeof(struct htypename); 931 for (i = 0; i < numsymbols; i++) { 932 if (!strcmp(htnamemap[i].name, tmpstr)) { 933 break; 934 } 935 } 936 if (i < numsymbols) { 937 value = htnamemap[i].htype; 938 } 939 } 940 if (value >= hwinfocnt) { 941 return E_BAD_HWATYPE; 942 } 943 hp->htype = (byte) (value & 0xFF); 944 hp->flags.htype = TRUE; 945 } 946 break; 947 948 case SYM_IMPRESS_SERVER: 949 PARSE_IAL(impress_server); 950 break; 951 952 case SYM_IPADDR: 953 PARSE_IA1(iaddr); 954 break; 955 956 case SYM_LOG_SERVER: 957 PARSE_IAL(log_server); 958 break; 959 960 case SYM_LPR_SERVER: 961 PARSE_IAL(lpr_server); 962 break; 963 964 case SYM_NAME_SERVER: 965 PARSE_IAL(name_server); 966 break; 967 968 case SYM_RLP_SERVER: 969 PARSE_IAL(rlp_server); 970 break; 971 972 case SYM_SUBNET_MASK: 973 PARSE_IA1(subnet_mask); 974 break; 975 976 case SYM_TIME_OFFSET: 977 if (optype == OP_BOOLEAN) 978 return E_SYNTAX_ERROR; 979 hp->flags.time_offset = FALSE; 980 if (optype == OP_ADDITION) { 981 len = sizeof(tmpstr); 982 (void) get_string(symbol, tmpstr, &len); 983 if (!strncmp(tmpstr, "auto", 4)) { 984 hp->time_offset = secondswest; 985 } else { 986 if (sscanf(tmpstr, "%d", (int*)&timeoff) != 1) 987 return E_BAD_LONGWORD; 988 hp->time_offset = timeoff; 989 } 990 hp->flags.time_offset = TRUE; 991 } 992 break; 993 994 case SYM_TIME_SERVER: 995 PARSE_IAL(time_server); 996 break; 997 998 case SYM_VENDOR_MAGIC: 999 if (optype == OP_BOOLEAN) 1000 return E_SYNTAX_ERROR; 1001 hp->flags.vm_cookie = FALSE; 1002 if (optype == OP_ADDITION) { 1003 if (strncmp(*symbol, "auto", 4)) { 1004 /* The string is not "auto" */ 1005 if (!strncmp(*symbol, "rfc", 3)) { 1006 bcopy(vm_rfc1048, hp->vm_cookie, 4); 1007 } else if (!strncmp(*symbol, "cmu", 3)) { 1008 bcopy(vm_cmu, hp->vm_cookie, 4); 1009 } else { 1010 if (!isdigit(**symbol)) 1011 return E_BAD_IPADDR; 1012 if (prs_inetaddr(symbol, &value) < 0) 1013 return E_BAD_IPADDR; 1014 bcopy(&value, hp->vm_cookie, 4); 1015 } 1016 hp->flags.vm_cookie = TRUE; 1017 } 1018 } 1019 break; 1020 1021 case SYM_SIMILAR_ENTRY: 1022 switch (optype) { 1023 case OP_ADDITION: 1024 fill_defaults(hp, symbol); 1025 break; 1026 default: 1027 return E_SYNTAX_ERROR; 1028 } 1029 break; 1030 1031 case SYM_NAME_SWITCH: 1032 switch (optype) { 1033 case OP_ADDITION: 1034 return E_SYNTAX_ERROR; 1035 case OP_DELETION: 1036 hp->flags.send_name = FALSE; 1037 hp->flags.name_switch = FALSE; 1038 break; 1039 case OP_BOOLEAN: 1040 hp->flags.send_name = TRUE; 1041 hp->flags.name_switch = TRUE; 1042 break; 1043 } 1044 break; 1045 1046 case SYM_BOOTSIZE: 1047 switch (optype) { 1048 case OP_ADDITION: 1049 if (!strncmp(*symbol, "auto", 4)) { 1050 hp->flags.bootsize = TRUE; 1051 hp->flags.bootsize_auto = TRUE; 1052 } else { 1053 hp->bootsize = (unsigned int) get_u_long(symbol); 1054 hp->flags.bootsize = TRUE; 1055 hp->flags.bootsize_auto = FALSE; 1056 } 1057 break; 1058 case OP_DELETION: 1059 hp->flags.bootsize = FALSE; 1060 break; 1061 case OP_BOOLEAN: 1062 hp->flags.bootsize = TRUE; 1063 hp->flags.bootsize_auto = TRUE; 1064 break; 1065 } 1066 break; 1067 1068 case SYM_BOOT_SERVER: 1069 PARSE_IA1(bootserver); 1070 break; 1071 1072 case SYM_TFTPDIR: 1073 PARSE_STR(tftpdir); 1074 if ((hp->tftpdir != NULL) && 1075 (hp->tftpdir->string[0] != '/')) 1076 return E_BAD_PATHNAME; 1077 break; 1078 1079 case SYM_DUMP_FILE: 1080 PARSE_STR(dump_file); 1081 break; 1082 1083 case SYM_DOMAIN_NAME: 1084 PARSE_STR(domain_name); 1085 break; 1086 1087 case SYM_SWAP_SERVER: 1088 PARSE_IA1(swap_server); 1089 break; 1090 1091 case SYM_ROOT_PATH: 1092 PARSE_STR(root_path); 1093 break; 1094 1095 case SYM_EXTEN_FILE: 1096 PARSE_STR(exten_file); 1097 break; 1098 1099 case SYM_REPLY_ADDR: 1100 PARSE_IA1(reply_addr); 1101 break; 1102 1103 case SYM_NIS_DOMAIN: 1104 PARSE_STR(nis_domain); 1105 break; 1106 1107 case SYM_NIS_SERVER: 1108 PARSE_IAL(nis_server); 1109 break; 1110 1111 case SYM_NTP_SERVER: 1112 PARSE_IAL(ntp_server); 1113 break; 1114 1115 #ifdef YORK_EX_OPTION 1116 case SYM_EXEC_FILE: 1117 PARSE_STR(exec_file); 1118 break; 1119 #endif 1120 1121 case SYM_MSG_SIZE: 1122 PARSE_UINT(msg_size); 1123 if (hp->msg_size < BP_MINPKTSZ || 1124 hp->msg_size > MAX_MSG_SIZE) 1125 return E_BAD_VALUE; 1126 break; 1127 1128 case SYM_MIN_WAIT: 1129 PARSE_UINT(min_wait); 1130 break; 1131 1132 /* XXX - Add new tags here */ 1133 1134 default: 1135 return E_UNKNOWN_SYMBOL; 1136 1137 } /* switch symbolcode */ 1138 1139 return SUCCESS; 1140 } 1141 #undef PARSE_IA1 1142 #undef PARSE_IAL 1143 #undef PARSE_STR 1144 1145 1146 1147 1148 /* 1149 * Read a string from the buffer indirectly pointed to through "src" and 1150 * move it into the buffer pointed to by "dest". A pointer to the maximum 1151 * allowable length of the string (including null-terminator) is passed as 1152 * "length". The actual length of the string which was read is returned in 1153 * the unsigned integer pointed to by "length". This value is the same as 1154 * that which would be returned by applying the strlen() function on the 1155 * destination string (i.e the terminating null is not counted as a 1156 * character). Trailing whitespace is removed from the string. For 1157 * convenience, the function returns the new value of "dest". 1158 * 1159 * The string is read until the maximum number of characters, an unquoted 1160 * colon (:), or a null character is read. The return string in "dest" is 1161 * null-terminated. 1162 */ 1163 1164 PRIVATE char * 1165 get_string(src, dest, length) 1166 char **src, *dest; 1167 unsigned *length; 1168 { 1169 int n, len, quoteflag; 1170 1171 quoteflag = FALSE; 1172 n = 0; 1173 len = *length - 1; 1174 while ((n < len) && (**src)) { 1175 if (!quoteflag && (**src == ':')) { 1176 break; 1177 } 1178 if (**src == '"') { 1179 (*src)++; 1180 quoteflag = !quoteflag; 1181 continue; 1182 } 1183 if (**src == '\\') { 1184 (*src)++; 1185 if (!**src) { 1186 break; 1187 } 1188 } 1189 *dest++ = *(*src)++; 1190 n++; 1191 } 1192 1193 /* 1194 * Remove that troublesome trailing whitespace. . . 1195 */ 1196 while ((n > 0) && isspace(dest[-1])) { 1197 dest--; 1198 n--; 1199 } 1200 1201 *dest = '\0'; 1202 *length = n; 1203 return dest; 1204 } 1205 1206 1207 1208 /* 1209 * Read the string indirectly pointed to by "src", update the caller's 1210 * pointer, and return a pointer to a malloc'ed shared_string structure 1211 * containing the string. 1212 * 1213 * The string is read using the same rules as get_string() above. 1214 */ 1215 1216 PRIVATE struct shared_string * 1217 get_shared_string(src) 1218 char **src; 1219 { 1220 char retstring[MAXSTRINGLEN]; 1221 struct shared_string *s; 1222 unsigned length; 1223 1224 length = sizeof(retstring); 1225 (void) get_string(src, retstring, &length); 1226 1227 s = (struct shared_string *) smalloc(sizeof(struct shared_string) 1228 + length); 1229 s->linkcount = 1; 1230 strcpy(s->string, retstring); 1231 1232 return s; 1233 } 1234 1235 1236 1237 /* 1238 * Load RFC1048 generic information directly into a memory buffer. 1239 * 1240 * "src" indirectly points to the ASCII representation of the generic data. 1241 * "dest" points to a string structure which is updated to point to a new 1242 * string with the new data appended to the old string. The old string is 1243 * freed. 1244 * 1245 * The given tag value is inserted with the new data. 1246 * 1247 * The data may be represented as either a stream of hexadecimal numbers 1248 * representing bytes (any or all bytes may optionally start with '0x' and 1249 * be separated with periods ".") or as a quoted string of ASCII 1250 * characters (the quotes are required). 1251 */ 1252 1253 PRIVATE int 1254 process_generic(src, dest, tagvalue) 1255 char **src; 1256 struct shared_bindata **dest; 1257 u_int tagvalue; 1258 { 1259 byte tmpbuf[MAXBUFLEN]; 1260 byte *str; 1261 struct shared_bindata *bdata; 1262 u_int newlength, oldlength; 1263 1264 str = tmpbuf; 1265 *str++ = (tagvalue & 0xFF); /* Store tag value */ 1266 str++; /* Skip over length field */ 1267 if ((*src)[0] == '"') { /* ASCII data */ 1268 newlength = sizeof(tmpbuf) - 2; /* Set maximum allowed length */ 1269 (void) get_string(src, (char *) str, &newlength); 1270 newlength++; /* null terminator */ 1271 } else { /* Numeric data */ 1272 newlength = 0; 1273 while (newlength < sizeof(tmpbuf) - 2) { 1274 if (interp_byte(src, str++) < 0) 1275 break; 1276 newlength++; 1277 if (**src == '.') { 1278 (*src)++; 1279 } 1280 } 1281 } 1282 if ((*src)[0] != ':') 1283 return -1; 1284 1285 tmpbuf[1] = (newlength & 0xFF); 1286 oldlength = ((*dest)->length); 1287 bdata = (struct shared_bindata *) smalloc(sizeof(struct shared_bindata) 1288 + oldlength + newlength + 1); 1289 if (oldlength > 0) { 1290 bcopy((*dest)->data, bdata->data, oldlength); 1291 } 1292 bcopy(tmpbuf, bdata->data + oldlength, newlength + 2); 1293 bdata->length = oldlength + newlength + 2; 1294 bdata->linkcount = 1; 1295 if (*dest) { 1296 del_bindata(*dest); 1297 } 1298 *dest = bdata; 1299 return 0; 1300 } 1301 1302 1303 1304 /* 1305 * Verify that the given string makes sense as a hostname (according to 1306 * Appendix 1, page 29 of RFC882). 1307 * 1308 * Return TRUE for good names, FALSE otherwise. 1309 */ 1310 1311 PRIVATE boolean 1312 goodname(hostname) 1313 register char *hostname; 1314 { 1315 do { 1316 if (!isalpha(*hostname++)) { /* First character must be a letter */ 1317 return FALSE; 1318 } 1319 while (isalnum(*hostname) || 1320 (*hostname == '-') || 1321 (*hostname == '_') ) 1322 { 1323 hostname++; /* Alphanumeric or a hyphen */ 1324 } 1325 if (!isalnum(hostname[-1])) { /* Last must be alphanumeric */ 1326 return FALSE; 1327 } 1328 if (*hostname == '\0') {/* Done? */ 1329 return TRUE; 1330 } 1331 } while (*hostname++ == '.'); /* Dot, loop for next label */ 1332 1333 return FALSE; /* If it's not a dot, lose */ 1334 } 1335 1336 1337 1338 /* 1339 * Null compare function -- always returns FALSE so an element is always 1340 * inserted into a hash table (i.e. there is never a collision with an 1341 * existing element). 1342 */ 1343 1344 PRIVATE boolean 1345 nullcmp(d1, d2) 1346 hash_datum *d1, *d2; 1347 { 1348 return FALSE; 1349 } 1350 1351 1352 /* 1353 * Function for comparing a string with the hostname field of a host 1354 * structure. 1355 */ 1356 1357 boolean 1358 nmcmp(d1, d2) 1359 hash_datum *d1, *d2; 1360 { 1361 char *name = (char *) d1; /* XXX - OK? */ 1362 struct host *hp = (struct host *) d2; 1363 1364 return !strcmp(name, hp->hostname->string); 1365 } 1366 1367 1368 /* 1369 * Compare function to determine whether two hardware addresses are 1370 * equivalent. Returns TRUE if "host1" and "host2" are equivalent, FALSE 1371 * otherwise. 1372 * 1373 * If the hardware addresses of "host1" and "host2" are identical, but 1374 * they are on different IP subnets, this function returns FALSE. 1375 * 1376 * This function is used when inserting elements into the hardware address 1377 * hash table. 1378 */ 1379 1380 PRIVATE boolean 1381 hwinscmp(d1, d2) 1382 hash_datum *d1, *d2; 1383 { 1384 struct host *host1 = (struct host *) d1; 1385 struct host *host2 = (struct host *) d2; 1386 1387 if (host1->htype != host2->htype) { 1388 return FALSE; 1389 } 1390 if (bcmp(host1->haddr, host2->haddr, haddrlength(host1->htype))) { 1391 return FALSE; 1392 } 1393 /* XXX - Is the subnet_mask field set yet? */ 1394 if ((host1->subnet_mask.s_addr) == (host2->subnet_mask.s_addr)) { 1395 if (((host1->iaddr.s_addr) & (host1->subnet_mask.s_addr)) != 1396 ((host2->iaddr.s_addr) & (host2->subnet_mask.s_addr))) 1397 { 1398 return FALSE; 1399 } 1400 } 1401 return TRUE; 1402 } 1403 1404 1405 /* 1406 * Macros for use in the function below: 1407 */ 1408 1409 #define DUP_COPY(MEMBER) do \ 1410 { \ 1411 if (!hp->flags.MEMBER) { \ 1412 if ((hp->flags.MEMBER = hp2->flags.MEMBER) != 0) { \ 1413 hp->MEMBER = hp2->MEMBER; \ 1414 } \ 1415 } \ 1416 } while (0) 1417 1418 #define DUP_LINK(MEMBER) do \ 1419 { \ 1420 if (!hp->flags.MEMBER) { \ 1421 if ((hp->flags.MEMBER = hp2->flags.MEMBER) != 0) { \ 1422 assert(hp2->MEMBER); \ 1423 hp->MEMBER = hp2->MEMBER; \ 1424 (hp->MEMBER->linkcount)++; \ 1425 } \ 1426 } \ 1427 } while (0) 1428 1429 /* 1430 * Process the "similar entry" symbol. 1431 * 1432 * The host specified as the value of the "tc" symbol is used as a template 1433 * for the current host entry. Symbol values not explicitly set in the 1434 * current host entry are inferred from the template entry. 1435 */ 1436 PRIVATE void 1437 fill_defaults(hp, src) 1438 struct host *hp; 1439 char **src; 1440 { 1441 unsigned int tlen, hashcode; 1442 struct host *hp2; 1443 char tstring[MAXSTRINGLEN]; 1444 1445 tlen = sizeof(tstring); 1446 (void) get_string(src, tstring, &tlen); 1447 hashcode = hash_HashFunction((u_char *) tstring, tlen); 1448 hp2 = (struct host *) hash_Lookup(nmhashtable, hashcode, nmcmp, tstring); 1449 1450 if (hp2 == NULL) { 1451 report(LOG_ERR, "can't find tc=\"%s\"", tstring); 1452 return; 1453 } 1454 DUP_LINK(bootfile); 1455 DUP_LINK(cookie_server); 1456 DUP_LINK(domain_server); 1457 DUP_LINK(gateway); 1458 /* haddr not copied */ 1459 DUP_LINK(homedir); 1460 DUP_COPY(htype); 1461 1462 DUP_LINK(impress_server); 1463 /* iaddr not copied */ 1464 DUP_LINK(log_server); 1465 DUP_LINK(lpr_server); 1466 DUP_LINK(name_server); 1467 DUP_LINK(rlp_server); 1468 1469 DUP_COPY(subnet_mask); 1470 DUP_COPY(time_offset); 1471 DUP_LINK(time_server); 1472 1473 if (!hp->flags.vm_cookie) { 1474 if ((hp->flags.vm_cookie = hp2->flags.vm_cookie)) { 1475 bcopy(hp2->vm_cookie, hp->vm_cookie, 4); 1476 } 1477 } 1478 if (!hp->flags.name_switch) { 1479 if ((hp->flags.name_switch = hp2->flags.name_switch)) { 1480 hp->flags.send_name = hp2->flags.send_name; 1481 } 1482 } 1483 if (!hp->flags.bootsize) { 1484 if ((hp->flags.bootsize = hp2->flags.bootsize)) { 1485 hp->flags.bootsize_auto = hp2->flags.bootsize_auto; 1486 hp->bootsize = hp2->bootsize; 1487 } 1488 } 1489 DUP_COPY(bootserver); 1490 1491 DUP_LINK(tftpdir); 1492 DUP_LINK(dump_file); 1493 DUP_LINK(domain_name); 1494 1495 DUP_COPY(swap_server); 1496 DUP_LINK(root_path); 1497 DUP_LINK(exten_file); 1498 1499 DUP_COPY(reply_addr); 1500 1501 DUP_LINK(nis_domain); 1502 DUP_LINK(nis_server); 1503 DUP_LINK(ntp_server); 1504 1505 #ifdef YORK_EX_OPTION 1506 DUP_LINK(exec_file); 1507 #endif 1508 1509 DUP_COPY(msg_size); 1510 DUP_COPY(min_wait); 1511 1512 /* XXX - Add new tags here */ 1513 1514 DUP_LINK(generic); 1515 1516 } 1517 #undef DUP_COPY 1518 #undef DUP_LINK 1519 1520 1521 1522 /* 1523 * This function adjusts the caller's pointer to point just past the 1524 * first-encountered colon. If it runs into a null character, it leaves 1525 * the pointer pointing to it. 1526 */ 1527 1528 PRIVATE void 1529 adjust(s) 1530 char **s; 1531 { 1532 register char *t; 1533 1534 t = *s; 1535 while (*t && (*t != ':')) { 1536 t++; 1537 } 1538 if (*t) { 1539 t++; 1540 } 1541 *s = t; 1542 } 1543 1544 1545 1546 1547 /* 1548 * This function adjusts the caller's pointer to point to the first 1549 * non-whitespace character. If it runs into a null character, it leaves 1550 * the pointer pointing to it. 1551 */ 1552 1553 PRIVATE void 1554 eat_whitespace(s) 1555 char **s; 1556 { 1557 register char *t; 1558 1559 t = *s; 1560 while (*t && isspace(*t)) { 1561 t++; 1562 } 1563 *s = t; 1564 } 1565 1566 1567 1568 /* 1569 * This function converts the given string to all lowercase. 1570 */ 1571 1572 PRIVATE void 1573 makelower(s) 1574 char *s; 1575 { 1576 while (*s) { 1577 if (isupper(*s)) { 1578 *s = tolower(*s); 1579 } 1580 s++; 1581 } 1582 } 1583 1584 1585 1586 /* 1587 * 1588 * N O T E : 1589 * 1590 * In many of the functions which follow, a parameter such as "src" or 1591 * "symbol" is passed as a pointer to a pointer to something. This is 1592 * done for the purpose of letting the called function update the 1593 * caller's copy of the parameter (i.e. to effect call-by-reference 1594 * parameter passing). The value of the actual parameter is only used 1595 * to locate the real parameter of interest and then update this indirect 1596 * parameter. 1597 * 1598 * I'm sure somebody out there won't like this. . . . 1599 * (Yea, because it usually makes code slower... -gwr) 1600 * 1601 */ 1602 1603 1604 1605 /* 1606 * "src" points to a character pointer which points to an ASCII string of 1607 * whitespace-separated IP addresses. A pointer to an in_addr_list 1608 * structure containing the list of addresses is returned. NULL is 1609 * returned if no addresses were found at all. The pointer pointed to by 1610 * "src" is updated to point to the first non-address (illegal) character. 1611 */ 1612 1613 PRIVATE struct in_addr_list * 1614 get_addresses(src) 1615 char **src; 1616 { 1617 struct in_addr tmpaddrlist[MAXINADDRS]; 1618 struct in_addr *address1, *address2; 1619 struct in_addr_list *result; 1620 unsigned addrcount, totalsize; 1621 1622 address1 = tmpaddrlist; 1623 for (addrcount = 0; addrcount < MAXINADDRS; addrcount++) { 1624 while (isspace(**src) || (**src == ',')) { 1625 (*src)++; 1626 } 1627 if (!**src) { /* Quit if nothing more */ 1628 break; 1629 } 1630 if (prs_inetaddr(src, &(address1->s_addr)) < 0) { 1631 break; 1632 } 1633 address1++; /* Point to next address slot */ 1634 } 1635 if (addrcount < 1) { 1636 result = NULL; 1637 } else { 1638 totalsize = sizeof(struct in_addr_list) 1639 + (addrcount - 1) * sizeof(struct in_addr); 1640 result = (struct in_addr_list *) smalloc(totalsize); 1641 result->linkcount = 1; 1642 result->addrcount = addrcount; 1643 address1 = tmpaddrlist; 1644 address2 = result->addr; 1645 for (; addrcount > 0; addrcount--) { 1646 address2->s_addr = address1->s_addr; 1647 address1++; 1648 address2++; 1649 } 1650 } 1651 return result; 1652 } 1653 1654 1655 1656 /* 1657 * prs_inetaddr(src, result) 1658 * 1659 * "src" is a value-result parameter; the pointer it points to is updated 1660 * to point to the next data position. "result" points to an unsigned long 1661 * in which an address is returned. 1662 * 1663 * This function parses the IP address string in ASCII "dot notation" pointed 1664 * to by (*src) and places the result (in network byte order) in the unsigned 1665 * long pointed to by "result". For malformed addresses, -1 is returned, 1666 * (*src) points to the first illegal character, and the unsigned long pointed 1667 * to by "result" is unchanged. Successful calls return 0. 1668 */ 1669 1670 PRIVATE int 1671 prs_inetaddr(src, result) 1672 char **src; 1673 u_int32 *result; 1674 { 1675 char tmpstr[MAXSTRINGLEN]; 1676 register u_int32 value; 1677 u_int32 parts[4], *pp; 1678 int n; 1679 char *s, *t; 1680 1681 /* Leading alpha char causes IP addr lookup. */ 1682 if (isalpha(**src)) { 1683 /* Lookup IP address. */ 1684 s = *src; 1685 t = tmpstr; 1686 while ((isalnum(*s) || (*s == '.') || 1687 (*s == '-') || (*s == '_') ) && 1688 (t < &tmpstr[MAXSTRINGLEN - 1]) ) 1689 *t++ = *s++; 1690 *t = '\0'; 1691 *src = s; 1692 1693 n = lookup_ipa(tmpstr, result); 1694 if (n < 0) 1695 report(LOG_ERR, "can not get IP addr for %s", tmpstr); 1696 return n; 1697 } 1698 1699 /* 1700 * Parse an address in Internet format: 1701 * a.b.c.d 1702 * a.b.c (with c treated as 16-bits) 1703 * a.b (with b treated as 24 bits) 1704 */ 1705 pp = parts; 1706 loop: 1707 /* If it's not a digit, return error. */ 1708 if (!isdigit(**src)) 1709 return -1; 1710 *pp++ = get_u_long(src); 1711 if (**src == '.') { 1712 if (pp < (parts + 4)) { 1713 (*src)++; 1714 goto loop; 1715 } 1716 return (-1); 1717 } 1718 #if 0 1719 /* This is handled by the caller. */ 1720 if (**src && !(isspace(**src) || (**src == ':'))) { 1721 return (-1); 1722 } 1723 #endif 1724 1725 /* 1726 * Construct the address according to 1727 * the number of parts specified. 1728 */ 1729 n = pp - parts; 1730 switch (n) { 1731 case 1: /* a -- 32 bits */ 1732 value = parts[0]; 1733 break; 1734 case 2: /* a.b -- 8.24 bits */ 1735 value = (parts[0] << 24) | (parts[1] & 0xFFFFFF); 1736 break; 1737 case 3: /* a.b.c -- 8.8.16 bits */ 1738 value = (parts[0] << 24) | ((parts[1] & 0xFF) << 16) | 1739 (parts[2] & 0xFFFF); 1740 break; 1741 case 4: /* a.b.c.d -- 8.8.8.8 bits */ 1742 value = (parts[0] << 24) | ((parts[1] & 0xFF) << 16) | 1743 ((parts[2] & 0xFF) << 8) | (parts[3] & 0xFF); 1744 break; 1745 default: 1746 return (-1); 1747 } 1748 *result = htonl(value); 1749 return (0); 1750 } 1751 1752 1753 1754 /* 1755 * "src" points to a pointer which in turn points to a hexadecimal ASCII 1756 * string. This string is interpreted as a hardware address and returned 1757 * as a pointer to the actual hardware address, represented as an array of 1758 * bytes. 1759 * 1760 * The ASCII string must have the proper number of digits for the specified 1761 * hardware type (e.g. twelve digits for a 48-bit Ethernet address). 1762 * Two-digit sequences (bytes) may be separated with periods (.) and/or 1763 * prefixed with '0x' for readability, but this is not required. 1764 * 1765 * For bad addresses, the pointer which "src" points to is updated to point 1766 * to the start of the first two-digit sequence which was bad, and the 1767 * function returns a NULL pointer. 1768 */ 1769 1770 PRIVATE byte * 1771 prs_haddr(src, htype) 1772 char **src; 1773 u_int htype; 1774 { 1775 static byte haddr[MAXHADDRLEN]; 1776 byte *hap; 1777 char tmpstr[MAXSTRINGLEN]; 1778 u_int tmplen; 1779 unsigned hal; 1780 char *p; 1781 1782 hal = haddrlength(htype); /* Get length of this address type */ 1783 if (hal <= 0) { 1784 report(LOG_ERR, "Invalid addr type for HW addr parse"); 1785 return NULL; 1786 } 1787 tmplen = sizeof(tmpstr); 1788 get_string(src, tmpstr, &tmplen); 1789 p = tmpstr; 1790 1791 /* If it's a valid host name, try to lookup the HW address. */ 1792 if (goodname(p)) { 1793 /* Lookup Hardware Address for hostname. */ 1794 if ((hap = lookup_hwa(p, htype)) != NULL) 1795 return hap; /* success */ 1796 report(LOG_ERR, "Add 0x prefix if hex value starts with A-F"); 1797 /* OK, assume it must be numeric. */ 1798 } 1799 1800 hap = haddr; 1801 while (hap < haddr + hal) { 1802 if ((*p == '.') || (*p == ':')) 1803 p++; 1804 if (interp_byte(&p, hap++) < 0) { 1805 return NULL; 1806 } 1807 } 1808 return haddr; 1809 } 1810 1811 1812 1813 /* 1814 * "src" is a pointer to a character pointer which in turn points to a 1815 * hexadecimal ASCII representation of a byte. This byte is read, the 1816 * character pointer is updated, and the result is deposited into the 1817 * byte pointed to by "retbyte". 1818 * 1819 * The usual '0x' notation is allowed but not required. The number must be 1820 * a two digit hexadecimal number. If the number is invalid, "src" and 1821 * "retbyte" are left untouched and -1 is returned as the function value. 1822 * Successful calls return 0. 1823 */ 1824 1825 PRIVATE int 1826 interp_byte(src, retbyte) 1827 char **src; 1828 byte *retbyte; 1829 { 1830 int v; 1831 1832 if ((*src)[0] == '0' && 1833 ((*src)[1] == 'x' || 1834 (*src)[1] == 'X')) { 1835 (*src) += 2; /* allow 0x for hex, but don't require it */ 1836 } 1837 if (!isxdigit((*src)[0]) || !isxdigit((*src)[1])) { 1838 return -1; 1839 } 1840 if (sscanf(*src, "%2x", &v) != 1) { 1841 return -1; 1842 } 1843 (*src) += 2; 1844 *retbyte = (byte) (v & 0xFF); 1845 return 0; 1846 } 1847 1848 1849 1850 /* 1851 * The parameter "src" points to a character pointer which points to an 1852 * ASCII string representation of an unsigned number. The number is 1853 * returned as an unsigned long and the character pointer is updated to 1854 * point to the first illegal character. 1855 */ 1856 1857 PRIVATE u_int32 1858 get_u_long(src) 1859 char **src; 1860 { 1861 register u_int32 value, base; 1862 char c; 1863 1864 /* 1865 * Collect number up to first illegal character. Values are specified 1866 * as for C: 0x=hex, 0=octal, other=decimal. 1867 */ 1868 value = 0; 1869 base = 10; 1870 if (**src == '0') { 1871 base = 8; 1872 (*src)++; 1873 } 1874 if (**src == 'x' || **src == 'X') { 1875 base = 16; 1876 (*src)++; 1877 } 1878 while ((c = **src)) { 1879 if (isdigit(c)) { 1880 value = (value * base) + (c - '0'); 1881 (*src)++; 1882 continue; 1883 } 1884 if (base == 16 && isxdigit(c)) { 1885 value = (value << 4) + ((c & ~32) + 10 - 'A'); 1886 (*src)++; 1887 continue; 1888 } 1889 break; 1890 } 1891 return value; 1892 } 1893 1894 1895 1896 /* 1897 * Routines for deletion of data associated with the main data structure. 1898 */ 1899 1900 1901 /* 1902 * Frees the entire host data structure given. Does nothing if the passed 1903 * pointer is NULL. 1904 */ 1905 1906 PRIVATE void 1907 free_host(hmp) 1908 hash_datum *hmp; 1909 { 1910 struct host *hostptr = (struct host *) hmp; 1911 if (hostptr == NULL) 1912 return; 1913 assert(hostptr->linkcount > 0); 1914 if (--(hostptr->linkcount)) 1915 return; /* Still has references */ 1916 del_iplist(hostptr->cookie_server); 1917 del_iplist(hostptr->domain_server); 1918 del_iplist(hostptr->gateway); 1919 del_iplist(hostptr->impress_server); 1920 del_iplist(hostptr->log_server); 1921 del_iplist(hostptr->lpr_server); 1922 del_iplist(hostptr->name_server); 1923 del_iplist(hostptr->rlp_server); 1924 del_iplist(hostptr->time_server); 1925 del_iplist(hostptr->nis_server); 1926 del_iplist(hostptr->ntp_server); 1927 1928 /* 1929 * XXX - Add new tags here 1930 * (if the value is an IP list) 1931 */ 1932 1933 del_string(hostptr->hostname); 1934 del_string(hostptr->homedir); 1935 del_string(hostptr->bootfile); 1936 del_string(hostptr->tftpdir); 1937 del_string(hostptr->root_path); 1938 del_string(hostptr->domain_name); 1939 del_string(hostptr->dump_file); 1940 del_string(hostptr->exten_file); 1941 del_string(hostptr->nis_domain); 1942 1943 #ifdef YORK_EX_OPTION 1944 del_string(hostptr->exec_file); 1945 #endif 1946 1947 /* 1948 * XXX - Add new tags here 1949 * (if it is a shared string) 1950 */ 1951 1952 del_bindata(hostptr->generic); 1953 free((char *) hostptr); 1954 } 1955 1956 1957 1958 /* 1959 * Decrements the linkcount on the given IP address data structure. If the 1960 * linkcount goes to zero, the memory associated with the data is freed. 1961 */ 1962 1963 PRIVATE void 1964 del_iplist(iplist) 1965 struct in_addr_list *iplist; 1966 { 1967 if (iplist) { 1968 if (!(--(iplist->linkcount))) { 1969 free((char *) iplist); 1970 } 1971 } 1972 } 1973 1974 1975 1976 /* 1977 * Decrements the linkcount on a string data structure. If the count 1978 * goes to zero, the memory associated with the string is freed. Does 1979 * nothing if the passed pointer is NULL. 1980 */ 1981 1982 PRIVATE void 1983 del_string(stringptr) 1984 struct shared_string *stringptr; 1985 { 1986 if (stringptr) { 1987 if (!(--(stringptr->linkcount))) { 1988 free((char *) stringptr); 1989 } 1990 } 1991 } 1992 1993 1994 1995 /* 1996 * Decrements the linkcount on a shared_bindata data structure. If the 1997 * count goes to zero, the memory associated with the data is freed. Does 1998 * nothing if the passed pointer is NULL. 1999 */ 2000 2001 PRIVATE void 2002 del_bindata(dataptr) 2003 struct shared_bindata *dataptr; 2004 { 2005 if (dataptr) { 2006 if (!(--(dataptr->linkcount))) { 2007 free((char *) dataptr); 2008 } 2009 } 2010 } 2011 2012 2013 2014 2015 /* smalloc() -- safe malloc() 2016 * 2017 * Always returns a valid pointer (if it returns at all). The allocated 2018 * memory is initialized to all zeros. If malloc() returns an error, a 2019 * message is printed using the report() function and the program aborts 2020 * with a status of 1. 2021 */ 2022 2023 PRIVATE char * 2024 smalloc(nbytes) 2025 unsigned nbytes; 2026 { 2027 char *retvalue; 2028 2029 retvalue = malloc(nbytes); 2030 if (!retvalue) { 2031 report(LOG_ERR, "malloc() failure -- exiting"); 2032 exit(1); 2033 } 2034 bzero(retvalue, nbytes); 2035 return retvalue; 2036 } 2037 2038 2039 /* 2040 * Compare function to determine whether two hardware addresses are 2041 * equivalent. Returns TRUE if "host1" and "host2" are equivalent, FALSE 2042 * otherwise. 2043 * 2044 * This function is used when retrieving elements from the hardware address 2045 * hash table. 2046 */ 2047 2048 boolean 2049 hwlookcmp(d1, d2) 2050 hash_datum *d1, *d2; 2051 { 2052 struct host *host1 = (struct host *) d1; 2053 struct host *host2 = (struct host *) d2; 2054 2055 if (host1->htype != host2->htype) { 2056 return FALSE; 2057 } 2058 if (bcmp(host1->haddr, host2->haddr, haddrlength(host1->htype))) { 2059 return FALSE; 2060 } 2061 return TRUE; 2062 } 2063 2064 2065 /* 2066 * Compare function for doing IP address hash table lookup. 2067 */ 2068 2069 boolean 2070 iplookcmp(d1, d2) 2071 hash_datum *d1, *d2; 2072 { 2073 struct host *host1 = (struct host *) d1; 2074 struct host *host2 = (struct host *) d2; 2075 2076 return (host1->iaddr.s_addr == host2->iaddr.s_addr); 2077 } 2078 2079 /* 2080 * Local Variables: 2081 * tab-width: 4 2082 * c-indent-level: 4 2083 * c-argdecl-indent: 4 2084 * c-continued-statement-offset: 4 2085 * c-continued-brace-offset: -4 2086 * c-label-offset: -4 2087 * c-brace-offset: 0 2088 * End: 2089 */ 2090