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