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