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