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