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