readfile.c revision 1.17
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.17 2009/04/15 00:23:29 lukem 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 default: 607 *buffer++ = c; /* Store other characters */ 608 length++; 609 if (length >= *bufsiz - 1) { 610 goto done; 611 } 612 } 613 goto mainloop; /* Keep going */ 614 615 done: 616 *buffer = '\0'; /* Terminate string */ 617 *bufsiz = length; /* Tell the caller its length */ 618} 619 620 621 622/* 623 * Parse out all the various tags and parameters in the host entry pointed 624 * to by "src". Stuff all the data into the appropriate fields of the 625 * host structure pointed to by "host". If there is any problem with the 626 * entry, an error message is reported via report(), no further processing 627 * is done, and -1 is returned. Successful calls return 0. 628 * 629 * (Some errors probably shouldn't be so completely fatal. . . .) 630 */ 631 632PRIVATE int 633process_entry(struct host *host, char *src) 634{ 635 int retval; 636 const char *msg; 637 638 if (!host || *src == '\0') { 639 return -1; 640 } 641 host->hostname = get_shared_string(&src); 642#if 0 643 /* Be more liberal for the benefit of dummy tag names. */ 644 if (!goodname(host->hostname->string)) { 645 report(LOG_ERR, "bad hostname: \"%s\"", host->hostname->string); 646 del_string(host->hostname); 647 return -1; 648 } 649#endif 650 current_hostname = host->hostname->string; 651 adjust(&src); 652 while (TRUE) { 653 retval = eval_symbol(&src, host); 654 if (retval == SUCCESS) { 655 adjust(&src); 656 continue; 657 } 658 if (retval == E_END_OF_ENTRY) { 659 /* The default subnet mask is set in readtab() */ 660 return 0; 661 } 662 /* Some kind of error. */ 663 switch (retval) { 664 case E_SYNTAX_ERROR: 665 msg = "bad syntax"; 666 break; 667 case E_UNKNOWN_SYMBOL: 668 msg = "unknown symbol"; 669 break; 670 case E_BAD_IPADDR: 671 msg = "bad INET address"; 672 break; 673 case E_BAD_HWADDR: 674 msg = "bad hardware address"; 675 break; 676 case E_BAD_LONGWORD: 677 msg = "bad longword value"; 678 break; 679 case E_BAD_HWATYPE: 680 msg = "bad HW address type"; 681 break; 682 case E_BAD_PATHNAME: 683 msg = "bad pathname (need leading '/')"; 684 case E_BAD_VALUE: 685 msg = "bad value"; 686 default: 687 msg = "unknown error"; 688 break; 689 } /* switch */ 690 report(LOG_ERR, "in entry named \"%s\", symbol \"%s\": %s", 691 current_hostname, current_tagname, msg); 692 return -1; 693 } 694} 695 696 697/* 698 * Macros for use in the function below: 699 */ 700 701/* Parse one INET address stored directly in MEMBER. */ 702#define PARSE_IA1(MEMBER) do \ 703{ \ 704 if (optype == OP_BOOLEAN) \ 705 return E_SYNTAX_ERROR; \ 706 hp->flags.MEMBER = FALSE; \ 707 if (optype == OP_ADDITION) { \ 708 if (prs_inetaddr(symbol, &value) < 0) \ 709 return E_BAD_IPADDR; \ 710 hp->MEMBER.s_addr = value; \ 711 hp->flags.MEMBER = TRUE; \ 712 } \ 713} while (0) 714 715/* Parse a list of INET addresses pointed to by MEMBER */ 716#define PARSE_IAL(MEMBER) do \ 717{ \ 718 if (optype == OP_BOOLEAN) \ 719 return E_SYNTAX_ERROR; \ 720 if (hp->flags.MEMBER) { \ 721 hp->flags.MEMBER = FALSE; \ 722 assert(hp->MEMBER); \ 723 del_iplist(hp->MEMBER); \ 724 hp->MEMBER = NULL; \ 725 } \ 726 if (optype == OP_ADDITION) { \ 727 hp->MEMBER = get_addresses(symbol); \ 728 if (hp->MEMBER == NULL) \ 729 return E_SYNTAX_ERROR; \ 730 hp->flags.MEMBER = TRUE; \ 731 } \ 732} while (0) 733 734/* Parse a shared string pointed to by MEMBER */ 735#define PARSE_STR(MEMBER) do \ 736{ \ 737 if (optype == OP_BOOLEAN) \ 738 return E_SYNTAX_ERROR; \ 739 if (hp->flags.MEMBER) { \ 740 hp->flags.MEMBER = FALSE; \ 741 assert(hp->MEMBER); \ 742 del_string(hp->MEMBER); \ 743 hp->MEMBER = NULL; \ 744 } \ 745 if (optype == OP_ADDITION) { \ 746 hp->MEMBER = get_shared_string(symbol); \ 747 if (hp->MEMBER == NULL) \ 748 return E_SYNTAX_ERROR; \ 749 hp->flags.MEMBER = TRUE; \ 750 } \ 751} while (0) 752 753/* Parse an integer value for MEMBER */ 754#define PARSE_INT(MEMBER) do \ 755{ \ 756 if (optype == OP_BOOLEAN) \ 757 return E_SYNTAX_ERROR; \ 758 hp->flags.MEMBER = FALSE; \ 759 if (optype == OP_ADDITION) { \ 760 value = get_u_long(symbol); \ 761 hp->MEMBER = value; \ 762 hp->flags.MEMBER = TRUE; \ 763 } \ 764} while (0) 765 766/* 767 * Evaluate the two-character tag symbol pointed to by "symbol" and place 768 * the data in the structure pointed to by "hp". The pointer pointed to 769 * by "symbol" is updated to point past the source string (but may not 770 * point to the next tag entry). 771 * 772 * Obviously, this need a few more comments. . . . 773 */ 774PRIVATE int 775eval_symbol(char **symbol, struct host *hp) 776{ 777 char tmpstr[MAXSTRINGLEN]; 778 byte *tmphaddr; 779 struct symbolmap *symbolptr; 780 u_int32 value; 781 int32 ltimeoff; 782 int i, numsymbols; 783 unsigned len; 784 int optype; /* Indicates boolean, addition, or deletion */ 785 786 eat_whitespace(symbol); 787 788 /* Make sure this is set before returning. */ 789 current_tagname[0] = (*symbol)[0]; 790 current_tagname[1] = (*symbol)[1]; 791 current_tagname[2] = 0; 792 793 if ((*symbol)[0] == '\0') { 794 return E_END_OF_ENTRY; 795 } 796 if ((*symbol)[0] == ':') { 797 return SUCCESS; 798 } 799 if ((*symbol)[0] == 'T') { /* generic symbol */ 800 (*symbol)++; 801 value = get_u_long(symbol); 802 snprintf(current_tagname, sizeof(current_tagname), 803 "T%d", value); 804 eat_whitespace(symbol); 805 if ((*symbol)[0] != '=') { 806 return E_SYNTAX_ERROR; 807 } 808 (*symbol)++; 809 if (!(hp->generic)) { 810 hp->generic = (struct shared_bindata *) 811 smalloc(sizeof(struct shared_bindata)); 812 } 813 if (process_generic(symbol, &(hp->generic), (byte) (value & 0xFF))) 814 return E_SYNTAX_ERROR; 815 hp->flags.generic = TRUE; 816 return SUCCESS; 817 } 818 /* 819 * Determine the type of operation to be done on this symbol 820 */ 821 switch ((*symbol)[2]) { 822 case '=': 823 optype = OP_ADDITION; 824 break; 825 case '@': 826 optype = OP_DELETION; 827 break; 828 case ':': 829 case '\0': 830 optype = OP_BOOLEAN; 831 break; 832 default: 833 return E_SYNTAX_ERROR; 834 } 835 836 symbolptr = symbol_list; 837 numsymbols = sizeof(symbol_list) / sizeof(struct symbolmap); 838 for (i = 0; i < numsymbols; i++) { 839 if (((symbolptr->symbol)[0] == (*symbol)[0]) && 840 ((symbolptr->symbol)[1] == (*symbol)[1])) { 841 break; 842 } 843 symbolptr++; 844 } 845 if (i >= numsymbols) { 846 return E_UNKNOWN_SYMBOL; 847 } 848 /* 849 * Skip past the = or @ character (to point to the data) if this 850 * isn't a boolean operation. For boolean operations, just skip 851 * over the two-character tag symbol (and nothing else. . . .). 852 */ 853 (*symbol) += (optype == OP_BOOLEAN) ? 2 : 3; 854 855 eat_whitespace(symbol); 856 857 /* The cases below are in order by symbolcode value. */ 858 switch (symbolptr->symbolcode) { 859 860 case SYM_BOOTFILE: 861 PARSE_STR(bootfile); 862 break; 863 864 case SYM_COOKIE_SERVER: 865 PARSE_IAL(cookie_server); 866 break; 867 868 case SYM_DOMAIN_SERVER: 869 PARSE_IAL(domain_server); 870 break; 871 872 case SYM_GATEWAY: 873 PARSE_IAL(gateway); 874 break; 875 876 case SYM_HWADDR: 877 if (optype == OP_BOOLEAN) 878 return E_SYNTAX_ERROR; 879 hp->flags.haddr = FALSE; 880 if (optype == OP_ADDITION) { 881 /* Default the HW type to Ethernet */ 882 if (hp->flags.htype == 0) { 883 hp->flags.htype = TRUE; 884 hp->htype = HTYPE_ETHERNET; 885 } 886 tmphaddr = prs_haddr(symbol, hp->htype); 887 if (!tmphaddr) 888 return E_BAD_HWADDR; 889 bcopy(tmphaddr, hp->haddr, haddrlength(hp->htype)); 890 hp->flags.haddr = TRUE; 891 } 892 break; 893 894 case SYM_HOMEDIR: 895 PARSE_STR(homedir); 896 break; 897 898 case SYM_HTYPE: 899 if (optype == OP_BOOLEAN) 900 return E_SYNTAX_ERROR; 901 hp->flags.htype = FALSE; 902 if (optype == OP_ADDITION) { 903 value = 0L; /* Assume an illegal value */ 904 eat_whitespace(symbol); 905 if (isdigit((unsigned char)**symbol)) { 906 value = get_u_long(symbol); 907 } else { 908 len = sizeof(tmpstr); 909 (void) get_string(symbol, tmpstr, &len); 910 makelower(tmpstr); 911 numsymbols = sizeof(htnamemap) / 912 sizeof(struct htypename); 913 for (i = 0; i < numsymbols; i++) { 914 if (!strcmp(htnamemap[i].name, tmpstr)) { 915 break; 916 } 917 } 918 if (i < numsymbols) { 919 value = htnamemap[i].htype; 920 } 921 } 922 if (value >= hwinfocnt) { 923 return E_BAD_HWATYPE; 924 } 925 hp->htype = (byte) (value & 0xFF); 926 hp->flags.htype = TRUE; 927 } 928 break; 929 930 case SYM_IMPRESS_SERVER: 931 PARSE_IAL(impress_server); 932 break; 933 934 case SYM_IPADDR: 935 PARSE_IA1(iaddr); 936 break; 937 938 case SYM_LOG_SERVER: 939 PARSE_IAL(log_server); 940 break; 941 942 case SYM_LPR_SERVER: 943 PARSE_IAL(lpr_server); 944 break; 945 946 case SYM_NAME_SERVER: 947 PARSE_IAL(name_server); 948 break; 949 950 case SYM_RLP_SERVER: 951 PARSE_IAL(rlp_server); 952 break; 953 954 case SYM_SUBNET_MASK: 955 PARSE_IA1(subnet_mask); 956 break; 957 958 case SYM_TIME_OFFSET: 959 if (optype == OP_BOOLEAN) 960 return E_SYNTAX_ERROR; 961 hp->flags.time_offset = FALSE; 962 if (optype == OP_ADDITION) { 963 len = sizeof(tmpstr); 964 (void) get_string(symbol, tmpstr, &len); 965 if (!strncmp(tmpstr, "auto", 4)) { 966 hp->time_offset = secondswest; 967 } else { 968 if (sscanf(tmpstr, "%d", <imeoff) != 1) 969 return E_BAD_LONGWORD; 970 hp->time_offset = ltimeoff; 971 } 972 hp->flags.time_offset = TRUE; 973 } 974 break; 975 976 case SYM_TIME_SERVER: 977 PARSE_IAL(time_server); 978 break; 979 980 case SYM_VENDOR_MAGIC: 981 if (optype == OP_BOOLEAN) 982 return E_SYNTAX_ERROR; 983 hp->flags.vm_cookie = FALSE; 984 if (optype == OP_ADDITION) { 985 if (strncmp(*symbol, "auto", 4)) { 986 /* The string is not "auto" */ 987 if (!strncmp(*symbol, "rfc", 3)) { 988 bcopy(vm_rfc1048, hp->vm_cookie, 4); 989 } else if (!strncmp(*symbol, "cmu", 3)) { 990 bcopy(vm_cmu, hp->vm_cookie, 4); 991 } else { 992 if (!isdigit((unsigned char)**symbol)) 993 return E_BAD_IPADDR; 994 if (prs_inetaddr(symbol, &value) < 0) 995 return E_BAD_IPADDR; 996 bcopy(&value, hp->vm_cookie, 4); 997 } 998 hp->flags.vm_cookie = TRUE; 999 } 1000 } 1001 break; 1002 1003 case SYM_SIMILAR_ENTRY: 1004 switch (optype) { 1005 case OP_ADDITION: 1006 fill_defaults(hp, symbol); 1007 break; 1008 default: 1009 return E_SYNTAX_ERROR; 1010 } 1011 break; 1012 1013 case SYM_NAME_SWITCH: 1014 switch (optype) { 1015 case OP_ADDITION: 1016 return E_SYNTAX_ERROR; 1017 case OP_DELETION: 1018 hp->flags.send_name = FALSE; 1019 hp->flags.name_switch = FALSE; 1020 break; 1021 case OP_BOOLEAN: 1022 hp->flags.send_name = TRUE; 1023 hp->flags.name_switch = TRUE; 1024 break; 1025 } 1026 break; 1027 1028 case SYM_BOOTSIZE: 1029 switch (optype) { 1030 case OP_ADDITION: 1031 if (!strncmp(*symbol, "auto", 4)) { 1032 hp->flags.bootsize = TRUE; 1033 hp->flags.bootsize_auto = TRUE; 1034 } else { 1035 hp->bootsize = (unsigned int) get_u_long(symbol); 1036 hp->flags.bootsize = TRUE; 1037 hp->flags.bootsize_auto = FALSE; 1038 } 1039 break; 1040 case OP_DELETION: 1041 hp->flags.bootsize = FALSE; 1042 break; 1043 case OP_BOOLEAN: 1044 hp->flags.bootsize = TRUE; 1045 hp->flags.bootsize_auto = TRUE; 1046 break; 1047 } 1048 break; 1049 1050 case SYM_BOOT_SERVER: 1051 PARSE_IA1(bootserver); 1052 break; 1053 1054 case SYM_TFTPDIR: 1055 PARSE_STR(tftpdir); 1056 if ((hp->tftpdir != NULL) && 1057 (hp->tftpdir->string[0] != '/')) 1058 return E_BAD_PATHNAME; 1059 break; 1060 1061 case SYM_DUMP_FILE: 1062 PARSE_STR(dump_file); 1063 break; 1064 1065 case SYM_DOMAIN_NAME: 1066 PARSE_STR(domain_name); 1067 break; 1068 1069 case SYM_SWAP_SERVER: 1070 PARSE_IA1(swap_server); 1071 break; 1072 1073 case SYM_ROOT_PATH: 1074 PARSE_STR(root_path); 1075 break; 1076 1077 case SYM_EXTEN_FILE: 1078 PARSE_STR(exten_file); 1079 break; 1080 1081 case SYM_REPLY_ADDR: 1082 PARSE_IA1(reply_addr); 1083 break; 1084 1085 case SYM_NIS_DOMAIN: 1086 PARSE_STR(nis_domain); 1087 break; 1088 1089 case SYM_NIS_SERVER: 1090 PARSE_IAL(nis_server); 1091 break; 1092 1093 case SYM_NTP_SERVER: 1094 PARSE_IAL(ntp_server); 1095 break; 1096 1097#ifdef YORK_EX_OPTION 1098 case SYM_EXEC_FILE: 1099 PARSE_STR(exec_file); 1100 break; 1101#endif 1102 1103 case SYM_MSG_SIZE: 1104 PARSE_INT(msg_size); 1105 if (hp->msg_size < BP_MINPKTSZ || 1106 hp->msg_size > MAX_MSG_SIZE) 1107 return E_BAD_VALUE; 1108 break; 1109 1110 case SYM_MIN_WAIT: 1111 PARSE_INT(min_wait); 1112 if (hp->min_wait == 0) 1113 return E_BAD_VALUE; 1114 break; 1115 1116 /* XXX - Add new tags here */ 1117 1118 default: 1119 return E_UNKNOWN_SYMBOL; 1120 1121 } /* switch symbolcode */ 1122 1123 return SUCCESS; 1124} 1125#undef PARSE_IA1 1126#undef PARSE_IAL 1127#undef PARSE_STR 1128 1129 1130 1131 1132/* 1133 * Read a string from the buffer indirectly pointed to through "src" and 1134 * move it into the buffer pointed to by "dest". A pointer to the maximum 1135 * allowable length of the string (including null-terminator) is passed as 1136 * "length". The actual length of the string which was read is returned in 1137 * the unsigned integer pointed to by "length". This value is the same as 1138 * that which would be returned by applying the strlen() function on the 1139 * destination string (i.e the terminating null is not counted as a 1140 * character). Trailing whitespace is removed from the string. For 1141 * convenience, the function returns the new value of "dest". 1142 * 1143 * The string is read until the maximum number of characters, an unquoted 1144 * colon (:), or a null character is read. The return string in "dest" is 1145 * null-terminated. 1146 */ 1147 1148PRIVATE char * 1149get_string(char **src, char *dest, unsigned int *length) 1150{ 1151 int n, len, quoteflag; 1152 1153 quoteflag = FALSE; 1154 n = 0; 1155 len = *length - 1; 1156 while ((n < len) && (**src)) { 1157 if (!quoteflag && (**src == ':')) { 1158 break; 1159 } 1160 if (**src == '"') { 1161 (*src)++; 1162 quoteflag = !quoteflag; 1163 continue; 1164 } 1165 if (**src == '\\') { 1166 (*src)++; 1167 if (!**src) { 1168 break; 1169 } 1170 } 1171 *dest++ = *(*src)++; 1172 n++; 1173 } 1174 1175 /* 1176 * Remove that troublesome trailing whitespace. . . 1177 */ 1178 while ((n > 0) && isspace((unsigned char)dest[-1])) { 1179 dest--; 1180 n--; 1181 } 1182 1183 *dest = '\0'; 1184 *length = n; 1185 return dest; 1186} 1187 1188 1189 1190/* 1191 * Read the string indirectly pointed to by "src", update the caller's 1192 * pointer, and return a pointer to a malloc'ed shared_string structure 1193 * containing the string. 1194 * 1195 * The string is read using the same rules as get_string() above. 1196 */ 1197 1198PRIVATE struct shared_string * 1199get_shared_string(char **src) 1200{ 1201 char retstring[MAXSTRINGLEN]; 1202 struct shared_string *s; 1203 unsigned length; 1204 1205 length = sizeof(retstring); 1206 (void) get_string(src, retstring, &length); 1207 1208 s = (struct shared_string *) smalloc(sizeof(struct shared_string) + 1209 length); 1210 s->linkcount = 1; 1211 strlcpy(s->string, retstring, sizeof(retstring)); 1212 1213 return s; 1214} 1215 1216 1217 1218/* 1219 * Load RFC1048 generic information directly into a memory buffer. 1220 * 1221 * "src" indirectly points to the ASCII representation of the generic data. 1222 * "dest" points to a string structure which is updated to point to a new 1223 * string with the new data appended to the old string. The old string is 1224 * freed. 1225 * 1226 * The given tag value is inserted with the new data. 1227 * 1228 * The data may be represented as either a stream of hexadecimal numbers 1229 * representing bytes (any or all bytes may optionally start with '0x' and 1230 * be separated with periods ".") or as a quoted string of ASCII 1231 * characters (the quotes are required). 1232 */ 1233 1234PRIVATE int 1235process_generic(char **src, struct shared_bindata **dest, u_int tagvalue) 1236{ 1237 byte tmpbuf[MAXBUFLEN]; 1238 byte *str; 1239 struct shared_bindata *bdata; 1240 u_int newlength, oldlength; 1241 1242 str = tmpbuf; 1243 *str++ = (tagvalue & 0xFF); /* Store tag value */ 1244 str++; /* Skip over length field */ 1245 if ((*src)[0] == '"') { /* ASCII data */ 1246 newlength = sizeof(tmpbuf) - 2; /* Set maximum allowed length */ 1247 (void) get_string(src, (char *) str, &newlength); 1248 /* Do NOT include the terminating null. */ 1249 } else { /* Numeric data */ 1250 newlength = 0; 1251 while (newlength < sizeof(tmpbuf) - 2) { 1252 if (interp_byte(src, str++) < 0) 1253 break; 1254 newlength++; 1255 if (**src == '.') { 1256 (*src)++; 1257 } 1258 } 1259 } 1260 if ((*src)[0] != ':') 1261 return -1; 1262 1263 tmpbuf[1] = (newlength & 0xFF); 1264 oldlength = ((*dest)->length); 1265 bdata = (struct shared_bindata *) smalloc(sizeof(struct shared_bindata) 1266 + oldlength + newlength + 1); 1267 if (oldlength > 0) { 1268 bcopy((*dest)->data, bdata->data, oldlength); 1269 } 1270 bcopy(tmpbuf, bdata->data + oldlength, newlength + 2); 1271 bdata->length = oldlength + newlength + 2; 1272 bdata->linkcount = 1; 1273 del_bindata(*dest); 1274 *dest = bdata; 1275 return 0; 1276} 1277 1278 1279 1280/* 1281 * Verify that the given string makes sense as a hostname (according to 1282 * Appendix 1, page 29 of RFC882). 1283 * 1284 * Return TRUE for good names, FALSE otherwise. 1285 */ 1286 1287PRIVATE boolean 1288goodname(char *hostname) 1289{ 1290 do { 1291 if (!isalpha((unsigned char)*hostname++)) { /* First character must be a letter */ 1292 return FALSE; 1293 } 1294 while (isalnum((unsigned char)*hostname) || 1295 (*hostname == '-') || 1296 (*hostname == '_') ) 1297 { 1298 hostname++; /* Alphanumeric or a hyphen */ 1299 } 1300 if (!isalnum((unsigned char)hostname[-1])) { /* Last must be alphanumeric */ 1301 return FALSE; 1302 } 1303 if (*hostname == '\0') {/* Done? */ 1304 return TRUE; 1305 } 1306 } while (*hostname++ == '.'); /* Dot, loop for next label */ 1307 1308 return FALSE; /* If it's not a dot, lose */ 1309} 1310 1311 1312 1313/* 1314 * Null compare function -- always returns FALSE so an element is always 1315 * inserted into a hash table (i.e. there is never a collision with an 1316 * existing element). 1317 */ 1318 1319PRIVATE boolean 1320nullcmp(hash_datum *d1, hash_datum *d2) 1321{ 1322 return FALSE; 1323} 1324 1325 1326/* 1327 * Function for comparing a string with the hostname field of a host 1328 * structure. 1329 */ 1330 1331boolean 1332nmcmp(hash_datum *d1, hash_datum *d2) 1333{ 1334 char *name = (char *) d1; /* XXX - OK? */ 1335 struct host *hp = (struct host *) d2; 1336 1337 return !strcmp(name, hp->hostname->string); 1338} 1339 1340 1341/* 1342 * Compare function to determine whether two hardware addresses are 1343 * equivalent. Returns TRUE if "host1" and "host2" are equivalent, FALSE 1344 * otherwise. 1345 * 1346 * If the hardware addresses of "host1" and "host2" are identical, but 1347 * they are on different IP subnets, this function returns FALSE. 1348 * 1349 * This function is used when inserting elements into the hardware address 1350 * hash table. 1351 */ 1352 1353PRIVATE boolean 1354hwinscmp(hash_datum *d1, hash_datum *d2) 1355{ 1356 struct host *host1 = (struct host *) d1; 1357 struct host *host2 = (struct host *) d2; 1358 1359 if (host1->htype != host2->htype) { 1360 return FALSE; 1361 } 1362 if (bcmp(host1->haddr, host2->haddr, haddrlength(host1->htype))) { 1363 return FALSE; 1364 } 1365 /* XXX - Is the subnet_mask field set yet? */ 1366 if ((host1->subnet_mask.s_addr) == (host2->subnet_mask.s_addr)) { 1367 if (((host1->iaddr.s_addr) & (host1->subnet_mask.s_addr)) != 1368 ((host2->iaddr.s_addr) & (host2->subnet_mask.s_addr))) 1369 { 1370 return FALSE; 1371 } 1372 } 1373 return TRUE; 1374} 1375 1376 1377/* 1378 * Macros for use in the function below: 1379 */ 1380 1381#define DUP_COPY(MEMBER) do \ 1382{ \ 1383 if (!hp->flags.MEMBER) { \ 1384 if ((hp->flags.MEMBER = hp2->flags.MEMBER) != 0) { \ 1385 hp->MEMBER = hp2->MEMBER; \ 1386 } \ 1387 } \ 1388} while (0) 1389 1390#define DUP_LINK(MEMBER) do \ 1391{ \ 1392 if (!hp->flags.MEMBER) { \ 1393 if ((hp->flags.MEMBER = hp2->flags.MEMBER) != 0) { \ 1394 assert(hp2->MEMBER); \ 1395 hp->MEMBER = hp2->MEMBER; \ 1396 (hp->MEMBER->linkcount)++; \ 1397 } \ 1398 } \ 1399} while (0) 1400 1401/* 1402 * Process the "similar entry" symbol. 1403 * 1404 * The host specified as the value of the "tc" symbol is used as a template 1405 * for the current host entry. Symbol values not explicitly set in the 1406 * current host entry are inferred from the template entry. 1407 */ 1408PRIVATE void 1409fill_defaults(struct host *hp, char **src) 1410{ 1411 unsigned int tlen, hashcode; 1412 struct host *hp2; 1413 char tstring[MAXSTRINGLEN]; 1414 1415 tlen = sizeof(tstring); 1416 (void) get_string(src, tstring, &tlen); 1417 hashcode = hash_HashFunction((u_char *) tstring, tlen); 1418 hp2 = (struct host *) hash_Lookup(nmhashtable, hashcode, nmcmp, tstring); 1419 1420 if (hp2 == NULL) { 1421 report(LOG_ERR, "can't find tc=\"%s\"", tstring); 1422 return; 1423 } 1424 DUP_LINK(bootfile); 1425 DUP_LINK(cookie_server); 1426 DUP_LINK(domain_server); 1427 DUP_LINK(gateway); 1428 /* haddr not copied */ 1429 DUP_LINK(homedir); 1430 DUP_COPY(htype); 1431 1432 DUP_LINK(impress_server); 1433 /* iaddr not copied */ 1434 DUP_LINK(log_server); 1435 DUP_LINK(lpr_server); 1436 DUP_LINK(name_server); 1437 DUP_LINK(rlp_server); 1438 1439 DUP_COPY(subnet_mask); 1440 DUP_COPY(time_offset); 1441 DUP_LINK(time_server); 1442 1443 if (!hp->flags.vm_cookie) { 1444 if ((hp->flags.vm_cookie = hp2->flags.vm_cookie)) { 1445 bcopy(hp2->vm_cookie, hp->vm_cookie, 4); 1446 } 1447 } 1448 if (!hp->flags.name_switch) { 1449 if ((hp->flags.name_switch = hp2->flags.name_switch)) { 1450 hp->flags.send_name = hp2->flags.send_name; 1451 } 1452 } 1453 if (!hp->flags.bootsize) { 1454 if ((hp->flags.bootsize = hp2->flags.bootsize)) { 1455 hp->flags.bootsize_auto = hp2->flags.bootsize_auto; 1456 hp->bootsize = hp2->bootsize; 1457 } 1458 } 1459 DUP_COPY(bootserver); 1460 1461 DUP_LINK(tftpdir); 1462 DUP_LINK(dump_file); 1463 DUP_LINK(domain_name); 1464 1465 DUP_COPY(swap_server); 1466 DUP_LINK(root_path); 1467 DUP_LINK(exten_file); 1468 1469 DUP_COPY(reply_addr); 1470 1471 DUP_LINK(nis_domain); 1472 DUP_LINK(nis_server); 1473 DUP_LINK(ntp_server); 1474 1475#ifdef YORK_EX_OPTION 1476 DUP_LINK(exec_file); 1477#endif 1478 1479 DUP_COPY(msg_size); 1480 DUP_COPY(min_wait); 1481 1482 /* XXX - Add new tags here */ 1483 1484 DUP_LINK(generic); 1485 1486} 1487#undef DUP_COPY 1488#undef DUP_LINK 1489 1490 1491 1492/* 1493 * This function adjusts the caller's pointer to point just past the 1494 * first-encountered colon. If it runs into a null character, it leaves 1495 * the pointer pointing to it. 1496 */ 1497 1498PRIVATE void 1499adjust(char **s) 1500{ 1501 char *t; 1502 1503 t = *s; 1504 while (*t && (*t != ':')) { 1505 t++; 1506 } 1507 if (*t) { 1508 t++; 1509 } 1510 *s = t; 1511} 1512 1513 1514 1515 1516/* 1517 * This function adjusts the caller's pointer to point to the first 1518 * non-whitespace character. If it runs into a null character, it leaves 1519 * the pointer pointing to it. 1520 */ 1521 1522PRIVATE void 1523eat_whitespace(char **s) 1524{ 1525 char *t; 1526 1527 t = *s; 1528 while (*t && isspace((unsigned char)*t)) { 1529 t++; 1530 } 1531 *s = t; 1532} 1533 1534 1535 1536/* 1537 * This function converts the given string to all lowercase. 1538 */ 1539 1540PRIVATE void 1541makelower(char *s) 1542{ 1543 while (*s) { 1544 if (isupper((unsigned char)*s)) { 1545 *s = tolower((unsigned char)*s); 1546 } 1547 s++; 1548 } 1549} 1550 1551 1552 1553/* 1554 * 1555 * N O T E : 1556 * 1557 * In many of the functions which follow, a parameter such as "src" or 1558 * "symbol" is passed as a pointer to a pointer to something. This is 1559 * done for the purpose of letting the called function update the 1560 * caller's copy of the parameter (i.e. to effect call-by-reference 1561 * parameter passing). The value of the actual parameter is only used 1562 * to locate the real parameter of interest and then update this indirect 1563 * parameter. 1564 * 1565 * I'm sure somebody out there won't like this. . . . 1566 * (Yea, because it usually makes code slower... -gwr) 1567 * 1568 */ 1569 1570 1571 1572/* 1573 * "src" points to a character pointer which points to an ASCII string of 1574 * whitespace-separated IP addresses. A pointer to an in_addr_list 1575 * structure containing the list of addresses is returned. NULL is 1576 * returned if no addresses were found at all. The pointer pointed to by 1577 * "src" is updated to point to the first non-address (illegal) character. 1578 */ 1579 1580PRIVATE struct in_addr_list * 1581get_addresses(char **src) 1582{ 1583 struct in_addr tmpaddrlist[MAXINADDRS]; 1584 struct in_addr *address1, *address2; 1585 struct in_addr_list *result; 1586 unsigned addrcount, totalsize; 1587 1588 address1 = tmpaddrlist; 1589 for (addrcount = 0; addrcount < MAXINADDRS; addrcount++) { 1590 while (isspace((unsigned char)**src) || (**src == ',')) { 1591 (*src)++; 1592 } 1593 if (!**src) { /* Quit if nothing more */ 1594 break; 1595 } 1596 if (prs_inetaddr(src, &(address1->s_addr)) < 0) { 1597 break; 1598 } 1599 address1++; /* Point to next address slot */ 1600 } 1601 if (addrcount < 1) { 1602 result = NULL; 1603 } else { 1604 totalsize = sizeof(struct in_addr_list) 1605 + (addrcount - 1) * sizeof(struct in_addr); 1606 result = (struct in_addr_list *) smalloc(totalsize); 1607 result->linkcount = 1; 1608 result->addrcount = addrcount; 1609 address1 = tmpaddrlist; 1610 address2 = result->addr; 1611 for (; addrcount > 0; addrcount--) { 1612 address2->s_addr = address1->s_addr; 1613 address1++; 1614 address2++; 1615 } 1616 } 1617 return result; 1618} 1619 1620 1621 1622/* 1623 * prs_inetaddr(src, result) 1624 * 1625 * "src" is a value-result parameter; the pointer it points to is updated 1626 * to point to the next data position. "result" points to an unsigned long 1627 * in which an address is returned. 1628 * 1629 * This function parses the IP address string in ASCII "dot notation" pointed 1630 * to by (*src) and places the result (in network byte order) in the unsigned 1631 * long pointed to by "result". For malformed addresses, -1 is returned, 1632 * (*src) points to the first illegal character, and the unsigned long pointed 1633 * to by "result" is unchanged. Successful calls return 0. 1634 */ 1635 1636PRIVATE int 1637prs_inetaddr(char **src, u_int32 *result) 1638{ 1639 char tmpstr[MAXSTRINGLEN]; 1640 u_int32 value; 1641 u_int32 parts[4], *pp; 1642 int n; 1643 char *s, *t; 1644 1645#if 1 /* XXX - experimental */ 1646 /* Leading alpha char causes IP addr lookup. */ 1647 if (isalpha((unsigned char)**src)) { 1648 /* Lookup IP address. */ 1649 s = *src; 1650 t = tmpstr; 1651 while ((isalnum((unsigned char)*s) || (*s == '.') || 1652 (*s == '-') || (*s == '_') ) && 1653 (t < &tmpstr[MAXSTRINGLEN - 1]) ) 1654 *t++ = *s++; 1655 *t = '\0'; 1656 *src = s; 1657 1658 n = lookup_ipa(tmpstr, result); 1659 if (n < 0) 1660 report(LOG_ERR, "can not get IP addr for %s", tmpstr); 1661 return n; 1662 } 1663#endif 1664 1665 /* 1666 * Parse an address in Internet format: 1667 * a.b.c.d 1668 * a.b.c (with c treated as 16-bits) 1669 * a.b (with b treated as 24 bits) 1670 */ 1671 pp = parts; 1672 loop: 1673 /* If it's not a digit, return error. */ 1674 if (!isdigit((unsigned char)**src)) 1675 return -1; 1676 *pp++ = get_u_long(src); 1677 if (**src == '.') { 1678 if (pp < (parts + 4)) { 1679 (*src)++; 1680 goto loop; 1681 } 1682 return (-1); 1683 } 1684#if 0 1685 /* This is handled by the caller. */ 1686 if (**src && !((unsigned char)isspace(**src) || (**src == ':'))) { 1687 return (-1); 1688 } 1689#endif 1690 1691 /* 1692 * Construct the address according to 1693 * the number of parts specified. 1694 */ 1695 n = pp - parts; 1696 switch (n) { 1697 case 1: /* a -- 32 bits */ 1698 value = parts[0]; 1699 break; 1700 case 2: /* a.b -- 8.24 bits */ 1701 value = (parts[0] << 24) | (parts[1] & 0xFFFFFF); 1702 break; 1703 case 3: /* a.b.c -- 8.8.16 bits */ 1704 value = (parts[0] << 24) | ((parts[1] & 0xFF) << 16) | 1705 (parts[2] & 0xFFFF); 1706 break; 1707 case 4: /* a.b.c.d -- 8.8.8.8 bits */ 1708 value = (parts[0] << 24) | ((parts[1] & 0xFF) << 16) | 1709 ((parts[2] & 0xFF) << 8) | (parts[3] & 0xFF); 1710 break; 1711 default: 1712 return (-1); 1713 } 1714 *result = htonl(value); 1715 return (0); 1716} 1717 1718 1719 1720/* 1721 * "src" points to a pointer which in turn points to a hexadecimal ASCII 1722 * string. This string is interpreted as a hardware address and returned 1723 * as a pointer to the actual hardware address, represented as an array of 1724 * bytes. 1725 * 1726 * The ASCII string must have the proper number of digits for the specified 1727 * hardware type (e.g. twelve digits for a 48-bit Ethernet address). 1728 * Two-digit sequences (bytes) may be separated with periods (.) and/or 1729 * prefixed with '0x' for readability, but this is not required. 1730 * 1731 * For bad addresses, the pointer which "src" points to is updated to point 1732 * to the start of the first two-digit sequence which was bad, and the 1733 * function returns a NULL pointer. 1734 */ 1735 1736PRIVATE byte * 1737prs_haddr(char **src, u_int htype) 1738{ 1739 static byte haddr[MAXHADDRLEN]; 1740 byte *hap; 1741 char tmpstr[MAXSTRINGLEN]; 1742 u_int tmplen; 1743 unsigned hal; 1744 char *p; 1745 1746 hal = haddrlength(htype); /* Get length of this address type */ 1747 if (hal <= 0) { 1748 report(LOG_ERR, "Invalid addr type for HW addr parse"); 1749 return NULL; 1750 } 1751 tmplen = sizeof(tmpstr); 1752 get_string(src, tmpstr, &tmplen); 1753 p = tmpstr; 1754 1755#if 1 /* XXX - experimental */ 1756 /* If it's a valid host name, try to lookup the HW address. */ 1757 if (goodname(p)) { 1758 /* Lookup Hardware Address for hostname. */ 1759 if ((hap = lookup_hwa(p, htype)) != NULL) 1760 return hap; /* success */ 1761 report(LOG_ERR, "Add 0x prefix if hex value starts with A-F"); 1762 /* OK, assume it must be numeric. */ 1763 } 1764#endif 1765 1766 hap = haddr; 1767 while (hap < haddr + hal) { 1768 if ((*p == '.') || (*p == ':')) 1769 p++; 1770 if (interp_byte(&p, hap++) < 0) { 1771 return NULL; 1772 } 1773 } 1774 return haddr; 1775} 1776 1777 1778 1779/* 1780 * "src" is a pointer to a character pointer which in turn points to a 1781 * hexadecimal ASCII representation of a byte. This byte is read, the 1782 * character pointer is updated, and the result is deposited into the 1783 * byte pointed to by "retbyte". 1784 * 1785 * The usual '0x' notation is allowed but not required. The number must be 1786 * a two digit hexadecimal number. If the number is invalid, "src" and 1787 * "retbyte" are left untouched and -1 is returned as the function value. 1788 * Successful calls return 0. 1789 */ 1790 1791PRIVATE int 1792interp_byte(char **src, byte *retbyte) 1793{ 1794 int v; 1795 1796 if ((*src)[0] == '0' && 1797 ((*src)[1] == 'x' || 1798 (*src)[1] == 'X')) { 1799 (*src) += 2; /* allow 0x for hex, but don't require it */ 1800 } 1801 if (!isxdigit((unsigned char)(*src)[0]) || !isxdigit((unsigned char)(*src)[1])) { 1802 return -1; 1803 } 1804 if (sscanf(*src, "%2x", &v) != 1) { 1805 return -1; 1806 } 1807 (*src) += 2; 1808 *retbyte = (byte) (v & 0xFF); 1809 return 0; 1810} 1811 1812 1813 1814/* 1815 * The parameter "src" points to a character pointer which points to an 1816 * ASCII string representation of an unsigned number. The number is 1817 * returned as an unsigned long and the character pointer is updated to 1818 * point to the first illegal character. 1819 */ 1820 1821PRIVATE u_int32 1822get_u_long(char **src) 1823{ 1824 u_int32 value, base; 1825 char c; 1826 1827 /* 1828 * Collect number up to first illegal character. Values are specified 1829 * as for C: 0x=hex, 0=octal, other=decimal. 1830 */ 1831 value = 0; 1832 base = 10; 1833 if (**src == '0') { 1834 base = 8; 1835 (*src)++; 1836 } 1837 if (**src == 'x' || **src == 'X') { 1838 base = 16; 1839 (*src)++; 1840 } 1841 while ((c = **src)) { 1842 if (isdigit((unsigned char)c)) { 1843 value = (value * base) + (c - '0'); 1844 (*src)++; 1845 continue; 1846 } 1847 if (base == 16 && isxdigit((unsigned char)c)) { 1848 value = (value << 4) + ((c & ~32) + 10 - 'A'); 1849 (*src)++; 1850 continue; 1851 } 1852 break; 1853 } 1854 return value; 1855} 1856 1857 1858 1859/* 1860 * Routines for deletion of data associated with the main data structure. 1861 */ 1862 1863 1864/* 1865 * Frees the entire host data structure given. Does nothing if the passed 1866 * pointer is NULL. 1867 */ 1868 1869PRIVATE void 1870free_host(hash_datum *hmp) 1871{ 1872 struct host *hostptr = (struct host *) hmp; 1873 if (hostptr == NULL) 1874 return; 1875 assert(hostptr->linkcount > 0); 1876 if (--(hostptr->linkcount)) 1877 return; /* Still has references */ 1878 del_iplist(hostptr->cookie_server); 1879 del_iplist(hostptr->domain_server); 1880 del_iplist(hostptr->gateway); 1881 del_iplist(hostptr->impress_server); 1882 del_iplist(hostptr->log_server); 1883 del_iplist(hostptr->lpr_server); 1884 del_iplist(hostptr->name_server); 1885 del_iplist(hostptr->rlp_server); 1886 del_iplist(hostptr->time_server); 1887 del_iplist(hostptr->nis_server); 1888 del_iplist(hostptr->ntp_server); 1889 1890 /* 1891 * XXX - Add new tags here 1892 * (if the value is an IP list) 1893 */ 1894 1895 del_string(hostptr->hostname); 1896 del_string(hostptr->homedir); 1897 del_string(hostptr->bootfile); 1898 del_string(hostptr->tftpdir); 1899 del_string(hostptr->root_path); 1900 del_string(hostptr->domain_name); 1901 del_string(hostptr->dump_file); 1902 del_string(hostptr->exten_file); 1903 del_string(hostptr->nis_domain); 1904 1905#ifdef YORK_EX_OPTION 1906 del_string(hostptr->exec_file); 1907#endif 1908 1909 /* 1910 * XXX - Add new tags here 1911 * (if it is a shared string) 1912 */ 1913 1914 del_bindata(hostptr->generic); 1915 free((char *) hostptr); 1916} 1917 1918 1919 1920/* 1921 * Decrements the linkcount on the given IP address data structure. If the 1922 * linkcount goes to zero, the memory associated with the data is freed. 1923 */ 1924 1925PRIVATE void 1926del_iplist(struct in_addr_list *iplist) 1927{ 1928 if (iplist) { 1929 if (!(--(iplist->linkcount))) { 1930 free((char *) iplist); 1931 } 1932 } 1933} 1934 1935 1936 1937/* 1938 * Decrements the linkcount on a string data structure. If the count 1939 * goes to zero, the memory associated with the string is freed. Does 1940 * nothing if the passed pointer is NULL. 1941 */ 1942 1943PRIVATE void 1944del_string(struct shared_string *stringptr) 1945{ 1946 if (stringptr) { 1947 if (!(--(stringptr->linkcount))) { 1948 free((char *) stringptr); 1949 } 1950 } 1951} 1952 1953 1954 1955/* 1956 * Decrements the linkcount on a shared_bindata data structure. If the 1957 * count goes to zero, the memory associated with the data is freed. Does 1958 * nothing if the passed pointer is NULL. 1959 */ 1960 1961PRIVATE void 1962del_bindata(struct shared_bindata *dataptr) 1963{ 1964 if (dataptr) { 1965 if (!(--(dataptr->linkcount))) { 1966 free((char *) dataptr); 1967 } 1968 } 1969} 1970 1971 1972 1973 1974/* smalloc() -- safe malloc() 1975 * 1976 * Always returns a valid pointer (if it returns at all). The allocated 1977 * memory is initialized to all zeros. If malloc() returns an error, a 1978 * message is printed using the report() function and the program aborts 1979 * with a status of 1. 1980 */ 1981 1982PRIVATE char * 1983smalloc(unsigned int nbytes) 1984{ 1985 char *retvalue; 1986 1987 retvalue = malloc(nbytes); 1988 if (!retvalue) { 1989 report(LOG_ERR, "malloc() failure -- exiting"); 1990 exit(1); 1991 } 1992 bzero(retvalue, nbytes); 1993 return retvalue; 1994} 1995 1996 1997/* 1998 * Compare function to determine whether two hardware addresses are 1999 * equivalent. Returns TRUE if "host1" and "host2" are equivalent, FALSE 2000 * otherwise. 2001 * 2002 * This function is used when retrieving elements from the hardware address 2003 * hash table. 2004 */ 2005 2006boolean 2007hwlookcmp(hash_datum *d1, hash_datum *d2) 2008{ 2009 struct host *host1 = (struct host *) d1; 2010 struct host *host2 = (struct host *) d2; 2011 2012 if (host1->htype != host2->htype) { 2013 return FALSE; 2014 } 2015 if (bcmp(host1->haddr, host2->haddr, haddrlength(host1->htype))) { 2016 return FALSE; 2017 } 2018 return TRUE; 2019} 2020 2021 2022/* 2023 * Compare function for doing IP address hash table lookup. 2024 */ 2025 2026boolean 2027iplookcmp(hash_datum *d1, hash_datum *d2) 2028{ 2029 struct host *host1 = (struct host *) d1; 2030 struct host *host2 = (struct host *) d2; 2031 2032 return (host1->iaddr.s_addr == host2->iaddr.s_addr); 2033} 2034 2035/* 2036 * Local Variables: 2037 * tab-width: 4 2038 * c-indent-level: 4 2039 * c-argdecl-indent: 4 2040 * c-continued-statement-offset: 4 2041 * c-continued-brace-offset: -4 2042 * c-label-offset: -4 2043 * c-brace-offset: 0 2044 * End: 2045 */ 2046