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