GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.sbin/rbootd/rbootd.c Lines: 0 122 0.0 %
Date: 2017-11-13 Branches: 0 80 0.0 %

Line Branch Exec Source
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
}