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