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