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