GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.sbin/tcpdump/privsep.c Lines: 0 390 0.0 %
Date: 2017-11-07 Branches: 0 191 0.0 %

Line Branch Exec Source
1
/*	$OpenBSD: privsep.c,v 1.47 2017/09/08 19:30:13 brynet Exp $	*/
2
3
/*
4
 * Copyright (c) 2003 Can Erkin Acar
5
 * Copyright (c) 2003 Anil Madhavapeddy <anil@recoil.org>
6
 *
7
 * Permission to use, copy, modify, and distribute this software for any
8
 * purpose with or without fee is hereby granted, provided that the above
9
 * copyright notice and this permission notice appear in all copies.
10
 *
11
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18
 */
19
20
#include <sys/types.h>
21
#include <sys/socket.h>
22
#include <sys/wait.h>
23
#include <sys/ioctl.h>
24
25
#include <netinet/in.h>
26
#include <net/if.h>
27
#include <netinet/if_ether.h>
28
#include <net/bpf.h>
29
#include <net/pfvar.h>
30
31
#include <rpc/rpc.h>
32
33
#include <err.h>
34
#include <errno.h>
35
#include <fcntl.h>
36
#include <netdb.h>
37
#include <paths.h>
38
#include <pwd.h>
39
#include <signal.h>
40
#include <stdarg.h>
41
#include <stdio.h>
42
#include <stdlib.h>
43
#include <string.h>
44
#include <syslog.h>
45
#include <unistd.h>
46
47
#include "interface.h"
48
#include "privsep.h"
49
#include "pfctl_parser.h"
50
51
/*
52
 * tcpdump goes through four states: STATE_INIT is where the
53
 * bpf device and the input file is opened. In STATE_BPF, the
54
 * pcap filter gets set. STATE_FILTER is used for parsing
55
 * /etc/services and /etc/protocols and opening the output
56
 * file. STATE_RUN is the packet processing part.
57
 */
58
59
enum priv_state {
60
	STATE_INIT,		/* initial state */
61
	STATE_BPF,		/* input file/device opened */
62
	STATE_FILTER,		/* filter applied */
63
	STATE_RUN,		/* running and accepting network traffic */
64
	STATE_EXIT		/* in the process of dying */
65
};
66
67
#define ALLOW(action)	(1 << (action))
68
69
/*
70
 * Set of maximum allowed actions.
71
 */
72
static const int allowed_max[] = {
73
	/* INIT */	ALLOW(PRIV_OPEN_BPF) | ALLOW(PRIV_OPEN_DUMP) |
74
			ALLOW(PRIV_SETFILTER),
75
	/* BPF */	ALLOW(PRIV_SETFILTER),
76
	/* FILTER */	ALLOW(PRIV_OPEN_OUTPUT) | ALLOW(PRIV_GETSERVENTRIES) |
77
			ALLOW(PRIV_GETPROTOENTRIES) |
78
			ALLOW(PRIV_ETHER_NTOHOST) | ALLOW(PRIV_INIT_DONE),
79
	/* RUN */	ALLOW(PRIV_GETHOSTBYADDR) | ALLOW(PRIV_ETHER_NTOHOST) |
80
			ALLOW(PRIV_GETRPCBYNUMBER) | ALLOW(PRIV_GETLINES) |
81
			ALLOW(PRIV_LOCALTIME) | ALLOW(PRIV_PCAP_STATS),
82
	/* EXIT */	0
83
};
84
85
/*
86
 * Default set of allowed actions. More actions get added
87
 * later depending on the supplied parameters.
88
 */
