1 /* $OpenBSD: tftp-proxy.c,v 1.7 2013/12/23 11:45:39 benno Exp $ 2 * 3 * Copyright (c) 2005 DLS Internet Services 4 * Copyright (c) 2004, 2005 Camiel Dobbelaar, <cd@sentia.nl> 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. The name of the author may not be used to endorse or promote products 16 * derived from this software without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 */ 29 30 #include <sys/ioctl.h> 31 #include <sys/param.h> 32 #include <sys/types.h> 33 #include <sys/socket.h> 34 #include <sys/uio.h> 35 36 #include <netinet/in.h> 37 #include <arpa/inet.h> 38 #include <arpa/tftp.h> 39 #include <net/if.h> 40 #include <net/pfvar.h> 41 #include <netdb.h> 42 43 #include <unistd.h> 44 #include <errno.h> 45 #include <err.h> 46 #include <pwd.h> 47 #include <stdio.h> 48 #include <syslog.h> 49 #include <string.h> 50 #include <stdlib.h> 51 #include <event.h> 52 53 #include "filter.h" 54 55 #define CHROOT_DIR "/var/empty" 56 #define NOPRIV_USER "proxy" 57 58 #define DEFTRANSWAIT 2 59 #define NTOP_BUFS 4 60 #define PKTSIZE SEGSIZE+4 61 62 const char *opcode(int); 63 const char *sock_ntop(struct sockaddr *); 64 static void usage(void); 65 66 struct proxy_listener { 67 struct event ev; 68 TAILQ_ENTRY(proxy_listener) entry; 69 int (*cmsg2dst)(struct cmsghdr *, struct sockaddr_storage *); 70 int s; 71 }; 72 73 void proxy_listen(const char *, const char *, int); 74 void proxy_listener_events(void); 75 int proxy_dst4(struct cmsghdr *, struct sockaddr_storage *); 76 int proxy_dst6(struct cmsghdr *, struct sockaddr_storage *); 77 void proxy_recv(int, short, void *); 78 79 struct fd_reply { 80 TAILQ_ENTRY(fd_reply) entry; 81 int fd; 82 }; 83 84 struct privproc { 85 struct event pop_ev; 86 struct event push_ev; 87 TAILQ_HEAD(, fd_reply) replies; 88 struct evbuffer *buf; 89 }; 90 91 void proxy_privproc(int, struct passwd *); 92 void privproc_push(int, short, void *); 93 void privproc_pop(int, short, void *); 94 95 void unprivproc_push(int, short, void *); 96 void unprivproc_pop(int, short, void *); 97 void unprivproc_timeout(int, short, void *); 98 99 char ntop_buf[NTOP_BUFS][INET6_ADDRSTRLEN]; 100 101 struct loggers { 102 void (*err)(int, const char *, ...); 103 void (*errx)(int, const char *, ...); 104 void (*warn)(const char *, ...); 105 void (*warnx)(const char *, ...); 106 void (*info)(const char *, ...); 107 }; 108 109 const struct loggers conslogger = { 110 err, 111 errx, 112 warn, 113 warnx, 114 warnx 115 }; 116 117 void syslog_err(int, const char *, ...); 118 void syslog_errx(int, const char *, ...); 119 void syslog_warn(const char *, ...); 120 void syslog_warnx(const char *, ...); 121 void syslog_info(const char *, ...); 122 void syslog_vstrerror(int, int, const char *, va_list); 123 124 const struct loggers syslogger = { 125 syslog_err, 126 syslog_errx, 127 syslog_warn, 128 syslog_warnx, 129 syslog_info, 130 }; 131 132 const struct loggers *logger = &conslogger; 133 134 #define lerr(_e, _f...) logger->err((_e), _f) 135 #define lerrx(_e, _f...) logger->errx((_e), _f) 136 #define lwarn(_f...) logger->warn(_f) 137 #define lwarnx(_f...) logger->warnx(_f) 138 #define linfo(_f...) logger->info(_f) 139 140 __dead void 141 usage(void) 142 { 143 extern char *__progname; 144 fprintf(stderr, "usage: %s [-46dv] [-l address] [-p port]" 145 " [-w transwait]\n", __progname); 146 exit(1); 147 } 148 149 int debug = 0; 150 int verbose = 0; 151 struct timeval transwait = { DEFTRANSWAIT, 0 }; 152 153 int on = 1; 154 155 struct addr_pair { 156 struct sockaddr_storage src; 157 struct sockaddr_storage dst; 158 }; 159 160 struct proxy_request { 161 char buf[SEGSIZE_MAX + 4]; 162 size_t buflen; 163 164 struct addr_pair addrs; 165 166 struct event ev; 167 TAILQ_ENTRY(proxy_request) entry; 168 u_int32_t id; 169 }; 170 171 struct proxy_child { 172 TAILQ_HEAD(, proxy_request) fdrequests; 173 TAILQ_HEAD(, proxy_request) tmrequests; 174 struct event push_ev; 175 struct event pop_ev; 176 struct evbuffer *buf; 177 }; 178 179 struct proxy_child *child = NULL; 180 TAILQ_HEAD(, proxy_listener) proxy_listeners; 181 182 int 183 main(int argc, char *argv[]) 184 { 185 extern char *__progname; 186 187 int c; 188 const char *errstr; 189 190 struct passwd *pw; 191 192 char *addr = "localhost"; 193 char *port = "6969"; 194 int family = AF_UNSPEC; 195 196 int pair[2]; 197 198 while ((c = getopt(argc, argv, "46dvl:p:w:")) != -1) { 199 switch (c) { 200 case '4': 201 family = AF_INET; 202 break; 203 case '6': 204 family = AF_INET6; 205 break; 206 case 'd': 207 verbose = debug = 1; 208 break; 209 case 'l': 210 addr = optarg; 211 break; 212 case 'p': 213 port = optarg; 214 break; 215 case 'v': 216 verbose = 1; 217 break; 218 case 'w': 219 transwait.tv_sec = strtonum(optarg, 1, 30, &errstr); 220 if (errstr) 221 errx(1, "wait is %s", errstr); 222 break; 223 default: 224 usage(); 225 /* NOTREACHED */ 226 } 227 } 228 229 if (geteuid() != 0) 230 errx(1, "need root privileges"); 231 232 if (!debug && daemon(1, 0) == -1) 233 err(1, "daemon"); 234 235 if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, pair) == -1) 236 lerr(1, "socketpair"); 237 238 pw = getpwnam(NOPRIV_USER); 239 if (pw == NULL) 240 lerrx(1, "no %s user", NOPRIV_USER); 241 242 switch (fork()) { 243 case -1: 244 lerr(1, "fork"); 245 246 case 0: 247 setproctitle("privproc"); 248 close(pair[1]); 249 proxy_privproc(pair[0], pw); 250 /* this never returns */ 251 252 default: 253 setproctitle("unprivproc"); 254 close(pair[0]); 255 break; 256 } 257 258 child = calloc(1, sizeof(*child)); 259 if (child == NULL) 260 lerr(1, "alloc(child)"); 261 262 child->buf = evbuffer_new(); 263 if (child->buf == NULL) 264 lerr(1, "child evbuffer"); 265 266 TAILQ_INIT(&child->fdrequests); 267 TAILQ_INIT(&child->tmrequests); 268 269 if (!debug) { 270 openlog(__progname, LOG_PID|LOG_NDELAY, LOG_DAEMON); 271 tzset(); 272 logger = &syslogger; 273 } 274 275 proxy_listen(addr, port, family); 276 277 /* open /dev/pf */ 278 init_filter(NULL, verbose); 279 280 /* revoke privs */ 281 pw = getpwnam(NOPRIV_USER); 282 if (!pw) 283 lerrx(1, "no such user %s", NOPRIV_USER); 284 285 if (chroot(CHROOT_DIR) == -1) 286 lerr(1, "chroot %s", CHROOT_DIR); 287 288 if (chdir("/") == -1) 289 lerr(1, "chdir %s", CHROOT_DIR); 290 291 if (setgroups(1, &pw->pw_gid) || 292 setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) || 293 setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid)) 294 err(1, "unable to revoke privs"); 295 296 event_init(); 297 298 proxy_listener_events(); 299 300 if (ioctl(pair[1], FIONBIO, &on) == -1) 301 lerr(1, "ioctl(FIONBIO)"); 302 303 event_set(&child->pop_ev, pair[1], EV_READ | EV_PERSIST, 304 unprivproc_pop, NULL); 305 event_set(&child->push_ev, pair[1], EV_WRITE, 306 unprivproc_push, NULL); 307 308 event_add(&child->pop_ev, NULL); 309 310 event_dispatch(); 311 312 return(0); 313 } 314 315 316 void 317 proxy_privproc(int s, struct passwd *pw) 318 { 319 extern char *__progname; 320 struct privproc p; 321 322 if (!debug) { 323 openlog(__progname, LOG_PID|LOG_NDELAY, LOG_DAEMON); 324 tzset(); 325 logger = &syslogger; 326 } 327 328 if (ioctl(s, FIONBIO, &on) == -1) 329 lerr(1, "ioctl(FIONBIO)"); 330 331 if (chroot(CHROOT_DIR) == -1) 332 lerr(1, "chroot to %s", CHROOT_DIR); 333 334 if (chdir("/") == -1) 335 lerr(1, "chdir to %s", CHROOT_DIR); 336 337 if (setgroups(1, &pw->pw_gid) || 338 setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid)) 339 lerr(1, "unable to set group ids"); 340 341 TAILQ_INIT(&p.replies); 342 343 p.buf = evbuffer_new(); 344 if (p.buf == NULL) 345 err(1, "pop evbuffer_new"); 346 347 event_init(); 348 349 event_set(&p.pop_ev, s, EV_READ | EV_PERSIST, privproc_pop, &p); 350 event_set(&p.push_ev, s, EV_WRITE, privproc_push, &p); 351 352 event_add(&p.pop_ev, NULL); 353 354 event_dispatch(); 355 } 356 357 void 358 privproc_pop(int fd, short events, void *arg) 359 { 360 struct addr_pair req; 361 struct privproc *p = arg; 362 struct fd_reply *rep; 363 int add = 0; 364 365 switch (evbuffer_read(p->buf, fd, sizeof(req))) { 366 case 0: 367 lerrx(1, "unprivproc has gone"); 368 case -1: 369 switch (errno) { 370 case EAGAIN: 371 case EINTR: 372 return; 373 default: 374 lerr(1, "privproc_pop read"); 375 } 376 default: 377 break; 378 } 379 380 while (EVBUFFER_LENGTH(p->buf) >= sizeof(req)) { 381 evbuffer_remove(p->buf, &req, sizeof(req)); 382 383 /* do i really need to check this? */ 384 if (req.src.ss_family != req.dst.ss_family) 385 lerrx(1, "family mismatch"); 386 387 rep = calloc(1, sizeof(*rep)); 388 if (rep == NULL) 389 lerr(1, "reply calloc"); 390 391 rep->fd = socket(req.src.ss_family, SOCK_DGRAM, IPPROTO_UDP); 392 if (rep->fd == -1) 393 lerr(1, "privproc socket"); 394 395 if (ioctl(rep->fd, FIONBIO, &on) == -1) 396 err(1, "privproc ioctl(FIONBIO)"); 397 398 if (setsockopt(rep->fd, SOL_SOCKET, SO_BINDANY, 399 &on, sizeof(on)) == -1) 400 lerr(1, "privproc setsockopt(BINDANY)"); 401 402 if (setsockopt(rep->fd, SOL_SOCKET, SO_REUSEADDR, 403 &on, sizeof(on)) == -1) 404 lerr(1, "privproc setsockopt(REUSEADDR)"); 405 406 if (setsockopt(rep->fd, SOL_SOCKET, SO_REUSEPORT, 407 &on, sizeof(on)) == -1) 408 lerr(1, "privproc setsockopt(REUSEPORT)"); 409 410 if (bind(rep->fd, (struct sockaddr *)&req.src, 411 req.src.ss_len) == -1) 412 lerr(1, "privproc bind"); 413 414 if (TAILQ_EMPTY(&p->replies)) 415 add = 1; 416 417 TAILQ_INSERT_TAIL(&p->replies, rep, entry); 418 } 419 420 if (add) 421 event_add(&p->push_ev, NULL); 422 } 423 424 void 425 privproc_push(int fd, short events, void *arg) 426 { 427 struct privproc *p = arg; 428 struct fd_reply *rep; 429 430 struct msghdr msg; 431 union { 432 struct cmsghdr hdr; 433 char buf[CMSG_SPACE(sizeof(int))]; 434 } cmsgbuf; 435 struct cmsghdr *cmsg; 436 struct iovec iov; 437 int result = 0; 438 439 while ((rep = TAILQ_FIRST(&p->replies)) != NULL) { 440 memset(&msg, 0, sizeof(msg)); 441 442 msg.msg_control = (caddr_t)&cmsgbuf.buf; 443 msg.msg_controllen = sizeof(cmsgbuf.buf); 444 cmsg = CMSG_FIRSTHDR(&msg); 445 cmsg->cmsg_len = CMSG_LEN(sizeof(int)); 446 cmsg->cmsg_level = SOL_SOCKET; 447 cmsg->cmsg_type = SCM_RIGHTS; 448 *(int *)CMSG_DATA(cmsg) = rep->fd; 449 450 iov.iov_base = &result; 451 iov.iov_len = sizeof(int); 452 msg.msg_iov = &iov; 453 msg.msg_iovlen = 1; 454 455 switch (sendmsg(fd, &msg, 0)) { 456 case sizeof(int): 457 break; 458 459 case -1: 460 if (errno == EAGAIN) 461 goto again; 462 463 lerr(1, "privproc sendmsg"); 464 /* NOTREACHED */ 465 466 default: 467 lerrx(1, "privproc sendmsg weird len"); 468 } 469 470 TAILQ_REMOVE(&p->replies, rep, entry); 471 close(rep->fd); 472 free(rep); 473 } 474 475 if (TAILQ_EMPTY(&p->replies)) 476 return; 477 478 again: 479 event_add(&p->push_ev, NULL); 480 } 481 482 void 483 proxy_listen(const char *addr, const char *port, int family) 484 { 485 struct proxy_listener *l; 486 487 struct addrinfo hints, *res, *res0; 488 int error; 489 int s, on = 1; 490 int serrno; 491 const char *cause = NULL; 492 493 memset(&hints, 0, sizeof(hints)); 494 hints.ai_family = family; 495 hints.ai_socktype = SOCK_DGRAM; 496 hints.ai_flags = AI_PASSIVE; 497 498 TAILQ_INIT(&proxy_listeners); 499 500 error = getaddrinfo(addr, port, &hints, &res0); 501 if (error) 502 errx(1, "%s:%s: %s", addr, port, gai_strerror(error)); 503 504 for (res = res0; res != NULL; res = res->ai_next) { 505 s = socket(res->ai_family, res->ai_socktype, res->ai_protocol); 506 if (s == -1) { 507 cause = "socket"; 508 continue; 509 } 510 511 if (bind(s, res->ai_addr, res->ai_addrlen) == -1) { 512 cause = "bind"; 513 serrno = errno; 514 close(s); 515 errno = serrno; 516 continue; 517 } 518 519 l = calloc(1, sizeof(*l)); 520 if (l == NULL) 521 err(1, "listener alloc"); 522 523 if (ioctl(s, FIONBIO, &on) == -1) 524 err(1, "ioctl(FIONBIO)"); 525 526 switch (res->ai_family) { 527 case AF_INET: 528 l->cmsg2dst = proxy_dst4; 529 530 if (setsockopt(s, IPPROTO_IP, IP_RECVDSTADDR, 531 &on, sizeof(on)) == -1) 532 errx(1, "setsockopt(IP_RECVDSTADDR)"); 533 if (setsockopt(s, IPPROTO_IP, IP_RECVDSTPORT, 534 &on, sizeof(on)) == -1) 535 errx(1, "setsockopt(IP_RECVDSTPORT)"); 536 break; 537 case AF_INET6: 538 l->cmsg2dst = proxy_dst6; 539 540 if (setsockopt(s, IPPROTO_IPV6, IPV6_RECVPKTINFO, 541 &on, sizeof(on)) == -1) 542 errx(1, "setsockopt(IPV6_RECVPKTINFO)"); 543 if (setsockopt(s, IPPROTO_IPV6, IPV6_RECVDSTPORT, 544 &on, sizeof(on)) == -1) 545 errx(1, "setsockopt(IPV6_RECVDSTPORT)"); 546 break; 547 } 548 l->s = s; 549 550 TAILQ_INSERT_TAIL(&proxy_listeners, l, entry); 551 } 552 freeaddrinfo(res0); 553 554 if (TAILQ_EMPTY(&proxy_listeners)) 555 err(1, "%s", cause); 556 } 557 558 void 559 proxy_listener_events(void) 560 { 561 struct proxy_listener *l; 562 563 TAILQ_FOREACH(l, &proxy_listeners, entry) { 564 event_set(&l->ev, l->s, EV_READ | EV_PERSIST, proxy_recv, l); 565 event_add(&l->ev, NULL); 566 } 567 } 568 569 char safety[SEGSIZE_MAX + 4]; 570 571 int 572 proxy_dst4(struct cmsghdr *cmsg, struct sockaddr_storage *ss) 573 { 574 struct sockaddr_in *sin = (struct sockaddr_in *)ss; 575 576 if (cmsg->cmsg_level != IPPROTO_IP) 577 return (0); 578 579 switch (cmsg->cmsg_type) { 580 case IP_RECVDSTADDR: 581 memcpy(&sin->sin_addr, CMSG_DATA(cmsg), sizeof(sin->sin_addr)); 582 if (sin->sin_addr.s_addr == INADDR_BROADCAST) 583 return (-1); 584 break; 585 586 case IP_RECVDSTPORT: 587 memcpy(&sin->sin_port, CMSG_DATA(cmsg), sizeof(sin->sin_port)); 588 break; 589 } 590 591 return (0); 592 } 593 594 int 595 proxy_dst6(struct cmsghdr *cmsg, struct sockaddr_storage *ss) 596 { 597 struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)ss; 598 struct in6_pktinfo *ipi = (struct in6_pktinfo *)CMSG_DATA(cmsg); 599 600 if (cmsg->cmsg_level != IPPROTO_IPV6) 601 return (0); 602 603 switch (cmsg->cmsg_type) { 604 case IPV6_PKTINFO: 605 memcpy(&sin6->sin6_addr, &ipi->ipi6_addr, 606 sizeof(sin6->sin6_addr)); 607 #ifdef __KAME__ 608 if (IN6_IS_ADDR_LINKLOCAL(&ipi->ipi6_addr)) 609 sin6->sin6_scope_id = ipi->ipi6_ifindex; 610 #endif 611 break; 612 case IPV6_RECVDSTPORT: 613 memcpy(&sin6->sin6_port, CMSG_DATA(cmsg), 614 sizeof(sin6->sin6_port)); 615 break; 616 } 617 618 return (0); 619 } 620 621 void 622 proxy_recv(int fd, short events, void *arg) 623 { 624 struct proxy_listener *l = arg; 625 626 union { 627 struct cmsghdr hdr; 628 char buf[CMSG_SPACE(sizeof(struct sockaddr_storage)) + 629 CMSG_SPACE(sizeof(in_port_t))]; 630 } cmsgbuf; 631 struct cmsghdr *cmsg; 632 struct msghdr msg; 633 struct iovec iov; 634 ssize_t n; 635 636 struct proxy_request *r; 637 struct tftphdr *tp; 638 639 r = calloc(1, sizeof(*r)); 640 if (r == NULL) { 641 recv(fd, safety, sizeof(safety), 0); 642 return; 643 } 644 r->id = arc4random(); /* XXX unique? */ 645 646 bzero(&msg, sizeof(msg)); 647 iov.iov_base = r->buf; 648 iov.iov_len = sizeof(r->buf); 649 msg.msg_name = &r->addrs.src; 650 msg.msg_namelen = sizeof(r->addrs.src); 651 msg.msg_iov = &iov; 652 msg.msg_iovlen = 1; 653 msg.msg_control = &cmsgbuf.buf; 654 msg.msg_controllen = sizeof(cmsgbuf.buf); 655 656 n = recvmsg(fd, &msg, 0); 657 if (n == -1) { 658 switch (errno) { 659 case EAGAIN: 660 case EINTR: 661 goto err; 662 default: 663 lerr(1, "recvmsg"); 664 /* NOTREACHED */ 665 } 666 } 667 r->buflen = n; 668 669 /* check the packet */ 670 if (n < 5) { 671 /* not enough to be a real packet */ 672 goto err; 673 } 674 tp = (struct tftphdr *)r->buf; 675 switch (ntohs(tp->th_opcode)) { 676 case RRQ: 677 case WRQ: 678 break; 679 default: 680 goto err; 681 } 682 683 r->addrs.dst.ss_family = r->addrs.src.ss_family; 684 r->addrs.dst.ss_len = r->addrs.src.ss_len; 685 686 /* get local address if possible */ 687 for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL; 688 cmsg = CMSG_NXTHDR(&msg, cmsg)) { 689 if (l->cmsg2dst(cmsg, &r->addrs.dst) == -1) 690 goto err; 691 } 692 693 if (verbose) { 694 linfo("%s:%d -> %s:%d \"%s %s\"", 695 sock_ntop((struct sockaddr *)&r->addrs.src), 696 ntohs(((struct sockaddr_in *)&r->addrs.src)->sin_port), 697 sock_ntop((struct sockaddr *)&r->addrs.dst), 698 ntohs(((struct sockaddr_in *)&r->addrs.dst)->sin_port), 699 opcode(ntohs(tp->th_opcode)), tp->th_stuff); 700 /* XXX tp->th_stuff could be garbage */ 701 } 702 703 TAILQ_INSERT_TAIL(&child->fdrequests, r, entry); 704 evbuffer_add(child->buf, &r->addrs, sizeof(r->addrs)); 705 event_add(&child->push_ev, NULL); 706 707 return; 708 709 err: 710 free(r); 711 } 712 713 void 714 unprivproc_push(int fd, short events, void *arg) 715 { 716 if (evbuffer_write(child->buf, fd) == -1) 717 lerr(1, "child evbuffer_write"); 718 719 if (EVBUFFER_LENGTH(child->buf)) 720 event_add(&child->push_ev, NULL); 721 } 722 723 void 724 unprivproc_pop(int fd, short events, void *arg) 725 { 726 struct proxy_request *r; 727 728 struct msghdr msg; 729 union { 730 struct cmsghdr hdr; 731 char buf[CMSG_SPACE(sizeof(int))]; 732 } cmsgbuf; 733 struct cmsghdr *cmsg; 734 struct iovec iov; 735 int result; 736 int s; 737 738 do { 739 memset(&msg, 0, sizeof(msg)); 740 iov.iov_base = &result; 741 iov.iov_len = sizeof(int); 742 msg.msg_iov = &iov; 743 msg.msg_iovlen = 1; 744 msg.msg_control = &cmsgbuf.buf; 745 msg.msg_controllen = sizeof(cmsgbuf.buf); 746 747 switch (recvmsg(fd, &msg, 0)) { 748 case sizeof(int): 749 break; 750 751 case -1: 752 switch (errno) { 753 case EAGAIN: 754 case EINTR: 755 return; 756 default: 757 lerr(1, "child recvmsg"); 758 } 759 /* NOTREACHED */ 760 761 case 0: 762 lerrx(1, "privproc closed connection"); 763 764 default: 765 lerrx(1, "child recvmsg was weird"); 766 /* NOTREACHED */ 767 } 768 769 if (result != 0) { 770 errno = result; 771 lerr(1, "child fdpass fail"); 772 } 773 774 cmsg = CMSG_FIRSTHDR(&msg); 775 if (cmsg == NULL) 776 lerrx(1, "%s: no message header", __func__); 777 778 if (cmsg->cmsg_type != SCM_RIGHTS) { 779 lerrx(1, "%s: expected type %d got %d", __func__, 780 SCM_RIGHTS, cmsg->cmsg_type); 781 } 782 783 s = (*(int *)CMSG_DATA(cmsg)); 784 785 r = TAILQ_FIRST(&child->fdrequests); 786 if (r == NULL) 787 lerrx(1, "got fd without a pending request"); 788 789 TAILQ_REMOVE(&child->fdrequests, r, entry); 790 791 /* get ready to add rules */ 792 if (prepare_commit(r->id) == -1) 793 lerr(1, "%s: prepare_commit", __func__); 794 795 if (add_filter(r->id, PF_IN, (struct sockaddr *)&r->addrs.dst, 796 (struct sockaddr *)&r->addrs.src, 797 ntohs(((struct sockaddr_in *)&r->addrs.src)->sin_port), 798 IPPROTO_UDP) == -1) 799 lerr(1, "%s: couldn't add pass in", __func__); 800 801 if (add_filter(r->id, PF_OUT, (struct sockaddr *)&r->addrs.dst, 802 (struct sockaddr *)&r->addrs.src, 803 ntohs(((struct sockaddr_in *)&r->addrs.src)->sin_port), 804 IPPROTO_UDP) == -1) 805 lerr(1, "%s: couldn't add pass out", __func__); 806 807 if (do_commit() == -1) 808 lerr(1, "%s: couldn't commit rules", __func__); 809 810 /* forward the initial tftp request and start the insanity */ 811 if (sendto(s, r->buf, r->buflen, 0, 812 (struct sockaddr *)&r->addrs.dst, 813 r->addrs.dst.ss_len) == -1) 814 lerr(1, "%s: unable to send", __func__); 815 816 close(s); 817 818 evtimer_set(&r->ev, unprivproc_timeout, r); 819 evtimer_add(&r->ev, &transwait); 820 821 TAILQ_INSERT_TAIL(&child->tmrequests, r, entry); 822 } while (!TAILQ_EMPTY(&child->fdrequests)); 823 } 824 825 void 826 unprivproc_timeout(int fd, short events, void *arg) 827 { 828 struct proxy_request *r = arg; 829 830 TAILQ_REMOVE(&child->tmrequests, r, entry); 831 832 /* delete our rdr rule and clean up */ 833 prepare_commit(r->id); 834 do_commit(); 835 836 free(r); 837 } 838 839 840 const char * 841 opcode(int code) 842 { 843 static char str[6]; 844 845 switch (code) { 846 case 1: 847 (void)snprintf(str, sizeof(str), "RRQ"); 848 break; 849 case 2: 850 (void)snprintf(str, sizeof(str), "WRQ"); 851 break; 852 default: 853 (void)snprintf(str, sizeof(str), "(%d)", code); 854 break; 855 } 856 857 return (str); 858 } 859 860 const char * 861 sock_ntop(struct sockaddr *sa) 862 { 863 static int n = 0; 864 865 /* Cycle to next buffer. */ 866 n = (n + 1) % NTOP_BUFS; 867 ntop_buf[n][0] = '\0'; 868 869 if (sa->sa_family == AF_INET) { 870 struct sockaddr_in *sin = (struct sockaddr_in *)sa; 871 872 return (inet_ntop(AF_INET, &sin->sin_addr, ntop_buf[n], 873 sizeof ntop_buf[0])); 874 } 875 876 if (sa->sa_family == AF_INET6) { 877 struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa; 878 879 return (inet_ntop(AF_INET6, &sin6->sin6_addr, ntop_buf[n], 880 sizeof ntop_buf[0])); 881 } 882 883 return (NULL); 884 } 885 886 void 887 syslog_vstrerror(int e, int priority, const char *fmt, va_list ap) 888 { 889 char *s; 890 891 if (vasprintf(&s, fmt, ap) == -1) { 892 syslog(LOG_EMERG, "unable to alloc in syslog_vstrerror"); 893 exit(1); 894 } 895 896 syslog(priority, "%s: %s", s, strerror(e)); 897 898 free(s); 899 } 900 901 void 902 syslog_err(int ecode, const char *fmt, ...) 903 { 904 va_list ap; 905 906 va_start(ap, fmt); 907 syslog_vstrerror(errno, LOG_EMERG, fmt, ap); 908 va_end(ap); 909 910 exit(ecode); 911 } 912 913 void 914 syslog_errx(int ecode, const char *fmt, ...) 915 { 916 va_list ap; 917 918 va_start(ap, fmt); 919 vsyslog(LOG_WARNING, fmt, ap); 920 va_end(ap); 921 922 exit(ecode); 923 } 924 925 void 926 syslog_warn(const char *fmt, ...) 927 { 928 va_list ap; 929 930 va_start(ap, fmt); 931 syslog_vstrerror(errno, LOG_WARNING, fmt, ap); 932 va_end(ap); 933 } 934 935 void 936 syslog_warnx(const char *fmt, ...) 937 { 938 va_list ap; 939 940 va_start(ap, fmt); 941 vsyslog(LOG_WARNING, fmt, ap); 942 va_end(ap); 943 } 944 945 void 946 syslog_info(const char *fmt, ...) 947 { 948 va_list ap; 949 950 va_start(ap, fmt); 951 vsyslog(LOG_INFO, fmt, ap); 952 va_end(ap); 953 } 954 955