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