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