readfile.c revision 97417
1/************************************************************************
2          Copyright 1988, 1991 by Carnegie Mellon University
3
4                          All Rights Reserved
5
6Permission to use, copy, modify, and distribute this software and its
7documentation for any purpose and without fee is hereby granted, provided
8that the above copyright notice appear in all copies and that both that
9copyright notice and this permission notice appear in supporting
10documentation, and that the name of Carnegie Mellon University not be used
11in advertising or publicity pertaining to distribution of the software
12without specific, written prior permission.
13
14CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
15SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
16IN NO EVENT SHALL CMU BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
17DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
18PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
19ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
20SOFTWARE.
21
22 $FreeBSD: head/libexec/bootpd/readfile.c 97417 2002-05-28 18:36:43Z alfred $
23
24************************************************************************/
25
26/*
27 * bootpd configuration file reading code.
28 *
29 * The routines in this file deal with reading, interpreting, and storing
30 * the information found in the bootpd configuration file (usually
31 * /etc/bootptab).
32 */
33
34
35#include <sys/errno.h>
36#include <sys/types.h>
37#include <sys/stat.h>
38#include <sys/file.h>
39#include <sys/time.h>
40#include <netinet/in.h>
41
42#include <stdlib.h>
43#include <stdio.h>
44#include <string.h>
45#include <ctype.h>
46#include <assert.h>
47#include <syslog.h>
48
49#ifndef USE_BFUNCS
50#include <memory.h>
51/* Yes, memcpy is OK here (no overlapped copies). */
52#define	bcopy(a,b,c)	memcpy(b,a,c)
53#define	bzero(p,l)	memset(p,0,l)
54#define	bcmp(a,b,c)	memcmp(a,b,c)
55#endif
56
57#include "bootp.h"
58#include "hash.h"
59#include "hwaddr.h"
60#include "lookup.h"
61#include "readfile.h"
62#include "report.h"
63#include "tzone.h"
64#include "bootpd.h"
65
66#define HASHTABLESIZE		257	/* Hash table size (prime) */
67
68/* Non-standard hardware address type (see bootp.h) */
69#define HTYPE_DIRECT	0
70
71/* Error codes returned by eval_symbol: */
72#define SUCCESS			  0
73#define E_END_OF_ENTRY		(-1)
74#define E_SYNTAX_ERROR		(-2)
75#define E_UNKNOWN_SYMBOL	(-3)
76#define E_BAD_IPADDR		(-4)
77#define E_BAD_HWADDR		(-5)
78#define E_BAD_LONGWORD		(-6)
79#define E_BAD_HWATYPE		(-7)
80#define E_BAD_PATHNAME		(-8)
81#define E_BAD_VALUE 		(-9)
82
83/* Tag idendities. */
84#define SYM_NULL		  0
85#define SYM_BOOTFILE		  1
86#define SYM_COOKIE_SERVER	  2
87#define SYM_DOMAIN_SERVER	  3
88#define SYM_GATEWAY		  4
89#define SYM_HWADDR		  5
90#define SYM_HOMEDIR		  6
91#define SYM_HTYPE		  7
92#define SYM_IMPRESS_SERVER	  8
93#define SYM_IPADDR		  9
94#define SYM_LOG_SERVER		 10
95#define SYM_LPR_SERVER		 11
96#define SYM_NAME_SERVER		 12
97#define SYM_RLP_SERVER		 13
98#define SYM_SUBNET_MASK		 14
99#define SYM_TIME_OFFSET		 15
100#define SYM_TIME_SERVER		 16
101#define SYM_VENDOR_MAGIC	 17
102#define SYM_SIMILAR_ENTRY	 18
103#define SYM_NAME_SWITCH		 19
104#define SYM_BOOTSIZE		 20
105#define SYM_BOOT_SERVER		 22
106#define SYM_TFTPDIR		 23
107#define SYM_DUMP_FILE		 24
108#define SYM_DOMAIN_NAME          25
109#define SYM_SWAP_SERVER          26
110#define SYM_ROOT_PATH            27
111#define SYM_EXTEN_FILE           28
112#define SYM_REPLY_ADDR           29
113#define SYM_NIS_DOMAIN           30	/* RFC 1533 */
114#define SYM_NIS_SERVER           31	/* RFC 1533 */
115#define SYM_NTP_SERVER           32	/* RFC 1533 */
116#define SYM_EXEC_FILE		 33	/* YORK_EX_OPTION */
117#define SYM_MSG_SIZE 		 34
118#define SYM_MIN_WAIT		 35
119/* XXX - Add new tags here */
120
121#define OP_ADDITION		  1	/* Operations on tags */
122#define OP_DELETION		  2
123#define OP_BOOLEAN		  3
124
125#define MAXINADDRS		 16	/* Max size of an IP address list */
126#define MAXBUFLEN		256	/* Max temp buffer space */
127#define MAXENTRYLEN	       2048	/* Max size of an entire entry */
128
129
130
131/*
132 * Structure used to map a configuration-file symbol (such as "ds") to a
133 * unique integer.
134 */
135
136struct symbolmap {
137	char *symbol;
138	int symbolcode;
139};
140
141
142struct htypename {
143	char *name;
144	byte htype;
145};
146
147
148PRIVATE int nhosts;				/* Number of hosts (/w hw or IP address) */
149PRIVATE int nentries;			/* Total number of entries */
150PRIVATE int32 modtime = 0;		/* Last modification time of bootptab */
151PRIVATE char *current_hostname;	/* Name of the current entry. */
152PRIVATE char current_tagname[8];
153
154/*
155 * List of symbolic names used in the bootptab file.  The order and actual
156 * values of the symbol codes (SYM_. . .) are unimportant, but they must
157 * all be unique.
158 */
159
160PRIVATE struct symbolmap symbol_list[] = {
161	{"bf", SYM_BOOTFILE},
162	{"bs", SYM_BOOTSIZE},
163	{"cs", SYM_COOKIE_SERVER},
164	{"df", SYM_DUMP_FILE},
165	{"dn", SYM_DOMAIN_NAME},
166	{"ds", SYM_DOMAIN_SERVER},
167	{"ef", SYM_EXTEN_FILE},
168	{"ex", SYM_EXEC_FILE},		/* YORK_EX_OPTION */
169	{"gw", SYM_GATEWAY},
170	{"ha", SYM_HWADDR},
171	{"hd", SYM_HOMEDIR},
172	{"hn", SYM_NAME_SWITCH},
173	{"ht", SYM_HTYPE},
174	{"im", SYM_IMPRESS_SERVER},
175	{"ip", SYM_IPADDR},
176	{"lg", SYM_LOG_SERVER},
177	{"lp", SYM_LPR_SERVER},
178	{"ms", SYM_MSG_SIZE},
179	{"mw", SYM_MIN_WAIT},
180	{"ns", SYM_NAME_SERVER},
181	{"nt", SYM_NTP_SERVER},
182	{"ra", SYM_REPLY_ADDR},
183	{"rl", SYM_RLP_SERVER},
184	{"rp", SYM_ROOT_PATH},
185	{"sa", SYM_BOOT_SERVER},
186	{"sm", SYM_SUBNET_MASK},
187	{"sw", SYM_SWAP_SERVER},
188	{"tc", SYM_SIMILAR_ENTRY},
189	{"td", SYM_TFTPDIR},
190	{"to", SYM_TIME_OFFSET},
191	{"ts", SYM_TIME_SERVER},
192	{"vm", SYM_VENDOR_MAGIC},
193	{"yd", SYM_NIS_DOMAIN},
194	{"ys", SYM_NIS_SERVER},
195	/* XXX - Add new tags here */
196};
197
198
199/*
200 * List of symbolic names for hardware types.  Name translates into
201 * hardware type code listed with it.  Names must begin with a letter
202 * and must be all lowercase.  This is searched linearly, so put
203 * commonly-used entries near the beginning.
204 */
205
206PRIVATE struct htypename htnamemap[] = {
207	{"ethernet", HTYPE_ETHERNET},
208	{"ethernet3", HTYPE_EXP_ETHERNET},
209	{"ether", HTYPE_ETHERNET},
210	{"ether3", HTYPE_EXP_ETHERNET},
211	{"ieee802", HTYPE_IEEE802},
212	{"tr", HTYPE_IEEE802},
213	{"token-ring", HTYPE_IEEE802},
214	{"pronet", HTYPE_PRONET},
215	{"chaos", HTYPE_CHAOS},
216	{"arcnet", HTYPE_ARCNET},
217	{"ax.25", HTYPE_AX25},
218	{"direct", HTYPE_DIRECT},
219	{"serial", HTYPE_DIRECT},
220	{"slip", HTYPE_DIRECT},
221	{"ppp", HTYPE_DIRECT}
222};
223
224
225
226/*
227 * Externals and forward declarations.
228 */
229
230extern boolean iplookcmp();
231boolean nmcmp(hash_datum *, hash_datum *);
232
233PRIVATE void
234	adjust(char **);
235PRIVATE void
236	del_string(struct shared_string *);
237PRIVATE void
238	del_bindata(struct shared_bindata *);
239PRIVATE void
240	del_iplist(struct in_addr_list *);
241PRIVATE void
242	eat_whitespace(char **);
243PRIVATE int
244	eval_symbol(char **, struct host *);
245PRIVATE void
246	fill_defaults(struct host *, char **);
247PRIVATE void
248	free_host(hash_datum *);
249PRIVATE struct in_addr_list *
250	get_addresses(char **);
251PRIVATE struct shared_string *
252	get_shared_string(char **);
253PRIVATE char *
254	get_string(char **, char *, u_int *);
255PRIVATE u_int32
256	get_u_long(char **);
257PRIVATE boolean
258	goodname(char *);
259PRIVATE boolean
260	hwinscmp(hash_datum *, hash_datum *);
261PRIVATE int
262	interp_byte(char **, byte *);
263PRIVATE void
264	makelower(char *);
265PRIVATE boolean
266        nullcmp(hash_datum *, hash_datum *);
267PRIVATE int
268	process_entry(struct host *, char *);
269PRIVATE int
270	process_generic(char **, struct shared_bindata **, u_int);
271PRIVATE byte *
272	prs_haddr(char **, u_int);
273PRIVATE int
274	prs_inetaddr(char **, u_int32 *);
275PRIVATE void
276	read_entry(FILE *, char *, u_int *);
277PRIVATE char *
278	smalloc(u_int);
279
280
281/*
282 * Vendor magic cookies for CMU and RFC1048
283 */
284u_char vm_cmu[4] = VM_CMU;
285u_char vm_rfc1048[4] = VM_RFC1048;
286
287/*
288 * Main hash tables
289 */
290hash_tbl *hwhashtable;
291hash_tbl *iphashtable;
292hash_tbl *nmhashtable;
293
294/*
295 * Allocate hash tables for hardware address, ip address, and hostname
296 * (shared by bootpd and bootpef)
297 */
298void
299rdtab_init()
300{
301	hwhashtable = hash_Init(HASHTABLESIZE);
302	iphashtable = hash_Init(HASHTABLESIZE);
303	nmhashtable = hash_Init(HASHTABLESIZE);
304	if (!(hwhashtable && iphashtable && nmhashtable)) {
305		report(LOG_ERR, "Unable to allocate hash tables.");
306		exit(1);
307	}
308}
309
310
311/*
312 * Read bootptab database file.  Avoid rereading the file if the
313 * write date hasn't changed since the last time we read it.
314 */
315
316void
317readtab(force)
318	int force;
319{
320	struct host *hp;
321	FILE *fp;
322	struct stat st;
323	unsigned hashcode, buflen;
324	static char buffer[MAXENTRYLEN];
325
326	/*
327	 * Check the last modification time.
328	 */
329	if (stat(bootptab, &st) < 0) {
330		report(LOG_ERR, "stat on \"%s\": %s",
331			   bootptab, get_errmsg());
332		return;
333	}
334#ifdef DEBUG
335	if (debug > 3) {
336		char timestr[28];
337		strcpy(timestr, ctime(&(st.st_mtime)));
338		/* zap the newline */
339		timestr[24] = '\0';
340		report(LOG_INFO, "bootptab mtime: %s",
341			   timestr);
342	}
343#endif
344	if ((force == 0) &&
345		(st.st_mtime == modtime) &&
346		st.st_nlink) {
347		/*
348		 * hasn't been modified or deleted yet.
349		 */
350		return;
351	}
352	if (debug)
353		report(LOG_INFO, "reading %s\"%s\"",
354			   (modtime != 0L) ? "new " : "",
355			   bootptab);
356
357	/*
358	 * Open bootptab file.
359	 */
360	if ((fp = fopen(bootptab, "r")) == NULL) {
361		report(LOG_ERR, "error opening \"%s\": %s", bootptab, get_errmsg());
362		return;
363	}
364	/*
365	 * Record file modification time.
366	 */
367	if (fstat(fileno(fp), &st) < 0) {
368		report(LOG_ERR, "fstat: %s", get_errmsg());
369		fclose(fp);
370		return;
371	}
372	modtime = st.st_mtime;
373
374	/*
375	 * Entirely erase all hash tables.
376	 */
377	hash_Reset(hwhashtable, free_host);
378	hash_Reset(iphashtable, free_host);
379	hash_Reset(nmhashtable, free_host);
380
381	nhosts = 0;
382	nentries = 0;
383	while (TRUE) {
384		buflen = sizeof(buffer);
385		read_entry(fp, buffer, &buflen);
386		if (buflen == 0) {		/* More entries? */
387			break;
388		}
389		hp = (struct host *) smalloc(sizeof(struct host));
390		bzero((char *) hp, sizeof(*hp));
391		/* the link count it zero */
392
393		/*
394		 * Get individual info
395		 */
396		if (process_entry(hp, buffer) < 0) {
397			hp->linkcount = 1;
398			free_host((hash_datum *) hp);
399			continue;
400		}
401		/*
402		 * If this is not a dummy entry, and the IP or HW
403		 * address is not yet set, try to get them here.
404		 * Dummy entries have . as first char of name.
405		 */
406		if (goodname(hp->hostname->string)) {
407			char *hn = hp->hostname->string;
408			u_int32 value;
409			if (hp->flags.iaddr == 0) {
410				if (lookup_ipa(hn, &value)) {
411					report(LOG_ERR, "can not get IP addr for %s", hn);
412					report(LOG_ERR, "(dummy names should start with '.')");
413				} else {
414					hp->iaddr.s_addr = value;
415					hp->flags.iaddr = TRUE;
416				}
417			}
418			/* Set default subnet mask. */
419			if (hp->flags.subnet_mask == 0) {
420				if (lookup_netmask(hp->iaddr.s_addr, &value)) {
421					report(LOG_ERR, "can not get netmask for %s", hn);
422				} else {
423					hp->subnet_mask.s_addr = value;
424					hp->flags.subnet_mask = TRUE;
425				}
426			}
427		}
428		if (hp->flags.iaddr) {
429			nhosts++;
430		}
431		/* Register by HW addr if known. */
432		if (hp->flags.htype && hp->flags.haddr) {
433			/* We will either insert it or free it. */
434			hp->linkcount++;
435			hashcode = hash_HashFunction(hp->haddr, haddrlength(hp->htype));
436			if (hash_Insert(hwhashtable, hashcode, hwinscmp, hp, hp) < 0) {
437				report(LOG_NOTICE, "duplicate %s address: %s",
438					   netname(hp->htype),
439					   haddrtoa(hp->haddr, haddrlength(hp->htype)));
440				free_host((hash_datum *) hp);
441				continue;
442			}
443		}
444		/* Register by IP addr if known. */
445		if (hp->flags.iaddr) {
446			hashcode = hash_HashFunction((u_char *) & (hp->iaddr.s_addr), 4);
447			if (hash_Insert(iphashtable, hashcode, nullcmp, hp, hp) < 0) {
448				report(LOG_ERR,
449					   "hash_Insert() failed on IP address insertion");
450			} else {
451				/* Just inserted the host struct in a new hash list. */
452				hp->linkcount++;
453			}
454		}
455		/* Register by Name (always known) */
456		hashcode = hash_HashFunction((u_char *) hp->hostname->string,
457									 strlen(hp->hostname->string));
458		if (hash_Insert(nmhashtable, hashcode, nullcmp,
459						hp->hostname->string, hp) < 0) {
460			report(LOG_ERR,
461				 "hash_Insert() failed on insertion of hostname: \"%s\"",
462				   hp->hostname->string);
463		} else {
464			/* Just inserted the host struct in a new hash list. */
465			hp->linkcount++;
466		}
467
468		nentries++;
469	}
470
471	fclose(fp);
472	if (debug)
473		report(LOG_INFO, "read %d entries (%d hosts) from \"%s\"",
474			   nentries, nhosts, bootptab);
475	return;
476}
477
478
479
480/*
481 * Read an entire host entry from the file pointed to by "fp" and insert it
482 * into the memory pointed to by "buffer".  Leading whitespace and comments
483 * starting with "#" are ignored (removed).  Backslashes (\) always quote
484 * the next character except that newlines preceded by a backslash cause
485 * line-continuation onto the next line.  The entry is terminated by a
486 * newline character which is not preceded by a backslash.  Sequences
487 * surrounded by double quotes are taken literally (including newlines, but
488 * not backslashes).
489 *
490 * The "bufsiz" parameter points to an unsigned int which specifies the
491 * maximum permitted buffer size.  Upon return, this value will be replaced
492 * with the actual length of the entry (not including the null terminator).
493 *
494 * This code is a little scary. . . .  I don't like using gotos in C
495 * either, but I first wrote this as an FSM diagram and gotos seemed like
496 * the easiest way to implement it.  Maybe later I'll clean it up.
497 */
498
499PRIVATE void
500read_entry(fp, buffer, bufsiz)
501	FILE *fp;
502	char *buffer;
503	unsigned *bufsiz;
504{
505	int c, length;
506
507	length = 0;
508
509	/*
510	 * Eat whitespace, blank lines, and comment lines.
511	 */
512  top:
513	c = fgetc(fp);
514	if (c < 0) {
515		goto done;				/* Exit if end-of-file */
516	}
517	if (isspace(c)) {
518		goto top;				/* Skip over whitespace */
519	}
520	if (c == '#') {
521		while (TRUE) {			/* Eat comments after # */
522			c = fgetc(fp);
523			if (c < 0) {
524				goto done;		/* Exit if end-of-file */
525			}
526			if (c == '\n') {
527				goto top;		/* Try to read the next line */
528			}
529		}
530	}
531	ungetc(c, fp);				/* Other character, push it back to reprocess it */
532
533
534	/*
535	 * Now we're actually reading a data entry.  Get each character and
536	 * assemble it into the data buffer, processing special characters like
537	 * double quotes (") and backslashes (\).
538	 */
539
540  mainloop:
541	c = fgetc(fp);
542	switch (c) {
543	case EOF:
544	case '\n':
545		goto done;				/* Exit on EOF or newline */
546	case '\\':
547		c = fgetc(fp);			/* Backslash, read a new character */
548		if (c < 0) {
549			goto done;			/* Exit on EOF */
550		}
551		*buffer++ = c;			/* Store the literal character */
552		length++;
553		if (length < *bufsiz - 1) {
554			goto mainloop;
555		} else {
556			goto done;
557		}
558	case '"':
559		*buffer++ = '"';		/* Store double-quote */
560		length++;
561		if (length >= *bufsiz - 1) {
562			goto done;
563		}
564		while (TRUE) {			/* Special quote processing loop */
565			c = fgetc(fp);
566			switch (c) {
567			case EOF:
568				goto done;		/* Exit on EOF . . . */
569			case '"':
570				*buffer++ = '"';/* Store matching quote */
571				length++;
572				if (length < *bufsiz - 1) {
573					goto mainloop;	/* And continue main loop */
574				} else {
575					goto done;
576				}
577			case '\\':
578				if ((c = fgetc(fp)) < 0) {	/* Backslash */
579					goto done;	/* EOF. . . .*/
580				}				/* else fall through */
581			default:
582				*buffer++ = c;	/* Other character, store it */
583				length++;
584				if (length >= *bufsiz - 1) {
585					goto done;
586				}
587			}
588		}
589	case ':':
590		*buffer++ = c;			/* Store colons */
591		length++;
592		if (length >= *bufsiz - 1) {
593			goto done;
594		}
595		do {					/* But remove whitespace after them */
596			c = fgetc(fp);
597			if ((c < 0) || (c == '\n')) {
598				goto done;
599			}
600		} while (isspace(c));	/* Skip whitespace */
601
602		if (c == '\\') {		/* Backslash quotes next character */
603			c = fgetc(fp);
604			if (c < 0) {
605				goto done;
606			}
607			if (c == '\n') {
608				goto top;		/* Backslash-newline continuation */
609			}
610		}
611		/* fall through if "other" character */
612	default:
613		*buffer++ = c;			/* Store other characters */
614		length++;
615		if (length >= *bufsiz - 1) {
616			goto done;
617		}
618	}
619	goto mainloop;				/* Keep going */
620
621  done:
622	*buffer = '\0';				/* Terminate string */
623	*bufsiz = length;			/* Tell the caller its length */
624}
625
626
627
628/*
629 * Parse out all the various tags and parameters in the host entry pointed
630 * to by "src".  Stuff all the data into the appropriate fields of the
631 * host structure pointed to by "host".  If there is any problem with the
632 * entry, an error message is reported via report(), no further processing
633 * is done, and -1 is returned.  Successful calls return 0.
634 *
635 * (Some errors probably shouldn't be so completely fatal. . . .)
636 */
637
638PRIVATE int
639process_entry(host, src)
640	struct host *host;
641	char *src;
642{
643	int retval;
644	char *msg;
645
646	if (!host || *src == '\0') {
647		return -1;
648	}
649	host->hostname = get_shared_string(&src);
650#if 0
651	/* Be more liberal for the benefit of dummy tag names. */
652	if (!goodname(host->hostname->string)) {
653		report(LOG_ERR, "bad hostname: \"%s\"", host->hostname->string);
654		del_string(host->hostname);
655		return -1;
656	}
657#endif
658	current_hostname = host->hostname->string;
659	adjust(&src);
660	while (TRUE) {
661		retval = eval_symbol(&src, host);
662		if (retval == SUCCESS) {
663			adjust(&src);
664			continue;
665		}
666		if (retval == E_END_OF_ENTRY) {
667			/* The default subnet mask is set in readtab() */
668			return 0;
669		}
670		/* Some kind of error. */
671		switch (retval) {
672		case E_SYNTAX_ERROR:
673			msg = "bad syntax";
674			break;
675		case E_UNKNOWN_SYMBOL:
676			msg = "unknown symbol";
677			break;
678		case E_BAD_IPADDR:
679			msg = "bad INET address";
680			break;
681		case E_BAD_HWADDR:
682			msg = "bad hardware address";
683			break;
684		case E_BAD_LONGWORD:
685			msg = "bad longword value";
686			break;
687		case E_BAD_HWATYPE:
688			msg = "bad HW address type";
689			break;
690		case E_BAD_PATHNAME:
691			msg = "bad pathname (need leading '/')";
692			break;
693		case E_BAD_VALUE:
694			msg = "bad value";
695			break;
696		default:
697			msg = "unknown error";
698			break;
699		}						/* switch */
700		report(LOG_ERR, "in entry named \"%s\", symbol \"%s\": %s",
701			   current_hostname, current_tagname, msg);
702		return -1;
703	}
704}
705
706
707/*
708 * Macros for use in the function below:
709 */
710
711/* Parse one INET address stored directly in MEMBER. */
712#define PARSE_IA1(MEMBER) do \
713{ \
714	if (optype == OP_BOOLEAN) \
715		return E_SYNTAX_ERROR; \
716	hp->flags.MEMBER = FALSE; \
717	if (optype == OP_ADDITION) { \
718		if (prs_inetaddr(symbol, &value) < 0) \
719			return E_BAD_IPADDR; \
720		hp->MEMBER.s_addr = value; \
721		hp->flags.MEMBER = TRUE; \
722	} \
723} while (0)
724
725/* Parse a list of INET addresses pointed to by MEMBER */
726#define PARSE_IAL(MEMBER) do \
727{ \
728	if (optype == OP_BOOLEAN) \
729		return E_SYNTAX_ERROR; \
730	if (hp->flags.MEMBER) { \
731		hp->flags.MEMBER = FALSE; \
732		assert(hp->MEMBER); \
733		del_iplist(hp->MEMBER); \
734		hp->MEMBER = NULL; \
735	} \
736	if (optype == OP_ADDITION) { \
737		hp->MEMBER = get_addresses(symbol); \
738		if (hp->MEMBER == NULL) \
739			return E_SYNTAX_ERROR; \
740		hp->flags.MEMBER = TRUE; \
741	} \
742} while (0)
743
744/* Parse a shared string pointed to by MEMBER */
745#define PARSE_STR(MEMBER) do \
746{ \
747	if (optype == OP_BOOLEAN) \
748		return E_SYNTAX_ERROR; \
749	if (hp->flags.MEMBER) { \
750		hp->flags.MEMBER = FALSE; \
751		assert(hp->MEMBER); \
752		del_string(hp->MEMBER); \
753		hp->MEMBER = NULL; \
754	} \
755	if (optype == OP_ADDITION) { \
756		hp->MEMBER = get_shared_string(symbol); \
757		if (hp->MEMBER == NULL) \
758			return E_SYNTAX_ERROR; \
759		hp->flags.MEMBER = TRUE; \
760	} \
761} while (0)
762
763/* Parse an unsigned integer value for MEMBER */
764#define PARSE_UINT(MEMBER) do \
765{ \
766	if (optype == OP_BOOLEAN) \
767		return E_SYNTAX_ERROR; \
768	hp->flags.MEMBER = FALSE; \
769	if (optype == OP_ADDITION) { \
770		value = get_u_long(symbol); \
771		hp->MEMBER = value; \
772		hp->flags.MEMBER = TRUE; \
773	} \
774} while (0)
775
776/*
777 * Evaluate the two-character tag symbol pointed to by "symbol" and place
778 * the data in the structure pointed to by "hp".  The pointer pointed to
779 * by "symbol" is updated to point past the source string (but may not
780 * point to the next tag entry).
781 *
782 * Obviously, this need a few more comments. . . .
783 */
784PRIVATE int
785eval_symbol(symbol, hp)
786	char **symbol;
787	struct host *hp;
788{
789	char tmpstr[MAXSTRINGLEN];
790	byte *tmphaddr;
791	struct symbolmap *symbolptr;
792	u_int32 value;
793	int32 timeoff;
794	int i, numsymbols;
795	unsigned len;
796	int optype;					/* Indicates boolean, addition, or deletion */
797
798	eat_whitespace(symbol);
799
800	/* Make sure this is set before returning. */
801	current_tagname[0] = (*symbol)[0];
802	current_tagname[1] = (*symbol)[1];
803	current_tagname[2] = 0;
804
805	if ((*symbol)[0] == '\0') {
806		return E_END_OF_ENTRY;
807	}
808	if ((*symbol)[0] == ':') {
809		return SUCCESS;
810	}
811	if ((*symbol)[0] == 'T') {	/* generic symbol */
812		(*symbol)++;
813		value = get_u_long(symbol);
814		snprintf(current_tagname, sizeof(current_tagname),
815			"T%d", (int)value);
816		eat_whitespace(symbol);
817		if ((*symbol)[0] != '=') {
818			return E_SYNTAX_ERROR;
819		}
820		(*symbol)++;
821		if (!(hp->generic)) {
822			hp->generic = (struct shared_bindata *)
823				smalloc(sizeof(struct shared_bindata));
824		}
825		if (process_generic(symbol, &(hp->generic), (byte) (value & 0xFF)))
826			return E_SYNTAX_ERROR;
827		hp->flags.generic = TRUE;
828		return SUCCESS;
829	}
830	/*
831	 * Determine the type of operation to be done on this symbol
832	 */
833	switch ((*symbol)[2]) {
834	case '=':
835		optype = OP_ADDITION;
836		break;
837	case '@':
838		optype = OP_DELETION;
839		break;
840	case ':':
841	case '\0':
842		optype = OP_BOOLEAN;
843		break;
844	default:
845		return E_SYNTAX_ERROR;
846	}
847
848	symbolptr = symbol_list;
849	numsymbols = sizeof(symbol_list) / sizeof(struct symbolmap);
850	for (i = 0; i < numsymbols; i++) {
851		if (((symbolptr->symbol)[0] == (*symbol)[0]) &&
852			((symbolptr->symbol)[1] == (*symbol)[1])) {
853			break;
854		}
855		symbolptr++;
856	}
857	if (i >= numsymbols) {
858		return E_UNKNOWN_SYMBOL;
859	}
860	/*
861	 * Skip past the = or @ character (to point to the data) if this
862	 * isn't a boolean operation.  For boolean operations, just skip
863	 * over the two-character tag symbol (and nothing else. . . .).
864	 */
865	(*symbol) += (optype == OP_BOOLEAN) ? 2 : 3;
866
867	eat_whitespace(symbol);
868
869	/* The cases below are in order by symbolcode value. */
870	switch (symbolptr->symbolcode) {
871
872	case SYM_BOOTFILE:
873		PARSE_STR(bootfile);
874		break;
875
876	case SYM_COOKIE_SERVER:
877		PARSE_IAL(cookie_server);
878		break;
879
880	case SYM_DOMAIN_SERVER:
881		PARSE_IAL(domain_server);
882		break;
883
884	case SYM_GATEWAY:
885		PARSE_IAL(gateway);
886		break;
887
888	case SYM_HWADDR:
889		if (optype == OP_BOOLEAN)
890			return E_SYNTAX_ERROR;
891		hp->flags.haddr = FALSE;
892		if (optype == OP_ADDITION) {
893			/* Default the HW type to Ethernet */
894			if (hp->flags.htype == 0) {
895				hp->flags.htype = TRUE;
896				hp->htype = HTYPE_ETHERNET;
897			}
898			tmphaddr = prs_haddr(symbol, hp->htype);
899			if (!tmphaddr)
900				return E_BAD_HWADDR;
901			bcopy(tmphaddr, hp->haddr, haddrlength(hp->htype));
902			hp->flags.haddr = TRUE;
903		}
904		break;
905
906	case SYM_HOMEDIR:
907		PARSE_STR(homedir);
908		break;
909
910	case SYM_HTYPE:
911		if (optype == OP_BOOLEAN)
912			return E_SYNTAX_ERROR;
913		hp->flags.htype = FALSE;
914		if (optype == OP_ADDITION) {
915			value = 0L;			/* Assume an illegal value */
916			eat_whitespace(symbol);
917			if (isdigit(**symbol)) {
918				value = get_u_long(symbol);
919			} else {
920				len = sizeof(tmpstr);
921				(void) get_string(symbol, tmpstr, &len);
922				makelower(tmpstr);
923				numsymbols = sizeof(htnamemap) /
924					sizeof(struct htypename);
925				for (i = 0; i < numsymbols; i++) {
926					if (!strcmp(htnamemap[i].name, tmpstr)) {
927						break;
928					}
929				}
930				if (i < numsymbols) {
931					value = htnamemap[i].htype;
932				}
933			}
934			if (value >= hwinfocnt) {
935				return E_BAD_HWATYPE;
936			}
937			hp->htype = (byte) (value & 0xFF);
938			hp->flags.htype = TRUE;
939		}
940		break;
941
942	case SYM_IMPRESS_SERVER:
943		PARSE_IAL(impress_server);
944		break;
945
946	case SYM_IPADDR:
947		PARSE_IA1(iaddr);
948		break;
949
950	case SYM_LOG_SERVER:
951		PARSE_IAL(log_server);
952		break;
953
954	case SYM_LPR_SERVER:
955		PARSE_IAL(lpr_server);
956		break;
957
958	case SYM_NAME_SERVER:
959		PARSE_IAL(name_server);
960		break;
961
962	case SYM_RLP_SERVER:
963		PARSE_IAL(rlp_server);
964		break;
965
966	case SYM_SUBNET_MASK:
967		PARSE_IA1(subnet_mask);
968		break;
969
970	case SYM_TIME_OFFSET:
971		if (optype == OP_BOOLEAN)
972			return E_SYNTAX_ERROR;
973		hp->flags.time_offset = FALSE;
974		if (optype == OP_ADDITION) {
975			len = sizeof(tmpstr);
976			(void) get_string(symbol, tmpstr, &len);
977			if (!strncmp(tmpstr, "auto", 4)) {
978				hp->time_offset = secondswest;
979			} else {
980				if (sscanf(tmpstr, "%d", (int*)&timeoff) != 1)
981					return E_BAD_LONGWORD;
982				hp->time_offset = timeoff;
983			}
984			hp->flags.time_offset = TRUE;
985		}
986		break;
987
988	case SYM_TIME_SERVER:
989		PARSE_IAL(time_server);
990		break;
991
992	case SYM_VENDOR_MAGIC:
993		if (optype == OP_BOOLEAN)
994			return E_SYNTAX_ERROR;
995		hp->flags.vm_cookie = FALSE;
996		if (optype == OP_ADDITION) {
997			if (strncmp(*symbol, "auto", 4)) {
998				/* The string is not "auto" */
999				if (!strncmp(*symbol, "rfc", 3)) {
1000					bcopy(vm_rfc1048, hp->vm_cookie, 4);
1001				} else if (!strncmp(*symbol, "cmu", 3)) {
1002					bcopy(vm_cmu, hp->vm_cookie, 4);
1003				} else {
1004					if (!isdigit(**symbol))
1005						return E_BAD_IPADDR;
1006					if (prs_inetaddr(symbol, &value) < 0)
1007						return E_BAD_IPADDR;
1008					bcopy(&value, hp->vm_cookie, 4);
1009				}
1010				hp->flags.vm_cookie = TRUE;
1011			}
1012		}
1013		break;
1014
1015	case SYM_SIMILAR_ENTRY:
1016		switch (optype) {
1017		case OP_ADDITION:
1018			fill_defaults(hp, symbol);
1019			break;
1020		default:
1021			return E_SYNTAX_ERROR;
1022		}
1023		break;
1024
1025	case SYM_NAME_SWITCH:
1026		switch (optype) {
1027		case OP_ADDITION:
1028			return E_SYNTAX_ERROR;
1029		case OP_DELETION:
1030			hp->flags.send_name = FALSE;
1031			hp->flags.name_switch = FALSE;
1032			break;
1033		case OP_BOOLEAN:
1034			hp->flags.send_name = TRUE;
1035			hp->flags.name_switch = TRUE;
1036			break;
1037		}
1038		break;
1039
1040	case SYM_BOOTSIZE:
1041		switch (optype) {
1042		case OP_ADDITION:
1043			if (!strncmp(*symbol, "auto", 4)) {
1044				hp->flags.bootsize = TRUE;
1045				hp->flags.bootsize_auto = TRUE;
1046			} else {
1047				hp->bootsize = (unsigned int) get_u_long(symbol);
1048				hp->flags.bootsize = TRUE;
1049				hp->flags.bootsize_auto = FALSE;
1050			}
1051			break;
1052		case OP_DELETION:
1053			hp->flags.bootsize = FALSE;
1054			break;
1055		case OP_BOOLEAN:
1056			hp->flags.bootsize = TRUE;
1057			hp->flags.bootsize_auto = TRUE;
1058			break;
1059		}
1060		break;
1061
1062	case SYM_BOOT_SERVER:
1063		PARSE_IA1(bootserver);
1064		break;
1065
1066	case SYM_TFTPDIR:
1067		PARSE_STR(tftpdir);
1068		if ((hp->tftpdir != NULL) &&
1069			(hp->tftpdir->string[0] != '/'))
1070			return E_BAD_PATHNAME;
1071		break;
1072
1073	case SYM_DUMP_FILE:
1074		PARSE_STR(dump_file);
1075		break;
1076
1077	case SYM_DOMAIN_NAME:
1078		PARSE_STR(domain_name);
1079		break;
1080
1081	case SYM_SWAP_SERVER:
1082		PARSE_IA1(swap_server);
1083		break;
1084
1085	case SYM_ROOT_PATH:
1086		PARSE_STR(root_path);
1087		break;
1088
1089	case SYM_EXTEN_FILE:
1090		PARSE_STR(exten_file);
1091		break;
1092
1093	case SYM_REPLY_ADDR:
1094		PARSE_IA1(reply_addr);
1095		break;
1096
1097	case SYM_NIS_DOMAIN:
1098		PARSE_STR(nis_domain);
1099		break;
1100
1101	case SYM_NIS_SERVER:
1102		PARSE_IAL(nis_server);
1103		break;
1104
1105	case SYM_NTP_SERVER:
1106		PARSE_IAL(ntp_server);
1107		break;
1108
1109#ifdef	YORK_EX_OPTION
1110	case SYM_EXEC_FILE:
1111		PARSE_STR(exec_file);
1112		break;
1113#endif
1114
1115	case SYM_MSG_SIZE:
1116		PARSE_UINT(msg_size);
1117		if (hp->msg_size < BP_MINPKTSZ ||
1118			hp->msg_size > MAX_MSG_SIZE)
1119			return E_BAD_VALUE;
1120		break;
1121
1122	case SYM_MIN_WAIT:
1123		PARSE_UINT(min_wait);
1124		break;
1125
1126		/* XXX - Add new tags here */
1127
1128	default:
1129		return E_UNKNOWN_SYMBOL;
1130
1131	}							/* switch symbolcode */
1132
1133	return SUCCESS;
1134}
1135#undef	PARSE_IA1
1136#undef	PARSE_IAL
1137#undef	PARSE_STR
1138
1139
1140
1141
1142/*
1143 * Read a string from the buffer indirectly pointed to through "src" and
1144 * move it into the buffer pointed to by "dest".  A pointer to the maximum
1145 * allowable length of the string (including null-terminator) is passed as
1146 * "length".  The actual length of the string which was read is returned in
1147 * the unsigned integer pointed to by "length".  This value is the same as
1148 * that which would be returned by applying the strlen() function on the
1149 * destination string (i.e the terminating null is not counted as a
1150 * character).  Trailing whitespace is removed from the string.  For
1151 * convenience, the function returns the new value of "dest".
1152 *
1153 * The string is read until the maximum number of characters, an unquoted
1154 * colon (:), or a null character is read.  The return string in "dest" is
1155 * null-terminated.
1156 */
1157
1158PRIVATE char *
1159get_string(src, dest, length)
1160	char **src, *dest;
1161	unsigned *length;
1162{
1163	int n, len, quoteflag;
1164
1165	quoteflag = FALSE;
1166	n = 0;
1167	len = *length - 1;
1168	while ((n < len) && (**src)) {
1169		if (!quoteflag && (**src == ':')) {
1170			break;
1171		}
1172		if (**src == '"') {
1173			(*src)++;
1174			quoteflag = !quoteflag;
1175			continue;
1176		}
1177		if (**src == '\\') {
1178			(*src)++;
1179			if (!**src) {
1180				break;
1181			}
1182		}
1183		*dest++ = *(*src)++;
1184		n++;
1185	}
1186
1187	/*
1188	 * Remove that troublesome trailing whitespace. . .
1189	 */
1190	while ((n > 0) && isspace(dest[-1])) {
1191		dest--;
1192		n--;
1193	}
1194
1195	*dest = '\0';
1196	*length = n;
1197	return dest;
1198}
1199
1200
1201
1202/*
1203 * Read the string indirectly pointed to by "src", update the caller's
1204 * pointer, and return a pointer to a malloc'ed shared_string structure
1205 * containing the string.
1206 *
1207 * The string is read using the same rules as get_string() above.
1208 */
1209
1210PRIVATE struct shared_string *
1211get_shared_string(src)
1212	char **src;
1213{
1214	char retstring[MAXSTRINGLEN];
1215	struct shared_string *s;
1216	unsigned length;
1217
1218	length = sizeof(retstring);
1219	(void) get_string(src, retstring, &length);
1220
1221	s = (struct shared_string *) smalloc(sizeof(struct shared_string)
1222										 + length);
1223	s->linkcount = 1;
1224	strcpy(s->string, retstring);
1225
1226	return s;
1227}
1228
1229
1230
1231/*
1232 * Load RFC1048 generic information directly into a memory buffer.
1233 *
1234 * "src" indirectly points to the ASCII representation of the generic data.
1235 * "dest" points to a string structure which is updated to point to a new
1236 * string with the new data appended to the old string.  The old string is
1237 * freed.
1238 *
1239 * The given tag value is inserted with the new data.
1240 *
1241 * The data may be represented as either a stream of hexadecimal numbers
1242 * representing bytes (any or all bytes may optionally start with '0x' and
1243 * be separated with periods ".") or as a quoted string of ASCII
1244 * characters (the quotes are required).
1245 */
1246
1247PRIVATE int
1248process_generic(src, dest, tagvalue)
1249	char **src;
1250	struct shared_bindata **dest;
1251	u_int tagvalue;
1252{
1253	byte tmpbuf[MAXBUFLEN];
1254	byte *str;
1255	struct shared_bindata *bdata;
1256	u_int newlength, oldlength;
1257
1258	str = tmpbuf;
1259	*str++ = (tagvalue & 0xFF);	/* Store tag value */
1260	str++;						/* Skip over length field */
1261	if ((*src)[0] == '"') {		/* ASCII data */
1262		newlength = sizeof(tmpbuf) - 2;	/* Set maximum allowed length */
1263		(void) get_string(src, (char *) str, &newlength);
1264		newlength++;			/* null terminator */
1265	} else {					/* Numeric data */
1266		newlength = 0;
1267		while (newlength < sizeof(tmpbuf) - 2) {
1268			if (interp_byte(src, str++) < 0)
1269				break;
1270			newlength++;
1271			if (**src == '.') {
1272				(*src)++;
1273			}
1274		}
1275	}
1276	if ((*src)[0] != ':')
1277		return -1;
1278
1279	tmpbuf[1] = (newlength & 0xFF);
1280	oldlength = ((*dest)->length);
1281	bdata = (struct shared_bindata *) smalloc(sizeof(struct shared_bindata)
1282											+ oldlength + newlength + 1);
1283	if (oldlength > 0) {
1284		bcopy((*dest)->data, bdata->data, oldlength);
1285	}
1286	bcopy(tmpbuf, bdata->data + oldlength, newlength + 2);
1287	bdata->length = oldlength + newlength + 2;
1288	bdata->linkcount = 1;
1289	if (*dest) {
1290		del_bindata(*dest);
1291	}
1292	*dest = bdata;
1293	return 0;
1294}
1295
1296
1297
1298/*
1299 * Verify that the given string makes sense as a hostname (according to
1300 * Appendix 1, page 29 of RFC882).
1301 *
1302 * Return TRUE for good names, FALSE otherwise.
1303 */
1304
1305PRIVATE boolean
1306goodname(hostname)
1307	register char *hostname;
1308{
1309	do {
1310		if (!isalpha(*hostname++)) {	/* First character must be a letter */
1311			return FALSE;
1312		}
1313		while (isalnum(*hostname) ||
1314			   (*hostname == '-') ||
1315			   (*hostname == '_') )
1316		{
1317			hostname++;			/* Alphanumeric or a hyphen */
1318		}
1319		if (!isalnum(hostname[-1])) {	/* Last must be alphanumeric */
1320			return FALSE;
1321		}
1322		if (*hostname == '\0') {/* Done? */
1323			return TRUE;
1324		}
1325	} while (*hostname++ == '.');	/* Dot, loop for next label */
1326
1327	return FALSE;				/* If it's not a dot, lose */
1328}
1329
1330
1331
1332/*
1333 * Null compare function -- always returns FALSE so an element is always
1334 * inserted into a hash table (i.e. there is never a collision with an
1335 * existing element).
1336 */
1337
1338PRIVATE boolean
1339nullcmp(d1, d2)
1340	hash_datum *d1, *d2;
1341{
1342	return FALSE;
1343}
1344
1345
1346/*
1347 * Function for comparing a string with the hostname field of a host
1348 * structure.
1349 */
1350
1351boolean
1352nmcmp(d1, d2)
1353	hash_datum *d1, *d2;
1354{
1355	char *name = (char *) d1;	/* XXX - OK? */
1356	struct host *hp = (struct host *) d2;
1357
1358	return !strcmp(name, hp->hostname->string);
1359}
1360
1361
1362/*
1363 * Compare function to determine whether two hardware addresses are
1364 * equivalent.  Returns TRUE if "host1" and "host2" are equivalent, FALSE
1365 * otherwise.
1366 *
1367 * If the hardware addresses of "host1" and "host2" are identical, but
1368 * they are on different IP subnets, this function returns FALSE.
1369 *
1370 * This function is used when inserting elements into the hardware address
1371 * hash table.
1372 */
1373
1374PRIVATE boolean
1375hwinscmp(d1, d2)
1376	hash_datum *d1, *d2;
1377{
1378	struct host *host1 = (struct host *) d1;
1379	struct host *host2 = (struct host *) d2;
1380
1381	if (host1->htype != host2->htype) {
1382		return FALSE;
1383	}
1384	if (bcmp(host1->haddr, host2->haddr, haddrlength(host1->htype))) {
1385		return FALSE;
1386	}
1387	/* XXX - Is the subnet_mask field set yet? */
1388	if ((host1->subnet_mask.s_addr) == (host2->subnet_mask.s_addr)) {
1389		if (((host1->iaddr.s_addr) & (host1->subnet_mask.s_addr)) !=
1390			((host2->iaddr.s_addr) & (host2->subnet_mask.s_addr)))
1391		{
1392			return FALSE;
1393		}
1394	}
1395	return TRUE;
1396}
1397
1398
1399/*
1400 * Macros for use in the function below:
1401 */
1402
1403#define DUP_COPY(MEMBER) do \
1404{ \
1405	if (!hp->flags.MEMBER) { \
1406		if ((hp->flags.MEMBER = hp2->flags.MEMBER) != 0) { \
1407			hp->MEMBER = hp2->MEMBER; \
1408		} \
1409	} \
1410} while (0)
1411
1412#define DUP_LINK(MEMBER) do \
1413{ \
1414	if (!hp->flags.MEMBER) { \
1415		if ((hp->flags.MEMBER = hp2->flags.MEMBER) != 0) { \
1416			assert(hp2->MEMBER); \
1417			hp->MEMBER = hp2->MEMBER; \
1418			(hp->MEMBER->linkcount)++; \
1419		} \
1420	} \
1421} while (0)
1422
1423/*
1424 * Process the "similar entry" symbol.
1425 *
1426 * The host specified as the value of the "tc" symbol is used as a template
1427 * for the current host entry.  Symbol values not explicitly set in the
1428 * current host entry are inferred from the template entry.
1429 */
1430PRIVATE void
1431fill_defaults(hp, src)
1432	struct host *hp;
1433	char **src;
1434{
1435	unsigned int tlen, hashcode;
1436	struct host *hp2;
1437	char tstring[MAXSTRINGLEN];
1438
1439	tlen = sizeof(tstring);
1440	(void) get_string(src, tstring, &tlen);
1441	hashcode = hash_HashFunction((u_char *) tstring, tlen);
1442	hp2 = (struct host *) hash_Lookup(nmhashtable, hashcode, nmcmp, tstring);
1443
1444	if (hp2 == NULL) {
1445		report(LOG_ERR, "can't find tc=\"%s\"", tstring);
1446		return;
1447	}
1448	DUP_LINK(bootfile);
1449	DUP_LINK(cookie_server);
1450	DUP_LINK(domain_server);
1451	DUP_LINK(gateway);
1452	/* haddr not copied */
1453	DUP_LINK(homedir);
1454	DUP_COPY(htype);
1455
1456	DUP_LINK(impress_server);
1457	/* iaddr not copied */
1458	DUP_LINK(log_server);
1459	DUP_LINK(lpr_server);
1460	DUP_LINK(name_server);
1461	DUP_LINK(rlp_server);
1462
1463	DUP_COPY(subnet_mask);
1464	DUP_COPY(time_offset);
1465	DUP_LINK(time_server);
1466
1467	if (!hp->flags.vm_cookie) {
1468		if ((hp->flags.vm_cookie = hp2->flags.vm_cookie)) {
1469			bcopy(hp2->vm_cookie, hp->vm_cookie, 4);
1470		}
1471	}
1472	if (!hp->flags.name_switch) {
1473		if ((hp->flags.name_switch = hp2->flags.name_switch)) {
1474			hp->flags.send_name = hp2->flags.send_name;
1475		}
1476	}
1477	if (!hp->flags.bootsize) {
1478		if ((hp->flags.bootsize = hp2->flags.bootsize)) {
1479			hp->flags.bootsize_auto = hp2->flags.bootsize_auto;
1480			hp->bootsize = hp2->bootsize;
1481		}
1482	}
1483	DUP_COPY(bootserver);
1484
1485	DUP_LINK(tftpdir);
1486	DUP_LINK(dump_file);
1487	DUP_LINK(domain_name);
1488
1489	DUP_COPY(swap_server);
1490	DUP_LINK(root_path);
1491	DUP_LINK(exten_file);
1492
1493	DUP_COPY(reply_addr);
1494
1495	DUP_LINK(nis_domain);
1496	DUP_LINK(nis_server);
1497	DUP_LINK(ntp_server);
1498
1499#ifdef	YORK_EX_OPTION
1500	DUP_LINK(exec_file);
1501#endif
1502
1503	DUP_COPY(msg_size);
1504	DUP_COPY(min_wait);
1505
1506	/* XXX - Add new tags here */
1507
1508	DUP_LINK(generic);
1509
1510}
1511#undef	DUP_COPY
1512#undef	DUP_LINK
1513
1514
1515
1516/*
1517 * This function adjusts the caller's pointer to point just past the
1518 * first-encountered colon.  If it runs into a null character, it leaves
1519 * the pointer pointing to it.
1520 */
1521
1522PRIVATE void
1523adjust(s)
1524	char **s;
1525{
1526	register char *t;
1527
1528	t = *s;
1529	while (*t && (*t != ':')) {
1530		t++;
1531	}
1532	if (*t) {
1533		t++;
1534	}
1535	*s = t;
1536}
1537
1538
1539
1540
1541/*
1542 * This function adjusts the caller's pointer to point to the first
1543 * non-whitespace character.  If it runs into a null character, it leaves
1544 * the pointer pointing to it.
1545 */
1546
1547PRIVATE void
1548eat_whitespace(s)
1549	char **s;
1550{
1551	register char *t;
1552
1553	t = *s;
1554	while (*t && isspace(*t)) {
1555		t++;
1556	}
1557	*s = t;
1558}
1559
1560
1561
1562/*
1563 * This function converts the given string to all lowercase.
1564 */
1565
1566PRIVATE void
1567makelower(s)
1568	char *s;
1569{
1570	while (*s) {
1571		if (isupper(*s)) {
1572			*s = tolower(*s);
1573		}
1574		s++;
1575	}
1576}
1577
1578
1579
1580/*
1581 *
1582 *	N O T E :
1583 *
1584 *	In many of the functions which follow, a parameter such as "src" or
1585 *	"symbol" is passed as a pointer to a pointer to something.  This is
1586 *	done for the purpose of letting the called function update the
1587 *	caller's copy of the parameter (i.e. to effect call-by-reference
1588 *	parameter passing).  The value of the actual parameter is only used
1589 *	to locate the real parameter of interest and then update this indirect
1590 *	parameter.
1591 *
1592 *	I'm sure somebody out there won't like this. . . .
1593 *  (Yea, because it usually makes code slower... -gwr)
1594 *
1595 */
1596
1597
1598
1599/*
1600 * "src" points to a character pointer which points to an ASCII string of
1601 * whitespace-separated IP addresses.  A pointer to an in_addr_list
1602 * structure containing the list of addresses is returned.  NULL is
1603 * returned if no addresses were found at all.  The pointer pointed to by
1604 * "src" is updated to point to the first non-address (illegal) character.
1605 */
1606
1607PRIVATE struct in_addr_list *
1608get_addresses(src)
1609	char **src;
1610{
1611	struct in_addr tmpaddrlist[MAXINADDRS];
1612	struct in_addr *address1, *address2;
1613	struct in_addr_list *result;
1614	unsigned addrcount, totalsize;
1615
1616	address1 = tmpaddrlist;
1617	for (addrcount = 0; addrcount < MAXINADDRS; addrcount++) {
1618		while (isspace(**src) || (**src == ',')) {
1619			(*src)++;
1620		}
1621		if (!**src) {			/* Quit if nothing more */
1622			break;
1623		}
1624		if (prs_inetaddr(src, &(address1->s_addr)) < 0) {
1625			break;
1626		}
1627		address1++;				/* Point to next address slot */
1628	}
1629	if (addrcount < 1) {
1630		result = NULL;
1631	} else {
1632		totalsize = sizeof(struct in_addr_list)
1633		+			(addrcount - 1) * sizeof(struct in_addr);
1634		result = (struct in_addr_list *) smalloc(totalsize);
1635		result->linkcount = 1;
1636		result->addrcount = addrcount;
1637		address1 = tmpaddrlist;
1638		address2 = result->addr;
1639		for (; addrcount > 0; addrcount--) {
1640			address2->s_addr = address1->s_addr;
1641			address1++;
1642			address2++;
1643		}
1644	}
1645	return result;
1646}
1647
1648
1649
1650/*
1651 * prs_inetaddr(src, result)
1652 *
1653 * "src" is a value-result parameter; the pointer it points to is updated
1654 * to point to the next data position.   "result" points to an unsigned long
1655 * in which an address is returned.
1656 *
1657 * This function parses the IP address string in ASCII "dot notation" pointed
1658 * to by (*src) and places the result (in network byte order) in the unsigned
1659 * long pointed to by "result".  For malformed addresses, -1 is returned,
1660 * (*src) points to the first illegal character, and the unsigned long pointed
1661 * to by "result" is unchanged.  Successful calls return 0.
1662 */
1663
1664PRIVATE int
1665prs_inetaddr(src, result)
1666	char **src;
1667	u_int32 *result;
1668{
1669	char tmpstr[MAXSTRINGLEN];
1670	register u_int32 value;
1671	u_int32 parts[4], *pp;
1672	int n;
1673	char *s, *t;
1674
1675	/* Leading alpha char causes IP addr lookup. */
1676	if (isalpha(**src)) {
1677		/* Lookup IP address. */
1678		s = *src;
1679		t = tmpstr;
1680		while ((isalnum(*s) || (*s == '.') ||
1681				(*s == '-') || (*s == '_') ) &&
1682			   (t < &tmpstr[MAXSTRINGLEN - 1]) )
1683			*t++ = *s++;
1684		*t = '\0';
1685		*src = s;
1686
1687		n = lookup_ipa(tmpstr, result);
1688		if (n < 0)
1689			report(LOG_ERR, "can not get IP addr for %s", tmpstr);
1690		return n;
1691	}
1692
1693	/*
1694	 * Parse an address in Internet format:
1695	 *	a.b.c.d
1696	 *	a.b.c	(with c treated as 16-bits)
1697	 *	a.b	(with b treated as 24 bits)
1698	 */
1699	pp = parts;
1700  loop:
1701	/* If it's not a digit, return error. */
1702	if (!isdigit(**src))
1703		return -1;
1704	*pp++ = get_u_long(src);
1705	if (**src == '.') {
1706		if (pp < (parts + 4)) {
1707			(*src)++;
1708			goto loop;
1709		}
1710		return (-1);
1711	}
1712#if 0
1713	/* This is handled by the caller. */
1714	if (**src && !(isspace(**src) || (**src == ':'))) {
1715		return (-1);
1716	}
1717#endif
1718
1719	/*
1720	 * Construct the address according to
1721	 * the number of parts specified.
1722	 */
1723	n = pp - parts;
1724	switch (n) {
1725	case 1:					/* a -- 32 bits */
1726		value = parts[0];
1727		break;
1728	case 2:					/* a.b -- 8.24 bits */
1729		value = (parts[0] << 24) | (parts[1] & 0xFFFFFF);
1730		break;
1731	case 3:					/* a.b.c -- 8.8.16 bits */
1732		value = (parts[0] << 24) | ((parts[1] & 0xFF) << 16) |
1733			(parts[2] & 0xFFFF);
1734		break;
1735	case 4:					/* a.b.c.d -- 8.8.8.8 bits */
1736		value = (parts[0] << 24) | ((parts[1] & 0xFF) << 16) |
1737			((parts[2] & 0xFF) << 8) | (parts[3] & 0xFF);
1738		break;
1739	default:
1740		return (-1);
1741	}
1742	*result = htonl(value);
1743	return (0);
1744}
1745
1746
1747
1748/*
1749 * "src" points to a pointer which in turn points to a hexadecimal ASCII
1750 * string.  This string is interpreted as a hardware address and returned
1751 * as a pointer to the actual hardware address, represented as an array of
1752 * bytes.
1753 *
1754 * The ASCII string must have the proper number of digits for the specified
1755 * hardware type (e.g. twelve digits for a 48-bit Ethernet address).
1756 * Two-digit sequences (bytes) may be separated with periods (.)  and/or
1757 * prefixed with '0x' for readability, but this is not required.
1758 *
1759 * For bad addresses, the pointer which "src" points to is updated to point
1760 * to the start of the first two-digit sequence which was bad, and the
1761 * function returns a NULL pointer.
1762 */
1763
1764PRIVATE byte *
1765prs_haddr(src, htype)
1766	char **src;
1767	u_int htype;
1768{
1769	static byte haddr[MAXHADDRLEN];
1770	byte *hap;
1771	char tmpstr[MAXSTRINGLEN];
1772	u_int tmplen;
1773	unsigned hal;
1774	char *p;
1775
1776	hal = haddrlength(htype);	/* Get length of this address type */
1777	if (hal <= 0) {
1778		report(LOG_ERR, "Invalid addr type for HW addr parse");
1779		return NULL;
1780	}
1781	tmplen = sizeof(tmpstr);
1782	get_string(src, tmpstr, &tmplen);
1783	p = tmpstr;
1784
1785	/* If it's a valid host name, try to lookup the HW address. */
1786	if (goodname(p)) {
1787		/* Lookup Hardware Address for hostname. */
1788		if ((hap = lookup_hwa(p, htype)) != NULL)
1789			return hap; /* success */
1790		report(LOG_ERR, "Add 0x prefix if hex value starts with A-F");
1791		/* OK, assume it must be numeric. */
1792	}
1793
1794	hap = haddr;
1795	while (hap < haddr + hal) {
1796		if ((*p == '.') || (*p == ':'))
1797			p++;
1798		if (interp_byte(&p, hap++) < 0) {
1799			return NULL;
1800		}
1801	}
1802	return haddr;
1803}
1804
1805
1806
1807/*
1808 * "src" is a pointer to a character pointer which in turn points to a
1809 * hexadecimal ASCII representation of a byte.  This byte is read, the
1810 * character pointer is updated, and the result is deposited into the
1811 * byte pointed to by "retbyte".
1812 *
1813 * The usual '0x' notation is allowed but not required.  The number must be
1814 * a two digit hexadecimal number.  If the number is invalid, "src" and
1815 * "retbyte" are left untouched and -1 is returned as the function value.
1816 * Successful calls return 0.
1817 */
1818
1819PRIVATE int
1820interp_byte(src, retbyte)
1821	char **src;
1822	byte *retbyte;
1823{
1824	int v;
1825
1826	if ((*src)[0] == '0' &&
1827		((*src)[1] == 'x' ||
1828		 (*src)[1] == 'X')) {
1829		(*src) += 2;			/* allow 0x for hex, but don't require it */
1830	}
1831	if (!isxdigit((*src)[0]) || !isxdigit((*src)[1])) {
1832		return -1;
1833	}
1834	if (sscanf(*src, "%2x", &v) != 1) {
1835		return -1;
1836	}
1837	(*src) += 2;
1838	*retbyte = (byte) (v & 0xFF);
1839	return 0;
1840}
1841
1842
1843
1844/*
1845 * The parameter "src" points to a character pointer which points to an
1846 * ASCII string representation of an unsigned number.  The number is
1847 * returned as an unsigned long and the character pointer is updated to
1848 * point to the first illegal character.
1849 */
1850
1851PRIVATE u_int32
1852get_u_long(src)
1853	char **src;
1854{
1855	register u_int32 value, base;
1856	char c;
1857
1858	/*
1859	 * Collect number up to first illegal character.  Values are specified
1860	 * as for C:  0x=hex, 0=octal, other=decimal.
1861	 */
1862	value = 0;
1863	base = 10;
1864	if (**src == '0') {
1865		base = 8;
1866		(*src)++;
1867	}
1868	if (**src == 'x' || **src == 'X') {
1869		base = 16;
1870		(*src)++;
1871	}
1872	while ((c = **src)) {
1873		if (isdigit(c)) {
1874			value = (value * base) + (c - '0');
1875			(*src)++;
1876			continue;
1877		}
1878		if (base == 16 && isxdigit(c)) {
1879			value = (value << 4) + ((c & ~32) + 10 - 'A');
1880			(*src)++;
1881			continue;
1882		}
1883		break;
1884	}
1885	return value;
1886}
1887
1888
1889
1890/*
1891 * Routines for deletion of data associated with the main data structure.
1892 */
1893
1894
1895/*
1896 * Frees the entire host data structure given.  Does nothing if the passed
1897 * pointer is NULL.
1898 */
1899
1900PRIVATE void
1901free_host(hmp)
1902	hash_datum *hmp;
1903{
1904	struct host *hostptr = (struct host *) hmp;
1905	if (hostptr == NULL)
1906		return;
1907	assert(hostptr->linkcount > 0);
1908	if (--(hostptr->linkcount))
1909		return;					/* Still has references */
1910	del_iplist(hostptr->cookie_server);
1911	del_iplist(hostptr->domain_server);
1912	del_iplist(hostptr->gateway);
1913	del_iplist(hostptr->impress_server);
1914	del_iplist(hostptr->log_server);
1915	del_iplist(hostptr->lpr_server);
1916	del_iplist(hostptr->name_server);
1917	del_iplist(hostptr->rlp_server);
1918	del_iplist(hostptr->time_server);
1919	del_iplist(hostptr->nis_server);
1920	del_iplist(hostptr->ntp_server);
1921
1922	/*
1923	 * XXX - Add new tags here
1924	 * (if the value is an IP list)
1925	 */
1926
1927	del_string(hostptr->hostname);
1928	del_string(hostptr->homedir);
1929	del_string(hostptr->bootfile);
1930	del_string(hostptr->tftpdir);
1931	del_string(hostptr->root_path);
1932	del_string(hostptr->domain_name);
1933	del_string(hostptr->dump_file);
1934	del_string(hostptr->exten_file);
1935	del_string(hostptr->nis_domain);
1936
1937#ifdef	YORK_EX_OPTION
1938	del_string(hostptr->exec_file);
1939#endif
1940
1941	/*
1942	 * XXX - Add new tags here
1943	 * (if it is a shared string)
1944	 */
1945
1946	del_bindata(hostptr->generic);
1947	free((char *) hostptr);
1948}
1949
1950
1951
1952/*
1953 * Decrements the linkcount on the given IP address data structure.  If the
1954 * linkcount goes to zero, the memory associated with the data is freed.
1955 */
1956
1957PRIVATE void
1958del_iplist(iplist)
1959	struct in_addr_list *iplist;
1960{
1961	if (iplist) {
1962		if (!(--(iplist->linkcount))) {
1963			free((char *) iplist);
1964		}
1965	}
1966}
1967
1968
1969
1970/*
1971 * Decrements the linkcount on a string data structure.  If the count
1972 * goes to zero, the memory associated with the string is freed.  Does
1973 * nothing if the passed pointer is NULL.
1974 */
1975
1976PRIVATE void
1977del_string(stringptr)
1978	struct shared_string *stringptr;
1979{
1980	if (stringptr) {
1981		if (!(--(stringptr->linkcount))) {
1982			free((char *) stringptr);
1983		}
1984	}
1985}
1986
1987
1988
1989/*
1990 * Decrements the linkcount on a shared_bindata data structure.  If the
1991 * count goes to zero, the memory associated with the data is freed.  Does
1992 * nothing if the passed pointer is NULL.
1993 */
1994
1995PRIVATE void
1996del_bindata(dataptr)
1997	struct shared_bindata *dataptr;
1998{
1999	if (dataptr) {
2000		if (!(--(dataptr->linkcount))) {
2001			free((char *) dataptr);
2002		}
2003	}
2004}
2005
2006
2007
2008
2009/* smalloc()  --  safe malloc()
2010 *
2011 * Always returns a valid pointer (if it returns at all).  The allocated
2012 * memory is initialized to all zeros.  If malloc() returns an error, a
2013 * message is printed using the report() function and the program aborts
2014 * with a status of 1.
2015 */
2016
2017PRIVATE char *
2018smalloc(nbytes)
2019	unsigned nbytes;
2020{
2021	char *retvalue;
2022
2023	retvalue = malloc(nbytes);
2024	if (!retvalue) {
2025		report(LOG_ERR, "malloc() failure -- exiting");
2026		exit(1);
2027	}
2028	bzero(retvalue, nbytes);
2029	return retvalue;
2030}
2031
2032
2033/*
2034 * Compare function to determine whether two hardware addresses are
2035 * equivalent.  Returns TRUE if "host1" and "host2" are equivalent, FALSE
2036 * otherwise.
2037 *
2038 * This function is used when retrieving elements from the hardware address
2039 * hash table.
2040 */
2041
2042boolean
2043hwlookcmp(d1, d2)
2044	hash_datum *d1, *d2;
2045{
2046	struct host *host1 = (struct host *) d1;
2047	struct host *host2 = (struct host *) d2;
2048
2049	if (host1->htype != host2->htype) {
2050		return FALSE;
2051	}
2052	if (bcmp(host1->haddr, host2->haddr, haddrlength(host1->htype))) {
2053		return FALSE;
2054	}
2055	return TRUE;
2056}
2057
2058
2059/*
2060 * Compare function for doing IP address hash table lookup.
2061 */
2062
2063boolean
2064iplookcmp(d1, d2)
2065	hash_datum *d1, *d2;
2066{
2067	struct host *host1 = (struct host *) d1;
2068	struct host *host2 = (struct host *) d2;
2069
2070	return (host1->iaddr.s_addr == host2->iaddr.s_addr);
2071}
2072
2073/*
2074 * Local Variables:
2075 * tab-width: 4
2076 * c-indent-level: 4
2077 * c-argdecl-indent: 4
2078 * c-continued-statement-offset: 4
2079 * c-continued-brace-offset: -4
2080 * c-label-offset: -4
2081 * c-brace-offset: 0
2082 * End:
2083 */
2084