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