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