11592Srgrimes/*
21592Srgrimes * Copyright (c) 1988, 1992 The University of Utah and the Center
31592Srgrimes *	for Software Science (CSS).
41592Srgrimes * Copyright (c) 1992, 1993
51592Srgrimes *	The Regents of the University of California.  All rights reserved.
61592Srgrimes *
71592Srgrimes * This code is derived from software contributed to Berkeley by
81592Srgrimes * the Center for Software Science of the University of Utah Computer
91592Srgrimes * Science Department.  CSS requests users of this software to return
101592Srgrimes * to css-dist@cs.utah.edu any improvements that they make and grant
111592Srgrimes * CSS redistribution rights.
121592Srgrimes *
131592Srgrimes * Redistribution and use in source and binary forms, with or without
141592Srgrimes * modification, are permitted provided that the following conditions
151592Srgrimes * are met:
161592Srgrimes * 1. Redistributions of source code must retain the above copyright
171592Srgrimes *    notice, this list of conditions and the following disclaimer.
181592Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
191592Srgrimes *    notice, this list of conditions and the following disclaimer in the
201592Srgrimes *    documentation and/or other materials provided with the distribution.
21262435Sbrueffer * 3. Neither the name of the University nor the names of its contributors
221592Srgrimes *    may be used to endorse or promote products derived from this software
231592Srgrimes *    without specific prior written permission.
241592Srgrimes *
251592Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
261592Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
271592Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
281592Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
291592Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
301592Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
311592Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
321592Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
331592Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
341592Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
351592Srgrimes * SUCH DAMAGE.
361592Srgrimes *
3727077Ssteve *	from: @(#)parseconf.c	8.1 (Berkeley) 6/4/93
381592Srgrimes *
3927077Ssteve * From: Utah Hdr: parseconf.c 3.1 92/07/06
401592Srgrimes * Author: Jeff Forys, University of Utah CSS
411592Srgrimes */
421592Srgrimes
431592Srgrimes#ifndef lint
4431386Scharnier#if 0
4527077Sstevestatic const char sccsid[] = "@(#)parseconf.c	8.1 (Berkeley) 6/4/93";
4631386Scharnier#endif
4731386Scharnierstatic const char rcsid[] =
4850476Speter  "$FreeBSD$";
491592Srgrimes#endif /* not lint */
501592Srgrimes
511592Srgrimes#include <sys/param.h>
521592Srgrimes#include <sys/stat.h>
5366907Swollman#include <sys/time.h>
541592Srgrimes
551592Srgrimes#include <ctype.h>
561592Srgrimes#include <dirent.h>
571592Srgrimes#include <fcntl.h>
581592Srgrimes#include <signal.h>
591592Srgrimes#include <stdio.h>
601592Srgrimes#include <stdlib.h>
611592Srgrimes#include <string.h>
621592Srgrimes#include <syslog.h>
631592Srgrimes#include "defs.h"
641592Srgrimes
651592Srgrimes/*
661592Srgrimes**  ParseConfig -- parse the config file into linked list of clients.
671592Srgrimes**
681592Srgrimes**	Parameters:
691592Srgrimes**		None.
701592Srgrimes**
711592Srgrimes**	Returns:
721592Srgrimes**		1 on success, 0 otherwise.
731592Srgrimes**
741592Srgrimes**	Side Effects:
751592Srgrimes**		- Linked list of clients will be (re)allocated.
761592Srgrimes**
771592Srgrimes**	Warnings:
781592Srgrimes**		- GetBootFiles() must be called before this routine
791592Srgrimes**		  to create a linked list of default boot files.
801592Srgrimes*/
811592Srgrimesint
8290377SimpParseConfig(void)
831592Srgrimes{
841592Srgrimes	FILE *fp;
851592Srgrimes	CLIENT *client;
8627077Ssteve	u_int8_t *addr;
871592Srgrimes	char line[C_LINELEN];
8827079Ssteve	char *cp, *bcp;
8927079Ssteve	int i, j;
901592Srgrimes	int omask, linecnt = 0;
911592Srgrimes
921592Srgrimes	if (BootAny)				/* ignore config file */
931592Srgrimes		return(1);
941592Srgrimes
951592Srgrimes	FreeClients();				/* delete old list of clients */
961592Srgrimes
971592Srgrimes	if ((fp = fopen(ConfigFile, "r")) == NULL) {
981592Srgrimes		syslog(LOG_ERR, "ParseConfig: can't open config file (%s)",
991592Srgrimes		       ConfigFile);
1001592Srgrimes		return(0);
1011592Srgrimes	}
1021592Srgrimes
1031592Srgrimes	/*
1041592Srgrimes	 *  We've got to block SIGHUP to prevent reconfiguration while
1051592Srgrimes	 *  dealing with the linked list of Clients.  This can be done
1061592Srgrimes	 *  when actually linking the new client into the list, but
1071592Srgrimes	 *  this could have unexpected results if the server was HUP'd
1081592Srgrimes	 *  whilst reconfiguring.  Hence, it is done here.
1091592Srgrimes	 */
1101592Srgrimes	omask = sigblock(sigmask(SIGHUP));
1111592Srgrimes
1121592Srgrimes	/*
1131592Srgrimes	 *  GETSTR positions `bcp' at the start of the current token,
1141592Srgrimes	 *  and null terminates it.  `cp' is positioned at the start
1151592Srgrimes	 *  of the next token.  spaces & commas are separators.
1161592Srgrimes	 */
1171592Srgrimes#define GETSTR	while (isspace(*cp) || *cp == ',') cp++;	\
1181592Srgrimes		bcp = cp;					\
1191592Srgrimes		while (*cp && *cp!=',' && !isspace(*cp)) cp++;	\
1201592Srgrimes		if (*cp) *cp++ = '\0'
1211592Srgrimes
1221592Srgrimes	/*
1231592Srgrimes	 *  For each line, parse it into a new CLIENT struct.
1241592Srgrimes	 */
1251592Srgrimes	while (fgets(line, C_LINELEN, fp) != NULL) {
1261592Srgrimes		linecnt++;				/* line counter */
1271592Srgrimes
1281592Srgrimes		if (*line == '\0' || *line == '#')	/* ignore comment */
1291592Srgrimes			continue;
1301592Srgrimes
13127079Ssteve		if ((cp = strchr(line,'#')) != NULL)	/* trash comments */
1321592Srgrimes			*cp = '\0';
1331592Srgrimes
1341592Srgrimes		cp = line;				/* init `cp' */
1351592Srgrimes		GETSTR;					/* get RMP addr */
1361592Srgrimes		if (bcp == cp)				/* all delimiters */
1371592Srgrimes			continue;
1381592Srgrimes
1391592Srgrimes		/*
1401592Srgrimes		 *  Get an RMP address from a string.  Abort on failure.
1411592Srgrimes		 */
1421592Srgrimes		if ((addr = ParseAddr(bcp)) == NULL) {
1431592Srgrimes			syslog(LOG_ERR,
144229780Suqs			       "ParseConfig: line %d: can't parse <%s>",
1451592Srgrimes			       linecnt, bcp);
1461592Srgrimes			continue;
1471592Srgrimes		}
1481592Srgrimes
1491592Srgrimes		if ((client = NewClient(addr)) == NULL)	/* alloc new client */
1501592Srgrimes			continue;
1511592Srgrimes
1521592Srgrimes		GETSTR;					/* get first file */
1531592Srgrimes
1541592Srgrimes		/*
1551592Srgrimes		 *  If no boot files are spec'd, use the default list.
1561592Srgrimes		 *  Otherwise, validate each file (`bcp') against the
1571592Srgrimes		 *  list of boot-able files.
1581592Srgrimes		 */
1591592Srgrimes		i = 0;
1601592Srgrimes		if (bcp == cp)				/* no files spec'd */
1611592Srgrimes			for (; i < C_MAXFILE && BootFiles[i] != NULL; i++)
1621592Srgrimes				client->files[i] = BootFiles[i];
1631592Srgrimes		else {
1641592Srgrimes			do {
1651592Srgrimes				/*
1661592Srgrimes				 *  For each boot file spec'd, make sure it's
1671592Srgrimes				 *  in our list.  If so, include a pointer to
1681592Srgrimes				 *  it in the CLIENT's list of boot files.
1691592Srgrimes				 */
1701592Srgrimes				for (j = 0; ; j++) {
1711592Srgrimes					if (j==C_MAXFILE||BootFiles[j]==NULL) {
1721592Srgrimes						syslog(LOG_ERR, "ParseConfig: line %d: no boot file (%s)",
1731592Srgrimes						       linecnt, bcp);
1741592Srgrimes						break;
1751592Srgrimes					}
1761592Srgrimes					if (STREQN(BootFiles[j], bcp)) {
1771592Srgrimes						if (i < C_MAXFILE)
1781592Srgrimes							client->files[i++] =
1791592Srgrimes							    BootFiles[j];
1801592Srgrimes						else
1811592Srgrimes							syslog(LOG_ERR, "ParseConfig: line %d: too many boot files (%s)",
1821592Srgrimes							       linecnt, bcp);
1831592Srgrimes						break;
1841592Srgrimes					}
1851592Srgrimes				}
1861592Srgrimes				GETSTR;			/* get next file */
1871592Srgrimes			} while (bcp != cp);
1881592Srgrimes
1891592Srgrimes			/*
1901592Srgrimes			 *  Restricted list of boot files were spec'd,
1911592Srgrimes			 *  however, none of them were found.  Since we
192229780Suqs			 *  apparently can't let them boot "just anything",
1931592Srgrimes			 *  the entire record is invalidated.
1941592Srgrimes			 */
1951592Srgrimes			if (i == 0) {
1968870Srgrimes				FreeClient(client);
1971592Srgrimes				continue;
1981592Srgrimes			}
1991592Srgrimes		}
2001592Srgrimes
2011592Srgrimes		/*
2021592Srgrimes		 *  Link this client into the linked list of clients.
2031592Srgrimes		 *  SIGHUP has already been blocked.
2041592Srgrimes		 */
2051592Srgrimes		if (Clients)
2061592Srgrimes			client->next = Clients;
2071592Srgrimes		Clients = client;
2081592Srgrimes	}
2091592Srgrimes
2101592Srgrimes	(void) fclose(fp);				/* close config file */
2111592Srgrimes
2121592Srgrimes	(void) sigsetmask(omask);			/* reset signal mask */
2131592Srgrimes
2141592Srgrimes	return(1);					/* return success */
2151592Srgrimes}
2161592Srgrimes
2171592Srgrimes/*
2181592Srgrimes**  ParseAddr -- Parse a string containing an RMP address.
2191592Srgrimes**
2201592Srgrimes**	This routine is fairly liberal at parsing an RMP address.  The
2211592Srgrimes**	address must contain 6 octets consisting of between 0 and 2 hex
2221592Srgrimes**	chars (upper/lower case) separated by colons.  If two colons are
2231592Srgrimes**	together (e.g. "::", the octet between them is recorded as being
2241592Srgrimes**	zero.  Hence, the following addrs are all valid and parse to the
2251592Srgrimes**	same thing:
2261592Srgrimes**
2271592Srgrimes**		08:00:09:00:66:ad	8::9:0:66:AD	8::9::66:aD
2281592Srgrimes**
2291592Srgrimes**	For clarity, an RMP address is really an Ethernet address, but
2301592Srgrimes**	since the HP boot code uses IEEE 802.3, it's really an IEEE
2311592Srgrimes**	802.3 address.  Of course, all of these are identical.
2321592Srgrimes**
2331592Srgrimes**	Parameters:
2341592Srgrimes**		str - string representation of an RMP address.
2351592Srgrimes**
2361592Srgrimes**	Returns:
2371592Srgrimes**		pointer to a static array of RMP_ADDRLEN bytes.
2381592Srgrimes**
2391592Srgrimes**	Side Effects:
2401592Srgrimes**		None.
2411592Srgrimes**
2421592Srgrimes**	Warnings:
2431592Srgrimes**		- The return value points to a static buffer; it must
2441592Srgrimes**		  be copied if it's to be saved.
2451592Srgrimes*/
24627077Ssteveu_int8_t *
24790377SimpParseAddr(char *str)
2481592Srgrimes{
24927077Ssteve	static u_int8_t addr[RMP_ADDRLEN];
25027079Ssteve	char *cp;
25127079Ssteve	unsigned i;
25227079Ssteve	int part, subpart;
2531592Srgrimes
25427079Ssteve	memset((char *)&addr[0], 0, RMP_ADDRLEN);	/* zero static buffer */
2551592Srgrimes
2561592Srgrimes	part = subpart = 0;
2571592Srgrimes	for (cp = str; *cp; cp++) {
2581592Srgrimes		/*
2591592Srgrimes		 *  A colon (`:') must be used to delimit each octet.
2601592Srgrimes		 */
2611592Srgrimes		if (*cp == ':') {
2621592Srgrimes			if (++part == RMP_ADDRLEN)	/* too many parts */
2631592Srgrimes				return(NULL);
2641592Srgrimes			subpart = 0;
2651592Srgrimes			continue;
2661592Srgrimes		}
2671592Srgrimes
2681592Srgrimes		/*
2691592Srgrimes		 *  Convert hex character to an integer.
2701592Srgrimes		 */
2711592Srgrimes		if (isdigit(*cp))
2721592Srgrimes			i = *cp - '0';
2731592Srgrimes		else {
2741592Srgrimes			i = (isupper(*cp)? tolower(*cp): *cp) - 'a' + 10;
2751592Srgrimes			if (i < 10 || i > 15)		/* not a hex char */
2761592Srgrimes				return(NULL);
2771592Srgrimes		}
2781592Srgrimes
2791592Srgrimes		if (subpart++) {
2801592Srgrimes			if (subpart > 2)		/* too many hex chars */
2811592Srgrimes				return(NULL);
2821592Srgrimes			addr[part] <<= 4;
2831592Srgrimes		}
2841592Srgrimes		addr[part] |= i;
2851592Srgrimes	}
2861592Srgrimes
2871592Srgrimes	if (part != (RMP_ADDRLEN-1))			/* too few parts */
2881592Srgrimes		return(NULL);
2891592Srgrimes
2901592Srgrimes	return(&addr[0]);
2911592Srgrimes}
2921592Srgrimes
2931592Srgrimes/*
2941592Srgrimes**  GetBootFiles -- record list of files in current (boot) directory.
2951592Srgrimes**
2961592Srgrimes**	Parameters:
2971592Srgrimes**		None.
2981592Srgrimes**
2991592Srgrimes**	Returns:
3001592Srgrimes**		Number of boot files on success, 0 on failure.
3011592Srgrimes**
3021592Srgrimes**	Side Effects:
3031592Srgrimes**		Strings in `BootFiles' are freed/allocated.
3041592Srgrimes**
3051592Srgrimes**	Warnings:
3061592Srgrimes**		- After this routine is called, ParseConfig() must be
3071592Srgrimes**		  called to re-order it's list of boot file pointers.
3081592Srgrimes*/
3091592Srgrimesint
31090377SimpGetBootFiles(void)
3111592Srgrimes{
3121592Srgrimes	DIR *dfd;
3131592Srgrimes	struct stat statb;
31427079Ssteve	struct dirent *dp;
31527079Ssteve	int i;
3161592Srgrimes
3171592Srgrimes	/*
3181592Srgrimes	 *  Free the current list of boot files.
3191592Srgrimes	 */
3201592Srgrimes	for (i = 0; i < C_MAXFILE && BootFiles[i] != NULL; i++) {
3211592Srgrimes		FreeStr(BootFiles[i]);
3221592Srgrimes		BootFiles[i] = NULL;
3231592Srgrimes	}
3241592Srgrimes
3251592Srgrimes	/*
3261592Srgrimes	 *  Open current directory to read boot file names.
3271592Srgrimes	 */
3281592Srgrimes	if ((dfd = opendir(".")) == NULL) {	/* open BootDir */
3291592Srgrimes		syslog(LOG_ERR, "GetBootFiles: can't open directory (%s)\n",
3301592Srgrimes		       BootDir);
3311592Srgrimes		return(0);
3321592Srgrimes	}
3331592Srgrimes
3341592Srgrimes	/*
3351592Srgrimes	 *  Read each boot file name and allocate space for it in the
3361592Srgrimes	 *  list of boot files (BootFiles).  All boot files read after
3371592Srgrimes	 *  C_MAXFILE will be ignored.
3381592Srgrimes	 */
3391592Srgrimes	i = 0;
3401592Srgrimes	for (dp = readdir(dfd); dp != NULL; dp = readdir(dfd)) {
3411592Srgrimes		if (stat(dp->d_name, &statb) < 0 ||
3421592Srgrimes		    (statb.st_mode & S_IFMT) != S_IFREG)
3431592Srgrimes			continue;
3441592Srgrimes		if (i == C_MAXFILE)
3451592Srgrimes			syslog(LOG_ERR,
3461592Srgrimes			       "GetBootFiles: too many boot files (%s ignored)",
3471592Srgrimes			       dp->d_name);
3481592Srgrimes		else if ((BootFiles[i] = NewStr(dp->d_name)) != NULL)
3491592Srgrimes			i++;
3501592Srgrimes	}
3511592Srgrimes
3521592Srgrimes	(void) closedir(dfd);			/* close BootDir */
3531592Srgrimes
354229780Suqs	if (i == 0)				/* can't find any boot files */
3551592Srgrimes		syslog(LOG_ERR, "GetBootFiles: no boot files (%s)\n", BootDir);
3561592Srgrimes
3571592Srgrimes	return(i);
3581592Srgrimes}
359