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