89
static int allowed_ext[] = {
90
	/* INIT */	ALLOW(PRIV_SETFILTER),
91
	/* BPF */	ALLOW(PRIV_SETFILTER),
92
	/* FILTER */	ALLOW(PRIV_GETSERVENTRIES),
93
	/* RUN */	ALLOW(PRIV_GETLINES) | ALLOW(PRIV_LOCALTIME) |
94
			ALLOW(PRIV_PCAP_STATS),
95
	/* EXIT */	0
96
};
97
98
struct ftab {
99
	char *name;
100
	int max;
101
	int count;
102
};
103
104
static struct ftab file_table[] = {{PF_OSFP_FILE, 1, 0}};
105
106
#define NUM_FILETAB (sizeof(file_table) / sizeof(struct ftab))
107
108
int		debug_level = LOG_INFO;
109
int		priv_fd = -1;
110
volatile	pid_t child_pid = -1;
111
static volatile	sig_atomic_t cur_state = STATE_INIT;
112
113
extern void	set_slave_signals(void);
114
115
static void	impl_open_bpf(int, int *);
116
static void	impl_open_dump(int, const char *);
117
static void	impl_open_output(int, const char *);
118
static void	impl_setfilter(int, char *, int *);
119
static void	impl_init_done(int, int *);
120
static void	impl_gethostbyaddr(int);
121
static void	impl_ether_ntohost(int);
122
static void	impl_getrpcbynumber(int);
123
static void	impl_getserventries(int);
124
static void	impl_getprotoentries(int);
125
static void	impl_localtime(int fd);
126
static void	impl_getlines(int);
127
static void	impl_pcap_stats(int, int *);
128
129
static void	test_state(int, int);
130
static void	logmsg(int, const char *, ...);
131
132
int
133
priv_init(int argc, char **argv)
134
{
135
	int i, nargc, socks[2];
136
	struct passwd *pw;
137
	sigset_t allsigs, oset;
138
	char **privargv;
139
140
	closefrom(STDERR_FILENO + 1);
141
	for (i = 1; i < _NSIG; i++)
142
		signal(i, SIG_DFL);
143
144
	/* Create sockets */
145
	if (socketpair(AF_LOCAL, SOCK_STREAM, PF_UNSPEC, socks) == -1)
146
		err(1, "socketpair() failed");
147
148
	sigfillset(&allsigs);
149
	sigprocmask(SIG_BLOCK, &allsigs, &oset);
150
151
	child_pid = fork();
152
	if (child_pid < 0)
153
		err(1, "fork() failed");
154
155
	if (child_pid) {
156
		close(socks[0]);
157
		priv_fd = socks[1];
158
159
		set_slave_signals();
160
		sigprocmask(SIG_SETMASK, &oset, NULL);
161
162
		/*
163
		 * If run as regular user, packet parser will rely on
164
		 * pledge(2). If we are root, we want to chroot also..
165
		 */
166
		if (getuid() != 0)
167
			return (0);
168
169
		pw = getpwnam("_tcpdump");
170
		if (pw == NULL)
171
			errx(1, "unknown user _tcpdump");
172
173
		if (chroot(pw->pw_dir) == -1)
174
			err(1, "unable to chroot");
175
		if (chdir("/") == -1)
176
			err(1, "unable to chdir");
177
178
		/* drop to _tcpdump */
179
		if (setgroups(1, &pw->pw_gid) == -1)
180
			err(1, "setgroups() failed");
181
		if (setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) == -1)
182
			err(1, "setresgid() failed");
183
		if (setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid) == -1)
184
			err(1, "setresuid() failed");
185
186
		return (0);
187
	}
188
	close(socks[1]);
189
190
	if (dup2(socks[0], 3) == -1)
191
		err(1, "dup2 priv sock failed");
192
	closefrom(4);
193
194
	if ((privargv = reallocarray(NULL, argc + 2, sizeof(char *))) == NULL)
195
		err(1, "alloc priv argv failed");
196
	nargc = 0;
197
	privargv[nargc++] = argv[0];
198
	privargv[nargc++] = "-P";
199
	for (i = 1; i < argc; i++)
200
		privargv[nargc++] = argv[i];
201
	privargv[nargc] = NULL;
202
	execvp(privargv[0], privargv);
203
	err(1, "exec priv '%s' failed", privargv[0]);
