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