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