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