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