204
}
205
206
__dead void
207
priv_exec(int argc, char *argv[])
208
{
209
	int bpfd = -1;
210
	int i, sock, cmd, nflag = 0, Pflag = 0;
211
	char *cmdbuf, *infile = NULL;
212
	char *RFileName = NULL;
213
	char *WFileName = NULL;
214
215
	sock = 3;
216
217
	closefrom(4);
218
	for (i = 1; i < _NSIG; i++)
219
		signal(i, SIG_DFL);
220
221
	signal(SIGINT, SIG_IGN);
222
223
	/* parse the arguments for required options */
224
	opterr = 0;
225
	while ((i = getopt(argc, argv,
226
	    "ac:D:deE:fF:i:lLnNOopPqr:s:StT:vw:xXy:Y")) != -1) {
227
		switch (i) {
228
		case 'n':
229
			nflag++;
230
			break;
231
232
		case 'r':
233
			RFileName = optarg;
234
			break;
235
236
		case 'w':
237
			WFileName = optarg;
238
			break;
239
240
		case 'F':
241
			infile = optarg;
242
			break;
243
244
		case 'P':
245
			Pflag = 1;
246
			break;
247
248
		default:
249
			/* nothing */
250
			break;
251
		}
252
	}
253
254
	if (!Pflag)
255
		errx(1, "exec without priv");
256
257
	if (RFileName != NULL) {
258
		if (strcmp(RFileName, "-") != 0)
259
			allowed_ext[STATE_INIT] |= ALLOW(PRIV_OPEN_DUMP);
260
	} else
261
		allowed_ext[STATE_INIT] |= ALLOW(PRIV_OPEN_BPF);
262
	if (WFileName != NULL) {
263
		if (strcmp(WFileName, "-") != 0)
264
			allowed_ext[STATE_FILTER] |= ALLOW(PRIV_OPEN_OUTPUT);
265
		else
266
			allowed_ext[STATE_FILTER] |= ALLOW(PRIV_INIT_DONE);
267
	} else
268
		allowed_ext[STATE_FILTER] |= ALLOW(PRIV_INIT_DONE);
269
	if (!nflag) {
270
		allowed_ext[STATE_RUN] |= ALLOW(PRIV_GETHOSTBYADDR);
271
		allowed_ext[STATE_FILTER] |= ALLOW(PRIV_ETHER_NTOHOST);
272
		allowed_ext[STATE_RUN] |= ALLOW(PRIV_ETHER_NTOHOST);
273
		allowed_ext[STATE_RUN] |= ALLOW(PRIV_GETRPCBYNUMBER);
274
		allowed_ext[STATE_FILTER] |= ALLOW(PRIV_GETPROTOENTRIES);
275
	}
276
277
	if (infile)
278
		cmdbuf = read_infile(infile);
279
	else
280
		cmdbuf = copy_argv(&argv[optind]);
281
282
	setproctitle("[priv]");
283
284
	for (;;) {
285
		if (may_read(sock, &cmd, sizeof(int)))
286
			break;
287
		switch (cmd) {
288
		case PRIV_OPEN_BPF:
289
			test_state(cmd, STATE_BPF);
290
			impl_open_bpf(sock, &bpfd);
291
			break;
292
		case PRIV_OPEN_DUMP:
293
			test_state(cmd, STATE_BPF);
294
			impl_open_dump(sock, RFileName);
295
			break;
296
		case PRIV_OPEN_OUTPUT:
297
			test_state(cmd, STATE_RUN);
298
			impl_open_output(sock, WFileName);
299
			break;
300
		case PRIV_SETFILTER:
301
			test_state(cmd, STATE_FILTER);
302
			impl_setfilter(sock, cmdbuf, &bpfd);
303
			break;
304
		case PRIV_INIT_DONE:
305
			test_state(cmd, STATE_RUN);
306
			impl_init_done(sock, &bpfd);
307
308
			if (pledge("stdio rpath inet unix dns recvfd bpf flock cpath wpath", NULL) == -1)
309
				err(1, "pledge");
310
311
			break;
312
		case PRIV_GETHOSTBYADDR:
313
			test_state(cmd, STATE_RUN);
314
			impl_gethostbyaddr(sock);
315
			break;
316
		case PRIV_ETHER_NTOHOST:
317
			test_state(cmd, cur_state);
318
			impl_ether_ntohost(sock);
319
			break;
320
		case PRIV_GETRPCBYNUMBER:
321
			test_state(cmd, STATE_RUN);
322
			impl_getrpcbynumber(sock);
323
			break;
324
		case PRIV_GETSERVENTRIES:
325
			test_state(cmd, STATE_FILTER);
326
			impl_getserventries(sock);
327
			break;
328
		case PRIV_GETPROTOENTRIES:
329
			test_state(cmd, STATE_FILTER);
330
			impl_getprotoentries(sock);
331
			break;
332
		case PRIV_LOCALTIME:
333
			test_state(cmd, STATE_RUN);
334
			impl_localtime(sock);
335
			break;
336
		case PRIV_GETLINES:
337
			test_state(cmd, STATE_RUN);
338
			impl_getlines(sock);
339
			break;
340
		case PRIV_PCAP_STATS:
341
			test_state(cmd, STATE_RUN);
342
			impl_pcap_stats(sock, &bpfd);
343
			break;
344
		default:
345
			logmsg(LOG_ERR, "[priv]: unknown command %d", cmd);
346
			exit(1);
347
			/* NOTREACHED */
348
		}
349
	}
350
351
	/* NOTREACHED */
352
	exit(0);
353
}
354
355
static void
356
impl_open_bpf(int fd, int *bpfd)
357
{
358
	int snaplen, promisc, err;
359
	u_int dlt, dirfilt;
360
	char device[IFNAMSIZ];
361
	size_t iflen;
362
363
	logmsg(LOG_DEBUG, "[priv]: msg PRIV_OPEN_BPF received");
364
365
	must_read(fd, &snaplen, sizeof(int));
366
	must_read(fd, &promisc, sizeof(int));
367
	must_read(fd, &dlt, sizeof(u_int));
368
	must_read(fd, &dirfilt, sizeof(u_int));
369
	iflen = read_string(fd, device, sizeof(device), __func__);
370
	if (iflen == 0)
371
		errx(1, "Invalid interface size specified");
372
	*bpfd = pcap_live(device, snaplen, promisc, dlt, dirfilt);
373
	err = errno;
374
	if (*bpfd < 0)
375
		logmsg(LOG_DEBUG,
376
		    "[priv]: failed to open bpf device for %s: %s",
377
		    device, strerror(errno));
378
	send_fd(fd, *bpfd);
379
	must_write(fd, &err, sizeof(int));
380
	/* do not close bpfd until filter is set */
381
}
382
383
static void
384
impl_open_dump(int fd, const char *RFileName)
385
{
386
	int file, err = 0;
387
388
	logmsg(LOG_DEBUG, "[priv]: msg PRIV_OPEN_DUMP received");
389
390
	if (RFileName == NULL) {
391
		file = -1;
392
		logmsg(LOG_ERR, "[priv]: No offline file specified");
393
	} else {
394
		file = open(RFileName, O_RDONLY, 0);
395
		err = errno;
396
		if (file < 0)
397
			logmsg(LOG_DEBUG, "[priv]: failed to open %s: %s",
398
			    RFileName, strerror(errno));
399
	}
400
	send_fd(fd, file);
401
	must_write(fd, &err, sizeof(int));
402
	if (file >= 0)
403
		close(file);
404
}
405
406
static void
407
impl_open_output(int fd, const char *WFileName)
408
{
409
	int file, err;
410
411
	logmsg(LOG_DEBUG, "[priv]: msg PRIV_OPEN_OUTPUT received");
412
413
	file = open(WFileName, O_WRONLY|O_CREAT|O_TRUNC, 0666);
414
	err = errno;
415
	send_fd(fd, file);
416
	must_write(fd, &err, sizeof(int));
417
	if (file < 0)
418
		logmsg(LOG_DEBUG, "[priv]: failed to open %s: %s",
419
		    WFileName, strerror(err));
420
	else
421
		close(file);
422
}
423
424
static void
425
impl_setfilter(int fd, char *cmdbuf, int *bpfd)
426
{
427
	logmsg(LOG_DEBUG, "[priv]: msg PRIV_SETFILTER received");
428
429
	if (setfilter(*bpfd, fd, cmdbuf))
430
		logmsg(LOG_DEBUG, "[priv]: setfilter() failed");
431
}
432
433
static void
434
impl_init_done(int fd, int *bpfd)
435
{
436
	int ret;
437
438
	logmsg(LOG_DEBUG, "[priv]: msg PRIV_INIT_DONE received");
439
440
	ret = 0;
441
	must_write(fd, &ret, sizeof(ret));
442
}
443
444
static void
445
impl_gethostbyaddr(int fd)
446
{
447
	char hostname[HOST_NAME_MAX+1];
448
	size_t hostname_len;
449
	int addr_af;
450
	struct hostent *hp;
451
452
	logmsg(LOG_DEBUG, "[priv]: msg PRIV_GETHOSTBYADDR received");
453
454
	/* Expecting: address block, address family */
455
	hostname_len = read_block(fd, hostname, sizeof(hostname), __func__);
456
	if (hostname_len == 0)
457
		_exit(1);
458
	must_read(fd, &addr_af, sizeof(int));
459
	hp = gethostbyaddr(hostname, hostname_len, addr_af);
460
	if (hp == NULL)
461
		write_zero(fd);
462
	else
463
		write_string(fd, hp->h_name);
464
}
465
466
static void
467
impl_ether_ntohost(int fd)
468
{
469
	struct ether_addr ether;
470
	char hostname[HOST_NAME_MAX+1];
471
472
	logmsg(LOG_DEBUG, "[priv]: msg PRIV_ETHER_NTOHOST received");
473
474
	/* Expecting: ethernet address */
475
	must_read(fd, &ether, sizeof(ether));
476
	if (ether_ntohost(hostname, &ether) == -1)
477
		write_zero(fd);
478
	else
479
		write_string(fd, hostname);
480
}
481
482
static void
483
impl_getrpcbynumber(int fd)
484
{
485
	int rpc;
486
	struct rpcent *rpce;
487
488
	logmsg(LOG_DEBUG, "[priv]: msg PRIV_GETRPCBYNUMBER received");
489
490
	must_read(fd, &rpc, sizeof(int));
491
	rpce = getrpcbynumber(rpc);
492
	if (rpce == NULL)
493
		write_zero(fd);
494
	else
495
		write_string(fd, rpce->r_name);
496
}
497
498
static void
499
impl_getserventries(int fd)
500
{
501
	struct servent *sp;
502
503
	logmsg(LOG_DEBUG, "[priv]: msg PRIV_GETSERVENTRIES received");
504
505
	for (;;) {
506
		sp = getservent();
507
		if (sp == NULL) {
508
			write_zero(fd);
509
			break;
510
		} else {
511
			write_string(fd, sp->s_name);
512
			must_write(fd, &sp->s_port, sizeof(int));
513
			write_string(fd, sp->s_proto);
514
		}
515
	}
516
	endservent();
517
}
518
519
static void
520
impl_getprotoentries(int fd)
521
{
522
	struct protoent *pe;
523
524
	logmsg(LOG_DEBUG, "[priv]: msg PRIV_GETPROTOENTRIES received");
525
526
	for (;;) {
527
		pe = getprotoent();
528
		if (pe == NULL) {
529
			write_zero(fd);
530
			break;
531
		} else {
532
			write_string(fd, pe->p_name);
533
			must_write(fd, &pe->p_proto, sizeof(int));
534
		}
535
	}
536
	endprotoent();
537
}
538
539
/* read the time and send the corresponding localtime and gmtime
540
 * results back to the unprivileged process */
