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