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