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