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