541
static void
542
impl_localtime(int fd)
543
{
544
	struct tm *lt, *gt;
545
	time_t t;
546
547
	logmsg(LOG_DEBUG, "[priv]: msg PRIV_LOCALTIME received");
548
549
	must_read(fd, &t, sizeof(time_t));
550
551
	/* this must be done separately, since they apparently use the
552
	 * same local buffer */
553
	if ((lt = localtime(&t)) == NULL)
554
		errx(1, "localtime()");
555
	must_write(fd, lt, sizeof(*lt));
556
557
	if ((gt = gmtime(&t)) == NULL)
558
		errx(1, "gmtime()");
559
	must_write(fd, gt, sizeof(*gt));
560
561
	if (lt->tm_zone == NULL)
562
		write_zero(fd);
563
	else
564
		write_string(fd, lt->tm_zone);
565
}
566
567
static void
568
impl_getlines(int fd)
569
{
570
	FILE *fp;
571
	char *buf, *lbuf, *file;
572
	size_t len, fid;
573
574
	logmsg(LOG_DEBUG, "[priv]: msg PRIV_GETLINES received");
575
576
	must_read(fd, &fid, sizeof(size_t));
577
	if (fid >= NUM_FILETAB)
578
		errx(1, "invalid file id");
579
580
	file = file_table[fid].name;
581
582
	if (file == NULL)
583
		errx(1, "invalid file referenced");
584
585
	if (file_table[fid].count >= file_table[fid].max)
586
		errx(1, "maximum open count exceeded for %s", file);
587
588
	file_table[fid].count++;
589
590
	if ((fp = fopen(file, "r")) == NULL) {
591
		write_zero(fd);
592
		return;
593
	}
594
595
	lbuf = NULL;
596
	while ((buf = fgetln(fp, &len))) {
597
		if (buf[len - 1] == '\n')
598
			buf[len - 1] = '\0';
599
		else {
600
			if ((lbuf = malloc(len + 1)) == NULL)
601
				err(1, NULL);
602
			memcpy(lbuf, buf, len);
603
			lbuf[len] = '\0';
604
			buf = lbuf;
605
		}
606
607
		write_string(fd, buf);
608
609
		free(lbuf);
610
		lbuf = NULL;
611
	}
612
	write_zero(fd);
613
	fclose(fp);
614
}
615
616
static void
617
impl_pcap_stats(int fd, int *bpfd)
618
{
619
	struct pcap_stat stats;
620
621
	logmsg(LOG_DEBUG, "[priv]: msg PRIV_PCAP_STATS received");
622
623
	if (ioctl(*bpfd, BIOCGSTATS, &stats) == -1)
624
		write_zero(fd);
625
	else
626
		must_write(fd, &stats, sizeof(stats));
627
}
628
629
void
630
priv_init_done(void)
631
{
632
	int ret;
633
634
	if (priv_fd < 0)
635
		errx(1, "%s: called from privileged portion", __func__);
636
637
	write_command(priv_fd, PRIV_INIT_DONE);
638
	must_read(priv_fd, &ret, sizeof(int));
639
}
640
641
/* Reverse address resolution; response is placed into res, and length of
642
 * response is returned (zero on error) */
