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