rbootd.c revision 90377
11592Srgrimes/*
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.
211592Srgrimes * 3. All advertising materials mentioning features or use of this software
221592Srgrimes *    must display the following acknowledgement:
231592Srgrimes *	This product includes software developed by the University of
241592Srgrimes *	California, Berkeley and its contributors.
251592Srgrimes * 4. Neither the name of the University nor the names of its contributors
261592Srgrimes *    may be used to endorse or promote products derived from this software
271592Srgrimes *    without specific prior written permission.
281592Srgrimes *
291592Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
301592Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
311592Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
321592Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
331592Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
341592Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
351592Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
361592Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
371592Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
381592Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
391592Srgrimes * SUCH DAMAGE.
401592Srgrimes *
4127077Ssteve *	from: @(#)rbootd.c	8.1 (Berkeley) 6/4/93
421592Srgrimes *
4327077Ssteve * From: Utah Hdr: rbootd.c 3.1 92/07/06
441592Srgrimes * Author: Jeff Forys, University of Utah CSS
451592Srgrimes */
461592Srgrimes
471592Srgrimes#ifndef lint
4827077Sstevestatic const char copyright[] =
491592Srgrimes"@(#) Copyright (c) 1992, 1993\n\
501592Srgrimes	The Regents of the University of California.  All rights reserved.\n";
511592Srgrimes#endif /* not lint */
521592Srgrimes
531592Srgrimes#ifndef lint
5431386Scharnier#if 0
5527077Sstevestatic const char sccsid[] = "@(#)rbootd.c	8.1 (Berkeley) 6/4/93";
5631386Scharnier#endif
5731386Scharnierstatic const char rcsid[] =
5850476Speter  "$FreeBSD: head/libexec/rbootd/rbootd.c 90377 2002-02-07 23:57:01Z imp $";
591592Srgrimes#endif /* not lint */
601592Srgrimes
611592Srgrimes#include <sys/param.h>
621592Srgrimes#include <sys/time.h>
631592Srgrimes#include <ctype.h>
6427077Ssteve#include <err.h>
651592Srgrimes#include <errno.h>
661592Srgrimes#include <fcntl.h>
671592Srgrimes#include <signal.h>
681592Srgrimes#include <stdio.h>
691592Srgrimes#include <stdlib.h>
701592Srgrimes#include <string.h>
711592Srgrimes#include <syslog.h>
721592Srgrimes#include <unistd.h>
731592Srgrimes#include "defs.h"
741592Srgrimes
7590377Simpstatic void usage(void);
761592Srgrimes
771592Srgrimesint
7890377Simpmain(int argc, char *argv[])
791592Srgrimes{
801592Srgrimes	int c, fd, omask, maxfds;
811592Srgrimes	fd_set rset;
821592Srgrimes
831592Srgrimes	/*
841592Srgrimes	 *  Close any open file descriptors.
851592Srgrimes	 *  Temporarily leave stdin & stdout open for `-d',
861592Srgrimes	 *  and stderr open for any pre-syslog error messages.
871592Srgrimes	 */
881592Srgrimes	{
891592Srgrimes		int i, nfds = getdtablesize();
901592Srgrimes
911592Srgrimes		for (i = 0; i < nfds; i++)
921592Srgrimes			if (i != fileno(stdin) && i != fileno(stdout) &&
931592Srgrimes			    i != fileno(stderr))
941592Srgrimes				(void) close(i);
951592Srgrimes	}
961592Srgrimes
971592Srgrimes	/*
981592Srgrimes	 *  Parse any arguments.
991592Srgrimes	 */
10024349Simp	while ((c = getopt(argc, argv, "adi:")) != -1)
1011592Srgrimes		switch(c) {
1021592Srgrimes		    case 'a':
1031592Srgrimes			BootAny++;
1041592Srgrimes			break;
1051592Srgrimes		    case 'd':
1061592Srgrimes			DebugFlg++;
1071592Srgrimes			break;
1081592Srgrimes		    case 'i':
1091592Srgrimes			IntfName = optarg;
1101592Srgrimes			break;
11131386Scharnier		    default:
11231386Scharnier			usage();
1131592Srgrimes		}
1141592Srgrimes	for (; optind < argc; optind++) {
1151592Srgrimes		if (ConfigFile == NULL)
1161592Srgrimes			ConfigFile = argv[optind];
1171592Srgrimes		else {
11831386Scharnier			warnx("too many config files (`%s' ignored)",
11927077Ssteve			    argv[optind]);
1201592Srgrimes		}
1211592Srgrimes	}
1221592Srgrimes
1231592Srgrimes	if (ConfigFile == NULL)			/* use default config file */
1241592Srgrimes		ConfigFile = DfltConfig;
1251592Srgrimes
1261592Srgrimes	if (DebugFlg) {
1271592Srgrimes		DbgFp = stdout;				/* output to stdout */
1281592Srgrimes
1291592Srgrimes		(void) signal(SIGUSR1, SIG_IGN);	/* dont muck w/DbgFp */
1301592Srgrimes		(void) signal(SIGUSR2, SIG_IGN);
13127077Ssteve		(void) fclose(stderr);			/* finished with it */
1321592Srgrimes	} else {
13327077Ssteve		if (daemon(0, 0))
13427077Ssteve			err(1, "can't detach from terminal");
1351592Srgrimes
1361592Srgrimes		(void) signal(SIGUSR1, DebugOn);
1371592Srgrimes		(void) signal(SIGUSR2, DebugOff);
1381592Srgrimes	}
1391592Srgrimes
14031386Scharnier	openlog("rbootd", LOG_PID, LOG_DAEMON);
1411592Srgrimes
1421592Srgrimes	/*
1431592Srgrimes	 *  If no interface was specified, get one now.
1441592Srgrimes	 *
1451592Srgrimes	 *  This is convoluted because we want to get the default interface
1461592Srgrimes	 *  name for the syslog("restarted") message.  If BpfGetIntfName()
1471592Srgrimes	 *  runs into an error, it will return a syslog-able error message
1481592Srgrimes	 *  (in `errmsg') which will be displayed here.
1491592Srgrimes	 */
1501592Srgrimes	if (IntfName == NULL) {
1511592Srgrimes		char *errmsg;
1521592Srgrimes
1531592Srgrimes		if ((IntfName = BpfGetIntfName(&errmsg)) == NULL) {
1541592Srgrimes			syslog(LOG_NOTICE, "restarted (??)");
15568894Skris			/* BpfGetIntfName() returns safe names, using %m */
15668894Skris			syslog(LOG_ERR, "%s", errmsg);
1571592Srgrimes			Exit(0);
1581592Srgrimes		}
1591592Srgrimes	}
1601592Srgrimes
1611592Srgrimes	syslog(LOG_NOTICE, "restarted (%s)", IntfName);
1621592Srgrimes
1631592Srgrimes	(void) signal(SIGHUP, ReConfig);
1641592Srgrimes	(void) signal(SIGINT, Exit);
1651592Srgrimes	(void) signal(SIGTERM, Exit);
1661592Srgrimes
1671592Srgrimes	/*
1681592Srgrimes	 *  Grab our host name and pid.
1691592Srgrimes	 */
17045422Sbrian	if (gethostname(MyHost, MAXHOSTNAMELEN - 1) < 0) {
1711592Srgrimes		syslog(LOG_ERR, "gethostname: %m");
1721592Srgrimes		Exit(0);
1731592Srgrimes	}
17445422Sbrian	MyHost[MAXHOSTNAMELEN - 1] = '\0';
1751592Srgrimes
1761592Srgrimes	MyPid = getpid();
1771592Srgrimes
1781592Srgrimes	/*
1791592Srgrimes	 *  Write proc's pid to a file.
1801592Srgrimes	 */
1811592Srgrimes	{
1821592Srgrimes		FILE *fp;
1831592Srgrimes
1841592Srgrimes		if ((fp = fopen(PidFile, "w")) != NULL) {
18527077Ssteve			(void) fprintf(fp, "%d\n", (int) MyPid);
1861592Srgrimes			(void) fclose(fp);
1871592Srgrimes		} else {
1881592Srgrimes			syslog(LOG_WARNING, "fopen: failed (%s)", PidFile);
1891592Srgrimes		}
1901592Srgrimes	}
1911592Srgrimes
1921592Srgrimes	/*
1931592Srgrimes	 *  All boot files are relative to the boot directory, we might
1941592Srgrimes	 *  as well chdir() there to make life easier.
1951592Srgrimes	 */
1961592Srgrimes	if (chdir(BootDir) < 0) {
1971592Srgrimes		syslog(LOG_ERR, "chdir: %m (%s)", BootDir);
1981592Srgrimes		Exit(0);
1991592Srgrimes	}
2001592Srgrimes
2011592Srgrimes	/*
2021592Srgrimes	 *  Initial configuration.
2031592Srgrimes	 */
2041592Srgrimes	omask = sigblock(sigmask(SIGHUP));	/* prevent reconfig's */
2051592Srgrimes	if (GetBootFiles() == 0)		/* get list of boot files */
2061592Srgrimes		Exit(0);
2071592Srgrimes	if (ParseConfig() == 0)			/* parse config file */
2081592Srgrimes		Exit(0);
2091592Srgrimes
2101592Srgrimes	/*
2111592Srgrimes	 *  Open and initialize a BPF device for the appropriate interface.
2121592Srgrimes	 *  If an error is encountered, a message is displayed and Exit()
2131592Srgrimes	 *  is called.
2141592Srgrimes	 */
2151592Srgrimes	fd = BpfOpen();
2161592Srgrimes
2171592Srgrimes	(void) sigsetmask(omask);		/* allow reconfig's */
2181592Srgrimes
2191592Srgrimes	/*
2201592Srgrimes	 *  Main loop: receive a packet, determine where it came from,
2211592Srgrimes	 *  and if we service this host, call routine to handle request.
2221592Srgrimes	 */
2231592Srgrimes	maxfds = fd + 1;
2241592Srgrimes	FD_ZERO(&rset);
2251592Srgrimes	FD_SET(fd, &rset);
2261592Srgrimes	for (;;) {
2271592Srgrimes		struct timeval timeout;
2281592Srgrimes		fd_set r;
2291592Srgrimes		int nsel;
2301592Srgrimes
2311592Srgrimes		r = rset;
2321592Srgrimes
2331592Srgrimes		if (RmpConns == NULL) {		/* timeout isnt necessary */
23427077Ssteve			nsel = select(maxfds, &r, NULL, NULL, NULL);
2351592Srgrimes		} else {
2361592Srgrimes			timeout.tv_sec = RMP_TIMEOUT;
2371592Srgrimes			timeout.tv_usec = 0;
23827077Ssteve			nsel = select(maxfds, &r, NULL, NULL, &timeout);
2391592Srgrimes		}
2401592Srgrimes
2411592Srgrimes		if (nsel < 0) {
2421592Srgrimes			if (errno == EINTR)
2431592Srgrimes				continue;
2441592Srgrimes			syslog(LOG_ERR, "select: %m");
2451592Srgrimes			Exit(0);
2461592Srgrimes		} else if (nsel == 0) {		/* timeout */
2471592Srgrimes			DoTimeout();			/* clear stale conns */
2481592Srgrimes			continue;
2491592Srgrimes		}
2501592Srgrimes
2511592Srgrimes		if (FD_ISSET(fd, &r)) {
2521592Srgrimes			RMPCONN rconn;
2531592Srgrimes			CLIENT *client, *FindClient();
2541592Srgrimes			int doread = 1;
2551592Srgrimes
2561592Srgrimes			while (BpfRead(&rconn, doread)) {
2571592Srgrimes				doread = 0;
2581592Srgrimes
2591592Srgrimes				if (DbgFp != NULL)	/* display packet */
2601592Srgrimes					DispPkt(&rconn,DIR_RCVD);
2611592Srgrimes
2621592Srgrimes				omask = sigblock(sigmask(SIGHUP));
2631592Srgrimes
2641592Srgrimes				/*
2651592Srgrimes				 *  If we do not restrict service, set the
2661592Srgrimes				 *  client to NULL (ProcessPacket() handles
2671592Srgrimes				 *  this).  Otherwise, check that we can
2681592Srgrimes				 *  service this host; if not, log a message
2691592Srgrimes				 *  and ignore the packet.
2701592Srgrimes				 */
2711592Srgrimes				if (BootAny) {
2721592Srgrimes					client = NULL;
2731592Srgrimes				} else if ((client=FindClient(&rconn))==NULL) {
2741592Srgrimes					syslog(LOG_INFO,
2751592Srgrimes					       "%s: boot packet ignored",
2761592Srgrimes					       EnetStr(&rconn));
2771592Srgrimes					(void) sigsetmask(omask);
2781592Srgrimes					continue;
2791592Srgrimes				}
2801592Srgrimes
2811592Srgrimes				ProcessPacket(&rconn,client);
2821592Srgrimes
2831592Srgrimes				(void) sigsetmask(omask);
2841592Srgrimes			}
2851592Srgrimes		}
2861592Srgrimes	}
2871592Srgrimes}
2881592Srgrimes
28931386Scharnierstatic void
29090377Simpusage(void)
29131386Scharnier{
29231386Scharnier	fprintf(stderr, "usage: rbootd [-ad] [-i interface] [config_file]\n");
29331386Scharnier	exit (1);
29431386Scharnier}
29531386Scharnier
2961592Srgrimes/*
2971592Srgrimes**  DoTimeout -- Free any connections that have timed out.
2981592Srgrimes**
2991592Srgrimes**	Parameters:
3001592Srgrimes**		None.
3011592Srgrimes**
3021592Srgrimes**	Returns:
3031592Srgrimes**		Nothing.
3041592Srgrimes**
3051592Srgrimes**	Side Effects:
3061592Srgrimes**		- Timed out connections in `RmpConns' will be freed.
3071592Srgrimes*/
3081592Srgrimesvoid
30990377SimpDoTimeout(void)
3101592Srgrimes{
31127079Ssteve	RMPCONN *rtmp;
3121592Srgrimes	struct timeval now;
3131592Srgrimes
3141592Srgrimes	(void) gettimeofday(&now, (struct timezone *)0);
3151592Srgrimes
3161592Srgrimes	/*
3171592Srgrimes	 *  For each active connection, if RMP_TIMEOUT seconds have passed
3181592Srgrimes	 *  since the last packet was sent, delete the connection.
3191592Srgrimes	 */
3201592Srgrimes	for (rtmp = RmpConns; rtmp != NULL; rtmp = rtmp->next)
3211592Srgrimes		if ((rtmp->tstamp.tv_sec + RMP_TIMEOUT) < now.tv_sec) {
3221592Srgrimes			syslog(LOG_WARNING, "%s: connection timed out (%u)",
3231592Srgrimes			       EnetStr(rtmp), rtmp->rmp.r_type);
3241592Srgrimes			RemoveConn(rtmp);
3251592Srgrimes		}
3261592Srgrimes}
3271592Srgrimes
3281592Srgrimes/*
3291592Srgrimes**  FindClient -- Find client associated with a packet.
3301592Srgrimes**
3311592Srgrimes**	Parameters:
3328870Srgrimes**		rconn - the new packet.
3331592Srgrimes**
3341592Srgrimes**	Returns:
3351592Srgrimes**		Pointer to client info if found, NULL otherwise.
3361592Srgrimes**
3371592Srgrimes**	Side Effects:
3381592Srgrimes**		None.
3391592Srgrimes**
3401592Srgrimes**	Warnings:
3411592Srgrimes**		- This routine must be called with SIGHUP blocked since
3421592Srgrimes**		  a reconfigure can invalidate the information returned.
3431592Srgrimes*/
3441592Srgrimes
3451592SrgrimesCLIENT *
34690377SimpFindClient(RMPCONN *rconn)
3471592Srgrimes{
34827079Ssteve	CLIENT *ctmp;
3491592Srgrimes
3501592Srgrimes	for (ctmp = Clients; ctmp != NULL; ctmp = ctmp->next)
3511592Srgrimes		if (bcmp((char *)&rconn->rmp.hp_hdr.saddr[0],
3521592Srgrimes		         (char *)&ctmp->addr[0], RMP_ADDRLEN) == 0)
3531592Srgrimes			break;
3541592Srgrimes
3551592Srgrimes	return(ctmp);
3561592Srgrimes}
3571592Srgrimes
3581592Srgrimes/*
3591592Srgrimes**  Exit -- Log an error message and exit.
3601592Srgrimes**
3611592Srgrimes**	Parameters:
3621592Srgrimes**		sig - caught signal (or zero if not dying on a signal).
3631592Srgrimes**
3641592Srgrimes**	Returns:
3651592Srgrimes**		Does not return.
3661592Srgrimes**
3671592Srgrimes**	Side Effects:
3681592Srgrimes**		- This process ceases to exist.
3691592Srgrimes*/
3701592Srgrimesvoid
37190377SimpExit(int sig)
3721592Srgrimes{
3731592Srgrimes	if (sig > 0)
3741592Srgrimes		syslog(LOG_ERR, "going down on signal %d", sig);
3751592Srgrimes	else
3761592Srgrimes		syslog(LOG_ERR, "going down with fatal error");
3771592Srgrimes	BpfClose();
3781592Srgrimes	exit(1);
3791592Srgrimes}
3801592Srgrimes
3811592Srgrimes/*
3821592Srgrimes**  ReConfig -- Get new list of boot files and reread config files.
3831592Srgrimes**
3841592Srgrimes**	Parameters:
3851592Srgrimes**		None.
3861592Srgrimes**
3871592Srgrimes**	Returns:
3881592Srgrimes**		Nothing.
3891592Srgrimes**
3901592Srgrimes**	Side Effects:
3911592Srgrimes**		- All active connections are dropped.
3921592Srgrimes**		- List of boot-able files is changed.
3931592Srgrimes**		- List of clients is changed.
3941592Srgrimes**
3951592Srgrimes**	Warnings:
3961592Srgrimes**		- This routine must be called with SIGHUP blocked.
3971592Srgrimes*/
3981592Srgrimesvoid
39990377SimpReConfig(int signo)
4001592Srgrimes{
4011592Srgrimes	syslog(LOG_NOTICE, "reconfiguring boot server");
4021592Srgrimes
4031592Srgrimes	FreeConns();
4041592Srgrimes
4051592Srgrimes	if (GetBootFiles() == 0)
4061592Srgrimes		Exit(0);
4071592Srgrimes
4081592Srgrimes	if (ParseConfig() == 0)
4091592Srgrimes		Exit(0);
4101592Srgrimes}
4111592Srgrimes
4121592Srgrimes/*
4131592Srgrimes**  DebugOff -- Turn off debugging.
4141592Srgrimes**
4151592Srgrimes**	Parameters:
4161592Srgrimes**		None.
4171592Srgrimes**
4181592Srgrimes**	Returns:
4191592Srgrimes**		Nothing.
4201592Srgrimes**
4211592Srgrimes**	Side Effects:
4221592Srgrimes**		- Debug file is closed.
4231592Srgrimes*/
4241592Srgrimesvoid
42590377SimpDebugOff(int signo)
4261592Srgrimes{
4271592Srgrimes	if (DbgFp != NULL)
4281592Srgrimes		(void) fclose(DbgFp);
4291592Srgrimes
4301592Srgrimes	DbgFp = NULL;
4311592Srgrimes}
4321592Srgrimes
4331592Srgrimes/*
4341592Srgrimes**  DebugOn -- Turn on debugging.
4351592Srgrimes**
4361592Srgrimes**	Parameters:
4371592Srgrimes**		None.
4381592Srgrimes**
4391592Srgrimes**	Returns:
4401592Srgrimes**		Nothing.
4411592Srgrimes**
4421592Srgrimes**	Side Effects:
4431592Srgrimes**		- Debug file is opened/truncated if not already opened,
4441592Srgrimes**		  otherwise do nothing.
4451592Srgrimes*/
4461592Srgrimesvoid
44790377SimpDebugOn(int signo)
4481592Srgrimes{
4491592Srgrimes	if (DbgFp == NULL) {
4501592Srgrimes		if ((DbgFp = fopen(DbgFile, "w")) == NULL)
4511592Srgrimes			syslog(LOG_ERR, "can't open debug file (%s)", DbgFile);
4521592Srgrimes	}
4531592Srgrimes}
454