1 /* $OpenBSD: privsep.c,v 1.29 2011/04/03 21:11:27 stsp 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 24 #include <net/bpf.h> 25 #include <net/if.h> 26 #include <net/pfvar.h> 27 #include <netinet/in.h> 28 #include <netinet/if_ether.h> 29 30 #include <rpc/rpc.h> 31 32 #include <err.h> 33 #include <errno.h> 34 #include <fcntl.h> 35 #include <locale.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 <tzfile.h> 46 #include <unistd.h> 47 48 #include "interface.h" 49 #include "privsep.h" 50 #include "pfctl_parser.h" 51 52 /* 53 * tcpdump goes through four states: STATE_INIT is where the 54 * bpf device and the input file is opened. In STATE_BPF, the 55 * pcap filter gets set. STATE_FILTER is used for parsing 56 * /etc/services and /etc/protocols and opening the output 57 * file. STATE_RUN is the packet processing part. 58 */ 59 60 enum priv_state { 61 STATE_INIT, /* initial state */ 62 STATE_BPF, /* input file/device opened */ 63 STATE_FILTER, /* filter applied */ 64 STATE_RUN /* running and accepting network traffic */ 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) 82 }; 83 84 /* 85 * Default set of allowed actions. More actions get added 86 * later depending on the supplied parameters. 87 */ 88 static int allowed_ext[] = { 89 /* INIT */ ALLOW(PRIV_SETFILTER), 90 /* BPF */ ALLOW(PRIV_SETFILTER), 91 /* FILTER */ ALLOW(PRIV_GETSERVENTRIES), 92 /* RUN */ ALLOW(PRIV_GETLINES) | ALLOW(PRIV_LOCALTIME) 93 }; 94 95 struct ftab { 96 char *name; 97 int max; 98 int count; 99 }; 100 101 static struct ftab file_table[] = {{"/etc/appletalk.names", 1, 0}, 102 {PF_OSFP_FILE, 1, 0}}; 103 104 #define NUM_FILETAB (sizeof(file_table) / sizeof(struct ftab)) 105 106 int debug_level = LOG_INFO; 107 int priv_fd = -1; 108 volatile pid_t child_pid = -1; 109 static volatile sig_atomic_t cur_state = STATE_INIT; 110 111 extern void set_slave_signals(void); 112 113 static void impl_open_bpf(int, int *); 114 static void impl_open_dump(int, const char *); 115 static void impl_open_output(int, const char *); 116 static void impl_setfilter(int, char *, int *); 117 static void impl_init_done(int, int *); 118 static void impl_gethostbyaddr(int); 119 static void impl_ether_ntohost(int); 120 static void impl_getrpcbynumber(int); 121 static void impl_getserventries(int); 122 static void impl_getprotoentries(int); 123 static void impl_localtime(int fd); 124 static void impl_getlines(int); 125 126 static void test_state(int, int); 127 static void logmsg(int, const char *, ...); 128 129 int 130 priv_init(int argc, char **argv) 131 { 132 int bpfd = -1; 133 int i, socks[2], cmd, nflag = 0; 134 struct passwd *pw; 135 uid_t uid; 136 gid_t gid; 137 char *cmdbuf, *infile = NULL; 138 char *RFileName = NULL; 139 char *WFileName = NULL; 140 sigset_t allsigs, oset; 141 142 if (geteuid() != 0) 143 errx(1, "need root privileges"); 144 145 closefrom(STDERR_FILENO + 1); 146 for (i = 1; i < _NSIG; i++) 147 signal(i, SIG_DFL); 148 149 /* Create sockets */ 150 if (socketpair(AF_LOCAL, SOCK_STREAM, PF_UNSPEC, socks) == -1) 151 err(1, "socketpair() failed"); 152 153 sigfillset(&allsigs); 154 sigprocmask(SIG_BLOCK, &allsigs, &oset); 155 156 child_pid = fork(); 157 if (child_pid < 0) 158 err(1, "fork() failed"); 159 160 if (child_pid) { 161 /* Parent, drop privileges to _tcpdump */ 162 pw = getpwnam("_tcpdump"); 163 if (pw == NULL) 164 errx(1, "unknown user _tcpdump"); 165 166 /* set the locale before chrooting */ 167 (void)setlocale(LC_CTYPE, ""); 168 169 /* chroot, drop privs and return */ 170 if (chroot(pw->pw_dir) != 0) 171 err(1, "unable to chroot"); 172 if (chdir("/") != 0) 173 err(1, "unable to chdir"); 174 175 /* drop to _tcpdump */ 176 if (setgroups(1, &pw->pw_gid) == -1) 177 err(1, "setgroups() failed"); 178 if (setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) == -1) 179 err(1, "setresgid() failed"); 180 if (setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid) == -1) 181 err(1, "setresuid() failed"); 182 endpwent(); 183 184 close(socks[0]); 185 priv_fd = socks[1]; 186 187 set_slave_signals(); 188 sigprocmask(SIG_SETMASK, &oset, NULL); 189 190 return (0); 191 } 192 193 sigprocmask(SIG_SETMASK, &oset, NULL); 194 195 /* Child - drop suid privileges */ 196 gid = getgid(); 197 uid = getuid(); 198 199 if (setresgid(gid, gid, gid) == -1) 200 err(1, "setresgid() failed"); 201 if (setresuid(uid, uid, uid) == -1) 202 err(1, "setresuid() failed"); 203 204 /* parse the arguments for required options */ 205 opterr = 0; 206 while ((i = getopt(argc, argv, 207 "ac:D:deE:fF:i:lLnNOopqr:s:StT:vw:xXy:Y")) != -1) { 208 switch (i) { 209 case 'n': 210 nflag++; 211 break; 212 213 case 'r': 214 RFileName = optarg; 215 break; 216 217 case 'w': 218 WFileName = optarg; 219 break; 220 221 case 'F': 222 infile = optarg; 223 break; 224 225 default: 226 /* nothing */ 227 break; 228 } 229 } 230 231 if (RFileName != NULL) { 232 if (strcmp(RFileName, "-") != 0) 233 allowed_ext[STATE_INIT] |= ALLOW(PRIV_OPEN_DUMP); 234 } else 235 allowed_ext[STATE_INIT] |= ALLOW(PRIV_OPEN_BPF); 236 if (WFileName != NULL) { 237 if (strcmp(WFileName, "-") != 0) 238 allowed_ext[STATE_FILTER] |= ALLOW(PRIV_OPEN_OUTPUT); 239 else 240 allowed_ext[STATE_FILTER] |= ALLOW(PRIV_INIT_DONE); 241 } else 242 allowed_ext[STATE_FILTER] |= ALLOW(PRIV_INIT_DONE); 243 if (!nflag) { 244 allowed_ext[STATE_RUN] |= ALLOW(PRIV_GETHOSTBYADDR); 245 allowed_ext[STATE_FILTER] |= ALLOW(PRIV_ETHER_NTOHOST); 246 allowed_ext[STATE_RUN] |= ALLOW(PRIV_ETHER_NTOHOST); 247 allowed_ext[STATE_RUN] |= ALLOW(PRIV_GETRPCBYNUMBER); 248 allowed_ext[STATE_FILTER] |= ALLOW(PRIV_GETPROTOENTRIES); 249 } 250 251 if (infile) 252 cmdbuf = read_infile(infile); 253 else 254 cmdbuf = copy_argv(&argv[optind]); 255 256 setproctitle("[priv]"); 257 close(socks[1]); 258 259 for (;;) { 260 if (may_read(socks[0], &cmd, sizeof(int))) 261 break; 262 switch (cmd) { 263 case PRIV_OPEN_BPF: 264 test_state(cmd, STATE_BPF); 265 impl_open_bpf(socks[0], &bpfd); 266 break; 267 case PRIV_OPEN_DUMP: 268 test_state(cmd, STATE_BPF); 269 impl_open_dump(socks[0], RFileName); 270 break; 271 case PRIV_OPEN_OUTPUT: 272 test_state(cmd, STATE_RUN); 273 impl_open_output(socks[0], WFileName); 274 break; 275 case PRIV_SETFILTER: 276 test_state(cmd, STATE_FILTER); 277 impl_setfilter(socks[0], cmdbuf, &bpfd); 278 break; 279 case PRIV_INIT_DONE: 280 test_state(cmd, STATE_RUN); 281 impl_init_done(socks[0], &bpfd); 282 break; 283 case PRIV_GETHOSTBYADDR: 284 test_state(cmd, STATE_RUN); 285 impl_gethostbyaddr(socks[0]); 286 break; 287 case PRIV_ETHER_NTOHOST: 288 test_state(cmd, cur_state); 289 impl_ether_ntohost(socks[0]); 290 break; 291 case PRIV_GETRPCBYNUMBER: 292 test_state(cmd, STATE_RUN); 293 impl_getrpcbynumber(socks[0]); 294 break; 295 case PRIV_GETSERVENTRIES: 296 test_state(cmd, STATE_FILTER); 297 impl_getserventries(socks[0]); 298 break; 299 case PRIV_GETPROTOENTRIES: 300 test_state(cmd, STATE_FILTER); 301 impl_getprotoentries(socks[0]); 302 break; 303 case PRIV_LOCALTIME: 304 test_state(cmd, STATE_RUN); 305 impl_localtime(socks[0]); 306 break; 307 case PRIV_GETLINES: 308 test_state(cmd, STATE_RUN); 309 impl_getlines(socks[0]); 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 close(*bpfd); /* done with bpf descriptor */ 399 *bpfd = -1; 400 } 401 402 static void 403 impl_init_done(int fd, int *bpfd) 404 { 405 int ret; 406 407 logmsg(LOG_DEBUG, "[priv]: msg PRIV_INIT_DONE received"); 408 409 close(*bpfd); /* done with bpf descriptor */ 410 *bpfd = -1; 411 ret = 0; 412 must_write(fd, &ret, sizeof(ret)); 413 } 414 415 static void 416 impl_gethostbyaddr(int fd) 417 { 418 char hostname[MAXHOSTNAMELEN]; 419 size_t hostname_len; 420 int addr_af; 421 struct hostent *hp; 422 423 logmsg(LOG_DEBUG, "[priv]: msg PRIV_GETHOSTBYADDR received"); 424 425 /* Expecting: address block, address family */ 426 hostname_len = read_block(fd, hostname, sizeof(hostname), __func__); 427 if (hostname_len == 0) 428 _exit(1); 429 must_read(fd, &addr_af, sizeof(int)); 430 hp = gethostbyaddr(hostname, hostname_len, addr_af); 431 if (hp == NULL) 432 write_zero(fd); 433 else 434 write_string(fd, hp->h_name); 435 } 436 437 static void 438 impl_ether_ntohost(int fd) 439 { 440 struct ether_addr ether; 441 char hostname[MAXHOSTNAMELEN]; 442 443 logmsg(LOG_DEBUG, "[priv]: msg PRIV_ETHER_NTOHOST received"); 444 445 /* Expecting: ethernet address */ 446 must_read(fd, ðer, sizeof(ether)); 447 if (ether_ntohost(hostname, ðer) == -1) 448 write_zero(fd); 449 else 450 write_string(fd, hostname); 451 } 452 453 static void 454 impl_getrpcbynumber(int fd) 455 { 456 int rpc; 457 struct rpcent *rpce; 458 459 logmsg(LOG_DEBUG, "[priv]: msg PRIV_GETRPCBYNUMBER received"); 460 461 must_read(fd, &rpc, sizeof(int)); 462 rpce = getrpcbynumber(rpc); 463 if (rpce == NULL) 464 write_zero(fd); 465 else 466 write_string(fd, rpce->r_name); 467 } 468 469 static void 470 impl_getserventries(int fd) 471 { 472 struct servent *sp; 473 474 logmsg(LOG_DEBUG, "[priv]: msg PRIV_GETSERVENTRIES received"); 475 476 for (;;) { 477 sp = getservent(); 478 if (sp == NULL) { 479 write_zero(fd); 480 break; 481 } else { 482 write_string(fd, sp->s_name); 483 must_write(fd, &sp->s_port, sizeof(int)); 484 write_string(fd, sp->s_proto); 485 } 486 } 487 endservent(); 488 } 489 490 static void 491 impl_getprotoentries(int fd) 492 { 493 struct protoent *pe; 494 495 logmsg(LOG_DEBUG, "[priv]: msg PRIV_GETPROTOENTRIES received"); 496 497 for (;;) { 498 pe = getprotoent(); 499 if (pe == NULL) { 500 write_zero(fd); 501 break; 502 } else { 503 write_string(fd, pe->p_name); 504 must_write(fd, &pe->p_proto, sizeof(int)); 505 } 506 } 507 endprotoent(); 508 } 509 510 /* read the time and send the corresponding localtime and gmtime 511 * results back to the unprivileged process */ 512 static void 513 impl_localtime(int fd) 514 { 515 struct tm *lt, *gt; 516 time_t t; 517 518 logmsg(LOG_DEBUG, "[priv]: msg PRIV_LOCALTIME received"); 519 520 must_read(fd, &t, sizeof(time_t)); 521 522 /* this must be done separately, since they apparently use the 523 * same local buffer */ 524 if ((lt = localtime(&t)) == NULL) 525 errx(1, "localtime()"); 526 must_write(fd, lt, sizeof(*lt)); 527 528 if ((gt = gmtime(&t)) == NULL) 529 errx(1, "gmtime()"); 530 must_write(fd, gt, sizeof(*gt)); 531 532 if (lt->tm_zone == NULL) 533 write_zero(fd); 534 else 535 write_string(fd, lt->tm_zone); 536 } 537 538 static void 539 impl_getlines(int fd) 540 { 541 FILE *fp; 542 char *buf, *lbuf, *file; 543 size_t len, fid; 544 545 logmsg(LOG_DEBUG, "[priv]: msg PRIV_GETLINES received"); 546 547 must_read(fd, &fid, sizeof(size_t)); 548 if (fid >= NUM_FILETAB) 549 errx(1, "invalid file id"); 550 551 file = file_table[fid].name; 552 553 if (file == NULL) 554 errx(1, "invalid file referenced"); 555 556 if (file_table[fid].count >= file_table[fid].max) 557 errx(1, "maximum open count exceeded for %s", file); 558 559 file_table[fid].count++; 560 561 if ((fp = fopen(file, "r")) == NULL) { 562 write_zero(fd); 563 return; 564 } 565 566 lbuf = NULL; 567 while ((buf = fgetln(fp, &len))) { 568 if (buf[len - 1] == '\n') 569 buf[len - 1] = '\0'; 570 else { 571 if ((lbuf = (char *)malloc(len + 1)) == NULL) 572 err(1, NULL); 573 memcpy(lbuf, buf, len); 574 lbuf[len] = '\0'; 575 buf = lbuf; 576 } 577 578 write_string(fd, buf); 579 580 if (lbuf != NULL) { 581 free(lbuf); 582 lbuf = NULL; 583 } 584 } 585 write_zero(fd); 586 fclose(fp); 587 } 588 589 void 590 priv_init_done(void) 591 { 592 int ret; 593 594 if (priv_fd < 0) 595 errx(1, "%s: called from privileged portion", __func__); 596 597 write_command(priv_fd, PRIV_INIT_DONE); 598 must_read(priv_fd, &ret, sizeof(int)); 599 } 600 601 /* Reverse address resolution; response is placed into res, and length of 602 * response is returned (zero on error) */ 603 size_t 604 priv_gethostbyaddr(char *addr, size_t addr_len, int af, char *res, size_t res_len) 605 { 606 if (priv_fd < 0) 607 errx(1, "%s called from privileged portion", __func__); 608 609 write_command(priv_fd, PRIV_GETHOSTBYADDR); 610 write_block(priv_fd, addr_len, addr); 611 must_write(priv_fd, &af, sizeof(int)); 612 613 return (read_string(priv_fd, res, res_len, __func__)); 614 } 615 616 size_t 617 priv_ether_ntohost(char *name, size_t name_len, struct ether_addr *e) 618 { 619 if (priv_fd < 0) 620 errx(1, "%s called from privileged portion", __func__); 621 622 write_command(priv_fd, PRIV_ETHER_NTOHOST); 623 must_write(priv_fd, e, sizeof(*e)); 624 625 /* Read the host name */ 626 return (read_string(priv_fd, name, name_len, __func__)); 627 } 628 629 size_t 630 priv_getrpcbynumber(int rpc, char *progname, size_t progname_len) 631 { 632 if (priv_fd < 0) 633 errx(1, "%s called from privileged portion", __func__); 634 635 write_command(priv_fd, PRIV_GETRPCBYNUMBER); 636 must_write(priv_fd, &rpc, sizeof(int)); 637 638 return read_string(priv_fd, progname, progname_len, __func__); 639 } 640 641 /* start getting service entries */ 642 void 643 priv_getserventries(void) 644 { 645 if (priv_fd < 0) 646 errx(1, "%s called from privileged portion", __func__); 647 648 write_command(priv_fd, PRIV_GETSERVENTRIES); 649 } 650 651 /* retrieve a service entry, should be called repeatedly after calling 652 priv_getserventries(), until it returns zero. */ 653 size_t 654 priv_getserventry(char *name, size_t name_len, int *port, char *prot, 655 size_t prot_len) 656 { 657 if (priv_fd < 0) 658 errx(1, "%s called from privileged portion", __func__); 659 660 /* read the service name */ 661 if (read_string(priv_fd, name, name_len, __func__) == 0) 662 return 0; 663 664 /* read the port */ 665 must_read(priv_fd, port, sizeof(int)); 666 667 /* read the protocol */ 668 return (read_string(priv_fd, prot, prot_len, __func__)); 669 } 670 671 /* start getting ip protocol entries */ 672 void 673 priv_getprotoentries(void) 674 { 675 if (priv_fd < 0) 676 errx(1, "%s called from privileged portion", __func__); 677 678 write_command(priv_fd, PRIV_GETPROTOENTRIES); 679 } 680 681 /* retrieve a ip protocol entry, should be called repeatedly after calling 682 priv_getprotoentries(), until it returns zero. */ 683 size_t 684 priv_getprotoentry(char *name, size_t name_len, int *num) 685 { 686 if (priv_fd < 0) 687 errx(1, "%s called from privileged portion", __func__); 688 689 /* read the proto name */ 690 if (read_string(priv_fd, name, name_len, __func__) == 0) 691 return 0; 692 693 /* read the num */ 694 must_read(priv_fd, num, sizeof(int)); 695 696 return (1); 697 } 698 699 /* localtime() replacement: ask the privileged process for localtime and 700 * gmtime, cache the localtime for about one minute i.e. until one of the 701 * fields other than seconds changes. The check is done using gmtime 702 * values since they are the same in parent and child. */ 703 struct tm * 704 priv_localtime(const time_t *t) 705 { 706 static struct tm lt, gt0; 707 static struct tm *gt = NULL; 708 static char zone[TZ_MAX_CHARS]; 709 710 if (gt != NULL) { 711 gt = gmtime(t); 712 gt0.tm_sec = gt->tm_sec; 713 gt0.tm_zone = gt->tm_zone; 714 715 if (memcmp(gt, >0, sizeof(struct tm)) == 0) { 716 lt.tm_sec = gt0.tm_sec; 717 return < 718 } 719 } 720 721 write_command(priv_fd, PRIV_LOCALTIME); 722 must_write(priv_fd, t, sizeof(time_t)); 723 must_read(priv_fd, <, sizeof(lt)); 724 must_read(priv_fd, >0, sizeof(gt0)); 725 726 if (read_string(priv_fd, zone, sizeof(zone), __func__)) 727 lt.tm_zone = zone; 728 else 729 lt.tm_zone = NULL; 730 731 gt0.tm_zone = NULL; 732 gt = >0; 733 734 return < 735 } 736 737 /* start getting lines from a file */ 738 void 739 priv_getlines(size_t sz) 740 { 741 if (priv_fd < 0) 742 errx(1, "%s called from privileged portion", __func__); 743 744 write_command(priv_fd, PRIV_GETLINES); 745 must_write(priv_fd, &sz, sizeof(size_t)); 746 } 747 748 /* retrieve a line from a file, should be called repeatedly after calling 749 priv_getlines(), until it returns zero. */ 750 size_t 751 priv_getline(char *line, size_t line_len) 752 { 753 if (priv_fd < 0) 754 errx(1, "%s called from privileged portion", __func__); 755 756 /* read the line */ 757 return (read_string(priv_fd, line, line_len, __func__)); 758 } 759 760 /* Read all data or return 1 for error. */ 761 int 762 may_read(int fd, void *buf, size_t n) 763 { 764 char *s = buf; 765 ssize_t res, pos = 0; 766 767 while (n > pos) { 768 res = read(fd, s + pos, n - pos); 769 switch (res) { 770 case -1: 771 if (errno == EINTR || errno == EAGAIN) 772 continue; 773 /* FALLTHROUGH */ 774 case 0: 775 return (1); 776 default: 777 pos += res; 778 } 779 } 780 return (0); 781 } 782 783 /* Read data with the assertion that it all must come through, or 784 * else abort the process. Based on atomicio() from openssh. */ 785 void 786 must_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 _exit(0); 800 default: 801 pos += res; 802 } 803 } 804 } 805 806 /* Write data with the assertion that it all has to be written, or 807 * else abort the process. Based on atomicio() from openssh. */ 808 void 809 must_write(int fd, const void *buf, size_t n) 810 { 811 const char *s = buf; 812 ssize_t res, pos = 0; 813 814 while (n > pos) { 815 res = write(fd, s + pos, n - pos); 816 switch (res) { 817 case -1: 818 if (errno == EINTR || errno == EAGAIN) 819 continue; 820 /* FALLTHROUGH */ 821 case 0: 822 _exit(0); 823 default: 824 pos += res; 825 } 826 } 827 } 828 829 /* test for a given state, and possibly increase state */ 830 static void 831 test_state(int action, int next) 832 { 833 if (cur_state < 0 || cur_state > STATE_RUN) { 834 logmsg(LOG_ERR, "[priv] Invalid state: %d", cur_state); 835 _exit(1); 836 } 837 if ((allowed_max[cur_state] & allowed_ext[cur_state] 838 & ALLOW(action)) == 0) { 839 logmsg(LOG_ERR, "[priv] Invalid action %d in state %d", 840 action, cur_state); 841 _exit(1); 842 } 843 if (next < cur_state) { 844 logmsg(LOG_ERR, "[priv] Invalid next state: %d < %d", 845 next, cur_state); 846 _exit(1); 847 } 848 849 cur_state = next; 850 } 851 852 static void 853 logmsg(int pri, const char *message, ...) 854 { 855 va_list ap; 856 if (pri > debug_level) 857 return; 858 va_start(ap, message); 859 860 vfprintf(stderr, message, ap); 861 fprintf(stderr, "\n"); 862 va_end(ap); 863 } 864 865 /* write a command to the peer */ 866 void 867 write_command(int fd, int cmd) 868 { 869 must_write(fd, &cmd, sizeof(cmd)); 870 } 871 872 /* write a zero 'length' to signal an error to read_{string|block} */ 873 void 874 write_zero(int fd) 875 { 876 size_t len = 0; 877 must_write(fd, &len, sizeof(size_t)); 878 } 879 880 /* send a string */ 881 void 882 write_string(int fd, const char *str) 883 { 884 size_t len; 885 886 len = strlen(str) + 1; 887 must_write(fd, &len, sizeof(size_t)); 888 must_write(fd, str, len); 889 } 890 891 /* send a block of data of given size */ 892 void 893 write_block(int fd, size_t size, const char *str) 894 { 895 must_write(fd, &size, sizeof(size_t)); 896 must_write(fd, str, size); 897 } 898 899 /* read a string from the channel, return 0 if error, or total size of 900 * the buffer, including the terminating '\0' */ 901 size_t 902 read_string(int fd, char *buf, size_t size, const char *func) 903 { 904 size_t len; 905 906 len = read_block(fd, buf, size, func); 907 if (len == 0) 908 return (0); 909 910 if (buf[len - 1] != '\0') 911 errx(1, "%s: received invalid string", func); 912 913 return (len); 914 } 915 916 /* read a block of data from the channel, return length of data, or 0 917 * if error */ 918 size_t 919 read_block(int fd, char *buf, size_t size, const char *func) 920 { 921 size_t len; 922 /* Expect back an integer size, and then a string of that length */ 923 must_read(fd, &len, sizeof(size_t)); 924 925 /* Check there was no error (indicated by a return of 0) */ 926 if (len == 0) 927 return (0); 928 929 /* Make sure we aren't overflowing the passed in buffer */ 930 if (size < len) 931 errx(1, "%s: overflow attempt in return", func); 932 933 /* Read the string and make sure we got all of it */ 934 must_read(fd, buf, len); 935 return (len); 936 } 937