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