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