643
size_t
644
priv_gethostbyaddr(char *addr, size_t addr_len, int af, char *res, size_t res_len)
645
{
646
	if (priv_fd < 0)
647
		errx(1, "%s called from privileged portion", __func__);
648
649
	write_command(priv_fd, PRIV_GETHOSTBYADDR);
650
	write_block(priv_fd, addr_len, addr);
651
	must_write(priv_fd, &af, sizeof(int));
652
653
	return (read_string(priv_fd, res, res_len, __func__));
654
}
655
656
size_t
657
priv_ether_ntohost(char *name, size_t name_len, struct ether_addr *e)
658
{
659
	if (priv_fd < 0)
660
		errx(1, "%s called from privileged portion", __func__);
661
662
	write_command(priv_fd, PRIV_ETHER_NTOHOST);
663
	must_write(priv_fd, e, sizeof(*e));
664
665
	/* Read the host name */
666
	return (read_string(priv_fd, name, name_len, __func__));
667
}
668
669
size_t
670
priv_getrpcbynumber(int rpc, char *progname, size_t progname_len)
671
{
672
	if (priv_fd < 0)
673
		errx(1, "%s called from privileged portion", __func__);
674
675
	write_command(priv_fd, PRIV_GETRPCBYNUMBER);
676
	must_write(priv_fd, &rpc, sizeof(int));
677
678
	return read_string(priv_fd, progname, progname_len, __func__);
679
}
680
681
/* start getting service entries */
682
void
683
priv_getserventries(void)
684
{
685
	if (priv_fd < 0)
686
		errx(1, "%s called from privileged portion", __func__);
687
688
	write_command(priv_fd, PRIV_GETSERVENTRIES);
689
}
690
691
/* retrieve a service entry, should be called repeatedly after calling
692
   priv_getserventries(), until it returns zero. */
