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