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