readfile.c revision 84119
13229Spst/************************************************************************
23229Spst          Copyright 1988, 1991 by Carnegie Mellon University
33229Spst
43229Spst                          All Rights Reserved
53229Spst
63229SpstPermission to use, copy, modify, and distribute this software and its
73229Spstdocumentation for any purpose and without fee is hereby granted, provided
83229Spstthat the above copyright notice appear in all copies and that both that
93229Spstcopyright notice and this permission notice appear in supporting
103229Spstdocumentation, and that the name of Carnegie Mellon University not be used
113229Spstin advertising or publicity pertaining to distribution of the software
123229Spstwithout specific, written prior permission.
133229Spst
143229SpstCARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
153229SpstSOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
163229SpstIN NO EVENT SHALL CMU BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
173229SpstDAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
183229SpstPROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
193229SpstACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
203229SpstSOFTWARE.
2118471Swosch
2250476Speter $FreeBSD: head/libexec/bootpd/readfile.c 84119 2001-09-29 10:31:28Z iedowse $
2318471Swosch
243229Spst************************************************************************/
253229Spst
263229Spst/*
273229Spst * bootpd configuration file reading code.
283229Spst *
293229Spst * The routines in this file deal with reading, interpreting, and storing
303229Spst * the information found in the bootpd configuration file (usually
313229Spst * /etc/bootptab).
323229Spst */
333229Spst
343229Spst
353229Spst#include <sys/errno.h>
363229Spst#include <sys/types.h>
373229Spst#include <sys/stat.h>
383229Spst#include <sys/file.h>
393229Spst#include <sys/time.h>
403229Spst#include <netinet/in.h>
413229Spst
423229Spst#include <stdlib.h>
433229Spst#include <stdio.h>
443229Spst#include <string.h>
453229Spst#include <ctype.h>
463229Spst#include <assert.h>
473229Spst#include <syslog.h>
483229Spst
493229Spst#ifndef USE_BFUNCS
503229Spst#include <memory.h>
513229Spst/* Yes, memcpy is OK here (no overlapped copies). */
523229Spst#define	bcopy(a,b,c)	memcpy(b,a,c)
533229Spst#define	bzero(p,l)	memset(p,0,l)
543229Spst#define	bcmp(a,b,c)	memcmp(a,b,c)
553229Spst#endif
563229Spst
573229Spst#include "bootp.h"
583229Spst#include "hash.h"
593229Spst#include "hwaddr.h"
603229Spst#include "lookup.h"
613229Spst#include "readfile.h"
623229Spst#include "report.h"
633229Spst#include "tzone.h"
643229Spst#include "bootpd.h"
653229Spst
663229Spst#define HASHTABLESIZE		257	/* Hash table size (prime) */
673229Spst
683229Spst/* Non-standard hardware address type (see bootp.h) */
693229Spst#define HTYPE_DIRECT	0
703229Spst
713229Spst/* Error codes returned by eval_symbol: */
723229Spst#define SUCCESS			  0
733229Spst#define E_END_OF_ENTRY		(-1)
743229Spst#define E_SYNTAX_ERROR		(-2)
753229Spst#define E_UNKNOWN_SYMBOL	(-3)
763229Spst#define E_BAD_IPADDR		(-4)
773229Spst#define E_BAD_HWADDR		(-5)
783229Spst#define E_BAD_LONGWORD		(-6)
793229Spst#define E_BAD_HWATYPE		(-7)
803229Spst#define E_BAD_PATHNAME		(-8)
813229Spst#define E_BAD_VALUE 		(-9)
823229Spst
833229Spst/* Tag idendities. */
843229Spst#define SYM_NULL		  0
853229Spst#define SYM_BOOTFILE		  1
863229Spst#define SYM_COOKIE_SERVER	  2
873229Spst#define SYM_DOMAIN_SERVER	  3
883229Spst#define SYM_GATEWAY		  4
893229Spst#define SYM_HWADDR		  5
903229Spst#define SYM_HOMEDIR		  6
913229Spst#define SYM_HTYPE		  7
923229Spst#define SYM_IMPRESS_SERVER	  8
933229Spst#define SYM_IPADDR		  9
943229Spst#define SYM_LOG_SERVER		 10
953229Spst#define SYM_LPR_SERVER		 11
963229Spst#define SYM_NAME_SERVER		 12
973229Spst#define SYM_RLP_SERVER		 13
983229Spst#define SYM_SUBNET_MASK		 14
993229Spst#define SYM_TIME_OFFSET		 15
1003229Spst#define SYM_TIME_SERVER		 16
1013229Spst#define SYM_VENDOR_MAGIC	 17
1023229Spst#define SYM_SIMILAR_ENTRY	 18
1033229Spst#define SYM_NAME_SWITCH		 19
1043229Spst#define SYM_BOOTSIZE		 20
1053229Spst#define SYM_BOOT_SERVER		 22
1063229Spst#define SYM_TFTPDIR		 23
1073229Spst#define SYM_DUMP_FILE		 24
1083229Spst#define SYM_DOMAIN_NAME          25
1093229Spst#define SYM_SWAP_SERVER          26
1103229Spst#define SYM_ROOT_PATH            27
1113229Spst#define SYM_EXTEN_FILE           28
1123229Spst#define SYM_REPLY_ADDR           29
1133229Spst#define SYM_NIS_DOMAIN           30	/* RFC 1533 */
1143229Spst#define SYM_NIS_SERVER           31	/* RFC 1533 */
1153229Spst#define SYM_NTP_SERVER           32	/* RFC 1533 */
1163229Spst#define SYM_EXEC_FILE		 33	/* YORK_EX_OPTION */
1173229Spst#define SYM_MSG_SIZE 		 34
1183229Spst#define SYM_MIN_WAIT		 35
1193229Spst/* XXX - Add new tags here */
1203229Spst
1213229Spst#define OP_ADDITION		  1	/* Operations on tags */
1223229Spst#define OP_DELETION		  2
1233229Spst#define OP_BOOLEAN		  3
1243229Spst
1253229Spst#define MAXINADDRS		 16	/* Max size of an IP address list */
1263229Spst#define MAXBUFLEN		256	/* Max temp buffer space */
1273229Spst#define MAXENTRYLEN	       2048	/* Max size of an entire entry */
1283229Spst
1293229Spst
1303229Spst
1313229Spst/*
1323229Spst * Structure used to map a configuration-file symbol (such as "ds") to a
1333229Spst * unique integer.
1343229Spst */
1353229Spst
1363229Spststruct symbolmap {
1373229Spst	char *symbol;
1383229Spst	int symbolcode;
1393229Spst};
1403229Spst
1413229Spst
1423229Spststruct htypename {
1433229Spst	char *name;
1443229Spst	byte htype;
1453229Spst};
1463229Spst
1473229Spst
1483229SpstPRIVATE int nhosts;				/* Number of hosts (/w hw or IP address) */
1493229SpstPRIVATE int nentries;			/* Total number of entries */
1503229SpstPRIVATE int32 modtime = 0;		/* Last modification time of bootptab */
1513229SpstPRIVATE char *current_hostname;	/* Name of the current entry. */
1523229SpstPRIVATE char current_tagname[8];
1533229Spst
1543229Spst/*
1553229Spst * List of symbolic names used in the bootptab file.  The order and actual
1563229Spst * values of the symbol codes (SYM_. . .) are unimportant, but they must
1573229Spst * all be unique.
1583229Spst */
1593229Spst
1603229SpstPRIVATE struct symbolmap symbol_list[] = {
1613229Spst	{"bf", SYM_BOOTFILE},
1623229Spst	{"bs", SYM_BOOTSIZE},
1633229Spst	{"cs", SYM_COOKIE_SERVER},
1643229Spst	{"df", SYM_DUMP_FILE},
1653229Spst	{"dn", SYM_DOMAIN_NAME},
1663229Spst	{"ds", SYM_DOMAIN_SERVER},
1673229Spst	{"ef", SYM_EXTEN_FILE},
1683229Spst	{"ex", SYM_EXEC_FILE},		/* YORK_EX_OPTION */
1693229Spst	{"gw", SYM_GATEWAY},
1703229Spst	{"ha", SYM_HWADDR},
1713229Spst	{"hd", SYM_HOMEDIR},
1723229Spst	{"hn", SYM_NAME_SWITCH},
1733229Spst	{"ht", SYM_HTYPE},
1743229Spst	{"im", SYM_IMPRESS_SERVER},
1753229Spst	{"ip", SYM_IPADDR},
1763229Spst	{"lg", SYM_LOG_SERVER},
1773229Spst	{"lp", SYM_LPR_SERVER},
1783229Spst	{"ms", SYM_MSG_SIZE},
1793229Spst	{"mw", SYM_MIN_WAIT},
1803229Spst	{"ns", SYM_NAME_SERVER},
1813229Spst	{"nt", SYM_NTP_SERVER},
1823229Spst	{"ra", SYM_REPLY_ADDR},
1833229Spst	{"rl", SYM_RLP_SERVER},
1843229Spst	{"rp", SYM_ROOT_PATH},
1853229Spst	{"sa", SYM_BOOT_SERVER},
1863229Spst	{"sm", SYM_SUBNET_MASK},
1873229Spst	{"sw", SYM_SWAP_SERVER},
1883229Spst	{"tc", SYM_SIMILAR_ENTRY},
1893229Spst	{"td", SYM_TFTPDIR},
1903229Spst	{"to", SYM_TIME_OFFSET},
1913229Spst	{"ts", SYM_TIME_SERVER},
1923229Spst	{"vm", SYM_VENDOR_MAGIC},
1933229Spst	{"yd", SYM_NIS_DOMAIN},
1943229Spst	{"ys", SYM_NIS_SERVER},
1953229Spst	/* XXX - Add new tags here */
1963229Spst};
1973229Spst
1983229Spst
1993229Spst/*
2003229Spst * List of symbolic names for hardware types.  Name translates into
2013229Spst * hardware type code listed with it.  Names must begin with a letter
2023229Spst * and must be all lowercase.  This is searched linearly, so put
2033229Spst * commonly-used entries near the beginning.
2043229Spst */
2053229Spst
2063229SpstPRIVATE struct htypename htnamemap[] = {
2073229Spst	{"ethernet", HTYPE_ETHERNET},
2083229Spst	{"ethernet3", HTYPE_EXP_ETHERNET},
2093229Spst	{"ether", HTYPE_ETHERNET},
2103229Spst	{"ether3", HTYPE_EXP_ETHERNET},
2113229Spst	{"ieee802", HTYPE_IEEE802},
2123229Spst	{"tr", HTYPE_IEEE802},
2133229Spst	{"token-ring", HTYPE_IEEE802},
2143229Spst	{"pronet", HTYPE_PRONET},
2153229Spst	{"chaos", HTYPE_CHAOS},
2163229Spst	{"arcnet", HTYPE_ARCNET},
2173229Spst	{"ax.25", HTYPE_AX25},
2183229Spst	{"direct", HTYPE_DIRECT},
2193229Spst	{"serial", HTYPE_DIRECT},
2203229Spst	{"slip", HTYPE_DIRECT},
2213229Spst	{"ppp", HTYPE_DIRECT}
2223229Spst};
2233229Spst
2243229Spst
2253229Spst
2263229Spst/*
2273229Spst * Externals and forward declarations.
2283229Spst */
2293229Spst
2303229Spst#ifdef	__STDC__
2313229Spst#define P(args) args
2323229Spst#else
2333229Spst#define P(args) ()
2343229Spst#endif
2353229Spst
2363229Spstextern boolean iplookcmp();
2373229Spstboolean nmcmp P((hash_datum *, hash_datum *));
2383229Spst
2393229SpstPRIVATE void
2403229Spst	adjust P((char **));
2413229SpstPRIVATE void
2423229Spst	del_string P((struct shared_string *));
2433229SpstPRIVATE void
2443229Spst	del_bindata P((struct shared_bindata *));
2453229SpstPRIVATE void
2463229Spst	del_iplist P((struct in_addr_list *));
2473229SpstPRIVATE void
2483229Spst	eat_whitespace P((char **));
2493229SpstPRIVATE int
2503229Spst	eval_symbol P((char **, struct host *));
2513229SpstPRIVATE void
2523229Spst	fill_defaults P((struct host *, char **));
2533229SpstPRIVATE void
2543229Spst	free_host P((hash_datum *));
2553229SpstPRIVATE struct in_addr_list *
2563229Spst	get_addresses P((char **));
2573229SpstPRIVATE struct shared_string *
2583229Spst	get_shared_string P((char **));
2593229SpstPRIVATE char *
2603229Spst	get_string P((char **, char *, u_int *));
2613229SpstPRIVATE u_int32
2623229Spst	get_u_long P((char **));
2633229SpstPRIVATE boolean
2643229Spst	goodname P((char *));
2653229SpstPRIVATE boolean
2663229Spst	hwinscmp P((hash_datum *, hash_datum *));
2673229SpstPRIVATE int
2683229Spst	interp_byte P((char **, byte *));
2693229SpstPRIVATE void
2703229Spst	makelower P((char *));
2713229SpstPRIVATE boolean
2723229Spst        nullcmp P((hash_datum *, hash_datum *));
2733229SpstPRIVATE int
2743229Spst	process_entry P((struct host *, char *));
2753229SpstPRIVATE int
2763229Spst	process_generic P((char **, struct shared_bindata **, u_int));
2773229SpstPRIVATE byte *
2783229Spst	prs_haddr P((char **, u_int));
2793229SpstPRIVATE int
2803229Spst	prs_inetaddr P((char **, u_int32 *));
2813229SpstPRIVATE void
2823229Spst	read_entry P((FILE *, char *, u_int *));
2833229SpstPRIVATE char *
2843229Spst	smalloc P((u_int));
2853229Spst
2863229Spst#undef P
2873229Spst
2883229Spst
2893229Spst/*
2903229Spst * Vendor magic cookies for CMU and RFC1048
2913229Spst */
2923229Spstu_char vm_cmu[4] = VM_CMU;
2933229Spstu_char vm_rfc1048[4] = VM_RFC1048;
2943229Spst
2953229Spst/*
2963229Spst * Main hash tables
2973229Spst */
2983229Spsthash_tbl *hwhashtable;
2993229Spsthash_tbl *iphashtable;
3003229Spsthash_tbl *nmhashtable;
3013229Spst
3023229Spst/*
3033229Spst * Allocate hash tables for hardware address, ip address, and hostname
3043229Spst * (shared by bootpd and bootpef)
3053229Spst */
3063229Spstvoid
3073229Spstrdtab_init()
3083229Spst{
3093229Spst	hwhashtable = hash_Init(HASHTABLESIZE);
3103229Spst	iphashtable = hash_Init(HASHTABLESIZE);
3113229Spst	nmhashtable = hash_Init(HASHTABLESIZE);
3123229Spst	if (!(hwhashtable && iphashtable && nmhashtable)) {
3133229Spst		report(LOG_ERR, "Unable to allocate hash tables.");
3143229Spst		exit(1);
3153229Spst	}
3163229Spst}
3173229Spst
3183229Spst
3193229Spst/*
3203229Spst * Read bootptab database file.  Avoid rereading the file if the
3213229Spst * write date hasn't changed since the last time we read it.
3223229Spst */
3233229Spst
3243229Spstvoid
3253229Spstreadtab(force)
3263229Spst	int force;
3273229Spst{
3283229Spst	struct host *hp;
3293229Spst	FILE *fp;
3303229Spst	struct stat st;
3313229Spst	unsigned hashcode, buflen;
3323229Spst	static char buffer[MAXENTRYLEN];
3333229Spst
3343229Spst	/*
3353229Spst	 * Check the last modification time.
3363229Spst	 */
3373229Spst	if (stat(bootptab, &st) < 0) {
3383229Spst		report(LOG_ERR, "stat on \"%s\": %s",
3393229Spst			   bootptab, get_errmsg());
3403229Spst		return;
3413229Spst	}
3423229Spst#ifdef DEBUG
3433229Spst	if (debug > 3) {
3443229Spst		char timestr[28];
3453229Spst		strcpy(timestr, ctime(&(st.st_mtime)));
3463229Spst		/* zap the newline */
3473229Spst		timestr[24] = '\0';
3483229Spst		report(LOG_INFO, "bootptab mtime: %s",
3493229Spst			   timestr);
3503229Spst	}
3513229Spst#endif
3523229Spst	if ((force == 0) &&
3533229Spst		(st.st_mtime == modtime) &&
3543229Spst		st.st_nlink) {
3553229Spst		/*
3563229Spst		 * hasn't been modified or deleted yet.
3573229Spst		 */
3583229Spst		return;
3593229Spst	}
3603229Spst	if (debug)
3613229Spst		report(LOG_INFO, "reading %s\"%s\"",
3623229Spst			   (modtime != 0L) ? "new " : "",
3633229Spst			   bootptab);
3643229Spst
3653229Spst	/*
3663229Spst	 * Open bootptab file.
3673229Spst	 */
3683229Spst	if ((fp = fopen(bootptab, "r")) == NULL) {
3693229Spst		report(LOG_ERR, "error opening \"%s\": %s", bootptab, get_errmsg());
3703229Spst		return;
3713229Spst	}
3723229Spst	/*
3733229Spst	 * Record file modification time.
3743229Spst	 */
3753229Spst	if (fstat(fileno(fp), &st) < 0) {
3763229Spst		report(LOG_ERR, "fstat: %s", get_errmsg());
3773229Spst		fclose(fp);
3783229Spst		return;
3793229Spst	}
3803229Spst	modtime = st.st_mtime;
3813229Spst
3823229Spst	/*
3833229Spst	 * Entirely erase all hash tables.
3843229Spst	 */
3853229Spst	hash_Reset(hwhashtable, free_host);
3863229Spst	hash_Reset(iphashtable, free_host);
3873229Spst	hash_Reset(nmhashtable, free_host);
3883229Spst
3893229Spst	nhosts = 0;
3903229Spst	nentries = 0;
3913229Spst	while (TRUE) {
3923229Spst		buflen = sizeof(buffer);
3933229Spst		read_entry(fp, buffer, &buflen);
3943229Spst		if (buflen == 0) {		/* More entries? */
3953229Spst			break;
3963229Spst		}
3973229Spst		hp = (struct host *) smalloc(sizeof(struct host));
3983229Spst		bzero((char *) hp, sizeof(*hp));
3993229Spst		/* the link count it zero */
4003229Spst
4013229Spst		/*
4023229Spst		 * Get individual info
4033229Spst		 */
4043229Spst		if (process_entry(hp, buffer) < 0) {
4053229Spst			hp->linkcount = 1;
4063229Spst			free_host((hash_datum *) hp);
4073229Spst			continue;
4083229Spst		}
4093229Spst		/*
4103229Spst		 * If this is not a dummy entry, and the IP or HW
4113229Spst		 * address is not yet set, try to get them here.
4123229Spst		 * Dummy entries have . as first char of name.
4133229Spst		 */
4143229Spst		if (goodname(hp->hostname->string)) {
4153229Spst			char *hn = hp->hostname->string;
4163229Spst			u_int32 value;
4173229Spst			if (hp->flags.iaddr == 0) {
4183229Spst				if (lookup_ipa(hn, &value)) {
4193229Spst					report(LOG_ERR, "can not get IP addr for %s", hn);
4203229Spst					report(LOG_ERR, "(dummy names should start with '.')");
4213229Spst				} else {
4223229Spst					hp->iaddr.s_addr = value;
4233229Spst					hp->flags.iaddr = TRUE;
4243229Spst				}
4253229Spst			}
4263229Spst			/* Set default subnet mask. */
4273229Spst			if (hp->flags.subnet_mask == 0) {
4283229Spst				if (lookup_netmask(hp->iaddr.s_addr, &value)) {
4293229Spst					report(LOG_ERR, "can not get netmask for %s", hn);
4303229Spst				} else {
4313229Spst					hp->subnet_mask.s_addr = value;
4323229Spst					hp->flags.subnet_mask = TRUE;
4333229Spst				}
4343229Spst			}
4353229Spst		}
4363229Spst		if (hp->flags.iaddr) {
4373229Spst			nhosts++;
4383229Spst		}
4393229Spst		/* Register by HW addr if known. */
4403229Spst		if (hp->flags.htype && hp->flags.haddr) {
4413229Spst			/* We will either insert it or free it. */
4423229Spst			hp->linkcount++;
4433229Spst			hashcode = hash_HashFunction(hp->haddr, haddrlength(hp->htype));
4443229Spst			if (hash_Insert(hwhashtable, hashcode, hwinscmp, hp, hp) < 0) {
4453229Spst				report(LOG_NOTICE, "duplicate %s address: %s",
4463229Spst					   netname(hp->htype),
44713572Spst					   haddrtoa(hp->haddr, haddrlength(hp->htype)));
4483229Spst				free_host((hash_datum *) hp);
4493229Spst				continue;
4503229Spst			}
4513229Spst		}
4523229Spst		/* Register by IP addr if known. */
4533229Spst		if (hp->flags.iaddr) {
4543229Spst			hashcode = hash_HashFunction((u_char *) & (hp->iaddr.s_addr), 4);
4553229Spst			if (hash_Insert(iphashtable, hashcode, nullcmp, hp, hp) < 0) {
4563229Spst				report(LOG_ERR,
4573229Spst					   "hash_Insert() failed on IP address insertion");
4583229Spst			} else {
4593229Spst				/* Just inserted the host struct in a new hash list. */
4603229Spst				hp->linkcount++;
4613229Spst			}
4623229Spst		}
4633229Spst		/* Register by Name (always known) */
4643229Spst		hashcode = hash_HashFunction((u_char *) hp->hostname->string,
4653229Spst									 strlen(hp->hostname->string));
4663229Spst		if (hash_Insert(nmhashtable, hashcode, nullcmp,
4673229Spst						hp->hostname->string, hp) < 0) {
4683229Spst			report(LOG_ERR,
4693229Spst				 "hash_Insert() failed on insertion of hostname: \"%s\"",
4703229Spst				   hp->hostname->string);
4713229Spst		} else {
4723229Spst			/* Just inserted the host struct in a new hash list. */
4733229Spst			hp->linkcount++;
4743229Spst		}
4753229Spst
4763229Spst		nentries++;
4773229Spst	}
4783229Spst
4793229Spst	fclose(fp);
4803229Spst	if (debug)
4813229Spst		report(LOG_INFO, "read %d entries (%d hosts) from \"%s\"",
4823229Spst			   nentries, nhosts, bootptab);
4833229Spst	return;
4843229Spst}
4853229Spst
4863229Spst
4873229Spst
4883229Spst/*
4893229Spst * Read an entire host entry from the file pointed to by "fp" and insert it
4903229Spst * into the memory pointed to by "buffer".  Leading whitespace and comments
4913229Spst * starting with "#" are ignored (removed).  Backslashes (\) always quote
49272640Sasmodai * the next character except that newlines preceded by a backslash cause
4933229Spst * line-continuation onto the next line.  The entry is terminated by a
49472640Sasmodai * newline character which is not preceded by a backslash.  Sequences
4953229Spst * surrounded by double quotes are taken literally (including newlines, but
4963229Spst * not backslashes).
4973229Spst *
4983229Spst * The "bufsiz" parameter points to an unsigned int which specifies the
4993229Spst * maximum permitted buffer size.  Upon return, this value will be replaced
5003229Spst * with the actual length of the entry (not including the null terminator).
5013229Spst *
5023229Spst * This code is a little scary. . . .  I don't like using gotos in C
5033229Spst * either, but I first wrote this as an FSM diagram and gotos seemed like
5043229Spst * the easiest way to implement it.  Maybe later I'll clean it up.
5053229Spst */
5063229Spst
5073229SpstPRIVATE void
5083229Spstread_entry(fp, buffer, bufsiz)
5093229Spst	FILE *fp;
5103229Spst	char *buffer;
5113229Spst	unsigned *bufsiz;
5123229Spst{
5133229Spst	int c, length;
5143229Spst
5153229Spst	length = 0;
5163229Spst
5173229Spst	/*
5183229Spst	 * Eat whitespace, blank lines, and comment lines.
5193229Spst	 */
5203229Spst  top:
5213229Spst	c = fgetc(fp);
5223229Spst	if (c < 0) {
5233229Spst		goto done;				/* Exit if end-of-file */
5243229Spst	}
5253229Spst	if (isspace(c)) {
5263229Spst		goto top;				/* Skip over whitespace */
5273229Spst	}
5283229Spst	if (c == '#') {
5293229Spst		while (TRUE) {			/* Eat comments after # */
5303229Spst			c = fgetc(fp);
5313229Spst			if (c < 0) {
5323229Spst				goto done;		/* Exit if end-of-file */
5333229Spst			}
5343229Spst			if (c == '\n') {
5353229Spst				goto top;		/* Try to read the next line */
5363229Spst			}
5373229Spst		}
5383229Spst	}
5393229Spst	ungetc(c, fp);				/* Other character, push it back to reprocess it */
5403229Spst
5413229Spst
5423229Spst	/*
5433229Spst	 * Now we're actually reading a data entry.  Get each character and
5443229Spst	 * assemble it into the data buffer, processing special characters like
5453229Spst	 * double quotes (") and backslashes (\).
5463229Spst	 */
5473229Spst
5483229Spst  mainloop:
5493229Spst	c = fgetc(fp);
5503229Spst	switch (c) {
5513229Spst	case EOF:
5523229Spst	case '\n':
5533229Spst		goto done;				/* Exit on EOF or newline */
5543229Spst	case '\\':
5553229Spst		c = fgetc(fp);			/* Backslash, read a new character */
5563229Spst		if (c < 0) {
5573229Spst			goto done;			/* Exit on EOF */
5583229Spst		}
5593229Spst		*buffer++ = c;			/* Store the literal character */
5603229Spst		length++;
5613229Spst		if (length < *bufsiz - 1) {
5623229Spst			goto mainloop;
5633229Spst		} else {
5643229Spst			goto done;
5653229Spst		}
5663229Spst	case '"':
5673229Spst		*buffer++ = '"';		/* Store double-quote */
5683229Spst		length++;
5693229Spst		if (length >= *bufsiz - 1) {
5703229Spst			goto done;
5713229Spst		}
5723229Spst		while (TRUE) {			/* Special quote processing loop */
5733229Spst			c = fgetc(fp);
5743229Spst			switch (c) {
5753229Spst			case EOF:
5763229Spst				goto done;		/* Exit on EOF . . . */
5773229Spst			case '"':
5783229Spst				*buffer++ = '"';/* Store matching quote */
5793229Spst				length++;
5803229Spst				if (length < *bufsiz - 1) {
5813229Spst					goto mainloop;	/* And continue main loop */
5823229Spst				} else {
5833229Spst					goto done;
5843229Spst				}
5853229Spst			case '\\':
5863229Spst				if ((c = fgetc(fp)) < 0) {	/* Backslash */
5873229Spst					goto done;	/* EOF. . . .*/
5883229Spst				}				/* else fall through */
5893229Spst			default:
5903229Spst				*buffer++ = c;	/* Other character, store it */
5913229Spst				length++;
5923229Spst				if (length >= *bufsiz - 1) {
5933229Spst					goto done;
5943229Spst				}
5953229Spst			}
5963229Spst		}
5973229Spst	case ':':
5983229Spst		*buffer++ = c;			/* Store colons */
5993229Spst		length++;
6003229Spst		if (length >= *bufsiz - 1) {
6013229Spst			goto done;
6023229Spst		}
6033229Spst		do {					/* But remove whitespace after them */
6043229Spst			c = fgetc(fp);
6053229Spst			if ((c < 0) || (c == '\n')) {
6063229Spst				goto done;
6073229Spst			}
6083229Spst		} while (isspace(c));	/* Skip whitespace */
6093229Spst
6103229Spst		if (c == '\\') {		/* Backslash quotes next character */
6113229Spst			c = fgetc(fp);
6123229Spst			if (c < 0) {
6133229Spst				goto done;
6143229Spst			}
6153229Spst			if (c == '\n') {
6163229Spst				goto top;		/* Backslash-newline continuation */
6173229Spst			}
6183229Spst		}
6193229Spst		/* fall through if "other" character */
6203229Spst	default:
6213229Spst		*buffer++ = c;			/* Store other characters */
6223229Spst		length++;
6233229Spst		if (length >= *bufsiz - 1) {
6243229Spst			goto done;
6253229Spst		}
6263229Spst	}
6273229Spst	goto mainloop;				/* Keep going */
6283229Spst
6293229Spst  done:
6303229Spst	*buffer = '\0';				/* Terminate string */
6313229Spst	*bufsiz = length;			/* Tell the caller its length */
6323229Spst}
6333229Spst
6343229Spst
6353229Spst
6363229Spst/*
6373229Spst * Parse out all the various tags and parameters in the host entry pointed
6383229Spst * to by "src".  Stuff all the data into the appropriate fields of the
6393229Spst * host structure pointed to by "host".  If there is any problem with the
6403229Spst * entry, an error message is reported via report(), no further processing
6413229Spst * is done, and -1 is returned.  Successful calls return 0.
6423229Spst *
6433229Spst * (Some errors probably shouldn't be so completely fatal. . . .)
6443229Spst */
6453229Spst
6463229SpstPRIVATE int
6473229Spstprocess_entry(host, src)
6483229Spst	struct host *host;
6493229Spst	char *src;
6503229Spst{
6513229Spst	int retval;
6523229Spst	char *msg;
6533229Spst
6543229Spst	if (!host || *src == '\0') {
6553229Spst		return -1;
6563229Spst	}
6573229Spst	host->hostname = get_shared_string(&src);
6583229Spst#if 0
6593229Spst	/* Be more liberal for the benefit of dummy tag names. */
6603229Spst	if (!goodname(host->hostname->string)) {
6613229Spst		report(LOG_ERR, "bad hostname: \"%s\"", host->hostname->string);
6623229Spst		del_string(host->hostname);
6633229Spst		return -1;
6643229Spst	}
6653229Spst#endif
6663229Spst	current_hostname = host->hostname->string;
6673229Spst	adjust(&src);
6683229Spst	while (TRUE) {
6693229Spst		retval = eval_symbol(&src, host);
6703229Spst		if (retval == SUCCESS) {
6713229Spst			adjust(&src);
6723229Spst			continue;
6733229Spst		}
6743229Spst		if (retval == E_END_OF_ENTRY) {
6753229Spst			/* The default subnet mask is set in readtab() */
6763229Spst			return 0;
6773229Spst		}
6783229Spst		/* Some kind of error. */
6793229Spst		switch (retval) {
6803229Spst		case E_SYNTAX_ERROR:
6813229Spst			msg = "bad syntax";
6823229Spst			break;
6833229Spst		case E_UNKNOWN_SYMBOL:
6843229Spst			msg = "unknown symbol";
6853229Spst			break;
6863229Spst		case E_BAD_IPADDR:
6873229Spst			msg = "bad INET address";
6883229Spst			break;
6893229Spst		case E_BAD_HWADDR:
6903229Spst			msg = "bad hardware address";
6913229Spst			break;
6923229Spst		case E_BAD_LONGWORD:
6933229Spst			msg = "bad longword value";
6943229Spst			break;
6953229Spst		case E_BAD_HWATYPE:
6963229Spst			msg = "bad HW address type";
6973229Spst			break;
6983229Spst		case E_BAD_PATHNAME:
6993229Spst			msg = "bad pathname (need leading '/')";
70084119Siedowse			break;
7013229Spst		case E_BAD_VALUE:
7023229Spst			msg = "bad value";
70384119Siedowse			break;
7043229Spst		default:
70584119Siedowse			msg = "unknown error";
7063229Spst			break;
7073229Spst		}						/* switch */
7083229Spst		report(LOG_ERR, "in entry named \"%s\", symbol \"%s\": %s",
7093229Spst			   current_hostname, current_tagname, msg);
7103229Spst		return -1;
7113229Spst	}
7123229Spst}
7133229Spst
7143229Spst
7153229Spst/*
7163229Spst * Macros for use in the function below:
7173229Spst */
7183229Spst
7193229Spst/* Parse one INET address stored directly in MEMBER. */
7203229Spst#define PARSE_IA1(MEMBER) do \
7213229Spst{ \
7223229Spst	if (optype == OP_BOOLEAN) \
7233229Spst		return E_SYNTAX_ERROR; \
7243229Spst	hp->flags.MEMBER = FALSE; \
7253229Spst	if (optype == OP_ADDITION) { \
7263229Spst		if (prs_inetaddr(symbol, &value) < 0) \
7273229Spst			return E_BAD_IPADDR; \
7283229Spst		hp->MEMBER.s_addr = value; \
7293229Spst		hp->flags.MEMBER = TRUE; \
7303229Spst	} \
7313229Spst} while (0)
7323229Spst
7333229Spst/* Parse a list of INET addresses pointed to by MEMBER */
7343229Spst#define PARSE_IAL(MEMBER) do \
7353229Spst{ \
7363229Spst	if (optype == OP_BOOLEAN) \
7373229Spst		return E_SYNTAX_ERROR; \
7383229Spst	if (hp->flags.MEMBER) { \
7393229Spst		hp->flags.MEMBER = FALSE; \
7403229Spst		assert(hp->MEMBER); \
7413229Spst		del_iplist(hp->MEMBER); \
7423229Spst		hp->MEMBER = NULL; \
7433229Spst	} \
7443229Spst	if (optype == OP_ADDITION) { \
7453229Spst		hp->MEMBER = get_addresses(symbol); \
7463229Spst		if (hp->MEMBER == NULL) \
7473229Spst			return E_SYNTAX_ERROR; \
7483229Spst		hp->flags.MEMBER = TRUE; \
7493229Spst	} \
7503229Spst} while (0)
7513229Spst
7523229Spst/* Parse a shared string pointed to by MEMBER */
7533229Spst#define PARSE_STR(MEMBER) do \
7543229Spst{ \
7553229Spst	if (optype == OP_BOOLEAN) \
7563229Spst		return E_SYNTAX_ERROR; \
7573229Spst	if (hp->flags.MEMBER) { \
7583229Spst		hp->flags.MEMBER = FALSE; \
7593229Spst		assert(hp->MEMBER); \
7603229Spst		del_string(hp->MEMBER); \
7613229Spst		hp->MEMBER = NULL; \
7623229Spst	} \
7633229Spst	if (optype == OP_ADDITION) { \
7643229Spst		hp->MEMBER = get_shared_string(symbol); \
7653229Spst		if (hp->MEMBER == NULL) \
7663229Spst			return E_SYNTAX_ERROR; \
7673229Spst		hp->flags.MEMBER = TRUE; \
7683229Spst	} \
7693229Spst} while (0)
7703229Spst
77113572Spst/* Parse an unsigned integer value for MEMBER */
77213572Spst#define PARSE_UINT(MEMBER) do \
7733229Spst{ \
7743229Spst	if (optype == OP_BOOLEAN) \
7753229Spst		return E_SYNTAX_ERROR; \
7763229Spst	hp->flags.MEMBER = FALSE; \
7773229Spst	if (optype == OP_ADDITION) { \
7783229Spst		value = get_u_long(symbol); \
7793229Spst		hp->MEMBER = value; \
7803229Spst		hp->flags.MEMBER = TRUE; \
7813229Spst	} \
7823229Spst} while (0)
7833229Spst
7843229Spst/*
7853229Spst * Evaluate the two-character tag symbol pointed to by "symbol" and place
7863229Spst * the data in the structure pointed to by "hp".  The pointer pointed to
7873229Spst * by "symbol" is updated to point past the source string (but may not
7883229Spst * point to the next tag entry).
7893229Spst *
7903229Spst * Obviously, this need a few more comments. . . .
7913229Spst */
7923229SpstPRIVATE int
7933229Spsteval_symbol(symbol, hp)
7943229Spst	char **symbol;
7953229Spst	struct host *hp;
7963229Spst{
7973229Spst	char tmpstr[MAXSTRINGLEN];
7983229Spst	byte *tmphaddr;
7993229Spst	struct symbolmap *symbolptr;
8003229Spst	u_int32 value;
8013229Spst	int32 timeoff;
8023229Spst	int i, numsymbols;
8033229Spst	unsigned len;
8043229Spst	int optype;					/* Indicates boolean, addition, or deletion */
8053229Spst
8063229Spst	eat_whitespace(symbol);
8073229Spst
8083229Spst	/* Make sure this is set before returning. */
8093229Spst	current_tagname[0] = (*symbol)[0];
8103229Spst	current_tagname[1] = (*symbol)[1];
8113229Spst	current_tagname[2] = 0;
8123229Spst
8133229Spst	if ((*symbol)[0] == '\0') {
8143229Spst		return E_END_OF_ENTRY;
8153229Spst	}
8163229Spst	if ((*symbol)[0] == ':') {
8173229Spst		return SUCCESS;
8183229Spst	}
8193229Spst	if ((*symbol)[0] == 'T') {	/* generic symbol */
8203229Spst		(*symbol)++;
8213229Spst		value = get_u_long(symbol);
82231971Simp		snprintf(current_tagname, sizeof(current_tagname),
82331971Simp			"T%d", (int)value);
8243229Spst		eat_whitespace(symbol);
8253229Spst		if ((*symbol)[0] != '=') {
8263229Spst			return E_SYNTAX_ERROR;
8273229Spst		}
8283229Spst		(*symbol)++;
8293229Spst		if (!(hp->generic)) {
8303229Spst			hp->generic = (struct shared_bindata *)
8313229Spst				smalloc(sizeof(struct shared_bindata));
8323229Spst		}
8333229Spst		if (process_generic(symbol, &(hp->generic), (byte) (value & 0xFF)))
8343229Spst			return E_SYNTAX_ERROR;
8353229Spst		hp->flags.generic = TRUE;
8363229Spst		return SUCCESS;
8373229Spst	}
8383229Spst	/*
8393229Spst	 * Determine the type of operation to be done on this symbol
8403229Spst	 */
8413229Spst	switch ((*symbol)[2]) {
8423229Spst	case '=':
8433229Spst		optype = OP_ADDITION;
8443229Spst		break;
8453229Spst	case '@':
8463229Spst		optype = OP_DELETION;
8473229Spst		break;
8483229Spst	case ':':
8493229Spst	case '\0':
8503229Spst		optype = OP_BOOLEAN;
8513229Spst		break;
8523229Spst	default:
8533229Spst		return E_SYNTAX_ERROR;
8543229Spst	}
8553229Spst
8563229Spst	symbolptr = symbol_list;
8573229Spst	numsymbols = sizeof(symbol_list) / sizeof(struct symbolmap);
8583229Spst	for (i = 0; i < numsymbols; i++) {
8593229Spst		if (((symbolptr->symbol)[0] == (*symbol)[0]) &&
8603229Spst			((symbolptr->symbol)[1] == (*symbol)[1])) {
8613229Spst			break;
8623229Spst		}
8633229Spst		symbolptr++;
8643229Spst	}
8653229Spst	if (i >= numsymbols) {
8663229Spst		return E_UNKNOWN_SYMBOL;
8673229Spst	}
8683229Spst	/*
8693229Spst	 * Skip past the = or @ character (to point to the data) if this
8703229Spst	 * isn't a boolean operation.  For boolean operations, just skip
8713229Spst	 * over the two-character tag symbol (and nothing else. . . .).
8723229Spst	 */
8733229Spst	(*symbol) += (optype == OP_BOOLEAN) ? 2 : 3;
8743229Spst
8753229Spst	eat_whitespace(symbol);
8763229Spst
8773229Spst	/* The cases below are in order by symbolcode value. */
8783229Spst	switch (symbolptr->symbolcode) {
8793229Spst
8803229Spst	case SYM_BOOTFILE:
8813229Spst		PARSE_STR(bootfile);
8823229Spst		break;
8833229Spst
8843229Spst	case SYM_COOKIE_SERVER:
8853229Spst		PARSE_IAL(cookie_server);
8863229Spst		break;
8873229Spst
8883229Spst	case SYM_DOMAIN_SERVER:
8893229Spst		PARSE_IAL(domain_server);
8903229Spst		break;
8913229Spst
8923229Spst	case SYM_GATEWAY:
8933229Spst		PARSE_IAL(gateway);
8943229Spst		break;
8953229Spst
8963229Spst	case SYM_HWADDR:
8973229Spst		if (optype == OP_BOOLEAN)
8983229Spst			return E_SYNTAX_ERROR;
8993229Spst		hp->flags.haddr = FALSE;
9003229Spst		if (optype == OP_ADDITION) {
9013229Spst			/* Default the HW type to Ethernet */
9023229Spst			if (hp->flags.htype == 0) {
9033229Spst				hp->flags.htype = TRUE;
9043229Spst				hp->htype = HTYPE_ETHERNET;
9053229Spst			}
9063229Spst			tmphaddr = prs_haddr(symbol, hp->htype);
9073229Spst			if (!tmphaddr)
9083229Spst				return E_BAD_HWADDR;
9093229Spst			bcopy(tmphaddr, hp->haddr, haddrlength(hp->htype));
9103229Spst			hp->flags.haddr = TRUE;
9113229Spst		}
9123229Spst		break;
9133229Spst
9143229Spst	case SYM_HOMEDIR:
9153229Spst		PARSE_STR(homedir);
9163229Spst		break;
9173229Spst
9183229Spst	case SYM_HTYPE:
9193229Spst		if (optype == OP_BOOLEAN)
9203229Spst			return E_SYNTAX_ERROR;
9213229Spst		hp->flags.htype = FALSE;
9223229Spst		if (optype == OP_ADDITION) {
9233229Spst			value = 0L;			/* Assume an illegal value */
9243229Spst			eat_whitespace(symbol);
9253229Spst			if (isdigit(**symbol)) {
9263229Spst				value = get_u_long(symbol);
9273229Spst			} else {
9283229Spst				len = sizeof(tmpstr);
9293229Spst				(void) get_string(symbol, tmpstr, &len);
9303229Spst				makelower(tmpstr);
9313229Spst				numsymbols = sizeof(htnamemap) /
9323229Spst					sizeof(struct htypename);
9333229Spst				for (i = 0; i < numsymbols; i++) {
9343229Spst					if (!strcmp(htnamemap[i].name, tmpstr)) {
9353229Spst						break;
9363229Spst					}
9373229Spst				}
9383229Spst				if (i < numsymbols) {
9393229Spst					value = htnamemap[i].htype;
9403229Spst				}
9413229Spst			}
9423229Spst			if (value >= hwinfocnt) {
9433229Spst				return E_BAD_HWATYPE;
9443229Spst			}
9453229Spst			hp->htype = (byte) (value & 0xFF);
9463229Spst			hp->flags.htype = TRUE;
9473229Spst		}
9483229Spst		break;
9493229Spst
9503229Spst	case SYM_IMPRESS_SERVER:
9513229Spst		PARSE_IAL(impress_server);
9523229Spst		break;
9533229Spst
9543229Spst	case SYM_IPADDR:
9553229Spst		PARSE_IA1(iaddr);
9563229Spst		break;
9573229Spst
9583229Spst	case SYM_LOG_SERVER:
9593229Spst		PARSE_IAL(log_server);
9603229Spst		break;
9613229Spst
9623229Spst	case SYM_LPR_SERVER:
9633229Spst		PARSE_IAL(lpr_server);
9643229Spst		break;
9653229Spst
9663229Spst	case SYM_NAME_SERVER:
9673229Spst		PARSE_IAL(name_server);
9683229Spst		break;
9693229Spst
9703229Spst	case SYM_RLP_SERVER:
9713229Spst		PARSE_IAL(rlp_server);
9723229Spst		break;
9733229Spst
9743229Spst	case SYM_SUBNET_MASK:
9753229Spst		PARSE_IA1(subnet_mask);
9763229Spst		break;
9773229Spst
9783229Spst	case SYM_TIME_OFFSET:
9793229Spst		if (optype == OP_BOOLEAN)
9803229Spst			return E_SYNTAX_ERROR;
9813229Spst		hp->flags.time_offset = FALSE;
9823229Spst		if (optype == OP_ADDITION) {
9833229Spst			len = sizeof(tmpstr);
9843229Spst			(void) get_string(symbol, tmpstr, &len);
9853229Spst			if (!strncmp(tmpstr, "auto", 4)) {
9863229Spst				hp->time_offset = secondswest;
9873229Spst			} else {
98813572Spst				if (sscanf(tmpstr, "%d", (int*)&timeoff) != 1)
9893229Spst					return E_BAD_LONGWORD;
9903229Spst				hp->time_offset = timeoff;
9913229Spst			}
9923229Spst			hp->flags.time_offset = TRUE;
9933229Spst		}
9943229Spst		break;
9953229Spst
9963229Spst	case SYM_TIME_SERVER:
9973229Spst		PARSE_IAL(time_server);
9983229Spst		break;
9993229Spst
10003229Spst	case SYM_VENDOR_MAGIC:
10013229Spst		if (optype == OP_BOOLEAN)
10023229Spst			return E_SYNTAX_ERROR;
10033229Spst		hp->flags.vm_cookie = FALSE;
10043229Spst		if (optype == OP_ADDITION) {
10053229Spst			if (strncmp(*symbol, "auto", 4)) {
10063229Spst				/* The string is not "auto" */
10073229Spst				if (!strncmp(*symbol, "rfc", 3)) {
10083229Spst					bcopy(vm_rfc1048, hp->vm_cookie, 4);
10093229Spst				} else if (!strncmp(*symbol, "cmu", 3)) {
10103229Spst					bcopy(vm_cmu, hp->vm_cookie, 4);
10113229Spst				} else {
10123229Spst					if (!isdigit(**symbol))
10133229Spst						return E_BAD_IPADDR;
10143229Spst					if (prs_inetaddr(symbol, &value) < 0)
10153229Spst						return E_BAD_IPADDR;
10163229Spst					bcopy(&value, hp->vm_cookie, 4);
10173229Spst				}
10183229Spst				hp->flags.vm_cookie = TRUE;
10193229Spst			}
10203229Spst		}
10213229Spst		break;
10223229Spst
10233229Spst	case SYM_SIMILAR_ENTRY:
10243229Spst		switch (optype) {
10253229Spst		case OP_ADDITION:
10263229Spst			fill_defaults(hp, symbol);
10273229Spst			break;
10283229Spst		default:
10293229Spst			return E_SYNTAX_ERROR;
10303229Spst		}
10313229Spst		break;
10323229Spst
10333229Spst	case SYM_NAME_SWITCH:
10343229Spst		switch (optype) {
10353229Spst		case OP_ADDITION:
10363229Spst			return E_SYNTAX_ERROR;
10373229Spst		case OP_DELETION:
10383229Spst			hp->flags.send_name = FALSE;
10393229Spst			hp->flags.name_switch = FALSE;
10403229Spst			break;
10413229Spst		case OP_BOOLEAN:
10423229Spst			hp->flags.send_name = TRUE;
10433229Spst			hp->flags.name_switch = TRUE;
10443229Spst			break;
10453229Spst		}
10463229Spst		break;
10473229Spst
10483229Spst	case SYM_BOOTSIZE:
10493229Spst		switch (optype) {
10503229Spst		case OP_ADDITION:
10513229Spst			if (!strncmp(*symbol, "auto", 4)) {
10523229Spst				hp->flags.bootsize = TRUE;
10533229Spst				hp->flags.bootsize_auto = TRUE;
10543229Spst			} else {
10553229Spst				hp->bootsize = (unsigned int) get_u_long(symbol);
10563229Spst				hp->flags.bootsize = TRUE;
10573229Spst				hp->flags.bootsize_auto = FALSE;
10583229Spst			}
10593229Spst			break;
10603229Spst		case OP_DELETION:
10613229Spst			hp->flags.bootsize = FALSE;
10623229Spst			break;
10633229Spst		case OP_BOOLEAN:
10643229Spst			hp->flags.bootsize = TRUE;
10653229Spst			hp->flags.bootsize_auto = TRUE;
10663229Spst			break;
10673229Spst		}
10683229Spst		break;
10693229Spst
10703229Spst	case SYM_BOOT_SERVER:
10713229Spst		PARSE_IA1(bootserver);
10723229Spst		break;
10733229Spst
10743229Spst	case SYM_TFTPDIR:
10753229Spst		PARSE_STR(tftpdir);
10763229Spst		if ((hp->tftpdir != NULL) &&
10773229Spst			(hp->tftpdir->string[0] != '/'))
10783229Spst			return E_BAD_PATHNAME;
10793229Spst		break;
10803229Spst
10813229Spst	case SYM_DUMP_FILE:
10823229Spst		PARSE_STR(dump_file);
10833229Spst		break;
10843229Spst
10853229Spst	case SYM_DOMAIN_NAME:
10863229Spst		PARSE_STR(domain_name);
10873229Spst		break;
10883229Spst
10893229Spst	case SYM_SWAP_SERVER:
10903229Spst		PARSE_IA1(swap_server);
10913229Spst		break;
10923229Spst
10933229Spst	case SYM_ROOT_PATH:
10943229Spst		PARSE_STR(root_path);
10953229Spst		break;
10963229Spst
10973229Spst	case SYM_EXTEN_FILE:
10983229Spst		PARSE_STR(exten_file);
10993229Spst		break;
11003229Spst
11013229Spst	case SYM_REPLY_ADDR:
11023229Spst		PARSE_IA1(reply_addr);
11033229Spst		break;
11043229Spst
11053229Spst	case SYM_NIS_DOMAIN:
11063229Spst		PARSE_STR(nis_domain);
11073229Spst		break;
11083229Spst
11093229Spst	case SYM_NIS_SERVER:
11103229Spst		PARSE_IAL(nis_server);
11113229Spst		break;
11123229Spst
11133229Spst	case SYM_NTP_SERVER:
11143229Spst		PARSE_IAL(ntp_server);
11153229Spst		break;
11163229Spst
11173229Spst#ifdef	YORK_EX_OPTION
11183229Spst	case SYM_EXEC_FILE:
11193229Spst		PARSE_STR(exec_file);
11203229Spst		break;
11213229Spst#endif
11223229Spst
11233229Spst	case SYM_MSG_SIZE:
112413572Spst		PARSE_UINT(msg_size);
11253229Spst		if (hp->msg_size < BP_MINPKTSZ ||
11263229Spst			hp->msg_size > MAX_MSG_SIZE)
11273229Spst			return E_BAD_VALUE;
11283229Spst		break;
11293229Spst
11303229Spst	case SYM_MIN_WAIT:
113113572Spst		PARSE_UINT(min_wait);
11323229Spst		break;
11333229Spst
11343229Spst		/* XXX - Add new tags here */
11353229Spst
11363229Spst	default:
11373229Spst		return E_UNKNOWN_SYMBOL;
11383229Spst
11393229Spst	}							/* switch symbolcode */
11403229Spst
11413229Spst	return SUCCESS;
11423229Spst}
11433229Spst#undef	PARSE_IA1
11443229Spst#undef	PARSE_IAL
11453229Spst#undef	PARSE_STR
11463229Spst
11473229Spst
11483229Spst
11493229Spst
11503229Spst/*
11513229Spst * Read a string from the buffer indirectly pointed to through "src" and
11523229Spst * move it into the buffer pointed to by "dest".  A pointer to the maximum
11533229Spst * allowable length of the string (including null-terminator) is passed as
11543229Spst * "length".  The actual length of the string which was read is returned in
11553229Spst * the unsigned integer pointed to by "length".  This value is the same as
11563229Spst * that which would be returned by applying the strlen() function on the
11573229Spst * destination string (i.e the terminating null is not counted as a
11583229Spst * character).  Trailing whitespace is removed from the string.  For
11593229Spst * convenience, the function returns the new value of "dest".
11603229Spst *
11613229Spst * The string is read until the maximum number of characters, an unquoted
11623229Spst * colon (:), or a null character is read.  The return string in "dest" is
11633229Spst * null-terminated.
11643229Spst */
11653229Spst
11663229SpstPRIVATE char *
11673229Spstget_string(src, dest, length)
11683229Spst	char **src, *dest;
11693229Spst	unsigned *length;
11703229Spst{
11713229Spst	int n, len, quoteflag;
11723229Spst
11733229Spst	quoteflag = FALSE;
11743229Spst	n = 0;
11753229Spst	len = *length - 1;
11763229Spst	while ((n < len) && (**src)) {
11773229Spst		if (!quoteflag && (**src == ':')) {
11783229Spst			break;
11793229Spst		}
11803229Spst		if (**src == '"') {
11813229Spst			(*src)++;
11823229Spst			quoteflag = !quoteflag;
11833229Spst			continue;
11843229Spst		}
11853229Spst		if (**src == '\\') {
11863229Spst			(*src)++;
11873229Spst			if (!**src) {
11883229Spst				break;
11893229Spst			}
11903229Spst		}
11913229Spst		*dest++ = *(*src)++;
11923229Spst		n++;
11933229Spst	}
11943229Spst
11953229Spst	/*
11963229Spst	 * Remove that troublesome trailing whitespace. . .
11973229Spst	 */
11983229Spst	while ((n > 0) && isspace(dest[-1])) {
11993229Spst		dest--;
12003229Spst		n--;
12013229Spst	}
12023229Spst
12033229Spst	*dest = '\0';
12043229Spst	*length = n;
12053229Spst	return dest;
12063229Spst}
12073229Spst
12083229Spst
12093229Spst
12103229Spst/*
12113229Spst * Read the string indirectly pointed to by "src", update the caller's
12123229Spst * pointer, and return a pointer to a malloc'ed shared_string structure
12133229Spst * containing the string.
12143229Spst *
12153229Spst * The string is read using the same rules as get_string() above.
12163229Spst */
12173229Spst
12183229SpstPRIVATE struct shared_string *
12193229Spstget_shared_string(src)
12203229Spst	char **src;
12213229Spst{
12223229Spst	char retstring[MAXSTRINGLEN];
12233229Spst	struct shared_string *s;
12243229Spst	unsigned length;
12253229Spst
12263229Spst	length = sizeof(retstring);
12273229Spst	(void) get_string(src, retstring, &length);
12283229Spst
12293229Spst	s = (struct shared_string *) smalloc(sizeof(struct shared_string)
12303229Spst										 + length);
12313229Spst	s->linkcount = 1;
12323229Spst	strcpy(s->string, retstring);
12333229Spst
12343229Spst	return s;
12353229Spst}
12363229Spst
12373229Spst
12383229Spst
12393229Spst/*
12403229Spst * Load RFC1048 generic information directly into a memory buffer.
12413229Spst *
12423229Spst * "src" indirectly points to the ASCII representation of the generic data.
12433229Spst * "dest" points to a string structure which is updated to point to a new
12443229Spst * string with the new data appended to the old string.  The old string is
12453229Spst * freed.
12463229Spst *
12473229Spst * The given tag value is inserted with the new data.
12483229Spst *
12493229Spst * The data may be represented as either a stream of hexadecimal numbers
12503229Spst * representing bytes (any or all bytes may optionally start with '0x' and
12513229Spst * be separated with periods ".") or as a quoted string of ASCII
12523229Spst * characters (the quotes are required).
12533229Spst */
12543229Spst
12553229SpstPRIVATE int
12563229Spstprocess_generic(src, dest, tagvalue)
12573229Spst	char **src;
12583229Spst	struct shared_bindata **dest;
12593229Spst	u_int tagvalue;
12603229Spst{
12613229Spst	byte tmpbuf[MAXBUFLEN];
12623229Spst	byte *str;
12633229Spst	struct shared_bindata *bdata;
12643229Spst	u_int newlength, oldlength;
12653229Spst
12663229Spst	str = tmpbuf;
12673229Spst	*str++ = (tagvalue & 0xFF);	/* Store tag value */
12683229Spst	str++;						/* Skip over length field */
12693229Spst	if ((*src)[0] == '"') {		/* ASCII data */
12703229Spst		newlength = sizeof(tmpbuf) - 2;	/* Set maximum allowed length */
12713229Spst		(void) get_string(src, (char *) str, &newlength);
12723229Spst		newlength++;			/* null terminator */
12733229Spst	} else {					/* Numeric data */
12743229Spst		newlength = 0;
12753229Spst		while (newlength < sizeof(tmpbuf) - 2) {
12763229Spst			if (interp_byte(src, str++) < 0)
12773229Spst				break;
12783229Spst			newlength++;
12793229Spst			if (**src == '.') {
12803229Spst				(*src)++;
12813229Spst			}
12823229Spst		}
12833229Spst	}
12843229Spst	if ((*src)[0] != ':')
12853229Spst		return -1;
12863229Spst
12873229Spst	tmpbuf[1] = (newlength & 0xFF);
12883229Spst	oldlength = ((*dest)->length);
12893229Spst	bdata = (struct shared_bindata *) smalloc(sizeof(struct shared_bindata)
12903229Spst											+ oldlength + newlength + 1);
12913229Spst	if (oldlength > 0) {
12923229Spst		bcopy((*dest)->data, bdata->data, oldlength);
12933229Spst	}
12943229Spst	bcopy(tmpbuf, bdata->data + oldlength, newlength + 2);
12953229Spst	bdata->length = oldlength + newlength + 2;
12963229Spst	bdata->linkcount = 1;
12973229Spst	if (*dest) {
12983229Spst		del_bindata(*dest);
12993229Spst	}
13003229Spst	*dest = bdata;
13013229Spst	return 0;
13023229Spst}
13033229Spst
13043229Spst
13053229Spst
13063229Spst/*
13073229Spst * Verify that the given string makes sense as a hostname (according to
13083229Spst * Appendix 1, page 29 of RFC882).
13093229Spst *
13103229Spst * Return TRUE for good names, FALSE otherwise.
13113229Spst */
13123229Spst
13133229SpstPRIVATE boolean
13143229Spstgoodname(hostname)
13153229Spst	register char *hostname;
13163229Spst{
13173229Spst	do {
13183229Spst		if (!isalpha(*hostname++)) {	/* First character must be a letter */
13193229Spst			return FALSE;
13203229Spst		}
13213229Spst		while (isalnum(*hostname) ||
13223229Spst			   (*hostname == '-') ||
13233229Spst			   (*hostname == '_') )
13243229Spst		{
13253229Spst			hostname++;			/* Alphanumeric or a hyphen */
13263229Spst		}
13273229Spst		if (!isalnum(hostname[-1])) {	/* Last must be alphanumeric */
13283229Spst			return FALSE;
13293229Spst		}
13303229Spst		if (*hostname == '\0') {/* Done? */
13313229Spst			return TRUE;
13323229Spst		}
13333229Spst	} while (*hostname++ == '.');	/* Dot, loop for next label */
13343229Spst
13353229Spst	return FALSE;				/* If it's not a dot, lose */
13363229Spst}
13373229Spst
13383229Spst
13393229Spst
13403229Spst/*
13413229Spst * Null compare function -- always returns FALSE so an element is always
13423229Spst * inserted into a hash table (i.e. there is never a collision with an
13433229Spst * existing element).
13443229Spst */
13453229Spst
13463229SpstPRIVATE boolean
13473229Spstnullcmp(d1, d2)
13483229Spst	hash_datum *d1, *d2;
13493229Spst{
13503229Spst	return FALSE;
13513229Spst}
13523229Spst
13533229Spst
13543229Spst/*
13553229Spst * Function for comparing a string with the hostname field of a host
13563229Spst * structure.
13573229Spst */
13583229Spst
13593229Spstboolean
13603229Spstnmcmp(d1, d2)
13613229Spst	hash_datum *d1, *d2;
13623229Spst{
13633229Spst	char *name = (char *) d1;	/* XXX - OK? */
13643229Spst	struct host *hp = (struct host *) d2;
13653229Spst
13663229Spst	return !strcmp(name, hp->hostname->string);
13673229Spst}
13683229Spst
13693229Spst
13703229Spst/*
13713229Spst * Compare function to determine whether two hardware addresses are
13723229Spst * equivalent.  Returns TRUE if "host1" and "host2" are equivalent, FALSE
13733229Spst * otherwise.
13743229Spst *
13753229Spst * If the hardware addresses of "host1" and "host2" are identical, but
13763229Spst * they are on different IP subnets, this function returns FALSE.
13773229Spst *
13783229Spst * This function is used when inserting elements into the hardware address
13793229Spst * hash table.
13803229Spst */
13813229Spst
13823229SpstPRIVATE boolean
13833229Spsthwinscmp(d1, d2)
13843229Spst	hash_datum *d1, *d2;
13853229Spst{
13863229Spst	struct host *host1 = (struct host *) d1;
13873229Spst	struct host *host2 = (struct host *) d2;
13883229Spst
13893229Spst	if (host1->htype != host2->htype) {
13903229Spst		return FALSE;
13913229Spst	}
13923229Spst	if (bcmp(host1->haddr, host2->haddr, haddrlength(host1->htype))) {
13933229Spst		return FALSE;
13943229Spst	}
13953229Spst	/* XXX - Is the subnet_mask field set yet? */
13963229Spst	if ((host1->subnet_mask.s_addr) == (host2->subnet_mask.s_addr)) {
13973229Spst		if (((host1->iaddr.s_addr) & (host1->subnet_mask.s_addr)) !=
13983229Spst			((host2->iaddr.s_addr) & (host2->subnet_mask.s_addr)))
13993229Spst		{
14003229Spst			return FALSE;
14013229Spst		}
14023229Spst	}
14033229Spst	return TRUE;
14043229Spst}
14053229Spst
14063229Spst
14073229Spst/*
14083229Spst * Macros for use in the function below:
14093229Spst */
14103229Spst
14113229Spst#define DUP_COPY(MEMBER) do \
14123229Spst{ \
14133229Spst	if (!hp->flags.MEMBER) { \
14143229Spst		if ((hp->flags.MEMBER = hp2->flags.MEMBER) != 0) { \
14153229Spst			hp->MEMBER = hp2->MEMBER; \
14163229Spst		} \
14173229Spst	} \
14183229Spst} while (0)
14193229Spst
14203229Spst#define DUP_LINK(MEMBER) do \
14213229Spst{ \
14223229Spst	if (!hp->flags.MEMBER) { \
14233229Spst		if ((hp->flags.MEMBER = hp2->flags.MEMBER) != 0) { \
14243229Spst			assert(hp2->MEMBER); \
14253229Spst			hp->MEMBER = hp2->MEMBER; \
14263229Spst			(hp->MEMBER->linkcount)++; \
14273229Spst		} \
14283229Spst	} \
14293229Spst} while (0)
14303229Spst
14313229Spst/*
14323229Spst * Process the "similar entry" symbol.
14333229Spst *
14343229Spst * The host specified as the value of the "tc" symbol is used as a template
14353229Spst * for the current host entry.  Symbol values not explicitly set in the
14363229Spst * current host entry are inferred from the template entry.
14373229Spst */
14383229SpstPRIVATE void
14393229Spstfill_defaults(hp, src)
14403229Spst	struct host *hp;
14413229Spst	char **src;
14423229Spst{
14433229Spst	unsigned int tlen, hashcode;
14443229Spst	struct host *hp2;
14453229Spst	char tstring[MAXSTRINGLEN];
14463229Spst
14473229Spst	tlen = sizeof(tstring);
14483229Spst	(void) get_string(src, tstring, &tlen);
14493229Spst	hashcode = hash_HashFunction((u_char *) tstring, tlen);
14503229Spst	hp2 = (struct host *) hash_Lookup(nmhashtable, hashcode, nmcmp, tstring);
14513229Spst
14523229Spst	if (hp2 == NULL) {
14533229Spst		report(LOG_ERR, "can't find tc=\"%s\"", tstring);
14543229Spst		return;
14553229Spst	}
14563229Spst	DUP_LINK(bootfile);
14573229Spst	DUP_LINK(cookie_server);
14583229Spst	DUP_LINK(domain_server);
14593229Spst	DUP_LINK(gateway);
14603229Spst	/* haddr not copied */
14613229Spst	DUP_LINK(homedir);
14623229Spst	DUP_COPY(htype);
14633229Spst
14643229Spst	DUP_LINK(impress_server);
14653229Spst	/* iaddr not copied */
14663229Spst	DUP_LINK(log_server);
14673229Spst	DUP_LINK(lpr_server);
14683229Spst	DUP_LINK(name_server);
14693229Spst	DUP_LINK(rlp_server);
14703229Spst
14713229Spst	DUP_COPY(subnet_mask);
14723229Spst	DUP_COPY(time_offset);
14733229Spst	DUP_LINK(time_server);
14743229Spst
14753229Spst	if (!hp->flags.vm_cookie) {
14763229Spst		if ((hp->flags.vm_cookie = hp2->flags.vm_cookie)) {
14773229Spst			bcopy(hp2->vm_cookie, hp->vm_cookie, 4);
14783229Spst		}
14793229Spst	}
14803229Spst	if (!hp->flags.name_switch) {
14813229Spst		if ((hp->flags.name_switch = hp2->flags.name_switch)) {
14823229Spst			hp->flags.send_name = hp2->flags.send_name;
14833229Spst		}
14843229Spst	}
14853229Spst	if (!hp->flags.bootsize) {
14863229Spst		if ((hp->flags.bootsize = hp2->flags.bootsize)) {
14873229Spst			hp->flags.bootsize_auto = hp2->flags.bootsize_auto;
14883229Spst			hp->bootsize = hp2->bootsize;
14893229Spst		}
14903229Spst	}
14913229Spst	DUP_COPY(bootserver);
14923229Spst
14933229Spst	DUP_LINK(tftpdir);
14943229Spst	DUP_LINK(dump_file);
14953229Spst	DUP_LINK(domain_name);
14963229Spst
14973229Spst	DUP_COPY(swap_server);
14983229Spst	DUP_LINK(root_path);
14993229Spst	DUP_LINK(exten_file);
15003229Spst
15013229Spst	DUP_COPY(reply_addr);
15023229Spst
15033229Spst	DUP_LINK(nis_domain);
15043229Spst	DUP_LINK(nis_server);
15053229Spst	DUP_LINK(ntp_server);
15063229Spst
15073229Spst#ifdef	YORK_EX_OPTION
15083229Spst	DUP_LINK(exec_file);
15093229Spst#endif
15103229Spst
15113229Spst	DUP_COPY(msg_size);
15123229Spst	DUP_COPY(min_wait);
15133229Spst
15143229Spst	/* XXX - Add new tags here */
15153229Spst
15163229Spst	DUP_LINK(generic);
15173229Spst
15183229Spst}
15193229Spst#undef	DUP_COPY
15203229Spst#undef	DUP_LINK
15213229Spst
15223229Spst
15233229Spst
15243229Spst/*
15253229Spst * This function adjusts the caller's pointer to point just past the
15263229Spst * first-encountered colon.  If it runs into a null character, it leaves
15273229Spst * the pointer pointing to it.
15283229Spst */
15293229Spst
15303229SpstPRIVATE void
15313229Spstadjust(s)
15323229Spst	char **s;
15333229Spst{
15343229Spst	register char *t;
15353229Spst
15363229Spst	t = *s;
15373229Spst	while (*t && (*t != ':')) {
15383229Spst		t++;
15393229Spst	}
15403229Spst	if (*t) {
15413229Spst		t++;
15423229Spst	}
15433229Spst	*s = t;
15443229Spst}
15453229Spst
15463229Spst
15473229Spst
15483229Spst
15493229Spst/*
15503229Spst * This function adjusts the caller's pointer to point to the first
15513229Spst * non-whitespace character.  If it runs into a null character, it leaves
15523229Spst * the pointer pointing to it.
15533229Spst */
15543229Spst
15553229SpstPRIVATE void
15563229Spsteat_whitespace(s)
15573229Spst	char **s;
15583229Spst{
15593229Spst	register char *t;
15603229Spst
15613229Spst	t = *s;
15623229Spst	while (*t && isspace(*t)) {
15633229Spst		t++;
15643229Spst	}
15653229Spst	*s = t;
15663229Spst}
15673229Spst
15683229Spst
15693229Spst
15703229Spst/*
15713229Spst * This function converts the given string to all lowercase.
15723229Spst */
15733229Spst
15743229SpstPRIVATE void
15753229Spstmakelower(s)
15763229Spst	char *s;
15773229Spst{
15783229Spst	while (*s) {
15793229Spst		if (isupper(*s)) {
15803229Spst			*s = tolower(*s);
15813229Spst		}
15823229Spst		s++;
15833229Spst	}
15843229Spst}
15853229Spst
15863229Spst
15873229Spst
15883229Spst/*
15893229Spst *
15903229Spst *	N O T E :
15913229Spst *
15923229Spst *	In many of the functions which follow, a parameter such as "src" or
15933229Spst *	"symbol" is passed as a pointer to a pointer to something.  This is
15943229Spst *	done for the purpose of letting the called function update the
15953229Spst *	caller's copy of the parameter (i.e. to effect call-by-reference
15963229Spst *	parameter passing).  The value of the actual parameter is only used
15973229Spst *	to locate the real parameter of interest and then update this indirect
15983229Spst *	parameter.
15993229Spst *
16003229Spst *	I'm sure somebody out there won't like this. . . .
16013229Spst *  (Yea, because it usually makes code slower... -gwr)
16023229Spst *
16033229Spst */
16043229Spst
16053229Spst
16063229Spst
16073229Spst/*
16083229Spst * "src" points to a character pointer which points to an ASCII string of
16093229Spst * whitespace-separated IP addresses.  A pointer to an in_addr_list
16103229Spst * structure containing the list of addresses is returned.  NULL is
16113229Spst * returned if no addresses were found at all.  The pointer pointed to by
16123229Spst * "src" is updated to point to the first non-address (illegal) character.
16133229Spst */
16143229Spst
16153229SpstPRIVATE struct in_addr_list *
16163229Spstget_addresses(src)
16173229Spst	char **src;
16183229Spst{
16193229Spst	struct in_addr tmpaddrlist[MAXINADDRS];
16203229Spst	struct in_addr *address1, *address2;
16213229Spst	struct in_addr_list *result;
16223229Spst	unsigned addrcount, totalsize;
16233229Spst
16243229Spst	address1 = tmpaddrlist;
16253229Spst	for (addrcount = 0; addrcount < MAXINADDRS; addrcount++) {
16263229Spst		while (isspace(**src) || (**src == ',')) {
16273229Spst			(*src)++;
16283229Spst		}
16293229Spst		if (!**src) {			/* Quit if nothing more */
16303229Spst			break;
16313229Spst		}
16323229Spst		if (prs_inetaddr(src, &(address1->s_addr)) < 0) {
16333229Spst			break;
16343229Spst		}
16353229Spst		address1++;				/* Point to next address slot */
16363229Spst	}
16373229Spst	if (addrcount < 1) {
16383229Spst		result = NULL;
16393229Spst	} else {
16403229Spst		totalsize = sizeof(struct in_addr_list)
16413229Spst		+			(addrcount - 1) * sizeof(struct in_addr);
16423229Spst		result = (struct in_addr_list *) smalloc(totalsize);
16433229Spst		result->linkcount = 1;
16443229Spst		result->addrcount = addrcount;
16453229Spst		address1 = tmpaddrlist;
16463229Spst		address2 = result->addr;
16473229Spst		for (; addrcount > 0; addrcount--) {
16483229Spst			address2->s_addr = address1->s_addr;
16493229Spst			address1++;
16503229Spst			address2++;
16513229Spst		}
16523229Spst	}
16533229Spst	return result;
16543229Spst}
16553229Spst
16563229Spst
16573229Spst
16583229Spst/*
16593229Spst * prs_inetaddr(src, result)
16603229Spst *
16613229Spst * "src" is a value-result parameter; the pointer it points to is updated
16623229Spst * to point to the next data position.   "result" points to an unsigned long
16633229Spst * in which an address is returned.
16643229Spst *
16653229Spst * This function parses the IP address string in ASCII "dot notation" pointed
16663229Spst * to by (*src) and places the result (in network byte order) in the unsigned
16673229Spst * long pointed to by "result".  For malformed addresses, -1 is returned,
16683229Spst * (*src) points to the first illegal character, and the unsigned long pointed
16693229Spst * to by "result" is unchanged.  Successful calls return 0.
16703229Spst */
16713229Spst
16723229SpstPRIVATE int
16733229Spstprs_inetaddr(src, result)
16743229Spst	char **src;
16753229Spst	u_int32 *result;
16763229Spst{
16773229Spst	char tmpstr[MAXSTRINGLEN];
16783229Spst	register u_int32 value;
16793229Spst	u_int32 parts[4], *pp;
16803229Spst	int n;
16813229Spst	char *s, *t;
16823229Spst
16833229Spst	/* Leading alpha char causes IP addr lookup. */
16843229Spst	if (isalpha(**src)) {
16853229Spst		/* Lookup IP address. */
16863229Spst		s = *src;
16873229Spst		t = tmpstr;
16883229Spst		while ((isalnum(*s) || (*s == '.') ||
16893229Spst				(*s == '-') || (*s == '_') ) &&
16903229Spst			   (t < &tmpstr[MAXSTRINGLEN - 1]) )
16913229Spst			*t++ = *s++;
16923229Spst		*t = '\0';
16933229Spst		*src = s;
16943229Spst
16953229Spst		n = lookup_ipa(tmpstr, result);
16963229Spst		if (n < 0)
16973229Spst			report(LOG_ERR, "can not get IP addr for %s", tmpstr);
16983229Spst		return n;
16993229Spst	}
17003229Spst
17013229Spst	/*
17023229Spst	 * Parse an address in Internet format:
17033229Spst	 *	a.b.c.d
17043229Spst	 *	a.b.c	(with c treated as 16-bits)
17053229Spst	 *	a.b	(with b treated as 24 bits)
17063229Spst	 */
17073229Spst	pp = parts;
17083229Spst  loop:
17093229Spst	/* If it's not a digit, return error. */
17103229Spst	if (!isdigit(**src))
17113229Spst		return -1;
17123229Spst	*pp++ = get_u_long(src);
17133229Spst	if (**src == '.') {
17143229Spst		if (pp < (parts + 4)) {
17153229Spst			(*src)++;
17163229Spst			goto loop;
17173229Spst		}
17183229Spst		return (-1);
17193229Spst	}
17203229Spst#if 0
17213229Spst	/* This is handled by the caller. */
17223229Spst	if (**src && !(isspace(**src) || (**src == ':'))) {
17233229Spst		return (-1);
17243229Spst	}
17253229Spst#endif
17263229Spst
17273229Spst	/*
17283229Spst	 * Construct the address according to
17293229Spst	 * the number of parts specified.
17303229Spst	 */
17313229Spst	n = pp - parts;
17323229Spst	switch (n) {
17333229Spst	case 1:					/* a -- 32 bits */
17343229Spst		value = parts[0];
17353229Spst		break;
17363229Spst	case 2:					/* a.b -- 8.24 bits */
17373229Spst		value = (parts[0] << 24) | (parts[1] & 0xFFFFFF);
17383229Spst		break;
17393229Spst	case 3:					/* a.b.c -- 8.8.16 bits */
17403229Spst		value = (parts[0] << 24) | ((parts[1] & 0xFF) << 16) |
17413229Spst			(parts[2] & 0xFFFF);
17423229Spst		break;
17433229Spst	case 4:					/* a.b.c.d -- 8.8.8.8 bits */
17443229Spst		value = (parts[0] << 24) | ((parts[1] & 0xFF) << 16) |
17453229Spst			((parts[2] & 0xFF) << 8) | (parts[3] & 0xFF);
17463229Spst		break;
17473229Spst	default:
17483229Spst		return (-1);
17493229Spst	}
17503229Spst	*result = htonl(value);
17513229Spst	return (0);
17523229Spst}
17533229Spst
17543229Spst
17553229Spst
17563229Spst/*
17573229Spst * "src" points to a pointer which in turn points to a hexadecimal ASCII
17583229Spst * string.  This string is interpreted as a hardware address and returned
17593229Spst * as a pointer to the actual hardware address, represented as an array of
17603229Spst * bytes.
17613229Spst *
17623229Spst * The ASCII string must have the proper number of digits for the specified
17633229Spst * hardware type (e.g. twelve digits for a 48-bit Ethernet address).
17643229Spst * Two-digit sequences (bytes) may be separated with periods (.)  and/or
17653229Spst * prefixed with '0x' for readability, but this is not required.
17663229Spst *
17673229Spst * For bad addresses, the pointer which "src" points to is updated to point
17683229Spst * to the start of the first two-digit sequence which was bad, and the
17693229Spst * function returns a NULL pointer.
17703229Spst */
17713229Spst
17723229SpstPRIVATE byte *
17733229Spstprs_haddr(src, htype)
17743229Spst	char **src;
17753229Spst	u_int htype;
17763229Spst{
17773229Spst	static byte haddr[MAXHADDRLEN];
17783229Spst	byte *hap;
17793229Spst	char tmpstr[MAXSTRINGLEN];
17803229Spst	u_int tmplen;
17813229Spst	unsigned hal;
17823229Spst	char *p;
17833229Spst
17843229Spst	hal = haddrlength(htype);	/* Get length of this address type */
17853229Spst	if (hal <= 0) {
17863229Spst		report(LOG_ERR, "Invalid addr type for HW addr parse");
17873229Spst		return NULL;
17883229Spst	}
17893229Spst	tmplen = sizeof(tmpstr);
17903229Spst	get_string(src, tmpstr, &tmplen);
17913229Spst	p = tmpstr;
17923229Spst
17933229Spst	/* If it's a valid host name, try to lookup the HW address. */
17943229Spst	if (goodname(p)) {
17953229Spst		/* Lookup Hardware Address for hostname. */
17963229Spst		if ((hap = lookup_hwa(p, htype)) != NULL)
17973229Spst			return hap; /* success */
17983229Spst		report(LOG_ERR, "Add 0x prefix if hex value starts with A-F");
17993229Spst		/* OK, assume it must be numeric. */
18003229Spst	}
18013229Spst
18023229Spst	hap = haddr;
18033229Spst	while (hap < haddr + hal) {
180413572Spst		if ((*p == '.') || (*p == ':'))
18053229Spst			p++;
18063229Spst		if (interp_byte(&p, hap++) < 0) {
18073229Spst			return NULL;
18083229Spst		}
18093229Spst	}
18103229Spst	return haddr;
18113229Spst}
18123229Spst
18133229Spst
18143229Spst
18153229Spst/*
18163229Spst * "src" is a pointer to a character pointer which in turn points to a
18173229Spst * hexadecimal ASCII representation of a byte.  This byte is read, the
18183229Spst * character pointer is updated, and the result is deposited into the
18193229Spst * byte pointed to by "retbyte".
18203229Spst *
18213229Spst * The usual '0x' notation is allowed but not required.  The number must be
18223229Spst * a two digit hexadecimal number.  If the number is invalid, "src" and
18233229Spst * "retbyte" are left untouched and -1 is returned as the function value.
18243229Spst * Successful calls return 0.
18253229Spst */
18263229Spst
18273229SpstPRIVATE int
18283229Spstinterp_byte(src, retbyte)
18293229Spst	char **src;
18303229Spst	byte *retbyte;
18313229Spst{
18323229Spst	int v;
18333229Spst
18343229Spst	if ((*src)[0] == '0' &&
18353229Spst		((*src)[1] == 'x' ||
18363229Spst		 (*src)[1] == 'X')) {
18373229Spst		(*src) += 2;			/* allow 0x for hex, but don't require it */
18383229Spst	}
18393229Spst	if (!isxdigit((*src)[0]) || !isxdigit((*src)[1])) {
18403229Spst		return -1;
18413229Spst	}
18423229Spst	if (sscanf(*src, "%2x", &v) != 1) {
18433229Spst		return -1;
18443229Spst	}
18453229Spst	(*src) += 2;
18463229Spst	*retbyte = (byte) (v & 0xFF);
18473229Spst	return 0;
18483229Spst}
18493229Spst
18503229Spst
18513229Spst
18523229Spst/*
18533229Spst * The parameter "src" points to a character pointer which points to an
18543229Spst * ASCII string representation of an unsigned number.  The number is
18553229Spst * returned as an unsigned long and the character pointer is updated to
18563229Spst * point to the first illegal character.
18573229Spst */
18583229Spst
18593229SpstPRIVATE u_int32
18603229Spstget_u_long(src)
18613229Spst	char **src;
18623229Spst{
18633229Spst	register u_int32 value, base;
18643229Spst	char c;
18653229Spst
18663229Spst	/*
18673229Spst	 * Collect number up to first illegal character.  Values are specified
18683229Spst	 * as for C:  0x=hex, 0=octal, other=decimal.
18693229Spst	 */
18703229Spst	value = 0;
18713229Spst	base = 10;
18723229Spst	if (**src == '0') {
18733229Spst		base = 8;
18743229Spst		(*src)++;
18753229Spst	}
18763229Spst	if (**src == 'x' || **src == 'X') {
18773229Spst		base = 16;
18783229Spst		(*src)++;
18793229Spst	}
18803229Spst	while ((c = **src)) {
18813229Spst		if (isdigit(c)) {
18823229Spst			value = (value * base) + (c - '0');
18833229Spst			(*src)++;
18843229Spst			continue;
18853229Spst		}
18863229Spst		if (base == 16 && isxdigit(c)) {
18873229Spst			value = (value << 4) + ((c & ~32) + 10 - 'A');
18883229Spst			(*src)++;
18893229Spst			continue;
18903229Spst		}
18913229Spst		break;
18923229Spst	}
18933229Spst	return value;
18943229Spst}
18953229Spst
18963229Spst
18973229Spst
18983229Spst/*
18993229Spst * Routines for deletion of data associated with the main data structure.
19003229Spst */
19013229Spst
19023229Spst
19033229Spst/*
19043229Spst * Frees the entire host data structure given.  Does nothing if the passed
19053229Spst * pointer is NULL.
19063229Spst */
19073229Spst
19083229SpstPRIVATE void
19093229Spstfree_host(hmp)
19103229Spst	hash_datum *hmp;
19113229Spst{
19123229Spst	struct host *hostptr = (struct host *) hmp;
19133229Spst	if (hostptr == NULL)
19143229Spst		return;
19153229Spst	assert(hostptr->linkcount > 0);
19163229Spst	if (--(hostptr->linkcount))
19173229Spst		return;					/* Still has references */
19183229Spst	del_iplist(hostptr->cookie_server);
19193229Spst	del_iplist(hostptr->domain_server);
19203229Spst	del_iplist(hostptr->gateway);
19213229Spst	del_iplist(hostptr->impress_server);
19223229Spst	del_iplist(hostptr->log_server);
19233229Spst	del_iplist(hostptr->lpr_server);
19243229Spst	del_iplist(hostptr->name_server);
19253229Spst	del_iplist(hostptr->rlp_server);
19263229Spst	del_iplist(hostptr->time_server);
19273229Spst	del_iplist(hostptr->nis_server);
19283229Spst	del_iplist(hostptr->ntp_server);
19293229Spst
19303229Spst	/*
19313229Spst	 * XXX - Add new tags here
19323229Spst	 * (if the value is an IP list)
19333229Spst	 */
19343229Spst
19353229Spst	del_string(hostptr->hostname);
19363229Spst	del_string(hostptr->homedir);
19373229Spst	del_string(hostptr->bootfile);
19383229Spst	del_string(hostptr->tftpdir);
19393229Spst	del_string(hostptr->root_path);
19403229Spst	del_string(hostptr->domain_name);
19413229Spst	del_string(hostptr->dump_file);
19423229Spst	del_string(hostptr->exten_file);
19433229Spst	del_string(hostptr->nis_domain);
19443229Spst
19453229Spst#ifdef	YORK_EX_OPTION
19463229Spst	del_string(hostptr->exec_file);
19473229Spst#endif
19483229Spst
19493229Spst	/*
19503229Spst	 * XXX - Add new tags here
19513229Spst	 * (if it is a shared string)
19523229Spst	 */
19533229Spst
19543229Spst	del_bindata(hostptr->generic);
19553229Spst	free((char *) hostptr);
19563229Spst}
19573229Spst
19583229Spst
19593229Spst
19603229Spst/*
19613229Spst * Decrements the linkcount on the given IP address data structure.  If the
19623229Spst * linkcount goes to zero, the memory associated with the data is freed.
19633229Spst */
19643229Spst
19653229SpstPRIVATE void
19663229Spstdel_iplist(iplist)
19673229Spst	struct in_addr_list *iplist;
19683229Spst{
19693229Spst	if (iplist) {
19703229Spst		if (!(--(iplist->linkcount))) {
19713229Spst			free((char *) iplist);
19723229Spst		}
19733229Spst	}
19743229Spst}
19753229Spst
19763229Spst
19773229Spst
19783229Spst/*
19793229Spst * Decrements the linkcount on a string data structure.  If the count
19803229Spst * goes to zero, the memory associated with the string is freed.  Does
19813229Spst * nothing if the passed pointer is NULL.
19823229Spst */
19833229Spst
19843229SpstPRIVATE void
19853229Spstdel_string(stringptr)
19863229Spst	struct shared_string *stringptr;
19873229Spst{
19883229Spst	if (stringptr) {
19893229Spst		if (!(--(stringptr->linkcount))) {
19903229Spst			free((char *) stringptr);
19913229Spst		}
19923229Spst	}
19933229Spst}
19943229Spst
19953229Spst
19963229Spst
19973229Spst/*
19983229Spst * Decrements the linkcount on a shared_bindata data structure.  If the
19993229Spst * count goes to zero, the memory associated with the data is freed.  Does
20003229Spst * nothing if the passed pointer is NULL.
20013229Spst */
20023229Spst
20033229SpstPRIVATE void
20043229Spstdel_bindata(dataptr)
20053229Spst	struct shared_bindata *dataptr;
20063229Spst{
20073229Spst	if (dataptr) {
20083229Spst		if (!(--(dataptr->linkcount))) {
20093229Spst			free((char *) dataptr);
20103229Spst		}
20113229Spst	}
20123229Spst}
20133229Spst
20143229Spst
20153229Spst
20163229Spst
20173229Spst/* smalloc()  --  safe malloc()
20183229Spst *
20193229Spst * Always returns a valid pointer (if it returns at all).  The allocated
20203229Spst * memory is initialized to all zeros.  If malloc() returns an error, a
20213229Spst * message is printed using the report() function and the program aborts
20223229Spst * with a status of 1.
20233229Spst */
20243229Spst
20253229SpstPRIVATE char *
20263229Spstsmalloc(nbytes)
20273229Spst	unsigned nbytes;
20283229Spst{
20293229Spst	char *retvalue;
20303229Spst
20313229Spst	retvalue = malloc(nbytes);
20323229Spst	if (!retvalue) {
20333229Spst		report(LOG_ERR, "malloc() failure -- exiting");
20343229Spst		exit(1);
20353229Spst	}
20363229Spst	bzero(retvalue, nbytes);
20373229Spst	return retvalue;
20383229Spst}
20393229Spst
20403229Spst
20413229Spst/*
20423229Spst * Compare function to determine whether two hardware addresses are
20433229Spst * equivalent.  Returns TRUE if "host1" and "host2" are equivalent, FALSE
20443229Spst * otherwise.
20453229Spst *
20463229Spst * This function is used when retrieving elements from the hardware address
20473229Spst * hash table.
20483229Spst */
20493229Spst
20503229Spstboolean
20513229Spsthwlookcmp(d1, d2)
20523229Spst	hash_datum *d1, *d2;
20533229Spst{
20543229Spst	struct host *host1 = (struct host *) d1;
20553229Spst	struct host *host2 = (struct host *) d2;
20563229Spst
20573229Spst	if (host1->htype != host2->htype) {
20583229Spst		return FALSE;
20593229Spst	}
20603229Spst	if (bcmp(host1->haddr, host2->haddr, haddrlength(host1->htype))) {
20613229Spst		return FALSE;
20623229Spst	}
20633229Spst	return TRUE;
20643229Spst}
20653229Spst
20663229Spst
20673229Spst/*
20683229Spst * Compare function for doing IP address hash table lookup.
20693229Spst */
20703229Spst
20713229Spstboolean
20723229Spstiplookcmp(d1, d2)
20733229Spst	hash_datum *d1, *d2;
20743229Spst{
20753229Spst	struct host *host1 = (struct host *) d1;
20763229Spst	struct host *host2 = (struct host *) d2;
20773229Spst
20783229Spst	return (host1->iaddr.s_addr == host2->iaddr.s_addr);
20793229Spst}
20803229Spst
20813229Spst/*
20823229Spst * Local Variables:
20833229Spst * tab-width: 4
20843229Spst * c-indent-level: 4
20853229Spst * c-argdecl-indent: 4
20863229Spst * c-continued-statement-offset: 4
20873229Spst * c-continued-brace-offset: -4
20883229Spst * c-label-offset: -4
20893229Spst * c-brace-offset: 0
20903229Spst * End:
20913229Spst */
2092