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