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