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