1 /* $OpenBSD: parseconf.c,v 1.11 2013/11/28 18:26:46 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((unsigned char)*cp) || *cp == ',') \ 113 cp++; \ 114 bcp = cp; \ 115 while (*cp && *cp!=',' && !isspace((unsigned char)*cp)) \ 116 cp++; \ 117 if (*cp) \ 118 *cp++ = '\0' 119 120 /* 121 * For each line, parse it into a new CLIENT struct. 122 */ 123 while (fgets(line, C_LINELEN, fp) != NULL) { 124 linecnt++; /* line counter */ 125 126 if (*line == '\0' || *line == '#') /* ignore comment */ 127 continue; 128 129 if ((cp = strchr(line,'#')) != NULL) /* trash comments */ 130 *cp = '\0'; 131 132 cp = line; /* init `cp' */ 133 GETSTR; /* get RMP addr */ 134 if (bcp == cp) /* all delimiters */ 135 continue; 136 137 /* 138 * Get an RMP address from a string. Abort on failure. 139 */ 140 if ((addr = ParseAddr(bcp)) == NULL) { 141 syslog(LOG_ERR, 142 "ParseConfig: line %d: cant parse <%s>", 143 linecnt, bcp); 144 continue; 145 } 146 147 if ((client = NewClient(addr)) == NULL) /* alloc new client */ 148 continue; 149 150 GETSTR; /* get first file */ 151 152 /* 153 * If no boot files are spec'd, use the default list. 154 * Otherwise, validate each file (`bcp') against the 155 * list of bootable files. 156 */ 157 i = 0; 158 if (bcp == cp) { /* no files spec'd */ 159 for (; i < C_MAXFILE && BootFiles[i] != NULL; i++) 160 client->files[i] = BootFiles[i]; 161 } else { 162 do { 163 /* 164 * For each boot file spec'd, make sure it's 165 * in our list. If so, include a pointer to 166 * it in the CLIENT's list of boot files. 167 */ 168 for (j = 0; ; j++) { 169 if (j==C_MAXFILE||BootFiles[j]==NULL) { 170 syslog(LOG_ERR, 171 "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 sigprocmask(SIG_SETMASK, &omask, NULL); /* reset signal mask */ 211 return(1); /* return success */ 212 } 213 214 /* 215 ** ParseAddr -- Parse a string containing an RMP address. 216 ** 217 ** This routine is fairly liberal at parsing an RMP address. The 218 ** address must contain 6 octets consisting of between 0 and 2 hex 219 ** chars (upper/lower case) separated by colons. If two colons are 220 ** together (e.g. "::", the octet between them is recorded as being 221 ** zero. Hence, the following addrs are all valid and parse to the 222 ** same thing: 223 ** 224 ** 08:00:09:00:66:ad 8::9:0:66:AD 8::9::66:aD 225 ** 226 ** For clarity, an RMP address is really an Ethernet address, but 227 ** since the HP boot code uses IEEE 802.3, it's really an IEEE 228 ** 802.3 address. Of course, all of these are identical. 229 ** 230 ** Parameters: 231 ** str - string representation of an RMP address. 232 ** 233 ** Returns: 234 ** pointer to a static array of RMP_ADDRLEN bytes. 235 ** 236 ** Side Effects: 237 ** None. 238 ** 239 ** Warnings: 240 ** - The return value points to a static buffer; it must 241 ** be copied if it's to be saved. 242 */ 243 u_int8_t * 244 ParseAddr(char *str) 245 { 246 static u_int8_t addr[RMP_ADDRLEN]; 247 int part, subpart; 248 unsigned int i; 249 char *cp; 250 251 bzero((char *)&addr[0], RMP_ADDRLEN); /* zero static buffer */ 252 253 part = subpart = 0; 254 for (cp = str; *cp; cp++) { 255 /* 256 * A colon (`:') must be used to delimit each octet. 257 */ 258 if (*cp == ':') { 259 if (++part == RMP_ADDRLEN) /* too many parts */ 260 return(NULL); 261 subpart = 0; 262 continue; 263 } 264 265 /* 266 * Convert hex character to an integer. 267 */ 268 if (isdigit((unsigned char)*cp)) 269 i = *cp - '0'; 270 else { 271 i = (isupper((unsigned char)*cp) ? 272 tolower((unsigned char)*cp) : *cp) - 'a' + 10; 273 if (i < 10 || i > 15) /* not a hex char */ 274 return(NULL); 275 } 276 277 if (subpart++) { 278 if (subpart > 2) /* too many hex chars */ 279 return(NULL); 280 addr[part] <<= 4; 281 } 282 addr[part] |= i; 283 } 284 285 if (part != (RMP_ADDRLEN-1)) /* too few parts */ 286 return(NULL); 287 288 return(&addr[0]); 289 } 290 291 /* 292 ** GetBootFiles -- record list of files in current (boot) directory. 293 ** 294 ** Parameters: 295 ** None. 296 ** 297 ** Returns: 298 ** Number of boot files on success, 0 on failure. 299 ** 300 ** Side Effects: 301 ** Strings in `BootFiles' are freed/allocated. 302 ** 303 ** Warnings: 304 ** - After this routine is called, ParseConfig() must be 305 ** called to re-order it's list of boot file pointers. 306 */ 307 int 308 GetBootFiles(void) 309 { 310 struct stat statb; 311 struct dirent *dp; 312 DIR *dfd; 313 int i; 314 315 /* 316 * Free the current list of boot files. 317 */ 318 for (i = 0; i < C_MAXFILE && BootFiles[i] != NULL; i++) { 319 FreeStr(BootFiles[i]); 320 BootFiles[i] = NULL; 321 } 322 323 /* 324 * Open current directory to read boot file names. 325 */ 326 if ((dfd = opendir(".")) == NULL) { /* open BootDir */ 327 syslog(LOG_ERR, "GetBootFiles: can't open directory (%s)", 328 BootDir); 329 return(0); 330 } 331 332 /* 333 * Read each boot file name and allocate space for it in the 334 * list of boot files (BootFiles). All boot files read after 335 * C_MAXFILE will be ignored. 336 */ 337 i = 0; 338 for (dp = readdir(dfd); dp != NULL; dp = readdir(dfd)) { 339 if (stat(dp->d_name, &statb) < 0 || 340 (statb.st_mode & S_IFMT) != S_IFREG) 341 continue; 342 if (i == C_MAXFILE) 343 syslog(LOG_ERR, 344 "GetBootFiles: too many boot files (%s ignored)", 345 dp->d_name); 346 else if ((BootFiles[i] = NewStr(dp->d_name)) != NULL) 347 i++; 348 } 349 350 (void) closedir(dfd); /* close BootDir */ 351 352 if (i == 0) /* cant find any boot files */ 353 syslog(LOG_ERR, "GetBootFiles: no boot files (%s)", BootDir); 354 355 return(i); 356 } 357