parseconf.c revision 1592
1/*
2 * Copyright (c) 1988, 1992 The University of Utah and the Center
3 *	for Software Science (CSS).
4 * Copyright (c) 1992, 1993
5 *	The Regents of the University of California.  All rights reserved.
6 *
7 * This code is derived from software contributed to Berkeley by
8 * the Center for Software Science of the University of Utah Computer
9 * Science Department.  CSS requests users of this software to return
10 * to css-dist@cs.utah.edu any improvements that they make and grant
11 * CSS redistribution rights.
12 *
13 * Redistribution and use in source and binary forms, with or without
14 * modification, are permitted provided that the following conditions
15 * are met:
16 * 1. Redistributions of source code must retain the above copyright
17 *    notice, this list of conditions and the following disclaimer.
18 * 2. Redistributions in binary form must reproduce the above copyright
19 *    notice, this list of conditions and the following disclaimer in the
20 *    documentation and/or other materials provided with the distribution.
21 * 3. All advertising materials mentioning features or use of this software
22 *    must display the following acknowledgement:
23 *	This product includes software developed by the University of
24 *	California, Berkeley and its contributors.
25 * 4. Neither the name of the University nor the names of its contributors
26 *    may be used to endorse or promote products derived from this software
27 *    without specific prior written permission.
28 *
29 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
30 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
31 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
32 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
33 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
34 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
35 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
36 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
37 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
38 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
39 * SUCH DAMAGE.
40 *
41 *	@(#)parseconf.c	8.1 (Berkeley) 6/4/93
42 *
43 * Utah $Hdr: parseconf.c 3.1 92/07/06$
44 * Author: Jeff Forys, University of Utah CSS
45 */
46
47#ifndef lint
48static char sccsid[] = "@(#)parseconf.c	8.1 (Berkeley) 6/4/93";
49#endif /* not lint */
50
51#include <sys/param.h>
52#include <sys/stat.h>
53
54#include <ctype.h>
55#include <dirent.h>
56#include <fcntl.h>
57#include <signal.h>
58#include <stdio.h>
59#include <stdlib.h>
60#include <string.h>
61#include <syslog.h>
62#include "defs.h"
63
64/*
65**  ParseConfig -- parse the config file into linked list of clients.
66**
67**	Parameters:
68**		None.
69**
70**	Returns:
71**		1 on success, 0 otherwise.
72**
73**	Side Effects:
74**		- Linked list of clients will be (re)allocated.
75**
76**	Warnings:
77**		- GetBootFiles() must be called before this routine
78**		  to create a linked list of default boot files.
79*/
80int
81ParseConfig()
82{
83	FILE *fp;
84	CLIENT *client;
85	u_char *addr;
86	char line[C_LINELEN];
87	register char *cp, *bcp;
88	register int i, j;
89	int omask, linecnt = 0;
90
91	if (BootAny)				/* ignore config file */
92		return(1);
93
94	FreeClients();				/* delete old list of clients */
95
96	if ((fp = fopen(ConfigFile, "r")) == NULL) {
97		syslog(LOG_ERR, "ParseConfig: can't open config file (%s)",
98		       ConfigFile);
99		return(0);
100	}
101
102	/*
103	 *  We've got to block SIGHUP to prevent reconfiguration while
104	 *  dealing with the linked list of Clients.  This can be done
105	 *  when actually linking the new client into the list, but
106	 *  this could have unexpected results if the server was HUP'd
107	 *  whilst reconfiguring.  Hence, it is done here.
108	 */
109	omask = sigblock(sigmask(SIGHUP));
110
111	/*
112	 *  GETSTR positions `bcp' at the start of the current token,
113	 *  and null terminates it.  `cp' is positioned at the start
114	 *  of the next token.  spaces & commas are separators.
115	 */
116#define GETSTR	while (isspace(*cp) || *cp == ',') cp++;	\
117		bcp = cp;					\
118		while (*cp && *cp!=',' && !isspace(*cp)) cp++;	\
119		if (*cp) *cp++ = '\0'
120
121	/*
122	 *  For each line, parse it into a new CLIENT struct.
123	 */
124	while (fgets(line, C_LINELEN, fp) != NULL) {
125		linecnt++;				/* line counter */
126
127		if (*line == '\0' || *line == '#')	/* ignore comment */
128			continue;
129
130		if ((cp = index(line,'#')) != NULL)	/* trash comments */
131			*cp = '\0';
132
133		cp = line;				/* init `cp' */
134		GETSTR;					/* get RMP addr */
135		if (bcp == cp)				/* all delimiters */
136			continue;
137
138		/*
139		 *  Get an RMP address from a string.  Abort on failure.
140		 */
141		if ((addr = ParseAddr(bcp)) == NULL) {
142			syslog(LOG_ERR,
143			       "ParseConfig: line %d: cant parse <%s>",
144			       linecnt, bcp);
145			continue;
146		}
147
148		if ((client = NewClient(addr)) == NULL)	/* alloc new client */
149			continue;
150
151		GETSTR;					/* get first file */
152
153		/*
154		 *  If no boot files are spec'd, use the default list.
155		 *  Otherwise, validate each file (`bcp') against the
156		 *  list of boot-able files.
157		 */
158		i = 0;
159		if (bcp == cp)				/* no files spec'd */
160			for (; i < C_MAXFILE && BootFiles[i] != NULL; i++)
161				client->files[i] = BootFiles[i];
162		else {
163			do {
164				/*
165				 *  For each boot file spec'd, make sure it's
166				 *  in our list.  If so, include a pointer to
167				 *  it in the CLIENT's list of boot files.
168				 */
169				for (j = 0; ; j++) {
170					if (j==C_MAXFILE||BootFiles[j]==NULL) {
171						syslog(LOG_ERR, "ParseConfig: line %d: no boot file (%s)",
172						       linecnt, bcp);
173						break;
174					}
175					if (STREQN(BootFiles[j], bcp)) {
176						if (i < C_MAXFILE)
177							client->files[i++] =
178							    BootFiles[j];
179						else
180							syslog(LOG_ERR, "ParseConfig: line %d: too many boot files (%s)",
181							       linecnt, bcp);
182						break;
183					}
184				}
185				GETSTR;			/* get next file */
186			} while (bcp != cp);
187
188			/*
189			 *  Restricted list of boot files were spec'd,
190			 *  however, none of them were found.  Since we
191			 *  apparently cant let them boot "just anything",
192			 *  the entire record is invalidated.
193			 */
194			if (i == 0) {
195				FreeClient(client);
196				continue;
197			}
198		}
199
200		/*
201		 *  Link this client into the linked list of clients.
202		 *  SIGHUP has already been blocked.
203		 */
204		if (Clients)
205			client->next = Clients;
206		Clients = client;
207	}
208
209	(void) fclose(fp);				/* close config file */
210
211	(void) sigsetmask(omask);			/* reset signal mask */
212
213	return(1);					/* return success */
214}
215
216/*
217**  ParseAddr -- Parse a string containing an RMP address.
218**
219**	This routine is fairly liberal at parsing an RMP address.  The
220**	address must contain 6 octets consisting of between 0 and 2 hex
221**	chars (upper/lower case) separated by colons.  If two colons are
222**	together (e.g. "::", the octet between them is recorded as being
223**	zero.  Hence, the following addrs are all valid and parse to the
224**	same thing:
225**
226**		08:00:09:00:66:ad	8::9:0:66:AD	8::9::66:aD
227**
228**	For clarity, an RMP address is really an Ethernet address, but
229**	since the HP boot code uses IEEE 802.3, it's really an IEEE
230**	802.3 address.  Of course, all of these are identical.
231**
232**	Parameters:
233**		str - string representation of an RMP address.
234**
235**	Returns:
236**		pointer to a static array of RMP_ADDRLEN bytes.
237**
238**	Side Effects:
239**		None.
240**
241**	Warnings:
242**		- The return value points to a static buffer; it must
243**		  be copied if it's to be saved.
244**		- For speed, we assume a u_char consists of 8 bits.
245*/
246u_char *
247ParseAddr(str)
248	char *str;
249{
250	static u_char addr[RMP_ADDRLEN];
251	register char *cp;
252	register unsigned i;
253	register int part, subpart;
254
255	bzero((char *)&addr[0], RMP_ADDRLEN);	/* zero static buffer */
256
257	part = subpart = 0;
258	for (cp = str; *cp; cp++) {
259		/*
260		 *  A colon (`:') must be used to delimit each octet.
261		 */
262		if (*cp == ':') {
263			if (++part == RMP_ADDRLEN)	/* too many parts */
264				return(NULL);
265			subpart = 0;
266			continue;
267		}
268
269		/*
270		 *  Convert hex character to an integer.
271		 */
272		if (isdigit(*cp))
273			i = *cp - '0';
274		else {
275			i = (isupper(*cp)? tolower(*cp): *cp) - 'a' + 10;
276			if (i < 10 || i > 15)		/* not a hex char */
277				return(NULL);
278		}
279
280		if (subpart++) {
281			if (subpart > 2)		/* too many hex chars */
282				return(NULL);
283			addr[part] <<= 4;
284		}
285		addr[part] |= i;
286	}
287
288	if (part != (RMP_ADDRLEN-1))			/* too few parts */
289		return(NULL);
290
291	return(&addr[0]);
292}
293
294/*
295**  GetBootFiles -- record list of files in current (boot) directory.
296**
297**	Parameters:
298**		None.
299**
300**	Returns:
301**		Number of boot files on success, 0 on failure.
302**
303**	Side Effects:
304**		Strings in `BootFiles' are freed/allocated.
305**
306**	Warnings:
307**		- After this routine is called, ParseConfig() must be
308**		  called to re-order it's list of boot file pointers.
309*/
310int
311GetBootFiles()
312{
313	DIR *dfd;
314	struct stat statb;
315	register struct dirent *dp;
316	register int i;
317
318	/*
319	 *  Free the current list of boot files.
320	 */
321	for (i = 0; i < C_MAXFILE && BootFiles[i] != NULL; i++) {
322		FreeStr(BootFiles[i]);
323		BootFiles[i] = NULL;
324	}
325
326	/*
327	 *  Open current directory to read boot file names.
328	 */
329	if ((dfd = opendir(".")) == NULL) {	/* open BootDir */
330		syslog(LOG_ERR, "GetBootFiles: can't open directory (%s)\n",
331		       BootDir);
332		return(0);
333	}
334
335	/*
336	 *  Read each boot file name and allocate space for it in the
337	 *  list of boot files (BootFiles).  All boot files read after
338	 *  C_MAXFILE will be ignored.
339	 */
340	i = 0;
341	for (dp = readdir(dfd); dp != NULL; dp = readdir(dfd)) {
342		if (stat(dp->d_name, &statb) < 0 ||
343		    (statb.st_mode & S_IFMT) != S_IFREG)
344			continue;
345		if (i == C_MAXFILE)
346			syslog(LOG_ERR,
347			       "GetBootFiles: too many boot files (%s ignored)",
348			       dp->d_name);
349		else if ((BootFiles[i] = NewStr(dp->d_name)) != NULL)
350			i++;
351	}
352
353	(void) closedir(dfd);			/* close BootDir */
354
355	if (i == 0)				/* cant find any boot files */
356		syslog(LOG_ERR, "GetBootFiles: no boot files (%s)\n", BootDir);
357
358	return(i);
359}
360