Home | History | Annotate | Line # | Download | only in common
readfile.c revision 1.2
      1 /************************************************************************
      2           Copyright 1988, 1991 by Carnegie Mellon University
      3 
      4                           All Rights Reserved
      5 
      6 Permission to use, copy, modify, and distribute this software and its
      7 documentation for any purpose and without fee is hereby granted, provided
      8 that the above copyright notice appear in all copies and that both that
      9 copyright notice and this permission notice appear in supporting
     10 documentation, and that the name of Carnegie Mellon University not be used
     11 in advertising or publicity pertaining to distribution of the software
     12 without specific, written prior permission.
     13 
     14 CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
     15 SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
     16 IN NO EVENT SHALL CMU BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
     17 DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
     18 PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
     19 ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
     20 SOFTWARE.
     21 ************************************************************************/
     22 
     23 #ifndef lint
     24 static char rcsid[] = "$Id: readfile.c,v 1.2 1994/08/22 22:15:04 gwr Exp $";
     25 #endif
     26 
     27 
     28 /*
     29  * bootpd configuration file reading code.
     30  *
     31  * The routines in this file deal with reading, interpreting, and storing
     32  * the information found in the bootpd configuration file (usually
     33  * /etc/bootptab).
     34  */
     35 
     36 
     37 #include <sys/errno.h>
     38 #include <sys/types.h>
     39 #include <sys/stat.h>
     40 #include <sys/file.h>
     41 #include <sys/time.h>
     42 #include <netinet/in.h>
     43 
     44 #include <stdlib.h>
     45 #include <stdio.h>
     46 #include <string.h>
     47 #include <ctype.h>
     48 #include <assert.h>
     49 #include <syslog.h>
     50 
     51 #ifndef USE_BFUNCS
     52 #include <memory.h>
     53 /* Yes, memcpy is OK here (no overlapped copies). */
     54 #define	bcopy(a,b,c)	memcpy(b,a,c)
     55 #define	bzero(p,l)	memset(p,0,l)
     56 #define	bcmp(a,b,c)	memcmp(a,b,c)
     57 #endif
     58 
     59 #include "bootp.h"
     60 #include "hash.h"
     61 #include "hwaddr.h"
     62 #include "lookup.h"
     63 #include "readfile.h"
     64 #include "report.h"
     65 #include "tzone.h"
     66 #include "bootpd.h"
     67 
     68 #define HASHTABLESIZE		257	/* Hash table size (prime) */
     69 
     70 /* Non-standard hardware address type (see bootp.h) */
     71 #define HTYPE_DIRECT	0
     72 
     73 /* Error codes returned by eval_symbol: */
     74 #define SUCCESS			  0
     75 #define E_END_OF_ENTRY		(-1)
     76 #define E_SYNTAX_ERROR		(-2)
     77 #define E_UNKNOWN_SYMBOL	(-3)
     78 #define E_BAD_IPADDR		(-4)
     79 #define E_BAD_HWADDR		(-5)
     80 #define E_BAD_LONGWORD		(-6)
     81 #define E_BAD_HWATYPE		(-7)
     82 #define E_BAD_PATHNAME		(-8)
     83 #define E_BAD_VALUE 		(-9)
     84 
     85 /* Tag idendities. */
     86 #define SYM_NULL		  0
     87 #define SYM_BOOTFILE		  1
     88 #define SYM_COOKIE_SERVER	  2
     89 #define SYM_DOMAIN_SERVER	  3
     90 #define SYM_GATEWAY		  4
     91 #define SYM_HWADDR		  5
     92 #define SYM_HOMEDIR		  6
     93 #define SYM_HTYPE		  7
     94 #define SYM_IMPRESS_SERVER	  8
     95 #define SYM_IPADDR		  9
     96 #define SYM_LOG_SERVER		 10
     97 #define SYM_LPR_SERVER		 11
     98 #define SYM_NAME_SERVER		 12
     99 #define SYM_RLP_SERVER		 13
    100 #define SYM_SUBNET_MASK		 14
    101 #define SYM_TIME_OFFSET		 15
    102 #define SYM_TIME_SERVER		 16
    103 #define SYM_VENDOR_MAGIC	 17
    104 #define SYM_SIMILAR_ENTRY	 18
    105 #define SYM_NAME_SWITCH		 19
    106 #define SYM_BOOTSIZE		 20
    107 #define SYM_BOOT_SERVER		 22
    108 #define SYM_TFTPDIR		 23
    109 #define SYM_DUMP_FILE		 24
    110 #define SYM_DOMAIN_NAME          25
    111 #define SYM_SWAP_SERVER          26
    112 #define SYM_ROOT_PATH            27
    113 #define SYM_EXTEN_FILE           28
    114 #define SYM_REPLY_ADDR           29
    115 #define SYM_NIS_DOMAIN           30	/* RFC 1533 */
    116 #define SYM_NIS_SERVER           31	/* RFC 1533 */
    117 #define SYM_NTP_SERVER           32	/* RFC 1533 */
    118 #define SYM_EXEC_FILE		 33	/* YORK_EX_OPTION */
    119 #define SYM_MSG_SIZE 		 34
    120 #define SYM_MIN_WAIT		 35
    121 /* XXX - Add new tags here */
    122 
    123 #define OP_ADDITION		  1	/* Operations on tags */
    124 #define OP_DELETION		  2
    125 #define OP_BOOLEAN		  3
    126 
    127 #define MAXINADDRS		 16	/* Max size of an IP address list */
    128 #define MAXBUFLEN		256	/* Max temp buffer space */
    129 #define MAXENTRYLEN	       2048	/* Max size of an entire entry */
    130 
    131 
    133 
    134 /*
    135  * Structure used to map a configuration-file symbol (such as "ds") to a
    136  * unique integer.
    137  */
    138 
    139 struct symbolmap {
    140 	char *symbol;
    141 	int symbolcode;
    142 };
    143 
    144 
    145 struct htypename {
    146 	char *name;
    147 	byte htype;
    148 };
    149 
    150 
    151 PRIVATE int nhosts;				/* Number of hosts (/w hw or IP address) */
    152 PRIVATE int nentries;			/* Total number of entries */
    153 PRIVATE int32 modtime = 0;		/* Last modification time of bootptab */
    154 PRIVATE char *current_hostname;	/* Name of the current entry. */
    155 PRIVATE char current_tagname[8];
    156 
    157 /*
    158  * List of symbolic names used in the bootptab file.  The order and actual
    159  * values of the symbol codes (SYM_. . .) are unimportant, but they must
    160  * all be unique.
    161  */
    162 
    163 PRIVATE struct symbolmap symbol_list[] = {
    164 	{"bf", SYM_BOOTFILE},
    165 	{"bs", SYM_BOOTSIZE},
    166 	{"cs", SYM_COOKIE_SERVER},
    167 	{"df", SYM_DUMP_FILE},
    168 	{"dn", SYM_DOMAIN_NAME},
    169 	{"ds", SYM_DOMAIN_SERVER},
    170 	{"ef", SYM_EXTEN_FILE},
    171 	{"ex", SYM_EXEC_FILE},		/* YORK_EX_OPTION */
    172 	{"gw", SYM_GATEWAY},
    173 	{"ha", SYM_HWADDR},
    174 	{"hd", SYM_HOMEDIR},
    175 	{"hn", SYM_NAME_SWITCH},
    176 	{"ht", SYM_HTYPE},
    177 	{"im", SYM_IMPRESS_SERVER},
    178 	{"ip", SYM_IPADDR},
    179 	{"lg", SYM_LOG_SERVER},
    180 	{"lp", SYM_LPR_SERVER},
    181 	{"ms", SYM_MSG_SIZE},
    182 	{"mw", SYM_MIN_WAIT},
    183 	{"ns", SYM_NAME_SERVER},
    184 	{"nt", SYM_NTP_SERVER},
    185 	{"ra", SYM_REPLY_ADDR},
    186 	{"rl", SYM_RLP_SERVER},
    187 	{"rp", SYM_ROOT_PATH},
    188 	{"sa", SYM_BOOT_SERVER},
    189 	{"sm", SYM_SUBNET_MASK},
    190 	{"sw", SYM_SWAP_SERVER},
    191 	{"tc", SYM_SIMILAR_ENTRY},
    192 	{"td", SYM_TFTPDIR},
    193 	{"to", SYM_TIME_OFFSET},
    194 	{"ts", SYM_TIME_SERVER},
    195 	{"vm", SYM_VENDOR_MAGIC},
    196 	{"yd", SYM_NIS_DOMAIN},
    197 	{"ys", SYM_NIS_SERVER},
    198 	/* XXX - Add new tags here */
    199 };
    200 
    201 
    202 /*
    203  * List of symbolic names for hardware types.  Name translates into
    204  * hardware type code listed with it.  Names must begin with a letter
    205  * and must be all lowercase.  This is searched linearly, so put
    206  * commonly-used entries near the beginning.
    207  */
    208 
    209 PRIVATE struct htypename htnamemap[] = {
    210 	{"ethernet", HTYPE_ETHERNET},
    211 	{"ethernet3", HTYPE_EXP_ETHERNET},
    212 	{"ether", HTYPE_ETHERNET},
    213 	{"ether3", HTYPE_EXP_ETHERNET},
    214 	{"ieee802", HTYPE_IEEE802},
    215 	{"tr", HTYPE_IEEE802},
    216 	{"token-ring", HTYPE_IEEE802},
    217 	{"pronet", HTYPE_PRONET},
    218 	{"chaos", HTYPE_CHAOS},
    219 	{"arcnet", HTYPE_ARCNET},
    220 	{"ax.25", HTYPE_AX25},
    221 	{"direct", HTYPE_DIRECT},
    222 	{"serial", HTYPE_DIRECT},
    223 	{"slip", HTYPE_DIRECT},
    224 	{"ppp", HTYPE_DIRECT}
    225 };
    226 
    227 
    228 
    229 /*
    230  * Externals and forward declarations.
    231  */
    232 
    233 #ifdef	__STDC__
    234 #define P(args) args
    235 #else
    236 #define P(args) ()
    237 #endif
    238 
    239 extern boolean iplookcmp();
    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, 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 shared_string *ss;
    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 		newlength++;			/* null terminator */
   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 == '.')
   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