1 |
|
|
/* $OpenBSD: rbootd.c,v 1.31 2016/05/29 02:19:02 guenther Exp $ */ |
2 |
|
|
/* $NetBSD: rbootd.c,v 1.5 1995/10/06 05:12:17 thorpej Exp $ */ |
3 |
|
|
|
4 |
|
|
/* |
5 |
|
|
* Copyright (c) 1988, 1992 The University of Utah and the Center |
6 |
|
|
* for Software Science (CSS). |
7 |
|
|
* Copyright (c) 1992, 1993 |
8 |
|
|
* The Regents of the University of California. All rights reserved. |
9 |
|
|
* |
10 |
|
|
* This code is derived from software contributed to Berkeley by |
11 |
|
|
* the Center for Software Science of the University of Utah Computer |
12 |
|
|
* Science Department. CSS requests users of this software to return |
13 |
|
|
* to css-dist@cs.utah.edu any improvements that they make and grant |
14 |
|
|
* CSS redistribution rights. |
15 |
|
|
* |
16 |
|
|
* Redistribution and use in source and binary forms, with or without |
17 |
|
|
* modification, are permitted provided that the following conditions |
18 |
|
|
* are met: |
19 |
|
|
* 1. Redistributions of source code must retain the above copyright |
20 |
|
|
* notice, this list of conditions and the following disclaimer. |
21 |
|
|
* 2. Redistributions in binary form must reproduce the above copyright |
22 |
|
|
* notice, this list of conditions and the following disclaimer in the |
23 |
|
|
* documentation and/or other materials provided with the distribution. |
24 |
|
|
* 3. Neither the name of the University nor the names of its contributors |
25 |
|
|
* may be used to endorse or promote products derived from this software |
26 |
|
|
* without specific prior written permission. |
27 |
|
|
* |
28 |
|
|
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND |
29 |
|
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
30 |
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
31 |
|
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE |
32 |
|
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
33 |
|
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
34 |
|
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
35 |
|
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
36 |
|
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
37 |
|
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
38 |
|
|
* SUCH DAMAGE. |
39 |
|
|
* |
40 |
|
|
* from: @(#)rbootd.c 8.1 (Berkeley) 6/4/93 |
41 |
|
|
* |
42 |
|
|
* From: Utah Hdr: rbootd.c 3.1 92/07/06 |
43 |
|
|
* Author: Jeff Forys, University of Utah CSS |
44 |
|
|
*/ |
45 |
|
|
|
46 |
|
|
#include <sys/time.h> |
47 |
|
|
|
48 |
|
|
#include <err.h> |
49 |
|
|
#include <errno.h> |
50 |
|
|
#include <signal.h> |
51 |
|
|
#include <stdio.h> |
52 |
|
|
#include <stdlib.h> |
53 |
|
|
#include <string.h> |
54 |
|
|
#include <syslog.h> |
55 |
|
|
#include <unistd.h> |
56 |
|
|
#include <limits.h> |
57 |
|
|
#include <pwd.h> |
58 |
|
|
#include <poll.h> |
59 |
|
|
|
60 |
|
|
#include "defs.h" |
61 |
|
|
|
62 |
|
|
extern char *__progname; /* from crt0.o */ |
63 |
|
|
|
64 |
|
|
volatile sig_atomic_t dodebugoff; |
65 |
|
|
volatile sig_atomic_t dodebugon; |
66 |
|
|
volatile sig_atomic_t doreconfig; |
67 |
|
|
|
68 |
|
|
void DebugOff(int); |
69 |
|
|
void DebugOn(int); |
70 |
|
|
void ReConfig(int); |
71 |
|
|
void Exit(int); |
72 |
|
|
|
73 |
|
|
void DoDebugOff(void); |
74 |
|
|
void DoDebugOn(void); |
75 |
|
|
void DoReConfig(void); |
76 |
|
|
|
77 |
|
|
void DoTimeout(void); |
78 |
|
|
CLIENT *FindClient(RMPCONN *); |
79 |
|
|
|
80 |
|
|
int |
81 |
|
|
main(int argc, char *argv[]) |
82 |
|
|
{ |
83 |
|
|
int c, fd; |
84 |
|
|
struct passwd *pw; |
85 |
|
|
struct pollfd pfd[1]; |
86 |
|
|
|
87 |
|
|
closefrom(STDERR_FILENO + 1); |
88 |
|
|
|
89 |
|
|
if ((pw = getpwnam("_rbootd")) == NULL) |
90 |
|
|
err(1, "getpwnam"); |
91 |
|
|
|
92 |
|
|
while ((c = getopt(argc, argv, "adi:")) != -1) |
93 |
|
|
switch (c) { |
94 |
|
|
case 'a': |
95 |
|
|
BootAny++; |
96 |
|
|
break; |
97 |
|
|
case 'd': |
98 |
|
|
DebugFlg++; |
99 |
|
|
break; |
100 |
|
|
case 'i': |
101 |
|
|
IntfName = optarg; |
102 |
|
|
break; |
103 |
|
|
} |
104 |
|
|
for (; optind < argc; optind++) { |
105 |
|
|
if (ConfigFile == NULL) |
106 |
|
|
ConfigFile = argv[optind]; |
107 |
|
|
else { |
108 |
|
|
warnx("too many config files (`%s' ignored)", |
109 |
|
|
argv[optind]); |
110 |
|
|
} |
111 |
|
|
} |
112 |
|
|
|
113 |
|
|
if (ConfigFile == NULL) /* use default config file */ |
114 |
|
|
ConfigFile = DfltConfig; |
115 |
|
|
|
116 |
|
|
if (DebugFlg) { |
117 |
|
|
DbgFp = stdout; /* output to stdout */ |
118 |
|
|
|
119 |
|
|
(void) signal(SIGUSR1, SIG_IGN); /* dont muck w/DbgFp */ |
120 |
|
|
(void) signal(SIGUSR2, SIG_IGN); |
121 |
|
|
(void) fclose(stderr); /* finished with it */ |
122 |
|
|
} else { |
123 |
|
|
if (daemon(0, 0)) |
124 |
|
|
err(1, "can't detach from terminal"); |
125 |
|
|
|
126 |
|
|
(void) signal(SIGUSR1, DebugOn); |
127 |
|
|
(void) signal(SIGUSR2, DebugOff); |
128 |
|
|
} |
129 |
|
|
|
130 |
|
|
/* |
131 |
|
|
* If no interface was specified, get one now. |
132 |
|
|
* |
133 |
|
|
* This is convoluted because we want to get the default interface |
134 |
|
|
* name for the syslog("restarted") message. If BpfGetIntfName() |
135 |
|
|
* runs into an error, it will return a syslog-able error message |
136 |
|
|
* (in `errmsg') which will be displayed here. |
137 |
|
|
*/ |
138 |
|
|
if (IntfName == NULL) { |
139 |
|
|
char *errmsg; |
140 |
|
|
|
141 |
|
|
if ((IntfName = BpfGetIntfName(&errmsg)) == NULL) { |
142 |
|
|
/* BpfGetIntfName() returns safe names, using %m */ |
143 |
|
|
syslog(LOG_ERR, "%s", errmsg); |
144 |
|
|
DoExit(); |
145 |
|
|
} |
146 |
|
|
} |
147 |
|
|
|
148 |
|
|
openlog(__progname, LOG_PID, LOG_DAEMON); |
149 |
|
|
fd = BpfOpen(); |
150 |
|
|
syslog(LOG_NOTICE, "restarted (%s)", IntfName); |
151 |
|
|
|
152 |
|
|
(void) signal(SIGHUP, ReConfig); |
153 |
|
|
(void) signal(SIGINT, Exit); |
154 |
|
|
(void) signal(SIGTERM, Exit); |
155 |
|
|
|
156 |
|
|
gethostname(MyHost, HOST_NAME_MAX+1); |
157 |
|
|
|
158 |
|
|
/* |
159 |
|
|
* All boot files are relative to the boot directory, we might |
160 |
|
|
* as well chdir() there to make life easier. |
161 |
|
|
*/ |
162 |
|
|
if (chdir(BootDir) < 0) { |
163 |
|
|
syslog(LOG_ERR, "chdir: %m (%s)", BootDir); |
164 |
|
|
DoExit(); |
165 |
|
|
} |
166 |
|
|
|
167 |
|
|
/* |
168 |
|
|
* Initial configuration. |
169 |
|
|
*/ |
170 |
|
|
if (GetBootFiles() == 0) /* get list of boot files */ |
171 |
|
|
DoExit(); |
172 |
|
|
if (ParseConfig() == 0) /* parse config file */ |
173 |
|
|
DoExit(); |
174 |
|
|
|
175 |
|
|
if (chroot(BootDir) == -1) { |
176 |
|
|
syslog(LOG_CRIT, "chroot %s: %m", BootDir); |
177 |
|
|
exit(1); |
178 |
|
|
} |
179 |
|
|
if (chdir("/") == -1) { |
180 |
|
|
syslog(LOG_CRIT, "chdir(\"/\"): %m"); |
181 |
|
|
exit(1); |
182 |
|
|
} |
183 |
|
|
if (setgroups(1, &pw->pw_gid) || |
184 |
|
|
setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) || |
185 |
|
|
setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid)) { |
186 |
|
|
syslog(LOG_CRIT, "can't drop privileges: %m"); |
187 |
|
|
exit(1); |
188 |
|
|
} |
189 |
|
|
endpwent(); |
190 |
|
|
|
191 |
|
|
/* |
192 |
|
|
* Main loop: receive a packet, determine where it came from, |
193 |
|
|
* and if we service this host, call routine to handle request. |
194 |
|
|
*/ |
195 |
|
|
pfd[0].fd = fd; |
196 |
|
|
pfd[0].events = POLLIN; |
197 |
|
|
for (;;) { |
198 |
|
|
int nsel; |
199 |
|
|
|
200 |
|
|
/* |
201 |
|
|
* Check pending actions |
202 |
|
|
*/ |
203 |
|
|
if (dodebugoff) { |
204 |
|
|
DoDebugOff(); |
205 |
|
|
dodebugoff = 0; |
206 |
|
|
} |
207 |
|
|
if (dodebugon) { |
208 |
|
|
DoDebugOn(); |
209 |
|
|
dodebugon = 0; |
210 |
|
|
} |
211 |
|
|
if (doreconfig) { |
212 |
|
|
DoReConfig(); |
213 |
|
|
doreconfig = 0; |
214 |
|
|
} |
215 |
|
|
|
216 |
|
|
nsel = poll(pfd, 1, RmpConns ? RMP_TIMEOUT * 100 : -1); |
217 |
|
|
|
218 |
|
|
if (nsel < 0) { |
219 |
|
|
if (errno == EINTR) |
220 |
|
|
continue; |
221 |
|
|
syslog(LOG_ERR, "poll: %m"); |
222 |
|
|
DoExit(); |
223 |
|
|
} else if (nsel == 0) { /* timeout */ |
224 |
|
|
DoTimeout(); /* clear stale conns */ |
225 |
|
|
continue; |
226 |
|
|
} |
227 |
|
|
|
228 |
|
|
if (pfd[0].revents & POLLIN) { |
229 |
|
|
RMPCONN rconn; |
230 |
|
|
CLIENT *client; |
231 |
|
|
int doread = 1; |
232 |
|
|
|
233 |
|
|
while (BpfRead(&rconn, doread)) { |
234 |
|
|
doread = 0; |
235 |
|
|
|
236 |
|
|
if (DbgFp != NULL) /* display packet */ |
237 |
|
|
DispPkt(&rconn,DIR_RCVD); |
238 |
|
|
|
239 |
|
|
/* |
240 |
|
|
* If we do not restrict service, set the |
241 |
|
|
* client to NULL (ProcessPacket() handles |
242 |
|
|
* this). Otherwise, check that we can |
243 |
|
|
* service this host; if not, log a message |
244 |
|
|
* and ignore the packet. |
245 |
|
|
*/ |
246 |
|
|
if (BootAny) { |
247 |
|
|
client = NULL; |
248 |
|
|
} else if ((client=FindClient(&rconn))==NULL) { |
249 |
|
|
syslog(LOG_INFO, |
250 |
|
|
"%s: boot packet ignored", |
251 |
|
|
EnetStr(&rconn)); |
252 |
|
|
continue; |
253 |
|
|
} |
254 |
|
|
|
255 |
|
|
ProcessPacket(&rconn,client); |
256 |
|
|
} |
257 |
|
|
} |
258 |
|
|
} |
259 |
|
|
} |
260 |
|
|
|
261 |
|
|
/* |
262 |
|
|
** DoTimeout -- Free any connections that have timed out. |
263 |
|
|
** |
264 |
|
|
** Parameters: |
265 |
|
|
** None. |
266 |
|
|
** |
267 |
|
|
** Returns: |
268 |
|
|
** Nothing. |
269 |
|
|
** |
270 |
|
|
** Side Effects: |
271 |
|
|
** - Timed out connections in `RmpConns' will be freed. |
272 |
|
|
*/ |
273 |
|
|
void |
274 |
|
|
DoTimeout(void) |
275 |
|
|
{ |
276 |
|
|
RMPCONN *rtmp; |
277 |
|
|
struct timeval now; |
278 |
|
|
|
279 |
|
|
(void) gettimeofday(&now, NULL); |
280 |
|
|
|
281 |
|
|
/* |
282 |
|
|
* For each active connection, if RMP_TIMEOUT seconds have passed |
283 |
|
|
* since the last packet was sent, delete the connection. |
284 |
|
|
*/ |
285 |
|
|
for (rtmp = RmpConns; rtmp != NULL; rtmp = rtmp->next) |
286 |
|
|
if ((rtmp->tstamp.tv_sec + RMP_TIMEOUT) < now.tv_sec) { |
287 |
|
|
syslog(LOG_WARNING, "%s: connection timed out (%u)", |
288 |
|
|
EnetStr(rtmp), rtmp->rmp.r_type); |
289 |
|
|
RemoveConn(rtmp); |
290 |
|
|
} |
291 |
|
|
} |
292 |
|
|
|
293 |
|
|
/* |
294 |
|
|
** FindClient -- Find client associated with a packet. |
295 |
|
|
** |
296 |
|
|
** Parameters: |
297 |
|
|
** rconn - the new packet. |
298 |
|
|
** |
299 |
|
|
** Returns: |
300 |
|
|
** Pointer to client info if found, NULL otherwise. |
301 |
|
|
** |
302 |
|
|
** Side Effects: |
303 |
|
|
** None. |
304 |
|
|
** |
305 |
|
|
** Warnings: |
306 |
|
|
** - This routine must be called with SIGHUP blocked since |
307 |
|
|
** a reconfigure can invalidate the information returned. |
308 |
|
|
*/ |
309 |
|
|
CLIENT * |
310 |
|
|
FindClient(RMPCONN *rconn) |
311 |
|
|
{ |
312 |
|
|
CLIENT *ctmp; |
313 |
|
|
|
314 |
|
|
for (ctmp = Clients; ctmp != NULL; ctmp = ctmp->next) |
315 |
|
|
if (bcmp((char *)&rconn->rmp.hp_hdr.saddr[0], |
316 |
|
|
(char *)&ctmp->addr[0], RMP_ADDRLEN) == 0) |
317 |
|
|
break; |
318 |
|
|
|
319 |
|
|
return(ctmp); |
320 |
|
|
} |
321 |
|
|
|
322 |
|
|
/* |
323 |
|
|
** Exit -- Log an error message and exit. |
324 |
|
|
** |
325 |
|
|
** Parameters: |
326 |
|
|
** sig - caught signal (or zero if not dying on a signal). |
327 |
|
|
** |
328 |
|
|
** Returns: |
329 |
|
|
** Does not return. |
330 |
|
|
** |
331 |
|
|
** Side Effects: |
332 |
|
|
** - This process ceases to exist. |
333 |
|
|
*/ |
334 |
|
|
void |
335 |
|
|
Exit(int sig) |
336 |
|
|
{ |
337 |
|
|
struct syslog_data sdata = SYSLOG_DATA_INIT; |
338 |
|
|
|
339 |
|
|
syslog_r(LOG_ERR, &sdata, "going down on signal %d", sig); |
340 |
|
|
_exit(1); |
341 |
|
|
} |
342 |
|
|
|
343 |
|
|
void |
344 |
|
|
DoExit(void) |
345 |
|
|
{ |
346 |
|
|
syslog(LOG_ERR, "going down on fatal error"); |
347 |
|
|
exit(1); |
348 |
|
|
} |
349 |
|
|
|
350 |
|
|
/* |
351 |
|
|
** ReConfig -- Get new list of boot files and reread config files. |
352 |
|
|
** |
353 |
|
|
** Parameters: |
354 |
|
|
** None. |
355 |
|
|
** |
356 |
|
|
** Returns: |
357 |
|
|
** Nothing. |
358 |
|
|
** |
359 |
|
|
** Side Effects: |
360 |
|
|
** - All active connections are dropped. |
361 |
|
|
** - List of bootable files is changed. |
362 |
|
|
** - List of clients is changed. |
363 |
|
|
** |
364 |
|
|
** Warnings: |
365 |
|
|
** - This routine must be called with SIGHUP blocked. |
366 |
|
|
*/ |
367 |
|
|
void |
368 |
|
|
ReConfig(int signo) |
369 |
|
|
{ |
370 |
|
|
doreconfig = 1; |
371 |
|
|
} |
372 |
|
|
|
373 |
|
|
void |
374 |
|
|
DoReConfig(void) |
375 |
|
|
{ |
376 |
|
|
syslog(LOG_NOTICE, "reconfiguring boot server"); |
377 |
|
|
|
378 |
|
|
FreeConns(); |
379 |
|
|
|
380 |
|
|
if (GetBootFiles() == 0) |
381 |
|
|
DoExit(); |
382 |
|
|
|
383 |
|
|
if (ParseConfig() == 0) |
384 |
|
|
DoExit(); |
385 |
|
|
} |
386 |
|
|
|
387 |
|
|
/* |
388 |
|
|
** DebugOff -- Turn off debugging. |
389 |
|
|
** |
390 |
|
|
** Parameters: |
391 |
|
|
** None. |
392 |
|
|
** |
393 |
|
|
** Returns: |
394 |
|
|
** Nothing. |
395 |
|
|
** |
396 |
|
|
** Side Effects: |
397 |
|
|
** - Debug file is closed. |
398 |
|
|
*/ |
399 |
|
|
void |
400 |
|
|
DebugOff(int signo) |
401 |
|
|
{ |
402 |
|
|
dodebugoff = 1; |
403 |
|
|
} |
404 |
|
|
|
405 |
|
|
void |
406 |
|
|
DoDebugOff(void) |
407 |
|
|
{ |
408 |
|
|
if (DbgFp != NULL) |
409 |
|
|
(void) fclose(DbgFp); |
410 |
|
|
|
411 |
|
|
DbgFp = NULL; |
412 |
|
|
} |
413 |
|
|
|
414 |
|
|
/* |
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 |
|
|
*/ |
427 |
|
|
void |
428 |
|
|
DebugOn(int signo) |
429 |
|
|
{ |
430 |
|
|
dodebugon = 1; |
431 |
|
|
} |
432 |
|
|
|
433 |
|
|
void |
434 |
|
|
DoDebugOn(void) |
435 |
|
|
{ |
436 |
|
|
if (DbgFp == NULL) { |
437 |
|
|
if ((DbgFp = fopen(DbgFile, "w")) == NULL) |
438 |
|
|
syslog(LOG_ERR, "can't open debug file (%s)", DbgFile); |
439 |
|
|
} |
440 |
|
|
} |