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