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