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