xref: /netbsd-src/usr.sbin/bootp/common/readfile.c (revision fbffadb9f864c0324fb295860ab0faeb187269cc)
15e9d01f2Sgwr /************************************************************************
25e9d01f2Sgwr           Copyright 1988, 1991 by Carnegie Mellon University
35e9d01f2Sgwr 
45e9d01f2Sgwr                           All Rights Reserved
55e9d01f2Sgwr 
65e9d01f2Sgwr Permission to use, copy, modify, and distribute this software and its
75e9d01f2Sgwr documentation for any purpose and without fee is hereby granted, provided
85e9d01f2Sgwr that the above copyright notice appear in all copies and that both that
95e9d01f2Sgwr copyright notice and this permission notice appear in supporting
105e9d01f2Sgwr documentation, and that the name of Carnegie Mellon University not be used
115e9d01f2Sgwr in advertising or publicity pertaining to distribution of the software
125e9d01f2Sgwr without specific, written prior permission.
135e9d01f2Sgwr 
145e9d01f2Sgwr CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
155e9d01f2Sgwr SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
165e9d01f2Sgwr IN NO EVENT SHALL CMU BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
175e9d01f2Sgwr DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
185e9d01f2Sgwr PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
195e9d01f2Sgwr ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
205e9d01f2Sgwr SOFTWARE.
215e9d01f2Sgwr ************************************************************************/
225e9d01f2Sgwr 
239493bb79Slukem #include <sys/cdefs.h>
245e9d01f2Sgwr #ifndef lint
25*fbffadb9Smrg __RCSID("$NetBSD: readfile.c,v 1.21 2019/02/03 03:19:30 mrg Exp $");
265e9d01f2Sgwr #endif
275e9d01f2Sgwr 
285e9d01f2Sgwr 
295e9d01f2Sgwr /*
305e9d01f2Sgwr  * bootpd configuration file reading code.
315e9d01f2Sgwr  *
325e9d01f2Sgwr  * The routines in this file deal with reading, interpreting, and storing
335e9d01f2Sgwr  * the information found in the bootpd configuration file (usually
345e9d01f2Sgwr  * /etc/bootptab).
355e9d01f2Sgwr  */
365e9d01f2Sgwr 
375e9d01f2Sgwr 
385e9d01f2Sgwr #include <sys/types.h>
395e9d01f2Sgwr #include <sys/stat.h>
405e9d01f2Sgwr #include <sys/file.h>
415e9d01f2Sgwr #include <sys/time.h>
425e9d01f2Sgwr #include <netinet/in.h>
435e9d01f2Sgwr 
443ed4fcf6Skleink #include <errno.h>
455e9d01f2Sgwr #include <stdlib.h>
465e9d01f2Sgwr #include <stdio.h>
475e9d01f2Sgwr #include <string.h>
48be45f4d0Stls #include <strings.h>
4953ec1d71Skleink #include <time.h>
505e9d01f2Sgwr #include <ctype.h>
515e9d01f2Sgwr #include <assert.h>
525e9d01f2Sgwr #include <syslog.h>
535e9d01f2Sgwr 
545e9d01f2Sgwr #include "bootp.h"
555e9d01f2Sgwr #include "hash.h"
565e9d01f2Sgwr #include "hwaddr.h"
575e9d01f2Sgwr #include "lookup.h"
585e9d01f2Sgwr #include "readfile.h"
595e9d01f2Sgwr #include "report.h"
605e9d01f2Sgwr #include "tzone.h"
615e9d01f2Sgwr #include "bootpd.h"
625e9d01f2Sgwr 
635e9d01f2Sgwr #define HASHTABLESIZE		257	/* Hash table size (prime) */
645e9d01f2Sgwr 
655e9d01f2Sgwr /* Non-standard hardware address type (see bootp.h) */
665e9d01f2Sgwr #define HTYPE_DIRECT	0
675e9d01f2Sgwr 
685e9d01f2Sgwr /* Error codes returned by eval_symbol: */
695e9d01f2Sgwr #define SUCCESS			  0
705e9d01f2Sgwr #define E_END_OF_ENTRY		(-1)
715e9d01f2Sgwr #define E_SYNTAX_ERROR		(-2)
725e9d01f2Sgwr #define E_UNKNOWN_SYMBOL	(-3)
735e9d01f2Sgwr #define E_BAD_IPADDR		(-4)
745e9d01f2Sgwr #define E_BAD_HWADDR		(-5)
755e9d01f2Sgwr #define E_BAD_LONGWORD		(-6)
765e9d01f2Sgwr #define E_BAD_HWATYPE		(-7)
775e9d01f2Sgwr #define E_BAD_PATHNAME		(-8)
78bcb13babSgwr #define E_BAD_VALUE 		(-9)
795e9d01f2Sgwr 
805e9d01f2Sgwr /* Tag idendities. */
815e9d01f2Sgwr #define SYM_NULL		  0
825e9d01f2Sgwr #define SYM_BOOTFILE		  1
835e9d01f2Sgwr #define SYM_COOKIE_SERVER	  2
845e9d01f2Sgwr #define SYM_DOMAIN_SERVER	  3
855e9d01f2Sgwr #define SYM_GATEWAY		  4
865e9d01f2Sgwr #define SYM_HWADDR		  5
875e9d01f2Sgwr #define SYM_HOMEDIR		  6
885e9d01f2Sgwr #define SYM_HTYPE		  7
895e9d01f2Sgwr #define SYM_IMPRESS_SERVER	  8
905e9d01f2Sgwr #define SYM_IPADDR		  9
915e9d01f2Sgwr #define SYM_LOG_SERVER		 10
925e9d01f2Sgwr #define SYM_LPR_SERVER		 11
935e9d01f2Sgwr #define SYM_NAME_SERVER		 12
945e9d01f2Sgwr #define SYM_RLP_SERVER		 13
955e9d01f2Sgwr #define SYM_SUBNET_MASK		 14
965e9d01f2Sgwr #define SYM_TIME_OFFSET		 15
975e9d01f2Sgwr #define SYM_TIME_SERVER		 16
985e9d01f2Sgwr #define SYM_VENDOR_MAGIC	 17
995e9d01f2Sgwr #define SYM_SIMILAR_ENTRY	 18
1005e9d01f2Sgwr #define SYM_NAME_SWITCH		 19
1015e9d01f2Sgwr #define SYM_BOOTSIZE		 20
1025e9d01f2Sgwr #define SYM_BOOT_SERVER		 22
1035e9d01f2Sgwr #define SYM_TFTPDIR		 23
1045e9d01f2Sgwr #define SYM_DUMP_FILE		 24
1055e9d01f2Sgwr #define SYM_DOMAIN_NAME          25
1065e9d01f2Sgwr #define SYM_SWAP_SERVER          26
1075e9d01f2Sgwr #define SYM_ROOT_PATH            27
1085e9d01f2Sgwr #define SYM_EXTEN_FILE           28
1095e9d01f2Sgwr #define SYM_REPLY_ADDR           29
1105e9d01f2Sgwr #define SYM_NIS_DOMAIN           30	/* RFC 1533 */
1115e9d01f2Sgwr #define SYM_NIS_SERVER           31	/* RFC 1533 */
1125e9d01f2Sgwr #define SYM_NTP_SERVER           32	/* RFC 1533 */
1135e9d01f2Sgwr #define SYM_EXEC_FILE		 33	/* YORK_EX_OPTION */
114bcb13babSgwr #define SYM_MSG_SIZE 		 34
115bcb13babSgwr #define SYM_MIN_WAIT		 35
1165e9d01f2Sgwr /* XXX - Add new tags here */
1175e9d01f2Sgwr 
1185e9d01f2Sgwr #define OP_ADDITION		  1	/* Operations on tags */
1195e9d01f2Sgwr #define OP_DELETION		  2
1205e9d01f2Sgwr #define OP_BOOLEAN		  3
1215e9d01f2Sgwr 
1225e9d01f2Sgwr #define MAXINADDRS		 16	/* Max size of an IP address list */
123bcb13babSgwr #define MAXBUFLEN		256	/* Max temp buffer space */
1245e9d01f2Sgwr #define MAXENTRYLEN	       2048	/* Max size of an entire entry */
1255e9d01f2Sgwr 
1265e9d01f2Sgwr 
1275e9d01f2Sgwr 
1285e9d01f2Sgwr /*
1295e9d01f2Sgwr  * Structure used to map a configuration-file symbol (such as "ds") to a
1305e9d01f2Sgwr  * unique integer.
1315e9d01f2Sgwr  */
1325e9d01f2Sgwr 
1335e9d01f2Sgwr struct symbolmap {
134c8f61d2bSxtraeme 	const char *symbol;
1355e9d01f2Sgwr 	int symbolcode;
1365e9d01f2Sgwr };
1375e9d01f2Sgwr 
1385e9d01f2Sgwr 
1395e9d01f2Sgwr struct htypename {
140c8f61d2bSxtraeme 	const char *name;
1415e9d01f2Sgwr 	byte htype;
1425e9d01f2Sgwr };
1435e9d01f2Sgwr 
1445e9d01f2Sgwr 
1455e9d01f2Sgwr PRIVATE int nhosts;				/* Number of hosts (/w hw or IP address) */
1465e9d01f2Sgwr PRIVATE int nentries;			/* Total number of entries */
1475e9d01f2Sgwr PRIVATE int32 modtime = 0;		/* Last modification time of bootptab */
1485e9d01f2Sgwr PRIVATE char *current_hostname;	/* Name of the current entry. */
1495e9d01f2Sgwr PRIVATE char current_tagname[8];
1505e9d01f2Sgwr 
1515e9d01f2Sgwr /*
1525e9d01f2Sgwr  * List of symbolic names used in the bootptab file.  The order and actual
1535e9d01f2Sgwr  * values of the symbol codes (SYM_. . .) are unimportant, but they must
1545e9d01f2Sgwr  * all be unique.
1555e9d01f2Sgwr  */
1565e9d01f2Sgwr 
1575e9d01f2Sgwr PRIVATE struct symbolmap symbol_list[] = {
1585e9d01f2Sgwr 	{"bf", SYM_BOOTFILE},
1595e9d01f2Sgwr 	{"bs", SYM_BOOTSIZE},
1605e9d01f2Sgwr 	{"cs", SYM_COOKIE_SERVER},
1615e9d01f2Sgwr 	{"df", SYM_DUMP_FILE},
1625e9d01f2Sgwr 	{"dn", SYM_DOMAIN_NAME},
1635e9d01f2Sgwr 	{"ds", SYM_DOMAIN_SERVER},
1645e9d01f2Sgwr 	{"ef", SYM_EXTEN_FILE},
1655e9d01f2Sgwr 	{"ex", SYM_EXEC_FILE},		/* YORK_EX_OPTION */
1665e9d01f2Sgwr 	{"gw", SYM_GATEWAY},
1675e9d01f2Sgwr 	{"ha", SYM_HWADDR},
1685e9d01f2Sgwr 	{"hd", SYM_HOMEDIR},
1695e9d01f2Sgwr 	{"hn", SYM_NAME_SWITCH},
1705e9d01f2Sgwr 	{"ht", SYM_HTYPE},
1715e9d01f2Sgwr 	{"im", SYM_IMPRESS_SERVER},
1725e9d01f2Sgwr 	{"ip", SYM_IPADDR},
1735e9d01f2Sgwr 	{"lg", SYM_LOG_SERVER},
1745e9d01f2Sgwr 	{"lp", SYM_LPR_SERVER},
175bcb13babSgwr 	{"ms", SYM_MSG_SIZE},
176bcb13babSgwr 	{"mw", SYM_MIN_WAIT},
1775e9d01f2Sgwr 	{"ns", SYM_NAME_SERVER},
1785e9d01f2Sgwr 	{"nt", SYM_NTP_SERVER},
1795e9d01f2Sgwr 	{"ra", SYM_REPLY_ADDR},
1805e9d01f2Sgwr 	{"rl", SYM_RLP_SERVER},
1815e9d01f2Sgwr 	{"rp", SYM_ROOT_PATH},
1825e9d01f2Sgwr 	{"sa", SYM_BOOT_SERVER},
1835e9d01f2Sgwr 	{"sm", SYM_SUBNET_MASK},
1845e9d01f2Sgwr 	{"sw", SYM_SWAP_SERVER},
1855e9d01f2Sgwr 	{"tc", SYM_SIMILAR_ENTRY},
1865e9d01f2Sgwr 	{"td", SYM_TFTPDIR},
1875e9d01f2Sgwr 	{"to", SYM_TIME_OFFSET},
1885e9d01f2Sgwr 	{"ts", SYM_TIME_SERVER},
1895e9d01f2Sgwr 	{"vm", SYM_VENDOR_MAGIC},
1905e9d01f2Sgwr 	{"yd", SYM_NIS_DOMAIN},
1915e9d01f2Sgwr 	{"ys", SYM_NIS_SERVER},
1925e9d01f2Sgwr 	/* XXX - Add new tags here */
1935e9d01f2Sgwr };
1945e9d01f2Sgwr 
1955e9d01f2Sgwr 
1965e9d01f2Sgwr /*
1975e9d01f2Sgwr  * List of symbolic names for hardware types.  Name translates into
1985e9d01f2Sgwr  * hardware type code listed with it.  Names must begin with a letter
1995e9d01f2Sgwr  * and must be all lowercase.  This is searched linearly, so put
2005e9d01f2Sgwr  * commonly-used entries near the beginning.
2015e9d01f2Sgwr  */
2025e9d01f2Sgwr 
2035e9d01f2Sgwr PRIVATE struct htypename htnamemap[] = {
2045e9d01f2Sgwr 	{"ethernet", HTYPE_ETHERNET},
2055e9d01f2Sgwr 	{"ethernet3", HTYPE_EXP_ETHERNET},
2065e9d01f2Sgwr 	{"ether", HTYPE_ETHERNET},
2075e9d01f2Sgwr 	{"ether3", HTYPE_EXP_ETHERNET},
2085e9d01f2Sgwr 	{"ieee802", HTYPE_IEEE802},
2095e9d01f2Sgwr 	{"tr", HTYPE_IEEE802},
2105e9d01f2Sgwr 	{"token-ring", HTYPE_IEEE802},
2115e9d01f2Sgwr 	{"pronet", HTYPE_PRONET},
2125e9d01f2Sgwr 	{"chaos", HTYPE_CHAOS},
2135e9d01f2Sgwr 	{"arcnet", HTYPE_ARCNET},
2145e9d01f2Sgwr 	{"ax.25", HTYPE_AX25},
2155e9d01f2Sgwr 	{"direct", HTYPE_DIRECT},
2165e9d01f2Sgwr 	{"serial", HTYPE_DIRECT},
2175e9d01f2Sgwr 	{"slip", HTYPE_DIRECT},
2185e9d01f2Sgwr 	{"ppp", HTYPE_DIRECT}
2195e9d01f2Sgwr };
2205e9d01f2Sgwr 
2215e9d01f2Sgwr 
2225e9d01f2Sgwr 
2235e9d01f2Sgwr /*
2245e9d01f2Sgwr  * Externals and forward declarations.
2255e9d01f2Sgwr  */
2265e9d01f2Sgwr 
227131109e4Swiz boolean nmcmp(hash_datum *, hash_datum *);
2285e9d01f2Sgwr 
2295e9d01f2Sgwr PRIVATE void
230131109e4Swiz 	adjust(char **);
2315e9d01f2Sgwr PRIVATE void
232131109e4Swiz 	del_string(struct shared_string *);
2335e9d01f2Sgwr PRIVATE void
234131109e4Swiz 	del_bindata(struct shared_bindata *);
2355e9d01f2Sgwr PRIVATE void
236131109e4Swiz 	del_iplist(struct in_addr_list *);
2375e9d01f2Sgwr PRIVATE void
238131109e4Swiz 	eat_whitespace(char **);
2395e9d01f2Sgwr PRIVATE int
240131109e4Swiz 	eval_symbol(char **, struct host *);
2415e9d01f2Sgwr PRIVATE void
242131109e4Swiz 	fill_defaults(struct host *, char **);
2435e9d01f2Sgwr PRIVATE void
244131109e4Swiz 	free_host(hash_datum *);
2455e9d01f2Sgwr PRIVATE struct in_addr_list *
246131109e4Swiz 	get_addresses(char **);
2475e9d01f2Sgwr PRIVATE struct shared_string *
248131109e4Swiz 	get_shared_string(char **);
2495e9d01f2Sgwr PRIVATE char *
250131109e4Swiz 	get_string(char **, char *, u_int *);
2515e9d01f2Sgwr PRIVATE u_int32
252131109e4Swiz 	get_u_long(char **);
2535e9d01f2Sgwr PRIVATE boolean
254131109e4Swiz 	goodname(char *);
2555e9d01f2Sgwr PRIVATE boolean
256131109e4Swiz 	hwinscmp(hash_datum *, hash_datum *);
2575e9d01f2Sgwr PRIVATE int
258131109e4Swiz 	interp_byte(char **, byte *);
2595e9d01f2Sgwr PRIVATE void
260131109e4Swiz 	makelower(char *);
2615e9d01f2Sgwr PRIVATE boolean
262131109e4Swiz         nullcmp(hash_datum *, hash_datum *);
2635e9d01f2Sgwr PRIVATE int
264131109e4Swiz 	process_entry(struct host *, char *);
2655e9d01f2Sgwr PRIVATE int
266131109e4Swiz 	process_generic(char **, struct shared_bindata **, u_int);
2675e9d01f2Sgwr PRIVATE byte *
268131109e4Swiz 	prs_haddr(char **, u_int);
2695e9d01f2Sgwr PRIVATE int
270131109e4Swiz 	prs_inetaddr(char **, u_int32 *);
2715e9d01f2Sgwr PRIVATE void
272131109e4Swiz 	read_entry(FILE *, char *, u_int *);
2735e9d01f2Sgwr PRIVATE char *
274131109e4Swiz 	smalloc(u_int);
2755e9d01f2Sgwr 
2765e9d01f2Sgwr 
2775e9d01f2Sgwr 
2785e9d01f2Sgwr /*
2795e9d01f2Sgwr  * Vendor magic cookies for CMU and RFC1048
2805e9d01f2Sgwr  */
2815e9d01f2Sgwr u_char vm_cmu[4] = VM_CMU;
2825e9d01f2Sgwr u_char vm_rfc1048[4] = VM_RFC1048;
2835e9d01f2Sgwr 
2845e9d01f2Sgwr /*
2855e9d01f2Sgwr  * Main hash tables
2865e9d01f2Sgwr  */
2875e9d01f2Sgwr hash_tbl *hwhashtable;
2885e9d01f2Sgwr hash_tbl *iphashtable;
2895e9d01f2Sgwr hash_tbl *nmhashtable;
2905e9d01f2Sgwr 
2915e9d01f2Sgwr /*
2925e9d01f2Sgwr  * Allocate hash tables for hardware address, ip address, and hostname
2935e9d01f2Sgwr  * (shared by bootpd and bootpef)
2945e9d01f2Sgwr  */
2955e9d01f2Sgwr void
rdtab_init(void)296131109e4Swiz rdtab_init(void)
2975e9d01f2Sgwr {
2985e9d01f2Sgwr 	hwhashtable = hash_Init(HASHTABLESIZE);
2995e9d01f2Sgwr 	iphashtable = hash_Init(HASHTABLESIZE);
3005e9d01f2Sgwr 	nmhashtable = hash_Init(HASHTABLESIZE);
3015e9d01f2Sgwr 	if (!(hwhashtable && iphashtable && nmhashtable)) {
3025e9d01f2Sgwr 		report(LOG_ERR, "Unable to allocate hash tables.");
3035e9d01f2Sgwr 		exit(1);
3045e9d01f2Sgwr 	}
3055e9d01f2Sgwr }
3065e9d01f2Sgwr 
3075e9d01f2Sgwr 
3085e9d01f2Sgwr /*
3095e9d01f2Sgwr  * Read bootptab database file.  Avoid rereading the file if the
3105e9d01f2Sgwr  * write date hasn't changed since the last time we read it.
3115e9d01f2Sgwr  */
3125e9d01f2Sgwr 
3135e9d01f2Sgwr void
readtab(int force)314131109e4Swiz readtab(int force)
3155e9d01f2Sgwr {
3165e9d01f2Sgwr 	struct host *hp;
3175e9d01f2Sgwr 	FILE *fp;
3185e9d01f2Sgwr 	struct stat st;
3195e9d01f2Sgwr 	unsigned hashcode, buflen;
3205e9d01f2Sgwr 	static char buffer[MAXENTRYLEN];
3215e9d01f2Sgwr 
3225e9d01f2Sgwr 	/*
3235e9d01f2Sgwr 	 * Check the last modification time.
3245e9d01f2Sgwr 	 */
3255e9d01f2Sgwr 	if (stat(bootptab, &st) < 0) {
3265e9d01f2Sgwr 		report(LOG_ERR, "stat on \"%s\": %s",
3275e9d01f2Sgwr 			   bootptab, get_errmsg());
3285e9d01f2Sgwr 		return;
3295e9d01f2Sgwr 	}
3305e9d01f2Sgwr #ifdef DEBUG
3315e9d01f2Sgwr 	if (debug > 3) {
3325e9d01f2Sgwr 		char timestr[28];
3335402d14cSitojun 		strlcpy(timestr, ctime(&(st.st_mtime)), sizeof(timestr));
3345e9d01f2Sgwr 		/* zap the newline */
3355e9d01f2Sgwr 		timestr[24] = '\0';
3365e9d01f2Sgwr 		report(LOG_INFO, "bootptab mtime: %s",
3375e9d01f2Sgwr 			   timestr);
3385e9d01f2Sgwr 	}
3395e9d01f2Sgwr #endif
3405e9d01f2Sgwr 	if ((force == 0) &&
3415e9d01f2Sgwr 		(st.st_mtime == modtime) &&
3425e9d01f2Sgwr 		st.st_nlink) {
3435e9d01f2Sgwr 		/*
3445e9d01f2Sgwr 		 * hasn't been modified or deleted yet.
3455e9d01f2Sgwr 		 */
3465e9d01f2Sgwr 		return;
3475e9d01f2Sgwr 	}
3485e9d01f2Sgwr 	if (debug)
3495e9d01f2Sgwr 		report(LOG_INFO, "reading %s\"%s\"",
3505e9d01f2Sgwr 			   (modtime != 0L) ? "new " : "",
3515e9d01f2Sgwr 			   bootptab);
3525e9d01f2Sgwr 
3535e9d01f2Sgwr 	/*
3545e9d01f2Sgwr 	 * Open bootptab file.
3555e9d01f2Sgwr 	 */
3565e9d01f2Sgwr 	if ((fp = fopen(bootptab, "r")) == NULL) {
3575e9d01f2Sgwr 		report(LOG_ERR, "error opening \"%s\": %s", bootptab, get_errmsg());
3585e9d01f2Sgwr 		return;
3595e9d01f2Sgwr 	}
3605e9d01f2Sgwr 	/*
3615e9d01f2Sgwr 	 * Record file modification time.
3625e9d01f2Sgwr 	 */
3635e9d01f2Sgwr 	if (fstat(fileno(fp), &st) < 0) {
3645e9d01f2Sgwr 		report(LOG_ERR, "fstat: %s", get_errmsg());
3655e9d01f2Sgwr 		fclose(fp);
3665e9d01f2Sgwr 		return;
3675e9d01f2Sgwr 	}
3685e9d01f2Sgwr 	modtime = st.st_mtime;
3695e9d01f2Sgwr 
3705e9d01f2Sgwr 	/*
3715e9d01f2Sgwr 	 * Entirely erase all hash tables.
3725e9d01f2Sgwr 	 */
3735e9d01f2Sgwr 	hash_Reset(hwhashtable, free_host);
3745e9d01f2Sgwr 	hash_Reset(iphashtable, free_host);
3755e9d01f2Sgwr 	hash_Reset(nmhashtable, free_host);
3765e9d01f2Sgwr 
3775e9d01f2Sgwr 	nhosts = 0;
3785e9d01f2Sgwr 	nentries = 0;
3795e9d01f2Sgwr 	while (TRUE) {
3805e9d01f2Sgwr 		buflen = sizeof(buffer);
3815e9d01f2Sgwr 		read_entry(fp, buffer, &buflen);
3825e9d01f2Sgwr 		if (buflen == 0) {		/* More entries? */
3835e9d01f2Sgwr 			break;
3845e9d01f2Sgwr 		}
3855e9d01f2Sgwr 		hp = (struct host *) smalloc(sizeof(struct host));
3865e9d01f2Sgwr 		bzero((char *) hp, sizeof(*hp));
3875e9d01f2Sgwr 		/* the link count it zero */
3885e9d01f2Sgwr 
3895e9d01f2Sgwr 		/*
3905e9d01f2Sgwr 		 * Get individual info
3915e9d01f2Sgwr 		 */
3925e9d01f2Sgwr 		if (process_entry(hp, buffer) < 0) {
3935e9d01f2Sgwr 			hp->linkcount = 1;
3945e9d01f2Sgwr 			free_host((hash_datum *) hp);
3955e9d01f2Sgwr 			continue;
3965e9d01f2Sgwr 		}
3975e9d01f2Sgwr 		/*
3985e9d01f2Sgwr 		 * If this is not a dummy entry, and the IP or HW
3995e9d01f2Sgwr 		 * address is not yet set, try to get them here.
4005e9d01f2Sgwr 		 * Dummy entries have . as first char of name.
4015e9d01f2Sgwr 		 */
4025e9d01f2Sgwr 		if (goodname(hp->hostname->string)) {
4035e9d01f2Sgwr 			char *hn = hp->hostname->string;
4045e9d01f2Sgwr 			u_int32 value;
4055e9d01f2Sgwr 			if (hp->flags.iaddr == 0) {
4065e9d01f2Sgwr 				if (lookup_ipa(hn, &value)) {
4075e9d01f2Sgwr 					report(LOG_ERR, "can not get IP addr for %s", hn);
4085e9d01f2Sgwr 					report(LOG_ERR, "(dummy names should start with '.')");
4095e9d01f2Sgwr 				} else {
4105e9d01f2Sgwr 					hp->iaddr.s_addr = value;
4115e9d01f2Sgwr 					hp->flags.iaddr = TRUE;
4125e9d01f2Sgwr 				}
4135e9d01f2Sgwr 			}
4145e9d01f2Sgwr 			/* Set default subnet mask. */
4155e9d01f2Sgwr 			if (hp->flags.subnet_mask == 0) {
4165e9d01f2Sgwr 				if (lookup_netmask(hp->iaddr.s_addr, &value)) {
4175e9d01f2Sgwr 					report(LOG_ERR, "can not get netmask for %s", hn);
4185e9d01f2Sgwr 				} else {
4195e9d01f2Sgwr 					hp->subnet_mask.s_addr = value;
4205e9d01f2Sgwr 					hp->flags.subnet_mask = TRUE;
4215e9d01f2Sgwr 				}
4225e9d01f2Sgwr 			}
4235e9d01f2Sgwr 		}
4245e9d01f2Sgwr 		if (hp->flags.iaddr) {
4255e9d01f2Sgwr 			nhosts++;
4265e9d01f2Sgwr 		}
4275e9d01f2Sgwr 		/* Register by HW addr if known. */
4285e9d01f2Sgwr 		if (hp->flags.htype && hp->flags.haddr) {
4295e9d01f2Sgwr 			/* We will either insert it or free it. */
4305e9d01f2Sgwr 			hp->linkcount++;
4315e9d01f2Sgwr 			hashcode = hash_HashFunction(hp->haddr, haddrlength(hp->htype));
4325e9d01f2Sgwr 			if (hash_Insert(hwhashtable, hashcode, hwinscmp, hp, hp) < 0) {
4335e9d01f2Sgwr 				report(LOG_NOTICE, "duplicate %s address: %s",
4345e9d01f2Sgwr 					   netname(hp->htype),
4352a645560Sgwr 					   haddrtoa(hp->haddr, haddrlength(hp->htype)));
4365e9d01f2Sgwr 				free_host((hash_datum *) hp);
4375e9d01f2Sgwr 				continue;
4385e9d01f2Sgwr 			}
4395e9d01f2Sgwr 		}
4405e9d01f2Sgwr 		/* Register by IP addr if known. */
4415e9d01f2Sgwr 		if (hp->flags.iaddr) {
4425e9d01f2Sgwr 			hashcode = hash_HashFunction((u_char *) & (hp->iaddr.s_addr), 4);
4435e9d01f2Sgwr 			if (hash_Insert(iphashtable, hashcode, nullcmp, hp, hp) < 0) {
4445e9d01f2Sgwr 				report(LOG_ERR,
4455e9d01f2Sgwr 					   "hash_Insert() failed on IP address insertion");
4465e9d01f2Sgwr 			} else {
4475e9d01f2Sgwr 				/* Just inserted the host struct in a new hash list. */
4485e9d01f2Sgwr 				hp->linkcount++;
4495e9d01f2Sgwr 			}
4505e9d01f2Sgwr 		}
4515e9d01f2Sgwr 		/* Register by Name (always known) */
4525e9d01f2Sgwr 		hashcode = hash_HashFunction((u_char *) hp->hostname->string,
4535e9d01f2Sgwr 									 strlen(hp->hostname->string));
4545e9d01f2Sgwr 		if (hash_Insert(nmhashtable, hashcode, nullcmp,
4555e9d01f2Sgwr 						hp->hostname->string, hp) < 0) {
4565e9d01f2Sgwr 			report(LOG_ERR,
4575e9d01f2Sgwr 				 "hash_Insert() failed on insertion of hostname: \"%s\"",
4585e9d01f2Sgwr 				   hp->hostname->string);
4595e9d01f2Sgwr 		} else {
4605e9d01f2Sgwr 			/* Just inserted the host struct in a new hash list. */
4615e9d01f2Sgwr 			hp->linkcount++;
4625e9d01f2Sgwr 		}
4635e9d01f2Sgwr 
4645e9d01f2Sgwr 		nentries++;
4655e9d01f2Sgwr 	}
4665e9d01f2Sgwr 
4675e9d01f2Sgwr 	fclose(fp);
4685e9d01f2Sgwr 	if (debug)
4695e9d01f2Sgwr 		report(LOG_INFO, "read %d entries (%d hosts) from \"%s\"",
4705e9d01f2Sgwr 			   nentries, nhosts, bootptab);
4715e9d01f2Sgwr 	return;
4725e9d01f2Sgwr }
4735e9d01f2Sgwr 
4745e9d01f2Sgwr 
4755e9d01f2Sgwr 
4765e9d01f2Sgwr /*
4775e9d01f2Sgwr  * Read an entire host entry from the file pointed to by "fp" and insert it
4785e9d01f2Sgwr  * into the memory pointed to by "buffer".  Leading whitespace and comments
4795e9d01f2Sgwr  * starting with "#" are ignored (removed).  Backslashes (\) always quote
4801e378c4cSwiz  * the next character except that newlines preceded by a backslash cause
4815e9d01f2Sgwr  * line-continuation onto the next line.  The entry is terminated by a
4821e378c4cSwiz  * newline character which is not preceded by a backslash.  Sequences
4835e9d01f2Sgwr  * surrounded by double quotes are taken literally (including newlines, but
4845e9d01f2Sgwr  * not backslashes).
4855e9d01f2Sgwr  *
4865e9d01f2Sgwr  * The "bufsiz" parameter points to an unsigned int which specifies the
4875e9d01f2Sgwr  * maximum permitted buffer size.  Upon return, this value will be replaced
4885e9d01f2Sgwr  * with the actual length of the entry (not including the null terminator).
4895e9d01f2Sgwr  *
4905e9d01f2Sgwr  * This code is a little scary. . . .  I don't like using gotos in C
4915e9d01f2Sgwr  * either, but I first wrote this as an FSM diagram and gotos seemed like
4925e9d01f2Sgwr  * the easiest way to implement it.  Maybe later I'll clean it up.
4935e9d01f2Sgwr  */
4945e9d01f2Sgwr 
4955e9d01f2Sgwr PRIVATE void
read_entry(FILE * fp,char * buffer,unsigned int * bufsiz)496131109e4Swiz read_entry(FILE *fp, char *buffer, unsigned int *bufsiz)
4975e9d01f2Sgwr {
4987affd655Slukem 	int c;
4997affd655Slukem 	unsigned int length;
5005e9d01f2Sgwr 
5015e9d01f2Sgwr 	length = 0;
5025e9d01f2Sgwr 
5035e9d01f2Sgwr 	/*
5045e9d01f2Sgwr 	 * Eat whitespace, blank lines, and comment lines.
5055e9d01f2Sgwr 	 */
5065e9d01f2Sgwr   top:
5075e9d01f2Sgwr 	c = fgetc(fp);
5085e9d01f2Sgwr 	if (c < 0) {
5095e9d01f2Sgwr 		goto done;				/* Exit if end-of-file */
5105e9d01f2Sgwr 	}
5115e9d01f2Sgwr 	if (isspace(c)) {
5125e9d01f2Sgwr 		goto top;				/* Skip over whitespace */
5135e9d01f2Sgwr 	}
5145e9d01f2Sgwr 	if (c == '#') {
5155e9d01f2Sgwr 		while (TRUE) {			/* Eat comments after # */
5165e9d01f2Sgwr 			c = fgetc(fp);
5175e9d01f2Sgwr 			if (c < 0) {
5185e9d01f2Sgwr 				goto done;		/* Exit if end-of-file */
5195e9d01f2Sgwr 			}
5205e9d01f2Sgwr 			if (c == '\n') {
5215e9d01f2Sgwr 				goto top;		/* Try to read the next line */
5225e9d01f2Sgwr 			}
5235e9d01f2Sgwr 		}
5245e9d01f2Sgwr 	}
5255e9d01f2Sgwr 	ungetc(c, fp);				/* Other character, push it back to reprocess it */
5265e9d01f2Sgwr 
5275e9d01f2Sgwr 
5285e9d01f2Sgwr 	/*
5295e9d01f2Sgwr 	 * Now we're actually reading a data entry.  Get each character and
5305e9d01f2Sgwr 	 * assemble it into the data buffer, processing special characters like
5315e9d01f2Sgwr 	 * double quotes (") and backslashes (\).
5325e9d01f2Sgwr 	 */
5335e9d01f2Sgwr 
5345e9d01f2Sgwr   mainloop:
5355e9d01f2Sgwr 	c = fgetc(fp);
5365e9d01f2Sgwr 	switch (c) {
5375e9d01f2Sgwr 	case EOF:
5385e9d01f2Sgwr 	case '\n':
5395e9d01f2Sgwr 		goto done;				/* Exit on EOF or newline */
5405e9d01f2Sgwr 	case '\\':
5415e9d01f2Sgwr 		c = fgetc(fp);			/* Backslash, read a new character */
5425e9d01f2Sgwr 		if (c < 0) {
5435e9d01f2Sgwr 			goto done;			/* Exit on EOF */
5445e9d01f2Sgwr 		}
5455e9d01f2Sgwr 		*buffer++ = c;			/* Store the literal character */
5465e9d01f2Sgwr 		length++;
5475e9d01f2Sgwr 		if (length < *bufsiz - 1) {
5485e9d01f2Sgwr 			goto mainloop;
5495e9d01f2Sgwr 		} else {
5505e9d01f2Sgwr 			goto done;
5515e9d01f2Sgwr 		}
5525e9d01f2Sgwr 	case '"':
5535e9d01f2Sgwr 		*buffer++ = '"';		/* Store double-quote */
5545e9d01f2Sgwr 		length++;
5555e9d01f2Sgwr 		if (length >= *bufsiz - 1) {
5565e9d01f2Sgwr 			goto done;
5575e9d01f2Sgwr 		}
5585e9d01f2Sgwr 		while (TRUE) {			/* Special quote processing loop */
5595e9d01f2Sgwr 			c = fgetc(fp);
5605e9d01f2Sgwr 			switch (c) {
5615e9d01f2Sgwr 			case EOF:
5625e9d01f2Sgwr 				goto done;		/* Exit on EOF . . . */
5635e9d01f2Sgwr 			case '"':
5645e9d01f2Sgwr 				*buffer++ = '"';/* Store matching quote */
5655e9d01f2Sgwr 				length++;
5665e9d01f2Sgwr 				if (length < *bufsiz - 1) {
5675e9d01f2Sgwr 					goto mainloop;	/* And continue main loop */
5685e9d01f2Sgwr 				} else {
5695e9d01f2Sgwr 					goto done;
5705e9d01f2Sgwr 				}
5715e9d01f2Sgwr 			case '\\':
5725e9d01f2Sgwr 				if ((c = fgetc(fp)) < 0) {	/* Backslash */
5735e9d01f2Sgwr 					goto done;	/* EOF. . . .*/
5745e9d01f2Sgwr 				}				/* else fall through */
5755e9d01f2Sgwr 			default:
5765e9d01f2Sgwr 				*buffer++ = c;	/* Other character, store it */
5775e9d01f2Sgwr 				length++;
5785e9d01f2Sgwr 				if (length >= *bufsiz - 1) {
5795e9d01f2Sgwr 					goto done;
5805e9d01f2Sgwr 				}
5815e9d01f2Sgwr 			}
5825e9d01f2Sgwr 		}
5835e9d01f2Sgwr 	case ':':
5845e9d01f2Sgwr 		*buffer++ = c;			/* Store colons */
5855e9d01f2Sgwr 		length++;
5865e9d01f2Sgwr 		if (length >= *bufsiz - 1) {
5875e9d01f2Sgwr 			goto done;
5885e9d01f2Sgwr 		}
5895e9d01f2Sgwr 		do {					/* But remove whitespace after them */
5905e9d01f2Sgwr 			c = fgetc(fp);
5915e9d01f2Sgwr 			if ((c < 0) || (c == '\n')) {
5925e9d01f2Sgwr 				goto done;
5935e9d01f2Sgwr 			}
5945e9d01f2Sgwr 		} while (isspace(c));	/* Skip whitespace */
5955e9d01f2Sgwr 
5965e9d01f2Sgwr 		if (c == '\\') {		/* Backslash quotes next character */
5975e9d01f2Sgwr 			c = fgetc(fp);
5985e9d01f2Sgwr 			if (c < 0) {
5995e9d01f2Sgwr 				goto done;
6005e9d01f2Sgwr 			}
6015e9d01f2Sgwr 			if (c == '\n') {
6025e9d01f2Sgwr 				goto top;		/* Backslash-newline continuation */
6035e9d01f2Sgwr 			}
6045e9d01f2Sgwr 		}
6055e9d01f2Sgwr 		/* fall through if "other" character */
606*fbffadb9Smrg 		/* FALLTHROUGH */
6075e9d01f2Sgwr 	default:
6085e9d01f2Sgwr 		*buffer++ = c;			/* Store other characters */
6095e9d01f2Sgwr 		length++;
6105e9d01f2Sgwr 		if (length >= *bufsiz - 1) {
6115e9d01f2Sgwr 			goto done;
6125e9d01f2Sgwr 		}
6135e9d01f2Sgwr 	}
6145e9d01f2Sgwr 	goto mainloop;				/* Keep going */
6155e9d01f2Sgwr 
6165e9d01f2Sgwr   done:
6175e9d01f2Sgwr 	*buffer = '\0';				/* Terminate string */
6185e9d01f2Sgwr 	*bufsiz = length;			/* Tell the caller its length */
6195e9d01f2Sgwr }
6205e9d01f2Sgwr 
6215e9d01f2Sgwr 
6225e9d01f2Sgwr 
6235e9d01f2Sgwr /*
6245e9d01f2Sgwr  * Parse out all the various tags and parameters in the host entry pointed
6255e9d01f2Sgwr  * to by "src".  Stuff all the data into the appropriate fields of the
6265e9d01f2Sgwr  * host structure pointed to by "host".  If there is any problem with the
6275e9d01f2Sgwr  * entry, an error message is reported via report(), no further processing
6285e9d01f2Sgwr  * is done, and -1 is returned.  Successful calls return 0.
6295e9d01f2Sgwr  *
6305e9d01f2Sgwr  * (Some errors probably shouldn't be so completely fatal. . . .)
6315e9d01f2Sgwr  */
6325e9d01f2Sgwr 
6335e9d01f2Sgwr PRIVATE int
process_entry(struct host * host,char * src)634131109e4Swiz process_entry(struct host *host, char *src)
6355e9d01f2Sgwr {
6365e9d01f2Sgwr 	int retval;
637c8f61d2bSxtraeme 	const char *msg;
6385e9d01f2Sgwr 
6395e9d01f2Sgwr 	if (!host || *src == '\0') {
6405e9d01f2Sgwr 		return -1;
6415e9d01f2Sgwr 	}
6425e9d01f2Sgwr 	host->hostname = get_shared_string(&src);
6435e9d01f2Sgwr #if 0
6445e9d01f2Sgwr 	/* Be more liberal for the benefit of dummy tag names. */
6455e9d01f2Sgwr 	if (!goodname(host->hostname->string)) {
6465e9d01f2Sgwr 		report(LOG_ERR, "bad hostname: \"%s\"", host->hostname->string);
6475e9d01f2Sgwr 		del_string(host->hostname);
6485e9d01f2Sgwr 		return -1;
6495e9d01f2Sgwr 	}
6505e9d01f2Sgwr #endif
6515e9d01f2Sgwr 	current_hostname = host->hostname->string;
6525e9d01f2Sgwr 	adjust(&src);
6535e9d01f2Sgwr 	while (TRUE) {
6545e9d01f2Sgwr 		retval = eval_symbol(&src, host);
6555e9d01f2Sgwr 		if (retval == SUCCESS) {
6565e9d01f2Sgwr 			adjust(&src);
6575e9d01f2Sgwr 			continue;
6585e9d01f2Sgwr 		}
6595e9d01f2Sgwr 		if (retval == E_END_OF_ENTRY) {
6605e9d01f2Sgwr 			/* The default subnet mask is set in readtab() */
6615e9d01f2Sgwr 			return 0;
6625e9d01f2Sgwr 		}
6635e9d01f2Sgwr 		/* Some kind of error. */
6645e9d01f2Sgwr 		switch (retval) {
6655e9d01f2Sgwr 		case E_SYNTAX_ERROR:
6665e9d01f2Sgwr 			msg = "bad syntax";
6675e9d01f2Sgwr 			break;
6685e9d01f2Sgwr 		case E_UNKNOWN_SYMBOL:
6695e9d01f2Sgwr 			msg = "unknown symbol";
6705e9d01f2Sgwr 			break;
6715e9d01f2Sgwr 		case E_BAD_IPADDR:
6725e9d01f2Sgwr 			msg = "bad INET address";
6735e9d01f2Sgwr 			break;
6745e9d01f2Sgwr 		case E_BAD_HWADDR:
6755e9d01f2Sgwr 			msg = "bad hardware address";
6765e9d01f2Sgwr 			break;
6775e9d01f2Sgwr 		case E_BAD_LONGWORD:
6785e9d01f2Sgwr 			msg = "bad longword value";
6795e9d01f2Sgwr 			break;
6805e9d01f2Sgwr 		case E_BAD_HWATYPE:
6815e9d01f2Sgwr 			msg = "bad HW address type";
6825e9d01f2Sgwr 			break;
6835e9d01f2Sgwr 		case E_BAD_PATHNAME:
6845e9d01f2Sgwr 			msg = "bad pathname (need leading '/')";
6857e975aafSwiz 			break;
686bcb13babSgwr 		case E_BAD_VALUE:
687bcb13babSgwr 			msg = "bad value";
6887e975aafSwiz 			break;
6895e9d01f2Sgwr 		default:
6907bd6fd35Swiz 			msg = "unknown error";
6915e9d01f2Sgwr 			break;
6925e9d01f2Sgwr 		}						/* switch */
6935e9d01f2Sgwr 		report(LOG_ERR, "in entry named \"%s\", symbol \"%s\": %s",
6945e9d01f2Sgwr 			   current_hostname, current_tagname, msg);
6955e9d01f2Sgwr 		return -1;
6965e9d01f2Sgwr 	}
6975e9d01f2Sgwr }
6985e9d01f2Sgwr 
6995e9d01f2Sgwr 
7005e9d01f2Sgwr /*
7015e9d01f2Sgwr  * Macros for use in the function below:
7025e9d01f2Sgwr  */
7035e9d01f2Sgwr 
7045e9d01f2Sgwr /* Parse one INET address stored directly in MEMBER. */
7055e9d01f2Sgwr #define PARSE_IA1(MEMBER) do \
7065e9d01f2Sgwr { \
7075e9d01f2Sgwr 	if (optype == OP_BOOLEAN) \
7085e9d01f2Sgwr 		return E_SYNTAX_ERROR; \
7095e9d01f2Sgwr 	hp->flags.MEMBER = FALSE; \
7105e9d01f2Sgwr 	if (optype == OP_ADDITION) { \
7115e9d01f2Sgwr 		if (prs_inetaddr(symbol, &value) < 0) \
7125e9d01f2Sgwr 			return E_BAD_IPADDR; \
7135e9d01f2Sgwr 		hp->MEMBER.s_addr = value; \
7145e9d01f2Sgwr 		hp->flags.MEMBER = TRUE; \
7155e9d01f2Sgwr 	} \
7165e9d01f2Sgwr } while (0)
7175e9d01f2Sgwr 
7185e9d01f2Sgwr /* Parse a list of INET addresses pointed to by MEMBER */
7195e9d01f2Sgwr #define PARSE_IAL(MEMBER) do \
7205e9d01f2Sgwr { \
7215e9d01f2Sgwr 	if (optype == OP_BOOLEAN) \
7225e9d01f2Sgwr 		return E_SYNTAX_ERROR; \
7235e9d01f2Sgwr 	if (hp->flags.MEMBER) { \
7245e9d01f2Sgwr 		hp->flags.MEMBER = FALSE; \
7255e9d01f2Sgwr 		assert(hp->MEMBER); \
7265e9d01f2Sgwr 		del_iplist(hp->MEMBER); \
7275e9d01f2Sgwr 		hp->MEMBER = NULL; \
7285e9d01f2Sgwr 	} \
7295e9d01f2Sgwr 	if (optype == OP_ADDITION) { \
7305e9d01f2Sgwr 		hp->MEMBER = get_addresses(symbol); \
7315e9d01f2Sgwr 		if (hp->MEMBER == NULL) \
7325e9d01f2Sgwr 			return E_SYNTAX_ERROR; \
7335e9d01f2Sgwr 		hp->flags.MEMBER = TRUE; \
7345e9d01f2Sgwr 	} \
7355e9d01f2Sgwr } while (0)
7365e9d01f2Sgwr 
7375e9d01f2Sgwr /* Parse a shared string pointed to by MEMBER */
7385e9d01f2Sgwr #define PARSE_STR(MEMBER) do \
7395e9d01f2Sgwr { \
7405e9d01f2Sgwr 	if (optype == OP_BOOLEAN) \
7415e9d01f2Sgwr 		return E_SYNTAX_ERROR; \
7425e9d01f2Sgwr 	if (hp->flags.MEMBER) { \
7435e9d01f2Sgwr 		hp->flags.MEMBER = FALSE; \
7445e9d01f2Sgwr 		assert(hp->MEMBER); \
7455e9d01f2Sgwr 		del_string(hp->MEMBER); \
7465e9d01f2Sgwr 		hp->MEMBER = NULL; \
7475e9d01f2Sgwr 	} \
7485e9d01f2Sgwr 	if (optype == OP_ADDITION) { \
7495e9d01f2Sgwr 		hp->MEMBER = get_shared_string(symbol); \
7505e9d01f2Sgwr 		if (hp->MEMBER == NULL) \
7515e9d01f2Sgwr 			return E_SYNTAX_ERROR; \
7525e9d01f2Sgwr 		hp->flags.MEMBER = TRUE; \
7535e9d01f2Sgwr 	} \
7545e9d01f2Sgwr } while (0)
7555e9d01f2Sgwr 
756bcb13babSgwr /* Parse an integer value for MEMBER */
757bcb13babSgwr #define PARSE_INT(MEMBER) do \
758bcb13babSgwr { \
759bcb13babSgwr 	if (optype == OP_BOOLEAN) \
760bcb13babSgwr 		return E_SYNTAX_ERROR; \
761bcb13babSgwr 	hp->flags.MEMBER = FALSE; \
762bcb13babSgwr 	if (optype == OP_ADDITION) { \
763bcb13babSgwr 		value = get_u_long(symbol); \
764bcb13babSgwr 		hp->MEMBER = value; \
765bcb13babSgwr 		hp->flags.MEMBER = TRUE; \
766bcb13babSgwr 	} \
767bcb13babSgwr } while (0)
768bcb13babSgwr 
7695e9d01f2Sgwr /*
7705e9d01f2Sgwr  * Evaluate the two-character tag symbol pointed to by "symbol" and place
7715e9d01f2Sgwr  * the data in the structure pointed to by "hp".  The pointer pointed to
7725e9d01f2Sgwr  * by "symbol" is updated to point past the source string (but may not
7735e9d01f2Sgwr  * point to the next tag entry).
7745e9d01f2Sgwr  *
7755e9d01f2Sgwr  * Obviously, this need a few more comments. . . .
7765e9d01f2Sgwr  */
7775e9d01f2Sgwr PRIVATE int
eval_symbol(char ** symbol,struct host * hp)778131109e4Swiz eval_symbol(char **symbol, struct host *hp)
7795e9d01f2Sgwr {
7805e9d01f2Sgwr 	char tmpstr[MAXSTRINGLEN];
7815e9d01f2Sgwr 	byte *tmphaddr;
7825e9d01f2Sgwr 	struct symbolmap *symbolptr;
7835e9d01f2Sgwr 	u_int32 value;
784c8f61d2bSxtraeme 	int32 ltimeoff;
7855e9d01f2Sgwr 	int i, numsymbols;
7865e9d01f2Sgwr 	unsigned len;
7875e9d01f2Sgwr 	int optype;					/* Indicates boolean, addition, or deletion */
7885e9d01f2Sgwr 
7895e9d01f2Sgwr 	eat_whitespace(symbol);
7905e9d01f2Sgwr 
7915e9d01f2Sgwr 	/* Make sure this is set before returning. */
7925e9d01f2Sgwr 	current_tagname[0] = (*symbol)[0];
7935e9d01f2Sgwr 	current_tagname[1] = (*symbol)[1];
7945e9d01f2Sgwr 	current_tagname[2] = 0;
7955e9d01f2Sgwr 
7965e9d01f2Sgwr 	if ((*symbol)[0] == '\0') {
7975e9d01f2Sgwr 		return E_END_OF_ENTRY;
7985e9d01f2Sgwr 	}
7995e9d01f2Sgwr 	if ((*symbol)[0] == ':') {
8005e9d01f2Sgwr 		return SUCCESS;
8015e9d01f2Sgwr 	}
8025e9d01f2Sgwr 	if ((*symbol)[0] == 'T') {	/* generic symbol */
8035e9d01f2Sgwr 		(*symbol)++;
8045e9d01f2Sgwr 		value = get_u_long(symbol);
8055402d14cSitojun 		snprintf(current_tagname, sizeof(current_tagname),
8065402d14cSitojun 		    "T%d", value);
8075e9d01f2Sgwr 		eat_whitespace(symbol);
8085e9d01f2Sgwr 		if ((*symbol)[0] != '=') {
8095e9d01f2Sgwr 			return E_SYNTAX_ERROR;
8105e9d01f2Sgwr 		}
8115e9d01f2Sgwr 		(*symbol)++;
8125e9d01f2Sgwr 		if (!(hp->generic)) {
8135e9d01f2Sgwr 			hp->generic = (struct shared_bindata *)
8145e9d01f2Sgwr 				smalloc(sizeof(struct shared_bindata));
8155e9d01f2Sgwr 		}
8165e9d01f2Sgwr 		if (process_generic(symbol, &(hp->generic), (byte) (value & 0xFF)))
8175e9d01f2Sgwr 			return E_SYNTAX_ERROR;
8185e9d01f2Sgwr 		hp->flags.generic = TRUE;
8195e9d01f2Sgwr 		return SUCCESS;
8205e9d01f2Sgwr 	}
8215e9d01f2Sgwr 	/*
8225e9d01f2Sgwr 	 * Determine the type of operation to be done on this symbol
8235e9d01f2Sgwr 	 */
8245e9d01f2Sgwr 	switch ((*symbol)[2]) {
8255e9d01f2Sgwr 	case '=':
8265e9d01f2Sgwr 		optype = OP_ADDITION;
8275e9d01f2Sgwr 		break;
8285e9d01f2Sgwr 	case '@':
8295e9d01f2Sgwr 		optype = OP_DELETION;
8305e9d01f2Sgwr 		break;
8315e9d01f2Sgwr 	case ':':
8325e9d01f2Sgwr 	case '\0':
8335e9d01f2Sgwr 		optype = OP_BOOLEAN;
8345e9d01f2Sgwr 		break;
8355e9d01f2Sgwr 	default:
8365e9d01f2Sgwr 		return E_SYNTAX_ERROR;
8375e9d01f2Sgwr 	}
8385e9d01f2Sgwr 
8395e9d01f2Sgwr 	symbolptr = symbol_list;
8405e9d01f2Sgwr 	numsymbols = sizeof(symbol_list) / sizeof(struct symbolmap);
8415e9d01f2Sgwr 	for (i = 0; i < numsymbols; i++) {
8425e9d01f2Sgwr 		if (((symbolptr->symbol)[0] == (*symbol)[0]) &&
8435e9d01f2Sgwr 			((symbolptr->symbol)[1] == (*symbol)[1])) {
8445e9d01f2Sgwr 			break;
8455e9d01f2Sgwr 		}
8465e9d01f2Sgwr 		symbolptr++;
8475e9d01f2Sgwr 	}
8485e9d01f2Sgwr 	if (i >= numsymbols) {
8495e9d01f2Sgwr 		return E_UNKNOWN_SYMBOL;
8505e9d01f2Sgwr 	}
8515e9d01f2Sgwr 	/*
8525e9d01f2Sgwr 	 * Skip past the = or @ character (to point to the data) if this
8535e9d01f2Sgwr 	 * isn't a boolean operation.  For boolean operations, just skip
8545e9d01f2Sgwr 	 * over the two-character tag symbol (and nothing else. . . .).
8555e9d01f2Sgwr 	 */
8565e9d01f2Sgwr 	(*symbol) += (optype == OP_BOOLEAN) ? 2 : 3;
8575e9d01f2Sgwr 
8585e9d01f2Sgwr 	eat_whitespace(symbol);
8595e9d01f2Sgwr 
8605e9d01f2Sgwr 	/* The cases below are in order by symbolcode value. */
8615e9d01f2Sgwr 	switch (symbolptr->symbolcode) {
8625e9d01f2Sgwr 
8635e9d01f2Sgwr 	case SYM_BOOTFILE:
8645e9d01f2Sgwr 		PARSE_STR(bootfile);
8655e9d01f2Sgwr 		break;
8665e9d01f2Sgwr 
8675e9d01f2Sgwr 	case SYM_COOKIE_SERVER:
8685e9d01f2Sgwr 		PARSE_IAL(cookie_server);
8695e9d01f2Sgwr 		break;
8705e9d01f2Sgwr 
8715e9d01f2Sgwr 	case SYM_DOMAIN_SERVER:
8725e9d01f2Sgwr 		PARSE_IAL(domain_server);
8735e9d01f2Sgwr 		break;
8745e9d01f2Sgwr 
8755e9d01f2Sgwr 	case SYM_GATEWAY:
8765e9d01f2Sgwr 		PARSE_IAL(gateway);
8775e9d01f2Sgwr 		break;
8785e9d01f2Sgwr 
8795e9d01f2Sgwr 	case SYM_HWADDR:
8805e9d01f2Sgwr 		if (optype == OP_BOOLEAN)
8815e9d01f2Sgwr 			return E_SYNTAX_ERROR;
8825e9d01f2Sgwr 		hp->flags.haddr = FALSE;
8835e9d01f2Sgwr 		if (optype == OP_ADDITION) {
8845e9d01f2Sgwr 			/* Default the HW type to Ethernet */
8855e9d01f2Sgwr 			if (hp->flags.htype == 0) {
8865e9d01f2Sgwr 				hp->flags.htype = TRUE;
8875e9d01f2Sgwr 				hp->htype = HTYPE_ETHERNET;
8885e9d01f2Sgwr 			}
8895e9d01f2Sgwr 			tmphaddr = prs_haddr(symbol, hp->htype);
8905e9d01f2Sgwr 			if (!tmphaddr)
8915e9d01f2Sgwr 				return E_BAD_HWADDR;
8925e9d01f2Sgwr 			bcopy(tmphaddr, hp->haddr, haddrlength(hp->htype));
8935e9d01f2Sgwr 			hp->flags.haddr = TRUE;
8945e9d01f2Sgwr 		}
8955e9d01f2Sgwr 		break;
8965e9d01f2Sgwr 
8975e9d01f2Sgwr 	case SYM_HOMEDIR:
8985e9d01f2Sgwr 		PARSE_STR(homedir);
8995e9d01f2Sgwr 		break;
9005e9d01f2Sgwr 
9015e9d01f2Sgwr 	case SYM_HTYPE:
9025e9d01f2Sgwr 		if (optype == OP_BOOLEAN)
9035e9d01f2Sgwr 			return E_SYNTAX_ERROR;
9045e9d01f2Sgwr 		hp->flags.htype = FALSE;
9055e9d01f2Sgwr 		if (optype == OP_ADDITION) {
9065e9d01f2Sgwr 			value = 0L;			/* Assume an illegal value */
9075e9d01f2Sgwr 			eat_whitespace(symbol);
908e09553f3Sdsl 			if (isdigit((unsigned char)**symbol)) {
9095e9d01f2Sgwr 				value = get_u_long(symbol);
9105e9d01f2Sgwr 			} else {
9115e9d01f2Sgwr 				len = sizeof(tmpstr);
9125e9d01f2Sgwr 				(void) get_string(symbol, tmpstr, &len);
9135e9d01f2Sgwr 				makelower(tmpstr);
9145e9d01f2Sgwr 				numsymbols = sizeof(htnamemap) /
9155e9d01f2Sgwr 					sizeof(struct htypename);
9165e9d01f2Sgwr 				for (i = 0; i < numsymbols; i++) {
9175e9d01f2Sgwr 					if (!strcmp(htnamemap[i].name, tmpstr)) {
9185e9d01f2Sgwr 						break;
9195e9d01f2Sgwr 					}
9205e9d01f2Sgwr 				}
9215e9d01f2Sgwr 				if (i < numsymbols) {
9225e9d01f2Sgwr 					value = htnamemap[i].htype;
9235e9d01f2Sgwr 				}
9245e9d01f2Sgwr 			}
9255e9d01f2Sgwr 			if (value >= hwinfocnt) {
9265e9d01f2Sgwr 				return E_BAD_HWATYPE;
9275e9d01f2Sgwr 			}
9285e9d01f2Sgwr 			hp->htype = (byte) (value & 0xFF);
9295e9d01f2Sgwr 			hp->flags.htype = TRUE;
9305e9d01f2Sgwr 		}
9315e9d01f2Sgwr 		break;
9325e9d01f2Sgwr 
9335e9d01f2Sgwr 	case SYM_IMPRESS_SERVER:
9345e9d01f2Sgwr 		PARSE_IAL(impress_server);
9355e9d01f2Sgwr 		break;
9365e9d01f2Sgwr 
9375e9d01f2Sgwr 	case SYM_IPADDR:
9385e9d01f2Sgwr 		PARSE_IA1(iaddr);
9395e9d01f2Sgwr 		break;
9405e9d01f2Sgwr 
9415e9d01f2Sgwr 	case SYM_LOG_SERVER:
9425e9d01f2Sgwr 		PARSE_IAL(log_server);
9435e9d01f2Sgwr 		break;
9445e9d01f2Sgwr 
9455e9d01f2Sgwr 	case SYM_LPR_SERVER:
9465e9d01f2Sgwr 		PARSE_IAL(lpr_server);
9475e9d01f2Sgwr 		break;
9485e9d01f2Sgwr 
9495e9d01f2Sgwr 	case SYM_NAME_SERVER:
9505e9d01f2Sgwr 		PARSE_IAL(name_server);
9515e9d01f2Sgwr 		break;
9525e9d01f2Sgwr 
9535e9d01f2Sgwr 	case SYM_RLP_SERVER:
9545e9d01f2Sgwr 		PARSE_IAL(rlp_server);
9555e9d01f2Sgwr 		break;
9565e9d01f2Sgwr 
9575e9d01f2Sgwr 	case SYM_SUBNET_MASK:
9585e9d01f2Sgwr 		PARSE_IA1(subnet_mask);
9595e9d01f2Sgwr 		break;
9605e9d01f2Sgwr 
9615e9d01f2Sgwr 	case SYM_TIME_OFFSET:
9625e9d01f2Sgwr 		if (optype == OP_BOOLEAN)
9635e9d01f2Sgwr 			return E_SYNTAX_ERROR;
9645e9d01f2Sgwr 		hp->flags.time_offset = FALSE;
9655e9d01f2Sgwr 		if (optype == OP_ADDITION) {
9665e9d01f2Sgwr 			len = sizeof(tmpstr);
9675e9d01f2Sgwr 			(void) get_string(symbol, tmpstr, &len);
9685e9d01f2Sgwr 			if (!strncmp(tmpstr, "auto", 4)) {
9695e9d01f2Sgwr 				hp->time_offset = secondswest;
9705e9d01f2Sgwr 			} else {
971c8f61d2bSxtraeme 				if (sscanf(tmpstr, "%d", &ltimeoff) != 1)
9725e9d01f2Sgwr 					return E_BAD_LONGWORD;
973c8f61d2bSxtraeme 				hp->time_offset = ltimeoff;
9745e9d01f2Sgwr 			}
9755e9d01f2Sgwr 			hp->flags.time_offset = TRUE;
9765e9d01f2Sgwr 		}
9775e9d01f2Sgwr 		break;
9785e9d01f2Sgwr 
9795e9d01f2Sgwr 	case SYM_TIME_SERVER:
9805e9d01f2Sgwr 		PARSE_IAL(time_server);
9815e9d01f2Sgwr 		break;
9825e9d01f2Sgwr 
9835e9d01f2Sgwr 	case SYM_VENDOR_MAGIC:
9845e9d01f2Sgwr 		if (optype == OP_BOOLEAN)
9855e9d01f2Sgwr 			return E_SYNTAX_ERROR;
9865e9d01f2Sgwr 		hp->flags.vm_cookie = FALSE;
9875e9d01f2Sgwr 		if (optype == OP_ADDITION) {
9885e9d01f2Sgwr 			if (strncmp(*symbol, "auto", 4)) {
9895e9d01f2Sgwr 				/* The string is not "auto" */
9905e9d01f2Sgwr 				if (!strncmp(*symbol, "rfc", 3)) {
9915e9d01f2Sgwr 					bcopy(vm_rfc1048, hp->vm_cookie, 4);
9925e9d01f2Sgwr 				} else if (!strncmp(*symbol, "cmu", 3)) {
9935e9d01f2Sgwr 					bcopy(vm_cmu, hp->vm_cookie, 4);
9945e9d01f2Sgwr 				} else {
995e09553f3Sdsl 					if (!isdigit((unsigned char)**symbol))
9965e9d01f2Sgwr 						return E_BAD_IPADDR;
9975e9d01f2Sgwr 					if (prs_inetaddr(symbol, &value) < 0)
9985e9d01f2Sgwr 						return E_BAD_IPADDR;
9995e9d01f2Sgwr 					bcopy(&value, hp->vm_cookie, 4);
10005e9d01f2Sgwr 				}
10015e9d01f2Sgwr 				hp->flags.vm_cookie = TRUE;
10025e9d01f2Sgwr 			}
10035e9d01f2Sgwr 		}
10045e9d01f2Sgwr 		break;
10055e9d01f2Sgwr 
10065e9d01f2Sgwr 	case SYM_SIMILAR_ENTRY:
10075e9d01f2Sgwr 		switch (optype) {
10085e9d01f2Sgwr 		case OP_ADDITION:
10095e9d01f2Sgwr 			fill_defaults(hp, symbol);
10105e9d01f2Sgwr 			break;
10115e9d01f2Sgwr 		default:
10125e9d01f2Sgwr 			return E_SYNTAX_ERROR;
10135e9d01f2Sgwr 		}
10145e9d01f2Sgwr 		break;
10155e9d01f2Sgwr 
10165e9d01f2Sgwr 	case SYM_NAME_SWITCH:
10175e9d01f2Sgwr 		switch (optype) {
10185e9d01f2Sgwr 		case OP_ADDITION:
10195e9d01f2Sgwr 			return E_SYNTAX_ERROR;
10205e9d01f2Sgwr 		case OP_DELETION:
10215e9d01f2Sgwr 			hp->flags.send_name = FALSE;
10225e9d01f2Sgwr 			hp->flags.name_switch = FALSE;
10235e9d01f2Sgwr 			break;
10245e9d01f2Sgwr 		case OP_BOOLEAN:
10255e9d01f2Sgwr 			hp->flags.send_name = TRUE;
10265e9d01f2Sgwr 			hp->flags.name_switch = TRUE;
10275e9d01f2Sgwr 			break;
10285e9d01f2Sgwr 		}
10295e9d01f2Sgwr 		break;
10305e9d01f2Sgwr 
10315e9d01f2Sgwr 	case SYM_BOOTSIZE:
10325e9d01f2Sgwr 		switch (optype) {
10335e9d01f2Sgwr 		case OP_ADDITION:
10345e9d01f2Sgwr 			if (!strncmp(*symbol, "auto", 4)) {
10355e9d01f2Sgwr 				hp->flags.bootsize = TRUE;
10365e9d01f2Sgwr 				hp->flags.bootsize_auto = TRUE;
10375e9d01f2Sgwr 			} else {
10385e9d01f2Sgwr 				hp->bootsize = (unsigned int) get_u_long(symbol);
10395e9d01f2Sgwr 				hp->flags.bootsize = TRUE;
10405e9d01f2Sgwr 				hp->flags.bootsize_auto = FALSE;
10415e9d01f2Sgwr 			}
10425e9d01f2Sgwr 			break;
10435e9d01f2Sgwr 		case OP_DELETION:
10445e9d01f2Sgwr 			hp->flags.bootsize = FALSE;
10455e9d01f2Sgwr 			break;
10465e9d01f2Sgwr 		case OP_BOOLEAN:
10475e9d01f2Sgwr 			hp->flags.bootsize = TRUE;
10485e9d01f2Sgwr 			hp->flags.bootsize_auto = TRUE;
10495e9d01f2Sgwr 			break;
10505e9d01f2Sgwr 		}
10515e9d01f2Sgwr 		break;
10525e9d01f2Sgwr 
10535e9d01f2Sgwr 	case SYM_BOOT_SERVER:
10545e9d01f2Sgwr 		PARSE_IA1(bootserver);
10555e9d01f2Sgwr 		break;
10565e9d01f2Sgwr 
10575e9d01f2Sgwr 	case SYM_TFTPDIR:
10585e9d01f2Sgwr 		PARSE_STR(tftpdir);
10595e9d01f2Sgwr 		if ((hp->tftpdir != NULL) &&
10605e9d01f2Sgwr 			(hp->tftpdir->string[0] != '/'))
10615e9d01f2Sgwr 			return E_BAD_PATHNAME;
10625e9d01f2Sgwr 		break;
10635e9d01f2Sgwr 
10645e9d01f2Sgwr 	case SYM_DUMP_FILE:
10655e9d01f2Sgwr 		PARSE_STR(dump_file);
10665e9d01f2Sgwr 		break;
10675e9d01f2Sgwr 
10685e9d01f2Sgwr 	case SYM_DOMAIN_NAME:
10695e9d01f2Sgwr 		PARSE_STR(domain_name);
10705e9d01f2Sgwr 		break;
10715e9d01f2Sgwr 
10725e9d01f2Sgwr 	case SYM_SWAP_SERVER:
10735e9d01f2Sgwr 		PARSE_IA1(swap_server);
10745e9d01f2Sgwr 		break;
10755e9d01f2Sgwr 
10765e9d01f2Sgwr 	case SYM_ROOT_PATH:
10775e9d01f2Sgwr 		PARSE_STR(root_path);
10785e9d01f2Sgwr 		break;
10795e9d01f2Sgwr 
10805e9d01f2Sgwr 	case SYM_EXTEN_FILE:
10815e9d01f2Sgwr 		PARSE_STR(exten_file);
10825e9d01f2Sgwr 		break;
10835e9d01f2Sgwr 
10845e9d01f2Sgwr 	case SYM_REPLY_ADDR:
10855e9d01f2Sgwr 		PARSE_IA1(reply_addr);
10865e9d01f2Sgwr 		break;
10875e9d01f2Sgwr 
10885e9d01f2Sgwr 	case SYM_NIS_DOMAIN:
10895e9d01f2Sgwr 		PARSE_STR(nis_domain);
10905e9d01f2Sgwr 		break;
10915e9d01f2Sgwr 
10925e9d01f2Sgwr 	case SYM_NIS_SERVER:
10935e9d01f2Sgwr 		PARSE_IAL(nis_server);
10945e9d01f2Sgwr 		break;
10955e9d01f2Sgwr 
10965e9d01f2Sgwr 	case SYM_NTP_SERVER:
10975e9d01f2Sgwr 		PARSE_IAL(ntp_server);
10985e9d01f2Sgwr 		break;
10995e9d01f2Sgwr 
11005e9d01f2Sgwr #ifdef	YORK_EX_OPTION
11015e9d01f2Sgwr 	case SYM_EXEC_FILE:
11025e9d01f2Sgwr 		PARSE_STR(exec_file);
11035e9d01f2Sgwr 		break;
11045e9d01f2Sgwr #endif
11055e9d01f2Sgwr 
1106bcb13babSgwr 	case SYM_MSG_SIZE:
1107bcb13babSgwr 		PARSE_INT(msg_size);
1108bcb13babSgwr 		if (hp->msg_size < BP_MINPKTSZ ||
1109bcb13babSgwr 			hp->msg_size > MAX_MSG_SIZE)
1110bcb13babSgwr 			return E_BAD_VALUE;
1111bcb13babSgwr 		break;
1112bcb13babSgwr 
1113bcb13babSgwr 	case SYM_MIN_WAIT:
1114bcb13babSgwr 		PARSE_INT(min_wait);
1115c8f61d2bSxtraeme 		if (hp->min_wait == 0)
1116bcb13babSgwr 			return E_BAD_VALUE;
1117bcb13babSgwr 		break;
1118bcb13babSgwr 
11195e9d01f2Sgwr 		/* XXX - Add new tags here */
11205e9d01f2Sgwr 
11215e9d01f2Sgwr 	default:
11225e9d01f2Sgwr 		return E_UNKNOWN_SYMBOL;
11235e9d01f2Sgwr 
11245e9d01f2Sgwr 	}							/* switch symbolcode */
11255e9d01f2Sgwr 
11265e9d01f2Sgwr 	return SUCCESS;
11275e9d01f2Sgwr }
11285e9d01f2Sgwr #undef	PARSE_IA1
11295e9d01f2Sgwr #undef	PARSE_IAL
11305e9d01f2Sgwr #undef	PARSE_STR
11315e9d01f2Sgwr 
11325e9d01f2Sgwr 
11335e9d01f2Sgwr 
11345e9d01f2Sgwr 
11355e9d01f2Sgwr /*
11365e9d01f2Sgwr  * Read a string from the buffer indirectly pointed to through "src" and
11375e9d01f2Sgwr  * move it into the buffer pointed to by "dest".  A pointer to the maximum
11385e9d01f2Sgwr  * allowable length of the string (including null-terminator) is passed as
11395e9d01f2Sgwr  * "length".  The actual length of the string which was read is returned in
11405e9d01f2Sgwr  * the unsigned integer pointed to by "length".  This value is the same as
11415e9d01f2Sgwr  * that which would be returned by applying the strlen() function on the
11425e9d01f2Sgwr  * destination string (i.e the terminating null is not counted as a
11435e9d01f2Sgwr  * character).  Trailing whitespace is removed from the string.  For
11445e9d01f2Sgwr  * convenience, the function returns the new value of "dest".
11455e9d01f2Sgwr  *
11465e9d01f2Sgwr  * The string is read until the maximum number of characters, an unquoted
11475e9d01f2Sgwr  * colon (:), or a null character is read.  The return string in "dest" is
11485e9d01f2Sgwr  * null-terminated.
11495e9d01f2Sgwr  */
11505e9d01f2Sgwr 
11515e9d01f2Sgwr PRIVATE char *
get_string(char ** src,char * dest,unsigned int * length)1152131109e4Swiz get_string(char **src, char *dest, unsigned int *length)
11535e9d01f2Sgwr {
11545e9d01f2Sgwr 	int n, len, quoteflag;
11555e9d01f2Sgwr 
11565e9d01f2Sgwr 	quoteflag = FALSE;
11575e9d01f2Sgwr 	n = 0;
11585e9d01f2Sgwr 	len = *length - 1;
11595e9d01f2Sgwr 	while ((n < len) && (**src)) {
11605e9d01f2Sgwr 		if (!quoteflag && (**src == ':')) {
11615e9d01f2Sgwr 			break;
11625e9d01f2Sgwr 		}
11635e9d01f2Sgwr 		if (**src == '"') {
11645e9d01f2Sgwr 			(*src)++;
11655e9d01f2Sgwr 			quoteflag = !quoteflag;
11665e9d01f2Sgwr 			continue;
11675e9d01f2Sgwr 		}
11685e9d01f2Sgwr 		if (**src == '\\') {
11695e9d01f2Sgwr 			(*src)++;
11705e9d01f2Sgwr 			if (!**src) {
11715e9d01f2Sgwr 				break;
11725e9d01f2Sgwr 			}
11735e9d01f2Sgwr 		}
11745e9d01f2Sgwr 		*dest++ = *(*src)++;
11755e9d01f2Sgwr 		n++;
11765e9d01f2Sgwr 	}
11775e9d01f2Sgwr 
11785e9d01f2Sgwr 	/*
11795e9d01f2Sgwr 	 * Remove that troublesome trailing whitespace. . .
11805e9d01f2Sgwr 	 */
1181e09553f3Sdsl 	while ((n > 0) && isspace((unsigned char)dest[-1])) {
11825e9d01f2Sgwr 		dest--;
11835e9d01f2Sgwr 		n--;
11845e9d01f2Sgwr 	}
11855e9d01f2Sgwr 
11865e9d01f2Sgwr 	*dest = '\0';
11875e9d01f2Sgwr 	*length = n;
11885e9d01f2Sgwr 	return dest;
11895e9d01f2Sgwr }
11905e9d01f2Sgwr 
11915e9d01f2Sgwr 
11925e9d01f2Sgwr 
11935e9d01f2Sgwr /*
11945e9d01f2Sgwr  * Read the string indirectly pointed to by "src", update the caller's
11955e9d01f2Sgwr  * pointer, and return a pointer to a malloc'ed shared_string structure
11965e9d01f2Sgwr  * containing the string.
11975e9d01f2Sgwr  *
11985e9d01f2Sgwr  * The string is read using the same rules as get_string() above.
11995e9d01f2Sgwr  */
12005e9d01f2Sgwr 
12015e9d01f2Sgwr PRIVATE struct shared_string *
get_shared_string(char ** src)1202131109e4Swiz get_shared_string(char **src)
12035e9d01f2Sgwr {
12045e9d01f2Sgwr 	char retstring[MAXSTRINGLEN];
12055e9d01f2Sgwr 	struct shared_string *s;
12065e9d01f2Sgwr 	unsigned length;
12075e9d01f2Sgwr 
12085e9d01f2Sgwr 	length = sizeof(retstring);
12095e9d01f2Sgwr 	(void) get_string(src, retstring, &length);
12105e9d01f2Sgwr 
12115402d14cSitojun 	s = (struct shared_string *) smalloc(sizeof(struct shared_string) +
121232ffffe1Sjoerg 	    length + 1);
12135e9d01f2Sgwr 	s->linkcount = 1;
121432ffffe1Sjoerg 	memcpy(s->string, retstring, length + 1);
12155e9d01f2Sgwr 
12165e9d01f2Sgwr 	return s;
12175e9d01f2Sgwr }
12185e9d01f2Sgwr 
12195e9d01f2Sgwr 
12205e9d01f2Sgwr 
12215e9d01f2Sgwr /*
12225e9d01f2Sgwr  * Load RFC1048 generic information directly into a memory buffer.
12235e9d01f2Sgwr  *
12245e9d01f2Sgwr  * "src" indirectly points to the ASCII representation of the generic data.
12255e9d01f2Sgwr  * "dest" points to a string structure which is updated to point to a new
12265e9d01f2Sgwr  * string with the new data appended to the old string.  The old string is
12275e9d01f2Sgwr  * freed.
12285e9d01f2Sgwr  *
12295e9d01f2Sgwr  * The given tag value is inserted with the new data.
12305e9d01f2Sgwr  *
12315e9d01f2Sgwr  * The data may be represented as either a stream of hexadecimal numbers
12325e9d01f2Sgwr  * representing bytes (any or all bytes may optionally start with '0x' and
12335e9d01f2Sgwr  * be separated with periods ".") or as a quoted string of ASCII
12345e9d01f2Sgwr  * characters (the quotes are required).
12355e9d01f2Sgwr  */
12365e9d01f2Sgwr 
12375e9d01f2Sgwr PRIVATE int
process_generic(char ** src,struct shared_bindata ** dest,u_int tagvalue)1238131109e4Swiz process_generic(char **src, struct shared_bindata **dest, u_int tagvalue)
12395e9d01f2Sgwr {
12405e9d01f2Sgwr 	byte tmpbuf[MAXBUFLEN];
12415e9d01f2Sgwr 	byte *str;
12425e9d01f2Sgwr 	struct shared_bindata *bdata;
12435e9d01f2Sgwr 	u_int newlength, oldlength;
12445e9d01f2Sgwr 
12455e9d01f2Sgwr 	str = tmpbuf;
12465e9d01f2Sgwr 	*str++ = (tagvalue & 0xFF);	/* Store tag value */
12475e9d01f2Sgwr 	str++;						/* Skip over length field */
12485e9d01f2Sgwr 	if ((*src)[0] == '"') {		/* ASCII data */
12495e9d01f2Sgwr 		newlength = sizeof(tmpbuf) - 2;	/* Set maximum allowed length */
12505e9d01f2Sgwr 		(void) get_string(src, (char *) str, &newlength);
12512a645560Sgwr 		/* Do NOT include the terminating null. */
12525e9d01f2Sgwr 	} else {					/* Numeric data */
12535e9d01f2Sgwr 		newlength = 0;
12545e9d01f2Sgwr 		while (newlength < sizeof(tmpbuf) - 2) {
12555e9d01f2Sgwr 			if (interp_byte(src, str++) < 0)
12565e9d01f2Sgwr 				break;
12575e9d01f2Sgwr 			newlength++;
12585e9d01f2Sgwr 			if (**src == '.') {
12595e9d01f2Sgwr 				(*src)++;
12605e9d01f2Sgwr 			}
12615e9d01f2Sgwr 		}
12625e9d01f2Sgwr 	}
12635e9d01f2Sgwr 	if ((*src)[0] != ':')
12645e9d01f2Sgwr 		return -1;
12655e9d01f2Sgwr 
12665e9d01f2Sgwr 	tmpbuf[1] = (newlength & 0xFF);
12675e9d01f2Sgwr 	oldlength = ((*dest)->length);
12685e9d01f2Sgwr 	bdata = (struct shared_bindata *) smalloc(sizeof(struct shared_bindata)
12695e9d01f2Sgwr 											+ oldlength + newlength + 1);
12705e9d01f2Sgwr 	if (oldlength > 0) {
12715e9d01f2Sgwr 		bcopy((*dest)->data, bdata->data, oldlength);
12725e9d01f2Sgwr 	}
12735e9d01f2Sgwr 	bcopy(tmpbuf, bdata->data + oldlength, newlength + 2);
12745e9d01f2Sgwr 	bdata->length = oldlength + newlength + 2;
12755e9d01f2Sgwr 	bdata->linkcount = 1;
12765e9d01f2Sgwr 	del_bindata(*dest);
12775e9d01f2Sgwr 	*dest = bdata;
12785e9d01f2Sgwr 	return 0;
12795e9d01f2Sgwr }
12805e9d01f2Sgwr 
12815e9d01f2Sgwr 
12825e9d01f2Sgwr 
12835e9d01f2Sgwr /*
12845e9d01f2Sgwr  * Verify that the given string makes sense as a hostname (according to
12855e9d01f2Sgwr  * Appendix 1, page 29 of RFC882).
12865e9d01f2Sgwr  *
12875e9d01f2Sgwr  * Return TRUE for good names, FALSE otherwise.
12885e9d01f2Sgwr  */
12895e9d01f2Sgwr 
12905e9d01f2Sgwr PRIVATE boolean
goodname(char * hostname)1291aae9c2a0Swiz goodname(char *hostname)
12925e9d01f2Sgwr {
12935e9d01f2Sgwr 	do {
1294e09553f3Sdsl 		if (!isalpha((unsigned char)*hostname++)) {	/* First character must be a letter */
12955e9d01f2Sgwr 			return FALSE;
12965e9d01f2Sgwr 		}
1297e09553f3Sdsl 		while (isalnum((unsigned char)*hostname) ||
12985e9d01f2Sgwr 			   (*hostname == '-') ||
12995e9d01f2Sgwr 			   (*hostname == '_') )
13005e9d01f2Sgwr 		{
13015e9d01f2Sgwr 			hostname++;			/* Alphanumeric or a hyphen */
13025e9d01f2Sgwr 		}
1303e09553f3Sdsl 		if (!isalnum((unsigned char)hostname[-1])) {	/* Last must be alphanumeric */
13045e9d01f2Sgwr 			return FALSE;
13055e9d01f2Sgwr 		}
13065e9d01f2Sgwr 		if (*hostname == '\0') {/* Done? */
13075e9d01f2Sgwr 			return TRUE;
13085e9d01f2Sgwr 		}
13095e9d01f2Sgwr 	} while (*hostname++ == '.');	/* Dot, loop for next label */
13105e9d01f2Sgwr 
13115e9d01f2Sgwr 	return FALSE;				/* If it's not a dot, lose */
13125e9d01f2Sgwr }
13135e9d01f2Sgwr 
13145e9d01f2Sgwr 
13155e9d01f2Sgwr 
13165e9d01f2Sgwr /*
13175e9d01f2Sgwr  * Null compare function -- always returns FALSE so an element is always
13185e9d01f2Sgwr  * inserted into a hash table (i.e. there is never a collision with an
13195e9d01f2Sgwr  * existing element).
13205e9d01f2Sgwr  */
13215e9d01f2Sgwr 
13225e9d01f2Sgwr PRIVATE boolean
nullcmp(hash_datum * d1,hash_datum * d2)1323131109e4Swiz nullcmp(hash_datum *d1, hash_datum *d2)
13245e9d01f2Sgwr {
13255e9d01f2Sgwr 	return FALSE;
13265e9d01f2Sgwr }
13275e9d01f2Sgwr 
13285e9d01f2Sgwr 
13295e9d01f2Sgwr /*
13305e9d01f2Sgwr  * Function for comparing a string with the hostname field of a host
13315e9d01f2Sgwr  * structure.
13325e9d01f2Sgwr  */
13335e9d01f2Sgwr 
13345e9d01f2Sgwr boolean
nmcmp(hash_datum * d1,hash_datum * d2)1335131109e4Swiz nmcmp(hash_datum *d1, hash_datum *d2)
13365e9d01f2Sgwr {
13375e9d01f2Sgwr 	char *name = (char *) d1;	/* XXX - OK? */
13385e9d01f2Sgwr 	struct host *hp = (struct host *) d2;
13395e9d01f2Sgwr 
13405e9d01f2Sgwr 	return !strcmp(name, hp->hostname->string);
13415e9d01f2Sgwr }
13425e9d01f2Sgwr 
13435e9d01f2Sgwr 
13445e9d01f2Sgwr /*
13455e9d01f2Sgwr  * Compare function to determine whether two hardware addresses are
13465e9d01f2Sgwr  * equivalent.  Returns TRUE if "host1" and "host2" are equivalent, FALSE
13475e9d01f2Sgwr  * otherwise.
13485e9d01f2Sgwr  *
13495e9d01f2Sgwr  * If the hardware addresses of "host1" and "host2" are identical, but
13505e9d01f2Sgwr  * they are on different IP subnets, this function returns FALSE.
13515e9d01f2Sgwr  *
13525e9d01f2Sgwr  * This function is used when inserting elements into the hardware address
13535e9d01f2Sgwr  * hash table.
13545e9d01f2Sgwr  */
13555e9d01f2Sgwr 
13565e9d01f2Sgwr PRIVATE boolean
hwinscmp(hash_datum * d1,hash_datum * d2)1357131109e4Swiz hwinscmp(hash_datum *d1, hash_datum *d2)
13585e9d01f2Sgwr {
13595e9d01f2Sgwr 	struct host *host1 = (struct host *) d1;
13605e9d01f2Sgwr 	struct host *host2 = (struct host *) d2;
13615e9d01f2Sgwr 
13625e9d01f2Sgwr 	if (host1->htype != host2->htype) {
13635e9d01f2Sgwr 		return FALSE;
13645e9d01f2Sgwr 	}
13655e9d01f2Sgwr 	if (bcmp(host1->haddr, host2->haddr, haddrlength(host1->htype))) {
13665e9d01f2Sgwr 		return FALSE;
13675e9d01f2Sgwr 	}
13685e9d01f2Sgwr 	/* XXX - Is the subnet_mask field set yet? */
13695e9d01f2Sgwr 	if ((host1->subnet_mask.s_addr) == (host2->subnet_mask.s_addr)) {
13705e9d01f2Sgwr 		if (((host1->iaddr.s_addr) & (host1->subnet_mask.s_addr)) !=
13715e9d01f2Sgwr 			((host2->iaddr.s_addr) & (host2->subnet_mask.s_addr)))
13725e9d01f2Sgwr 		{
13735e9d01f2Sgwr 			return FALSE;
13745e9d01f2Sgwr 		}
13755e9d01f2Sgwr 	}
13765e9d01f2Sgwr 	return TRUE;
13775e9d01f2Sgwr }
13785e9d01f2Sgwr 
13795e9d01f2Sgwr 
13805e9d01f2Sgwr /*
13815e9d01f2Sgwr  * Macros for use in the function below:
13825e9d01f2Sgwr  */
13835e9d01f2Sgwr 
13845e9d01f2Sgwr #define DUP_COPY(MEMBER) do \
13855e9d01f2Sgwr { \
13865e9d01f2Sgwr 	if (!hp->flags.MEMBER) { \
13875e9d01f2Sgwr 		if ((hp->flags.MEMBER = hp2->flags.MEMBER) != 0) { \
13885e9d01f2Sgwr 			hp->MEMBER = hp2->MEMBER; \
13895e9d01f2Sgwr 		} \
13905e9d01f2Sgwr 	} \
13915e9d01f2Sgwr } while (0)
13925e9d01f2Sgwr 
13935e9d01f2Sgwr #define DUP_LINK(MEMBER) do \
13945e9d01f2Sgwr { \
13955e9d01f2Sgwr 	if (!hp->flags.MEMBER) { \
13965e9d01f2Sgwr 		if ((hp->flags.MEMBER = hp2->flags.MEMBER) != 0) { \
13975e9d01f2Sgwr 			assert(hp2->MEMBER); \
13985e9d01f2Sgwr 			hp->MEMBER = hp2->MEMBER; \
13995e9d01f2Sgwr 			(hp->MEMBER->linkcount)++; \
14005e9d01f2Sgwr 		} \
14015e9d01f2Sgwr 	} \
14025e9d01f2Sgwr } while (0)
14035e9d01f2Sgwr 
14045e9d01f2Sgwr /*
14055e9d01f2Sgwr  * Process the "similar entry" symbol.
14065e9d01f2Sgwr  *
14075e9d01f2Sgwr  * The host specified as the value of the "tc" symbol is used as a template
14085e9d01f2Sgwr  * for the current host entry.  Symbol values not explicitly set in the
14095e9d01f2Sgwr  * current host entry are inferred from the template entry.
14105e9d01f2Sgwr  */
14115e9d01f2Sgwr PRIVATE void
fill_defaults(struct host * hp,char ** src)1412131109e4Swiz fill_defaults(struct host *hp, char **src)
14135e9d01f2Sgwr {
14145e9d01f2Sgwr 	unsigned int tlen, hashcode;
14155e9d01f2Sgwr 	struct host *hp2;
14165e9d01f2Sgwr 	char tstring[MAXSTRINGLEN];
14175e9d01f2Sgwr 
14185e9d01f2Sgwr 	tlen = sizeof(tstring);
14195e9d01f2Sgwr 	(void) get_string(src, tstring, &tlen);
14205e9d01f2Sgwr 	hashcode = hash_HashFunction((u_char *) tstring, tlen);
14215e9d01f2Sgwr 	hp2 = (struct host *) hash_Lookup(nmhashtable, hashcode, nmcmp, tstring);
14225e9d01f2Sgwr 
14235e9d01f2Sgwr 	if (hp2 == NULL) {
14245e9d01f2Sgwr 		report(LOG_ERR, "can't find tc=\"%s\"", tstring);
14255e9d01f2Sgwr 		return;
14265e9d01f2Sgwr 	}
14275e9d01f2Sgwr 	DUP_LINK(bootfile);
14285e9d01f2Sgwr 	DUP_LINK(cookie_server);
14295e9d01f2Sgwr 	DUP_LINK(domain_server);
14305e9d01f2Sgwr 	DUP_LINK(gateway);
14315e9d01f2Sgwr 	/* haddr not copied */
14325e9d01f2Sgwr 	DUP_LINK(homedir);
14335e9d01f2Sgwr 	DUP_COPY(htype);
14345e9d01f2Sgwr 
14355e9d01f2Sgwr 	DUP_LINK(impress_server);
14365e9d01f2Sgwr 	/* iaddr not copied */
14375e9d01f2Sgwr 	DUP_LINK(log_server);
14385e9d01f2Sgwr 	DUP_LINK(lpr_server);
14395e9d01f2Sgwr 	DUP_LINK(name_server);
14405e9d01f2Sgwr 	DUP_LINK(rlp_server);
14415e9d01f2Sgwr 
14425e9d01f2Sgwr 	DUP_COPY(subnet_mask);
14435e9d01f2Sgwr 	DUP_COPY(time_offset);
14445e9d01f2Sgwr 	DUP_LINK(time_server);
14455e9d01f2Sgwr 
14465e9d01f2Sgwr 	if (!hp->flags.vm_cookie) {
14475e9d01f2Sgwr 		if ((hp->flags.vm_cookie = hp2->flags.vm_cookie)) {
14485e9d01f2Sgwr 			bcopy(hp2->vm_cookie, hp->vm_cookie, 4);
14495e9d01f2Sgwr 		}
14505e9d01f2Sgwr 	}
14515e9d01f2Sgwr 	if (!hp->flags.name_switch) {
14525e9d01f2Sgwr 		if ((hp->flags.name_switch = hp2->flags.name_switch)) {
14535e9d01f2Sgwr 			hp->flags.send_name = hp2->flags.send_name;
14545e9d01f2Sgwr 		}
14555e9d01f2Sgwr 	}
14565e9d01f2Sgwr 	if (!hp->flags.bootsize) {
14575e9d01f2Sgwr 		if ((hp->flags.bootsize = hp2->flags.bootsize)) {
14585e9d01f2Sgwr 			hp->flags.bootsize_auto = hp2->flags.bootsize_auto;
14595e9d01f2Sgwr 			hp->bootsize = hp2->bootsize;
14605e9d01f2Sgwr 		}
14615e9d01f2Sgwr 	}
14625e9d01f2Sgwr 	DUP_COPY(bootserver);
14635e9d01f2Sgwr 
14645e9d01f2Sgwr 	DUP_LINK(tftpdir);
14655e9d01f2Sgwr 	DUP_LINK(dump_file);
14665e9d01f2Sgwr 	DUP_LINK(domain_name);
14675e9d01f2Sgwr 
14685e9d01f2Sgwr 	DUP_COPY(swap_server);
14695e9d01f2Sgwr 	DUP_LINK(root_path);
14705e9d01f2Sgwr 	DUP_LINK(exten_file);
14715e9d01f2Sgwr 
14725e9d01f2Sgwr 	DUP_COPY(reply_addr);
14735e9d01f2Sgwr 
14745e9d01f2Sgwr 	DUP_LINK(nis_domain);
14755e9d01f2Sgwr 	DUP_LINK(nis_server);
14765e9d01f2Sgwr 	DUP_LINK(ntp_server);
14775e9d01f2Sgwr 
14785e9d01f2Sgwr #ifdef	YORK_EX_OPTION
14795e9d01f2Sgwr 	DUP_LINK(exec_file);
14805e9d01f2Sgwr #endif
14815e9d01f2Sgwr 
1482bcb13babSgwr 	DUP_COPY(msg_size);
1483bcb13babSgwr 	DUP_COPY(min_wait);
1484bcb13babSgwr 
14855e9d01f2Sgwr 	/* XXX - Add new tags here */
14865e9d01f2Sgwr 
14875e9d01f2Sgwr 	DUP_LINK(generic);
14885e9d01f2Sgwr 
14895e9d01f2Sgwr }
14905e9d01f2Sgwr #undef	DUP_COPY
14915e9d01f2Sgwr #undef	DUP_LINK
14925e9d01f2Sgwr 
14935e9d01f2Sgwr 
14945e9d01f2Sgwr 
14955e9d01f2Sgwr /*
14965e9d01f2Sgwr  * This function adjusts the caller's pointer to point just past the
14975e9d01f2Sgwr  * first-encountered colon.  If it runs into a null character, it leaves
14985e9d01f2Sgwr  * the pointer pointing to it.
14995e9d01f2Sgwr  */
15005e9d01f2Sgwr 
15015e9d01f2Sgwr PRIVATE void
adjust(char ** s)1502131109e4Swiz adjust(char **s)
15035e9d01f2Sgwr {
1504aae9c2a0Swiz 	char *t;
15055e9d01f2Sgwr 
15065e9d01f2Sgwr 	t = *s;
15075e9d01f2Sgwr 	while (*t && (*t != ':')) {
15085e9d01f2Sgwr 		t++;
15095e9d01f2Sgwr 	}
15105e9d01f2Sgwr 	if (*t) {
15115e9d01f2Sgwr 		t++;
15125e9d01f2Sgwr 	}
15135e9d01f2Sgwr 	*s = t;
15145e9d01f2Sgwr }
15155e9d01f2Sgwr 
15165e9d01f2Sgwr 
15175e9d01f2Sgwr 
15185e9d01f2Sgwr 
15195e9d01f2Sgwr /*
15205e9d01f2Sgwr  * This function adjusts the caller's pointer to point to the first
15215e9d01f2Sgwr  * non-whitespace character.  If it runs into a null character, it leaves
15225e9d01f2Sgwr  * the pointer pointing to it.
15235e9d01f2Sgwr  */
15245e9d01f2Sgwr 
15255e9d01f2Sgwr PRIVATE void
eat_whitespace(char ** s)1526131109e4Swiz eat_whitespace(char **s)
15275e9d01f2Sgwr {
1528aae9c2a0Swiz 	char *t;
15295e9d01f2Sgwr 
15305e9d01f2Sgwr 	t = *s;
1531e09553f3Sdsl 	while (*t && isspace((unsigned char)*t)) {
15325e9d01f2Sgwr 		t++;
15335e9d01f2Sgwr 	}
15345e9d01f2Sgwr 	*s = t;
15355e9d01f2Sgwr }
15365e9d01f2Sgwr 
15375e9d01f2Sgwr 
15385e9d01f2Sgwr 
15395e9d01f2Sgwr /*
15405e9d01f2Sgwr  * This function converts the given string to all lowercase.
15415e9d01f2Sgwr  */
15425e9d01f2Sgwr 
15435e9d01f2Sgwr PRIVATE void
makelower(char * s)1544131109e4Swiz makelower(char *s)
15455e9d01f2Sgwr {
15465e9d01f2Sgwr 	while (*s) {
1547e09553f3Sdsl 		if (isupper((unsigned char)*s)) {
1548e09553f3Sdsl 			*s = tolower((unsigned char)*s);
15495e9d01f2Sgwr 		}
15505e9d01f2Sgwr 		s++;
15515e9d01f2Sgwr 	}
15525e9d01f2Sgwr }
15535e9d01f2Sgwr 
15545e9d01f2Sgwr 
15555e9d01f2Sgwr 
15565e9d01f2Sgwr /*
15575e9d01f2Sgwr  *
15585e9d01f2Sgwr  *	N O T E :
15595e9d01f2Sgwr  *
15605e9d01f2Sgwr  *	In many of the functions which follow, a parameter such as "src" or
15615e9d01f2Sgwr  *	"symbol" is passed as a pointer to a pointer to something.  This is
15625e9d01f2Sgwr  *	done for the purpose of letting the called function update the
15635e9d01f2Sgwr  *	caller's copy of the parameter (i.e. to effect call-by-reference
15645e9d01f2Sgwr  *	parameter passing).  The value of the actual parameter is only used
15655e9d01f2Sgwr  *	to locate the real parameter of interest and then update this indirect
15665e9d01f2Sgwr  *	parameter.
15675e9d01f2Sgwr  *
15685e9d01f2Sgwr  *	I'm sure somebody out there won't like this. . . .
15695e9d01f2Sgwr  *  (Yea, because it usually makes code slower... -gwr)
15705e9d01f2Sgwr  *
15715e9d01f2Sgwr  */
15725e9d01f2Sgwr 
15735e9d01f2Sgwr 
15745e9d01f2Sgwr 
15755e9d01f2Sgwr /*
15765e9d01f2Sgwr  * "src" points to a character pointer which points to an ASCII string of
15775e9d01f2Sgwr  * whitespace-separated IP addresses.  A pointer to an in_addr_list
15785e9d01f2Sgwr  * structure containing the list of addresses is returned.  NULL is
15795e9d01f2Sgwr  * returned if no addresses were found at all.  The pointer pointed to by
15805e9d01f2Sgwr  * "src" is updated to point to the first non-address (illegal) character.
15815e9d01f2Sgwr  */
15825e9d01f2Sgwr 
15835e9d01f2Sgwr PRIVATE struct in_addr_list *
get_addresses(char ** src)1584131109e4Swiz get_addresses(char **src)
15855e9d01f2Sgwr {
15868ef27f1eSjoerg 	__aligned(4) struct in_addr tmpaddrlist[MAXINADDRS];
15875e9d01f2Sgwr 	struct in_addr_list *result;
15888ef27f1eSjoerg 	unsigned addrcount, totalsize, address;
15895e9d01f2Sgwr 
15908ef27f1eSjoerg 	for (address = 0, addrcount = 0; addrcount < MAXINADDRS; addrcount++) {
1591e09553f3Sdsl 		while (isspace((unsigned char)**src) || (**src == ',')) {
15925e9d01f2Sgwr 			(*src)++;
15935e9d01f2Sgwr 		}
15945e9d01f2Sgwr 		if (!**src) {			/* Quit if nothing more */
15955e9d01f2Sgwr 			break;
15965e9d01f2Sgwr 		}
15978ef27f1eSjoerg 		if (prs_inetaddr(src, &tmpaddrlist[address].s_addr) < 0) {
15985e9d01f2Sgwr 			break;
15995e9d01f2Sgwr 		}
16008ef27f1eSjoerg 		address++;				/* Point to next address slot */
16015e9d01f2Sgwr 	}
16025e9d01f2Sgwr 	if (addrcount < 1) {
16035e9d01f2Sgwr 		result = NULL;
16045e9d01f2Sgwr 	} else {
16055e9d01f2Sgwr 		totalsize = sizeof(struct in_addr_list)
16065e9d01f2Sgwr 		+			(addrcount - 1) * sizeof(struct in_addr);
16075e9d01f2Sgwr 		result = (struct in_addr_list *) smalloc(totalsize);
16085e9d01f2Sgwr 		result->linkcount = 1;
16095e9d01f2Sgwr 		result->addrcount = addrcount;
16108ef27f1eSjoerg 		for (address = 0; address < addrcount; ++address)
16118ef27f1eSjoerg 			result->addr[address] = tmpaddrlist[address];
16125e9d01f2Sgwr 	}
16135e9d01f2Sgwr 	return result;
16145e9d01f2Sgwr }
16155e9d01f2Sgwr 
16165e9d01f2Sgwr 
16175e9d01f2Sgwr 
16185e9d01f2Sgwr /*
16195e9d01f2Sgwr  * prs_inetaddr(src, result)
16205e9d01f2Sgwr  *
16215e9d01f2Sgwr  * "src" is a value-result parameter; the pointer it points to is updated
16225e9d01f2Sgwr  * to point to the next data position.   "result" points to an unsigned long
16235e9d01f2Sgwr  * in which an address is returned.
16245e9d01f2Sgwr  *
16255e9d01f2Sgwr  * This function parses the IP address string in ASCII "dot notation" pointed
16265e9d01f2Sgwr  * to by (*src) and places the result (in network byte order) in the unsigned
16275e9d01f2Sgwr  * long pointed to by "result".  For malformed addresses, -1 is returned,
16285e9d01f2Sgwr  * (*src) points to the first illegal character, and the unsigned long pointed
16295e9d01f2Sgwr  * to by "result" is unchanged.  Successful calls return 0.
16305e9d01f2Sgwr  */
16315e9d01f2Sgwr 
16325e9d01f2Sgwr PRIVATE int
prs_inetaddr(char ** src,u_int32 * result)1633131109e4Swiz prs_inetaddr(char **src, u_int32 *result)
16345e9d01f2Sgwr {
16355e9d01f2Sgwr 	char tmpstr[MAXSTRINGLEN];
1636aae9c2a0Swiz 	u_int32 value;
16375e9d01f2Sgwr 	u_int32 parts[4], *pp;
16385e9d01f2Sgwr 	int n;
16395e9d01f2Sgwr 	char *s, *t;
16405e9d01f2Sgwr 
16415e9d01f2Sgwr #if 1	/* XXX - experimental */
16425e9d01f2Sgwr 	/* Leading alpha char causes IP addr lookup. */
1643e09553f3Sdsl 	if (isalpha((unsigned char)**src)) {
16445e9d01f2Sgwr 		/* Lookup IP address. */
16455e9d01f2Sgwr 		s = *src;
16465e9d01f2Sgwr 		t = tmpstr;
1647e09553f3Sdsl 		while ((isalnum((unsigned char)*s) || (*s == '.') ||
16485e9d01f2Sgwr 				(*s == '-') || (*s == '_') ) &&
16495e9d01f2Sgwr 			   (t < &tmpstr[MAXSTRINGLEN - 1]) )
16505e9d01f2Sgwr 			*t++ = *s++;
16515e9d01f2Sgwr 		*t = '\0';
16525e9d01f2Sgwr 		*src = s;
16535e9d01f2Sgwr 
16545e9d01f2Sgwr 		n = lookup_ipa(tmpstr, result);
16555e9d01f2Sgwr 		if (n < 0)
16565e9d01f2Sgwr 			report(LOG_ERR, "can not get IP addr for %s", tmpstr);
16575e9d01f2Sgwr 		return n;
16585e9d01f2Sgwr 	}
16595e9d01f2Sgwr #endif
16605e9d01f2Sgwr 
16615e9d01f2Sgwr 	/*
16625e9d01f2Sgwr 	 * Parse an address in Internet format:
16635e9d01f2Sgwr 	 *	a.b.c.d
16645e9d01f2Sgwr 	 *	a.b.c	(with c treated as 16-bits)
16655e9d01f2Sgwr 	 *	a.b	(with b treated as 24 bits)
16665e9d01f2Sgwr 	 */
16675e9d01f2Sgwr 	pp = parts;
16685e9d01f2Sgwr   loop:
16695e9d01f2Sgwr 	/* If it's not a digit, return error. */
1670e09553f3Sdsl 	if (!isdigit((unsigned char)**src))
16715e9d01f2Sgwr 		return -1;
16725e9d01f2Sgwr 	*pp++ = get_u_long(src);
16735e9d01f2Sgwr 	if (**src == '.') {
16745e9d01f2Sgwr 		if (pp < (parts + 4)) {
16755e9d01f2Sgwr 			(*src)++;
16765e9d01f2Sgwr 			goto loop;
16775e9d01f2Sgwr 		}
16785e9d01f2Sgwr 		return (-1);
16795e9d01f2Sgwr 	}
16805e9d01f2Sgwr #if 0
16815e9d01f2Sgwr 	/* This is handled by the caller. */
1682e09553f3Sdsl 	if (**src && !((unsigned char)isspace(**src) || (**src == ':'))) {
16835e9d01f2Sgwr 		return (-1);
16845e9d01f2Sgwr 	}
16855e9d01f2Sgwr #endif
16865e9d01f2Sgwr 
16875e9d01f2Sgwr 	/*
16885e9d01f2Sgwr 	 * Construct the address according to
16895e9d01f2Sgwr 	 * the number of parts specified.
16905e9d01f2Sgwr 	 */
16915e9d01f2Sgwr 	n = pp - parts;
16925e9d01f2Sgwr 	switch (n) {
16935e9d01f2Sgwr 	case 1:					/* a -- 32 bits */
16945e9d01f2Sgwr 		value = parts[0];
16955e9d01f2Sgwr 		break;
16965e9d01f2Sgwr 	case 2:					/* a.b -- 8.24 bits */
16975e9d01f2Sgwr 		value = (parts[0] << 24) | (parts[1] & 0xFFFFFF);
16985e9d01f2Sgwr 		break;
16995e9d01f2Sgwr 	case 3:					/* a.b.c -- 8.8.16 bits */
17005e9d01f2Sgwr 		value = (parts[0] << 24) | ((parts[1] & 0xFF) << 16) |
17015e9d01f2Sgwr 			(parts[2] & 0xFFFF);
17025e9d01f2Sgwr 		break;
17035e9d01f2Sgwr 	case 4:					/* a.b.c.d -- 8.8.8.8 bits */
17045e9d01f2Sgwr 		value = (parts[0] << 24) | ((parts[1] & 0xFF) << 16) |
17055e9d01f2Sgwr 			((parts[2] & 0xFF) << 8) | (parts[3] & 0xFF);
17065e9d01f2Sgwr 		break;
17075e9d01f2Sgwr 	default:
17085e9d01f2Sgwr 		return (-1);
17095e9d01f2Sgwr 	}
17105e9d01f2Sgwr 	*result = htonl(value);
17115e9d01f2Sgwr 	return (0);
17125e9d01f2Sgwr }
17135e9d01f2Sgwr 
17145e9d01f2Sgwr 
17155e9d01f2Sgwr 
17165e9d01f2Sgwr /*
17175e9d01f2Sgwr  * "src" points to a pointer which in turn points to a hexadecimal ASCII
17185e9d01f2Sgwr  * string.  This string is interpreted as a hardware address and returned
17195e9d01f2Sgwr  * as a pointer to the actual hardware address, represented as an array of
17205e9d01f2Sgwr  * bytes.
17215e9d01f2Sgwr  *
17225e9d01f2Sgwr  * The ASCII string must have the proper number of digits for the specified
17235e9d01f2Sgwr  * hardware type (e.g. twelve digits for a 48-bit Ethernet address).
17245e9d01f2Sgwr  * Two-digit sequences (bytes) may be separated with periods (.)  and/or
17255e9d01f2Sgwr  * prefixed with '0x' for readability, but this is not required.
17265e9d01f2Sgwr  *
17275e9d01f2Sgwr  * For bad addresses, the pointer which "src" points to is updated to point
17285e9d01f2Sgwr  * to the start of the first two-digit sequence which was bad, and the
17295e9d01f2Sgwr  * function returns a NULL pointer.
17305e9d01f2Sgwr  */
17315e9d01f2Sgwr 
17325e9d01f2Sgwr PRIVATE byte *
prs_haddr(char ** src,u_int htype)1733131109e4Swiz prs_haddr(char **src, u_int htype)
17345e9d01f2Sgwr {
17355e9d01f2Sgwr 	static byte haddr[MAXHADDRLEN];
17365e9d01f2Sgwr 	byte *hap;
17375e9d01f2Sgwr 	char tmpstr[MAXSTRINGLEN];
17385e9d01f2Sgwr 	u_int tmplen;
17395e9d01f2Sgwr 	unsigned hal;
17405e9d01f2Sgwr 	char *p;
17415e9d01f2Sgwr 
17425e9d01f2Sgwr 	hal = haddrlength(htype);	/* Get length of this address type */
17435e9d01f2Sgwr 	if (hal <= 0) {
17445e9d01f2Sgwr 		report(LOG_ERR, "Invalid addr type for HW addr parse");
17455e9d01f2Sgwr 		return NULL;
17465e9d01f2Sgwr 	}
17475e9d01f2Sgwr 	tmplen = sizeof(tmpstr);
17485e9d01f2Sgwr 	get_string(src, tmpstr, &tmplen);
17495e9d01f2Sgwr 	p = tmpstr;
17505e9d01f2Sgwr 
17515e9d01f2Sgwr #if 1	/* XXX - experimental */
17525e9d01f2Sgwr 	/* If it's a valid host name, try to lookup the HW address. */
17535e9d01f2Sgwr 	if (goodname(p)) {
17545e9d01f2Sgwr 		/* Lookup Hardware Address for hostname. */
17555e9d01f2Sgwr 		if ((hap = lookup_hwa(p, htype)) != NULL)
17565e9d01f2Sgwr 			return hap; /* success */
17575e9d01f2Sgwr 		report(LOG_ERR, "Add 0x prefix if hex value starts with A-F");
17585e9d01f2Sgwr 		/* OK, assume it must be numeric. */
17595e9d01f2Sgwr 	}
17605e9d01f2Sgwr #endif
17615e9d01f2Sgwr 
17625e9d01f2Sgwr 	hap = haddr;
17635e9d01f2Sgwr 	while (hap < haddr + hal) {
17642a645560Sgwr 		if ((*p == '.') || (*p == ':'))
17655e9d01f2Sgwr 			p++;
17665e9d01f2Sgwr 		if (interp_byte(&p, hap++) < 0) {
17675e9d01f2Sgwr 			return NULL;
17685e9d01f2Sgwr 		}
17695e9d01f2Sgwr 	}
17705e9d01f2Sgwr 	return haddr;
17715e9d01f2Sgwr }
17725e9d01f2Sgwr 
17735e9d01f2Sgwr 
17745e9d01f2Sgwr 
17755e9d01f2Sgwr /*
17765e9d01f2Sgwr  * "src" is a pointer to a character pointer which in turn points to a
17775e9d01f2Sgwr  * hexadecimal ASCII representation of a byte.  This byte is read, the
17785e9d01f2Sgwr  * character pointer is updated, and the result is deposited into the
17795e9d01f2Sgwr  * byte pointed to by "retbyte".
17805e9d01f2Sgwr  *
17815e9d01f2Sgwr  * The usual '0x' notation is allowed but not required.  The number must be
17825e9d01f2Sgwr  * a two digit hexadecimal number.  If the number is invalid, "src" and
17835e9d01f2Sgwr  * "retbyte" are left untouched and -1 is returned as the function value.
17845e9d01f2Sgwr  * Successful calls return 0.
17855e9d01f2Sgwr  */
17865e9d01f2Sgwr 
17875e9d01f2Sgwr PRIVATE int
interp_byte(char ** src,byte * retbyte)1788131109e4Swiz interp_byte(char **src, byte *retbyte)
17895e9d01f2Sgwr {
17905e9d01f2Sgwr 	int v;
17915e9d01f2Sgwr 
17925e9d01f2Sgwr 	if ((*src)[0] == '0' &&
17935e9d01f2Sgwr 		((*src)[1] == 'x' ||
17945e9d01f2Sgwr 		 (*src)[1] == 'X')) {
17955e9d01f2Sgwr 		(*src) += 2;			/* allow 0x for hex, but don't require it */
17965e9d01f2Sgwr 	}
1797e09553f3Sdsl 	if (!isxdigit((unsigned char)(*src)[0]) || !isxdigit((unsigned char)(*src)[1])) {
17985e9d01f2Sgwr 		return -1;
17995e9d01f2Sgwr 	}
18005e9d01f2Sgwr 	if (sscanf(*src, "%2x", &v) != 1) {
18015e9d01f2Sgwr 		return -1;
18025e9d01f2Sgwr 	}
18035e9d01f2Sgwr 	(*src) += 2;
18045e9d01f2Sgwr 	*retbyte = (byte) (v & 0xFF);
18055e9d01f2Sgwr 	return 0;
18065e9d01f2Sgwr }
18075e9d01f2Sgwr 
18085e9d01f2Sgwr 
18095e9d01f2Sgwr 
18105e9d01f2Sgwr /*
18115e9d01f2Sgwr  * The parameter "src" points to a character pointer which points to an
18125e9d01f2Sgwr  * ASCII string representation of an unsigned number.  The number is
18135e9d01f2Sgwr  * returned as an unsigned long and the character pointer is updated to
18145e9d01f2Sgwr  * point to the first illegal character.
18155e9d01f2Sgwr  */
18165e9d01f2Sgwr 
18175e9d01f2Sgwr PRIVATE u_int32
get_u_long(char ** src)1818131109e4Swiz get_u_long(char **src)
18195e9d01f2Sgwr {
1820aae9c2a0Swiz 	u_int32 value, base;
18215e9d01f2Sgwr 	char c;
18225e9d01f2Sgwr 
18235e9d01f2Sgwr 	/*
18245e9d01f2Sgwr 	 * Collect number up to first illegal character.  Values are specified
18255e9d01f2Sgwr 	 * as for C:  0x=hex, 0=octal, other=decimal.
18265e9d01f2Sgwr 	 */
18275e9d01f2Sgwr 	value = 0;
18285e9d01f2Sgwr 	base = 10;
18295e9d01f2Sgwr 	if (**src == '0') {
18305e9d01f2Sgwr 		base = 8;
18315e9d01f2Sgwr 		(*src)++;
18325e9d01f2Sgwr 	}
18335e9d01f2Sgwr 	if (**src == 'x' || **src == 'X') {
18345e9d01f2Sgwr 		base = 16;
18355e9d01f2Sgwr 		(*src)++;
18365e9d01f2Sgwr 	}
18375e9d01f2Sgwr 	while ((c = **src)) {
1838e09553f3Sdsl 		if (isdigit((unsigned char)c)) {
18395e9d01f2Sgwr 			value = (value * base) + (c - '0');
18405e9d01f2Sgwr 			(*src)++;
18415e9d01f2Sgwr 			continue;
18425e9d01f2Sgwr 		}
1843e09553f3Sdsl 		if (base == 16 && isxdigit((unsigned char)c)) {
18445e9d01f2Sgwr 			value = (value << 4) + ((c & ~32) + 10 - 'A');
18455e9d01f2Sgwr 			(*src)++;
18465e9d01f2Sgwr 			continue;
18475e9d01f2Sgwr 		}
18485e9d01f2Sgwr 		break;
18495e9d01f2Sgwr 	}
18505e9d01f2Sgwr 	return value;
18515e9d01f2Sgwr }
18525e9d01f2Sgwr 
18535e9d01f2Sgwr 
18545e9d01f2Sgwr 
18555e9d01f2Sgwr /*
18565e9d01f2Sgwr  * Routines for deletion of data associated with the main data structure.
18575e9d01f2Sgwr  */
18585e9d01f2Sgwr 
18595e9d01f2Sgwr 
18605e9d01f2Sgwr /*
18615e9d01f2Sgwr  * Frees the entire host data structure given.  Does nothing if the passed
18625e9d01f2Sgwr  * pointer is NULL.
18635e9d01f2Sgwr  */
18645e9d01f2Sgwr 
18655e9d01f2Sgwr PRIVATE void
free_host(hash_datum * hmp)1866131109e4Swiz free_host(hash_datum *hmp)
18675e9d01f2Sgwr {
18685e9d01f2Sgwr 	struct host *hostptr = (struct host *) hmp;
18695e9d01f2Sgwr 	if (hostptr == NULL)
18705e9d01f2Sgwr 		return;
18715e9d01f2Sgwr 	assert(hostptr->linkcount > 0);
18725e9d01f2Sgwr 	if (--(hostptr->linkcount))
18735e9d01f2Sgwr 		return;					/* Still has references */
18745e9d01f2Sgwr 	del_iplist(hostptr->cookie_server);
18755e9d01f2Sgwr 	del_iplist(hostptr->domain_server);
18765e9d01f2Sgwr 	del_iplist(hostptr->gateway);
18775e9d01f2Sgwr 	del_iplist(hostptr->impress_server);
18785e9d01f2Sgwr 	del_iplist(hostptr->log_server);
18795e9d01f2Sgwr 	del_iplist(hostptr->lpr_server);
18805e9d01f2Sgwr 	del_iplist(hostptr->name_server);
18815e9d01f2Sgwr 	del_iplist(hostptr->rlp_server);
18825e9d01f2Sgwr 	del_iplist(hostptr->time_server);
18835e9d01f2Sgwr 	del_iplist(hostptr->nis_server);
18845e9d01f2Sgwr 	del_iplist(hostptr->ntp_server);
18855e9d01f2Sgwr 
18865e9d01f2Sgwr 	/*
18875e9d01f2Sgwr 	 * XXX - Add new tags here
18885e9d01f2Sgwr 	 * (if the value is an IP list)
18895e9d01f2Sgwr 	 */
18905e9d01f2Sgwr 
18915e9d01f2Sgwr 	del_string(hostptr->hostname);
18925e9d01f2Sgwr 	del_string(hostptr->homedir);
18935e9d01f2Sgwr 	del_string(hostptr->bootfile);
18945e9d01f2Sgwr 	del_string(hostptr->tftpdir);
18955e9d01f2Sgwr 	del_string(hostptr->root_path);
18965e9d01f2Sgwr 	del_string(hostptr->domain_name);
18975e9d01f2Sgwr 	del_string(hostptr->dump_file);
18985e9d01f2Sgwr 	del_string(hostptr->exten_file);
18995e9d01f2Sgwr 	del_string(hostptr->nis_domain);
19005e9d01f2Sgwr 
19015e9d01f2Sgwr #ifdef	YORK_EX_OPTION
19025e9d01f2Sgwr 	del_string(hostptr->exec_file);
19035e9d01f2Sgwr #endif
19045e9d01f2Sgwr 
19055e9d01f2Sgwr 	/*
19065e9d01f2Sgwr 	 * XXX - Add new tags here
19075e9d01f2Sgwr 	 * (if it is a shared string)
19085e9d01f2Sgwr 	 */
19095e9d01f2Sgwr 
19105e9d01f2Sgwr 	del_bindata(hostptr->generic);
19115e9d01f2Sgwr 	free((char *) hostptr);
19125e9d01f2Sgwr }
19135e9d01f2Sgwr 
19145e9d01f2Sgwr 
19155e9d01f2Sgwr 
19165e9d01f2Sgwr /*
19175e9d01f2Sgwr  * Decrements the linkcount on the given IP address data structure.  If the
19185e9d01f2Sgwr  * linkcount goes to zero, the memory associated with the data is freed.
19195e9d01f2Sgwr  */
19205e9d01f2Sgwr 
19215e9d01f2Sgwr PRIVATE void
del_iplist(struct in_addr_list * iplist)1922131109e4Swiz del_iplist(struct in_addr_list *iplist)
19235e9d01f2Sgwr {
19245e9d01f2Sgwr 	if (iplist) {
19255e9d01f2Sgwr 		if (!(--(iplist->linkcount))) {
19265e9d01f2Sgwr 			free((char *) iplist);
19275e9d01f2Sgwr 		}
19285e9d01f2Sgwr 	}
19295e9d01f2Sgwr }
19305e9d01f2Sgwr 
19315e9d01f2Sgwr 
19325e9d01f2Sgwr 
19335e9d01f2Sgwr /*
19345e9d01f2Sgwr  * Decrements the linkcount on a string data structure.  If the count
19355e9d01f2Sgwr  * goes to zero, the memory associated with the string is freed.  Does
19365e9d01f2Sgwr  * nothing if the passed pointer is NULL.
19375e9d01f2Sgwr  */
19385e9d01f2Sgwr 
19395e9d01f2Sgwr PRIVATE void
del_string(struct shared_string * stringptr)1940131109e4Swiz del_string(struct shared_string *stringptr)
19415e9d01f2Sgwr {
19425e9d01f2Sgwr 	if (stringptr) {
19435e9d01f2Sgwr 		if (!(--(stringptr->linkcount))) {
19445e9d01f2Sgwr 			free((char *) stringptr);
19455e9d01f2Sgwr 		}
19465e9d01f2Sgwr 	}
19475e9d01f2Sgwr }
19485e9d01f2Sgwr 
19495e9d01f2Sgwr 
19505e9d01f2Sgwr 
19515e9d01f2Sgwr /*
19525e9d01f2Sgwr  * Decrements the linkcount on a shared_bindata data structure.  If the
19535e9d01f2Sgwr  * count goes to zero, the memory associated with the data is freed.  Does
19545e9d01f2Sgwr  * nothing if the passed pointer is NULL.
19555e9d01f2Sgwr  */
19565e9d01f2Sgwr 
19575e9d01f2Sgwr PRIVATE void
del_bindata(struct shared_bindata * dataptr)1958131109e4Swiz del_bindata(struct shared_bindata *dataptr)
19595e9d01f2Sgwr {
19605e9d01f2Sgwr 	if (dataptr) {
19615e9d01f2Sgwr 		if (!(--(dataptr->linkcount))) {
19625e9d01f2Sgwr 			free((char *) dataptr);
19635e9d01f2Sgwr 		}
19645e9d01f2Sgwr 	}
19655e9d01f2Sgwr }
19665e9d01f2Sgwr 
19675e9d01f2Sgwr 
19685e9d01f2Sgwr 
19695e9d01f2Sgwr 
19705e9d01f2Sgwr /* smalloc()  --  safe malloc()
19715e9d01f2Sgwr  *
19725e9d01f2Sgwr  * Always returns a valid pointer (if it returns at all).  The allocated
19735e9d01f2Sgwr  * memory is initialized to all zeros.  If malloc() returns an error, a
19745e9d01f2Sgwr  * message is printed using the report() function and the program aborts
19755e9d01f2Sgwr  * with a status of 1.
19765e9d01f2Sgwr  */
19775e9d01f2Sgwr 
19785e9d01f2Sgwr PRIVATE char *
smalloc(unsigned int nbytes)1979131109e4Swiz smalloc(unsigned int nbytes)
19805e9d01f2Sgwr {
19815e9d01f2Sgwr 	char *retvalue;
19825e9d01f2Sgwr 
19835e9d01f2Sgwr 	retvalue = malloc(nbytes);
19845e9d01f2Sgwr 	if (!retvalue) {
19855e9d01f2Sgwr 		report(LOG_ERR, "malloc() failure -- exiting");
19865e9d01f2Sgwr 		exit(1);
19875e9d01f2Sgwr 	}
19885e9d01f2Sgwr 	bzero(retvalue, nbytes);
19895e9d01f2Sgwr 	return retvalue;
19905e9d01f2Sgwr }
19915e9d01f2Sgwr 
19925e9d01f2Sgwr 
19935e9d01f2Sgwr /*
19945e9d01f2Sgwr  * Compare function to determine whether two hardware addresses are
19955e9d01f2Sgwr  * equivalent.  Returns TRUE if "host1" and "host2" are equivalent, FALSE
19965e9d01f2Sgwr  * otherwise.
19975e9d01f2Sgwr  *
19985e9d01f2Sgwr  * This function is used when retrieving elements from the hardware address
19995e9d01f2Sgwr  * hash table.
20005e9d01f2Sgwr  */
20015e9d01f2Sgwr 
20025e9d01f2Sgwr boolean
hwlookcmp(hash_datum * d1,hash_datum * d2)2003131109e4Swiz hwlookcmp(hash_datum *d1, hash_datum *d2)
20045e9d01f2Sgwr {
20055e9d01f2Sgwr 	struct host *host1 = (struct host *) d1;
20065e9d01f2Sgwr 	struct host *host2 = (struct host *) d2;
20075e9d01f2Sgwr 
20085e9d01f2Sgwr 	if (host1->htype != host2->htype) {
20095e9d01f2Sgwr 		return FALSE;
20105e9d01f2Sgwr 	}
20115e9d01f2Sgwr 	if (bcmp(host1->haddr, host2->haddr, haddrlength(host1->htype))) {
20125e9d01f2Sgwr 		return FALSE;
20135e9d01f2Sgwr 	}
20145e9d01f2Sgwr 	return TRUE;
20155e9d01f2Sgwr }
20165e9d01f2Sgwr 
20175e9d01f2Sgwr 
20185e9d01f2Sgwr /*
20195e9d01f2Sgwr  * Compare function for doing IP address hash table lookup.
20205e9d01f2Sgwr  */
20215e9d01f2Sgwr 
20225e9d01f2Sgwr boolean
iplookcmp(hash_datum * d1,hash_datum * d2)2023131109e4Swiz iplookcmp(hash_datum *d1, hash_datum *d2)
20245e9d01f2Sgwr {
20255e9d01f2Sgwr 	struct host *host1 = (struct host *) d1;
20265e9d01f2Sgwr 	struct host *host2 = (struct host *) d2;
20275e9d01f2Sgwr 
20285e9d01f2Sgwr 	return (host1->iaddr.s_addr == host2->iaddr.s_addr);
20295e9d01f2Sgwr }
20305e9d01f2Sgwr 
20315e9d01f2Sgwr /*
20325e9d01f2Sgwr  * Local Variables:
20335e9d01f2Sgwr  * tab-width: 4
20345e9d01f2Sgwr  * c-indent-level: 4
20355e9d01f2Sgwr  * c-argdecl-indent: 4
20365e9d01f2Sgwr  * c-continued-statement-offset: 4
20375e9d01f2Sgwr  * c-continued-brace-offset: -4
20385e9d01f2Sgwr  * c-label-offset: -4
20395e9d01f2Sgwr  * c-brace-offset: 0
20405e9d01f2Sgwr  * End:
20415e9d01f2Sgwr  */
2042