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