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