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