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