1 /* $OpenBSD: rbootd.c,v 1.8 2001/09/04 23:35:59 millert Exp $ */ 2 /* $NetBSD: rbootd.c,v 1.5 1995/10/06 05:12:17 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. All advertising materials mentioning features or use of this software 25 * must display the following acknowledgement: 26 * This product includes software developed by the University of 27 * California, Berkeley and its contributors. 28 * 4. Neither the name of the University nor the names of its contributors 29 * may be used to endorse or promote products derived from this software 30 * without specific prior written permission. 31 * 32 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 33 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 34 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 35 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 36 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 37 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 38 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 39 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 40 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 41 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 42 * SUCH DAMAGE. 43 * 44 * from: @(#)rbootd.c 8.1 (Berkeley) 6/4/93 45 * 46 * From: Utah Hdr: rbootd.c 3.1 92/07/06 47 * Author: Jeff Forys, University of Utah CSS 48 */ 49 50 #ifndef lint 51 static char copyright[] = 52 "@(#) Copyright (c) 1992, 1993\n\ 53 The Regents of the University of California. All rights reserved.\n"; 54 #endif /* not lint */ 55 56 #ifndef lint 57 /*static char sccsid[] = "@(#)rbootd.c 8.1 (Berkeley) 6/4/93";*/ 58 static char rcsid[] = "$OpenBSD: rbootd.c,v 1.8 2001/09/04 23:35:59 millert Exp $"; 59 #endif /* not lint */ 60 61 #include <sys/param.h> 62 #include <sys/time.h> 63 #include <ctype.h> 64 #include <err.h> 65 #include <errno.h> 66 #include <fcntl.h> 67 #include <signal.h> 68 #include <stdio.h> 69 #include <stdlib.h> 70 #include <string.h> 71 #include <syslog.h> 72 #include <unistd.h> 73 #include "defs.h" 74 75 extern char *__progname; /* from crt0.o */ 76 77 int 78 main(argc, argv) 79 int argc; 80 char *argv[]; 81 { 82 int c, fd, maxfds; 83 fd_set rset; 84 sigset_t hmask, omask; 85 86 /* 87 * Close any open file descriptors. 88 * Temporarily leave stdin & stdout open for `-d', 89 * and stderr open for any pre-syslog error messages. 90 */ 91 { 92 int i, nfds = getdtablesize(); 93 94 for (i = 0; i < nfds; i++) 95 if (i != fileno(stdin) && i != fileno(stdout) && 96 i != fileno(stderr)) 97 (void) close(i); 98 } 99 100 /* 101 * Parse any arguments. 102 */ 103 while ((c = getopt(argc, argv, "adi:")) != -1) 104 switch(c) { 105 case 'a': 106 BootAny++; 107 break; 108 case 'd': 109 DebugFlg++; 110 break; 111 case 'i': 112 IntfName = optarg; 113 break; 114 } 115 for (; optind < argc; optind++) { 116 if (ConfigFile == NULL) 117 ConfigFile = argv[optind]; 118 else { 119 warnx("too many config files (`%s' ignored)", 120 argv[optind]); 121 } 122 } 123 124 if (ConfigFile == NULL) /* use default config file */ 125 ConfigFile = DfltConfig; 126 127 if (DebugFlg) { 128 DbgFp = stdout; /* output to stdout */ 129 130 (void) signal(SIGUSR1, SIG_IGN); /* dont muck w/DbgFp */ 131 (void) signal(SIGUSR2, SIG_IGN); 132 (void) fclose(stderr); /* finished with it */ 133 } else { 134 if (daemon(0, 0)) 135 err(1, "can't detach from terminal"); 136 137 (void) signal(SIGUSR1, DebugOn); 138 (void) signal(SIGUSR2, DebugOff); 139 } 140 141 openlog(__progname, LOG_PID, LOG_DAEMON); 142 143 /* 144 * If no interface was specified, get one now. 145 * 146 * This is convoluted because we want to get the default interface 147 * name for the syslog("restarted") message. If BpfGetIntfName() 148 * runs into an error, it will return a syslog-able error message 149 * (in `errmsg') which will be displayed here. 150 */ 151 if (IntfName == NULL) { 152 char *errmsg; 153 154 if ((IntfName = BpfGetIntfName(&errmsg)) == NULL) { 155 syslog(LOG_NOTICE, "restarted (??)"); 156 /* BpfGetIntfName() returns safe names, using %m */ 157 syslog(LOG_ERR, "%s", errmsg); 158 Exit(0); 159 } 160 } 161 162 syslog(LOG_NOTICE, "restarted (%s)", IntfName); 163 164 (void) signal(SIGHUP, ReConfig); 165 (void) signal(SIGINT, Exit); 166 (void) signal(SIGTERM, Exit); 167 168 /* 169 * Grab our host name and pid. 170 */ 171 if (gethostname(MyHost, MAXHOSTNAMELEN) < 0) { 172 syslog(LOG_ERR, "gethostname: %m"); 173 Exit(0); 174 } 175 MyHost[MAXHOSTNAMELEN] = '\0'; 176 177 MyPid = getpid(); 178 179 /* 180 * Write proc's pid to a file. 181 */ 182 { 183 FILE *fp; 184 185 if ((fp = fopen(PidFile, "w")) != NULL) { 186 (void) fprintf(fp, "%d\n", (int) MyPid); 187 (void) fclose(fp); 188 } else { 189 syslog(LOG_WARNING, "fopen: failed (%s)", PidFile); 190 } 191 } 192 193 /* 194 * All boot files are relative to the boot directory, we might 195 * as well chdir() there to make life easier. 196 */ 197 if (chdir(BootDir) < 0) { 198 syslog(LOG_ERR, "chdir: %m (%s)", BootDir); 199 Exit(0); 200 } 201 202 /* 203 * Initial configuration. 204 */ 205 sigemptyset(&hmask); 206 sigaddset(&hmask, SIGHUP); 207 sigprocmask(SIG_BLOCK, &hmask, &omask); /* prevent reconfig's */ 208 if (GetBootFiles() == 0) /* get list of boot files */ 209 Exit(0); 210 if (ParseConfig() == 0) /* parse config file */ 211 Exit(0); 212 213 /* 214 * Open and initialize a BPF device for the appropriate interface. 215 * If an error is encountered, a message is displayed and Exit() 216 * is called. 217 */ 218 fd = BpfOpen(); 219 220 sigprocmask(SIG_SETMASK, &omask, NULL); /* allow reconfig's */ 221 222 /* 223 * Main loop: receive a packet, determine where it came from, 224 * and if we service this host, call routine to handle request. 225 */ 226 maxfds = fd + 1; 227 FD_ZERO(&rset); 228 FD_SET(fd, &rset); 229 for (;;) { 230 struct timeval timeout; 231 fd_set r; 232 int nsel; 233 234 r = rset; 235 236 if (RmpConns == NULL) { /* timeout isnt necessary */ 237 nsel = select(maxfds, &r, NULL, NULL, NULL); 238 } else { 239 timeout.tv_sec = RMP_TIMEOUT; 240 timeout.tv_usec = 0; 241 nsel = select(maxfds, &r, NULL, NULL, &timeout); 242 } 243 244 if (nsel < 0) { 245 if (errno == EINTR) 246 continue; 247 syslog(LOG_ERR, "select: %m"); 248 Exit(0); 249 } else if (nsel == 0) { /* timeout */ 250 DoTimeout(); /* clear stale conns */ 251 continue; 252 } 253 254 if (FD_ISSET(fd, &r)) { 255 RMPCONN rconn; 256 CLIENT *client, *FindClient(); 257 int doread = 1; 258 259 while (BpfRead(&rconn, doread)) { 260 doread = 0; 261 262 if (DbgFp != NULL) /* display packet */ 263 DispPkt(&rconn,DIR_RCVD); 264 265 sigprocmask(SIG_BLOCK, &hmask, &omask); 266 267 /* 268 * If we do not restrict service, set the 269 * client to NULL (ProcessPacket() handles 270 * this). Otherwise, check that we can 271 * service this host; if not, log a message 272 * and ignore the packet. 273 */ 274 if (BootAny) { 275 client = NULL; 276 } else if ((client=FindClient(&rconn))==NULL) { 277 syslog(LOG_INFO, 278 "%s: boot packet ignored", 279 EnetStr(&rconn)); 280 sigprocmask(SIG_SETMASK, &omask, NULL); 281 continue; 282 } 283 284 ProcessPacket(&rconn,client); 285 286 sigprocmask(SIG_SETMASK, &omask, NULL); 287 } 288 } 289 } 290 } 291 292 /* 293 ** DoTimeout -- Free any connections that have timed out. 294 ** 295 ** Parameters: 296 ** None. 297 ** 298 ** Returns: 299 ** Nothing. 300 ** 301 ** Side Effects: 302 ** - Timed out connections in `RmpConns' will be freed. 303 */ 304 void 305 DoTimeout() 306 { 307 register RMPCONN *rtmp; 308 struct timeval now; 309 310 (void) gettimeofday(&now, (struct timezone *)0); 311 312 /* 313 * For each active connection, if RMP_TIMEOUT seconds have passed 314 * since the last packet was sent, delete the connection. 315 */ 316 for (rtmp = RmpConns; rtmp != NULL; rtmp = rtmp->next) 317 if ((rtmp->tstamp.tv_sec + RMP_TIMEOUT) < now.tv_sec) { 318 syslog(LOG_WARNING, "%s: connection timed out (%u)", 319 EnetStr(rtmp), rtmp->rmp.r_type); 320 RemoveConn(rtmp); 321 } 322 } 323 324 /* 325 ** FindClient -- Find client associated with a packet. 326 ** 327 ** Parameters: 328 ** rconn - the new packet. 329 ** 330 ** Returns: 331 ** Pointer to client info if found, NULL otherwise. 332 ** 333 ** Side Effects: 334 ** None. 335 ** 336 ** Warnings: 337 ** - This routine must be called with SIGHUP blocked since 338 ** a reconfigure can invalidate the information returned. 339 */ 340 341 CLIENT * 342 FindClient(rconn) 343 register RMPCONN *rconn; 344 { 345 register CLIENT *ctmp; 346 347 for (ctmp = Clients; ctmp != NULL; ctmp = ctmp->next) 348 if (bcmp((char *)&rconn->rmp.hp_hdr.saddr[0], 349 (char *)&ctmp->addr[0], RMP_ADDRLEN) == 0) 350 break; 351 352 return(ctmp); 353 } 354 355 /* 356 ** Exit -- Log an error message and exit. 357 ** 358 ** Parameters: 359 ** sig - caught signal (or zero if not dying on a signal). 360 ** 361 ** Returns: 362 ** Does not return. 363 ** 364 ** Side Effects: 365 ** - This process ceases to exist. 366 */ 367 void 368 Exit(sig) 369 int sig; 370 { 371 /* XXX race */ 372 if (sig > 0) 373 syslog(LOG_ERR, "going down on signal %d", sig); 374 else 375 syslog(LOG_ERR, "going down with fatal error"); 376 BpfClose(); 377 exit(1); 378 } 379 380 /* 381 ** ReConfig -- Get new list of boot files and reread config files. 382 ** 383 ** Parameters: 384 ** None. 385 ** 386 ** Returns: 387 ** Nothing. 388 ** 389 ** Side Effects: 390 ** - All active connections are dropped. 391 ** - List of boot-able files is changed. 392 ** - List of clients is changed. 393 ** 394 ** Warnings: 395 ** - This routine must be called with SIGHUP blocked. 396 */ 397 void 398 ReConfig(signo) 399 int signo; 400 { 401 /* XXX race */ 402 syslog(LOG_NOTICE, "reconfiguring boot server"); 403 404 FreeConns(); 405 406 if (GetBootFiles() == 0) 407 Exit(0); 408 409 if (ParseConfig() == 0) 410 Exit(0); 411 } 412 413 /* 414 ** DebugOff -- Turn off debugging. 415 ** 416 ** Parameters: 417 ** None. 418 ** 419 ** Returns: 420 ** Nothing. 421 ** 422 ** Side Effects: 423 ** - Debug file is closed. 424 */ 425 void 426 DebugOff(signo) 427 int signo; 428 { 429 /* XXX race */ 430 431 if (DbgFp != NULL) 432 (void) fclose(DbgFp); 433 434 DbgFp = NULL; 435 } 436 437 /* 438 ** DebugOn -- Turn on debugging. 439 ** 440 ** Parameters: 441 ** None. 442 ** 443 ** Returns: 444 ** Nothing. 445 ** 446 ** Side Effects: 447 ** - Debug file is opened/truncated if not already opened, 448 ** otherwise do nothing. 449 */ 450 void 451 DebugOn(signo) 452 int signo; 453 { 454 /* XXX race */ 455 if (DbgFp == NULL) { 456 if ((DbgFp = fopen(DbgFile, "w")) == NULL) 457 syslog(LOG_ERR, "can't open debug file (%s)", DbgFile); 458 } 459 } 460