/*-1* SPDX-License-Identifier: BSD-3-Clause2*3* Copyright (c) 1988, 1992 The University of Utah and the Center4* for Software Science (CSS).5* Copyright (c) 1992, 19936* The Regents of the University of California. All rights reserved.7*8* This code is derived from software contributed to Berkeley by9* the Center for Software Science of the University of Utah Computer10* Science Department. CSS requests users of this software to return11* to [email protected] any improvements that they make and grant12* CSS redistribution rights.13*14* Redistribution and use in source and binary forms, with or without15* modification, are permitted provided that the following conditions16* are met:17* 1. Redistributions of source code must retain the above copyright18* notice, this list of conditions and the following disclaimer.19* 2. Redistributions in binary form must reproduce the above copyright20* notice, this list of conditions and the following disclaimer in the21* documentation and/or other materials provided with the distribution.22* 3. Neither the name of the University nor the names of its contributors23* may be used to endorse or promote products derived from this software24* without specific prior written permission.25*26* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND27* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE28* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE29* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE30* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL31* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS32* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)33* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT34* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY35* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF36* SUCH DAMAGE.37*38* From: Utah Hdr: rbootd.c 3.1 92/07/0639* Author: Jeff Forys, University of Utah CSS40*/4142#include <sys/param.h>43#include <sys/time.h>44#include <ctype.h>45#include <err.h>46#include <errno.h>47#include <fcntl.h>48#include <signal.h>49#include <stdio.h>50#include <stdlib.h>51#include <string.h>52#include <syslog.h>53#include <unistd.h>54#include "defs.h"5556static void usage(void) __dead2;5758int59main(int argc, char *argv[])60{61int c, fd, omask, maxfds;62fd_set rset;6364/*65* Close any open file descriptors.66* Temporarily leave stdin & stdout open for `-d',67* and stderr open for any pre-syslog error messages.68*/69{70int i, nfds = getdtablesize();7172for (i = 0; i < nfds; i++)73if (i != fileno(stdin) && i != fileno(stdout) &&74i != fileno(stderr))75(void) close(i);76}7778/*79* Parse any arguments.80*/81while ((c = getopt(argc, argv, "adi:")) != -1)82switch(c) {83case 'a':84BootAny++;85break;86case 'd':87DebugFlg++;88break;89case 'i':90IntfName = optarg;91break;92default:93usage();94}95for (; optind < argc; optind++) {96if (ConfigFile == NULL)97ConfigFile = argv[optind];98else {99warnx("too many config files (`%s' ignored)",100argv[optind]);101}102}103104if (ConfigFile == NULL) /* use default config file */105ConfigFile = DfltConfig;106107if (DebugFlg) {108DbgFp = stdout; /* output to stdout */109110(void) signal(SIGUSR1, SIG_IGN); /* dont muck w/DbgFp */111(void) signal(SIGUSR2, SIG_IGN);112(void) fclose(stderr); /* finished with it */113} else {114if (daemon(0, 0))115err(1, "can't detach from terminal");116117(void) signal(SIGUSR1, DebugOn);118(void) signal(SIGUSR2, DebugOff);119}120121openlog("rbootd", LOG_PID, LOG_DAEMON);122123/*124* If no interface was specified, get one now.125*126* This is convoluted because we want to get the default interface127* name for the syslog("restarted") message. If BpfGetIntfName()128* runs into an error, it will return a syslog-able error message129* (in `errmsg') which will be displayed here.130*/131if (IntfName == NULL) {132char *errmsg;133134if ((IntfName = BpfGetIntfName(&errmsg)) == NULL) {135/* Backslash to avoid trigraph '??)'. */136syslog(LOG_NOTICE, "restarted (?\?)");137/* BpfGetIntfName() returns safe names, using %m */138syslog(LOG_ERR, "%s", errmsg);139Exit(0);140}141}142143syslog(LOG_NOTICE, "restarted (%s)", IntfName);144145(void) signal(SIGHUP, ReConfig);146(void) signal(SIGINT, Exit);147(void) signal(SIGTERM, Exit);148149/*150* Grab our host name and pid.151*/152if (gethostname(MyHost, MAXHOSTNAMELEN - 1) < 0) {153syslog(LOG_ERR, "gethostname: %m");154Exit(0);155}156MyHost[MAXHOSTNAMELEN - 1] = '\0';157158MyPid = getpid();159160/*161* Write proc's pid to a file.162*/163{164FILE *fp;165166if ((fp = fopen(PidFile, "w")) != NULL) {167(void) fprintf(fp, "%d\n", (int) MyPid);168(void) fclose(fp);169} else {170syslog(LOG_WARNING, "fopen: failed (%s)", PidFile);171}172}173174/*175* All boot files are relative to the boot directory, we might176* as well chdir() there to make life easier.177*/178if (chdir(BootDir) < 0) {179syslog(LOG_ERR, "chdir: %m (%s)", BootDir);180Exit(0);181}182183/*184* Initial configuration.185*/186omask = sigblock(sigmask(SIGHUP)); /* prevent reconfig's */187if (GetBootFiles() == 0) /* get list of boot files */188Exit(0);189if (ParseConfig() == 0) /* parse config file */190Exit(0);191192/*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*/197fd = BpfOpen();198199(void) sigsetmask(omask); /* allow reconfig's */200201/*202* Main loop: receive a packet, determine where it came from,203* and if we service this host, call routine to handle request.204*/205maxfds = fd + 1;206FD_ZERO(&rset);207FD_SET(fd, &rset);208for (;;) {209struct timeval timeout;210fd_set r;211int nsel;212213r = rset;214215if (RmpConns == NULL) { /* timeout isn't necessary */216nsel = select(maxfds, &r, NULL, NULL, NULL);217} else {218timeout.tv_sec = RMP_TIMEOUT;219timeout.tv_usec = 0;220nsel = select(maxfds, &r, NULL, NULL, &timeout);221}222223if (nsel < 0) {224if (errno == EINTR)225continue;226syslog(LOG_ERR, "select: %m");227Exit(0);228} else if (nsel == 0) { /* timeout */229DoTimeout(); /* clear stale conns */230continue;231}232233if (FD_ISSET(fd, &r)) {234RMPCONN rconn;235CLIENT *client;236int doread = 1;237238while (BpfRead(&rconn, doread)) {239doread = 0;240241if (DbgFp != NULL) /* display packet */242DispPkt(&rconn,DIR_RCVD);243244omask = sigblock(sigmask(SIGHUP));245246/*247* If we do not restrict service, set the248* client to NULL (ProcessPacket() handles249* this). Otherwise, check that we can250* service this host; if not, log a message251* and ignore the packet.252*/253if (BootAny) {254client = NULL;255} else if ((client=FindClient(&rconn))==NULL) {256syslog(LOG_INFO,257"%s: boot packet ignored",258EnetStr(&rconn));259(void) sigsetmask(omask);260continue;261}262263ProcessPacket(&rconn,client);264265(void) sigsetmask(omask);266}267}268}269}270271static void272usage(void)273{274fprintf(stderr, "usage: rbootd [-ad] [-i interface] [config_file]\n");275exit (1);276}277278/*279** DoTimeout -- Free any connections that have timed out.280**281** Parameters:282** None.283**284** Returns:285** Nothing.286**287** Side Effects:288** - Timed out connections in `RmpConns' will be freed.289*/290void291DoTimeout(void)292{293RMPCONN *rtmp;294time_t now;295296/*297* For each active connection, if RMP_TIMEOUT seconds have passed298* since the last packet was sent, delete the connection.299*/300now = time(NULL);301for (rtmp = RmpConns; rtmp != NULL; rtmp = rtmp->next)302if ((rtmp->tstamp.tv_sec + RMP_TIMEOUT) < now) {303syslog(LOG_WARNING, "%s: connection timed out (%u)",304EnetStr(rtmp), rtmp->rmp.r_type);305RemoveConn(rtmp);306}307}308309/*310** FindClient -- Find client associated with a packet.311**312** Parameters:313** rconn - the new packet.314**315** Returns:316** Pointer to client info if found, NULL otherwise.317**318** Side Effects:319** None.320**321** Warnings:322** - This routine must be called with SIGHUP blocked since323** a reconfigure can invalidate the information returned.324*/325326CLIENT *327FindClient(RMPCONN *rconn)328{329CLIENT *ctmp;330331for (ctmp = Clients; ctmp != NULL; ctmp = ctmp->next)332if (bcmp((char *)&rconn->rmp.hp_hdr.saddr[0],333(char *)&ctmp->addr[0], RMP_ADDRLEN) == 0)334break;335336return(ctmp);337}338339/*340** Exit -- Log an error message and exit.341**342** Parameters:343** sig - caught signal (or zero if not dying on a signal).344**345** Returns:346** Does not return.347**348** Side Effects:349** - This process ceases to exist.350*/351void352Exit(int sig)353{354if (sig > 0)355syslog(LOG_ERR, "going down on signal %d", sig);356else357syslog(LOG_ERR, "going down with fatal error");358BpfClose();359exit(1);360}361362/*363** ReConfig -- Get new list of boot files and reread config files.364**365** Parameters:366** None.367**368** Returns:369** Nothing.370**371** Side Effects:372** - All active connections are dropped.373** - List of boot-able files is changed.374** - List of clients is changed.375**376** Warnings:377** - This routine must be called with SIGHUP blocked.378*/379void380ReConfig(int signo __unused)381{382syslog(LOG_NOTICE, "reconfiguring boot server");383384FreeConns();385386if (GetBootFiles() == 0)387Exit(0);388389if (ParseConfig() == 0)390Exit(0);391}392393/*394** DebugOff -- Turn off debugging.395**396** Parameters:397** None.398**399** Returns:400** Nothing.401**402** Side Effects:403** - Debug file is closed.404*/405void406DebugOff(int signo __unused)407{408if (DbgFp != NULL)409(void) fclose(DbgFp);410411DbgFp = NULL;412}413414/*415** DebugOn -- Turn on debugging.416**417** Parameters:418** None.419**420** Returns:421** Nothing.422**423** Side Effects:424** - Debug file is opened/truncated if not already opened,425** otherwise do nothing.426*/427void428DebugOn(int signo __unused)429{430if (DbgFp == NULL) {431if ((DbgFp = fopen(DbgFile, "w")) == NULL)432syslog(LOG_ERR, "can't open debug file (%s)", DbgFile);433}434}435436437