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