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