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