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