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