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