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