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