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