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