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