xref: /freebsd/libexec/bootpd/readfile.c (revision a8445737e740901f5f2c8d24c12ef7fc8b00134e)
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 	$Id: readfile.c,v 1.4 1997/02/22 14:21:09 peter 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 preceeded by a backslash cause
493  * line-continuation onto the next line.  The entry is terminated by a
494  * newline character which is not preceeded 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 		case E_BAD_VALUE:
701 			msg = "bad value";
702 		default:
703 			msg = "unkown error";
704 			break;
705 		}						/* switch */
706 		report(LOG_ERR, "in entry named \"%s\", symbol \"%s\": %s",
707 			   current_hostname, current_tagname, msg);
708 		return -1;
709 	}
710 }
711 
712 
713 /*
714  * Macros for use in the function below:
715  */
716 
717 /* Parse one INET address stored directly in MEMBER. */
718 #define PARSE_IA1(MEMBER) do \
719 { \
720 	if (optype == OP_BOOLEAN) \
721 		return E_SYNTAX_ERROR; \
722 	hp->flags.MEMBER = FALSE; \
723 	if (optype == OP_ADDITION) { \
724 		if (prs_inetaddr(symbol, &value) < 0) \
725 			return E_BAD_IPADDR; \
726 		hp->MEMBER.s_addr = value; \
727 		hp->flags.MEMBER = TRUE; \
728 	} \
729 } while (0)
730 
731 /* Parse a list of INET addresses pointed to by MEMBER */
732 #define PARSE_IAL(MEMBER) do \
733 { \
734 	if (optype == OP_BOOLEAN) \
735 		return E_SYNTAX_ERROR; \
736 	if (hp->flags.MEMBER) { \
737 		hp->flags.MEMBER = FALSE; \
738 		assert(hp->MEMBER); \
739 		del_iplist(hp->MEMBER); \
740 		hp->MEMBER = NULL; \
741 	} \
742 	if (optype == OP_ADDITION) { \
743 		hp->MEMBER = get_addresses(symbol); \
744 		if (hp->MEMBER == NULL) \
745 			return E_SYNTAX_ERROR; \
746 		hp->flags.MEMBER = TRUE; \
747 	} \
748 } while (0)
749 
750 /* Parse a shared string pointed to by MEMBER */
751 #define PARSE_STR(MEMBER) do \
752 { \
753 	if (optype == OP_BOOLEAN) \
754 		return E_SYNTAX_ERROR; \
755 	if (hp->flags.MEMBER) { \
756 		hp->flags.MEMBER = FALSE; \
757 		assert(hp->MEMBER); \
758 		del_string(hp->MEMBER); \
759 		hp->MEMBER = NULL; \
760 	} \
761 	if (optype == OP_ADDITION) { \
762 		hp->MEMBER = get_shared_string(symbol); \
763 		if (hp->MEMBER == NULL) \
764 			return E_SYNTAX_ERROR; \
765 		hp->flags.MEMBER = TRUE; \
766 	} \
767 } while (0)
768 
769 /* Parse an unsigned integer value for MEMBER */
770 #define PARSE_UINT(MEMBER) do \
771 { \
772 	if (optype == OP_BOOLEAN) \
773 		return E_SYNTAX_ERROR; \
774 	hp->flags.MEMBER = FALSE; \
775 	if (optype == OP_ADDITION) { \
776 		value = get_u_long(symbol); \
777 		hp->MEMBER = value; \
778 		hp->flags.MEMBER = TRUE; \
779 	} \
780 } while (0)
781 
782 /*
783  * Evaluate the two-character tag symbol pointed to by "symbol" and place
784  * the data in the structure pointed to by "hp".  The pointer pointed to
785  * by "symbol" is updated to point past the source string (but may not
786  * point to the next tag entry).
787  *
788  * Obviously, this need a few more comments. . . .
789  */
790 PRIVATE int
791 eval_symbol(symbol, hp)
792 	char **symbol;
793 	struct host *hp;
794 {
795 	char tmpstr[MAXSTRINGLEN];
796 	byte *tmphaddr;
797 	struct symbolmap *symbolptr;
798 	u_int32 value;
799 	int32 timeoff;
800 	int i, numsymbols;
801 	unsigned len;
802 	int optype;					/* Indicates boolean, addition, or deletion */
803 
804 	eat_whitespace(symbol);
805 
806 	/* Make sure this is set before returning. */
807 	current_tagname[0] = (*symbol)[0];
808 	current_tagname[1] = (*symbol)[1];
809 	current_tagname[2] = 0;
810 
811 	if ((*symbol)[0] == '\0') {
812 		return E_END_OF_ENTRY;
813 	}
814 	if ((*symbol)[0] == ':') {
815 		return SUCCESS;
816 	}
817 	if ((*symbol)[0] == 'T') {	/* generic symbol */
818 		(*symbol)++;
819 		value = get_u_long(symbol);
820 		snprintf(current_tagname, sizeof(current_tagname),
821 			"T%d", (int)value);
822 		eat_whitespace(symbol);
823 		if ((*symbol)[0] != '=') {
824 			return E_SYNTAX_ERROR;
825 		}
826 		(*symbol)++;
827 		if (!(hp->generic)) {
828 			hp->generic = (struct shared_bindata *)
829 				smalloc(sizeof(struct shared_bindata));
830 		}
831 		if (process_generic(symbol, &(hp->generic), (byte) (value & 0xFF)))
832 			return E_SYNTAX_ERROR;
833 		hp->flags.generic = TRUE;
834 		return SUCCESS;
835 	}
836 	/*
837 	 * Determine the type of operation to be done on this symbol
838 	 */
839 	switch ((*symbol)[2]) {
840 	case '=':
841 		optype = OP_ADDITION;
842 		break;
843 	case '@':
844 		optype = OP_DELETION;
845 		break;
846 	case ':':
847 	case '\0':
848 		optype = OP_BOOLEAN;
849 		break;
850 	default:
851 		return E_SYNTAX_ERROR;
852 	}
853 
854 	symbolptr = symbol_list;
855 	numsymbols = sizeof(symbol_list) / sizeof(struct symbolmap);
856 	for (i = 0; i < numsymbols; i++) {
857 		if (((symbolptr->symbol)[0] == (*symbol)[0]) &&
858 			((symbolptr->symbol)[1] == (*symbol)[1])) {
859 			break;
860 		}
861 		symbolptr++;
862 	}
863 	if (i >= numsymbols) {
864 		return E_UNKNOWN_SYMBOL;
865 	}
866 	/*
867 	 * Skip past the = or @ character (to point to the data) if this
868 	 * isn't a boolean operation.  For boolean operations, just skip
869 	 * over the two-character tag symbol (and nothing else. . . .).
870 	 */
871 	(*symbol) += (optype == OP_BOOLEAN) ? 2 : 3;
872 
873 	eat_whitespace(symbol);
874 
875 	/* The cases below are in order by symbolcode value. */
876 	switch (symbolptr->symbolcode) {
877 
878 	case SYM_BOOTFILE:
879 		PARSE_STR(bootfile);
880 		break;
881 
882 	case SYM_COOKIE_SERVER:
883 		PARSE_IAL(cookie_server);
884 		break;
885 
886 	case SYM_DOMAIN_SERVER:
887 		PARSE_IAL(domain_server);
888 		break;
889 
890 	case SYM_GATEWAY:
891 		PARSE_IAL(gateway);
892 		break;
893 
894 	case SYM_HWADDR:
895 		if (optype == OP_BOOLEAN)
896 			return E_SYNTAX_ERROR;
897 		hp->flags.haddr = FALSE;
898 		if (optype == OP_ADDITION) {
899 			/* Default the HW type to Ethernet */
900 			if (hp->flags.htype == 0) {
901 				hp->flags.htype = TRUE;
902 				hp->htype = HTYPE_ETHERNET;
903 			}
904 			tmphaddr = prs_haddr(symbol, hp->htype);
905 			if (!tmphaddr)
906 				return E_BAD_HWADDR;
907 			bcopy(tmphaddr, hp->haddr, haddrlength(hp->htype));
908 			hp->flags.haddr = TRUE;
909 		}
910 		break;
911 
912 	case SYM_HOMEDIR:
913 		PARSE_STR(homedir);
914 		break;
915 
916 	case SYM_HTYPE:
917 		if (optype == OP_BOOLEAN)
918 			return E_SYNTAX_ERROR;
919 		hp->flags.htype = FALSE;
920 		if (optype == OP_ADDITION) {
921 			value = 0L;			/* Assume an illegal value */
922 			eat_whitespace(symbol);
923 			if (isdigit(**symbol)) {
924 				value = get_u_long(symbol);
925 			} else {
926 				len = sizeof(tmpstr);
927 				(void) get_string(symbol, tmpstr, &len);
928 				makelower(tmpstr);
929 				numsymbols = sizeof(htnamemap) /
930 					sizeof(struct htypename);
931 				for (i = 0; i < numsymbols; i++) {
932 					if (!strcmp(htnamemap[i].name, tmpstr)) {
933 						break;
934 					}
935 				}
936 				if (i < numsymbols) {
937 					value = htnamemap[i].htype;
938 				}
939 			}
940 			if (value >= hwinfocnt) {
941 				return E_BAD_HWATYPE;
942 			}
943 			hp->htype = (byte) (value & 0xFF);
944 			hp->flags.htype = TRUE;
945 		}
946 		break;
947 
948 	case SYM_IMPRESS_SERVER:
949 		PARSE_IAL(impress_server);
950 		break;
951 
952 	case SYM_IPADDR:
953 		PARSE_IA1(iaddr);
954 		break;
955 
956 	case SYM_LOG_SERVER:
957 		PARSE_IAL(log_server);
958 		break;
959 
960 	case SYM_LPR_SERVER:
961 		PARSE_IAL(lpr_server);
962 		break;
963 
964 	case SYM_NAME_SERVER:
965 		PARSE_IAL(name_server);
966 		break;
967 
968 	case SYM_RLP_SERVER:
969 		PARSE_IAL(rlp_server);
970 		break;
971 
972 	case SYM_SUBNET_MASK:
973 		PARSE_IA1(subnet_mask);
974 		break;
975 
976 	case SYM_TIME_OFFSET:
977 		if (optype == OP_BOOLEAN)
978 			return E_SYNTAX_ERROR;
979 		hp->flags.time_offset = FALSE;
980 		if (optype == OP_ADDITION) {
981 			len = sizeof(tmpstr);
982 			(void) get_string(symbol, tmpstr, &len);
983 			if (!strncmp(tmpstr, "auto", 4)) {
984 				hp->time_offset = secondswest;
985 			} else {
986 				if (sscanf(tmpstr, "%d", (int*)&timeoff) != 1)
987 					return E_BAD_LONGWORD;
988 				hp->time_offset = timeoff;
989 			}
990 			hp->flags.time_offset = TRUE;
991 		}
992 		break;
993 
994 	case SYM_TIME_SERVER:
995 		PARSE_IAL(time_server);
996 		break;
997 
998 	case SYM_VENDOR_MAGIC:
999 		if (optype == OP_BOOLEAN)
1000 			return E_SYNTAX_ERROR;
1001 		hp->flags.vm_cookie = FALSE;
1002 		if (optype == OP_ADDITION) {
1003 			if (strncmp(*symbol, "auto", 4)) {
1004 				/* The string is not "auto" */
1005 				if (!strncmp(*symbol, "rfc", 3)) {
1006 					bcopy(vm_rfc1048, hp->vm_cookie, 4);
1007 				} else if (!strncmp(*symbol, "cmu", 3)) {
1008 					bcopy(vm_cmu, hp->vm_cookie, 4);
1009 				} else {
1010 					if (!isdigit(**symbol))
1011 						return E_BAD_IPADDR;
1012 					if (prs_inetaddr(symbol, &value) < 0)
1013 						return E_BAD_IPADDR;
1014 					bcopy(&value, hp->vm_cookie, 4);
1015 				}
1016 				hp->flags.vm_cookie = TRUE;
1017 			}
1018 		}
1019 		break;
1020 
1021 	case SYM_SIMILAR_ENTRY:
1022 		switch (optype) {
1023 		case OP_ADDITION:
1024 			fill_defaults(hp, symbol);
1025 			break;
1026 		default:
1027 			return E_SYNTAX_ERROR;
1028 		}
1029 		break;
1030 
1031 	case SYM_NAME_SWITCH:
1032 		switch (optype) {
1033 		case OP_ADDITION:
1034 			return E_SYNTAX_ERROR;
1035 		case OP_DELETION:
1036 			hp->flags.send_name = FALSE;
1037 			hp->flags.name_switch = FALSE;
1038 			break;
1039 		case OP_BOOLEAN:
1040 			hp->flags.send_name = TRUE;
1041 			hp->flags.name_switch = TRUE;
1042 			break;
1043 		}
1044 		break;
1045 
1046 	case SYM_BOOTSIZE:
1047 		switch (optype) {
1048 		case OP_ADDITION:
1049 			if (!strncmp(*symbol, "auto", 4)) {
1050 				hp->flags.bootsize = TRUE;
1051 				hp->flags.bootsize_auto = TRUE;
1052 			} else {
1053 				hp->bootsize = (unsigned int) get_u_long(symbol);
1054 				hp->flags.bootsize = TRUE;
1055 				hp->flags.bootsize_auto = FALSE;
1056 			}
1057 			break;
1058 		case OP_DELETION:
1059 			hp->flags.bootsize = FALSE;
1060 			break;
1061 		case OP_BOOLEAN:
1062 			hp->flags.bootsize = TRUE;
1063 			hp->flags.bootsize_auto = TRUE;
1064 			break;
1065 		}
1066 		break;
1067 
1068 	case SYM_BOOT_SERVER:
1069 		PARSE_IA1(bootserver);
1070 		break;
1071 
1072 	case SYM_TFTPDIR:
1073 		PARSE_STR(tftpdir);
1074 		if ((hp->tftpdir != NULL) &&
1075 			(hp->tftpdir->string[0] != '/'))
1076 			return E_BAD_PATHNAME;
1077 		break;
1078 
1079 	case SYM_DUMP_FILE:
1080 		PARSE_STR(dump_file);
1081 		break;
1082 
1083 	case SYM_DOMAIN_NAME:
1084 		PARSE_STR(domain_name);
1085 		break;
1086 
1087 	case SYM_SWAP_SERVER:
1088 		PARSE_IA1(swap_server);
1089 		break;
1090 
1091 	case SYM_ROOT_PATH:
1092 		PARSE_STR(root_path);
1093 		break;
1094 
1095 	case SYM_EXTEN_FILE:
1096 		PARSE_STR(exten_file);
1097 		break;
1098 
1099 	case SYM_REPLY_ADDR:
1100 		PARSE_IA1(reply_addr);
1101 		break;
1102 
1103 	case SYM_NIS_DOMAIN:
1104 		PARSE_STR(nis_domain);
1105 		break;
1106 
1107 	case SYM_NIS_SERVER:
1108 		PARSE_IAL(nis_server);
1109 		break;
1110 
1111 	case SYM_NTP_SERVER:
1112 		PARSE_IAL(ntp_server);
1113 		break;
1114 
1115 #ifdef	YORK_EX_OPTION
1116 	case SYM_EXEC_FILE:
1117 		PARSE_STR(exec_file);
1118 		break;
1119 #endif
1120 
1121 	case SYM_MSG_SIZE:
1122 		PARSE_UINT(msg_size);
1123 		if (hp->msg_size < BP_MINPKTSZ ||
1124 			hp->msg_size > MAX_MSG_SIZE)
1125 			return E_BAD_VALUE;
1126 		break;
1127 
1128 	case SYM_MIN_WAIT:
1129 		PARSE_UINT(min_wait);
1130 		break;
1131 
1132 		/* XXX - Add new tags here */
1133 
1134 	default:
1135 		return E_UNKNOWN_SYMBOL;
1136 
1137 	}							/* switch symbolcode */
1138 
1139 	return SUCCESS;
1140 }
1141 #undef	PARSE_IA1
1142 #undef	PARSE_IAL
1143 #undef	PARSE_STR
1144 
1145 
1146 
1147 
1148 /*
1149  * Read a string from the buffer indirectly pointed to through "src" and
1150  * move it into the buffer pointed to by "dest".  A pointer to the maximum
1151  * allowable length of the string (including null-terminator) is passed as
1152  * "length".  The actual length of the string which was read is returned in
1153  * the unsigned integer pointed to by "length".  This value is the same as
1154  * that which would be returned by applying the strlen() function on the
1155  * destination string (i.e the terminating null is not counted as a
1156  * character).  Trailing whitespace is removed from the string.  For
1157  * convenience, the function returns the new value of "dest".
1158  *
1159  * The string is read until the maximum number of characters, an unquoted
1160  * colon (:), or a null character is read.  The return string in "dest" is
1161  * null-terminated.
1162  */
1163 
1164 PRIVATE char *
1165 get_string(src, dest, length)
1166 	char **src, *dest;
1167 	unsigned *length;
1168 {
1169 	int n, len, quoteflag;
1170 
1171 	quoteflag = FALSE;
1172 	n = 0;
1173 	len = *length - 1;
1174 	while ((n < len) && (**src)) {
1175 		if (!quoteflag && (**src == ':')) {
1176 			break;
1177 		}
1178 		if (**src == '"') {
1179 			(*src)++;
1180 			quoteflag = !quoteflag;
1181 			continue;
1182 		}
1183 		if (**src == '\\') {
1184 			(*src)++;
1185 			if (!**src) {
1186 				break;
1187 			}
1188 		}
1189 		*dest++ = *(*src)++;
1190 		n++;
1191 	}
1192 
1193 	/*
1194 	 * Remove that troublesome trailing whitespace. . .
1195 	 */
1196 	while ((n > 0) && isspace(dest[-1])) {
1197 		dest--;
1198 		n--;
1199 	}
1200 
1201 	*dest = '\0';
1202 	*length = n;
1203 	return dest;
1204 }
1205 
1206 
1207 
1208 /*
1209  * Read the string indirectly pointed to by "src", update the caller's
1210  * pointer, and return a pointer to a malloc'ed shared_string structure
1211  * containing the string.
1212  *
1213  * The string is read using the same rules as get_string() above.
1214  */
1215 
1216 PRIVATE struct shared_string *
1217 get_shared_string(src)
1218 	char **src;
1219 {
1220 	char retstring[MAXSTRINGLEN];
1221 	struct shared_string *s;
1222 	unsigned length;
1223 
1224 	length = sizeof(retstring);
1225 	(void) get_string(src, retstring, &length);
1226 
1227 	s = (struct shared_string *) smalloc(sizeof(struct shared_string)
1228 										 + length);
1229 	s->linkcount = 1;
1230 	strcpy(s->string, retstring);
1231 
1232 	return s;
1233 }
1234 
1235 
1236 
1237 /*
1238  * Load RFC1048 generic information directly into a memory buffer.
1239  *
1240  * "src" indirectly points to the ASCII representation of the generic data.
1241  * "dest" points to a string structure which is updated to point to a new
1242  * string with the new data appended to the old string.  The old string is
1243  * freed.
1244  *
1245  * The given tag value is inserted with the new data.
1246  *
1247  * The data may be represented as either a stream of hexadecimal numbers
1248  * representing bytes (any or all bytes may optionally start with '0x' and
1249  * be separated with periods ".") or as a quoted string of ASCII
1250  * characters (the quotes are required).
1251  */
1252 
1253 PRIVATE int
1254 process_generic(src, dest, tagvalue)
1255 	char **src;
1256 	struct shared_bindata **dest;
1257 	u_int tagvalue;
1258 {
1259 	byte tmpbuf[MAXBUFLEN];
1260 	byte *str;
1261 	struct shared_bindata *bdata;
1262 	u_int newlength, oldlength;
1263 
1264 	str = tmpbuf;
1265 	*str++ = (tagvalue & 0xFF);	/* Store tag value */
1266 	str++;						/* Skip over length field */
1267 	if ((*src)[0] == '"') {		/* ASCII data */
1268 		newlength = sizeof(tmpbuf) - 2;	/* Set maximum allowed length */
1269 		(void) get_string(src, (char *) str, &newlength);
1270 		newlength++;			/* null terminator */
1271 	} else {					/* Numeric data */
1272 		newlength = 0;
1273 		while (newlength < sizeof(tmpbuf) - 2) {
1274 			if (interp_byte(src, str++) < 0)
1275 				break;
1276 			newlength++;
1277 			if (**src == '.') {
1278 				(*src)++;
1279 			}
1280 		}
1281 	}
1282 	if ((*src)[0] != ':')
1283 		return -1;
1284 
1285 	tmpbuf[1] = (newlength & 0xFF);
1286 	oldlength = ((*dest)->length);
1287 	bdata = (struct shared_bindata *) smalloc(sizeof(struct shared_bindata)
1288 											+ oldlength + newlength + 1);
1289 	if (oldlength > 0) {
1290 		bcopy((*dest)->data, bdata->data, oldlength);
1291 	}
1292 	bcopy(tmpbuf, bdata->data + oldlength, newlength + 2);
1293 	bdata->length = oldlength + newlength + 2;
1294 	bdata->linkcount = 1;
1295 	if (*dest) {
1296 		del_bindata(*dest);
1297 	}
1298 	*dest = bdata;
1299 	return 0;
1300 }
1301 
1302 
1303 
1304 /*
1305  * Verify that the given string makes sense as a hostname (according to
1306  * Appendix 1, page 29 of RFC882).
1307  *
1308  * Return TRUE for good names, FALSE otherwise.
1309  */
1310 
1311 PRIVATE boolean
1312 goodname(hostname)
1313 	register char *hostname;
1314 {
1315 	do {
1316 		if (!isalpha(*hostname++)) {	/* First character must be a letter */
1317 			return FALSE;
1318 		}
1319 		while (isalnum(*hostname) ||
1320 			   (*hostname == '-') ||
1321 			   (*hostname == '_') )
1322 		{
1323 			hostname++;			/* Alphanumeric or a hyphen */
1324 		}
1325 		if (!isalnum(hostname[-1])) {	/* Last must be alphanumeric */
1326 			return FALSE;
1327 		}
1328 		if (*hostname == '\0') {/* Done? */
1329 			return TRUE;
1330 		}
1331 	} while (*hostname++ == '.');	/* Dot, loop for next label */
1332 
1333 	return FALSE;				/* If it's not a dot, lose */
1334 }
1335 
1336 
1337 
1338 /*
1339  * Null compare function -- always returns FALSE so an element is always
1340  * inserted into a hash table (i.e. there is never a collision with an
1341  * existing element).
1342  */
1343 
1344 PRIVATE boolean
1345 nullcmp(d1, d2)
1346 	hash_datum *d1, *d2;
1347 {
1348 	return FALSE;
1349 }
1350 
1351 
1352 /*
1353  * Function for comparing a string with the hostname field of a host
1354  * structure.
1355  */
1356 
1357 boolean
1358 nmcmp(d1, d2)
1359 	hash_datum *d1, *d2;
1360 {
1361 	char *name = (char *) d1;	/* XXX - OK? */
1362 	struct host *hp = (struct host *) d2;
1363 
1364 	return !strcmp(name, hp->hostname->string);
1365 }
1366 
1367 
1368 /*
1369  * Compare function to determine whether two hardware addresses are
1370  * equivalent.  Returns TRUE if "host1" and "host2" are equivalent, FALSE
1371  * otherwise.
1372  *
1373  * If the hardware addresses of "host1" and "host2" are identical, but
1374  * they are on different IP subnets, this function returns FALSE.
1375  *
1376  * This function is used when inserting elements into the hardware address
1377  * hash table.
1378  */
1379 
1380 PRIVATE boolean
1381 hwinscmp(d1, d2)
1382 	hash_datum *d1, *d2;
1383 {
1384 	struct host *host1 = (struct host *) d1;
1385 	struct host *host2 = (struct host *) d2;
1386 
1387 	if (host1->htype != host2->htype) {
1388 		return FALSE;
1389 	}
1390 	if (bcmp(host1->haddr, host2->haddr, haddrlength(host1->htype))) {
1391 		return FALSE;
1392 	}
1393 	/* XXX - Is the subnet_mask field set yet? */
1394 	if ((host1->subnet_mask.s_addr) == (host2->subnet_mask.s_addr)) {
1395 		if (((host1->iaddr.s_addr) & (host1->subnet_mask.s_addr)) !=
1396 			((host2->iaddr.s_addr) & (host2->subnet_mask.s_addr)))
1397 		{
1398 			return FALSE;
1399 		}
1400 	}
1401 	return TRUE;
1402 }
1403 
1404 
1405 /*
1406  * Macros for use in the function below:
1407  */
1408 
1409 #define DUP_COPY(MEMBER) do \
1410 { \
1411 	if (!hp->flags.MEMBER) { \
1412 		if ((hp->flags.MEMBER = hp2->flags.MEMBER) != 0) { \
1413 			hp->MEMBER = hp2->MEMBER; \
1414 		} \
1415 	} \
1416 } while (0)
1417 
1418 #define DUP_LINK(MEMBER) do \
1419 { \
1420 	if (!hp->flags.MEMBER) { \
1421 		if ((hp->flags.MEMBER = hp2->flags.MEMBER) != 0) { \
1422 			assert(hp2->MEMBER); \
1423 			hp->MEMBER = hp2->MEMBER; \
1424 			(hp->MEMBER->linkcount)++; \
1425 		} \
1426 	} \
1427 } while (0)
1428 
1429 /*
1430  * Process the "similar entry" symbol.
1431  *
1432  * The host specified as the value of the "tc" symbol is used as a template
1433  * for the current host entry.  Symbol values not explicitly set in the
1434  * current host entry are inferred from the template entry.
1435  */
1436 PRIVATE void
1437 fill_defaults(hp, src)
1438 	struct host *hp;
1439 	char **src;
1440 {
1441 	unsigned int tlen, hashcode;
1442 	struct host *hp2;
1443 	char tstring[MAXSTRINGLEN];
1444 
1445 	tlen = sizeof(tstring);
1446 	(void) get_string(src, tstring, &tlen);
1447 	hashcode = hash_HashFunction((u_char *) tstring, tlen);
1448 	hp2 = (struct host *) hash_Lookup(nmhashtable, hashcode, nmcmp, tstring);
1449 
1450 	if (hp2 == NULL) {
1451 		report(LOG_ERR, "can't find tc=\"%s\"", tstring);
1452 		return;
1453 	}
1454 	DUP_LINK(bootfile);
1455 	DUP_LINK(cookie_server);
1456 	DUP_LINK(domain_server);
1457 	DUP_LINK(gateway);
1458 	/* haddr not copied */
1459 	DUP_LINK(homedir);
1460 	DUP_COPY(htype);
1461 
1462 	DUP_LINK(impress_server);
1463 	/* iaddr not copied */
1464 	DUP_LINK(log_server);
1465 	DUP_LINK(lpr_server);
1466 	DUP_LINK(name_server);
1467 	DUP_LINK(rlp_server);
1468 
1469 	DUP_COPY(subnet_mask);
1470 	DUP_COPY(time_offset);
1471 	DUP_LINK(time_server);
1472 
1473 	if (!hp->flags.vm_cookie) {
1474 		if ((hp->flags.vm_cookie = hp2->flags.vm_cookie)) {
1475 			bcopy(hp2->vm_cookie, hp->vm_cookie, 4);
1476 		}
1477 	}
1478 	if (!hp->flags.name_switch) {
1479 		if ((hp->flags.name_switch = hp2->flags.name_switch)) {
1480 			hp->flags.send_name = hp2->flags.send_name;
1481 		}
1482 	}
1483 	if (!hp->flags.bootsize) {
1484 		if ((hp->flags.bootsize = hp2->flags.bootsize)) {
1485 			hp->flags.bootsize_auto = hp2->flags.bootsize_auto;
1486 			hp->bootsize = hp2->bootsize;
1487 		}
1488 	}
1489 	DUP_COPY(bootserver);
1490 
1491 	DUP_LINK(tftpdir);
1492 	DUP_LINK(dump_file);
1493 	DUP_LINK(domain_name);
1494 
1495 	DUP_COPY(swap_server);
1496 	DUP_LINK(root_path);
1497 	DUP_LINK(exten_file);
1498 
1499 	DUP_COPY(reply_addr);
1500 
1501 	DUP_LINK(nis_domain);
1502 	DUP_LINK(nis_server);
1503 	DUP_LINK(ntp_server);
1504 
1505 #ifdef	YORK_EX_OPTION
1506 	DUP_LINK(exec_file);
1507 #endif
1508 
1509 	DUP_COPY(msg_size);
1510 	DUP_COPY(min_wait);
1511 
1512 	/* XXX - Add new tags here */
1513 
1514 	DUP_LINK(generic);
1515 
1516 }
1517 #undef	DUP_COPY
1518 #undef	DUP_LINK
1519 
1520 
1521 
1522 /*
1523  * This function adjusts the caller's pointer to point just past the
1524  * first-encountered colon.  If it runs into a null character, it leaves
1525  * the pointer pointing to it.
1526  */
1527 
1528 PRIVATE void
1529 adjust(s)
1530 	char **s;
1531 {
1532 	register char *t;
1533 
1534 	t = *s;
1535 	while (*t && (*t != ':')) {
1536 		t++;
1537 	}
1538 	if (*t) {
1539 		t++;
1540 	}
1541 	*s = t;
1542 }
1543 
1544 
1545 
1546 
1547 /*
1548  * This function adjusts the caller's pointer to point to the first
1549  * non-whitespace character.  If it runs into a null character, it leaves
1550  * the pointer pointing to it.
1551  */
1552 
1553 PRIVATE void
1554 eat_whitespace(s)
1555 	char **s;
1556 {
1557 	register char *t;
1558 
1559 	t = *s;
1560 	while (*t && isspace(*t)) {
1561 		t++;
1562 	}
1563 	*s = t;
1564 }
1565 
1566 
1567 
1568 /*
1569  * This function converts the given string to all lowercase.
1570  */
1571 
1572 PRIVATE void
1573 makelower(s)
1574 	char *s;
1575 {
1576 	while (*s) {
1577 		if (isupper(*s)) {
1578 			*s = tolower(*s);
1579 		}
1580 		s++;
1581 	}
1582 }
1583 
1584 
1585 
1586 /*
1587  *
1588  *	N O T E :
1589  *
1590  *	In many of the functions which follow, a parameter such as "src" or
1591  *	"symbol" is passed as a pointer to a pointer to something.  This is
1592  *	done for the purpose of letting the called function update the
1593  *	caller's copy of the parameter (i.e. to effect call-by-reference
1594  *	parameter passing).  The value of the actual parameter is only used
1595  *	to locate the real parameter of interest and then update this indirect
1596  *	parameter.
1597  *
1598  *	I'm sure somebody out there won't like this. . . .
1599  *  (Yea, because it usually makes code slower... -gwr)
1600  *
1601  */
1602 
1603 
1604 
1605 /*
1606  * "src" points to a character pointer which points to an ASCII string of
1607  * whitespace-separated IP addresses.  A pointer to an in_addr_list
1608  * structure containing the list of addresses is returned.  NULL is
1609  * returned if no addresses were found at all.  The pointer pointed to by
1610  * "src" is updated to point to the first non-address (illegal) character.
1611  */
1612 
1613 PRIVATE struct in_addr_list *
1614 get_addresses(src)
1615 	char **src;
1616 {
1617 	struct in_addr tmpaddrlist[MAXINADDRS];
1618 	struct in_addr *address1, *address2;
1619 	struct in_addr_list *result;
1620 	unsigned addrcount, totalsize;
1621 
1622 	address1 = tmpaddrlist;
1623 	for (addrcount = 0; addrcount < MAXINADDRS; addrcount++) {
1624 		while (isspace(**src) || (**src == ',')) {
1625 			(*src)++;
1626 		}
1627 		if (!**src) {			/* Quit if nothing more */
1628 			break;
1629 		}
1630 		if (prs_inetaddr(src, &(address1->s_addr)) < 0) {
1631 			break;
1632 		}
1633 		address1++;				/* Point to next address slot */
1634 	}
1635 	if (addrcount < 1) {
1636 		result = NULL;
1637 	} else {
1638 		totalsize = sizeof(struct in_addr_list)
1639 		+			(addrcount - 1) * sizeof(struct in_addr);
1640 		result = (struct in_addr_list *) smalloc(totalsize);
1641 		result->linkcount = 1;
1642 		result->addrcount = addrcount;
1643 		address1 = tmpaddrlist;
1644 		address2 = result->addr;
1645 		for (; addrcount > 0; addrcount--) {
1646 			address2->s_addr = address1->s_addr;
1647 			address1++;
1648 			address2++;
1649 		}
1650 	}
1651 	return result;
1652 }
1653 
1654 
1655 
1656 /*
1657  * prs_inetaddr(src, result)
1658  *
1659  * "src" is a value-result parameter; the pointer it points to is updated
1660  * to point to the next data position.   "result" points to an unsigned long
1661  * in which an address is returned.
1662  *
1663  * This function parses the IP address string in ASCII "dot notation" pointed
1664  * to by (*src) and places the result (in network byte order) in the unsigned
1665  * long pointed to by "result".  For malformed addresses, -1 is returned,
1666  * (*src) points to the first illegal character, and the unsigned long pointed
1667  * to by "result" is unchanged.  Successful calls return 0.
1668  */
1669 
1670 PRIVATE int
1671 prs_inetaddr(src, result)
1672 	char **src;
1673 	u_int32 *result;
1674 {
1675 	char tmpstr[MAXSTRINGLEN];
1676 	register u_int32 value;
1677 	u_int32 parts[4], *pp;
1678 	int n;
1679 	char *s, *t;
1680 
1681 	/* Leading alpha char causes IP addr lookup. */
1682 	if (isalpha(**src)) {
1683 		/* Lookup IP address. */
1684 		s = *src;
1685 		t = tmpstr;
1686 		while ((isalnum(*s) || (*s == '.') ||
1687 				(*s == '-') || (*s == '_') ) &&
1688 			   (t < &tmpstr[MAXSTRINGLEN - 1]) )
1689 			*t++ = *s++;
1690 		*t = '\0';
1691 		*src = s;
1692 
1693 		n = lookup_ipa(tmpstr, result);
1694 		if (n < 0)
1695 			report(LOG_ERR, "can not get IP addr for %s", tmpstr);
1696 		return n;
1697 	}
1698 
1699 	/*
1700 	 * Parse an address in Internet format:
1701 	 *	a.b.c.d
1702 	 *	a.b.c	(with c treated as 16-bits)
1703 	 *	a.b	(with b treated as 24 bits)
1704 	 */
1705 	pp = parts;
1706   loop:
1707 	/* If it's not a digit, return error. */
1708 	if (!isdigit(**src))
1709 		return -1;
1710 	*pp++ = get_u_long(src);
1711 	if (**src == '.') {
1712 		if (pp < (parts + 4)) {
1713 			(*src)++;
1714 			goto loop;
1715 		}
1716 		return (-1);
1717 	}
1718 #if 0
1719 	/* This is handled by the caller. */
1720 	if (**src && !(isspace(**src) || (**src == ':'))) {
1721 		return (-1);
1722 	}
1723 #endif
1724 
1725 	/*
1726 	 * Construct the address according to
1727 	 * the number of parts specified.
1728 	 */
1729 	n = pp - parts;
1730 	switch (n) {
1731 	case 1:					/* a -- 32 bits */
1732 		value = parts[0];
1733 		break;
1734 	case 2:					/* a.b -- 8.24 bits */
1735 		value = (parts[0] << 24) | (parts[1] & 0xFFFFFF);
1736 		break;
1737 	case 3:					/* a.b.c -- 8.8.16 bits */
1738 		value = (parts[0] << 24) | ((parts[1] & 0xFF) << 16) |
1739 			(parts[2] & 0xFFFF);
1740 		break;
1741 	case 4:					/* a.b.c.d -- 8.8.8.8 bits */
1742 		value = (parts[0] << 24) | ((parts[1] & 0xFF) << 16) |
1743 			((parts[2] & 0xFF) << 8) | (parts[3] & 0xFF);
1744 		break;
1745 	default:
1746 		return (-1);
1747 	}
1748 	*result = htonl(value);
1749 	return (0);
1750 }
1751 
1752 
1753 
1754 /*
1755  * "src" points to a pointer which in turn points to a hexadecimal ASCII
1756  * string.  This string is interpreted as a hardware address and returned
1757  * as a pointer to the actual hardware address, represented as an array of
1758  * bytes.
1759  *
1760  * The ASCII string must have the proper number of digits for the specified
1761  * hardware type (e.g. twelve digits for a 48-bit Ethernet address).
1762  * Two-digit sequences (bytes) may be separated with periods (.)  and/or
1763  * prefixed with '0x' for readability, but this is not required.
1764  *
1765  * For bad addresses, the pointer which "src" points to is updated to point
1766  * to the start of the first two-digit sequence which was bad, and the
1767  * function returns a NULL pointer.
1768  */
1769 
1770 PRIVATE byte *
1771 prs_haddr(src, htype)
1772 	char **src;
1773 	u_int htype;
1774 {
1775 	static byte haddr[MAXHADDRLEN];
1776 	byte *hap;
1777 	char tmpstr[MAXSTRINGLEN];
1778 	u_int tmplen;
1779 	unsigned hal;
1780 	char *p;
1781 
1782 	hal = haddrlength(htype);	/* Get length of this address type */
1783 	if (hal <= 0) {
1784 		report(LOG_ERR, "Invalid addr type for HW addr parse");
1785 		return NULL;
1786 	}
1787 	tmplen = sizeof(tmpstr);
1788 	get_string(src, tmpstr, &tmplen);
1789 	p = tmpstr;
1790 
1791 	/* If it's a valid host name, try to lookup the HW address. */
1792 	if (goodname(p)) {
1793 		/* Lookup Hardware Address for hostname. */
1794 		if ((hap = lookup_hwa(p, htype)) != NULL)
1795 			return hap; /* success */
1796 		report(LOG_ERR, "Add 0x prefix if hex value starts with A-F");
1797 		/* OK, assume it must be numeric. */
1798 	}
1799 
1800 	hap = haddr;
1801 	while (hap < haddr + hal) {
1802 		if ((*p == '.') || (*p == ':'))
1803 			p++;
1804 		if (interp_byte(&p, hap++) < 0) {
1805 			return NULL;
1806 		}
1807 	}
1808 	return haddr;
1809 }
1810 
1811 
1812 
1813 /*
1814  * "src" is a pointer to a character pointer which in turn points to a
1815  * hexadecimal ASCII representation of a byte.  This byte is read, the
1816  * character pointer is updated, and the result is deposited into the
1817  * byte pointed to by "retbyte".
1818  *
1819  * The usual '0x' notation is allowed but not required.  The number must be
1820  * a two digit hexadecimal number.  If the number is invalid, "src" and
1821  * "retbyte" are left untouched and -1 is returned as the function value.
1822  * Successful calls return 0.
1823  */
1824 
1825 PRIVATE int
1826 interp_byte(src, retbyte)
1827 	char **src;
1828 	byte *retbyte;
1829 {
1830 	int v;
1831 
1832 	if ((*src)[0] == '0' &&
1833 		((*src)[1] == 'x' ||
1834 		 (*src)[1] == 'X')) {
1835 		(*src) += 2;			/* allow 0x for hex, but don't require it */
1836 	}
1837 	if (!isxdigit((*src)[0]) || !isxdigit((*src)[1])) {
1838 		return -1;
1839 	}
1840 	if (sscanf(*src, "%2x", &v) != 1) {
1841 		return -1;
1842 	}
1843 	(*src) += 2;
1844 	*retbyte = (byte) (v & 0xFF);
1845 	return 0;
1846 }
1847 
1848 
1849 
1850 /*
1851  * The parameter "src" points to a character pointer which points to an
1852  * ASCII string representation of an unsigned number.  The number is
1853  * returned as an unsigned long and the character pointer is updated to
1854  * point to the first illegal character.
1855  */
1856 
1857 PRIVATE u_int32
1858 get_u_long(src)
1859 	char **src;
1860 {
1861 	register u_int32 value, base;
1862 	char c;
1863 
1864 	/*
1865 	 * Collect number up to first illegal character.  Values are specified
1866 	 * as for C:  0x=hex, 0=octal, other=decimal.
1867 	 */
1868 	value = 0;
1869 	base = 10;
1870 	if (**src == '0') {
1871 		base = 8;
1872 		(*src)++;
1873 	}
1874 	if (**src == 'x' || **src == 'X') {
1875 		base = 16;
1876 		(*src)++;
1877 	}
1878 	while ((c = **src)) {
1879 		if (isdigit(c)) {
1880 			value = (value * base) + (c - '0');
1881 			(*src)++;
1882 			continue;
1883 		}
1884 		if (base == 16 && isxdigit(c)) {
1885 			value = (value << 4) + ((c & ~32) + 10 - 'A');
1886 			(*src)++;
1887 			continue;
1888 		}
1889 		break;
1890 	}
1891 	return value;
1892 }
1893 
1894 
1895 
1896 /*
1897  * Routines for deletion of data associated with the main data structure.
1898  */
1899 
1900 
1901 /*
1902  * Frees the entire host data structure given.  Does nothing if the passed
1903  * pointer is NULL.
1904  */
1905 
1906 PRIVATE void
1907 free_host(hmp)
1908 	hash_datum *hmp;
1909 {
1910 	struct host *hostptr = (struct host *) hmp;
1911 	if (hostptr == NULL)
1912 		return;
1913 	assert(hostptr->linkcount > 0);
1914 	if (--(hostptr->linkcount))
1915 		return;					/* Still has references */
1916 	del_iplist(hostptr->cookie_server);
1917 	del_iplist(hostptr->domain_server);
1918 	del_iplist(hostptr->gateway);
1919 	del_iplist(hostptr->impress_server);
1920 	del_iplist(hostptr->log_server);
1921 	del_iplist(hostptr->lpr_server);
1922 	del_iplist(hostptr->name_server);
1923 	del_iplist(hostptr->rlp_server);
1924 	del_iplist(hostptr->time_server);
1925 	del_iplist(hostptr->nis_server);
1926 	del_iplist(hostptr->ntp_server);
1927 
1928 	/*
1929 	 * XXX - Add new tags here
1930 	 * (if the value is an IP list)
1931 	 */
1932 
1933 	del_string(hostptr->hostname);
1934 	del_string(hostptr->homedir);
1935 	del_string(hostptr->bootfile);
1936 	del_string(hostptr->tftpdir);
1937 	del_string(hostptr->root_path);
1938 	del_string(hostptr->domain_name);
1939 	del_string(hostptr->dump_file);
1940 	del_string(hostptr->exten_file);
1941 	del_string(hostptr->nis_domain);
1942 
1943 #ifdef	YORK_EX_OPTION
1944 	del_string(hostptr->exec_file);
1945 #endif
1946 
1947 	/*
1948 	 * XXX - Add new tags here
1949 	 * (if it is a shared string)
1950 	 */
1951 
1952 	del_bindata(hostptr->generic);
1953 	free((char *) hostptr);
1954 }
1955 
1956 
1957 
1958 /*
1959  * Decrements the linkcount on the given IP address data structure.  If the
1960  * linkcount goes to zero, the memory associated with the data is freed.
1961  */
1962 
1963 PRIVATE void
1964 del_iplist(iplist)
1965 	struct in_addr_list *iplist;
1966 {
1967 	if (iplist) {
1968 		if (!(--(iplist->linkcount))) {
1969 			free((char *) iplist);
1970 		}
1971 	}
1972 }
1973 
1974 
1975 
1976 /*
1977  * Decrements the linkcount on a string data structure.  If the count
1978  * goes to zero, the memory associated with the string is freed.  Does
1979  * nothing if the passed pointer is NULL.
1980  */
1981 
1982 PRIVATE void
1983 del_string(stringptr)
1984 	struct shared_string *stringptr;
1985 {
1986 	if (stringptr) {
1987 		if (!(--(stringptr->linkcount))) {
1988 			free((char *) stringptr);
1989 		}
1990 	}
1991 }
1992 
1993 
1994 
1995 /*
1996  * Decrements the linkcount on a shared_bindata data structure.  If the
1997  * count goes to zero, the memory associated with the data is freed.  Does
1998  * nothing if the passed pointer is NULL.
1999  */
2000 
2001 PRIVATE void
2002 del_bindata(dataptr)
2003 	struct shared_bindata *dataptr;
2004 {
2005 	if (dataptr) {
2006 		if (!(--(dataptr->linkcount))) {
2007 			free((char *) dataptr);
2008 		}
2009 	}
2010 }
2011 
2012 
2013 
2014 
2015 /* smalloc()  --  safe malloc()
2016  *
2017  * Always returns a valid pointer (if it returns at all).  The allocated
2018  * memory is initialized to all zeros.  If malloc() returns an error, a
2019  * message is printed using the report() function and the program aborts
2020  * with a status of 1.
2021  */
2022 
2023 PRIVATE char *
2024 smalloc(nbytes)
2025 	unsigned nbytes;
2026 {
2027 	char *retvalue;
2028 
2029 	retvalue = malloc(nbytes);
2030 	if (!retvalue) {
2031 		report(LOG_ERR, "malloc() failure -- exiting");
2032 		exit(1);
2033 	}
2034 	bzero(retvalue, nbytes);
2035 	return retvalue;
2036 }
2037 
2038 
2039 /*
2040  * Compare function to determine whether two hardware addresses are
2041  * equivalent.  Returns TRUE if "host1" and "host2" are equivalent, FALSE
2042  * otherwise.
2043  *
2044  * This function is used when retrieving elements from the hardware address
2045  * hash table.
2046  */
2047 
2048 boolean
2049 hwlookcmp(d1, d2)
2050 	hash_datum *d1, *d2;
2051 {
2052 	struct host *host1 = (struct host *) d1;
2053 	struct host *host2 = (struct host *) d2;
2054 
2055 	if (host1->htype != host2->htype) {
2056 		return FALSE;
2057 	}
2058 	if (bcmp(host1->haddr, host2->haddr, haddrlength(host1->htype))) {
2059 		return FALSE;
2060 	}
2061 	return TRUE;
2062 }
2063 
2064 
2065 /*
2066  * Compare function for doing IP address hash table lookup.
2067  */
2068 
2069 boolean
2070 iplookcmp(d1, d2)
2071 	hash_datum *d1, *d2;
2072 {
2073 	struct host *host1 = (struct host *) d1;
2074 	struct host *host2 = (struct host *) d2;
2075 
2076 	return (host1->iaddr.s_addr == host2->iaddr.s_addr);
2077 }
2078 
2079 /*
2080  * Local Variables:
2081  * tab-width: 4
2082  * c-indent-level: 4
2083  * c-argdecl-indent: 4
2084  * c-continued-statement-offset: 4
2085  * c-continued-brace-offset: -4
2086  * c-label-offset: -4
2087  * c-brace-offset: 0
2088  * End:
2089  */
2090