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