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