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