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