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