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