/*-1* SPDX-License-Identifier: BSD-3-Clause2*3* Copyright (c) 1988, 1992 The University of Utah and the Center4* for Software Science (CSS).5* Copyright (c) 1992, 19936* The Regents of the University of California. All rights reserved.7*8* This code is derived from software contributed to Berkeley by9* the Center for Software Science of the University of Utah Computer10* Science Department. CSS requests users of this software to return11* to [email protected] any improvements that they make and grant12* CSS redistribution rights.13*14* Redistribution and use in source and binary forms, with or without15* modification, are permitted provided that the following conditions16* are met:17* 1. Redistributions of source code must retain the above copyright18* notice, this list of conditions and the following disclaimer.19* 2. Redistributions in binary form must reproduce the above copyright20* notice, this list of conditions and the following disclaimer in the21* documentation and/or other materials provided with the distribution.22* 3. Neither the name of the University nor the names of its contributors23* may be used to endorse or promote products derived from this software24* without specific prior written permission.25*26* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND27* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE28* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE29* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE30* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL31* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS32* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)33* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT34* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY35* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF36* SUCH DAMAGE.37*38* From: Utah Hdr: parseconf.c 3.1 92/07/0639* Author: Jeff Forys, University of Utah CSS40*/4142#include <sys/param.h>43#include <sys/stat.h>44#include <sys/time.h>4546#include <ctype.h>47#include <dirent.h>48#include <fcntl.h>49#include <signal.h>50#include <stdio.h>51#include <stdlib.h>52#include <string.h>53#include <syslog.h>54#include "defs.h"5556/*57** ParseConfig -- parse the config file into linked list of clients.58**59** Parameters:60** None.61**62** Returns:63** 1 on success, 0 otherwise.64**65** Side Effects:66** - Linked list of clients will be (re)allocated.67**68** Warnings:69** - GetBootFiles() must be called before this routine70** to create a linked list of default boot files.71*/72int73ParseConfig(void)74{75FILE *fp;76CLIENT *client;77u_int8_t *addr;78char line[C_LINELEN];79char *cp, *bcp;80int i, j;81int omask, linecnt = 0;8283if (BootAny) /* ignore config file */84return(1);8586FreeClients(); /* delete old list of clients */8788if ((fp = fopen(ConfigFile, "r")) == NULL) {89syslog(LOG_ERR, "ParseConfig: can't open config file (%s)",90ConfigFile);91return(0);92}9394/*95* We've got to block SIGHUP to prevent reconfiguration while96* dealing with the linked list of Clients. This can be done97* when actually linking the new client into the list, but98* this could have unexpected results if the server was HUP'd99* whilst reconfiguring. Hence, it is done here.100*/101omask = sigblock(sigmask(SIGHUP));102103/*104* GETSTR positions `bcp' at the start of the current token,105* and null terminates it. `cp' is positioned at the start106* of the next token. spaces & commas are separators.107*/108#define GETSTR while (isspace(*cp) || *cp == ',') cp++; \109bcp = cp; \110while (*cp && *cp!=',' && !isspace(*cp)) cp++; \111if (*cp) *cp++ = '\0'112113/*114* For each line, parse it into a new CLIENT struct.115*/116while (fgets(line, C_LINELEN, fp) != NULL) {117linecnt++; /* line counter */118119if (*line == '\0' || *line == '#') /* ignore comment */120continue;121122if ((cp = strchr(line,'#')) != NULL) /* trash comments */123*cp = '\0';124125cp = line; /* init `cp' */126GETSTR; /* get RMP addr */127if (bcp == cp) /* all delimiters */128continue;129130/*131* Get an RMP address from a string. Abort on failure.132*/133if ((addr = ParseAddr(bcp)) == NULL) {134syslog(LOG_ERR,135"ParseConfig: line %d: can't parse <%s>",136linecnt, bcp);137continue;138}139140if ((client = NewClient(addr)) == NULL) /* alloc new client */141continue;142143GETSTR; /* get first file */144145/*146* If no boot files are spec'd, use the default list.147* Otherwise, validate each file (`bcp') against the148* list of boot-able files.149*/150i = 0;151if (bcp == cp) /* no files spec'd */152for (; i < C_MAXFILE && BootFiles[i] != NULL; i++)153client->files[i] = BootFiles[i];154else {155do {156/*157* For each boot file spec'd, make sure it's158* in our list. If so, include a pointer to159* it in the CLIENT's list of boot files.160*/161for (j = 0; ; j++) {162if (j==C_MAXFILE||BootFiles[j]==NULL) {163syslog(LOG_ERR, "ParseConfig: line %d: no boot file (%s)",164linecnt, bcp);165break;166}167if (STREQN(BootFiles[j], bcp)) {168if (i < C_MAXFILE)169client->files[i++] =170BootFiles[j];171else172syslog(LOG_ERR, "ParseConfig: line %d: too many boot files (%s)",173linecnt, bcp);174break;175}176}177GETSTR; /* get next file */178} while (bcp != cp);179180/*181* Restricted list of boot files were spec'd,182* however, none of them were found. Since we183* apparently can't let them boot "just anything",184* the entire record is invalidated.185*/186if (i == 0) {187FreeClient(client);188continue;189}190}191192/*193* Link this client into the linked list of clients.194* SIGHUP has already been blocked.195*/196if (Clients)197client->next = Clients;198Clients = client;199}200201(void) fclose(fp); /* close config file */202203(void) sigsetmask(omask); /* reset signal mask */204205return(1); /* return success */206}207208/*209** ParseAddr -- Parse a string containing an RMP address.210**211** This routine is fairly liberal at parsing an RMP address. The212** address must contain 6 octets consisting of between 0 and 2 hex213** chars (upper/lower case) separated by colons. If two colons are214** together (e.g. "::", the octet between them is recorded as being215** zero. Hence, the following addrs are all valid and parse to the216** same thing:217**218** 08:00:09:00:66:ad 8::9:0:66:AD 8::9::66:aD219**220** For clarity, an RMP address is really an Ethernet address, but221** since the HP boot code uses IEEE 802.3, it's really an IEEE222** 802.3 address. Of course, all of these are identical.223**224** Parameters:225** str - string representation of an RMP address.226**227** Returns:228** pointer to a static array of RMP_ADDRLEN bytes.229**230** Side Effects:231** None.232**233** Warnings:234** - The return value points to a static buffer; it must235** be copied if it's to be saved.236*/237u_int8_t *238ParseAddr(char *str)239{240static u_int8_t addr[RMP_ADDRLEN];241char *cp;242unsigned i;243int part, subpart;244245memset((char *)&addr[0], 0, RMP_ADDRLEN); /* zero static buffer */246247part = subpart = 0;248for (cp = str; *cp; cp++) {249/*250* A colon (`:') must be used to delimit each octet.251*/252if (*cp == ':') {253if (++part == RMP_ADDRLEN) /* too many parts */254return(NULL);255subpart = 0;256continue;257}258259/*260* Convert hex character to an integer.261*/262if (isdigit(*cp))263i = *cp - '0';264else {265i = (isupper(*cp)? tolower(*cp): *cp) - 'a' + 10;266if (i < 10 || i > 15) /* not a hex char */267return(NULL);268}269270if (subpart++) {271if (subpart > 2) /* too many hex chars */272return(NULL);273addr[part] <<= 4;274}275addr[part] |= i;276}277278if (part != (RMP_ADDRLEN-1)) /* too few parts */279return(NULL);280281return(&addr[0]);282}283284/*285** GetBootFiles -- record list of files in current (boot) directory.286**287** Parameters:288** None.289**290** Returns:291** Number of boot files on success, 0 on failure.292**293** Side Effects:294** Strings in `BootFiles' are freed/allocated.295**296** Warnings:297** - After this routine is called, ParseConfig() must be298** called to re-order it's list of boot file pointers.299*/300int301GetBootFiles(void)302{303DIR *dfd;304struct stat statb;305struct dirent *dp;306int i;307308/*309* Free the current list of boot files.310*/311for (i = 0; i < C_MAXFILE && BootFiles[i] != NULL; i++) {312FreeStr(BootFiles[i]);313BootFiles[i] = NULL;314}315316/*317* Open current directory to read boot file names.318*/319if ((dfd = opendir(".")) == NULL) { /* open BootDir */320syslog(LOG_ERR, "GetBootFiles: can't open directory (%s)\n",321BootDir);322return(0);323}324325/*326* Read each boot file name and allocate space for it in the327* list of boot files (BootFiles). All boot files read after328* C_MAXFILE will be ignored.329*/330i = 0;331for (dp = readdir(dfd); dp != NULL; dp = readdir(dfd)) {332if (stat(dp->d_name, &statb) < 0 ||333(statb.st_mode & S_IFMT) != S_IFREG)334continue;335if (i == C_MAXFILE)336syslog(LOG_ERR,337"GetBootFiles: too many boot files (%s ignored)",338dp->d_name);339else if ((BootFiles[i] = NewStr(dp->d_name)) != NULL)340i++;341}342343(void) closedir(dfd); /* close BootDir */344345if (i == 0) /* can't find any boot files */346syslog(LOG_ERR, "GetBootFiles: no boot files (%s)\n", BootDir);347348return(i);349}350351352