xref: /netbsd-src/usr.sbin/bootp/common/readfile.c (revision d48f14661dda8638fee055ba15d35bdfb29b9fa8)
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.14 2006/05/23 01:29:31 christos 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 	del_bindata(*dest);
1280 	*dest = bdata;
1281 	return 0;
1282 }
1283 
1284 
1285 
1286 /*
1287  * Verify that the given string makes sense as a hostname (according to
1288  * Appendix 1, page 29 of RFC882).
1289  *
1290  * Return TRUE for good names, FALSE otherwise.
1291  */
1292 
1293 PRIVATE boolean
1294 goodname(char *hostname)
1295 {
1296 	do {
1297 		if (!isalpha((unsigned char)*hostname++)) {	/* First character must be a letter */
1298 			return FALSE;
1299 		}
1300 		while (isalnum((unsigned char)*hostname) ||
1301 			   (*hostname == '-') ||
1302 			   (*hostname == '_') )
1303 		{
1304 			hostname++;			/* Alphanumeric or a hyphen */
1305 		}
1306 		if (!isalnum((unsigned char)hostname[-1])) {	/* Last must be alphanumeric */
1307 			return FALSE;
1308 		}
1309 		if (*hostname == '\0') {/* Done? */
1310 			return TRUE;
1311 		}
1312 	} while (*hostname++ == '.');	/* Dot, loop for next label */
1313 
1314 	return FALSE;				/* If it's not a dot, lose */
1315 }
1316 
1317 
1318 
1319 /*
1320  * Null compare function -- always returns FALSE so an element is always
1321  * inserted into a hash table (i.e. there is never a collision with an
1322  * existing element).
1323  */
1324 
1325 PRIVATE boolean
1326 nullcmp(hash_datum *d1, hash_datum *d2)
1327 {
1328 	return FALSE;
1329 }
1330 
1331 
1332 /*
1333  * Function for comparing a string with the hostname field of a host
1334  * structure.
1335  */
1336 
1337 boolean
1338 nmcmp(hash_datum *d1, hash_datum *d2)
1339 {
1340 	char *name = (char *) d1;	/* XXX - OK? */
1341 	struct host *hp = (struct host *) d2;
1342 
1343 	return !strcmp(name, hp->hostname->string);
1344 }
1345 
1346 
1347 /*
1348  * Compare function to determine whether two hardware addresses are
1349  * equivalent.  Returns TRUE if "host1" and "host2" are equivalent, FALSE
1350  * otherwise.
1351  *
1352  * If the hardware addresses of "host1" and "host2" are identical, but
1353  * they are on different IP subnets, this function returns FALSE.
1354  *
1355  * This function is used when inserting elements into the hardware address
1356  * hash table.
1357  */
1358 
1359 PRIVATE boolean
1360 hwinscmp(hash_datum *d1, hash_datum *d2)
1361 {
1362 	struct host *host1 = (struct host *) d1;
1363 	struct host *host2 = (struct host *) d2;
1364 
1365 	if (host1->htype != host2->htype) {
1366 		return FALSE;
1367 	}
1368 	if (bcmp(host1->haddr, host2->haddr, haddrlength(host1->htype))) {
1369 		return FALSE;
1370 	}
1371 	/* XXX - Is the subnet_mask field set yet? */
1372 	if ((host1->subnet_mask.s_addr) == (host2->subnet_mask.s_addr)) {
1373 		if (((host1->iaddr.s_addr) & (host1->subnet_mask.s_addr)) !=
1374 			((host2->iaddr.s_addr) & (host2->subnet_mask.s_addr)))
1375 		{
1376 			return FALSE;
1377 		}
1378 	}
1379 	return TRUE;
1380 }
1381 
1382 
1383 /*
1384  * Macros for use in the function below:
1385  */
1386 
1387 #define DUP_COPY(MEMBER) do \
1388 { \
1389 	if (!hp->flags.MEMBER) { \
1390 		if ((hp->flags.MEMBER = hp2->flags.MEMBER) != 0) { \
1391 			hp->MEMBER = hp2->MEMBER; \
1392 		} \
1393 	} \
1394 } while (0)
1395 
1396 #define DUP_LINK(MEMBER) do \
1397 { \
1398 	if (!hp->flags.MEMBER) { \
1399 		if ((hp->flags.MEMBER = hp2->flags.MEMBER) != 0) { \
1400 			assert(hp2->MEMBER); \
1401 			hp->MEMBER = hp2->MEMBER; \
1402 			(hp->MEMBER->linkcount)++; \
1403 		} \
1404 	} \
1405 } while (0)
1406 
1407 /*
1408  * Process the "similar entry" symbol.
1409  *
1410  * The host specified as the value of the "tc" symbol is used as a template
1411  * for the current host entry.  Symbol values not explicitly set in the
1412  * current host entry are inferred from the template entry.
1413  */
1414 PRIVATE void
1415 fill_defaults(struct host *hp, char **src)
1416 {
1417 	unsigned int tlen, hashcode;
1418 	struct host *hp2;
1419 	char tstring[MAXSTRINGLEN];
1420 
1421 	tlen = sizeof(tstring);
1422 	(void) get_string(src, tstring, &tlen);
1423 	hashcode = hash_HashFunction((u_char *) tstring, tlen);
1424 	hp2 = (struct host *) hash_Lookup(nmhashtable, hashcode, nmcmp, tstring);
1425 
1426 	if (hp2 == NULL) {
1427 		report(LOG_ERR, "can't find tc=\"%s\"", tstring);
1428 		return;
1429 	}
1430 	DUP_LINK(bootfile);
1431 	DUP_LINK(cookie_server);
1432 	DUP_LINK(domain_server);
1433 	DUP_LINK(gateway);
1434 	/* haddr not copied */
1435 	DUP_LINK(homedir);
1436 	DUP_COPY(htype);
1437 
1438 	DUP_LINK(impress_server);
1439 	/* iaddr not copied */
1440 	DUP_LINK(log_server);
1441 	DUP_LINK(lpr_server);
1442 	DUP_LINK(name_server);
1443 	DUP_LINK(rlp_server);
1444 
1445 	DUP_COPY(subnet_mask);
1446 	DUP_COPY(time_offset);
1447 	DUP_LINK(time_server);
1448 
1449 	if (!hp->flags.vm_cookie) {
1450 		if ((hp->flags.vm_cookie = hp2->flags.vm_cookie)) {
1451 			bcopy(hp2->vm_cookie, hp->vm_cookie, 4);
1452 		}
1453 	}
1454 	if (!hp->flags.name_switch) {
1455 		if ((hp->flags.name_switch = hp2->flags.name_switch)) {
1456 			hp->flags.send_name = hp2->flags.send_name;
1457 		}
1458 	}
1459 	if (!hp->flags.bootsize) {
1460 		if ((hp->flags.bootsize = hp2->flags.bootsize)) {
1461 			hp->flags.bootsize_auto = hp2->flags.bootsize_auto;
1462 			hp->bootsize = hp2->bootsize;
1463 		}
1464 	}
1465 	DUP_COPY(bootserver);
1466 
1467 	DUP_LINK(tftpdir);
1468 	DUP_LINK(dump_file);
1469 	DUP_LINK(domain_name);
1470 
1471 	DUP_COPY(swap_server);
1472 	DUP_LINK(root_path);
1473 	DUP_LINK(exten_file);
1474 
1475 	DUP_COPY(reply_addr);
1476 
1477 	DUP_LINK(nis_domain);
1478 	DUP_LINK(nis_server);
1479 	DUP_LINK(ntp_server);
1480 
1481 #ifdef	YORK_EX_OPTION
1482 	DUP_LINK(exec_file);
1483 #endif
1484 
1485 	DUP_COPY(msg_size);
1486 	DUP_COPY(min_wait);
1487 
1488 	/* XXX - Add new tags here */
1489 
1490 	DUP_LINK(generic);
1491 
1492 }
1493 #undef	DUP_COPY
1494 #undef	DUP_LINK
1495 
1496 
1497 
1498 /*
1499  * This function adjusts the caller's pointer to point just past the
1500  * first-encountered colon.  If it runs into a null character, it leaves
1501  * the pointer pointing to it.
1502  */
1503 
1504 PRIVATE void
1505 adjust(char **s)
1506 {
1507 	char *t;
1508 
1509 	t = *s;
1510 	while (*t && (*t != ':')) {
1511 		t++;
1512 	}
1513 	if (*t) {
1514 		t++;
1515 	}
1516 	*s = t;
1517 }
1518 
1519 
1520 
1521 
1522 /*
1523  * This function adjusts the caller's pointer to point to the first
1524  * non-whitespace character.  If it runs into a null character, it leaves
1525  * the pointer pointing to it.
1526  */
1527 
1528 PRIVATE void
1529 eat_whitespace(char **s)
1530 {
1531 	char *t;
1532 
1533 	t = *s;
1534 	while (*t && isspace((unsigned char)*t)) {
1535 		t++;
1536 	}
1537 	*s = t;
1538 }
1539 
1540 
1541 
1542 /*
1543  * This function converts the given string to all lowercase.
1544  */
1545 
1546 PRIVATE void
1547 makelower(char *s)
1548 {
1549 	while (*s) {
1550 		if (isupper((unsigned char)*s)) {
1551 			*s = tolower((unsigned char)*s);
1552 		}
1553 		s++;
1554 	}
1555 }
1556 
1557 
1558 
1559 /*
1560  *
1561  *	N O T E :
1562  *
1563  *	In many of the functions which follow, a parameter such as "src" or
1564  *	"symbol" is passed as a pointer to a pointer to something.  This is
1565  *	done for the purpose of letting the called function update the
1566  *	caller's copy of the parameter (i.e. to effect call-by-reference
1567  *	parameter passing).  The value of the actual parameter is only used
1568  *	to locate the real parameter of interest and then update this indirect
1569  *	parameter.
1570  *
1571  *	I'm sure somebody out there won't like this. . . .
1572  *  (Yea, because it usually makes code slower... -gwr)
1573  *
1574  */
1575 
1576 
1577 
1578 /*
1579  * "src" points to a character pointer which points to an ASCII string of
1580  * whitespace-separated IP addresses.  A pointer to an in_addr_list
1581  * structure containing the list of addresses is returned.  NULL is
1582  * returned if no addresses were found at all.  The pointer pointed to by
1583  * "src" is updated to point to the first non-address (illegal) character.
1584  */
1585 
1586 PRIVATE struct in_addr_list *
1587 get_addresses(char **src)
1588 {
1589 	struct in_addr tmpaddrlist[MAXINADDRS];
1590 	struct in_addr *address1, *address2;
1591 	struct in_addr_list *result;
1592 	unsigned addrcount, totalsize;
1593 
1594 	address1 = tmpaddrlist;
1595 	for (addrcount = 0; addrcount < MAXINADDRS; addrcount++) {
1596 		while (isspace((unsigned char)**src) || (**src == ',')) {
1597 			(*src)++;
1598 		}
1599 		if (!**src) {			/* Quit if nothing more */
1600 			break;
1601 		}
1602 		if (prs_inetaddr(src, &(address1->s_addr)) < 0) {
1603 			break;
1604 		}
1605 		address1++;				/* Point to next address slot */
1606 	}
1607 	if (addrcount < 1) {
1608 		result = NULL;
1609 	} else {
1610 		totalsize = sizeof(struct in_addr_list)
1611 		+			(addrcount - 1) * sizeof(struct in_addr);
1612 		result = (struct in_addr_list *) smalloc(totalsize);
1613 		result->linkcount = 1;
1614 		result->addrcount = addrcount;
1615 		address1 = tmpaddrlist;
1616 		address2 = result->addr;
1617 		for (; addrcount > 0; addrcount--) {
1618 			address2->s_addr = address1->s_addr;
1619 			address1++;
1620 			address2++;
1621 		}
1622 	}
1623 	return result;
1624 }
1625 
1626 
1627 
1628 /*
1629  * prs_inetaddr(src, result)
1630  *
1631  * "src" is a value-result parameter; the pointer it points to is updated
1632  * to point to the next data position.   "result" points to an unsigned long
1633  * in which an address is returned.
1634  *
1635  * This function parses the IP address string in ASCII "dot notation" pointed
1636  * to by (*src) and places the result (in network byte order) in the unsigned
1637  * long pointed to by "result".  For malformed addresses, -1 is returned,
1638  * (*src) points to the first illegal character, and the unsigned long pointed
1639  * to by "result" is unchanged.  Successful calls return 0.
1640  */
1641 
1642 PRIVATE int
1643 prs_inetaddr(char **src, u_int32 *result)
1644 {
1645 	char tmpstr[MAXSTRINGLEN];
1646 	u_int32 value;
1647 	u_int32 parts[4], *pp;
1648 	int n;
1649 	char *s, *t;
1650 
1651 #if 1	/* XXX - experimental */
1652 	/* Leading alpha char causes IP addr lookup. */
1653 	if (isalpha((unsigned char)**src)) {
1654 		/* Lookup IP address. */
1655 		s = *src;
1656 		t = tmpstr;
1657 		while ((isalnum((unsigned char)*s) || (*s == '.') ||
1658 				(*s == '-') || (*s == '_') ) &&
1659 			   (t < &tmpstr[MAXSTRINGLEN - 1]) )
1660 			*t++ = *s++;
1661 		*t = '\0';
1662 		*src = s;
1663 
1664 		n = lookup_ipa(tmpstr, result);
1665 		if (n < 0)
1666 			report(LOG_ERR, "can not get IP addr for %s", tmpstr);
1667 		return n;
1668 	}
1669 #endif
1670 
1671 	/*
1672 	 * Parse an address in Internet format:
1673 	 *	a.b.c.d
1674 	 *	a.b.c	(with c treated as 16-bits)
1675 	 *	a.b	(with b treated as 24 bits)
1676 	 */
1677 	pp = parts;
1678   loop:
1679 	/* If it's not a digit, return error. */
1680 	if (!isdigit((unsigned char)**src))
1681 		return -1;
1682 	*pp++ = get_u_long(src);
1683 	if (**src == '.') {
1684 		if (pp < (parts + 4)) {
1685 			(*src)++;
1686 			goto loop;
1687 		}
1688 		return (-1);
1689 	}
1690 #if 0
1691 	/* This is handled by the caller. */
1692 	if (**src && !((unsigned char)isspace(**src) || (**src == ':'))) {
1693 		return (-1);
1694 	}
1695 #endif
1696 
1697 	/*
1698 	 * Construct the address according to
1699 	 * the number of parts specified.
1700 	 */
1701 	n = pp - parts;
1702 	switch (n) {
1703 	case 1:					/* a -- 32 bits */
1704 		value = parts[0];
1705 		break;
1706 	case 2:					/* a.b -- 8.24 bits */
1707 		value = (parts[0] << 24) | (parts[1] & 0xFFFFFF);
1708 		break;
1709 	case 3:					/* a.b.c -- 8.8.16 bits */
1710 		value = (parts[0] << 24) | ((parts[1] & 0xFF) << 16) |
1711 			(parts[2] & 0xFFFF);
1712 		break;
1713 	case 4:					/* a.b.c.d -- 8.8.8.8 bits */
1714 		value = (parts[0] << 24) | ((parts[1] & 0xFF) << 16) |
1715 			((parts[2] & 0xFF) << 8) | (parts[3] & 0xFF);
1716 		break;
1717 	default:
1718 		return (-1);
1719 	}
1720 	*result = htonl(value);
1721 	return (0);
1722 }
1723 
1724 
1725 
1726 /*
1727  * "src" points to a pointer which in turn points to a hexadecimal ASCII
1728  * string.  This string is interpreted as a hardware address and returned
1729  * as a pointer to the actual hardware address, represented as an array of
1730  * bytes.
1731  *
1732  * The ASCII string must have the proper number of digits for the specified
1733  * hardware type (e.g. twelve digits for a 48-bit Ethernet address).
1734  * Two-digit sequences (bytes) may be separated with periods (.)  and/or
1735  * prefixed with '0x' for readability, but this is not required.
1736  *
1737  * For bad addresses, the pointer which "src" points to is updated to point
1738  * to the start of the first two-digit sequence which was bad, and the
1739  * function returns a NULL pointer.
1740  */
1741 
1742 PRIVATE byte *
1743 prs_haddr(char **src, u_int htype)
1744 {
1745 	static byte haddr[MAXHADDRLEN];
1746 	byte *hap;
1747 	char tmpstr[MAXSTRINGLEN];
1748 	u_int tmplen;
1749 	unsigned hal;
1750 	char *p;
1751 
1752 	hal = haddrlength(htype);	/* Get length of this address type */
1753 	if (hal <= 0) {
1754 		report(LOG_ERR, "Invalid addr type for HW addr parse");
1755 		return NULL;
1756 	}
1757 	tmplen = sizeof(tmpstr);
1758 	get_string(src, tmpstr, &tmplen);
1759 	p = tmpstr;
1760 
1761 #if 1	/* XXX - experimental */
1762 	/* If it's a valid host name, try to lookup the HW address. */
1763 	if (goodname(p)) {
1764 		/* Lookup Hardware Address for hostname. */
1765 		if ((hap = lookup_hwa(p, htype)) != NULL)
1766 			return hap; /* success */
1767 		report(LOG_ERR, "Add 0x prefix if hex value starts with A-F");
1768 		/* OK, assume it must be numeric. */
1769 	}
1770 #endif
1771 
1772 	hap = haddr;
1773 	while (hap < haddr + hal) {
1774 		if ((*p == '.') || (*p == ':'))
1775 			p++;
1776 		if (interp_byte(&p, hap++) < 0) {
1777 			return NULL;
1778 		}
1779 	}
1780 	return haddr;
1781 }
1782 
1783 
1784 
1785 /*
1786  * "src" is a pointer to a character pointer which in turn points to a
1787  * hexadecimal ASCII representation of a byte.  This byte is read, the
1788  * character pointer is updated, and the result is deposited into the
1789  * byte pointed to by "retbyte".
1790  *
1791  * The usual '0x' notation is allowed but not required.  The number must be
1792  * a two digit hexadecimal number.  If the number is invalid, "src" and
1793  * "retbyte" are left untouched and -1 is returned as the function value.
1794  * Successful calls return 0.
1795  */
1796 
1797 PRIVATE int
1798 interp_byte(char **src, byte *retbyte)
1799 {
1800 	int v;
1801 
1802 	if ((*src)[0] == '0' &&
1803 		((*src)[1] == 'x' ||
1804 		 (*src)[1] == 'X')) {
1805 		(*src) += 2;			/* allow 0x for hex, but don't require it */
1806 	}
1807 	if (!isxdigit((unsigned char)(*src)[0]) || !isxdigit((unsigned char)(*src)[1])) {
1808 		return -1;
1809 	}
1810 	if (sscanf(*src, "%2x", &v) != 1) {
1811 		return -1;
1812 	}
1813 	(*src) += 2;
1814 	*retbyte = (byte) (v & 0xFF);
1815 	return 0;
1816 }
1817 
1818 
1819 
1820 /*
1821  * The parameter "src" points to a character pointer which points to an
1822  * ASCII string representation of an unsigned number.  The number is
1823  * returned as an unsigned long and the character pointer is updated to
1824  * point to the first illegal character.
1825  */
1826 
1827 PRIVATE u_int32
1828 get_u_long(char **src)
1829 {
1830 	u_int32 value, base;
1831 	char c;
1832 
1833 	/*
1834 	 * Collect number up to first illegal character.  Values are specified
1835 	 * as for C:  0x=hex, 0=octal, other=decimal.
1836 	 */
1837 	value = 0;
1838 	base = 10;
1839 	if (**src == '0') {
1840 		base = 8;
1841 		(*src)++;
1842 	}
1843 	if (**src == 'x' || **src == 'X') {
1844 		base = 16;
1845 		(*src)++;
1846 	}
1847 	while ((c = **src)) {
1848 		if (isdigit((unsigned char)c)) {
1849 			value = (value * base) + (c - '0');
1850 			(*src)++;
1851 			continue;
1852 		}
1853 		if (base == 16 && isxdigit((unsigned char)c)) {
1854 			value = (value << 4) + ((c & ~32) + 10 - 'A');
1855 			(*src)++;
1856 			continue;
1857 		}
1858 		break;
1859 	}
1860 	return value;
1861 }
1862 
1863 
1864 
1865 /*
1866  * Routines for deletion of data associated with the main data structure.
1867  */
1868 
1869 
1870 /*
1871  * Frees the entire host data structure given.  Does nothing if the passed
1872  * pointer is NULL.
1873  */
1874 
1875 PRIVATE void
1876 free_host(hash_datum *hmp)
1877 {
1878 	struct host *hostptr = (struct host *) hmp;
1879 	if (hostptr == NULL)
1880 		return;
1881 	assert(hostptr->linkcount > 0);
1882 	if (--(hostptr->linkcount))
1883 		return;					/* Still has references */
1884 	del_iplist(hostptr->cookie_server);
1885 	del_iplist(hostptr->domain_server);
1886 	del_iplist(hostptr->gateway);
1887 	del_iplist(hostptr->impress_server);
1888 	del_iplist(hostptr->log_server);
1889 	del_iplist(hostptr->lpr_server);
1890 	del_iplist(hostptr->name_server);
1891 	del_iplist(hostptr->rlp_server);
1892 	del_iplist(hostptr->time_server);
1893 	del_iplist(hostptr->nis_server);
1894 	del_iplist(hostptr->ntp_server);
1895 
1896 	/*
1897 	 * XXX - Add new tags here
1898 	 * (if the value is an IP list)
1899 	 */
1900 
1901 	del_string(hostptr->hostname);
1902 	del_string(hostptr->homedir);
1903 	del_string(hostptr->bootfile);
1904 	del_string(hostptr->tftpdir);
1905 	del_string(hostptr->root_path);
1906 	del_string(hostptr->domain_name);
1907 	del_string(hostptr->dump_file);
1908 	del_string(hostptr->exten_file);
1909 	del_string(hostptr->nis_domain);
1910 
1911 #ifdef	YORK_EX_OPTION
1912 	del_string(hostptr->exec_file);
1913 #endif
1914 
1915 	/*
1916 	 * XXX - Add new tags here
1917 	 * (if it is a shared string)
1918 	 */
1919 
1920 	del_bindata(hostptr->generic);
1921 	free((char *) hostptr);
1922 }
1923 
1924 
1925 
1926 /*
1927  * Decrements the linkcount on the given IP address data structure.  If the
1928  * linkcount goes to zero, the memory associated with the data is freed.
1929  */
1930 
1931 PRIVATE void
1932 del_iplist(struct in_addr_list *iplist)
1933 {
1934 	if (iplist) {
1935 		if (!(--(iplist->linkcount))) {
1936 			free((char *) iplist);
1937 		}
1938 	}
1939 }
1940 
1941 
1942 
1943 /*
1944  * Decrements the linkcount on a string data structure.  If the count
1945  * goes to zero, the memory associated with the string is freed.  Does
1946  * nothing if the passed pointer is NULL.
1947  */
1948 
1949 PRIVATE void
1950 del_string(struct shared_string *stringptr)
1951 {
1952 	if (stringptr) {
1953 		if (!(--(stringptr->linkcount))) {
1954 			free((char *) stringptr);
1955 		}
1956 	}
1957 }
1958 
1959 
1960 
1961 /*
1962  * Decrements the linkcount on a shared_bindata data structure.  If the
1963  * count goes to zero, the memory associated with the data is freed.  Does
1964  * nothing if the passed pointer is NULL.
1965  */
1966 
1967 PRIVATE void
1968 del_bindata(struct shared_bindata *dataptr)
1969 {
1970 	if (dataptr) {
1971 		if (!(--(dataptr->linkcount))) {
1972 			free((char *) dataptr);
1973 		}
1974 	}
1975 }
1976 
1977 
1978 
1979 
1980 /* smalloc()  --  safe malloc()
1981  *
1982  * Always returns a valid pointer (if it returns at all).  The allocated
1983  * memory is initialized to all zeros.  If malloc() returns an error, a
1984  * message is printed using the report() function and the program aborts
1985  * with a status of 1.
1986  */
1987 
1988 PRIVATE char *
1989 smalloc(unsigned int nbytes)
1990 {
1991 	char *retvalue;
1992 
1993 	retvalue = malloc(nbytes);
1994 	if (!retvalue) {
1995 		report(LOG_ERR, "malloc() failure -- exiting");
1996 		exit(1);
1997 	}
1998 	bzero(retvalue, nbytes);
1999 	return retvalue;
2000 }
2001 
2002 
2003 /*
2004  * Compare function to determine whether two hardware addresses are
2005  * equivalent.  Returns TRUE if "host1" and "host2" are equivalent, FALSE
2006  * otherwise.
2007  *
2008  * This function is used when retrieving elements from the hardware address
2009  * hash table.
2010  */
2011 
2012 boolean
2013 hwlookcmp(hash_datum *d1, hash_datum *d2)
2014 {
2015 	struct host *host1 = (struct host *) d1;
2016 	struct host *host2 = (struct host *) d2;
2017 
2018 	if (host1->htype != host2->htype) {
2019 		return FALSE;
2020 	}
2021 	if (bcmp(host1->haddr, host2->haddr, haddrlength(host1->htype))) {
2022 		return FALSE;
2023 	}
2024 	return TRUE;
2025 }
2026 
2027 
2028 /*
2029  * Compare function for doing IP address hash table lookup.
2030  */
2031 
2032 boolean
2033 iplookcmp(hash_datum *d1, hash_datum *d2)
2034 {
2035 	struct host *host1 = (struct host *) d1;
2036 	struct host *host2 = (struct host *) d2;
2037 
2038 	return (host1->iaddr.s_addr == host2->iaddr.s_addr);
2039 }
2040 
2041 /*
2042  * Local Variables:
2043  * tab-width: 4
2044  * c-indent-level: 4
2045  * c-argdecl-indent: 4
2046  * c-continued-statement-offset: 4
2047  * c-continued-brace-offset: -4
2048  * c-label-offset: -4
2049  * c-brace-offset: 0
2050  * End:
2051  */
2052