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