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