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