Home | History | Annotate | Line # | Download | only in common
readfile.c revision 1.14
      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.14 2006/05/23 01:29:31 christos Exp $");
     26 #endif
     27 
     28 
     29 /*
     30  * bootpd configuration file reading code.
     31  *
     32  * The routines in this file deal with reading, interpreting, and storing
     33  * the information found in the bootpd configuration file (usually
     34  * /etc/bootptab).
     35  */
     36 
     37 
     38 #include <sys/types.h>
     39 #include <sys/stat.h>
     40 #include <sys/file.h>
     41 #include <sys/time.h>
     42 #include <netinet/in.h>
     43 
     44 #include <errno.h>
     45 #include <stdlib.h>
     46 #include <stdio.h>
     47 #include <string.h>
     48 #include <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((unsigned char)**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((unsigned char)**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((unsigned char)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 	del_bindata(*dest);
   1289 	*dest = bdata;
   1290 	return 0;
   1291 }
   1292 
   1293 
   1295 
   1296 /*
   1297  * Verify that the given string makes sense as a hostname (according to
   1298  * Appendix 1, page 29 of RFC882).
   1299  *
   1300  * Return TRUE for good names, FALSE otherwise.
   1301  */
   1302 
   1303 PRIVATE boolean
   1304 goodname(char *hostname)
   1305 {
   1306 	do {
   1307 		if (!isalpha((unsigned char)*hostname++)) {	/* First character must be a letter */
   1308 			return FALSE;
   1309 		}
   1310 		while (isalnum((unsigned char)*hostname) ||
   1311 			   (*hostname == '-') ||
   1312 			   (*hostname == '_') )
   1313 		{
   1314 			hostname++;			/* Alphanumeric or a hyphen */
   1315 		}
   1316 		if (!isalnum((unsigned char)hostname[-1])) {	/* Last must be alphanumeric */
   1317 			return FALSE;
   1318 		}
   1319 		if (*hostname == '\0') {/* Done? */
   1320 			return TRUE;
   1321 		}
   1322 	} while (*hostname++ == '.');	/* Dot, loop for next label */
   1323 
   1324 	return FALSE;				/* If it's not a dot, lose */
   1325 }
   1326 
   1327 
   1329 
   1330 /*
   1331  * Null compare function -- always returns FALSE so an element is always
   1332  * inserted into a hash table (i.e. there is never a collision with an
   1333  * existing element).
   1334  */
   1335 
   1336 PRIVATE boolean
   1337 nullcmp(hash_datum *d1, hash_datum *d2)
   1338 {
   1339 	return FALSE;
   1340 }
   1341 
   1342 
   1343 /*
   1344  * Function for comparing a string with the hostname field of a host
   1345  * structure.
   1346  */
   1347 
   1348 boolean
   1349 nmcmp(hash_datum *d1, hash_datum *d2)
   1350 {
   1351 	char *name = (char *) d1;	/* XXX - OK? */
   1352 	struct host *hp = (struct host *) d2;
   1353 
   1354 	return !strcmp(name, hp->hostname->string);
   1355 }
   1356 
   1357 
   1358 /*
   1359  * Compare function to determine whether two hardware addresses are
   1360  * equivalent.  Returns TRUE if "host1" and "host2" are equivalent, FALSE
   1361  * otherwise.
   1362  *
   1363  * If the hardware addresses of "host1" and "host2" are identical, but
   1364  * they are on different IP subnets, this function returns FALSE.
   1365  *
   1366  * This function is used when inserting elements into the hardware address
   1367  * hash table.
   1368  */
   1369 
   1370 PRIVATE boolean
   1371 hwinscmp(hash_datum *d1, hash_datum *d2)
   1372 {
   1373 	struct host *host1 = (struct host *) d1;
   1374 	struct host *host2 = (struct host *) d2;
   1375 
   1376 	if (host1->htype != host2->htype) {
   1377 		return FALSE;
   1378 	}
   1379 	if (bcmp(host1->haddr, host2->haddr, haddrlength(host1->htype))) {
   1380 		return FALSE;
   1381 	}
   1382 	/* XXX - Is the subnet_mask field set yet? */
   1383 	if ((host1->subnet_mask.s_addr) == (host2->subnet_mask.s_addr)) {
   1384 		if (((host1->iaddr.s_addr) & (host1->subnet_mask.s_addr)) !=
   1385 			((host2->iaddr.s_addr) & (host2->subnet_mask.s_addr)))
   1386 		{
   1387 			return FALSE;
   1388 		}
   1389 	}
   1390 	return TRUE;
   1391 }
   1392 
   1393 
   1395 /*
   1396  * Macros for use in the function below:
   1397  */
   1398 
   1399 #define DUP_COPY(MEMBER) do \
   1400 { \
   1401 	if (!hp->flags.MEMBER) { \
   1402 		if ((hp->flags.MEMBER = hp2->flags.MEMBER) != 0) { \
   1403 			hp->MEMBER = hp2->MEMBER; \
   1404 		} \
   1405 	} \
   1406 } while (0)
   1407 
   1408 #define DUP_LINK(MEMBER) do \
   1409 { \
   1410 	if (!hp->flags.MEMBER) { \
   1411 		if ((hp->flags.MEMBER = hp2->flags.MEMBER) != 0) { \
   1412 			assert(hp2->MEMBER); \
   1413 			hp->MEMBER = hp2->MEMBER; \
   1414 			(hp->MEMBER->linkcount)++; \
   1415 		} \
   1416 	} \
   1417 } while (0)
   1418 
   1419 /*
   1420  * Process the "similar entry" symbol.
   1421  *
   1422  * The host specified as the value of the "tc" symbol is used as a template
   1423  * for the current host entry.  Symbol values not explicitly set in the
   1424  * current host entry are inferred from the template entry.
   1425  */
   1426 PRIVATE void
   1427 fill_defaults(struct host *hp, char **src)
   1428 {
   1429 	unsigned int tlen, hashcode;
   1430 	struct host *hp2;
   1431 	char tstring[MAXSTRINGLEN];
   1432 
   1433 	tlen = sizeof(tstring);
   1434 	(void) get_string(src, tstring, &tlen);
   1435 	hashcode = hash_HashFunction((u_char *) tstring, tlen);
   1436 	hp2 = (struct host *) hash_Lookup(nmhashtable, hashcode, nmcmp, tstring);
   1437 
   1438 	if (hp2 == NULL) {
   1439 		report(LOG_ERR, "can't find tc=\"%s\"", tstring);
   1440 		return;
   1441 	}
   1442 	DUP_LINK(bootfile);
   1443 	DUP_LINK(cookie_server);
   1444 	DUP_LINK(domain_server);
   1445 	DUP_LINK(gateway);
   1446 	/* haddr not copied */
   1447 	DUP_LINK(homedir);
   1448 	DUP_COPY(htype);
   1449 
   1450 	DUP_LINK(impress_server);
   1451 	/* iaddr not copied */
   1452 	DUP_LINK(log_server);
   1453 	DUP_LINK(lpr_server);
   1454 	DUP_LINK(name_server);
   1455 	DUP_LINK(rlp_server);
   1456 
   1457 	DUP_COPY(subnet_mask);
   1458 	DUP_COPY(time_offset);
   1459 	DUP_LINK(time_server);
   1460 
   1461 	if (!hp->flags.vm_cookie) {
   1462 		if ((hp->flags.vm_cookie = hp2->flags.vm_cookie)) {
   1463 			bcopy(hp2->vm_cookie, hp->vm_cookie, 4);
   1464 		}
   1465 	}
   1466 	if (!hp->flags.name_switch) {
   1467 		if ((hp->flags.name_switch = hp2->flags.name_switch)) {
   1468 			hp->flags.send_name = hp2->flags.send_name;
   1469 		}
   1470 	}
   1471 	if (!hp->flags.bootsize) {
   1472 		if ((hp->flags.bootsize = hp2->flags.bootsize)) {
   1473 			hp->flags.bootsize_auto = hp2->flags.bootsize_auto;
   1474 			hp->bootsize = hp2->bootsize;
   1475 		}
   1476 	}
   1477 	DUP_COPY(bootserver);
   1478 
   1479 	DUP_LINK(tftpdir);
   1480 	DUP_LINK(dump_file);
   1481 	DUP_LINK(domain_name);
   1482 
   1483 	DUP_COPY(swap_server);
   1484 	DUP_LINK(root_path);
   1485 	DUP_LINK(exten_file);
   1486 
   1487 	DUP_COPY(reply_addr);
   1488 
   1489 	DUP_LINK(nis_domain);
   1490 	DUP_LINK(nis_server);
   1491 	DUP_LINK(ntp_server);
   1492 
   1493 #ifdef	YORK_EX_OPTION
   1494 	DUP_LINK(exec_file);
   1495 #endif
   1496 
   1497 	DUP_COPY(msg_size);
   1498 	DUP_COPY(min_wait);
   1499 
   1500 	/* XXX - Add new tags here */
   1501 
   1502 	DUP_LINK(generic);
   1503 
   1504 }
   1505 #undef	DUP_COPY
   1506 #undef	DUP_LINK
   1507 
   1508 
   1510 
   1511 /*
   1512  * This function adjusts the caller's pointer to point just past the
   1513  * first-encountered colon.  If it runs into a null character, it leaves
   1514  * the pointer pointing to it.
   1515  */
   1516 
   1517 PRIVATE void
   1518 adjust(char **s)
   1519 {
   1520 	char *t;
   1521 
   1522 	t = *s;
   1523 	while (*t && (*t != ':')) {
   1524 		t++;
   1525 	}
   1526 	if (*t) {
   1527 		t++;
   1528 	}
   1529 	*s = t;
   1530 }
   1531 
   1532 
   1533 
   1534 
   1535 /*
   1536  * This function adjusts the caller's pointer to point to the first
   1537  * non-whitespace character.  If it runs into a null character, it leaves
   1538  * the pointer pointing to it.
   1539  */
   1540 
   1541 PRIVATE void
   1542 eat_whitespace(char **s)
   1543 {
   1544 	char *t;
   1545 
   1546 	t = *s;
   1547 	while (*t && isspace((unsigned char)*t)) {
   1548 		t++;
   1549 	}
   1550 	*s = t;
   1551 }
   1552 
   1553 
   1554 
   1555 /*
   1556  * This function converts the given string to all lowercase.
   1557  */
   1558 
   1559 PRIVATE void
   1560 makelower(char *s)
   1561 {
   1562 	while (*s) {
   1563 		if (isupper((unsigned char)*s)) {
   1564 			*s = tolower((unsigned char)*s);
   1565 		}
   1566 		s++;
   1567 	}
   1568 }
   1569 
   1570 
   1572 
   1573 /*
   1574  *
   1575  *	N O T E :
   1576  *
   1577  *	In many of the functions which follow, a parameter such as "src" or
   1578  *	"symbol" is passed as a pointer to a pointer to something.  This is
   1579  *	done for the purpose of letting the called function update the
   1580  *	caller's copy of the parameter (i.e. to effect call-by-reference
   1581  *	parameter passing).  The value of the actual parameter is only used
   1582  *	to locate the real parameter of interest and then update this indirect
   1583  *	parameter.
   1584  *
   1585  *	I'm sure somebody out there won't like this. . . .
   1586  *  (Yea, because it usually makes code slower... -gwr)
   1587  *
   1588  */
   1589 
   1590 
   1592 
   1593 /*
   1594  * "src" points to a character pointer which points to an ASCII string of
   1595  * whitespace-separated IP addresses.  A pointer to an in_addr_list
   1596  * structure containing the list of addresses is returned.  NULL is
   1597  * returned if no addresses were found at all.  The pointer pointed to by
   1598  * "src" is updated to point to the first non-address (illegal) character.
   1599  */
   1600 
   1601 PRIVATE struct in_addr_list *
   1602 get_addresses(char **src)
   1603 {
   1604 	struct in_addr tmpaddrlist[MAXINADDRS];
   1605 	struct in_addr *address1, *address2;
   1606 	struct in_addr_list *result;
   1607 	unsigned addrcount, totalsize;
   1608 
   1609 	address1 = tmpaddrlist;
   1610 	for (addrcount = 0; addrcount < MAXINADDRS; addrcount++) {
   1611 		while (isspace((unsigned char)**src) || (**src == ',')) {
   1612 			(*src)++;
   1613 		}
   1614 		if (!**src) {			/* Quit if nothing more */
   1615 			break;
   1616 		}
   1617 		if (prs_inetaddr(src, &(address1->s_addr)) < 0) {
   1618 			break;
   1619 		}
   1620 		address1++;				/* Point to next address slot */
   1621 	}
   1622 	if (addrcount < 1) {
   1623 		result = NULL;
   1624 	} else {
   1625 		totalsize = sizeof(struct in_addr_list)
   1626 		+			(addrcount - 1) * sizeof(struct in_addr);
   1627 		result = (struct in_addr_list *) smalloc(totalsize);
   1628 		result->linkcount = 1;
   1629 		result->addrcount = addrcount;
   1630 		address1 = tmpaddrlist;
   1631 		address2 = result->addr;
   1632 		for (; addrcount > 0; addrcount--) {
   1633 			address2->s_addr = address1->s_addr;
   1634 			address1++;
   1635 			address2++;
   1636 		}
   1637 	}
   1638 	return result;
   1639 }
   1640 
   1641 
   1643 
   1644 /*
   1645  * prs_inetaddr(src, result)
   1646  *
   1647  * "src" is a value-result parameter; the pointer it points to is updated
   1648  * to point to the next data position.   "result" points to an unsigned long
   1649  * in which an address is returned.
   1650  *
   1651  * This function parses the IP address string in ASCII "dot notation" pointed
   1652  * to by (*src) and places the result (in network byte order) in the unsigned
   1653  * long pointed to by "result".  For malformed addresses, -1 is returned,
   1654  * (*src) points to the first illegal character, and the unsigned long pointed
   1655  * to by "result" is unchanged.  Successful calls return 0.
   1656  */
   1657 
   1658 PRIVATE int
   1659 prs_inetaddr(char **src, u_int32 *result)
   1660 {
   1661 	char tmpstr[MAXSTRINGLEN];
   1662 	u_int32 value;
   1663 	u_int32 parts[4], *pp;
   1664 	int n;
   1665 	char *s, *t;
   1666 
   1667 #if 1	/* XXX - experimental */
   1668 	/* Leading alpha char causes IP addr lookup. */
   1669 	if (isalpha((unsigned char)**src)) {
   1670 		/* Lookup IP address. */
   1671 		s = *src;
   1672 		t = tmpstr;
   1673 		while ((isalnum((unsigned char)*s) || (*s == '.') ||
   1674 				(*s == '-') || (*s == '_') ) &&
   1675 			   (t < &tmpstr[MAXSTRINGLEN - 1]) )
   1676 			*t++ = *s++;
   1677 		*t = '\0';
   1678 		*src = s;
   1679 
   1680 		n = lookup_ipa(tmpstr, result);
   1681 		if (n < 0)
   1682 			report(LOG_ERR, "can not get IP addr for %s", tmpstr);
   1683 		return n;
   1684 	}
   1685 #endif
   1686 
   1687 	/*
   1688 	 * Parse an address in Internet format:
   1689 	 *	a.b.c.d
   1690 	 *	a.b.c	(with c treated as 16-bits)
   1691 	 *	a.b	(with b treated as 24 bits)
   1692 	 */
   1693 	pp = parts;
   1694   loop:
   1695 	/* If it's not a digit, return error. */
   1696 	if (!isdigit((unsigned char)**src))
   1697 		return -1;
   1698 	*pp++ = get_u_long(src);
   1699 	if (**src == '.') {
   1700 		if (pp < (parts + 4)) {
   1701 			(*src)++;
   1702 			goto loop;
   1703 		}
   1704 		return (-1);
   1705 	}
   1706 #if 0
   1707 	/* This is handled by the caller. */
   1708 	if (**src && !((unsigned char)isspace(**src) || (**src == ':'))) {
   1709 		return (-1);
   1710 	}
   1711 #endif
   1712 
   1713 	/*
   1714 	 * Construct the address according to
   1715 	 * the number of parts specified.
   1716 	 */
   1717 	n = pp - parts;
   1718 	switch (n) {
   1719 	case 1:					/* a -- 32 bits */
   1720 		value = parts[0];
   1721 		break;
   1722 	case 2:					/* a.b -- 8.24 bits */
   1723 		value = (parts[0] << 24) | (parts[1] & 0xFFFFFF);
   1724 		break;
   1725 	case 3:					/* a.b.c -- 8.8.16 bits */
   1726 		value = (parts[0] << 24) | ((parts[1] & 0xFF) << 16) |
   1727 			(parts[2] & 0xFFFF);
   1728 		break;
   1729 	case 4:					/* a.b.c.d -- 8.8.8.8 bits */
   1730 		value = (parts[0] << 24) | ((parts[1] & 0xFF) << 16) |
   1731 			((parts[2] & 0xFF) << 8) | (parts[3] & 0xFF);
   1732 		break;
   1733 	default:
   1734 		return (-1);
   1735 	}
   1736 	*result = htonl(value);
   1737 	return (0);
   1738 }
   1739 
   1740 
   1742 
   1743 /*
   1744  * "src" points to a pointer which in turn points to a hexadecimal ASCII
   1745  * string.  This string is interpreted as a hardware address and returned
   1746  * as a pointer to the actual hardware address, represented as an array of
   1747  * bytes.
   1748  *
   1749  * The ASCII string must have the proper number of digits for the specified
   1750  * hardware type (e.g. twelve digits for a 48-bit Ethernet address).
   1751  * Two-digit sequences (bytes) may be separated with periods (.)  and/or
   1752  * prefixed with '0x' for readability, but this is not required.
   1753  *
   1754  * For bad addresses, the pointer which "src" points to is updated to point
   1755  * to the start of the first two-digit sequence which was bad, and the
   1756  * function returns a NULL pointer.
   1757  */
   1758 
   1759 PRIVATE byte *
   1760 prs_haddr(char **src, u_int htype)
   1761 {
   1762 	static byte haddr[MAXHADDRLEN];
   1763 	byte *hap;
   1764 	char tmpstr[MAXSTRINGLEN];
   1765 	u_int tmplen;
   1766 	unsigned hal;
   1767 	char *p;
   1768 
   1769 	hal = haddrlength(htype);	/* Get length of this address type */
   1770 	if (hal <= 0) {
   1771 		report(LOG_ERR, "Invalid addr type for HW addr parse");
   1772 		return NULL;
   1773 	}
   1774 	tmplen = sizeof(tmpstr);
   1775 	get_string(src, tmpstr, &tmplen);
   1776 	p = tmpstr;
   1777 
   1778 #if 1	/* XXX - experimental */
   1779 	/* If it's a valid host name, try to lookup the HW address. */
   1780 	if (goodname(p)) {
   1781 		/* Lookup Hardware Address for hostname. */
   1782 		if ((hap = lookup_hwa(p, htype)) != NULL)
   1783 			return hap; /* success */
   1784 		report(LOG_ERR, "Add 0x prefix if hex value starts with A-F");
   1785 		/* OK, assume it must be numeric. */
   1786 	}
   1787 #endif
   1788 
   1789 	hap = haddr;
   1790 	while (hap < haddr + hal) {
   1791 		if ((*p == '.') || (*p == ':'))
   1792 			p++;
   1793 		if (interp_byte(&p, hap++) < 0) {
   1794 			return NULL;
   1795 		}
   1796 	}
   1797 	return haddr;
   1798 }
   1799 
   1800 
   1802 
   1803 /*
   1804  * "src" is a pointer to a character pointer which in turn points to a
   1805  * hexadecimal ASCII representation of a byte.  This byte is read, the
   1806  * character pointer is updated, and the result is deposited into the
   1807  * byte pointed to by "retbyte".
   1808  *
   1809  * The usual '0x' notation is allowed but not required.  The number must be
   1810  * a two digit hexadecimal number.  If the number is invalid, "src" and
   1811  * "retbyte" are left untouched and -1 is returned as the function value.
   1812  * Successful calls return 0.
   1813  */
   1814 
   1815 PRIVATE int
   1816 interp_byte(char **src, byte *retbyte)
   1817 {
   1818 	int v;
   1819 
   1820 	if ((*src)[0] == '0' &&
   1821 		((*src)[1] == 'x' ||
   1822 		 (*src)[1] == 'X')) {
   1823 		(*src) += 2;			/* allow 0x for hex, but don't require it */
   1824 	}
   1825 	if (!isxdigit((unsigned char)(*src)[0]) || !isxdigit((unsigned char)(*src)[1])) {
   1826 		return -1;
   1827 	}
   1828 	if (sscanf(*src, "%2x", &v) != 1) {
   1829 		return -1;
   1830 	}
   1831 	(*src) += 2;
   1832 	*retbyte = (byte) (v & 0xFF);
   1833 	return 0;
   1834 }
   1835 
   1836 
   1838 
   1839 /*
   1840  * The parameter "src" points to a character pointer which points to an
   1841  * ASCII string representation of an unsigned number.  The number is
   1842  * returned as an unsigned long and the character pointer is updated to
   1843  * point to the first illegal character.
   1844  */
   1845 
   1846 PRIVATE u_int32
   1847 get_u_long(char **src)
   1848 {
   1849 	u_int32 value, base;
   1850 	char c;
   1851 
   1852 	/*
   1853 	 * Collect number up to first illegal character.  Values are specified
   1854 	 * as for C:  0x=hex, 0=octal, other=decimal.
   1855 	 */
   1856 	value = 0;
   1857 	base = 10;
   1858 	if (**src == '0') {
   1859 		base = 8;
   1860 		(*src)++;
   1861 	}
   1862 	if (**src == 'x' || **src == 'X') {
   1863 		base = 16;
   1864 		(*src)++;
   1865 	}
   1866 	while ((c = **src)) {
   1867 		if (isdigit((unsigned char)c)) {
   1868 			value = (value * base) + (c - '0');
   1869 			(*src)++;
   1870 			continue;
   1871 		}
   1872 		if (base == 16 && isxdigit((unsigned char)c)) {
   1873 			value = (value << 4) + ((c & ~32) + 10 - 'A');
   1874 			(*src)++;
   1875 			continue;
   1876 		}
   1877 		break;
   1878 	}
   1879 	return value;
   1880 }
   1881 
   1882 
   1884 
   1885 /*
   1886  * Routines for deletion of data associated with the main data structure.
   1887  */
   1888 
   1889 
   1890 /*
   1891  * Frees the entire host data structure given.  Does nothing if the passed
   1892  * pointer is NULL.
   1893  */
   1894 
   1895 PRIVATE void
   1896 free_host(hash_datum *hmp)
   1897 {
   1898 	struct host *hostptr = (struct host *) hmp;
   1899 	if (hostptr == NULL)
   1900 		return;
   1901 	assert(hostptr->linkcount > 0);
   1902 	if (--(hostptr->linkcount))
   1903 		return;					/* Still has references */
   1904 	del_iplist(hostptr->cookie_server);
   1905 	del_iplist(hostptr->domain_server);
   1906 	del_iplist(hostptr->gateway);
   1907 	del_iplist(hostptr->impress_server);
   1908 	del_iplist(hostptr->log_server);
   1909 	del_iplist(hostptr->lpr_server);
   1910 	del_iplist(hostptr->name_server);
   1911 	del_iplist(hostptr->rlp_server);
   1912 	del_iplist(hostptr->time_server);
   1913 	del_iplist(hostptr->nis_server);
   1914 	del_iplist(hostptr->ntp_server);
   1915 
   1916 	/*
   1917 	 * XXX - Add new tags here
   1918 	 * (if the value is an IP list)
   1919 	 */
   1920 
   1921 	del_string(hostptr->hostname);
   1922 	del_string(hostptr->homedir);
   1923 	del_string(hostptr->bootfile);
   1924 	del_string(hostptr->tftpdir);
   1925 	del_string(hostptr->root_path);
   1926 	del_string(hostptr->domain_name);
   1927 	del_string(hostptr->dump_file);
   1928 	del_string(hostptr->exten_file);
   1929 	del_string(hostptr->nis_domain);
   1930 
   1931 #ifdef	YORK_EX_OPTION
   1932 	del_string(hostptr->exec_file);
   1933 #endif
   1934 
   1935 	/*
   1936 	 * XXX - Add new tags here
   1937 	 * (if it is a shared string)
   1938 	 */
   1939 
   1940 	del_bindata(hostptr->generic);
   1941 	free((char *) hostptr);
   1942 }
   1943 
   1944 
   1946 
   1947 /*
   1948  * Decrements the linkcount on the given IP address data structure.  If the
   1949  * linkcount goes to zero, the memory associated with the data is freed.
   1950  */
   1951 
   1952 PRIVATE void
   1953 del_iplist(struct in_addr_list *iplist)
   1954 {
   1955 	if (iplist) {
   1956 		if (!(--(iplist->linkcount))) {
   1957 			free((char *) iplist);
   1958 		}
   1959 	}
   1960 }
   1961 
   1962 
   1963 
   1964 /*
   1965  * Decrements the linkcount on a string data structure.  If the count
   1966  * goes to zero, the memory associated with the string is freed.  Does
   1967  * nothing if the passed pointer is NULL.
   1968  */
   1969 
   1970 PRIVATE void
   1971 del_string(struct shared_string *stringptr)
   1972 {
   1973 	if (stringptr) {
   1974 		if (!(--(stringptr->linkcount))) {
   1975 			free((char *) stringptr);
   1976 		}
   1977 	}
   1978 }
   1979 
   1980 
   1981 
   1982 /*
   1983  * Decrements the linkcount on a shared_bindata data structure.  If the
   1984  * count goes to zero, the memory associated with the data is freed.  Does
   1985  * nothing if the passed pointer is NULL.
   1986  */
   1987 
   1988 PRIVATE void
   1989 del_bindata(struct shared_bindata *dataptr)
   1990 {
   1991 	if (dataptr) {
   1992 		if (!(--(dataptr->linkcount))) {
   1993 			free((char *) dataptr);
   1994 		}
   1995 	}
   1996 }
   1997 
   1998 
   2000 
   2001 
   2002 /* smalloc()  --  safe malloc()
   2003  *
   2004  * Always returns a valid pointer (if it returns at all).  The allocated
   2005  * memory is initialized to all zeros.  If malloc() returns an error, a
   2006  * message is printed using the report() function and the program aborts
   2007  * with a status of 1.
   2008  */
   2009 
   2010 PRIVATE char *
   2011 smalloc(unsigned int nbytes)
   2012 {
   2013 	char *retvalue;
   2014 
   2015 	retvalue = malloc(nbytes);
   2016 	if (!retvalue) {
   2017 		report(LOG_ERR, "malloc() failure -- exiting");
   2018 		exit(1);
   2019 	}
   2020 	bzero(retvalue, nbytes);
   2021 	return retvalue;
   2022 }
   2023 
   2024 
   2026 /*
   2027  * Compare function to determine whether two hardware addresses are
   2028  * equivalent.  Returns TRUE if "host1" and "host2" are equivalent, FALSE
   2029  * otherwise.
   2030  *
   2031  * This function is used when retrieving elements from the hardware address
   2032  * hash table.
   2033  */
   2034 
   2035 boolean
   2036 hwlookcmp(hash_datum *d1, hash_datum *d2)
   2037 {
   2038 	struct host *host1 = (struct host *) d1;
   2039 	struct host *host2 = (struct host *) d2;
   2040 
   2041 	if (host1->htype != host2->htype) {
   2042 		return FALSE;
   2043 	}
   2044 	if (bcmp(host1->haddr, host2->haddr, haddrlength(host1->htype))) {
   2045 		return FALSE;
   2046 	}
   2047 	return TRUE;
   2048 }
   2049 
   2050 
   2051 /*
   2052  * Compare function for doing IP address hash table lookup.
   2053  */
   2054 
   2055 boolean
   2056 iplookcmp(hash_datum *d1, hash_datum *d2)
   2057 {
   2058 	struct host *host1 = (struct host *) d1;
   2059 	struct host *host2 = (struct host *) d2;
   2060 
   2061 	return (host1->iaddr.s_addr == host2->iaddr.s_addr);
   2062 }
   2063 
   2064 /*
   2065  * Local Variables:
   2066  * tab-width: 4
   2067  * c-indent-level: 4
   2068  * c-argdecl-indent: 4
   2069  * c-continued-statement-offset: 4
   2070  * c-continued-brace-offset: -4
   2071  * c-label-offset: -4
   2072  * c-brace-offset: 0
   2073  * End:
   2074  */
   2075