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