readfile.c revision 1.5
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#include <sys/cdefs.h>
24#ifndef lint
25__RCSID("$NetBSD: readfile.c,v 1.5 1998/03/14 04:39:55 lukem Exp $");
26#endif
27
28
29/*
30 * bootpd configuration file reading code.
31 *
32 * The routines in this file deal with reading, interpreting, and storing
33 * the information found in the bootpd configuration file (usually
34 * /etc/bootptab).
35 */
36
37
38#include <sys/errno.h>
39#include <sys/types.h>
40#include <sys/stat.h>
41#include <sys/file.h>
42#include <sys/time.h>
43#include <netinet/in.h>
44
45#include <stdlib.h>
46#include <stdio.h>
47#include <string.h>
48#include <ctype.h>
49#include <assert.h>
50#include <syslog.h>
51
52#ifndef USE_BFUNCS
53#include <memory.h>
54/* Yes, memcpy is OK here (no overlapped copies). */
55#define	bcopy(a,b,c)	memcpy(b,a,c)
56#define	bzero(p,l)	memset(p,0,l)
57#define	bcmp(a,b,c)	memcmp(a,b,c)
58#endif
59
60#include "bootp.h"
61#include "hash.h"
62#include "hwaddr.h"
63#include "lookup.h"
64#include "readfile.h"
65#include "report.h"
66#include "tzone.h"
67#include "bootpd.h"
68
69#define HASHTABLESIZE		257	/* Hash table size (prime) */
70
71/* Non-standard hardware address type (see bootp.h) */
72#define HTYPE_DIRECT	0
73
74/* Error codes returned by eval_symbol: */
75#define SUCCESS			  0
76#define E_END_OF_ENTRY		(-1)
77#define E_SYNTAX_ERROR		(-2)
78#define E_UNKNOWN_SYMBOL	(-3)
79#define E_BAD_IPADDR		(-4)
80#define E_BAD_HWADDR		(-5)
81#define E_BAD_LONGWORD		(-6)
82#define E_BAD_HWATYPE		(-7)
83#define E_BAD_PATHNAME		(-8)
84#define E_BAD_VALUE 		(-9)
85
86/* Tag idendities. */
87#define SYM_NULL		  0
88#define SYM_BOOTFILE		  1
89#define SYM_COOKIE_SERVER	  2
90#define SYM_DOMAIN_SERVER	  3
91#define SYM_GATEWAY		  4
92#define SYM_HWADDR		  5
93#define SYM_HOMEDIR		  6
94#define SYM_HTYPE		  7
95#define SYM_IMPRESS_SERVER	  8
96#define SYM_IPADDR		  9
97#define SYM_LOG_SERVER		 10
98#define SYM_LPR_SERVER		 11
99#define SYM_NAME_SERVER		 12
100#define SYM_RLP_SERVER		 13
101#define SYM_SUBNET_MASK		 14
102#define SYM_TIME_OFFSET		 15
103#define SYM_TIME_SERVER		 16
104#define SYM_VENDOR_MAGIC	 17
105#define SYM_SIMILAR_ENTRY	 18
106#define SYM_NAME_SWITCH		 19
107#define SYM_BOOTSIZE		 20
108#define SYM_BOOT_SERVER		 22
109#define SYM_TFTPDIR		 23
110#define SYM_DUMP_FILE		 24
111#define SYM_DOMAIN_NAME          25
112#define SYM_SWAP_SERVER          26
113#define SYM_ROOT_PATH            27
114#define SYM_EXTEN_FILE           28
115#define SYM_REPLY_ADDR           29
116#define SYM_NIS_DOMAIN           30	/* RFC 1533 */
117#define SYM_NIS_SERVER           31	/* RFC 1533 */
118#define SYM_NTP_SERVER           32	/* RFC 1533 */
119#define SYM_EXEC_FILE		 33	/* YORK_EX_OPTION */
120#define SYM_MSG_SIZE 		 34
121#define SYM_MIN_WAIT		 35
122/* XXX - Add new tags here */
123
124#define OP_ADDITION		  1	/* Operations on tags */
125#define OP_DELETION		  2
126#define OP_BOOLEAN		  3
127
128#define MAXINADDRS		 16	/* Max size of an IP address list */
129#define MAXBUFLEN		256	/* Max temp buffer space */
130#define MAXENTRYLEN	       2048	/* Max size of an entire entry */
131
132
133
134/*
135 * Structure used to map a configuration-file symbol (such as "ds") to a
136 * unique integer.
137 */
138
139struct symbolmap {
140	char *symbol;
141	int symbolcode;
142};
143
144
145struct htypename {
146	char *name;
147	byte htype;
148};
149
150
151PRIVATE int nhosts;				/* Number of hosts (/w hw or IP address) */
152PRIVATE int nentries;			/* Total number of entries */
153PRIVATE int32 modtime = 0;		/* Last modification time of bootptab */
154PRIVATE char *current_hostname;	/* Name of the current entry. */
155PRIVATE char current_tagname[8];
156
157/*
158 * List of symbolic names used in the bootptab file.  The order and actual
159 * values of the symbol codes (SYM_. . .) are unimportant, but they must
160 * all be unique.
161 */
162
163PRIVATE struct symbolmap symbol_list[] = {
164	{"bf", SYM_BOOTFILE},
165	{"bs", SYM_BOOTSIZE},
166	{"cs", SYM_COOKIE_SERVER},
167	{"df", SYM_DUMP_FILE},
168	{"dn", SYM_DOMAIN_NAME},
169	{"ds", SYM_DOMAIN_SERVER},
170	{"ef", SYM_EXTEN_FILE},
171	{"ex", SYM_EXEC_FILE},		/* YORK_EX_OPTION */
172	{"gw", SYM_GATEWAY},
173	{"ha", SYM_HWADDR},
174	{"hd", SYM_HOMEDIR},
175	{"hn", SYM_NAME_SWITCH},
176	{"ht", SYM_HTYPE},
177	{"im", SYM_IMPRESS_SERVER},
178	{"ip", SYM_IPADDR},
179	{"lg", SYM_LOG_SERVER},
180	{"lp", SYM_LPR_SERVER},
181	{"ms", SYM_MSG_SIZE},
182	{"mw", SYM_MIN_WAIT},
183	{"ns", SYM_NAME_SERVER},
184	{"nt", SYM_NTP_SERVER},
185	{"ra", SYM_REPLY_ADDR},
186	{"rl", SYM_RLP_SERVER},
187	{"rp", SYM_ROOT_PATH},
188	{"sa", SYM_BOOT_SERVER},
189	{"sm", SYM_SUBNET_MASK},
190	{"sw", SYM_SWAP_SERVER},
191	{"tc", SYM_SIMILAR_ENTRY},
192	{"td", SYM_TFTPDIR},
193	{"to", SYM_TIME_OFFSET},
194	{"ts", SYM_TIME_SERVER},
195	{"vm", SYM_VENDOR_MAGIC},
196	{"yd", SYM_NIS_DOMAIN},
197	{"ys", SYM_NIS_SERVER},
198	/* XXX - Add new tags here */
199};
200
201
202/*
203 * List of symbolic names for hardware types.  Name translates into
204 * hardware type code listed with it.  Names must begin with a letter
205 * and must be all lowercase.  This is searched linearly, so put
206 * commonly-used entries near the beginning.
207 */
208
209PRIVATE struct htypename htnamemap[] = {
210	{"ethernet", HTYPE_ETHERNET},
211	{"ethernet3", HTYPE_EXP_ETHERNET},
212	{"ether", HTYPE_ETHERNET},
213	{"ether3", HTYPE_EXP_ETHERNET},
214	{"ieee802", HTYPE_IEEE802},
215	{"tr", HTYPE_IEEE802},
216	{"token-ring", HTYPE_IEEE802},
217	{"pronet", HTYPE_PRONET},
218	{"chaos", HTYPE_CHAOS},
219	{"arcnet", HTYPE_ARCNET},
220	{"ax.25", HTYPE_AX25},
221	{"direct", HTYPE_DIRECT},
222	{"serial", HTYPE_DIRECT},
223	{"slip", HTYPE_DIRECT},
224	{"ppp", HTYPE_DIRECT}
225};
226
227
228
229/*
230 * Externals and forward declarations.
231 */
232
233#ifdef	__STDC__
234#define P(args) args
235#else
236#define P(args) ()
237#endif
238
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, haddrlength(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 symbolmap *symbolptr;
800	u_int32 value;
801	int32 timeoff;
802	int i, numsymbols;
803	unsigned len;
804	int optype;					/* Indicates boolean, addition, or deletion */
805
806	eat_whitespace(symbol);
807
808	/* Make sure this is set before returning. */
809	current_tagname[0] = (*symbol)[0];
810	current_tagname[1] = (*symbol)[1];
811	current_tagname[2] = 0;
812
813	if ((*symbol)[0] == '\0') {
814		return E_END_OF_ENTRY;
815	}
816	if ((*symbol)[0] == ':') {
817		return SUCCESS;
818	}
819	if ((*symbol)[0] == 'T') {	/* generic symbol */
820		(*symbol)++;
821		value = get_u_long(symbol);
822		sprintf(current_tagname, "T%d", value);
823		eat_whitespace(symbol);
824		if ((*symbol)[0] != '=') {
825			return E_SYNTAX_ERROR;
826		}
827		(*symbol)++;
828		if (!(hp->generic)) {
829			hp->generic = (struct shared_bindata *)
830				smalloc(sizeof(struct shared_bindata));
831		}
832		if (process_generic(symbol, &(hp->generic), (byte) (value & 0xFF)))
833			return E_SYNTAX_ERROR;
834		hp->flags.generic = TRUE;
835		return SUCCESS;
836	}
837	/*
838	 * Determine the type of operation to be done on this symbol
839	 */
840	switch ((*symbol)[2]) {
841	case '=':
842		optype = OP_ADDITION;
843		break;
844	case '@':
845		optype = OP_DELETION;
846		break;
847	case ':':
848	case '\0':
849		optype = OP_BOOLEAN;
850		break;
851	default:
852		return E_SYNTAX_ERROR;
853	}
854
855	symbolptr = symbol_list;
856	numsymbols = sizeof(symbol_list) / sizeof(struct symbolmap);
857	for (i = 0; i < numsymbols; i++) {
858		if (((symbolptr->symbol)[0] == (*symbol)[0]) &&
859			((symbolptr->symbol)[1] == (*symbol)[1])) {
860			break;
861		}
862		symbolptr++;
863	}
864	if (i >= numsymbols) {
865		return E_UNKNOWN_SYMBOL;
866	}
867	/*
868	 * Skip past the = or @ character (to point to the data) if this
869	 * isn't a boolean operation.  For boolean operations, just skip
870	 * over the two-character tag symbol (and nothing else. . . .).
871	 */
872	(*symbol) += (optype == OP_BOOLEAN) ? 2 : 3;
873
874	eat_whitespace(symbol);
875
876	/* The cases below are in order by symbolcode value. */
877	switch (symbolptr->symbolcode) {
878
879	case SYM_BOOTFILE:
880		PARSE_STR(bootfile);
881		break;
882
883	case SYM_COOKIE_SERVER:
884		PARSE_IAL(cookie_server);
885		break;
886
887	case SYM_DOMAIN_SERVER:
888		PARSE_IAL(domain_server);
889		break;
890
891	case SYM_GATEWAY:
892		PARSE_IAL(gateway);
893		break;
894
895	case SYM_HWADDR:
896		if (optype == OP_BOOLEAN)
897			return E_SYNTAX_ERROR;
898		hp->flags.haddr = FALSE;
899		if (optype == OP_ADDITION) {
900			/* Default the HW type to Ethernet */
901			if (hp->flags.htype == 0) {
902				hp->flags.htype = TRUE;
903				hp->htype = HTYPE_ETHERNET;
904			}
905			tmphaddr = prs_haddr(symbol, hp->htype);
906			if (!tmphaddr)
907				return E_BAD_HWADDR;
908			bcopy(tmphaddr, hp->haddr, haddrlength(hp->htype));
909			hp->flags.haddr = TRUE;
910		}
911		break;
912
913	case SYM_HOMEDIR:
914		PARSE_STR(homedir);
915		break;
916
917	case SYM_HTYPE:
918		if (optype == OP_BOOLEAN)
919			return E_SYNTAX_ERROR;
920		hp->flags.htype = FALSE;
921		if (optype == OP_ADDITION) {
922			value = 0L;			/* Assume an illegal value */
923			eat_whitespace(symbol);
924			if (isdigit(**symbol)) {
925				value = get_u_long(symbol);
926			} else {
927				len = sizeof(tmpstr);
928				(void) get_string(symbol, tmpstr, &len);
929				makelower(tmpstr);
930				numsymbols = sizeof(htnamemap) /
931					sizeof(struct htypename);
932				for (i = 0; i < numsymbols; i++) {
933					if (!strcmp(htnamemap[i].name, tmpstr)) {
934						break;
935					}
936				}
937				if (i < numsymbols) {
938					value = htnamemap[i].htype;
939				}
940			}
941			if (value >= hwinfocnt) {
942				return E_BAD_HWATYPE;
943			}
944			hp->htype = (byte) (value & 0xFF);
945			hp->flags.htype = TRUE;
946		}
947		break;
948
949	case SYM_IMPRESS_SERVER:
950		PARSE_IAL(impress_server);
951		break;
952
953	case SYM_IPADDR:
954		PARSE_IA1(iaddr);
955		break;
956
957	case SYM_LOG_SERVER:
958		PARSE_IAL(log_server);
959		break;
960
961	case SYM_LPR_SERVER:
962		PARSE_IAL(lpr_server);
963		break;
964
965	case SYM_NAME_SERVER:
966		PARSE_IAL(name_server);
967		break;
968
969	case SYM_RLP_SERVER:
970		PARSE_IAL(rlp_server);
971		break;
972
973	case SYM_SUBNET_MASK:
974		PARSE_IA1(subnet_mask);
975		break;
976
977	case SYM_TIME_OFFSET:
978		if (optype == OP_BOOLEAN)
979			return E_SYNTAX_ERROR;
980		hp->flags.time_offset = FALSE;
981		if (optype == OP_ADDITION) {
982			len = sizeof(tmpstr);
983			(void) get_string(symbol, tmpstr, &len);
984			if (!strncmp(tmpstr, "auto", 4)) {
985				hp->time_offset = secondswest;
986			} else {
987				if (sscanf(tmpstr, "%d", &timeoff) != 1)
988					return E_BAD_LONGWORD;
989				hp->time_offset = timeoff;
990			}
991			hp->flags.time_offset = TRUE;
992		}
993		break;
994
995	case SYM_TIME_SERVER:
996		PARSE_IAL(time_server);
997		break;
998
999	case SYM_VENDOR_MAGIC:
1000		if (optype == OP_BOOLEAN)
1001			return E_SYNTAX_ERROR;
1002		hp->flags.vm_cookie = FALSE;
1003		if (optype == OP_ADDITION) {
1004			if (strncmp(*symbol, "auto", 4)) {
1005				/* The string is not "auto" */
1006				if (!strncmp(*symbol, "rfc", 3)) {
1007					bcopy(vm_rfc1048, hp->vm_cookie, 4);
1008				} else if (!strncmp(*symbol, "cmu", 3)) {
1009					bcopy(vm_cmu, hp->vm_cookie, 4);
1010				} else {
1011					if (!isdigit(**symbol))
1012						return E_BAD_IPADDR;
1013					if (prs_inetaddr(symbol, &value) < 0)
1014						return E_BAD_IPADDR;
1015					bcopy(&value, hp->vm_cookie, 4);
1016				}
1017				hp->flags.vm_cookie = TRUE;
1018			}
1019		}
1020		break;
1021
1022	case SYM_SIMILAR_ENTRY:
1023		switch (optype) {
1024		case OP_ADDITION:
1025			fill_defaults(hp, symbol);
1026			break;
1027		default:
1028			return E_SYNTAX_ERROR;
1029		}
1030		break;
1031
1032	case SYM_NAME_SWITCH:
1033		switch (optype) {
1034		case OP_ADDITION:
1035			return E_SYNTAX_ERROR;
1036		case OP_DELETION:
1037			hp->flags.send_name = FALSE;
1038			hp->flags.name_switch = FALSE;
1039			break;
1040		case OP_BOOLEAN:
1041			hp->flags.send_name = TRUE;
1042			hp->flags.name_switch = TRUE;
1043			break;
1044		}
1045		break;
1046
1047	case SYM_BOOTSIZE:
1048		switch (optype) {
1049		case OP_ADDITION:
1050			if (!strncmp(*symbol, "auto", 4)) {
1051				hp->flags.bootsize = TRUE;
1052				hp->flags.bootsize_auto = TRUE;
1053			} else {
1054				hp->bootsize = (unsigned int) get_u_long(symbol);
1055				hp->flags.bootsize = TRUE;
1056				hp->flags.bootsize_auto = FALSE;
1057			}
1058			break;
1059		case OP_DELETION:
1060			hp->flags.bootsize = FALSE;
1061			break;
1062		case OP_BOOLEAN:
1063			hp->flags.bootsize = TRUE;
1064			hp->flags.bootsize_auto = TRUE;
1065			break;
1066		}
1067		break;
1068
1069	case SYM_BOOT_SERVER:
1070		PARSE_IA1(bootserver);
1071		break;
1072
1073	case SYM_TFTPDIR:
1074		PARSE_STR(tftpdir);
1075		if ((hp->tftpdir != NULL) &&
1076			(hp->tftpdir->string[0] != '/'))
1077			return E_BAD_PATHNAME;
1078		break;
1079
1080	case SYM_DUMP_FILE:
1081		PARSE_STR(dump_file);
1082		break;
1083
1084	case SYM_DOMAIN_NAME:
1085		PARSE_STR(domain_name);
1086		break;
1087
1088	case SYM_SWAP_SERVER:
1089		PARSE_IA1(swap_server);
1090		break;
1091
1092	case SYM_ROOT_PATH:
1093		PARSE_STR(root_path);
1094		break;
1095
1096	case SYM_EXTEN_FILE:
1097		PARSE_STR(exten_file);
1098		break;
1099
1100	case SYM_REPLY_ADDR:
1101		PARSE_IA1(reply_addr);
1102		break;
1103
1104	case SYM_NIS_DOMAIN:
1105		PARSE_STR(nis_domain);
1106		break;
1107
1108	case SYM_NIS_SERVER:
1109		PARSE_IAL(nis_server);
1110		break;
1111
1112	case SYM_NTP_SERVER:
1113		PARSE_IAL(ntp_server);
1114		break;
1115
1116#ifdef	YORK_EX_OPTION
1117	case SYM_EXEC_FILE:
1118		PARSE_STR(exec_file);
1119		break;
1120#endif
1121
1122	case SYM_MSG_SIZE:
1123		PARSE_INT(msg_size);
1124		if (hp->msg_size < BP_MINPKTSZ ||
1125			hp->msg_size > MAX_MSG_SIZE)
1126			return E_BAD_VALUE;
1127		break;
1128
1129	case SYM_MIN_WAIT:
1130		PARSE_INT(min_wait);
1131		if (hp->min_wait < 0)
1132			return E_BAD_VALUE;
1133		break;
1134
1135		/* XXX - Add new tags here */
1136
1137	default:
1138		return E_UNKNOWN_SYMBOL;
1139
1140	}							/* switch symbolcode */
1141
1142	return SUCCESS;
1143}
1144#undef	PARSE_IA1
1145#undef	PARSE_IAL
1146#undef	PARSE_STR
1147
1148
1149
1150
1151/*
1152 * Read a string from the buffer indirectly pointed to through "src" and
1153 * move it into the buffer pointed to by "dest".  A pointer to the maximum
1154 * allowable length of the string (including null-terminator) is passed as
1155 * "length".  The actual length of the string which was read is returned in
1156 * the unsigned integer pointed to by "length".  This value is the same as
1157 * that which would be returned by applying the strlen() function on the
1158 * destination string (i.e the terminating null is not counted as a
1159 * character).  Trailing whitespace is removed from the string.  For
1160 * convenience, the function returns the new value of "dest".
1161 *
1162 * The string is read until the maximum number of characters, an unquoted
1163 * colon (:), or a null character is read.  The return string in "dest" is
1164 * null-terminated.
1165 */
1166
1167PRIVATE char *
1168get_string(src, dest, length)
1169	char **src, *dest;
1170	unsigned *length;
1171{
1172	int n, len, quoteflag;
1173
1174	quoteflag = FALSE;
1175	n = 0;
1176	len = *length - 1;
1177	while ((n < len) && (**src)) {
1178		if (!quoteflag && (**src == ':')) {
1179			break;
1180		}
1181		if (**src == '"') {
1182			(*src)++;
1183			quoteflag = !quoteflag;
1184			continue;
1185		}
1186		if (**src == '\\') {
1187			(*src)++;
1188			if (!**src) {
1189				break;
1190			}
1191		}
1192		*dest++ = *(*src)++;
1193		n++;
1194	}
1195
1196	/*
1197	 * Remove that troublesome trailing whitespace. . .
1198	 */
1199	while ((n > 0) && isspace(dest[-1])) {
1200		dest--;
1201		n--;
1202	}
1203
1204	*dest = '\0';
1205	*length = n;
1206	return dest;
1207}
1208
1209
1210
1211/*
1212 * Read the string indirectly pointed to by "src", update the caller's
1213 * pointer, and return a pointer to a malloc'ed shared_string structure
1214 * containing the string.
1215 *
1216 * The string is read using the same rules as get_string() above.
1217 */
1218
1219PRIVATE struct shared_string *
1220get_shared_string(src)
1221	char **src;
1222{
1223	char retstring[MAXSTRINGLEN];
1224	struct shared_string *s;
1225	unsigned length;
1226
1227	length = sizeof(retstring);
1228	(void) get_string(src, retstring, &length);
1229
1230	s = (struct shared_string *) smalloc(sizeof(struct shared_string)
1231										 + length);
1232	s->linkcount = 1;
1233	strcpy(s->string, retstring);
1234
1235	return s;
1236}
1237
1238
1239
1240/*
1241 * Load RFC1048 generic information directly into a memory buffer.
1242 *
1243 * "src" indirectly points to the ASCII representation of the generic data.
1244 * "dest" points to a string structure which is updated to point to a new
1245 * string with the new data appended to the old string.  The old string is
1246 * freed.
1247 *
1248 * The given tag value is inserted with the new data.
1249 *
1250 * The data may be represented as either a stream of hexadecimal numbers
1251 * representing bytes (any or all bytes may optionally start with '0x' and
1252 * be separated with periods ".") or as a quoted string of ASCII
1253 * characters (the quotes are required).
1254 */
1255
1256PRIVATE int
1257process_generic(src, dest, tagvalue)
1258	char **src;
1259	struct shared_bindata **dest;
1260	u_int tagvalue;
1261{
1262	byte tmpbuf[MAXBUFLEN];
1263	byte *str;
1264	struct shared_bindata *bdata;
1265	u_int newlength, oldlength;
1266
1267	str = tmpbuf;
1268	*str++ = (tagvalue & 0xFF);	/* Store tag value */
1269	str++;						/* Skip over length field */
1270	if ((*src)[0] == '"') {		/* ASCII data */
1271		newlength = sizeof(tmpbuf) - 2;	/* Set maximum allowed length */
1272		(void) get_string(src, (char *) str, &newlength);
1273		/* Do NOT include the terminating null. */
1274	} else {					/* Numeric data */
1275		newlength = 0;
1276		while (newlength < sizeof(tmpbuf) - 2) {
1277			if (interp_byte(src, str++) < 0)
1278				break;
1279			newlength++;
1280			if (**src == '.') {
1281				(*src)++;
1282			}
1283		}
1284	}
1285	if ((*src)[0] != ':')
1286		return -1;
1287
1288	tmpbuf[1] = (newlength & 0xFF);
1289	oldlength = ((*dest)->length);
1290	bdata = (struct shared_bindata *) smalloc(sizeof(struct shared_bindata)
1291											+ oldlength + newlength + 1);
1292	if (oldlength > 0) {
1293		bcopy((*dest)->data, bdata->data, oldlength);
1294	}
1295	bcopy(tmpbuf, bdata->data + oldlength, newlength + 2);
1296	bdata->length = oldlength + newlength + 2;
1297	bdata->linkcount = 1;
1298	if (*dest) {
1299		del_bindata(*dest);
1300	}
1301	*dest = bdata;
1302	return 0;
1303}
1304
1305
1306
1307/*
1308 * Verify that the given string makes sense as a hostname (according to
1309 * Appendix 1, page 29 of RFC882).
1310 *
1311 * Return TRUE for good names, FALSE otherwise.
1312 */
1313
1314PRIVATE boolean
1315goodname(hostname)
1316	register char *hostname;
1317{
1318	do {
1319		if (!isalpha(*hostname++)) {	/* First character must be a letter */
1320			return FALSE;
1321		}
1322		while (isalnum(*hostname) ||
1323			   (*hostname == '-') ||
1324			   (*hostname == '_') )
1325		{
1326			hostname++;			/* Alphanumeric or a hyphen */
1327		}
1328		if (!isalnum(hostname[-1])) {	/* Last must be alphanumeric */
1329			return FALSE;
1330		}
1331		if (*hostname == '\0') {/* Done? */
1332			return TRUE;
1333		}
1334	} while (*hostname++ == '.');	/* Dot, loop for next label */
1335
1336	return FALSE;				/* If it's not a dot, lose */
1337}
1338
1339
1340
1341/*
1342 * Null compare function -- always returns FALSE so an element is always
1343 * inserted into a hash table (i.e. there is never a collision with an
1344 * existing element).
1345 */
1346
1347PRIVATE boolean
1348nullcmp(d1, d2)
1349	hash_datum *d1, *d2;
1350{
1351	return FALSE;
1352}
1353
1354
1355/*
1356 * Function for comparing a string with the hostname field of a host
1357 * structure.
1358 */
1359
1360boolean
1361nmcmp(d1, d2)
1362	hash_datum *d1, *d2;
1363{
1364	char *name = (char *) d1;	/* XXX - OK? */
1365	struct host *hp = (struct host *) d2;
1366
1367	return !strcmp(name, hp->hostname->string);
1368}
1369
1370
1371/*
1372 * Compare function to determine whether two hardware addresses are
1373 * equivalent.  Returns TRUE if "host1" and "host2" are equivalent, FALSE
1374 * otherwise.
1375 *
1376 * If the hardware addresses of "host1" and "host2" are identical, but
1377 * they are on different IP subnets, this function returns FALSE.
1378 *
1379 * This function is used when inserting elements into the hardware address
1380 * hash table.
1381 */
1382
1383PRIVATE boolean
1384hwinscmp(d1, d2)
1385	hash_datum *d1, *d2;
1386{
1387	struct host *host1 = (struct host *) d1;
1388	struct host *host2 = (struct host *) d2;
1389
1390	if (host1->htype != host2->htype) {
1391		return FALSE;
1392	}
1393	if (bcmp(host1->haddr, host2->haddr, haddrlength(host1->htype))) {
1394		return FALSE;
1395	}
1396	/* XXX - Is the subnet_mask field set yet? */
1397	if ((host1->subnet_mask.s_addr) == (host2->subnet_mask.s_addr)) {
1398		if (((host1->iaddr.s_addr) & (host1->subnet_mask.s_addr)) !=
1399			((host2->iaddr.s_addr) & (host2->subnet_mask.s_addr)))
1400		{
1401			return FALSE;
1402		}
1403	}
1404	return TRUE;
1405}
1406
1407
1408/*
1409 * Macros for use in the function below:
1410 */
1411
1412#define DUP_COPY(MEMBER) do \
1413{ \
1414	if (!hp->flags.MEMBER) { \
1415		if ((hp->flags.MEMBER = hp2->flags.MEMBER) != 0) { \
1416			hp->MEMBER = hp2->MEMBER; \
1417		} \
1418	} \
1419} while (0)
1420
1421#define DUP_LINK(MEMBER) do \
1422{ \
1423	if (!hp->flags.MEMBER) { \
1424		if ((hp->flags.MEMBER = hp2->flags.MEMBER) != 0) { \
1425			assert(hp2->MEMBER); \
1426			hp->MEMBER = hp2->MEMBER; \
1427			(hp->MEMBER->linkcount)++; \
1428		} \
1429	} \
1430} while (0)
1431
1432/*
1433 * Process the "similar entry" symbol.
1434 *
1435 * The host specified as the value of the "tc" symbol is used as a template
1436 * for the current host entry.  Symbol values not explicitly set in the
1437 * current host entry are inferred from the template entry.
1438 */
1439PRIVATE void
1440fill_defaults(hp, src)
1441	struct host *hp;
1442	char **src;
1443{
1444	unsigned int tlen, hashcode;
1445	struct host *hp2;
1446	char tstring[MAXSTRINGLEN];
1447
1448	tlen = sizeof(tstring);
1449	(void) get_string(src, tstring, &tlen);
1450	hashcode = hash_HashFunction((u_char *) tstring, tlen);
1451	hp2 = (struct host *) hash_Lookup(nmhashtable, hashcode, nmcmp, tstring);
1452
1453	if (hp2 == NULL) {
1454		report(LOG_ERR, "can't find tc=\"%s\"", tstring);
1455		return;
1456	}
1457	DUP_LINK(bootfile);
1458	DUP_LINK(cookie_server);
1459	DUP_LINK(domain_server);
1460	DUP_LINK(gateway);
1461	/* haddr not copied */
1462	DUP_LINK(homedir);
1463	DUP_COPY(htype);
1464
1465	DUP_LINK(impress_server);
1466	/* iaddr not copied */
1467	DUP_LINK(log_server);
1468	DUP_LINK(lpr_server);
1469	DUP_LINK(name_server);
1470	DUP_LINK(rlp_server);
1471
1472	DUP_COPY(subnet_mask);
1473	DUP_COPY(time_offset);
1474	DUP_LINK(time_server);
1475
1476	if (!hp->flags.vm_cookie) {
1477		if ((hp->flags.vm_cookie = hp2->flags.vm_cookie)) {
1478			bcopy(hp2->vm_cookie, hp->vm_cookie, 4);
1479		}
1480	}
1481	if (!hp->flags.name_switch) {
1482		if ((hp->flags.name_switch = hp2->flags.name_switch)) {
1483			hp->flags.send_name = hp2->flags.send_name;
1484		}
1485	}
1486	if (!hp->flags.bootsize) {
1487		if ((hp->flags.bootsize = hp2->flags.bootsize)) {
1488			hp->flags.bootsize_auto = hp2->flags.bootsize_auto;
1489			hp->bootsize = hp2->bootsize;
1490		}
1491	}
1492	DUP_COPY(bootserver);
1493
1494	DUP_LINK(tftpdir);
1495	DUP_LINK(dump_file);
1496	DUP_LINK(domain_name);
1497
1498	DUP_COPY(swap_server);
1499	DUP_LINK(root_path);
1500	DUP_LINK(exten_file);
1501
1502	DUP_COPY(reply_addr);
1503
1504	DUP_LINK(nis_domain);
1505	DUP_LINK(nis_server);
1506	DUP_LINK(ntp_server);
1507
1508#ifdef	YORK_EX_OPTION
1509	DUP_LINK(exec_file);
1510#endif
1511
1512	DUP_COPY(msg_size);
1513	DUP_COPY(min_wait);
1514
1515	/* XXX - Add new tags here */
1516
1517	DUP_LINK(generic);
1518
1519}
1520#undef	DUP_COPY
1521#undef	DUP_LINK
1522
1523
1524
1525/*
1526 * This function adjusts the caller's pointer to point just past the
1527 * first-encountered colon.  If it runs into a null character, it leaves
1528 * the pointer pointing to it.
1529 */
1530
1531PRIVATE void
1532adjust(s)
1533	char **s;
1534{
1535	register char *t;
1536
1537	t = *s;
1538	while (*t && (*t != ':')) {
1539		t++;
1540	}
1541	if (*t) {
1542		t++;
1543	}
1544	*s = t;
1545}
1546
1547
1548
1549
1550/*
1551 * This function adjusts the caller's pointer to point to the first
1552 * non-whitespace character.  If it runs into a null character, it leaves
1553 * the pointer pointing to it.
1554 */
1555
1556PRIVATE void
1557eat_whitespace(s)
1558	char **s;
1559{
1560	register char *t;
1561
1562	t = *s;
1563	while (*t && isspace(*t)) {
1564		t++;
1565	}
1566	*s = t;
1567}
1568
1569
1570
1571/*
1572 * This function converts the given string to all lowercase.
1573 */
1574
1575PRIVATE void
1576makelower(s)
1577	char *s;
1578{
1579	while (*s) {
1580		if (isupper(*s)) {
1581			*s = tolower(*s);
1582		}
1583		s++;
1584	}
1585}
1586
1587
1588
1589/*
1590 *
1591 *	N O T E :
1592 *
1593 *	In many of the functions which follow, a parameter such as "src" or
1594 *	"symbol" is passed as a pointer to a pointer to something.  This is
1595 *	done for the purpose of letting the called function update the
1596 *	caller's copy of the parameter (i.e. to effect call-by-reference
1597 *	parameter passing).  The value of the actual parameter is only used
1598 *	to locate the real parameter of interest and then update this indirect
1599 *	parameter.
1600 *
1601 *	I'm sure somebody out there won't like this. . . .
1602 *  (Yea, because it usually makes code slower... -gwr)
1603 *
1604 */
1605
1606
1607
1608/*
1609 * "src" points to a character pointer which points to an ASCII string of
1610 * whitespace-separated IP addresses.  A pointer to an in_addr_list
1611 * structure containing the list of addresses is returned.  NULL is
1612 * returned if no addresses were found at all.  The pointer pointed to by
1613 * "src" is updated to point to the first non-address (illegal) character.
1614 */
1615
1616PRIVATE struct in_addr_list *
1617get_addresses(src)
1618	char **src;
1619{
1620	struct in_addr tmpaddrlist[MAXINADDRS];
1621	struct in_addr *address1, *address2;
1622	struct in_addr_list *result;
1623	unsigned addrcount, totalsize;
1624
1625	address1 = tmpaddrlist;
1626	for (addrcount = 0; addrcount < MAXINADDRS; addrcount++) {
1627		while (isspace(**src) || (**src == ',')) {
1628			(*src)++;
1629		}
1630		if (!**src) {			/* Quit if nothing more */
1631			break;
1632		}
1633		if (prs_inetaddr(src, &(address1->s_addr)) < 0) {
1634			break;
1635		}
1636		address1++;				/* Point to next address slot */
1637	}
1638	if (addrcount < 1) {
1639		result = NULL;
1640	} else {
1641		totalsize = sizeof(struct in_addr_list)
1642		+			(addrcount - 1) * sizeof(struct in_addr);
1643		result = (struct in_addr_list *) smalloc(totalsize);
1644		result->linkcount = 1;
1645		result->addrcount = addrcount;
1646		address1 = tmpaddrlist;
1647		address2 = result->addr;
1648		for (; addrcount > 0; addrcount--) {
1649			address2->s_addr = address1->s_addr;
1650			address1++;
1651			address2++;
1652		}
1653	}
1654	return result;
1655}
1656
1657
1658
1659/*
1660 * prs_inetaddr(src, result)
1661 *
1662 * "src" is a value-result parameter; the pointer it points to is updated
1663 * to point to the next data position.   "result" points to an unsigned long
1664 * in which an address is returned.
1665 *
1666 * This function parses the IP address string in ASCII "dot notation" pointed
1667 * to by (*src) and places the result (in network byte order) in the unsigned
1668 * long pointed to by "result".  For malformed addresses, -1 is returned,
1669 * (*src) points to the first illegal character, and the unsigned long pointed
1670 * to by "result" is unchanged.  Successful calls return 0.
1671 */
1672
1673PRIVATE int
1674prs_inetaddr(src, result)
1675	char **src;
1676	u_int32 *result;
1677{
1678	char tmpstr[MAXSTRINGLEN];
1679	register u_int32 value;
1680	u_int32 parts[4], *pp;
1681	int n;
1682	char *s, *t;
1683
1684#if 1	/* XXX - experimental */
1685	/* Leading alpha char causes IP addr lookup. */
1686	if (isalpha(**src)) {
1687		/* Lookup IP address. */
1688		s = *src;
1689		t = tmpstr;
1690		while ((isalnum(*s) || (*s == '.') ||
1691				(*s == '-') || (*s == '_') ) &&
1692			   (t < &tmpstr[MAXSTRINGLEN - 1]) )
1693			*t++ = *s++;
1694		*t = '\0';
1695		*src = s;
1696
1697		n = lookup_ipa(tmpstr, result);
1698		if (n < 0)
1699			report(LOG_ERR, "can not get IP addr for %s", tmpstr);
1700		return n;
1701	}
1702#endif
1703
1704	/*
1705	 * Parse an address in Internet format:
1706	 *	a.b.c.d
1707	 *	a.b.c	(with c treated as 16-bits)
1708	 *	a.b	(with b treated as 24 bits)
1709	 */
1710	pp = parts;
1711  loop:
1712	/* If it's not a digit, return error. */
1713	if (!isdigit(**src))
1714		return -1;
1715	*pp++ = get_u_long(src);
1716	if (**src == '.') {
1717		if (pp < (parts + 4)) {
1718			(*src)++;
1719			goto loop;
1720		}
1721		return (-1);
1722	}
1723#if 0
1724	/* This is handled by the caller. */
1725	if (**src && !(isspace(**src) || (**src == ':'))) {
1726		return (-1);
1727	}
1728#endif
1729
1730	/*
1731	 * Construct the address according to
1732	 * the number of parts specified.
1733	 */
1734	n = pp - parts;
1735	switch (n) {
1736	case 1:					/* a -- 32 bits */
1737		value = parts[0];
1738		break;
1739	case 2:					/* a.b -- 8.24 bits */
1740		value = (parts[0] << 24) | (parts[1] & 0xFFFFFF);
1741		break;
1742	case 3:					/* a.b.c -- 8.8.16 bits */
1743		value = (parts[0] << 24) | ((parts[1] & 0xFF) << 16) |
1744			(parts[2] & 0xFFFF);
1745		break;
1746	case 4:					/* a.b.c.d -- 8.8.8.8 bits */
1747		value = (parts[0] << 24) | ((parts[1] & 0xFF) << 16) |
1748			((parts[2] & 0xFF) << 8) | (parts[3] & 0xFF);
1749		break;
1750	default:
1751		return (-1);
1752	}
1753	*result = htonl(value);
1754	return (0);
1755}
1756
1757
1758
1759/*
1760 * "src" points to a pointer which in turn points to a hexadecimal ASCII
1761 * string.  This string is interpreted as a hardware address and returned
1762 * as a pointer to the actual hardware address, represented as an array of
1763 * bytes.
1764 *
1765 * The ASCII string must have the proper number of digits for the specified
1766 * hardware type (e.g. twelve digits for a 48-bit Ethernet address).
1767 * Two-digit sequences (bytes) may be separated with periods (.)  and/or
1768 * prefixed with '0x' for readability, but this is not required.
1769 *
1770 * For bad addresses, the pointer which "src" points to is updated to point
1771 * to the start of the first two-digit sequence which was bad, and the
1772 * function returns a NULL pointer.
1773 */
1774
1775PRIVATE byte *
1776prs_haddr(src, htype)
1777	char **src;
1778	u_int htype;
1779{
1780	static byte haddr[MAXHADDRLEN];
1781	byte *hap;
1782	char tmpstr[MAXSTRINGLEN];
1783	u_int tmplen;
1784	unsigned hal;
1785	char *p;
1786
1787	hal = haddrlength(htype);	/* Get length of this address type */
1788	if (hal <= 0) {
1789		report(LOG_ERR, "Invalid addr type for HW addr parse");
1790		return NULL;
1791	}
1792	tmplen = sizeof(tmpstr);
1793	get_string(src, tmpstr, &tmplen);
1794	p = tmpstr;
1795
1796#if 1	/* XXX - experimental */
1797	/* If it's a valid host name, try to lookup the HW address. */
1798	if (goodname(p)) {
1799		/* Lookup Hardware Address for hostname. */
1800		if ((hap = lookup_hwa(p, htype)) != NULL)
1801			return hap; /* success */
1802		report(LOG_ERR, "Add 0x prefix if hex value starts with A-F");
1803		/* OK, assume it must be numeric. */
1804	}
1805#endif
1806
1807	hap = haddr;
1808	while (hap < haddr + hal) {
1809		if ((*p == '.') || (*p == ':'))
1810			p++;
1811		if (interp_byte(&p, hap++) < 0) {
1812			return NULL;
1813		}
1814	}
1815	return haddr;
1816}
1817
1818
1819
1820/*
1821 * "src" is a pointer to a character pointer which in turn points to a
1822 * hexadecimal ASCII representation of a byte.  This byte is read, the
1823 * character pointer is updated, and the result is deposited into the
1824 * byte pointed to by "retbyte".
1825 *
1826 * The usual '0x' notation is allowed but not required.  The number must be
1827 * a two digit hexadecimal number.  If the number is invalid, "src" and
1828 * "retbyte" are left untouched and -1 is returned as the function value.
1829 * Successful calls return 0.
1830 */
1831
1832PRIVATE int
1833interp_byte(src, retbyte)
1834	char **src;
1835	byte *retbyte;
1836{
1837	int v;
1838
1839	if ((*src)[0] == '0' &&
1840		((*src)[1] == 'x' ||
1841		 (*src)[1] == 'X')) {
1842		(*src) += 2;			/* allow 0x for hex, but don't require it */
1843	}
1844	if (!isxdigit((*src)[0]) || !isxdigit((*src)[1])) {
1845		return -1;
1846	}
1847	if (sscanf(*src, "%2x", &v) != 1) {
1848		return -1;
1849	}
1850	(*src) += 2;
1851	*retbyte = (byte) (v & 0xFF);
1852	return 0;
1853}
1854
1855
1856
1857/*
1858 * The parameter "src" points to a character pointer which points to an
1859 * ASCII string representation of an unsigned number.  The number is
1860 * returned as an unsigned long and the character pointer is updated to
1861 * point to the first illegal character.
1862 */
1863
1864PRIVATE u_int32
1865get_u_long(src)
1866	char **src;
1867{
1868	register u_int32 value, base;
1869	char c;
1870
1871	/*
1872	 * Collect number up to first illegal character.  Values are specified
1873	 * as for C:  0x=hex, 0=octal, other=decimal.
1874	 */
1875	value = 0;
1876	base = 10;
1877	if (**src == '0') {
1878		base = 8;
1879		(*src)++;
1880	}
1881	if (**src == 'x' || **src == 'X') {
1882		base = 16;
1883		(*src)++;
1884	}
1885	while ((c = **src)) {
1886		if (isdigit(c)) {
1887			value = (value * base) + (c - '0');
1888			(*src)++;
1889			continue;
1890		}
1891		if (base == 16 && isxdigit(c)) {
1892			value = (value << 4) + ((c & ~32) + 10 - 'A');
1893			(*src)++;
1894			continue;
1895		}
1896		break;
1897	}
1898	return value;
1899}
1900
1901
1902
1903/*
1904 * Routines for deletion of data associated with the main data structure.
1905 */
1906
1907
1908/*
1909 * Frees the entire host data structure given.  Does nothing if the passed
1910 * pointer is NULL.
1911 */
1912
1913PRIVATE void
1914free_host(hmp)
1915	hash_datum *hmp;
1916{
1917	struct host *hostptr = (struct host *) hmp;
1918	if (hostptr == NULL)
1919		return;
1920	assert(hostptr->linkcount > 0);
1921	if (--(hostptr->linkcount))
1922		return;					/* Still has references */
1923	del_iplist(hostptr->cookie_server);
1924	del_iplist(hostptr->domain_server);
1925	del_iplist(hostptr->gateway);
1926	del_iplist(hostptr->impress_server);
1927	del_iplist(hostptr->log_server);
1928	del_iplist(hostptr->lpr_server);
1929	del_iplist(hostptr->name_server);
1930	del_iplist(hostptr->rlp_server);
1931	del_iplist(hostptr->time_server);
1932	del_iplist(hostptr->nis_server);
1933	del_iplist(hostptr->ntp_server);
1934
1935	/*
1936	 * XXX - Add new tags here
1937	 * (if the value is an IP list)
1938	 */
1939
1940	del_string(hostptr->hostname);
1941	del_string(hostptr->homedir);
1942	del_string(hostptr->bootfile);
1943	del_string(hostptr->tftpdir);
1944	del_string(hostptr->root_path);
1945	del_string(hostptr->domain_name);
1946	del_string(hostptr->dump_file);
1947	del_string(hostptr->exten_file);
1948	del_string(hostptr->nis_domain);
1949
1950#ifdef	YORK_EX_OPTION
1951	del_string(hostptr->exec_file);
1952#endif
1953
1954	/*
1955	 * XXX - Add new tags here
1956	 * (if it is a shared string)
1957	 */
1958
1959	del_bindata(hostptr->generic);
1960	free((char *) hostptr);
1961}
1962
1963
1964
1965/*
1966 * Decrements the linkcount on the given IP address data structure.  If the
1967 * linkcount goes to zero, the memory associated with the data is freed.
1968 */
1969
1970PRIVATE void
1971del_iplist(iplist)
1972	struct in_addr_list *iplist;
1973{
1974	if (iplist) {
1975		if (!(--(iplist->linkcount))) {
1976			free((char *) iplist);
1977		}
1978	}
1979}
1980
1981
1982
1983/*
1984 * Decrements the linkcount on a string data structure.  If the count
1985 * goes to zero, the memory associated with the string is freed.  Does
1986 * nothing if the passed pointer is NULL.
1987 */
1988
1989PRIVATE void
1990del_string(stringptr)
1991	struct shared_string *stringptr;
1992{
1993	if (stringptr) {
1994		if (!(--(stringptr->linkcount))) {
1995			free((char *) stringptr);
1996		}
1997	}
1998}
1999
2000
2001
2002/*
2003 * Decrements the linkcount on a shared_bindata data structure.  If the
2004 * count goes to zero, the memory associated with the data is freed.  Does
2005 * nothing if the passed pointer is NULL.
2006 */
2007
2008PRIVATE void
2009del_bindata(dataptr)
2010	struct shared_bindata *dataptr;
2011{
2012	if (dataptr) {
2013		if (!(--(dataptr->linkcount))) {
2014			free((char *) dataptr);
2015		}
2016	}
2017}
2018
2019
2020
2021
2022/* smalloc()  --  safe malloc()
2023 *
2024 * Always returns a valid pointer (if it returns at all).  The allocated
2025 * memory is initialized to all zeros.  If malloc() returns an error, a
2026 * message is printed using the report() function and the program aborts
2027 * with a status of 1.
2028 */
2029
2030PRIVATE char *
2031smalloc(nbytes)
2032	unsigned nbytes;
2033{
2034	char *retvalue;
2035
2036	retvalue = malloc(nbytes);
2037	if (!retvalue) {
2038		report(LOG_ERR, "malloc() failure -- exiting");
2039		exit(1);
2040	}
2041	bzero(retvalue, nbytes);
2042	return retvalue;
2043}
2044
2045
2046/*
2047 * Compare function to determine whether two hardware addresses are
2048 * equivalent.  Returns TRUE if "host1" and "host2" are equivalent, FALSE
2049 * otherwise.
2050 *
2051 * This function is used when retrieving elements from the hardware address
2052 * hash table.
2053 */
2054
2055boolean
2056hwlookcmp(d1, d2)
2057	hash_datum *d1, *d2;
2058{
2059	struct host *host1 = (struct host *) d1;
2060	struct host *host2 = (struct host *) d2;
2061
2062	if (host1->htype != host2->htype) {
2063		return FALSE;
2064	}
2065	if (bcmp(host1->haddr, host2->haddr, haddrlength(host1->htype))) {
2066		return FALSE;
2067	}
2068	return TRUE;
2069}
2070
2071
2072/*
2073 * Compare function for doing IP address hash table lookup.
2074 */
2075
2076boolean
2077iplookcmp(d1, d2)
2078	hash_datum *d1, *d2;
2079{
2080	struct host *host1 = (struct host *) d1;
2081	struct host *host2 = (struct host *) d2;
2082
2083	return (host1->iaddr.s_addr == host2->iaddr.s_addr);
2084}
2085
2086/*
2087 * Local Variables:
2088 * tab-width: 4
2089 * c-indent-level: 4
2090 * c-argdecl-indent: 4
2091 * c-continued-statement-offset: 4
2092 * c-continued-brace-offset: -4
2093 * c-label-offset: -4
2094 * c-brace-offset: 0
2095 * End:
2096 */
2097