693
size_t
694
priv_getserventry(char *name, size_t name_len, int *port, char *prot,
695
    size_t prot_len)
696
{
697
	if (priv_fd < 0)
698
		errx(1, "%s called from privileged portion", __func__);
699
700
	/* read the service name */
701
	if (read_string(priv_fd, name, name_len, __func__) == 0)
702
		return 0;
703
704
	/* read the port */
705
	must_read(priv_fd, port, sizeof(int));
706
707
	/* read the protocol */
708
	return (read_string(priv_fd, prot, prot_len, __func__));
709
}
710
711
/* start getting ip protocol entries */
712
void
713
priv_getprotoentries(void)
714
{
715
	if (priv_fd < 0)
716
		errx(1, "%s called from privileged portion", __func__);
717
718
	write_command(priv_fd, PRIV_GETPROTOENTRIES);
719
}
720
721
/* retrieve a ip protocol entry, should be called repeatedly after calling
722
   priv_getprotoentries(), until it returns zero. */
723
size_t
724
priv_getprotoentry(char *name, size_t name_len, int *num)
725
{
726
	if (priv_fd < 0)
727
		errx(1, "%s called from privileged portion", __func__);
728
729
	/* read the proto name */
730
	if (read_string(priv_fd, name, name_len, __func__) == 0)
731
		return 0;
732
733
	/* read the num */
734
	must_read(priv_fd, num, sizeof(int));
735
736
	return (1);
737
}
738
739
/* localtime() replacement: ask the privileged process for localtime and
740
 * gmtime, cache the localtime for about one minute i.e. until one of the
741
 * fields other than seconds changes. The check is done using gmtime
742
 * values since they are the same in parent and child. */
