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