1331722Seadler/* 21592Srgrimes * Copyright (c) 1988, 1992 The University of Utah and the Center 31592Srgrimes * for Software Science (CSS). 41592Srgrimes * Copyright (c) 1992, 1993 51592Srgrimes * The Regents of the University of California. All rights reserved. 61592Srgrimes * 71592Srgrimes * This code is derived from software contributed to Berkeley by 81592Srgrimes * the Center for Software Science of the University of Utah Computer 91592Srgrimes * Science Department. CSS requests users of this software to return 101592Srgrimes * to css-dist@cs.utah.edu any improvements that they make and grant 111592Srgrimes * CSS redistribution rights. 121592Srgrimes * 131592Srgrimes * Redistribution and use in source and binary forms, with or without 141592Srgrimes * modification, are permitted provided that the following conditions 151592Srgrimes * are met: 161592Srgrimes * 1. Redistributions of source code must retain the above copyright 171592Srgrimes * notice, this list of conditions and the following disclaimer. 181592Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 191592Srgrimes * notice, this list of conditions and the following disclaimer in the 201592Srgrimes * documentation and/or other materials provided with the distribution. 21262136Sbrueffer * 3. Neither the name of the University nor the names of its contributors 221592Srgrimes * may be used to endorse or promote products derived from this software 231592Srgrimes * without specific prior written permission. 241592Srgrimes * 251592Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 261592Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 271592Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 281592Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 291592Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 301592Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 311592Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 321592Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 331592Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 341592Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 351592Srgrimes * SUCH DAMAGE. 361592Srgrimes * 3727077Ssteve * from: @(#)rbootd.c 8.1 (Berkeley) 6/4/93 381592Srgrimes * 3927077Ssteve * From: Utah Hdr: rbootd.c 3.1 92/07/06 401592Srgrimes * Author: Jeff Forys, University of Utah CSS 411592Srgrimes */ 421592Srgrimes 431592Srgrimes#ifndef lint 4427077Sstevestatic const char copyright[] = 451592Srgrimes"@(#) Copyright (c) 1992, 1993\n\ 461592Srgrimes The Regents of the University of California. All rights reserved.\n"; 471592Srgrimes#endif /* not lint */ 481592Srgrimes 491592Srgrimes#ifndef lint 5031386Scharnier#if 0 5127077Sstevestatic const char sccsid[] = "@(#)rbootd.c 8.1 (Berkeley) 6/4/93"; 5231386Scharnier#endif 531592Srgrimes#endif /* not lint */ 54216583Scharnier#include <sys/cdefs.h> 55216583Scharnier__FBSDID("$FreeBSD$"); 561592Srgrimes 571592Srgrimes#include <sys/param.h> 581592Srgrimes#include <sys/time.h> 591592Srgrimes#include <ctype.h> 6027077Ssteve#include <err.h> 611592Srgrimes#include <errno.h> 621592Srgrimes#include <fcntl.h> 631592Srgrimes#include <signal.h> 641592Srgrimes#include <stdio.h> 651592Srgrimes#include <stdlib.h> 661592Srgrimes#include <string.h> 671592Srgrimes#include <syslog.h> 681592Srgrimes#include <unistd.h> 691592Srgrimes#include "defs.h" 701592Srgrimes 7190377Simpstatic void usage(void); 721592Srgrimes 731592Srgrimesint 7490377Simpmain(int argc, char *argv[]) 751592Srgrimes{ 761592Srgrimes int c, fd, omask, maxfds; 771592Srgrimes fd_set rset; 781592Srgrimes 791592Srgrimes /* 801592Srgrimes * Close any open file descriptors. 811592Srgrimes * Temporarily leave stdin & stdout open for `-d', 821592Srgrimes * and stderr open for any pre-syslog error messages. 831592Srgrimes */ 841592Srgrimes { 851592Srgrimes int i, nfds = getdtablesize(); 861592Srgrimes 871592Srgrimes for (i = 0; i < nfds; i++) 881592Srgrimes if (i != fileno(stdin) && i != fileno(stdout) && 891592Srgrimes i != fileno(stderr)) 901592Srgrimes (void) close(i); 911592Srgrimes } 921592Srgrimes 931592Srgrimes /* 941592Srgrimes * Parse any arguments. 951592Srgrimes */ 9624349Simp while ((c = getopt(argc, argv, "adi:")) != -1) 971592Srgrimes switch(c) { 981592Srgrimes case 'a': 991592Srgrimes BootAny++; 1001592Srgrimes break; 1011592Srgrimes case 'd': 1021592Srgrimes DebugFlg++; 1031592Srgrimes break; 1041592Srgrimes case 'i': 1051592Srgrimes IntfName = optarg; 1061592Srgrimes break; 10731386Scharnier default: 10831386Scharnier usage(); 1091592Srgrimes } 1101592Srgrimes for (; optind < argc; optind++) { 1111592Srgrimes if (ConfigFile == NULL) 1121592Srgrimes ConfigFile = argv[optind]; 1131592Srgrimes else { 11431386Scharnier warnx("too many config files (`%s' ignored)", 11527077Ssteve argv[optind]); 1161592Srgrimes } 1171592Srgrimes } 1181592Srgrimes 1191592Srgrimes if (ConfigFile == NULL) /* use default config file */ 1201592Srgrimes ConfigFile = DfltConfig; 1211592Srgrimes 1221592Srgrimes if (DebugFlg) { 1231592Srgrimes DbgFp = stdout; /* output to stdout */ 1241592Srgrimes 1251592Srgrimes (void) signal(SIGUSR1, SIG_IGN); /* dont muck w/DbgFp */ 1261592Srgrimes (void) signal(SIGUSR2, SIG_IGN); 12727077Ssteve (void) fclose(stderr); /* finished with it */ 1281592Srgrimes } else { 12927077Ssteve if (daemon(0, 0)) 13027077Ssteve err(1, "can't detach from terminal"); 1311592Srgrimes 1321592Srgrimes (void) signal(SIGUSR1, DebugOn); 1331592Srgrimes (void) signal(SIGUSR2, DebugOff); 1341592Srgrimes } 1351592Srgrimes 13631386Scharnier openlog("rbootd", LOG_PID, LOG_DAEMON); 1371592Srgrimes 1381592Srgrimes /* 1391592Srgrimes * If no interface was specified, get one now. 1401592Srgrimes * 1411592Srgrimes * This is convoluted because we want to get the default interface 1421592Srgrimes * name for the syslog("restarted") message. If BpfGetIntfName() 1431592Srgrimes * runs into an error, it will return a syslog-able error message 1441592Srgrimes * (in `errmsg') which will be displayed here. 1451592Srgrimes */ 1461592Srgrimes if (IntfName == NULL) { 1471592Srgrimes char *errmsg; 1481592Srgrimes 1491592Srgrimes if ((IntfName = BpfGetIntfName(&errmsg)) == NULL) { 150134102Smaxim /* Backslash to avoid trigraph '??)'. */ 151134102Smaxim syslog(LOG_NOTICE, "restarted (?\?)"); 15268894Skris /* BpfGetIntfName() returns safe names, using %m */ 15368894Skris syslog(LOG_ERR, "%s", errmsg); 1541592Srgrimes Exit(0); 1551592Srgrimes } 1561592Srgrimes } 1571592Srgrimes 1581592Srgrimes syslog(LOG_NOTICE, "restarted (%s)", IntfName); 1591592Srgrimes 1601592Srgrimes (void) signal(SIGHUP, ReConfig); 1611592Srgrimes (void) signal(SIGINT, Exit); 1621592Srgrimes (void) signal(SIGTERM, Exit); 1631592Srgrimes 1641592Srgrimes /* 1651592Srgrimes * Grab our host name and pid. 1661592Srgrimes */ 16745422Sbrian if (gethostname(MyHost, MAXHOSTNAMELEN - 1) < 0) { 1681592Srgrimes syslog(LOG_ERR, "gethostname: %m"); 1691592Srgrimes Exit(0); 1701592Srgrimes } 17145422Sbrian MyHost[MAXHOSTNAMELEN - 1] = '\0'; 1721592Srgrimes 1731592Srgrimes MyPid = getpid(); 1741592Srgrimes 1751592Srgrimes /* 1761592Srgrimes * Write proc's pid to a file. 1771592Srgrimes */ 1781592Srgrimes { 1791592Srgrimes FILE *fp; 1801592Srgrimes 1811592Srgrimes if ((fp = fopen(PidFile, "w")) != NULL) { 18227077Ssteve (void) fprintf(fp, "%d\n", (int) MyPid); 1831592Srgrimes (void) fclose(fp); 1841592Srgrimes } else { 1851592Srgrimes syslog(LOG_WARNING, "fopen: failed (%s)", PidFile); 1861592Srgrimes } 1871592Srgrimes } 1881592Srgrimes 1891592Srgrimes /* 1901592Srgrimes * All boot files are relative to the boot directory, we might 1911592Srgrimes * as well chdir() there to make life easier. 1921592Srgrimes */ 1931592Srgrimes if (chdir(BootDir) < 0) { 1941592Srgrimes syslog(LOG_ERR, "chdir: %m (%s)", BootDir); 1951592Srgrimes Exit(0); 1961592Srgrimes } 1971592Srgrimes 1981592Srgrimes /* 1991592Srgrimes * Initial configuration. 2001592Srgrimes */ 2011592Srgrimes omask = sigblock(sigmask(SIGHUP)); /* prevent reconfig's */ 2021592Srgrimes if (GetBootFiles() == 0) /* get list of boot files */ 2031592Srgrimes Exit(0); 2041592Srgrimes if (ParseConfig() == 0) /* parse config file */ 2051592Srgrimes Exit(0); 2061592Srgrimes 2071592Srgrimes /* 2081592Srgrimes * Open and initialize a BPF device for the appropriate interface. 2091592Srgrimes * If an error is encountered, a message is displayed and Exit() 2101592Srgrimes * is called. 2111592Srgrimes */ 2121592Srgrimes fd = BpfOpen(); 2131592Srgrimes 2141592Srgrimes (void) sigsetmask(omask); /* allow reconfig's */ 2151592Srgrimes 2161592Srgrimes /* 2171592Srgrimes * Main loop: receive a packet, determine where it came from, 2181592Srgrimes * and if we service this host, call routine to handle request. 2191592Srgrimes */ 2201592Srgrimes maxfds = fd + 1; 2211592Srgrimes FD_ZERO(&rset); 2221592Srgrimes FD_SET(fd, &rset); 2231592Srgrimes for (;;) { 2241592Srgrimes struct timeval timeout; 2251592Srgrimes fd_set r; 2261592Srgrimes int nsel; 2271592Srgrimes 2281592Srgrimes r = rset; 2291592Srgrimes 230229780Suqs if (RmpConns == NULL) { /* timeout isn't necessary */ 23127077Ssteve nsel = select(maxfds, &r, NULL, NULL, NULL); 2321592Srgrimes } else { 2331592Srgrimes timeout.tv_sec = RMP_TIMEOUT; 2341592Srgrimes timeout.tv_usec = 0; 23527077Ssteve nsel = select(maxfds, &r, NULL, NULL, &timeout); 2361592Srgrimes } 2371592Srgrimes 2381592Srgrimes if (nsel < 0) { 2391592Srgrimes if (errno == EINTR) 2401592Srgrimes continue; 2411592Srgrimes syslog(LOG_ERR, "select: %m"); 2421592Srgrimes Exit(0); 2431592Srgrimes } else if (nsel == 0) { /* timeout */ 2441592Srgrimes DoTimeout(); /* clear stale conns */ 2451592Srgrimes continue; 2461592Srgrimes } 2471592Srgrimes 2481592Srgrimes if (FD_ISSET(fd, &r)) { 2491592Srgrimes RMPCONN rconn; 2501592Srgrimes CLIENT *client, *FindClient(); 2511592Srgrimes int doread = 1; 2521592Srgrimes 2531592Srgrimes while (BpfRead(&rconn, doread)) { 2541592Srgrimes doread = 0; 2551592Srgrimes 2561592Srgrimes if (DbgFp != NULL) /* display packet */ 2571592Srgrimes DispPkt(&rconn,DIR_RCVD); 2581592Srgrimes 2591592Srgrimes omask = sigblock(sigmask(SIGHUP)); 2601592Srgrimes 2611592Srgrimes /* 2621592Srgrimes * If we do not restrict service, set the 2631592Srgrimes * client to NULL (ProcessPacket() handles 2641592Srgrimes * this). Otherwise, check that we can 2651592Srgrimes * service this host; if not, log a message 2661592Srgrimes * and ignore the packet. 2671592Srgrimes */ 2681592Srgrimes if (BootAny) { 2691592Srgrimes client = NULL; 2701592Srgrimes } else if ((client=FindClient(&rconn))==NULL) { 2711592Srgrimes syslog(LOG_INFO, 2721592Srgrimes "%s: boot packet ignored", 2731592Srgrimes EnetStr(&rconn)); 2741592Srgrimes (void) sigsetmask(omask); 2751592Srgrimes continue; 2761592Srgrimes } 2771592Srgrimes 2781592Srgrimes ProcessPacket(&rconn,client); 2791592Srgrimes 2801592Srgrimes (void) sigsetmask(omask); 2811592Srgrimes } 2821592Srgrimes } 2831592Srgrimes } 2841592Srgrimes} 2851592Srgrimes 28631386Scharnierstatic void 28790377Simpusage(void) 28831386Scharnier{ 28931386Scharnier fprintf(stderr, "usage: rbootd [-ad] [-i interface] [config_file]\n"); 29031386Scharnier exit (1); 29131386Scharnier} 29231386Scharnier 2931592Srgrimes/* 2941592Srgrimes** DoTimeout -- Free any connections that have timed out. 2951592Srgrimes** 2961592Srgrimes** Parameters: 2971592Srgrimes** None. 2981592Srgrimes** 2991592Srgrimes** Returns: 3001592Srgrimes** Nothing. 3011592Srgrimes** 3021592Srgrimes** Side Effects: 3031592Srgrimes** - Timed out connections in `RmpConns' will be freed. 3041592Srgrimes*/ 3051592Srgrimesvoid 30690377SimpDoTimeout(void) 3071592Srgrimes{ 30827079Ssteve RMPCONN *rtmp; 309239991Sed time_t now; 3101592Srgrimes 3111592Srgrimes /* 3121592Srgrimes * For each active connection, if RMP_TIMEOUT seconds have passed 3131592Srgrimes * since the last packet was sent, delete the connection. 3141592Srgrimes */ 315239991Sed now = time(NULL); 3161592Srgrimes for (rtmp = RmpConns; rtmp != NULL; rtmp = rtmp->next) 317239991Sed if ((rtmp->tstamp.tv_sec + RMP_TIMEOUT) < now) { 3181592Srgrimes syslog(LOG_WARNING, "%s: connection timed out (%u)", 3191592Srgrimes EnetStr(rtmp), rtmp->rmp.r_type); 3201592Srgrimes RemoveConn(rtmp); 3211592Srgrimes } 3221592Srgrimes} 3231592Srgrimes 3241592Srgrimes/* 3251592Srgrimes** FindClient -- Find client associated with a packet. 3261592Srgrimes** 3271592Srgrimes** Parameters: 3288870Srgrimes** rconn - the new packet. 3291592Srgrimes** 3301592Srgrimes** Returns: 3311592Srgrimes** Pointer to client info if found, NULL otherwise. 3321592Srgrimes** 3331592Srgrimes** Side Effects: 3341592Srgrimes** None. 3351592Srgrimes** 3361592Srgrimes** Warnings: 3371592Srgrimes** - This routine must be called with SIGHUP blocked since 3381592Srgrimes** a reconfigure can invalidate the information returned. 3391592Srgrimes*/ 3401592Srgrimes 3411592SrgrimesCLIENT * 34290377SimpFindClient(RMPCONN *rconn) 3431592Srgrimes{ 34427079Ssteve CLIENT *ctmp; 3451592Srgrimes 3461592Srgrimes for (ctmp = Clients; ctmp != NULL; ctmp = ctmp->next) 3471592Srgrimes if (bcmp((char *)&rconn->rmp.hp_hdr.saddr[0], 3481592Srgrimes (char *)&ctmp->addr[0], RMP_ADDRLEN) == 0) 3491592Srgrimes break; 3501592Srgrimes 3511592Srgrimes return(ctmp); 3521592Srgrimes} 3531592Srgrimes 3541592Srgrimes/* 3551592Srgrimes** Exit -- Log an error message and exit. 3561592Srgrimes** 3571592Srgrimes** Parameters: 3581592Srgrimes** sig - caught signal (or zero if not dying on a signal). 3591592Srgrimes** 3601592Srgrimes** Returns: 3611592Srgrimes** Does not return. 3621592Srgrimes** 3631592Srgrimes** Side Effects: 3641592Srgrimes** - This process ceases to exist. 3651592Srgrimes*/ 3661592Srgrimesvoid 36790377SimpExit(int sig) 3681592Srgrimes{ 3691592Srgrimes if (sig > 0) 3701592Srgrimes syslog(LOG_ERR, "going down on signal %d", sig); 3711592Srgrimes else 3721592Srgrimes syslog(LOG_ERR, "going down with fatal error"); 3731592Srgrimes BpfClose(); 3741592Srgrimes exit(1); 3751592Srgrimes} 3761592Srgrimes 3771592Srgrimes/* 3781592Srgrimes** ReConfig -- Get new list of boot files and reread config files. 3791592Srgrimes** 3801592Srgrimes** Parameters: 3811592Srgrimes** None. 3821592Srgrimes** 3831592Srgrimes** Returns: 3841592Srgrimes** Nothing. 3851592Srgrimes** 3861592Srgrimes** Side Effects: 3871592Srgrimes** - All active connections are dropped. 3881592Srgrimes** - List of boot-able files is changed. 3891592Srgrimes** - List of clients is changed. 3901592Srgrimes** 3911592Srgrimes** Warnings: 3921592Srgrimes** - This routine must be called with SIGHUP blocked. 3931592Srgrimes*/ 3941592Srgrimesvoid 395216583ScharnierReConfig(int signo __unused) 3961592Srgrimes{ 3971592Srgrimes syslog(LOG_NOTICE, "reconfiguring boot server"); 3981592Srgrimes 3991592Srgrimes FreeConns(); 4001592Srgrimes 4011592Srgrimes if (GetBootFiles() == 0) 4021592Srgrimes Exit(0); 4031592Srgrimes 4041592Srgrimes if (ParseConfig() == 0) 4051592Srgrimes Exit(0); 4061592Srgrimes} 4071592Srgrimes 4081592Srgrimes/* 4091592Srgrimes** DebugOff -- Turn off debugging. 4101592Srgrimes** 4111592Srgrimes** Parameters: 4121592Srgrimes** None. 4131592Srgrimes** 4141592Srgrimes** Returns: 4151592Srgrimes** Nothing. 4161592Srgrimes** 4171592Srgrimes** Side Effects: 4181592Srgrimes** - Debug file is closed. 4191592Srgrimes*/ 4201592Srgrimesvoid 421216583ScharnierDebugOff(int signo __unused) 4221592Srgrimes{ 4231592Srgrimes if (DbgFp != NULL) 4241592Srgrimes (void) fclose(DbgFp); 4251592Srgrimes 4261592Srgrimes DbgFp = NULL; 4271592Srgrimes} 4281592Srgrimes 4291592Srgrimes/* 4301592Srgrimes** DebugOn -- Turn on debugging. 4311592Srgrimes** 4321592Srgrimes** Parameters: 4331592Srgrimes** None. 4341592Srgrimes** 4351592Srgrimes** Returns: 4361592Srgrimes** Nothing. 4371592Srgrimes** 4381592Srgrimes** Side Effects: 4391592Srgrimes** - Debug file is opened/truncated if not already opened, 4401592Srgrimes** otherwise do nothing. 4411592Srgrimes*/ 4421592Srgrimesvoid 443216583ScharnierDebugOn(int signo __unused) 4441592Srgrimes{ 4451592Srgrimes if (DbgFp == NULL) { 4461592Srgrimes if ((DbgFp = fopen(DbgFile, "w")) == NULL) 4471592Srgrimes syslog(LOG_ERR, "can't open debug file (%s)", DbgFile); 4481592Srgrimes } 4491592Srgrimes} 450