743
struct	tm *
744
priv_localtime(const time_t *t)
745
{
746
	static struct tm lt, gt0;
747
	static struct tm *gt = NULL;
748
	static char zone[PATH_MAX];
749
750
	if (gt != NULL) {
751
		gt = gmtime(t);
752
		gt0.tm_sec = gt->tm_sec;
753
		gt0.tm_zone = gt->tm_zone;
754
755
		if (memcmp(gt, &gt0, sizeof(struct tm)) == 0) {
756
			lt.tm_sec = gt0.tm_sec;
757
			return &lt;
758
		}
759
	}
760
761
	write_command(priv_fd, PRIV_LOCALTIME);
762
	must_write(priv_fd, t, sizeof(time_t));
763
	must_read(priv_fd, &lt, sizeof(lt));
764
	must_read(priv_fd, &gt0, sizeof(gt0));
765
766
	if (read_string(priv_fd, zone, sizeof(zone), __func__))
767
		lt.tm_zone = zone;
768
	else
769
		lt.tm_zone = NULL;
770
771
	gt0.tm_zone = NULL;
772
	gt = &gt0;
773
774
	return &lt;
775
}
776
777
/* start getting lines from a file */
778
void
779
priv_getlines(size_t sz)
780
{
781
	if (priv_fd < 0)
782
		errx(1, "%s called from privileged portion", __func__);
783
784
	write_command(priv_fd, PRIV_GETLINES);
785
	must_write(priv_fd, &sz, sizeof(size_t));
786
}
787
788
int
789
priv_pcap_stats(struct pcap_stat *ps)
790
{
791
	if (priv_fd < 0)
792
		errx(1, "%s: called from privileged portion", __func__);
793
794
	write_command(priv_fd, PRIV_PCAP_STATS);
795
	must_read(priv_fd, ps, sizeof(*ps));
796
	return (0);
797
}
798
799
/* retrieve a line from a file, should be called repeatedly after calling
800
   priv_getlines(), until it returns zero. */
801
size_t
802
priv_getline(char *line, size_t line_len)
803
{
804
	if (priv_fd < 0)
805
		errx(1, "%s called from privileged portion", __func__);
806
807
	/* read the line */
808
	return (read_string(priv_fd, line, line_len, __func__));
809
}
810
811
/* Read all data or return 1 for error. */
812
int
813
may_read(int fd, void *buf, size_t n)
814
{
815
	char *s = buf;
816
	ssize_t res, pos = 0;
817
818
	while (n > pos) {
819
		res = read(fd, s + pos, n - pos);
820
		switch (res) {
821
		case -1:
822
			if (errno == EINTR || errno == EAGAIN)
823
				continue;
824
			/* FALLTHROUGH */
825
		case 0:
826
			return (1);
827
		default:
828
			pos += res;
829
		}
830
	}
831
	return (0);
832
}
833
834
/* Read data with the assertion that it all must come through, or
835
 * else abort the process.  Based on atomicio() from openssh. */
