1 /************************************************************************ 2 Copyright 1988, 1991 by Carnegie Mellon University 3 4 All Rights Reserved 5 6 Permission to use, copy, modify, and distribute this software and its 7 documentation for any purpose and without fee is hereby granted, provided 8 that the above copyright notice appear in all copies and that both that 9 copyright notice and this permission notice appear in supporting 10 documentation, and that the name of Carnegie Mellon University not be used 11 in advertising or publicity pertaining to distribution of the software 12 without specific, written prior permission. 13 14 CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS 15 SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. 16 IN NO EVENT SHALL CMU BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL 17 DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR 18 PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS 19 ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS 20 SOFTWARE. 21 22 $FreeBSD: src/libexec/bootpd/readfile.c,v 1.6.2.2 2001/10/14 21:25:02 iedowse 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 preceded by a backslash cause 493 * line-continuation onto the next line. The entry is terminated by a 494 * newline character which is not preceded 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 break; 701 case E_BAD_VALUE: 702 msg = "bad value"; 703 break; 704 default: 705 msg = "unknown 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 unsigned integer value for MEMBER */ 772 #define PARSE_UINT(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 symbolmap *symbolptr; 800 u_int32 value; 801 int32 timeoff; 802 int i, numsymbols; 803 unsigned len; 804 int optype; /* Indicates boolean, addition, or deletion */ 805 806 eat_whitespace(symbol); 807 808 /* Make sure this is set before returning. */ 809 current_tagname[0] = (*symbol)[0]; 810 current_tagname[1] = (*symbol)[1]; 811 current_tagname[2] = 0; 812 813 if ((*symbol)[0] == '\0') { 814 return E_END_OF_ENTRY; 815 } 816 if ((*symbol)[0] == ':') { 817 return SUCCESS; 818 } 819 if ((*symbol)[0] == 'T') { /* generic symbol */ 820 (*symbol)++; 821 value = get_u_long(symbol); 822 snprintf(current_tagname, sizeof(current_tagname), 823 "T%d", (int)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", (int*)&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_UINT(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_UINT(min_wait); 1132 break; 1133 1134 /* XXX - Add new tags here */ 1135 1136 default: 1137 return E_UNKNOWN_SYMBOL; 1138 1139 } /* switch symbolcode */ 1140 1141 return SUCCESS; 1142 } 1143 #undef PARSE_IA1 1144 #undef PARSE_IAL 1145 #undef PARSE_STR 1146 1147 1148 1149 1150 /* 1151 * Read a string from the buffer indirectly pointed to through "src" and 1152 * move it into the buffer pointed to by "dest". A pointer to the maximum 1153 * allowable length of the string (including null-terminator) is passed as 1154 * "length". The actual length of the string which was read is returned in 1155 * the unsigned integer pointed to by "length". This value is the same as 1156 * that which would be returned by applying the strlen() function on the 1157 * destination string (i.e the terminating null is not counted as a 1158 * character). Trailing whitespace is removed from the string. For 1159 * convenience, the function returns the new value of "dest". 1160 * 1161 * The string is read until the maximum number of characters, an unquoted 1162 * colon (:), or a null character is read. The return string in "dest" is 1163 * null-terminated. 1164 */ 1165 1166 PRIVATE char * 1167 get_string(src, dest, length) 1168 char **src, *dest; 1169 unsigned *length; 1170 { 1171 int n, len, quoteflag; 1172 1173 quoteflag = FALSE; 1174 n = 0; 1175 len = *length - 1; 1176 while ((n < len) && (**src)) { 1177 if (!quoteflag && (**src == ':')) { 1178 break; 1179 } 1180 if (**src == '"') { 1181 (*src)++; 1182 quoteflag = !quoteflag; 1183 continue; 1184 } 1185 if (**src == '\\') { 1186 (*src)++; 1187 if (!**src) { 1188 break; 1189 } 1190 } 1191 *dest++ = *(*src)++; 1192 n++; 1193 } 1194 1195 /* 1196 * Remove that troublesome trailing whitespace. . . 1197 */ 1198 while ((n > 0) && isspace(dest[-1])) { 1199 dest--; 1200 n--; 1201 } 1202 1203 *dest = '\0'; 1204 *length = n; 1205 return dest; 1206 } 1207 1208 1209 1210 /* 1211 * Read the string indirectly pointed to by "src", update the caller's 1212 * pointer, and return a pointer to a malloc'ed shared_string structure 1213 * containing the string. 1214 * 1215 * The string is read using the same rules as get_string() above. 1216 */ 1217 1218 PRIVATE struct shared_string * 1219 get_shared_string(src) 1220 char **src; 1221 { 1222 char retstring[MAXSTRINGLEN]; 1223 struct shared_string *s; 1224 unsigned length; 1225 1226 length = sizeof(retstring); 1227 (void) get_string(src, retstring, &length); 1228 1229 s = (struct shared_string *) smalloc(sizeof(struct shared_string) 1230 + length); 1231 s->linkcount = 1; 1232 strcpy(s->string, retstring); 1233 1234 return s; 1235 } 1236 1237 1238 1239 /* 1240 * Load RFC1048 generic information directly into a memory buffer. 1241 * 1242 * "src" indirectly points to the ASCII representation of the generic data. 1243 * "dest" points to a string structure which is updated to point to a new 1244 * string with the new data appended to the old string. The old string is 1245 * freed. 1246 * 1247 * The given tag value is inserted with the new data. 1248 * 1249 * The data may be represented as either a stream of hexadecimal numbers 1250 * representing bytes (any or all bytes may optionally start with '0x' and 1251 * be separated with periods ".") or as a quoted string of ASCII 1252 * characters (the quotes are required). 1253 */ 1254 1255 PRIVATE int 1256 process_generic(src, dest, tagvalue) 1257 char **src; 1258 struct shared_bindata **dest; 1259 u_int tagvalue; 1260 { 1261 byte tmpbuf[MAXBUFLEN]; 1262 byte *str; 1263 struct shared_bindata *bdata; 1264 u_int newlength, oldlength; 1265 1266 str = tmpbuf; 1267 *str++ = (tagvalue & 0xFF); /* Store tag value */ 1268 str++; /* Skip over length field */ 1269 if ((*src)[0] == '"') { /* ASCII data */ 1270 newlength = sizeof(tmpbuf) - 2; /* Set maximum allowed length */ 1271 (void) get_string(src, (char *) str, &newlength); 1272 newlength++; /* null terminator */ 1273 } else { /* Numeric data */ 1274 newlength = 0; 1275 while (newlength < sizeof(tmpbuf) - 2) { 1276 if (interp_byte(src, str++) < 0) 1277 break; 1278 newlength++; 1279 if (**src == '.') { 1280 (*src)++; 1281 } 1282 } 1283 } 1284 if ((*src)[0] != ':') 1285 return -1; 1286 1287 tmpbuf[1] = (newlength & 0xFF); 1288 oldlength = ((*dest)->length); 1289 bdata = (struct shared_bindata *) smalloc(sizeof(struct shared_bindata) 1290 + oldlength + newlength + 1); 1291 if (oldlength > 0) { 1292 bcopy((*dest)->data, bdata->data, oldlength); 1293 } 1294 bcopy(tmpbuf, bdata->data + oldlength, newlength + 2); 1295 bdata->length = oldlength + newlength + 2; 1296 bdata->linkcount = 1; 1297 if (*dest) { 1298 del_bindata(*dest); 1299 } 1300 *dest = bdata; 1301 return 0; 1302 } 1303 1304 1305 1306 /* 1307 * Verify that the given string makes sense as a hostname (according to 1308 * Appendix 1, page 29 of RFC882). 1309 * 1310 * Return TRUE for good names, FALSE otherwise. 1311 */ 1312 1313 PRIVATE boolean 1314 goodname(hostname) 1315 register char *hostname; 1316 { 1317 do { 1318 if (!isalpha(*hostname++)) { /* First character must be a letter */ 1319 return FALSE; 1320 } 1321 while (isalnum(*hostname) || 1322 (*hostname == '-') || 1323 (*hostname == '_') ) 1324 { 1325 hostname++; /* Alphanumeric or a hyphen */ 1326 } 1327 if (!isalnum(hostname[-1])) { /* Last must be alphanumeric */ 1328 return FALSE; 1329 } 1330 if (*hostname == '\0') {/* Done? */ 1331 return TRUE; 1332 } 1333 } while (*hostname++ == '.'); /* Dot, loop for next label */ 1334 1335 return FALSE; /* If it's not a dot, lose */ 1336 } 1337 1338 1339 1340 /* 1341 * Null compare function -- always returns FALSE so an element is always 1342 * inserted into a hash table (i.e. there is never a collision with an 1343 * existing element). 1344 */ 1345 1346 PRIVATE boolean 1347 nullcmp(d1, d2) 1348 hash_datum *d1, *d2; 1349 { 1350 return FALSE; 1351 } 1352 1353 1354 /* 1355 * Function for comparing a string with the hostname field of a host 1356 * structure. 1357 */ 1358 1359 boolean 1360 nmcmp(d1, d2) 1361 hash_datum *d1, *d2; 1362 { 1363 char *name = (char *) d1; /* XXX - OK? */ 1364 struct host *hp = (struct host *) d2; 1365 1366 return !strcmp(name, hp->hostname->string); 1367 } 1368 1369 1370 /* 1371 * Compare function to determine whether two hardware addresses are 1372 * equivalent. Returns TRUE if "host1" and "host2" are equivalent, FALSE 1373 * otherwise. 1374 * 1375 * If the hardware addresses of "host1" and "host2" are identical, but 1376 * they are on different IP subnets, this function returns FALSE. 1377 * 1378 * This function is used when inserting elements into the hardware address 1379 * hash table. 1380 */ 1381 1382 PRIVATE boolean 1383 hwinscmp(d1, d2) 1384 hash_datum *d1, *d2; 1385 { 1386 struct host *host1 = (struct host *) d1; 1387 struct host *host2 = (struct host *) d2; 1388 1389 if (host1->htype != host2->htype) { 1390 return FALSE; 1391 } 1392 if (bcmp(host1->haddr, host2->haddr, haddrlength(host1->htype))) { 1393 return FALSE; 1394 } 1395 /* XXX - Is the subnet_mask field set yet? */ 1396 if ((host1->subnet_mask.s_addr) == (host2->subnet_mask.s_addr)) { 1397 if (((host1->iaddr.s_addr) & (host1->subnet_mask.s_addr)) != 1398 ((host2->iaddr.s_addr) & (host2->subnet_mask.s_addr))) 1399 { 1400 return FALSE; 1401 } 1402 } 1403 return TRUE; 1404 } 1405 1406 1407 /* 1408 * Macros for use in the function below: 1409 */ 1410 1411 #define DUP_COPY(MEMBER) do \ 1412 { \ 1413 if (!hp->flags.MEMBER) { \ 1414 if ((hp->flags.MEMBER = hp2->flags.MEMBER) != 0) { \ 1415 hp->MEMBER = hp2->MEMBER; \ 1416 } \ 1417 } \ 1418 } while (0) 1419 1420 #define DUP_LINK(MEMBER) do \ 1421 { \ 1422 if (!hp->flags.MEMBER) { \ 1423 if ((hp->flags.MEMBER = hp2->flags.MEMBER) != 0) { \ 1424 assert(hp2->MEMBER); \ 1425 hp->MEMBER = hp2->MEMBER; \ 1426 (hp->MEMBER->linkcount)++; \ 1427 } \ 1428 } \ 1429 } while (0) 1430 1431 /* 1432 * Process the "similar entry" symbol. 1433 * 1434 * The host specified as the value of the "tc" symbol is used as a template 1435 * for the current host entry. Symbol values not explicitly set in the 1436 * current host entry are inferred from the template entry. 1437 */ 1438 PRIVATE void 1439 fill_defaults(hp, src) 1440 struct host *hp; 1441 char **src; 1442 { 1443 unsigned int tlen, hashcode; 1444 struct host *hp2; 1445 char tstring[MAXSTRINGLEN]; 1446 1447 tlen = sizeof(tstring); 1448 (void) get_string(src, tstring, &tlen); 1449 hashcode = hash_HashFunction((u_char *) tstring, tlen); 1450 hp2 = (struct host *) hash_Lookup(nmhashtable, hashcode, nmcmp, tstring); 1451 1452 if (hp2 == NULL) { 1453 report(LOG_ERR, "can't find tc=\"%s\"", tstring); 1454 return; 1455 } 1456 DUP_LINK(bootfile); 1457 DUP_LINK(cookie_server); 1458 DUP_LINK(domain_server); 1459 DUP_LINK(gateway); 1460 /* haddr not copied */ 1461 DUP_LINK(homedir); 1462 DUP_COPY(htype); 1463 1464 DUP_LINK(impress_server); 1465 /* iaddr not copied */ 1466 DUP_LINK(log_server); 1467 DUP_LINK(lpr_server); 1468 DUP_LINK(name_server); 1469 DUP_LINK(rlp_server); 1470 1471 DUP_COPY(subnet_mask); 1472 DUP_COPY(time_offset); 1473 DUP_LINK(time_server); 1474 1475 if (!hp->flags.vm_cookie) { 1476 if ((hp->flags.vm_cookie = hp2->flags.vm_cookie)) { 1477 bcopy(hp2->vm_cookie, hp->vm_cookie, 4); 1478 } 1479 } 1480 if (!hp->flags.name_switch) { 1481 if ((hp->flags.name_switch = hp2->flags.name_switch)) { 1482 hp->flags.send_name = hp2->flags.send_name; 1483 } 1484 } 1485 if (!hp->flags.bootsize) { 1486 if ((hp->flags.bootsize = hp2->flags.bootsize)) { 1487 hp->flags.bootsize_auto = hp2->flags.bootsize_auto; 1488 hp->bootsize = hp2->bootsize; 1489 } 1490 } 1491 DUP_COPY(bootserver); 1492 1493 DUP_LINK(tftpdir); 1494 DUP_LINK(dump_file); 1495 DUP_LINK(domain_name); 1496 1497 DUP_COPY(swap_server); 1498 DUP_LINK(root_path); 1499 DUP_LINK(exten_file); 1500 1501 DUP_COPY(reply_addr); 1502 1503 DUP_LINK(nis_domain); 1504 DUP_LINK(nis_server); 1505 DUP_LINK(ntp_server); 1506 1507 #ifdef YORK_EX_OPTION 1508 DUP_LINK(exec_file); 1509 #endif 1510 1511 DUP_COPY(msg_size); 1512 DUP_COPY(min_wait); 1513 1514 /* XXX - Add new tags here */ 1515 1516 DUP_LINK(generic); 1517 1518 } 1519 #undef DUP_COPY 1520 #undef DUP_LINK 1521 1522 1523 1524 /* 1525 * This function adjusts the caller's pointer to point just past the 1526 * first-encountered colon. If it runs into a null character, it leaves 1527 * the pointer pointing to it. 1528 */ 1529 1530 PRIVATE void 1531 adjust(s) 1532 char **s; 1533 { 1534 register char *t; 1535 1536 t = *s; 1537 while (*t && (*t != ':')) { 1538 t++; 1539 } 1540 if (*t) { 1541 t++; 1542 } 1543 *s = t; 1544 } 1545 1546 1547 1548 1549 /* 1550 * This function adjusts the caller's pointer to point to the first 1551 * non-whitespace character. If it runs into a null character, it leaves 1552 * the pointer pointing to it. 1553 */ 1554 1555 PRIVATE void 1556 eat_whitespace(s) 1557 char **s; 1558 { 1559 register char *t; 1560 1561 t = *s; 1562 while (*t && isspace(*t)) { 1563 t++; 1564 } 1565 *s = t; 1566 } 1567 1568 1569 1570 /* 1571 * This function converts the given string to all lowercase. 1572 */ 1573 1574 PRIVATE void 1575 makelower(s) 1576 char *s; 1577 { 1578 while (*s) { 1579 if (isupper(*s)) { 1580 *s = tolower(*s); 1581 } 1582 s++; 1583 } 1584 } 1585 1586 1587 1588 /* 1589 * 1590 * N O T E : 1591 * 1592 * In many of the functions which follow, a parameter such as "src" or 1593 * "symbol" is passed as a pointer to a pointer to something. This is 1594 * done for the purpose of letting the called function update the 1595 * caller's copy of the parameter (i.e. to effect call-by-reference 1596 * parameter passing). The value of the actual parameter is only used 1597 * to locate the real parameter of interest and then update this indirect 1598 * parameter. 1599 * 1600 * I'm sure somebody out there won't like this. . . . 1601 * (Yea, because it usually makes code slower... -gwr) 1602 * 1603 */ 1604 1605 1606 1607 /* 1608 * "src" points to a character pointer which points to an ASCII string of 1609 * whitespace-separated IP addresses. A pointer to an in_addr_list 1610 * structure containing the list of addresses is returned. NULL is 1611 * returned if no addresses were found at all. The pointer pointed to by 1612 * "src" is updated to point to the first non-address (illegal) character. 1613 */ 1614 1615 PRIVATE struct in_addr_list * 1616 get_addresses(src) 1617 char **src; 1618 { 1619 struct in_addr tmpaddrlist[MAXINADDRS]; 1620 struct in_addr *address1, *address2; 1621 struct in_addr_list *result; 1622 unsigned addrcount, totalsize; 1623 1624 address1 = tmpaddrlist; 1625 for (addrcount = 0; addrcount < MAXINADDRS; addrcount++) { 1626 while (isspace(**src) || (**src == ',')) { 1627 (*src)++; 1628 } 1629 if (!**src) { /* Quit if nothing more */ 1630 break; 1631 } 1632 if (prs_inetaddr(src, &(address1->s_addr)) < 0) { 1633 break; 1634 } 1635 address1++; /* Point to next address slot */ 1636 } 1637 if (addrcount < 1) { 1638 result = NULL; 1639 } else { 1640 totalsize = sizeof(struct in_addr_list) 1641 + (addrcount - 1) * sizeof(struct in_addr); 1642 result = (struct in_addr_list *) smalloc(totalsize); 1643 result->linkcount = 1; 1644 result->addrcount = addrcount; 1645 address1 = tmpaddrlist; 1646 address2 = result->addr; 1647 for (; addrcount > 0; addrcount--) { 1648 address2->s_addr = address1->s_addr; 1649 address1++; 1650 address2++; 1651 } 1652 } 1653 return result; 1654 } 1655 1656 1657 1658 /* 1659 * prs_inetaddr(src, result) 1660 * 1661 * "src" is a value-result parameter; the pointer it points to is updated 1662 * to point to the next data position. "result" points to an unsigned long 1663 * in which an address is returned. 1664 * 1665 * This function parses the IP address string in ASCII "dot notation" pointed 1666 * to by (*src) and places the result (in network byte order) in the unsigned 1667 * long pointed to by "result". For malformed addresses, -1 is returned, 1668 * (*src) points to the first illegal character, and the unsigned long pointed 1669 * to by "result" is unchanged. Successful calls return 0. 1670 */ 1671 1672 PRIVATE int 1673 prs_inetaddr(src, result) 1674 char **src; 1675 u_int32 *result; 1676 { 1677 char tmpstr[MAXSTRINGLEN]; 1678 register u_int32 value; 1679 u_int32 parts[4], *pp; 1680 int n; 1681 char *s, *t; 1682 1683 /* Leading alpha char causes IP addr lookup. */ 1684 if (isalpha(**src)) { 1685 /* Lookup IP address. */ 1686 s = *src; 1687 t = tmpstr; 1688 while ((isalnum(*s) || (*s == '.') || 1689 (*s == '-') || (*s == '_') ) && 1690 (t < &tmpstr[MAXSTRINGLEN - 1]) ) 1691 *t++ = *s++; 1692 *t = '\0'; 1693 *src = s; 1694 1695 n = lookup_ipa(tmpstr, result); 1696 if (n < 0) 1697 report(LOG_ERR, "can not get IP addr for %s", tmpstr); 1698 return n; 1699 } 1700 1701 /* 1702 * Parse an address in Internet format: 1703 * a.b.c.d 1704 * a.b.c (with c treated as 16-bits) 1705 * a.b (with b treated as 24 bits) 1706 */ 1707 pp = parts; 1708 loop: 1709 /* If it's not a digit, return error. */ 1710 if (!isdigit(**src)) 1711 return -1; 1712 *pp++ = get_u_long(src); 1713 if (**src == '.') { 1714 if (pp < (parts + 4)) { 1715 (*src)++; 1716 goto loop; 1717 } 1718 return (-1); 1719 } 1720 #if 0 1721 /* This is handled by the caller. */ 1722 if (**src && !(isspace(**src) || (**src == ':'))) { 1723 return (-1); 1724 } 1725 #endif 1726 1727 /* 1728 * Construct the address according to 1729 * the number of parts specified. 1730 */ 1731 n = pp - parts; 1732 switch (n) { 1733 case 1: /* a -- 32 bits */ 1734 value = parts[0]; 1735 break; 1736 case 2: /* a.b -- 8.24 bits */ 1737 value = (parts[0] << 24) | (parts[1] & 0xFFFFFF); 1738 break; 1739 case 3: /* a.b.c -- 8.8.16 bits */ 1740 value = (parts[0] << 24) | ((parts[1] & 0xFF) << 16) | 1741 (parts[2] & 0xFFFF); 1742 break; 1743 case 4: /* a.b.c.d -- 8.8.8.8 bits */ 1744 value = (parts[0] << 24) | ((parts[1] & 0xFF) << 16) | 1745 ((parts[2] & 0xFF) << 8) | (parts[3] & 0xFF); 1746 break; 1747 default: 1748 return (-1); 1749 } 1750 *result = htonl(value); 1751 return (0); 1752 } 1753 1754 1755 1756 /* 1757 * "src" points to a pointer which in turn points to a hexadecimal ASCII 1758 * string. This string is interpreted as a hardware address and returned 1759 * as a pointer to the actual hardware address, represented as an array of 1760 * bytes. 1761 * 1762 * The ASCII string must have the proper number of digits for the specified 1763 * hardware type (e.g. twelve digits for a 48-bit Ethernet address). 1764 * Two-digit sequences (bytes) may be separated with periods (.) and/or 1765 * prefixed with '0x' for readability, but this is not required. 1766 * 1767 * For bad addresses, the pointer which "src" points to is updated to point 1768 * to the start of the first two-digit sequence which was bad, and the 1769 * function returns a NULL pointer. 1770 */ 1771 1772 PRIVATE byte * 1773 prs_haddr(src, htype) 1774 char **src; 1775 u_int htype; 1776 { 1777 static byte haddr[MAXHADDRLEN]; 1778 byte *hap; 1779 char tmpstr[MAXSTRINGLEN]; 1780 u_int tmplen; 1781 unsigned hal; 1782 char *p; 1783 1784 hal = haddrlength(htype); /* Get length of this address type */ 1785 if (hal <= 0) { 1786 report(LOG_ERR, "Invalid addr type for HW addr parse"); 1787 return NULL; 1788 } 1789 tmplen = sizeof(tmpstr); 1790 get_string(src, tmpstr, &tmplen); 1791 p = tmpstr; 1792 1793 /* If it's a valid host name, try to lookup the HW address. */ 1794 if (goodname(p)) { 1795 /* Lookup Hardware Address for hostname. */ 1796 if ((hap = lookup_hwa(p, htype)) != NULL) 1797 return hap; /* success */ 1798 report(LOG_ERR, "Add 0x prefix if hex value starts with A-F"); 1799 /* OK, assume it must be numeric. */ 1800 } 1801 1802 hap = haddr; 1803 while (hap < haddr + hal) { 1804 if ((*p == '.') || (*p == ':')) 1805 p++; 1806 if (interp_byte(&p, hap++) < 0) { 1807 return NULL; 1808 } 1809 } 1810 return haddr; 1811 } 1812 1813 1814 1815 /* 1816 * "src" is a pointer to a character pointer which in turn points to a 1817 * hexadecimal ASCII representation of a byte. This byte is read, the 1818 * character pointer is updated, and the result is deposited into the 1819 * byte pointed to by "retbyte". 1820 * 1821 * The usual '0x' notation is allowed but not required. The number must be 1822 * a two digit hexadecimal number. If the number is invalid, "src" and 1823 * "retbyte" are left untouched and -1 is returned as the function value. 1824 * Successful calls return 0. 1825 */ 1826 1827 PRIVATE int 1828 interp_byte(src, retbyte) 1829 char **src; 1830 byte *retbyte; 1831 { 1832 int v; 1833 1834 if ((*src)[0] == '0' && 1835 ((*src)[1] == 'x' || 1836 (*src)[1] == 'X')) { 1837 (*src) += 2; /* allow 0x for hex, but don't require it */ 1838 } 1839 if (!isxdigit((*src)[0]) || !isxdigit((*src)[1])) { 1840 return -1; 1841 } 1842 if (sscanf(*src, "%2x", &v) != 1) { 1843 return -1; 1844 } 1845 (*src) += 2; 1846 *retbyte = (byte) (v & 0xFF); 1847 return 0; 1848 } 1849 1850 1851 1852 /* 1853 * The parameter "src" points to a character pointer which points to an 1854 * ASCII string representation of an unsigned number. The number is 1855 * returned as an unsigned long and the character pointer is updated to 1856 * point to the first illegal character. 1857 */ 1858 1859 PRIVATE u_int32 1860 get_u_long(src) 1861 char **src; 1862 { 1863 register u_int32 value, base; 1864 char c; 1865 1866 /* 1867 * Collect number up to first illegal character. Values are specified 1868 * as for C: 0x=hex, 0=octal, other=decimal. 1869 */ 1870 value = 0; 1871 base = 10; 1872 if (**src == '0') { 1873 base = 8; 1874 (*src)++; 1875 } 1876 if (**src == 'x' || **src == 'X') { 1877 base = 16; 1878 (*src)++; 1879 } 1880 while ((c = **src)) { 1881 if (isdigit(c)) { 1882 value = (value * base) + (c - '0'); 1883 (*src)++; 1884 continue; 1885 } 1886 if (base == 16 && isxdigit(c)) { 1887 value = (value << 4) + ((c & ~32) + 10 - 'A'); 1888 (*src)++; 1889 continue; 1890 } 1891 break; 1892 } 1893 return value; 1894 } 1895 1896 1897 1898 /* 1899 * Routines for deletion of data associated with the main data structure. 1900 */ 1901 1902 1903 /* 1904 * Frees the entire host data structure given. Does nothing if the passed 1905 * pointer is NULL. 1906 */ 1907 1908 PRIVATE void 1909 free_host(hmp) 1910 hash_datum *hmp; 1911 { 1912 struct host *hostptr = (struct host *) hmp; 1913 if (hostptr == NULL) 1914 return; 1915 assert(hostptr->linkcount > 0); 1916 if (--(hostptr->linkcount)) 1917 return; /* Still has references */ 1918 del_iplist(hostptr->cookie_server); 1919 del_iplist(hostptr->domain_server); 1920 del_iplist(hostptr->gateway); 1921 del_iplist(hostptr->impress_server); 1922 del_iplist(hostptr->log_server); 1923 del_iplist(hostptr->lpr_server); 1924 del_iplist(hostptr->name_server); 1925 del_iplist(hostptr->rlp_server); 1926 del_iplist(hostptr->time_server); 1927 del_iplist(hostptr->nis_server); 1928 del_iplist(hostptr->ntp_server); 1929 1930 /* 1931 * XXX - Add new tags here 1932 * (if the value is an IP list) 1933 */ 1934 1935 del_string(hostptr->hostname); 1936 del_string(hostptr->homedir); 1937 del_string(hostptr->bootfile); 1938 del_string(hostptr->tftpdir); 1939 del_string(hostptr->root_path); 1940 del_string(hostptr->domain_name); 1941 del_string(hostptr->dump_file); 1942 del_string(hostptr->exten_file); 1943 del_string(hostptr->nis_domain); 1944 1945 #ifdef YORK_EX_OPTION 1946 del_string(hostptr->exec_file); 1947 #endif 1948 1949 /* 1950 * XXX - Add new tags here 1951 * (if it is a shared string) 1952 */ 1953 1954 del_bindata(hostptr->generic); 1955 free((char *) hostptr); 1956 } 1957 1958 1959 1960 /* 1961 * Decrements the linkcount on the given IP address data structure. If the 1962 * linkcount goes to zero, the memory associated with the data is freed. 1963 */ 1964 1965 PRIVATE void 1966 del_iplist(iplist) 1967 struct in_addr_list *iplist; 1968 { 1969 if (iplist) { 1970 if (!(--(iplist->linkcount))) { 1971 free((char *) iplist); 1972 } 1973 } 1974 } 1975 1976 1977 1978 /* 1979 * Decrements the linkcount on a string data structure. If the count 1980 * goes to zero, the memory associated with the string is freed. Does 1981 * nothing if the passed pointer is NULL. 1982 */ 1983 1984 PRIVATE void 1985 del_string(stringptr) 1986 struct shared_string *stringptr; 1987 { 1988 if (stringptr) { 1989 if (!(--(stringptr->linkcount))) { 1990 free((char *) stringptr); 1991 } 1992 } 1993 } 1994 1995 1996 1997 /* 1998 * Decrements the linkcount on a shared_bindata data structure. If the 1999 * count goes to zero, the memory associated with the data is freed. Does 2000 * nothing if the passed pointer is NULL. 2001 */ 2002 2003 PRIVATE void 2004 del_bindata(dataptr) 2005 struct shared_bindata *dataptr; 2006 { 2007 if (dataptr) { 2008 if (!(--(dataptr->linkcount))) { 2009 free((char *) dataptr); 2010 } 2011 } 2012 } 2013 2014 2015 2016 2017 /* smalloc() -- safe malloc() 2018 * 2019 * Always returns a valid pointer (if it returns at all). The allocated 2020 * memory is initialized to all zeros. If malloc() returns an error, a 2021 * message is printed using the report() function and the program aborts 2022 * with a status of 1. 2023 */ 2024 2025 PRIVATE char * 2026 smalloc(nbytes) 2027 unsigned nbytes; 2028 { 2029 char *retvalue; 2030 2031 retvalue = malloc(nbytes); 2032 if (!retvalue) { 2033 report(LOG_ERR, "malloc() failure -- exiting"); 2034 exit(1); 2035 } 2036 bzero(retvalue, nbytes); 2037 return retvalue; 2038 } 2039 2040 2041 /* 2042 * Compare function to determine whether two hardware addresses are 2043 * equivalent. Returns TRUE if "host1" and "host2" are equivalent, FALSE 2044 * otherwise. 2045 * 2046 * This function is used when retrieving elements from the hardware address 2047 * hash table. 2048 */ 2049 2050 boolean 2051 hwlookcmp(d1, d2) 2052 hash_datum *d1, *d2; 2053 { 2054 struct host *host1 = (struct host *) d1; 2055 struct host *host2 = (struct host *) d2; 2056 2057 if (host1->htype != host2->htype) { 2058 return FALSE; 2059 } 2060 if (bcmp(host1->haddr, host2->haddr, haddrlength(host1->htype))) { 2061 return FALSE; 2062 } 2063 return TRUE; 2064 } 2065 2066 2067 /* 2068 * Compare function for doing IP address hash table lookup. 2069 */ 2070 2071 boolean 2072 iplookcmp(d1, d2) 2073 hash_datum *d1, *d2; 2074 { 2075 struct host *host1 = (struct host *) d1; 2076 struct host *host2 = (struct host *) d2; 2077 2078 return (host1->iaddr.s_addr == host2->iaddr.s_addr); 2079 } 2080 2081 /* 2082 * Local Variables: 2083 * tab-width: 4 2084 * c-indent-level: 4 2085 * c-argdecl-indent: 4 2086 * c-continued-statement-offset: 4 2087 * c-continued-brace-offset: -4 2088 * c-label-offset: -4 2089 * c-brace-offset: 0 2090 * End: 2091 */ 2092