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