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