836
void
837
must_read(int fd, void *buf, size_t n)
838
{
839
	char *s = buf;
840
	ssize_t res, pos = 0;
841
842
	while (n > pos) {
843
		res = read(fd, s + pos, n - pos);
844
		switch (res) {
845
		case -1:
846
			if (errno == EINTR || errno == EAGAIN)
847
				continue;
848
			/* FALLTHROUGH */
849
		case 0:
850
			_exit(0);
851
		default:
852
			pos += res;
853
		}
854
	}
855
}
856
857
/* Write data with the assertion that it all has to be written, or
858
 * else abort the process.  Based on atomicio() from openssh. */
859
void
860
must_write(int fd, const void *buf, size_t n)
861
{
862
	const char *s = buf;
863
	ssize_t res, pos = 0;
864
865
	while (n > pos) {
866
		res = write(fd, s + pos, n - pos);
867
		switch (res) {
868
		case -1:
869
			if (errno == EINTR || errno == EAGAIN)
870
				continue;
871
			/* FALLTHROUGH */
872
		case 0:
873
			_exit(0);
874
		default:
875
			pos += res;
876
		}
877
	}
878
}
879
880
/* test for a given state, and possibly increase state */
881
static void
882
test_state(int action, int next)
883
{
884
	if (cur_state < 0 || cur_state > STATE_RUN) {
885
		logmsg(LOG_ERR, "[priv] Invalid state: %d", cur_state);
886
		_exit(1);
887
	}
888
	if ((allowed_max[cur_state] & allowed_ext[cur_state]
889
	    & ALLOW(action)) == 0) {
890
		logmsg(LOG_ERR, "[priv] Invalid action %d in state %d",
891
		    action, cur_state);
892
		_exit(1);
893
	}
894
	if (next < cur_state) {
895
		logmsg(LOG_ERR, "[priv] Invalid next state: %d < %d",
896
		    next, cur_state);
897
		_exit(1);
898
	}
899
900
	cur_state = next;
901
}
902
903
static void
904
logmsg(int pri, const char *message, ...)
905
{
906
	va_list ap;
907
	if (pri > debug_level)
908
		return;
909
	va_start(ap, message);
910
911
	vfprintf(stderr, message, ap);
912
	fprintf(stderr, "\n");
913
	va_end(ap);
914
}
915
916
/* write a command to the peer */
917
void
918
write_command(int fd, int cmd)
919
{
920
	must_write(fd, &cmd, sizeof(cmd));
921
}
922
923
/* write a zero 'length' to signal an error to read_{string|block} */
924
void
925
write_zero(int fd)
926
{
927
	size_t len = 0;
928
	must_write(fd, &len, sizeof(size_t));
929
}
930
931
/* send a string */
932
void
933
write_string(int fd, const char *str)
934
{
935
	size_t len;
936
937
	len = strlen(str) + 1;
938
	must_write(fd, &len, sizeof(size_t));
939
	must_write(fd, str, len);
940
}
941
942
/* send a block of data of given size */
943
void
944
write_block(int fd, size_t size, const char *str)
945
{
946
	must_write(fd, &size, sizeof(size_t));
947
	must_write(fd, str, size);
948
}
949
950
/* read a string from the channel, return 0 if error, or total size of
951
 * the buffer, including the terminating '\0' */
952
size_t
953
read_string(int fd, char *buf, size_t size, const char *func)
954
{
955
	size_t len;
956
957
	len = read_block(fd, buf, size, func);
958
	if (len == 0)
959
		return (0);
960
961
	if (buf[len - 1] != '\0')
962
		errx(1, "%s: received invalid string", func);
963
964
	return (len);
965
}
966
967
/* read a block of data from the channel, return length of data, or 0
968
 * if error */
969
size_t
970
read_block(int fd, char *buf, size_t size, const char *func)
971
{
972
	size_t len;
973
	/* Expect back an integer size, and then a string of that length */
974
	must_read(fd, &len, sizeof(size_t));
975
976
	/* Check there was no error (indicated by a return of 0) */
977
	if (len == 0)
978
		return (0);
979
980
	/* Make sure we aren't overflowing the passed in buffer */
981
	if (size < len)
982
		errx(1, "%s: overflow attempt in return", func);
983
984
	/* Read the string and make sure we got all of it */
985
	must_read(fd, buf, len);
986
	return (len);
987
}