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