1 /* $OpenBSD: tftp-proxy.c,v 1.22 2021/01/17 13:38:52 claudio 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 <stdarg.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 "_tftp_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 __dead void (*err)(int, const char *, ...) 103 __attribute__((__format__ (printf, 2, 3))); 104 __dead void (*errx)(int, const char *, ...) 105 __attribute__((__format__ (printf, 2, 3))); 106 void (*warn)(const char *, ...) 107 __attribute__((__format__ (printf, 1, 2))); 108 void (*warnx)(const char *, ...) 109 __attribute__((__format__ (printf, 1, 2))); 110 void (*info)(const char *, ...) 111 __attribute__((__format__ (printf, 1, 2))); 112 void (*debug)(const char *, ...) 113 __attribute__((__format__ (printf, 1, 2))); 114 }; 115 116 const struct loggers conslogger = { 117 err, 118 errx, 119 warn, 120 warnx, 121 warnx, /* info */ 122 warnx /* debug */ 123 }; 124 125 __dead void syslog_err(int, const char *, ...) 126 __attribute__((__format__ (printf, 2, 3))); 127 __dead void syslog_errx(int, const char *, ...) 128 __attribute__((__format__ (printf, 2, 3))); 129 void syslog_warn(const char *, ...) 130 __attribute__((__format__ (printf, 1, 2))); 131 void syslog_warnx(const char *, ...) 132 __attribute__((__format__ (printf, 1, 2))); 133 void syslog_info(const char *, ...) 134 __attribute__((__format__ (printf, 1, 2))); 135 void syslog_debug(const char *, ...) 136 __attribute__((__format__ (printf, 1, 2))); 137 void syslog_vstrerror(int, int, const char *, va_list) 138 __attribute__((__format__ (printf, 3, 0))); 139 140 const struct loggers syslogger = { 141 syslog_err, 142 syslog_errx, 143 syslog_warn, 144 syslog_warnx, 145 syslog_info, 146 syslog_debug 147 }; 148 149 const struct loggers *logger = &conslogger; 150 151 #define lerr(_e, _f...) logger->err((_e), _f) 152 #define lerrx(_e, _f...) logger->errx((_e), _f) 153 #define lwarn(_f...) logger->warn(_f) 154 #define lwarnx(_f...) logger->warnx(_f) 155 #define linfo(_f...) logger->info(_f) 156 #define ldebug(_f...) logger->debug(_f) 157 158 __dead void 159 usage(void) 160 { 161 extern char *__progname; 162 fprintf(stderr, "usage: %s [-46dv] [-a address] [-l address] [-p port]" 163 " [-w transwait]\n", __progname); 164 exit(1); 165 } 166 167 int debug = 0; 168 int verbose = 0; 169 struct timeval transwait = { DEFTRANSWAIT, 0 }; 170 171 int on = 1; 172 173 struct addr_pair { 174 struct sockaddr_storage src; 175 struct sockaddr_storage dst; 176 }; 177 178 struct proxy_request { 179 char buf[SEGSIZE_MAX + 4]; 180 size_t buflen; 181 182 struct addr_pair addrs; 183 184 struct event ev; 185 TAILQ_ENTRY(proxy_request) entry; 186 u_int32_t id; 187 }; 188 189 struct proxy_child { 190 TAILQ_HEAD(, proxy_request) fdrequests; 191 TAILQ_HEAD(, proxy_request) tmrequests; 192 struct event push_ev; 193 struct event pop_ev; 194 struct evbuffer *buf; 195 }; 196 197 struct proxy_child *child = NULL; 198 TAILQ_HEAD(, proxy_listener) proxy_listeners; 199 200 struct src_addr { 201 TAILQ_ENTRY(src_addr) entry; 202 struct sockaddr_storage addr; 203 socklen_t addrlen; 204 }; 205 TAILQ_HEAD(, src_addr) src_addrs; 206 207 void source_addresses(const char*, int); 208 209 int 210 main(int argc, char *argv[]) 211 { 212 extern char *__progname; 213 214 int c; 215 const char *errstr; 216 217 struct src_addr *saddr, *saddr2; 218 struct passwd *pw; 219 220 char *addr = "localhost"; 221 char *port = "6969"; 222 int family = AF_UNSPEC; 223 224 int pair[2]; 225 226 TAILQ_INIT(&src_addrs); 227 228 while ((c = getopt(argc, argv, "46a:dvl:p:w:")) != -1) { 229 switch (c) { 230 case '4': 231 family = AF_INET; 232 break; 233 case '6': 234 family = AF_INET6; 235 break; 236 case 'a': 237 source_addresses(optarg, family); 238 break; 239 case 'd': 240 verbose = debug = 1; 241 break; 242 case 'l': 243 addr = optarg; 244 break; 245 case 'p': 246 port = optarg; 247 break; 248 case 'v': 249 verbose = 1; 250 break; 251 case 'w': 252 transwait.tv_sec = strtonum(optarg, 1, 30, &errstr); 253 if (errstr) 254 errx(1, "wait is %s", errstr); 255 break; 256 default: 257 usage(); 258 /* NOTREACHED */ 259 } 260 } 261 262 if (geteuid() != 0) 263 lerrx(1, "need root privileges"); 264 265 if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK, PF_UNSPEC, pair) 266 == -1) 267 lerr(1, "socketpair"); 268 269 pw = getpwnam(NOPRIV_USER); 270 if (pw == NULL) 271 lerrx(1, "no %s user", NOPRIV_USER); 272 273 /* Family option may have been specified late. */ 274 if (family != AF_UNSPEC) 275 TAILQ_FOREACH_SAFE(saddr, &src_addrs, entry, saddr2) 276 if (saddr->addr.ss_family != family) { 277 TAILQ_REMOVE(&src_addrs, saddr, entry); 278 free(saddr); 279 } 280 281 if (!debug) { 282 if (daemon(1, 0) == -1) 283 lerr(1, "daemon"); 284 285 openlog(__progname, LOG_PID|LOG_NDELAY, LOG_DAEMON); 286 tzset(); 287 logger = &syslogger; 288 } 289 290 switch (fork()) { 291 case -1: 292 lerr(1, "fork"); 293 294 case 0: 295 setproctitle("privproc"); 296 close(pair[1]); 297 proxy_privproc(pair[0], pw); 298 /* this never returns */ 299 300 default: 301 setproctitle("unprivproc"); 302 close(pair[0]); 303 break; 304 } 305 306 child = calloc(1, sizeof(*child)); 307 if (child == NULL) 308 lerr(1, "alloc(child)"); 309 310 child->buf = evbuffer_new(); 311 if (child->buf == NULL) 312 lerr(1, "child evbuffer"); 313 314 TAILQ_INIT(&child->fdrequests); 315 TAILQ_INIT(&child->tmrequests); 316 317 proxy_listen(addr, port, family); 318 319 /* open /dev/pf */ 320 init_filter(NULL, verbose); 321 322 /* revoke privs */ 323 if (chroot(CHROOT_DIR) == -1) 324 lerr(1, "chroot %s", CHROOT_DIR); 325 326 if (chdir("/") == -1) 327 lerr(1, "chdir %s", CHROOT_DIR); 328 329 if (setgroups(1, &pw->pw_gid) || 330 setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) || 331 setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid)) 332 err(1, "unable to revoke privs"); 333 334 event_init(); 335 336 proxy_listener_events(); 337 338 event_set(&child->pop_ev, pair[1], EV_READ | EV_PERSIST, 339 unprivproc_pop, NULL); 340 event_set(&child->push_ev, pair[1], EV_WRITE, 341 unprivproc_push, NULL); 342 343 event_add(&child->pop_ev, NULL); 344 345 event_dispatch(); 346 347 return(0); 348 } 349 350 void 351 source_addresses(const char* name, int family) 352 { 353 struct addrinfo hints, *res, *res0; 354 struct src_addr *saddr; 355 int error; 356 357 memset(&hints, 0, sizeof(hints)); 358 hints.ai_family = family; 359 hints.ai_socktype = SOCK_DGRAM; 360 hints.ai_flags = AI_PASSIVE; 361 error = getaddrinfo(name, NULL, &hints, &res0); 362 if (error) 363 lerrx(1, "%s: %s", name, gai_strerror(error)); 364 for (res = res0; res != NULL; res = res->ai_next) { 365 if ((saddr = calloc(1, sizeof(struct src_addr))) == NULL) 366 lerrx(1, "calloc"); 367 memcpy(&(saddr->addr), res->ai_addr, res->ai_addrlen); 368 saddr->addrlen = res->ai_addrlen; 369 TAILQ_INSERT_TAIL(&src_addrs, saddr, entry); 370 } 371 freeaddrinfo(res0); 372 } 373 374 void 375 proxy_privproc(int s, struct passwd *pw) 376 { 377 struct privproc p; 378 379 if (chroot(CHROOT_DIR) == -1) 380 lerr(1, "chroot to %s", CHROOT_DIR); 381 382 if (chdir("/") == -1) 383 lerr(1, "chdir to %s", CHROOT_DIR); 384 385 if (setgroups(1, &pw->pw_gid) || 386 setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid)) 387 lerr(1, "unable to set group ids"); 388 389 if (pledge("stdio inet sendfd", NULL) == -1) 390 err(1, "pledge"); 391 392 TAILQ_INIT(&p.replies); 393 394 p.buf = evbuffer_new(); 395 if (p.buf == NULL) 396 err(1, "pop evbuffer_new"); 397 398 event_init(); 399 400 event_set(&p.pop_ev, s, EV_READ | EV_PERSIST, privproc_pop, &p); 401 event_set(&p.push_ev, s, EV_WRITE, privproc_push, &p); 402 403 event_add(&p.pop_ev, NULL); 404 405 event_dispatch(); 406 } 407 408 void 409 privproc_pop(int fd, short events, void *arg) 410 { 411 struct addr_pair req; 412 struct privproc *p = arg; 413 struct fd_reply *rep; 414 struct src_addr *saddr; 415 int add = 0; 416 417 switch (evbuffer_read(p->buf, fd, sizeof(req))) { 418 case 0: 419 lerrx(1, "unprivproc has gone"); 420 case -1: 421 switch (errno) { 422 case EAGAIN: 423 case EINTR: 424 return; 425 default: 426 lerr(1, "privproc_pop read"); 427 } 428 default: 429 break; 430 } 431 432 while (EVBUFFER_LENGTH(p->buf) >= sizeof(req)) { 433 evbuffer_remove(p->buf, &req, sizeof(req)); 434 435 /* do i really need to check this? */ 436 if (req.src.ss_family != req.dst.ss_family) 437 lerrx(1, "family mismatch"); 438 439 rep = calloc(1, sizeof(*rep)); 440 if (rep == NULL) 441 lerr(1, "reply calloc"); 442 443 rep->fd = socket(req.src.ss_family, SOCK_DGRAM | SOCK_NONBLOCK, 444 IPPROTO_UDP); 445 if (rep->fd == -1) 446 lerr(1, "privproc socket"); 447 448 if (setsockopt(rep->fd, SOL_SOCKET, SO_BINDANY, 449 &on, sizeof(on)) == -1) 450 lerr(1, "privproc setsockopt(BINDANY)"); 451 452 if (setsockopt(rep->fd, SOL_SOCKET, SO_REUSEADDR, 453 &on, sizeof(on)) == -1) 454 lerr(1, "privproc setsockopt(REUSEADDR)"); 455 456 if (setsockopt(rep->fd, SOL_SOCKET, SO_REUSEPORT, 457 &on, sizeof(on)) == -1) 458 lerr(1, "privproc setsockopt(REUSEPORT)"); 459 460 TAILQ_FOREACH(saddr, &src_addrs, entry) 461 if (saddr->addr.ss_family == req.src.ss_family) 462 break; 463 if (saddr == NULL) { 464 if (bind(rep->fd, (struct sockaddr *)&req.src, 465 req.src.ss_len) == -1) 466 lerr(1, "privproc bind"); 467 } else { 468 if (bind(rep->fd, (struct sockaddr*)&saddr->addr, 469 saddr->addrlen) == -1) 470 lerr(1, "privproc bind"); 471 } 472 473 if (TAILQ_EMPTY(&p->replies)) 474 add = 1; 475 476 TAILQ_INSERT_TAIL(&p->replies, rep, entry); 477 } 478 479 if (add) 480 event_add(&p->push_ev, NULL); 481 } 482 483 void 484 privproc_push(int fd, short events, void *arg) 485 { 486 struct privproc *p = arg; 487 struct fd_reply *rep; 488 489 struct msghdr msg; 490 union { 491 struct cmsghdr hdr; 492 char buf[CMSG_SPACE(sizeof(int))]; 493 } cmsgbuf; 494 struct cmsghdr *cmsg; 495 struct iovec iov; 496 int result = 0; 497 498 while ((rep = TAILQ_FIRST(&p->replies)) != NULL) { 499 memset(&msg, 0, sizeof(msg)); 500 501 msg.msg_control = (caddr_t)&cmsgbuf.buf; 502 msg.msg_controllen = sizeof(cmsgbuf.buf); 503 cmsg = CMSG_FIRSTHDR(&msg); 504 cmsg->cmsg_len = CMSG_LEN(sizeof(int)); 505 cmsg->cmsg_level = SOL_SOCKET; 506 cmsg->cmsg_type = SCM_RIGHTS; 507 *(int *)CMSG_DATA(cmsg) = rep->fd; 508 509 iov.iov_base = &result; 510 iov.iov_len = sizeof(int); 511 msg.msg_iov = &iov; 512 msg.msg_iovlen = 1; 513 514 switch (sendmsg(fd, &msg, 0)) { 515 case sizeof(int): 516 break; 517 518 case -1: 519 if (errno == EAGAIN) 520 goto again; 521 522 lerr(1, "privproc sendmsg"); 523 /* NOTREACHED */ 524 525 default: 526 lerrx(1, "privproc sendmsg weird len"); 527 } 528 529 TAILQ_REMOVE(&p->replies, rep, entry); 530 close(rep->fd); 531 free(rep); 532 } 533 534 if (TAILQ_EMPTY(&p->replies)) 535 return; 536 537 again: 538 event_add(&p->push_ev, NULL); 539 } 540 541 void 542 proxy_listen(const char *addr, const char *port, int family) 543 { 544 struct proxy_listener *l; 545 546 struct addrinfo hints, *res, *res0; 547 int error; 548 int s, on = 1; 549 int serrno; 550 const char *cause = NULL; 551 552 memset(&hints, 0, sizeof(hints)); 553 hints.ai_family = family; 554 hints.ai_socktype = SOCK_DGRAM; 555 hints.ai_flags = AI_PASSIVE; 556 557 TAILQ_INIT(&proxy_listeners); 558 559 error = getaddrinfo(addr, port, &hints, &res0); 560 if (error) 561 errx(1, "%s:%s: %s", addr, port, gai_strerror(error)); 562 563 for (res = res0; res != NULL; res = res->ai_next) { 564 s = socket(res->ai_family, res->ai_socktype | SOCK_NONBLOCK, 565 res->ai_protocol); 566 if (s == -1) { 567 cause = "socket"; 568 continue; 569 } 570 571 if (bind(s, res->ai_addr, res->ai_addrlen) == -1) { 572 cause = "bind"; 573 serrno = errno; 574 close(s); 575 errno = serrno; 576 continue; 577 } 578 579 l = calloc(1, sizeof(*l)); 580 if (l == NULL) 581 err(1, "listener alloc"); 582 583 switch (res->ai_family) { 584 case AF_INET: 585 l->cmsg2dst = proxy_dst4; 586 587 if (setsockopt(s, IPPROTO_IP, IP_RECVDSTADDR, 588 &on, sizeof(on)) == -1) 589 errx(1, "setsockopt(IP_RECVDSTADDR)"); 590 if (setsockopt(s, IPPROTO_IP, IP_RECVDSTPORT, 591 &on, sizeof(on)) == -1) 592 errx(1, "setsockopt(IP_RECVDSTPORT)"); 593 break; 594 case AF_INET6: 595 l->cmsg2dst = proxy_dst6; 596 597 if (setsockopt(s, IPPROTO_IPV6, IPV6_RECVPKTINFO, 598 &on, sizeof(on)) == -1) 599 errx(1, "setsockopt(IPV6_RECVPKTINFO)"); 600 if (setsockopt(s, IPPROTO_IPV6, IPV6_RECVDSTPORT, 601 &on, sizeof(on)) == -1) 602 errx(1, "setsockopt(IPV6_RECVDSTPORT)"); 603 break; 604 } 605 l->s = s; 606 607 TAILQ_INSERT_TAIL(&proxy_listeners, l, entry); 608 } 609 freeaddrinfo(res0); 610 611 if (TAILQ_EMPTY(&proxy_listeners)) 612 err(1, "%s", cause); 613 } 614 615 void 616 proxy_listener_events(void) 617 { 618 struct proxy_listener *l; 619 620 TAILQ_FOREACH(l, &proxy_listeners, entry) { 621 event_set(&l->ev, l->s, EV_READ | EV_PERSIST, proxy_recv, l); 622 event_add(&l->ev, NULL); 623 } 624 } 625 626 char safety[SEGSIZE_MAX + 4]; 627 628 int 629 proxy_dst4(struct cmsghdr *cmsg, struct sockaddr_storage *ss) 630 { 631 struct sockaddr_in *sin = (struct sockaddr_in *)ss; 632 633 if (cmsg->cmsg_level != IPPROTO_IP) 634 return (0); 635 636 switch (cmsg->cmsg_type) { 637 case IP_RECVDSTADDR: 638 memcpy(&sin->sin_addr, CMSG_DATA(cmsg), sizeof(sin->sin_addr)); 639 if (sin->sin_addr.s_addr == INADDR_BROADCAST) 640 return (-1); 641 break; 642 643 case IP_RECVDSTPORT: 644 memcpy(&sin->sin_port, CMSG_DATA(cmsg), sizeof(sin->sin_port)); 645 break; 646 } 647 648 return (0); 649 } 650 651 int 652 proxy_dst6(struct cmsghdr *cmsg, struct sockaddr_storage *ss) 653 { 654 struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)ss; 655 struct in6_pktinfo *ipi = (struct in6_pktinfo *)CMSG_DATA(cmsg); 656 657 if (cmsg->cmsg_level != IPPROTO_IPV6) 658 return (0); 659 660 switch (cmsg->cmsg_type) { 661 case IPV6_PKTINFO: 662 memcpy(&sin6->sin6_addr, &ipi->ipi6_addr, 663 sizeof(sin6->sin6_addr)); 664 if (IN6_IS_ADDR_LINKLOCAL(&ipi->ipi6_addr)) 665 sin6->sin6_scope_id = ipi->ipi6_ifindex; 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_CRIT, 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_CRIT, 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_ERR, 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_ERR, 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 void 1031 syslog_debug(const char *fmt, ...) 1032 { 1033 va_list ap; 1034 1035 if (!debug) 1036 return; 1037 1038 va_start(ap, fmt); 1039 vsyslog(LOG_DEBUG, fmt, ap); 1040 va_end(ap); 1041 } 1042