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