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