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