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