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