1/* $NetBSD: ftp.c,v 1.20 2024/02/09 20:55:15 andvar Exp $ */ 2/* $KAME: ftp.c,v 1.23 2003/08/19 21:20:33 itojun Exp $ */ 3 4/* 5 * Copyright (C) 1997 and 1998 WIDE Project. 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. Neither the name of the project nor the names of its contributors 17 * may be used to endorse or promote products derived from this software 18 * without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 */ 32 33#include <sys/param.h> 34#include <sys/types.h> 35#include <sys/socket.h> 36#include <sys/ioctl.h> 37#include <sys/time.h> 38 39#include <stdio.h> 40#include <stdlib.h> 41#include <string.h> 42#include <syslog.h> 43#include <unistd.h> 44#include <poll.h> 45#include <errno.h> 46#include <ctype.h> 47 48#include <netinet/in.h> 49#include <arpa/inet.h> 50#include <netdb.h> 51 52#include "faithd.h" 53 54static char rbuf[MSS]; 55static int passivemode = 0; 56static int wport4 = -1; /* listen() to active */ 57static int wport6 = -1; /* listen() to passive */ 58static int port4 = -1; /* active: inbound passive: outbound */ 59static int port6 = -1; /* active: outbound passive: inbound */ 60static struct sockaddr_storage data4; /* server data address */ 61static struct sockaddr_storage data6; /* client data address */ 62static int epsvall = 0; 63 64enum state { NONE, LPRT, EPRT, LPSV, EPSV }; 65 66static int ftp_activeconn(void); 67static int ftp_passiveconn(void); 68static ssize_t ftp_copy(int, int); 69static ssize_t ftp_copyresult(int, int, enum state); 70static ssize_t ftp_copycommand(int, int, enum state *); 71 72void 73ftp_relay(int ctl6, int ctl4) 74{ 75 struct pollfd pfd[6]; 76 ssize_t error; 77 enum state state = NONE; 78 79 syslog(LOG_INFO, "starting ftp control connection"); 80 81 for (;;) { 82 pfd[0].fd = ctl4; 83 pfd[0].events = POLLIN; 84 pfd[1].fd = ctl6; 85 pfd[1].events = POLLIN; 86 if (0 <= port4) { 87 pfd[2].fd = port4; 88 pfd[2].events = POLLIN; 89 } else 90 pfd[2].fd = -1; 91 if (0 <= port6) { 92 pfd[3].fd = port6; 93 pfd[3].events = POLLIN; 94 } else 95 pfd[3].fd = -1; 96#if 0 97 if (0 <= wport4) { 98 pfd[4].fd = wport4; 99 pfd[4].events = POLLIN; 100 } else 101 pfd[4].fd = -1; 102 if (0 <= wport6) { 103 pfd[5].fd = wport4; 104 pfd[5].events = POLLIN; 105 } else 106 pfd[5].fd = -1; 107#else 108 pfd[4].fd = pfd[5].fd = -1; 109 pfd[4].events = pfd[5].events = 0; 110#endif 111 error = poll(pfd, (unsigned int)(sizeof(pfd) / sizeof(pfd[0])), 112 FAITH_TIMEOUT * 1000); 113 if (error == -1) { 114 exit_failure("poll: %s", strerror(errno)); 115 } 116 else if (error == 0) 117 exit_failure("connection timeout"); 118 119 /* 120 * The order of the following checks does (slightly) matter. 121 * It is important to visit all checks (do not use "continue"), 122 * otherwise some of the pipe may become full and we cannot 123 * relay correctly. 124 */ 125 if (pfd[1].revents & POLLIN) 126 { 127 /* 128 * copy control connection from the client. 129 * command translation is necessary. 130 */ 131 error = ftp_copycommand(ctl6, ctl4, &state); 132 133 if (error < 0) 134 goto bad; 135 else if (error == 0) { 136 (void)close(ctl4); 137 (void)close(ctl6); 138 exit_success("terminating ftp control connection"); 139 /*NOTREACHED*/ 140 } 141 } 142 if (pfd[0].revents & POLLIN) 143 { 144 /* 145 * copy control connection from the server 146 * translation of result code is necessary. 147 */ 148 error = ftp_copyresult(ctl4, ctl6, state); 149 150 if (error < 0) 151 goto bad; 152 else if (error == 0) { 153 (void)close(ctl4); 154 (void)close(ctl6); 155 exit_success("terminating ftp control connection"); 156 /*NOTREACHED*/ 157 } 158 } 159 if (0 <= port4 && 0 <= port6 && (pfd[2].revents & POLLIN)) 160 { 161 /* 162 * copy data connection. 163 * no special treatment necessary. 164 */ 165 if (pfd[2].revents & POLLIN) 166 error = ftp_copy(port4, port6); 167 switch (error) { 168 case -1: 169 goto bad; 170 case 0: 171 if (port4 >= 0) { 172 (void)close(port4); 173 port4 = -1; 174 } 175 if (port6 >= 0) { 176 (void)close(port6); 177 port6 = -1; 178 } 179 syslog(LOG_INFO, "terminating data connection"); 180 break; 181 default: 182 break; 183 } 184 } 185 if (0 <= port4 && 0 <= port6 && (pfd[3].revents & POLLIN)) 186 { 187 /* 188 * copy data connection. 189 * no special treatment necessary. 190 */ 191 if (pfd[3].revents & POLLIN) 192 error = ftp_copy(port6, port4); 193 switch (error) { 194 case -1: 195 goto bad; 196 case 0: 197 if (port4 >= 0) { 198 (void)close(port4); 199 port4 = -1; 200 } 201 if (port6 >= 0) { 202 (void)close(port6); 203 port6 = -1; 204 } 205 syslog(LOG_INFO, "terminating data connection"); 206 break; 207 default: 208 break; 209 } 210 } 211#if 0 212 if (wport4 && (pfd[4].revents & POLLIN)) 213 { 214 /* 215 * establish active data connection from the server. 216 */ 217 ftp_activeconn(); 218 } 219 if (wport4 && (pfd[5].revents & POLLIN)) 220 { 221 /* 222 * establish passive data connection from the client. 223 */ 224 ftp_passiveconn(); 225 } 226#endif 227 } 228 229 bad: 230 exit_failure("%s", strerror(errno)); 231} 232 233static int 234ftp_activeconn() 235{ 236 socklen_t n; 237 int error; 238 struct pollfd pfd[1]; 239 struct sockaddr *sa; 240 241 /* get active connection from server */ 242 pfd[0].fd = wport4; 243 pfd[0].events = POLLIN; 244 n = sizeof(data4); 245 if (poll(pfd, (unsigned int)(sizeof(pfd) / sizeof(pfd[0])), 246 120000) == 0 || 247 (port4 = accept(wport4, (void *)&data4, &n)) < 0) 248 { 249 (void)close(wport4); 250 wport4 = -1; 251 syslog(LOG_INFO, "active mode data connection failed"); 252 return -1; 253 } 254 255 /* ask active connection to client */ 256 sa = (void *)&data6; 257 port6 = socket(sa->sa_family, SOCK_STREAM, 0); 258 if (port6 == -1) { 259 (void)close(port4); 260 (void)close(wport4); 261 port4 = wport4 = -1; 262 syslog(LOG_INFO, "active mode data connection failed"); 263 return -1; 264 } 265 error = connect(port6, sa, (socklen_t)sa->sa_len); 266 if (error < 0) { 267 (void)close(port6); 268 (void)close(port4); 269 (void)close(wport4); 270 port6 = port4 = wport4 = -1; 271 syslog(LOG_INFO, "active mode data connection failed"); 272 return -1; 273 } 274 275 syslog(LOG_INFO, "active mode data connection established"); 276 return 0; 277} 278 279static int 280ftp_passiveconn() 281{ 282 socklen_t len; 283 int error; 284 struct pollfd pfd[1]; 285 struct sockaddr *sa; 286 287 /* get passive connection from client */ 288 pfd[0].fd = wport6; 289 pfd[0].events = POLLIN; 290 len = sizeof(data6); 291 if (poll(pfd, (unsigned int)(sizeof(pfd) / sizeof(pfd[0])), 292 120000) == 0 || 293 (port6 = accept(wport6, (void *)&data6, &len)) < 0) 294 { 295 (void)close(wport6); 296 wport6 = -1; 297 syslog(LOG_INFO, "passive mode data connection failed"); 298 return -1; 299 } 300 301 /* ask passive connection to server */ 302 sa = (void *)&data4; 303 port4 = socket(sa->sa_family, SOCK_STREAM, 0); 304 if (port4 == -1) { 305 (void)close(wport6); 306 (void)close(port6); 307 wport6 = port6 = -1; 308 syslog(LOG_INFO, "passive mode data connection failed"); 309 return -1; 310 } 311 error = connect(port4, sa, (socklen_t)sa->sa_len); 312 if (error < 0) { 313 (void)close(wport6); 314 (void)close(port4); 315 (void)close(port6); 316 wport6 = port4 = port6 = -1; 317 syslog(LOG_INFO, "passive mode data connection failed"); 318 return -1; 319 } 320 321 syslog(LOG_INFO, "passive mode data connection established"); 322 return 0; 323} 324 325static ssize_t 326ftp_copy(int src, int dst) 327{ 328 int error, atmark; 329 ssize_t n; 330 331 /* OOB data handling */ 332 error = ioctl(src, SIOCATMARK, &atmark); 333 if (error != -1 && atmark == 1) { 334 n = read(src, rbuf, 1); 335 if (n == -1) 336 goto bad; 337 (void)send(dst, rbuf, (size_t)n, MSG_OOB); 338#if 0 339 n = read(src, rbuf, sizeof(rbuf)); 340 if (n == -1) 341 goto bad; 342 (void)write(dst, rbuf, (size_t)n); 343 return n; 344#endif 345 } 346 347 n = read(src, rbuf, sizeof(rbuf)); 348 switch (n) { 349 case -1: 350 case 0: 351 return n; 352 default: 353 (void)write(dst, rbuf, (size_t)n); 354 return n; 355 } 356 357 bad: 358 exit_failure("%s", strerror(errno)); 359 /*NOTREACHED*/ 360 return 0; /* to make gcc happy */ 361} 362 363static ssize_t 364ftp_copyresult(int src, int dst, enum state state) 365{ 366 int error, atmark; 367 ssize_t n; 368 socklen_t len; 369 char *param; 370 int code; 371 char *a, *p; 372 int i; 373 374 /* OOB data handling */ 375 error = ioctl(src, SIOCATMARK, &atmark); 376 if (error != -1 && atmark == 1) { 377 n = read(src, rbuf, 1); 378 if (n == -1) 379 goto bad; 380 (void)send(dst, rbuf, (size_t)n, MSG_OOB); 381#if 0 382 n = read(src, rbuf, sizeof(rbuf)); 383 if (n == -1) 384 goto bad; 385 (void)write(dst, rbuf, (size_t)n); 386 return n; 387#endif 388 } 389 390 n = read(src, rbuf, sizeof(rbuf)); 391 if (n <= 0) 392 return n; 393 rbuf[n] = '\0'; 394 395 /* 396 * parse argument 397 */ 398 p = rbuf; 399 for (i = 0; i < 3; i++) { 400 if (!isdigit((unsigned char)*p)) { 401 /* invalid reply */ 402 (void)write(dst, rbuf, (size_t)n); 403 return n; 404 } 405 p++; 406 } 407 if (!isspace((unsigned char)*p)) { 408 /* invalid reply */ 409 (void)write(dst, rbuf, (size_t)n); 410 return n; 411 } 412 code = atoi(rbuf); 413 param = p; 414 /* param points to first non-command token, if any */ 415 while (*param && isspace((unsigned char)*param)) 416 param++; 417 if (!*param) 418 param = NULL; 419 420 switch (state) { 421 case NONE: 422 if (!passivemode && rbuf[0] == '1') { 423 if (ftp_activeconn() < 0) { 424 n = snprintf(rbuf, sizeof(rbuf), 425 "425 Cannot open data connection\r\n"); 426 if (n < 0 || n >= (int)sizeof(rbuf)) 427 n = 0; 428 } 429 } 430 if (n) 431 (void)write(dst, rbuf, (size_t)n); 432 return n; 433 case LPRT: 434 case EPRT: 435 /* expecting "200 PORT command successful." */ 436 if (code == 200) { 437 p = strstr(rbuf, "PORT"); 438 if (p) { 439 p[0] = (state == LPRT) ? 'L' : 'E'; 440 p[1] = 'P'; 441 } 442 } else { 443 (void)close(wport4); 444 wport4 = -1; 445 } 446 (void)write(dst, rbuf, (size_t)n); 447 return n; 448 case LPSV: 449 case EPSV: 450 /* 451 * expecting "227 Entering Passive Mode (x,x,x,x,x,x,x)" 452 * (in some cases result comes without paren) 453 */ 454 if (code != 227) { 455passivefail0: 456 (void)close(wport6); 457 wport6 = -1; 458 (void)write(dst, rbuf, (size_t)n); 459 return n; 460 } 461 462 { 463 unsigned int ho[4], po[2]; 464 struct sockaddr_in *sin; 465 struct sockaddr_in6 *sin6; 466 u_short port; 467 468 /* 469 * PASV result -> LPSV/EPSV result 470 */ 471 p = param; 472 while (*p && *p != '(' && !isdigit((unsigned char)*p)) /*)*/ 473 p++; 474 if (!*p) 475 goto passivefail0; /*XXX*/ 476 if (*p == '(') /*)*/ 477 p++; 478 n = sscanf(p, "%u,%u,%u,%u,%u,%u", 479 &ho[0], &ho[1], &ho[2], &ho[3], &po[0], &po[1]); 480 if (n != 6) 481 goto passivefail0; /*XXX*/ 482 483 /* keep PORT parameter */ 484 memset(&data4, 0, sizeof(data4)); 485 sin = (void *)&data4; 486 sin->sin_len = sizeof(*sin); 487 sin->sin_family = AF_INET; 488 sin->sin_addr.s_addr = 0; 489 for (n = 0; n < 4; n++) { 490 sin->sin_addr.s_addr |= htonl(((uint32_t)(ho[n] & 0xff) 491 << (int)((3 - n) * 8))); 492 } 493 sin->sin_port = htons(((po[0] & 0xff) << 8) | (po[1] & 0xff)); 494 495 /* get ready for passive data connection */ 496 memset(&data6, 0, sizeof(data6)); 497 sin6 = (void *)&data6; 498 sin6->sin6_len = sizeof(*sin6); 499 sin6->sin6_family = AF_INET6; 500 wport6 = socket(sin6->sin6_family, SOCK_STREAM, 0); 501 if (wport6 == -1) { 502passivefail: 503 return dprintf(src, 504 "500 could not translate from PASV\r\n"); 505 } 506#ifdef IPV6_FAITH 507 { 508 int on = 1; 509 error = setsockopt(wport6, IPPROTO_IPV6, IPV6_FAITH, 510 &on, (socklen_t)sizeof(on)); 511 if (error == -1) 512 exit_failure("setsockopt(IPV6_FAITH): %s", strerror(errno)); 513 } 514#endif 515 error = bind(wport6, (void *)sin6, (socklen_t)sin6->sin6_len); 516 if (error == -1) { 517 (void)close(wport6); 518 wport6 = -1; 519 goto passivefail; 520 } 521 error = listen(wport6, 1); 522 if (error == -1) { 523 (void)close(wport6); 524 wport6 = -1; 525 goto passivefail; 526 } 527 528 /* transmit LPSV or EPSV */ 529 /* 530 * addr from dst, port from wport6 531 */ 532 len = sizeof(data6); 533 error = getsockname(wport6, (void *)&data6, &len); 534 if (error == -1) { 535 (void)close(wport6); 536 wport6 = -1; 537 goto passivefail; 538 } 539 sin6 = (void *)&data6; 540 port = sin6->sin6_port; 541 542 len = sizeof(data6); 543 error = getsockname(dst, (void *)&data6, &len); 544 if (error == -1) { 545 (void)close(wport6); 546 wport6 = -1; 547 goto passivefail; 548 } 549 sin6 = (void *)&data6; 550 sin6->sin6_port = port; 551 552 if (state == LPSV) { 553 a = (void *)&sin6->sin6_addr; 554 p = (void *)&sin6->sin6_port; 555 passivemode = 1; 556 return dprintf(dst, 557 "228 Entering Long Passive Mode (%d,%d,%d,%d,%d,%d," 558 "%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d)\r\n", 559 6, 16, UC(a[0]), UC(a[1]), UC(a[2]), UC(a[3]), 560 UC(a[4]), UC(a[5]), UC(a[6]), UC(a[7]), 561 UC(a[8]), UC(a[9]), UC(a[10]), UC(a[11]), 562 UC(a[12]), UC(a[13]), UC(a[14]), UC(a[15]), 563 2, UC(p[0]), UC(p[1])); 564 } else { 565 passivemode = 1; 566 return dprintf(dst, 567 "229 Entering Extended Passive Mode (|||%d|)\r\n", 568 ntohs(sin6->sin6_port)); 569 } 570 } 571 } 572 573 bad: 574 exit_failure("%s", strerror(errno)); 575 /*NOTREACHED*/ 576 return 0; /* to make gcc happy */ 577} 578 579static ssize_t 580ftp_copycommand(int src, int dst, enum state *state) 581{ 582 int error, atmark; 583 ssize_t n; 584 socklen_t len; 585 unsigned int af, hal, ho[16], pal, po[2]; 586 char *a, *p, *q; 587 char cmd[5], *param; 588 struct sockaddr_in *sin; 589 struct sockaddr_in6 *sin6; 590 enum state nstate; 591 char ch; 592 int i; 593 594 /* OOB data handling */ 595 error = ioctl(src, SIOCATMARK, &atmark); 596 if (error != -1 && atmark == 1) { 597 n = read(src, rbuf, 1); 598 if (n == -1) 599 goto bad; 600 (void)send(dst, rbuf, (size_t)n, MSG_OOB); 601#if 0 602 n = read(src, rbuf, sizeof(rbuf)); 603 if (n == -1) 604 goto bad; 605 (void)write(dst, rbuf, (size_t)n); 606 return n; 607#endif 608 } 609 610 n = read(src, rbuf, sizeof(rbuf)); 611 if (n <= 0) 612 return n; 613 rbuf[n] = '\0'; 614 615 if (n < 4) { 616 (void)write(dst, rbuf, (size_t)n); 617 return n; 618 } 619 620 /* 621 * parse argument 622 */ 623 p = rbuf; 624 q = cmd; 625 for (i = 0; i < 4; i++) { 626 if (!isalpha((unsigned char)*p)) { 627 /* invalid command */ 628 (void)write(dst, rbuf, (size_t)n); 629 return n; 630 } 631 *q++ = islower((unsigned char)*p) ? toupper((unsigned char)*p) : *p; 632 p++; 633 } 634 if (!isspace((unsigned char)*p)) { 635 /* invalid command */ 636 (void)write(dst, rbuf, (size_t)n); 637 return n; 638 } 639 *q = '\0'; 640 param = p; 641 /* param points to first non-command token, if any */ 642 while (*param && isspace((unsigned char)*param)) 643 param++; 644 if (!*param) 645 param = NULL; 646 647 *state = NONE; 648 649 if (strcmp(cmd, "LPRT") == 0 && param) { 650 /* 651 * LPRT -> PORT 652 */ 653 nstate = LPRT; 654 655 (void)close(wport4); 656 (void)close(wport6); 657 (void)close(port4); 658 (void)close(port6); 659 wport4 = wport6 = port4 = port6 = -1; 660 661 if (epsvall) { 662 return dprintf(src, "501 %s disallowed in EPSV ALL\r\n", 663 cmd); 664 } 665 666 n = sscanf(param, 667 "%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u," 668 "%u,%u,%u", &af, &hal, &ho[0], &ho[1], &ho[2], &ho[3], 669 &ho[4], &ho[5], &ho[6], &ho[7], 670 &ho[8], &ho[9], &ho[10], &ho[11], 671 &ho[12], &ho[13], &ho[14], &ho[15], 672 &pal, &po[0], &po[1]); 673 if (n != 21 || af != 6 || hal != 16|| pal != 2) { 674 return dprintf(src, 675 "501 illegal parameter to LPRT\r\n"); 676 } 677 678 /* keep LPRT parameter */ 679 memset(&data6, 0, sizeof(data6)); 680 sin6 = (void *)&data6; 681 sin6->sin6_len = sizeof(*sin6); 682 sin6->sin6_family = AF_INET6; 683 for (n = 0; n < 16; n++) 684 sin6->sin6_addr.s6_addr[n] = ho[n]; 685 sin6->sin6_port = htons(((po[0] & 0xff) << 8) | (po[1] & 0xff)); 686 687sendport: 688 /* get ready for active data connection */ 689 len = sizeof(data4); 690 error = getsockname(dst, (void *)&data4, &len); 691 if (error == -1) { 692lprtfail: 693 return dprintf(src, 694 "500 could not translate to PORT\r\n"); 695 } 696 if (((struct sockaddr *)(void *)&data4)->sa_family != AF_INET) 697 goto lprtfail; 698 sin = (void *)&data4; 699 sin->sin_port = 0; 700 wport4 = socket(sin->sin_family, SOCK_STREAM, 0); 701 if (wport4 == -1) 702 goto lprtfail; 703 error = bind(wport4, (void *)sin, (socklen_t)sin->sin_len); 704 if (error == -1) { 705 (void)close(wport4); 706 wport4 = -1; 707 goto lprtfail; 708 } 709 error = listen(wport4, 1); 710 if (error == -1) { 711 (void)close(wport4); 712 wport4 = -1; 713 goto lprtfail; 714 } 715 716 /* transmit PORT */ 717 len = sizeof(data4); 718 error = getsockname(wport4, (void *)&data4, &len); 719 if (error == -1) { 720 (void)close(wport4); 721 wport4 = -1; 722 goto lprtfail; 723 } 724 if (((struct sockaddr *)(void *)&data4)->sa_family != AF_INET) { 725 (void)close(wport4); 726 wport4 = -1; 727 goto lprtfail; 728 } 729 sin = (void *)&data4; 730 a = (void *)&sin->sin_addr; 731 p = (void *)&sin->sin_port; 732 *state = nstate; 733 passivemode = 0; 734 return dprintf(dst, "PORT %d,%d,%d,%d,%d,%d\r\n", 735 UC(a[0]), UC(a[1]), UC(a[2]), UC(a[3]), UC(p[0]), UC(p[1])); 736 } else if (strcmp(cmd, "EPRT") == 0 && param) { 737 /* 738 * EPRT -> PORT 739 */ 740 char *afp, *hostp, *portp; 741 struct addrinfo hints, *res; 742 743 nstate = EPRT; 744 745 (void)close(wport4); 746 (void)close(wport6); 747 (void)close(port4); 748 (void)close(port6); 749 wport4 = wport6 = port4 = port6 = -1; 750 751 if (epsvall) { 752 return dprintf(src, "501 %s disallowed in EPSV ALL\r\n", 753 cmd); 754 } 755 756 p = param; 757 ch = *p++; /* boundary character */ 758 afp = p; 759 while (*p && *p != ch) 760 p++; 761 if (!*p) { 762eprtparamfail: 763 return dprintf(src, 764 "501 illegal parameter to EPRT\r\n"); 765 } 766 *p++ = '\0'; 767 hostp = p; 768 while (*p && *p != ch) 769 p++; 770 if (!*p) 771 goto eprtparamfail; 772 *p++ = '\0'; 773 portp = p; 774 while (*p && *p != ch) 775 p++; 776 if (!*p) 777 goto eprtparamfail; 778 *p++ = '\0'; 779 780 n = sscanf(afp, "%d", &af); 781 if (n != 1 || af != 2) { 782 return dprintf(src, 783 "501 unsupported address family to EPRT\r\n"); 784 } 785 memset(&hints, 0, sizeof(hints)); 786 hints.ai_family = AF_UNSPEC; 787 hints.ai_socktype = SOCK_STREAM; 788 hints.ai_protocol = IPPROTO_TCP; 789 error = getaddrinfo(hostp, portp, &hints, &res); 790 if (error) { 791 return dprintf(src, 792 "501 EPRT: %s\r\n", gai_strerror(error)); 793 } 794 if (res->ai_next) { 795 freeaddrinfo(res); 796 return dprintf(src, 797 "501 EPRT: %s resolved to multiple addresses\r\n", 798 hostp); 799 } 800 801 memcpy(&data6, res->ai_addr, res->ai_addrlen); 802 803 freeaddrinfo(res); 804 goto sendport; 805 } else if (strcmp(cmd, "LPSV") == 0 && !param) { 806 /* 807 * LPSV -> PASV 808 */ 809 nstate = LPSV; 810 811 (void)close(wport4); 812 (void)close(wport6); 813 (void)close(port4); 814 (void)close(port6); 815 wport4 = wport6 = port4 = port6 = -1; 816 817 if (epsvall) { 818 return dprintf(src, "501 %s disallowed in EPSV ALL\r\n", 819 cmd); 820 } 821 822 *state = LPSV; 823 passivemode = 0; /* to be set to 1 later */ 824 /* transmit PASV */ 825 return dprintf(dst, "PASV\r\n"); 826 } else if (strcmp(cmd, "EPSV") == 0 && !param) { 827 /* 828 * EPSV -> PASV 829 */ 830 (void)close(wport4); 831 (void)close(wport6); 832 (void)close(port4); 833 (void)close(port6); 834 wport4 = wport6 = port4 = port6 = -1; 835 836 *state = EPSV; 837 passivemode = 0; /* to be set to 1 later */ 838 return dprintf(dst, "PASV\r\n"); 839 } else if (strcmp(cmd, "EPSV") == 0 && param && 840 strncasecmp(param, "ALL", 3) == 0 && 841 isspace((unsigned char)param[3])) { 842 /* 843 * EPSV ALL 844 */ 845 epsvall = 1; 846 return dprintf(src, "200 EPSV ALL command successful.\r\n"); 847 } else if (strcmp(cmd, "PORT") == 0 || strcmp(cmd, "PASV") == 0) { 848 /* 849 * reject PORT/PASV 850 */ 851 return dprintf(src, "502 %s not implemented.\r\n", cmd); 852 } else if (passivemode 853 && (strcmp(cmd, "STOR") == 0 854 || strcmp(cmd, "STOU") == 0 855 || strcmp(cmd, "RETR") == 0 856 || strcmp(cmd, "LIST") == 0 857 || strcmp(cmd, "NLST") == 0 858 || strcmp(cmd, "APPE") == 0)) { 859 /* 860 * commands with data transfer. need to care about passive 861 * mode data connection. 862 */ 863 864 *state = NONE; 865 if (ftp_passiveconn() < 0) { 866 return dprintf(src, 867 "425 Cannot open data connection\r\n"); 868 } else { 869 /* simply relay the command */ 870 return write(dst, rbuf, (size_t)n); 871 } 872 } else { 873 /* simply relay it */ 874 *state = NONE; 875 return write(dst, rbuf, (size_t)n); 876 } 877 878 bad: 879 exit_failure("%s", strerror(errno)); 880 /*NOTREACHED*/ 881 return 0; /* to make gcc happy */ 882} 883