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, ðer, sizeof(ether));
505 if (ether_ntohost(hostname, ðer) == -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, >0, sizeof(struct tm)) == 0) {
736 lt.tm_sec = gt0.tm_sec;
737 return <
738 }
739 }
740
741 write_command(priv_fd, PRIV_LOCALTIME);
742 must_write(priv_fd, t, sizeof(time_t));
743 must_read(priv_fd, <, sizeof(lt));
744 must_read(priv_fd, >0, 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 = >0;
753
754 return <
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