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