readfile.c revision 72640
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 72640 2001-02-18 10:25:42Z asmodai $
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 '/')";
7003229Spst		case E_BAD_VALUE:
7013229Spst			msg = "bad value";
7023229Spst		default:
7033229Spst			msg = "unkown error";
7043229Spst			break;
7053229Spst		}						/* switch */
7063229Spst		report(LOG_ERR, "in entry named \"%s\", symbol \"%s\": %s",
7073229Spst			   current_hostname, current_tagname, msg);
7083229Spst		return -1;
7093229Spst	}
7103229Spst}
7113229Spst
7123229Spst
7133229Spst/*
7143229Spst * Macros for use in the function below:
7153229Spst */
7163229Spst
7173229Spst/* Parse one INET address stored directly in MEMBER. */
7183229Spst#define PARSE_IA1(MEMBER) do \
7193229Spst{ \
7203229Spst	if (optype == OP_BOOLEAN) \
7213229Spst		return E_SYNTAX_ERROR; \
7223229Spst	hp->flags.MEMBER = FALSE; \
7233229Spst	if (optype == OP_ADDITION) { \
7243229Spst		if (prs_inetaddr(symbol, &value) < 0) \
7253229Spst			return E_BAD_IPADDR; \
7263229Spst		hp->MEMBER.s_addr = value; \
7273229Spst		hp->flags.MEMBER = TRUE; \
7283229Spst	} \
7293229Spst} while (0)
7303229Spst
7313229Spst/* Parse a list of INET addresses pointed to by MEMBER */
7323229Spst#define PARSE_IAL(MEMBER) do \
7333229Spst{ \
7343229Spst	if (optype == OP_BOOLEAN) \
7353229Spst		return E_SYNTAX_ERROR; \
7363229Spst	if (hp->flags.MEMBER) { \
7373229Spst		hp->flags.MEMBER = FALSE; \
7383229Spst		assert(hp->MEMBER); \
7393229Spst		del_iplist(hp->MEMBER); \
7403229Spst		hp->MEMBER = NULL; \
7413229Spst	} \
7423229Spst	if (optype == OP_ADDITION) { \
7433229Spst		hp->MEMBER = get_addresses(symbol); \
7443229Spst		if (hp->MEMBER == NULL) \
7453229Spst			return E_SYNTAX_ERROR; \
7463229Spst		hp->flags.MEMBER = TRUE; \
7473229Spst	} \
7483229Spst} while (0)
7493229Spst
7503229Spst/* Parse a shared string pointed to by MEMBER */
7513229Spst#define PARSE_STR(MEMBER) do \
7523229Spst{ \
7533229Spst	if (optype == OP_BOOLEAN) \
7543229Spst		return E_SYNTAX_ERROR; \
7553229Spst	if (hp->flags.MEMBER) { \
7563229Spst		hp->flags.MEMBER = FALSE; \
7573229Spst		assert(hp->MEMBER); \
7583229Spst		del_string(hp->MEMBER); \
7593229Spst		hp->MEMBER = NULL; \
7603229Spst	} \
7613229Spst	if (optype == OP_ADDITION) { \
7623229Spst		hp->MEMBER = get_shared_string(symbol); \
7633229Spst		if (hp->MEMBER == NULL) \
7643229Spst			return E_SYNTAX_ERROR; \
7653229Spst		hp->flags.MEMBER = TRUE; \
7663229Spst	} \
7673229Spst} while (0)
7683229Spst
76913572Spst/* Parse an unsigned integer value for MEMBER */
77013572Spst#define PARSE_UINT(MEMBER) do \
7713229Spst{ \
7723229Spst	if (optype == OP_BOOLEAN) \
7733229Spst		return E_SYNTAX_ERROR; \
7743229Spst	hp->flags.MEMBER = FALSE; \
7753229Spst	if (optype == OP_ADDITION) { \
7763229Spst		value = get_u_long(symbol); \
7773229Spst		hp->MEMBER = value; \
7783229Spst		hp->flags.MEMBER = TRUE; \
7793229Spst	} \
7803229Spst} while (0)
7813229Spst
7823229Spst/*
7833229Spst * Evaluate the two-character tag symbol pointed to by "symbol" and place
7843229Spst * the data in the structure pointed to by "hp".  The pointer pointed to
7853229Spst * by "symbol" is updated to point past the source string (but may not
7863229Spst * point to the next tag entry).
7873229Spst *
7883229Spst * Obviously, this need a few more comments. . . .
7893229Spst */
7903229SpstPRIVATE int
7913229Spsteval_symbol(symbol, hp)
7923229Spst	char **symbol;
7933229Spst	struct host *hp;
7943229Spst{
7953229Spst	char tmpstr[MAXSTRINGLEN];
7963229Spst	byte *tmphaddr;
7973229Spst	struct symbolmap *symbolptr;
7983229Spst	u_int32 value;
7993229Spst	int32 timeoff;
8003229Spst	int i, numsymbols;
8013229Spst	unsigned len;
8023229Spst	int optype;					/* Indicates boolean, addition, or deletion */
8033229Spst
8043229Spst	eat_whitespace(symbol);
8053229Spst
8063229Spst	/* Make sure this is set before returning. */
8073229Spst	current_tagname[0] = (*symbol)[0];
8083229Spst	current_tagname[1] = (*symbol)[1];
8093229Spst	current_tagname[2] = 0;
8103229Spst
8113229Spst	if ((*symbol)[0] == '\0') {
8123229Spst		return E_END_OF_ENTRY;
8133229Spst	}
8143229Spst	if ((*symbol)[0] == ':') {
8153229Spst		return SUCCESS;
8163229Spst	}
8173229Spst	if ((*symbol)[0] == 'T') {	/* generic symbol */
8183229Spst		(*symbol)++;
8193229Spst		value = get_u_long(symbol);
82031971Simp		snprintf(current_tagname, sizeof(current_tagname),
82131971Simp			"T%d", (int)value);
8223229Spst		eat_whitespace(symbol);
8233229Spst		if ((*symbol)[0] != '=') {
8243229Spst			return E_SYNTAX_ERROR;
8253229Spst		}
8263229Spst		(*symbol)++;
8273229Spst		if (!(hp->generic)) {
8283229Spst			hp->generic = (struct shared_bindata *)
8293229Spst				smalloc(sizeof(struct shared_bindata));
8303229Spst		}
8313229Spst		if (process_generic(symbol, &(hp->generic), (byte) (value & 0xFF)))
8323229Spst			return E_SYNTAX_ERROR;
8333229Spst		hp->flags.generic = TRUE;
8343229Spst		return SUCCESS;
8353229Spst	}
8363229Spst	/*
8373229Spst	 * Determine the type of operation to be done on this symbol
8383229Spst	 */
8393229Spst	switch ((*symbol)[2]) {
8403229Spst	case '=':
8413229Spst		optype = OP_ADDITION;
8423229Spst		break;
8433229Spst	case '@':
8443229Spst		optype = OP_DELETION;
8453229Spst		break;
8463229Spst	case ':':
8473229Spst	case '\0':
8483229Spst		optype = OP_BOOLEAN;
8493229Spst		break;
8503229Spst	default:
8513229Spst		return E_SYNTAX_ERROR;
8523229Spst	}
8533229Spst
8543229Spst	symbolptr = symbol_list;
8553229Spst	numsymbols = sizeof(symbol_list) / sizeof(struct symbolmap);
8563229Spst	for (i = 0; i < numsymbols; i++) {
8573229Spst		if (((symbolptr->symbol)[0] == (*symbol)[0]) &&
8583229Spst			((symbolptr->symbol)[1] == (*symbol)[1])) {
8593229Spst			break;
8603229Spst		}
8613229Spst		symbolptr++;
8623229Spst	}
8633229Spst	if (i >= numsymbols) {
8643229Spst		return E_UNKNOWN_SYMBOL;
8653229Spst	}
8663229Spst	/*
8673229Spst	 * Skip past the = or @ character (to point to the data) if this
8683229Spst	 * isn't a boolean operation.  For boolean operations, just skip
8693229Spst	 * over the two-character tag symbol (and nothing else. . . .).
8703229Spst	 */
8713229Spst	(*symbol) += (optype == OP_BOOLEAN) ? 2 : 3;
8723229Spst
8733229Spst	eat_whitespace(symbol);
8743229Spst
8753229Spst	/* The cases below are in order by symbolcode value. */
8763229Spst	switch (symbolptr->symbolcode) {
8773229Spst
8783229Spst	case SYM_BOOTFILE:
8793229Spst		PARSE_STR(bootfile);
8803229Spst		break;
8813229Spst
8823229Spst	case SYM_COOKIE_SERVER:
8833229Spst		PARSE_IAL(cookie_server);
8843229Spst		break;
8853229Spst
8863229Spst	case SYM_DOMAIN_SERVER:
8873229Spst		PARSE_IAL(domain_server);
8883229Spst		break;
8893229Spst
8903229Spst	case SYM_GATEWAY:
8913229Spst		PARSE_IAL(gateway);
8923229Spst		break;
8933229Spst
8943229Spst	case SYM_HWADDR:
8953229Spst		if (optype == OP_BOOLEAN)
8963229Spst			return E_SYNTAX_ERROR;
8973229Spst		hp->flags.haddr = FALSE;
8983229Spst		if (optype == OP_ADDITION) {
8993229Spst			/* Default the HW type to Ethernet */
9003229Spst			if (hp->flags.htype == 0) {
9013229Spst				hp->flags.htype = TRUE;
9023229Spst				hp->htype = HTYPE_ETHERNET;
9033229Spst			}
9043229Spst			tmphaddr = prs_haddr(symbol, hp->htype);
9053229Spst			if (!tmphaddr)
9063229Spst				return E_BAD_HWADDR;
9073229Spst			bcopy(tmphaddr, hp->haddr, haddrlength(hp->htype));
9083229Spst			hp->flags.haddr = TRUE;
9093229Spst		}
9103229Spst		break;
9113229Spst
9123229Spst	case SYM_HOMEDIR:
9133229Spst		PARSE_STR(homedir);
9143229Spst		break;
9153229Spst
9163229Spst	case SYM_HTYPE:
9173229Spst		if (optype == OP_BOOLEAN)
9183229Spst			return E_SYNTAX_ERROR;
9193229Spst		hp->flags.htype = FALSE;
9203229Spst		if (optype == OP_ADDITION) {
9213229Spst			value = 0L;			/* Assume an illegal value */
9223229Spst			eat_whitespace(symbol);
9233229Spst			if (isdigit(**symbol)) {
9243229Spst				value = get_u_long(symbol);
9253229Spst			} else {
9263229Spst				len = sizeof(tmpstr);
9273229Spst				(void) get_string(symbol, tmpstr, &len);
9283229Spst				makelower(tmpstr);
9293229Spst				numsymbols = sizeof(htnamemap) /
9303229Spst					sizeof(struct htypename);
9313229Spst				for (i = 0; i < numsymbols; i++) {
9323229Spst					if (!strcmp(htnamemap[i].name, tmpstr)) {
9333229Spst						break;
9343229Spst					}
9353229Spst				}
9363229Spst				if (i < numsymbols) {
9373229Spst					value = htnamemap[i].htype;
9383229Spst				}
9393229Spst			}
9403229Spst			if (value >= hwinfocnt) {
9413229Spst				return E_BAD_HWATYPE;
9423229Spst			}
9433229Spst			hp->htype = (byte) (value & 0xFF);
9443229Spst			hp->flags.htype = TRUE;
9453229Spst		}
9463229Spst		break;
9473229Spst
9483229Spst	case SYM_IMPRESS_SERVER:
9493229Spst		PARSE_IAL(impress_server);
9503229Spst		break;
9513229Spst
9523229Spst	case SYM_IPADDR:
9533229Spst		PARSE_IA1(iaddr);
9543229Spst		break;
9553229Spst
9563229Spst	case SYM_LOG_SERVER:
9573229Spst		PARSE_IAL(log_server);
9583229Spst		break;
9593229Spst
9603229Spst	case SYM_LPR_SERVER:
9613229Spst		PARSE_IAL(lpr_server);
9623229Spst		break;
9633229Spst
9643229Spst	case SYM_NAME_SERVER:
9653229Spst		PARSE_IAL(name_server);
9663229Spst		break;
9673229Spst
9683229Spst	case SYM_RLP_SERVER:
9693229Spst		PARSE_IAL(rlp_server);
9703229Spst		break;
9713229Spst
9723229Spst	case SYM_SUBNET_MASK:
9733229Spst		PARSE_IA1(subnet_mask);
9743229Spst		break;
9753229Spst
9763229Spst	case SYM_TIME_OFFSET:
9773229Spst		if (optype == OP_BOOLEAN)
9783229Spst			return E_SYNTAX_ERROR;
9793229Spst		hp->flags.time_offset = FALSE;
9803229Spst		if (optype == OP_ADDITION) {
9813229Spst			len = sizeof(tmpstr);
9823229Spst			(void) get_string(symbol, tmpstr, &len);
9833229Spst			if (!strncmp(tmpstr, "auto", 4)) {
9843229Spst				hp->time_offset = secondswest;
9853229Spst			} else {
98613572Spst				if (sscanf(tmpstr, "%d", (int*)&timeoff) != 1)
9873229Spst					return E_BAD_LONGWORD;
9883229Spst				hp->time_offset = timeoff;
9893229Spst			}
9903229Spst			hp->flags.time_offset = TRUE;
9913229Spst		}
9923229Spst		break;
9933229Spst
9943229Spst	case SYM_TIME_SERVER:
9953229Spst		PARSE_IAL(time_server);
9963229Spst		break;
9973229Spst
9983229Spst	case SYM_VENDOR_MAGIC:
9993229Spst		if (optype == OP_BOOLEAN)
10003229Spst			return E_SYNTAX_ERROR;
10013229Spst		hp->flags.vm_cookie = FALSE;
10023229Spst		if (optype == OP_ADDITION) {
10033229Spst			if (strncmp(*symbol, "auto", 4)) {
10043229Spst				/* The string is not "auto" */
10053229Spst				if (!strncmp(*symbol, "rfc", 3)) {
10063229Spst					bcopy(vm_rfc1048, hp->vm_cookie, 4);
10073229Spst				} else if (!strncmp(*symbol, "cmu", 3)) {
10083229Spst					bcopy(vm_cmu, hp->vm_cookie, 4);
10093229Spst				} else {
10103229Spst					if (!isdigit(**symbol))
10113229Spst						return E_BAD_IPADDR;
10123229Spst					if (prs_inetaddr(symbol, &value) < 0)
10133229Spst						return E_BAD_IPADDR;
10143229Spst					bcopy(&value, hp->vm_cookie, 4);
10153229Spst				}
10163229Spst				hp->flags.vm_cookie = TRUE;
10173229Spst			}
10183229Spst		}
10193229Spst		break;
10203229Spst
10213229Spst	case SYM_SIMILAR_ENTRY:
10223229Spst		switch (optype) {
10233229Spst		case OP_ADDITION:
10243229Spst			fill_defaults(hp, symbol);
10253229Spst			break;
10263229Spst		default:
10273229Spst			return E_SYNTAX_ERROR;
10283229Spst		}
10293229Spst		break;
10303229Spst
10313229Spst	case SYM_NAME_SWITCH:
10323229Spst		switch (optype) {
10333229Spst		case OP_ADDITION:
10343229Spst			return E_SYNTAX_ERROR;
10353229Spst		case OP_DELETION:
10363229Spst			hp->flags.send_name = FALSE;
10373229Spst			hp->flags.name_switch = FALSE;
10383229Spst			break;
10393229Spst		case OP_BOOLEAN:
10403229Spst			hp->flags.send_name = TRUE;
10413229Spst			hp->flags.name_switch = TRUE;
10423229Spst			break;
10433229Spst		}
10443229Spst		break;
10453229Spst
10463229Spst	case SYM_BOOTSIZE:
10473229Spst		switch (optype) {
10483229Spst		case OP_ADDITION:
10493229Spst			if (!strncmp(*symbol, "auto", 4)) {
10503229Spst				hp->flags.bootsize = TRUE;
10513229Spst				hp->flags.bootsize_auto = TRUE;
10523229Spst			} else {
10533229Spst				hp->bootsize = (unsigned int) get_u_long(symbol);
10543229Spst				hp->flags.bootsize = TRUE;
10553229Spst				hp->flags.bootsize_auto = FALSE;
10563229Spst			}
10573229Spst			break;
10583229Spst		case OP_DELETION:
10593229Spst			hp->flags.bootsize = FALSE;
10603229Spst			break;
10613229Spst		case OP_BOOLEAN:
10623229Spst			hp->flags.bootsize = TRUE;
10633229Spst			hp->flags.bootsize_auto = TRUE;
10643229Spst			break;
10653229Spst		}
10663229Spst		break;
10673229Spst
10683229Spst	case SYM_BOOT_SERVER:
10693229Spst		PARSE_IA1(bootserver);
10703229Spst		break;
10713229Spst
10723229Spst	case SYM_TFTPDIR:
10733229Spst		PARSE_STR(tftpdir);
10743229Spst		if ((hp->tftpdir != NULL) &&
10753229Spst			(hp->tftpdir->string[0] != '/'))
10763229Spst			return E_BAD_PATHNAME;
10773229Spst		break;
10783229Spst
10793229Spst	case SYM_DUMP_FILE:
10803229Spst		PARSE_STR(dump_file);
10813229Spst		break;
10823229Spst
10833229Spst	case SYM_DOMAIN_NAME:
10843229Spst		PARSE_STR(domain_name);
10853229Spst		break;
10863229Spst
10873229Spst	case SYM_SWAP_SERVER:
10883229Spst		PARSE_IA1(swap_server);
10893229Spst		break;
10903229Spst
10913229Spst	case SYM_ROOT_PATH:
10923229Spst		PARSE_STR(root_path);
10933229Spst		break;
10943229Spst
10953229Spst	case SYM_EXTEN_FILE:
10963229Spst		PARSE_STR(exten_file);
10973229Spst		break;
10983229Spst
10993229Spst	case SYM_REPLY_ADDR:
11003229Spst		PARSE_IA1(reply_addr);
11013229Spst		break;
11023229Spst
11033229Spst	case SYM_NIS_DOMAIN:
11043229Spst		PARSE_STR(nis_domain);
11053229Spst		break;
11063229Spst
11073229Spst	case SYM_NIS_SERVER:
11083229Spst		PARSE_IAL(nis_server);
11093229Spst		break;
11103229Spst
11113229Spst	case SYM_NTP_SERVER:
11123229Spst		PARSE_IAL(ntp_server);
11133229Spst		break;
11143229Spst
11153229Spst#ifdef	YORK_EX_OPTION
11163229Spst	case SYM_EXEC_FILE:
11173229Spst		PARSE_STR(exec_file);
11183229Spst		break;
11193229Spst#endif
11203229Spst
11213229Spst	case SYM_MSG_SIZE:
112213572Spst		PARSE_UINT(msg_size);
11233229Spst		if (hp->msg_size < BP_MINPKTSZ ||
11243229Spst			hp->msg_size > MAX_MSG_SIZE)
11253229Spst			return E_BAD_VALUE;
11263229Spst		break;
11273229Spst
11283229Spst	case SYM_MIN_WAIT:
112913572Spst		PARSE_UINT(min_wait);
11303229Spst		break;
11313229Spst
11323229Spst		/* XXX - Add new tags here */
11333229Spst
11343229Spst	default:
11353229Spst		return E_UNKNOWN_SYMBOL;
11363229Spst
11373229Spst	}							/* switch symbolcode */
11383229Spst
11393229Spst	return SUCCESS;
11403229Spst}
11413229Spst#undef	PARSE_IA1
11423229Spst#undef	PARSE_IAL
11433229Spst#undef	PARSE_STR
11443229Spst
11453229Spst
11463229Spst
11473229Spst
11483229Spst/*
11493229Spst * Read a string from the buffer indirectly pointed to through "src" and
11503229Spst * move it into the buffer pointed to by "dest".  A pointer to the maximum
11513229Spst * allowable length of the string (including null-terminator) is passed as
11523229Spst * "length".  The actual length of the string which was read is returned in
11533229Spst * the unsigned integer pointed to by "length".  This value is the same as
11543229Spst * that which would be returned by applying the strlen() function on the
11553229Spst * destination string (i.e the terminating null is not counted as a
11563229Spst * character).  Trailing whitespace is removed from the string.  For
11573229Spst * convenience, the function returns the new value of "dest".
11583229Spst *
11593229Spst * The string is read until the maximum number of characters, an unquoted
11603229Spst * colon (:), or a null character is read.  The return string in "dest" is
11613229Spst * null-terminated.
11623229Spst */
11633229Spst
11643229SpstPRIVATE char *
11653229Spstget_string(src, dest, length)
11663229Spst	char **src, *dest;
11673229Spst	unsigned *length;
11683229Spst{
11693229Spst	int n, len, quoteflag;
11703229Spst
11713229Spst	quoteflag = FALSE;
11723229Spst	n = 0;
11733229Spst	len = *length - 1;
11743229Spst	while ((n < len) && (**src)) {
11753229Spst		if (!quoteflag && (**src == ':')) {
11763229Spst			break;
11773229Spst		}
11783229Spst		if (**src == '"') {
11793229Spst			(*src)++;
11803229Spst			quoteflag = !quoteflag;
11813229Spst			continue;
11823229Spst		}
11833229Spst		if (**src == '\\') {
11843229Spst			(*src)++;
11853229Spst			if (!**src) {
11863229Spst				break;
11873229Spst			}
11883229Spst		}
11893229Spst		*dest++ = *(*src)++;
11903229Spst		n++;
11913229Spst	}
11923229Spst
11933229Spst	/*
11943229Spst	 * Remove that troublesome trailing whitespace. . .
11953229Spst	 */
11963229Spst	while ((n > 0) && isspace(dest[-1])) {
11973229Spst		dest--;
11983229Spst		n--;
11993229Spst	}
12003229Spst
12013229Spst	*dest = '\0';
12023229Spst	*length = n;
12033229Spst	return dest;
12043229Spst}
12053229Spst
12063229Spst
12073229Spst
12083229Spst/*
12093229Spst * Read the string indirectly pointed to by "src", update the caller's
12103229Spst * pointer, and return a pointer to a malloc'ed shared_string structure
12113229Spst * containing the string.
12123229Spst *
12133229Spst * The string is read using the same rules as get_string() above.
12143229Spst */
12153229Spst
12163229SpstPRIVATE struct shared_string *
12173229Spstget_shared_string(src)
12183229Spst	char **src;
12193229Spst{
12203229Spst	char retstring[MAXSTRINGLEN];
12213229Spst	struct shared_string *s;
12223229Spst	unsigned length;
12233229Spst
12243229Spst	length = sizeof(retstring);
12253229Spst	(void) get_string(src, retstring, &length);
12263229Spst
12273229Spst	s = (struct shared_string *) smalloc(sizeof(struct shared_string)
12283229Spst										 + length);
12293229Spst	s->linkcount = 1;
12303229Spst	strcpy(s->string, retstring);
12313229Spst
12323229Spst	return s;
12333229Spst}
12343229Spst
12353229Spst
12363229Spst
12373229Spst/*
12383229Spst * Load RFC1048 generic information directly into a memory buffer.
12393229Spst *
12403229Spst * "src" indirectly points to the ASCII representation of the generic data.
12413229Spst * "dest" points to a string structure which is updated to point to a new
12423229Spst * string with the new data appended to the old string.  The old string is
12433229Spst * freed.
12443229Spst *
12453229Spst * The given tag value is inserted with the new data.
12463229Spst *
12473229Spst * The data may be represented as either a stream of hexadecimal numbers
12483229Spst * representing bytes (any or all bytes may optionally start with '0x' and
12493229Spst * be separated with periods ".") or as a quoted string of ASCII
12503229Spst * characters (the quotes are required).
12513229Spst */
12523229Spst
12533229SpstPRIVATE int
12543229Spstprocess_generic(src, dest, tagvalue)
12553229Spst	char **src;
12563229Spst	struct shared_bindata **dest;
12573229Spst	u_int tagvalue;
12583229Spst{
12593229Spst	byte tmpbuf[MAXBUFLEN];
12603229Spst	byte *str;
12613229Spst	struct shared_bindata *bdata;
12623229Spst	u_int newlength, oldlength;
12633229Spst
12643229Spst	str = tmpbuf;
12653229Spst	*str++ = (tagvalue & 0xFF);	/* Store tag value */
12663229Spst	str++;						/* Skip over length field */
12673229Spst	if ((*src)[0] == '"') {		/* ASCII data */
12683229Spst		newlength = sizeof(tmpbuf) - 2;	/* Set maximum allowed length */
12693229Spst		(void) get_string(src, (char *) str, &newlength);
12703229Spst		newlength++;			/* null terminator */
12713229Spst	} else {					/* Numeric data */
12723229Spst		newlength = 0;
12733229Spst		while (newlength < sizeof(tmpbuf) - 2) {
12743229Spst			if (interp_byte(src, str++) < 0)
12753229Spst				break;
12763229Spst			newlength++;
12773229Spst			if (**src == '.') {
12783229Spst				(*src)++;
12793229Spst			}
12803229Spst		}
12813229Spst	}
12823229Spst	if ((*src)[0] != ':')
12833229Spst		return -1;
12843229Spst
12853229Spst	tmpbuf[1] = (newlength & 0xFF);
12863229Spst	oldlength = ((*dest)->length);
12873229Spst	bdata = (struct shared_bindata *) smalloc(sizeof(struct shared_bindata)
12883229Spst											+ oldlength + newlength + 1);
12893229Spst	if (oldlength > 0) {
12903229Spst		bcopy((*dest)->data, bdata->data, oldlength);
12913229Spst	}
12923229Spst	bcopy(tmpbuf, bdata->data + oldlength, newlength + 2);
12933229Spst	bdata->length = oldlength + newlength + 2;
12943229Spst	bdata->linkcount = 1;
12953229Spst	if (*dest) {
12963229Spst		del_bindata(*dest);
12973229Spst	}
12983229Spst	*dest = bdata;
12993229Spst	return 0;
13003229Spst}
13013229Spst
13023229Spst
13033229Spst
13043229Spst/*
13053229Spst * Verify that the given string makes sense as a hostname (according to
13063229Spst * Appendix 1, page 29 of RFC882).
13073229Spst *
13083229Spst * Return TRUE for good names, FALSE otherwise.
13093229Spst */
13103229Spst
13113229SpstPRIVATE boolean
13123229Spstgoodname(hostname)
13133229Spst	register char *hostname;
13143229Spst{
13153229Spst	do {
13163229Spst		if (!isalpha(*hostname++)) {	/* First character must be a letter */
13173229Spst			return FALSE;
13183229Spst		}
13193229Spst		while (isalnum(*hostname) ||
13203229Spst			   (*hostname == '-') ||
13213229Spst			   (*hostname == '_') )
13223229Spst		{
13233229Spst			hostname++;			/* Alphanumeric or a hyphen */
13243229Spst		}
13253229Spst		if (!isalnum(hostname[-1])) {	/* Last must be alphanumeric */
13263229Spst			return FALSE;
13273229Spst		}
13283229Spst		if (*hostname == '\0') {/* Done? */
13293229Spst			return TRUE;
13303229Spst		}
13313229Spst	} while (*hostname++ == '.');	/* Dot, loop for next label */
13323229Spst
13333229Spst	return FALSE;				/* If it's not a dot, lose */
13343229Spst}
13353229Spst
13363229Spst
13373229Spst
13383229Spst/*
13393229Spst * Null compare function -- always returns FALSE so an element is always
13403229Spst * inserted into a hash table (i.e. there is never a collision with an
13413229Spst * existing element).
13423229Spst */
13433229Spst
13443229SpstPRIVATE boolean
13453229Spstnullcmp(d1, d2)
13463229Spst	hash_datum *d1, *d2;
13473229Spst{
13483229Spst	return FALSE;
13493229Spst}
13503229Spst
13513229Spst
13523229Spst/*
13533229Spst * Function for comparing a string with the hostname field of a host
13543229Spst * structure.
13553229Spst */
13563229Spst
13573229Spstboolean
13583229Spstnmcmp(d1, d2)
13593229Spst	hash_datum *d1, *d2;
13603229Spst{
13613229Spst	char *name = (char *) d1;	/* XXX - OK? */
13623229Spst	struct host *hp = (struct host *) d2;
13633229Spst
13643229Spst	return !strcmp(name, hp->hostname->string);
13653229Spst}
13663229Spst
13673229Spst
13683229Spst/*
13693229Spst * Compare function to determine whether two hardware addresses are
13703229Spst * equivalent.  Returns TRUE if "host1" and "host2" are equivalent, FALSE
13713229Spst * otherwise.
13723229Spst *
13733229Spst * If the hardware addresses of "host1" and "host2" are identical, but
13743229Spst * they are on different IP subnets, this function returns FALSE.
13753229Spst *
13763229Spst * This function is used when inserting elements into the hardware address
13773229Spst * hash table.
13783229Spst */
13793229Spst
13803229SpstPRIVATE boolean
13813229Spsthwinscmp(d1, d2)
13823229Spst	hash_datum *d1, *d2;
13833229Spst{
13843229Spst	struct host *host1 = (struct host *) d1;
13853229Spst	struct host *host2 = (struct host *) d2;
13863229Spst
13873229Spst	if (host1->htype != host2->htype) {
13883229Spst		return FALSE;
13893229Spst	}
13903229Spst	if (bcmp(host1->haddr, host2->haddr, haddrlength(host1->htype))) {
13913229Spst		return FALSE;
13923229Spst	}
13933229Spst	/* XXX - Is the subnet_mask field set yet? */
13943229Spst	if ((host1->subnet_mask.s_addr) == (host2->subnet_mask.s_addr)) {
13953229Spst		if (((host1->iaddr.s_addr) & (host1->subnet_mask.s_addr)) !=
13963229Spst			((host2->iaddr.s_addr) & (host2->subnet_mask.s_addr)))
13973229Spst		{
13983229Spst			return FALSE;
13993229Spst		}
14003229Spst	}
14013229Spst	return TRUE;
14023229Spst}
14033229Spst
14043229Spst
14053229Spst/*
14063229Spst * Macros for use in the function below:
14073229Spst */
14083229Spst
14093229Spst#define DUP_COPY(MEMBER) do \
14103229Spst{ \
14113229Spst	if (!hp->flags.MEMBER) { \
14123229Spst		if ((hp->flags.MEMBER = hp2->flags.MEMBER) != 0) { \
14133229Spst			hp->MEMBER = hp2->MEMBER; \
14143229Spst		} \
14153229Spst	} \
14163229Spst} while (0)
14173229Spst
14183229Spst#define DUP_LINK(MEMBER) do \
14193229Spst{ \
14203229Spst	if (!hp->flags.MEMBER) { \
14213229Spst		if ((hp->flags.MEMBER = hp2->flags.MEMBER) != 0) { \
14223229Spst			assert(hp2->MEMBER); \
14233229Spst			hp->MEMBER = hp2->MEMBER; \
14243229Spst			(hp->MEMBER->linkcount)++; \
14253229Spst		} \
14263229Spst	} \
14273229Spst} while (0)
14283229Spst
14293229Spst/*
14303229Spst * Process the "similar entry" symbol.
14313229Spst *
14323229Spst * The host specified as the value of the "tc" symbol is used as a template
14333229Spst * for the current host entry.  Symbol values not explicitly set in the
14343229Spst * current host entry are inferred from the template entry.
14353229Spst */
14363229SpstPRIVATE void
14373229Spstfill_defaults(hp, src)
14383229Spst	struct host *hp;
14393229Spst	char **src;
14403229Spst{
14413229Spst	unsigned int tlen, hashcode;
14423229Spst	struct host *hp2;
14433229Spst	char tstring[MAXSTRINGLEN];
14443229Spst
14453229Spst	tlen = sizeof(tstring);
14463229Spst	(void) get_string(src, tstring, &tlen);
14473229Spst	hashcode = hash_HashFunction((u_char *) tstring, tlen);
14483229Spst	hp2 = (struct host *) hash_Lookup(nmhashtable, hashcode, nmcmp, tstring);
14493229Spst
14503229Spst	if (hp2 == NULL) {
14513229Spst		report(LOG_ERR, "can't find tc=\"%s\"", tstring);
14523229Spst		return;
14533229Spst	}
14543229Spst	DUP_LINK(bootfile);
14553229Spst	DUP_LINK(cookie_server);
14563229Spst	DUP_LINK(domain_server);
14573229Spst	DUP_LINK(gateway);
14583229Spst	/* haddr not copied */
14593229Spst	DUP_LINK(homedir);
14603229Spst	DUP_COPY(htype);
14613229Spst
14623229Spst	DUP_LINK(impress_server);
14633229Spst	/* iaddr not copied */
14643229Spst	DUP_LINK(log_server);
14653229Spst	DUP_LINK(lpr_server);
14663229Spst	DUP_LINK(name_server);
14673229Spst	DUP_LINK(rlp_server);
14683229Spst
14693229Spst	DUP_COPY(subnet_mask);
14703229Spst	DUP_COPY(time_offset);
14713229Spst	DUP_LINK(time_server);
14723229Spst
14733229Spst	if (!hp->flags.vm_cookie) {
14743229Spst		if ((hp->flags.vm_cookie = hp2->flags.vm_cookie)) {
14753229Spst			bcopy(hp2->vm_cookie, hp->vm_cookie, 4);
14763229Spst		}
14773229Spst	}
14783229Spst	if (!hp->flags.name_switch) {
14793229Spst		if ((hp->flags.name_switch = hp2->flags.name_switch)) {
14803229Spst			hp->flags.send_name = hp2->flags.send_name;
14813229Spst		}
14823229Spst	}
14833229Spst	if (!hp->flags.bootsize) {
14843229Spst		if ((hp->flags.bootsize = hp2->flags.bootsize)) {
14853229Spst			hp->flags.bootsize_auto = hp2->flags.bootsize_auto;
14863229Spst			hp->bootsize = hp2->bootsize;
14873229Spst		}
14883229Spst	}
14893229Spst	DUP_COPY(bootserver);
14903229Spst
14913229Spst	DUP_LINK(tftpdir);
14923229Spst	DUP_LINK(dump_file);
14933229Spst	DUP_LINK(domain_name);
14943229Spst
14953229Spst	DUP_COPY(swap_server);
14963229Spst	DUP_LINK(root_path);
14973229Spst	DUP_LINK(exten_file);
14983229Spst
14993229Spst	DUP_COPY(reply_addr);
15003229Spst
15013229Spst	DUP_LINK(nis_domain);
15023229Spst	DUP_LINK(nis_server);
15033229Spst	DUP_LINK(ntp_server);
15043229Spst
15053229Spst#ifdef	YORK_EX_OPTION
15063229Spst	DUP_LINK(exec_file);
15073229Spst#endif
15083229Spst
15093229Spst	DUP_COPY(msg_size);
15103229Spst	DUP_COPY(min_wait);
15113229Spst
15123229Spst	/* XXX - Add new tags here */
15133229Spst
15143229Spst	DUP_LINK(generic);
15153229Spst
15163229Spst}
15173229Spst#undef	DUP_COPY
15183229Spst#undef	DUP_LINK
15193229Spst
15203229Spst
15213229Spst
15223229Spst/*
15233229Spst * This function adjusts the caller's pointer to point just past the
15243229Spst * first-encountered colon.  If it runs into a null character, it leaves
15253229Spst * the pointer pointing to it.
15263229Spst */
15273229Spst
15283229SpstPRIVATE void
15293229Spstadjust(s)
15303229Spst	char **s;
15313229Spst{
15323229Spst	register char *t;
15333229Spst
15343229Spst	t = *s;
15353229Spst	while (*t && (*t != ':')) {
15363229Spst		t++;
15373229Spst	}
15383229Spst	if (*t) {
15393229Spst		t++;
15403229Spst	}
15413229Spst	*s = t;
15423229Spst}
15433229Spst
15443229Spst
15453229Spst
15463229Spst
15473229Spst/*
15483229Spst * This function adjusts the caller's pointer to point to the first
15493229Spst * non-whitespace character.  If it runs into a null character, it leaves
15503229Spst * the pointer pointing to it.
15513229Spst */
15523229Spst
15533229SpstPRIVATE void
15543229Spsteat_whitespace(s)
15553229Spst	char **s;
15563229Spst{
15573229Spst	register char *t;
15583229Spst
15593229Spst	t = *s;
15603229Spst	while (*t && isspace(*t)) {
15613229Spst		t++;
15623229Spst	}
15633229Spst	*s = t;
15643229Spst}
15653229Spst
15663229Spst
15673229Spst
15683229Spst/*
15693229Spst * This function converts the given string to all lowercase.
15703229Spst */
15713229Spst
15723229SpstPRIVATE void
15733229Spstmakelower(s)
15743229Spst	char *s;
15753229Spst{
15763229Spst	while (*s) {
15773229Spst		if (isupper(*s)) {
15783229Spst			*s = tolower(*s);
15793229Spst		}
15803229Spst		s++;
15813229Spst	}
15823229Spst}
15833229Spst
15843229Spst
15853229Spst
15863229Spst/*
15873229Spst *
15883229Spst *	N O T E :
15893229Spst *
15903229Spst *	In many of the functions which follow, a parameter such as "src" or
15913229Spst *	"symbol" is passed as a pointer to a pointer to something.  This is
15923229Spst *	done for the purpose of letting the called function update the
15933229Spst *	caller's copy of the parameter (i.e. to effect call-by-reference
15943229Spst *	parameter passing).  The value of the actual parameter is only used
15953229Spst *	to locate the real parameter of interest and then update this indirect
15963229Spst *	parameter.
15973229Spst *
15983229Spst *	I'm sure somebody out there won't like this. . . .
15993229Spst *  (Yea, because it usually makes code slower... -gwr)
16003229Spst *
16013229Spst */
16023229Spst
16033229Spst
16043229Spst
16053229Spst/*
16063229Spst * "src" points to a character pointer which points to an ASCII string of
16073229Spst * whitespace-separated IP addresses.  A pointer to an in_addr_list
16083229Spst * structure containing the list of addresses is returned.  NULL is
16093229Spst * returned if no addresses were found at all.  The pointer pointed to by
16103229Spst * "src" is updated to point to the first non-address (illegal) character.
16113229Spst */
16123229Spst
16133229SpstPRIVATE struct in_addr_list *
16143229Spstget_addresses(src)
16153229Spst	char **src;
16163229Spst{
16173229Spst	struct in_addr tmpaddrlist[MAXINADDRS];
16183229Spst	struct in_addr *address1, *address2;
16193229Spst	struct in_addr_list *result;
16203229Spst	unsigned addrcount, totalsize;
16213229Spst
16223229Spst	address1 = tmpaddrlist;
16233229Spst	for (addrcount = 0; addrcount < MAXINADDRS; addrcount++) {
16243229Spst		while (isspace(**src) || (**src == ',')) {
16253229Spst			(*src)++;
16263229Spst		}
16273229Spst		if (!**src) {			/* Quit if nothing more */
16283229Spst			break;
16293229Spst		}
16303229Spst		if (prs_inetaddr(src, &(address1->s_addr)) < 0) {
16313229Spst			break;
16323229Spst		}
16333229Spst		address1++;				/* Point to next address slot */
16343229Spst	}
16353229Spst	if (addrcount < 1) {
16363229Spst		result = NULL;
16373229Spst	} else {
16383229Spst		totalsize = sizeof(struct in_addr_list)
16393229Spst		+			(addrcount - 1) * sizeof(struct in_addr);
16403229Spst		result = (struct in_addr_list *) smalloc(totalsize);
16413229Spst		result->linkcount = 1;
16423229Spst		result->addrcount = addrcount;
16433229Spst		address1 = tmpaddrlist;
16443229Spst		address2 = result->addr;
16453229Spst		for (; addrcount > 0; addrcount--) {
16463229Spst			address2->s_addr = address1->s_addr;
16473229Spst			address1++;
16483229Spst			address2++;
16493229Spst		}
16503229Spst	}
16513229Spst	return result;
16523229Spst}
16533229Spst
16543229Spst
16553229Spst
16563229Spst/*
16573229Spst * prs_inetaddr(src, result)
16583229Spst *
16593229Spst * "src" is a value-result parameter; the pointer it points to is updated
16603229Spst * to point to the next data position.   "result" points to an unsigned long
16613229Spst * in which an address is returned.
16623229Spst *
16633229Spst * This function parses the IP address string in ASCII "dot notation" pointed
16643229Spst * to by (*src) and places the result (in network byte order) in the unsigned
16653229Spst * long pointed to by "result".  For malformed addresses, -1 is returned,
16663229Spst * (*src) points to the first illegal character, and the unsigned long pointed
16673229Spst * to by "result" is unchanged.  Successful calls return 0.
16683229Spst */
16693229Spst
16703229SpstPRIVATE int
16713229Spstprs_inetaddr(src, result)
16723229Spst	char **src;
16733229Spst	u_int32 *result;
16743229Spst{
16753229Spst	char tmpstr[MAXSTRINGLEN];
16763229Spst	register u_int32 value;
16773229Spst	u_int32 parts[4], *pp;
16783229Spst	int n;
16793229Spst	char *s, *t;
16803229Spst
16813229Spst	/* Leading alpha char causes IP addr lookup. */
16823229Spst	if (isalpha(**src)) {
16833229Spst		/* Lookup IP address. */
16843229Spst		s = *src;
16853229Spst		t = tmpstr;
16863229Spst		while ((isalnum(*s) || (*s == '.') ||
16873229Spst				(*s == '-') || (*s == '_') ) &&
16883229Spst			   (t < &tmpstr[MAXSTRINGLEN - 1]) )
16893229Spst			*t++ = *s++;
16903229Spst		*t = '\0';
16913229Spst		*src = s;
16923229Spst
16933229Spst		n = lookup_ipa(tmpstr, result);
16943229Spst		if (n < 0)
16953229Spst			report(LOG_ERR, "can not get IP addr for %s", tmpstr);
16963229Spst		return n;
16973229Spst	}
16983229Spst
16993229Spst	/*
17003229Spst	 * Parse an address in Internet format:
17013229Spst	 *	a.b.c.d
17023229Spst	 *	a.b.c	(with c treated as 16-bits)
17033229Spst	 *	a.b	(with b treated as 24 bits)
17043229Spst	 */
17053229Spst	pp = parts;
17063229Spst  loop:
17073229Spst	/* If it's not a digit, return error. */
17083229Spst	if (!isdigit(**src))
17093229Spst		return -1;
17103229Spst	*pp++ = get_u_long(src);
17113229Spst	if (**src == '.') {
17123229Spst		if (pp < (parts + 4)) {
17133229Spst			(*src)++;
17143229Spst			goto loop;
17153229Spst		}
17163229Spst		return (-1);
17173229Spst	}
17183229Spst#if 0
17193229Spst	/* This is handled by the caller. */
17203229Spst	if (**src && !(isspace(**src) || (**src == ':'))) {
17213229Spst		return (-1);
17223229Spst	}
17233229Spst#endif
17243229Spst
17253229Spst	/*
17263229Spst	 * Construct the address according to
17273229Spst	 * the number of parts specified.
17283229Spst	 */
17293229Spst	n = pp - parts;
17303229Spst	switch (n) {
17313229Spst	case 1:					/* a -- 32 bits */
17323229Spst		value = parts[0];
17333229Spst		break;
17343229Spst	case 2:					/* a.b -- 8.24 bits */
17353229Spst		value = (parts[0] << 24) | (parts[1] & 0xFFFFFF);
17363229Spst		break;
17373229Spst	case 3:					/* a.b.c -- 8.8.16 bits */
17383229Spst		value = (parts[0] << 24) | ((parts[1] & 0xFF) << 16) |
17393229Spst			(parts[2] & 0xFFFF);
17403229Spst		break;
17413229Spst	case 4:					/* a.b.c.d -- 8.8.8.8 bits */
17423229Spst		value = (parts[0] << 24) | ((parts[1] & 0xFF) << 16) |
17433229Spst			((parts[2] & 0xFF) << 8) | (parts[3] & 0xFF);
17443229Spst		break;
17453229Spst	default:
17463229Spst		return (-1);
17473229Spst	}
17483229Spst	*result = htonl(value);
17493229Spst	return (0);
17503229Spst}
17513229Spst
17523229Spst
17533229Spst
17543229Spst/*
17553229Spst * "src" points to a pointer which in turn points to a hexadecimal ASCII
17563229Spst * string.  This string is interpreted as a hardware address and returned
17573229Spst * as a pointer to the actual hardware address, represented as an array of
17583229Spst * bytes.
17593229Spst *
17603229Spst * The ASCII string must have the proper number of digits for the specified
17613229Spst * hardware type (e.g. twelve digits for a 48-bit Ethernet address).
17623229Spst * Two-digit sequences (bytes) may be separated with periods (.)  and/or
17633229Spst * prefixed with '0x' for readability, but this is not required.
17643229Spst *
17653229Spst * For bad addresses, the pointer which "src" points to is updated to point
17663229Spst * to the start of the first two-digit sequence which was bad, and the
17673229Spst * function returns a NULL pointer.
17683229Spst */
17693229Spst
17703229SpstPRIVATE byte *
17713229Spstprs_haddr(src, htype)
17723229Spst	char **src;
17733229Spst	u_int htype;
17743229Spst{
17753229Spst	static byte haddr[MAXHADDRLEN];
17763229Spst	byte *hap;
17773229Spst	char tmpstr[MAXSTRINGLEN];
17783229Spst	u_int tmplen;
17793229Spst	unsigned hal;
17803229Spst	char *p;
17813229Spst
17823229Spst	hal = haddrlength(htype);	/* Get length of this address type */
17833229Spst	if (hal <= 0) {
17843229Spst		report(LOG_ERR, "Invalid addr type for HW addr parse");
17853229Spst		return NULL;
17863229Spst	}
17873229Spst	tmplen = sizeof(tmpstr);
17883229Spst	get_string(src, tmpstr, &tmplen);
17893229Spst	p = tmpstr;
17903229Spst
17913229Spst	/* If it's a valid host name, try to lookup the HW address. */
17923229Spst	if (goodname(p)) {
17933229Spst		/* Lookup Hardware Address for hostname. */
17943229Spst		if ((hap = lookup_hwa(p, htype)) != NULL)
17953229Spst			return hap; /* success */
17963229Spst		report(LOG_ERR, "Add 0x prefix if hex value starts with A-F");
17973229Spst		/* OK, assume it must be numeric. */
17983229Spst	}
17993229Spst
18003229Spst	hap = haddr;
18013229Spst	while (hap < haddr + hal) {
180213572Spst		if ((*p == '.') || (*p == ':'))
18033229Spst			p++;
18043229Spst		if (interp_byte(&p, hap++) < 0) {
18053229Spst			return NULL;
18063229Spst		}
18073229Spst	}
18083229Spst	return haddr;
18093229Spst}
18103229Spst
18113229Spst
18123229Spst
18133229Spst/*
18143229Spst * "src" is a pointer to a character pointer which in turn points to a
18153229Spst * hexadecimal ASCII representation of a byte.  This byte is read, the
18163229Spst * character pointer is updated, and the result is deposited into the
18173229Spst * byte pointed to by "retbyte".
18183229Spst *
18193229Spst * The usual '0x' notation is allowed but not required.  The number must be
18203229Spst * a two digit hexadecimal number.  If the number is invalid, "src" and
18213229Spst * "retbyte" are left untouched and -1 is returned as the function value.
18223229Spst * Successful calls return 0.
18233229Spst */
18243229Spst
18253229SpstPRIVATE int
18263229Spstinterp_byte(src, retbyte)
18273229Spst	char **src;
18283229Spst	byte *retbyte;
18293229Spst{
18303229Spst	int v;
18313229Spst
18323229Spst	if ((*src)[0] == '0' &&
18333229Spst		((*src)[1] == 'x' ||
18343229Spst		 (*src)[1] == 'X')) {
18353229Spst		(*src) += 2;			/* allow 0x for hex, but don't require it */
18363229Spst	}
18373229Spst	if (!isxdigit((*src)[0]) || !isxdigit((*src)[1])) {
18383229Spst		return -1;
18393229Spst	}
18403229Spst	if (sscanf(*src, "%2x", &v) != 1) {
18413229Spst		return -1;
18423229Spst	}
18433229Spst	(*src) += 2;
18443229Spst	*retbyte = (byte) (v & 0xFF);
18453229Spst	return 0;
18463229Spst}
18473229Spst
18483229Spst
18493229Spst
18503229Spst/*
18513229Spst * The parameter "src" points to a character pointer which points to an
18523229Spst * ASCII string representation of an unsigned number.  The number is
18533229Spst * returned as an unsigned long and the character pointer is updated to
18543229Spst * point to the first illegal character.
18553229Spst */
18563229Spst
18573229SpstPRIVATE u_int32
18583229Spstget_u_long(src)
18593229Spst	char **src;
18603229Spst{
18613229Spst	register u_int32 value, base;
18623229Spst	char c;
18633229Spst
18643229Spst	/*
18653229Spst	 * Collect number up to first illegal character.  Values are specified
18663229Spst	 * as for C:  0x=hex, 0=octal, other=decimal.
18673229Spst	 */
18683229Spst	value = 0;
18693229Spst	base = 10;
18703229Spst	if (**src == '0') {
18713229Spst		base = 8;
18723229Spst		(*src)++;
18733229Spst	}
18743229Spst	if (**src == 'x' || **src == 'X') {
18753229Spst		base = 16;
18763229Spst		(*src)++;
18773229Spst	}
18783229Spst	while ((c = **src)) {
18793229Spst		if (isdigit(c)) {
18803229Spst			value = (value * base) + (c - '0');
18813229Spst			(*src)++;
18823229Spst			continue;
18833229Spst		}
18843229Spst		if (base == 16 && isxdigit(c)) {
18853229Spst			value = (value << 4) + ((c & ~32) + 10 - 'A');
18863229Spst			(*src)++;
18873229Spst			continue;
18883229Spst		}
18893229Spst		break;
18903229Spst	}
18913229Spst	return value;
18923229Spst}
18933229Spst
18943229Spst
18953229Spst
18963229Spst/*
18973229Spst * Routines for deletion of data associated with the main data structure.
18983229Spst */
18993229Spst
19003229Spst
19013229Spst/*
19023229Spst * Frees the entire host data structure given.  Does nothing if the passed
19033229Spst * pointer is NULL.
19043229Spst */
19053229Spst
19063229SpstPRIVATE void
19073229Spstfree_host(hmp)
19083229Spst	hash_datum *hmp;
19093229Spst{
19103229Spst	struct host *hostptr = (struct host *) hmp;
19113229Spst	if (hostptr == NULL)
19123229Spst		return;
19133229Spst	assert(hostptr->linkcount > 0);
19143229Spst	if (--(hostptr->linkcount))
19153229Spst		return;					/* Still has references */
19163229Spst	del_iplist(hostptr->cookie_server);
19173229Spst	del_iplist(hostptr->domain_server);
19183229Spst	del_iplist(hostptr->gateway);
19193229Spst	del_iplist(hostptr->impress_server);
19203229Spst	del_iplist(hostptr->log_server);
19213229Spst	del_iplist(hostptr->lpr_server);
19223229Spst	del_iplist(hostptr->name_server);
19233229Spst	del_iplist(hostptr->rlp_server);
19243229Spst	del_iplist(hostptr->time_server);
19253229Spst	del_iplist(hostptr->nis_server);
19263229Spst	del_iplist(hostptr->ntp_server);
19273229Spst
19283229Spst	/*
19293229Spst	 * XXX - Add new tags here
19303229Spst	 * (if the value is an IP list)
19313229Spst	 */
19323229Spst
19333229Spst	del_string(hostptr->hostname);
19343229Spst	del_string(hostptr->homedir);
19353229Spst	del_string(hostptr->bootfile);
19363229Spst	del_string(hostptr->tftpdir);
19373229Spst	del_string(hostptr->root_path);
19383229Spst	del_string(hostptr->domain_name);
19393229Spst	del_string(hostptr->dump_file);
19403229Spst	del_string(hostptr->exten_file);
19413229Spst	del_string(hostptr->nis_domain);
19423229Spst
19433229Spst#ifdef	YORK_EX_OPTION
19443229Spst	del_string(hostptr->exec_file);
19453229Spst#endif
19463229Spst
19473229Spst	/*
19483229Spst	 * XXX - Add new tags here
19493229Spst	 * (if it is a shared string)
19503229Spst	 */
19513229Spst
19523229Spst	del_bindata(hostptr->generic);
19533229Spst	free((char *) hostptr);
19543229Spst}
19553229Spst
19563229Spst
19573229Spst
19583229Spst/*
19593229Spst * Decrements the linkcount on the given IP address data structure.  If the
19603229Spst * linkcount goes to zero, the memory associated with the data is freed.
19613229Spst */
19623229Spst
19633229SpstPRIVATE void
19643229Spstdel_iplist(iplist)
19653229Spst	struct in_addr_list *iplist;
19663229Spst{
19673229Spst	if (iplist) {
19683229Spst		if (!(--(iplist->linkcount))) {
19693229Spst			free((char *) iplist);
19703229Spst		}
19713229Spst	}
19723229Spst}
19733229Spst
19743229Spst
19753229Spst
19763229Spst/*
19773229Spst * Decrements the linkcount on a string data structure.  If the count
19783229Spst * goes to zero, the memory associated with the string is freed.  Does
19793229Spst * nothing if the passed pointer is NULL.
19803229Spst */
19813229Spst
19823229SpstPRIVATE void
19833229Spstdel_string(stringptr)
19843229Spst	struct shared_string *stringptr;
19853229Spst{
19863229Spst	if (stringptr) {
19873229Spst		if (!(--(stringptr->linkcount))) {
19883229Spst			free((char *) stringptr);
19893229Spst		}
19903229Spst	}
19913229Spst}
19923229Spst
19933229Spst
19943229Spst
19953229Spst/*
19963229Spst * Decrements the linkcount on a shared_bindata data structure.  If the
19973229Spst * count goes to zero, the memory associated with the data is freed.  Does
19983229Spst * nothing if the passed pointer is NULL.
19993229Spst */
20003229Spst
20013229SpstPRIVATE void
20023229Spstdel_bindata(dataptr)
20033229Spst	struct shared_bindata *dataptr;
20043229Spst{
20053229Spst	if (dataptr) {
20063229Spst		if (!(--(dataptr->linkcount))) {
20073229Spst			free((char *) dataptr);
20083229Spst		}
20093229Spst	}
20103229Spst}
20113229Spst
20123229Spst
20133229Spst
20143229Spst
20153229Spst/* smalloc()  --  safe malloc()
20163229Spst *
20173229Spst * Always returns a valid pointer (if it returns at all).  The allocated
20183229Spst * memory is initialized to all zeros.  If malloc() returns an error, a
20193229Spst * message is printed using the report() function and the program aborts
20203229Spst * with a status of 1.
20213229Spst */
20223229Spst
20233229SpstPRIVATE char *
20243229Spstsmalloc(nbytes)
20253229Spst	unsigned nbytes;
20263229Spst{
20273229Spst	char *retvalue;
20283229Spst
20293229Spst	retvalue = malloc(nbytes);
20303229Spst	if (!retvalue) {
20313229Spst		report(LOG_ERR, "malloc() failure -- exiting");
20323229Spst		exit(1);
20333229Spst	}
20343229Spst	bzero(retvalue, nbytes);
20353229Spst	return retvalue;
20363229Spst}
20373229Spst
20383229Spst
20393229Spst/*
20403229Spst * Compare function to determine whether two hardware addresses are
20413229Spst * equivalent.  Returns TRUE if "host1" and "host2" are equivalent, FALSE
20423229Spst * otherwise.
20433229Spst *
20443229Spst * This function is used when retrieving elements from the hardware address
20453229Spst * hash table.
20463229Spst */
20473229Spst
20483229Spstboolean
20493229Spsthwlookcmp(d1, d2)
20503229Spst	hash_datum *d1, *d2;
20513229Spst{
20523229Spst	struct host *host1 = (struct host *) d1;
20533229Spst	struct host *host2 = (struct host *) d2;
20543229Spst
20553229Spst	if (host1->htype != host2->htype) {
20563229Spst		return FALSE;
20573229Spst	}
20583229Spst	if (bcmp(host1->haddr, host2->haddr, haddrlength(host1->htype))) {
20593229Spst		return FALSE;
20603229Spst	}
20613229Spst	return TRUE;
20623229Spst}
20633229Spst
20643229Spst
20653229Spst/*
20663229Spst * Compare function for doing IP address hash table lookup.
20673229Spst */
20683229Spst
20693229Spstboolean
20703229Spstiplookcmp(d1, d2)
20713229Spst	hash_datum *d1, *d2;
20723229Spst{
20733229Spst	struct host *host1 = (struct host *) d1;
20743229Spst	struct host *host2 = (struct host *) d2;
20753229Spst
20763229Spst	return (host1->iaddr.s_addr == host2->iaddr.s_addr);
20773229Spst}
20783229Spst
20793229Spst/*
20803229Spst * Local Variables:
20813229Spst * tab-width: 4
20823229Spst * c-indent-level: 4
20833229Spst * c-argdecl-indent: 4
20843229Spst * c-continued-statement-offset: 4
20853229Spst * c-continued-brace-offset: -4
20863229Spst * c-label-offset: -4
20873229Spst * c-brace-offset: 0
20883229Spst * End:
20893229Spst */
2090