ftp.c revision 78064
1/* $KAME: ftp.c,v 1.10 2000/09/14 00:23:39 itojun Exp $ */ 2 3/* 4 * Copyright (C) 1997 and 1998 WIDE Project. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 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. Neither the name of the project nor the names of its contributors 16 * may be used to endorse or promote products derived from this software 17 * without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * SUCH DAMAGE. 30 * 31 * $FreeBSD: head/usr.sbin/faithd/ftp.c 78064 2001-06-11 12:39:29Z ume $ 32 */ 33 34#include <sys/param.h> 35#include <sys/types.h> 36#include <sys/socket.h> 37#include <sys/ioctl.h> 38#include <sys/time.h> 39 40#include <stdio.h> 41#include <stdlib.h> 42#include <string.h> 43#include <syslog.h> 44#include <unistd.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 char sbuf[MSS]; 56static int passivemode = 0; 57static int wport4 = -1; /* listen() to active */ 58static int wport6 = -1; /* listen() to passive */ 59static int port4 = -1; /* active: inbound passive: outbound */ 60static int port6 = -1; /* active: outbound passive: inbound */ 61static struct sockaddr_storage data4; /* server data address */ 62static struct sockaddr_storage data6; /* client data address */ 63static int epsvall = 0; 64 65#ifdef FAITH4 66enum state { NONE, LPRT, EPRT, PORT, LPSV, EPSV, PASV }; 67#else 68enum state { NONE, LPRT, EPRT, LPSV, EPSV }; 69#endif 70 71static int ftp_activeconn __P((void)); 72static int ftp_passiveconn __P((void)); 73static int ftp_copy __P((int, int)); 74static int ftp_copyresult __P((int, int, enum state)); 75static int ftp_copycommand __P((int, int, enum state *)); 76 77void 78ftp_relay(int ctl6, int ctl4) 79{ 80 fd_set readfds; 81 int error; 82 enum state state = NONE; 83 struct timeval tv; 84 85 syslog(LOG_INFO, "starting ftp control connection"); 86 87 for (;;) { 88 FD_ZERO(&readfds); 89 FD_SET(ctl4, &readfds); 90 FD_SET(ctl6, &readfds); 91 if (0 <= port4) 92 FD_SET(port4, &readfds); 93 if (0 <= port6) 94 FD_SET(port6, &readfds); 95#if 0 96 if (0 <= wport4) 97 FD_SET(wport4, &readfds); 98 if (0 <= wport6) 99 FD_SET(wport6, &readfds); 100#endif 101 tv.tv_sec = FAITH_TIMEOUT; 102 tv.tv_usec = 0; 103 104 error = select(256, &readfds, NULL, NULL, &tv); 105 if (error == -1) 106 exit_failure("select: %s", ERRSTR); 107 else if (error == 0) 108 exit_failure("connection timeout"); 109 110 /* 111 * The order of the following checks does (slightly) matter. 112 * It is important to visit all checks (do not use "continue"), 113 * otherwise some of the pipe may become full and we cannot 114 * relay correctly. 115 */ 116 if (FD_ISSET(ctl6, &readfds)) { 117 /* 118 * copy control connection from the client. 119 * command translation is necessary. 120 */ 121 error = ftp_copycommand(ctl6, ctl4, &state); 122 123 switch (error) { 124 case -1: 125 goto bad; 126 case 0: 127 close(ctl4); 128 close(ctl6); 129 exit_success("terminating ftp control connection"); 130 /*NOTREACHED*/ 131 default: 132 break; 133 } 134 } 135 if (FD_ISSET(ctl4, &readfds)) { 136 /* 137 * copy control connection from the server 138 * translation of result code is necessary. 139 */ 140 error = ftp_copyresult(ctl4, ctl6, state); 141 142 switch (error) { 143 case -1: 144 goto bad; 145 case 0: 146 close(ctl4); 147 close(ctl6); 148 exit_success("terminating ftp control connection"); 149 /*NOTREACHED*/ 150 default: 151 break; 152 } 153 } 154 if (0 <= port4 && 0 <= port6 && FD_ISSET(port4, &readfds)) { 155 /* 156 * copy data connection. 157 * no special treatment necessary. 158 */ 159 if (FD_ISSET(port4, &readfds)) 160 error = ftp_copy(port4, port6); 161 switch (error) { 162 case -1: 163 goto bad; 164 case 0: 165 close(port4); 166 close(port6); 167 port4 = port6 = -1; 168 syslog(LOG_INFO, "terminating data connection"); 169 break; 170 default: 171 break; 172 } 173 } 174 if (0 <= port4 && 0 <= port6 && FD_ISSET(port6, &readfds)) { 175 /* 176 * copy data connection. 177 * no special treatment necessary. 178 */ 179 if (FD_ISSET(port6, &readfds)) 180 error = ftp_copy(port6, port4); 181 switch (error) { 182 case -1: 183 goto bad; 184 case 0: 185 close(port4); 186 close(port6); 187 port4 = port6 = -1; 188 syslog(LOG_INFO, "terminating data connection"); 189 break; 190 default: 191 break; 192 } 193 } 194#if 0 195 if (wport4 && FD_ISSET(wport4, &readfds)) { 196 /* 197 * establish active data connection from the server. 198 */ 199 ftp_activeconn(); 200 } 201 if (wport6 && FD_ISSET(wport6, &readfds)) { 202 /* 203 * establish passive data connection from the client. 204 */ 205 ftp_passiveconn(); 206 } 207#endif 208 } 209 210 bad: 211 exit_failure(ERRSTR); 212} 213 214static int 215ftp_activeconn() 216{ 217 int n; 218 int error; 219 fd_set set; 220 struct timeval timeout; 221 struct sockaddr *sa; 222 223 /* get active connection from server */ 224 FD_ZERO(&set); 225 FD_SET(wport4, &set); 226 timeout.tv_sec = 120; 227 timeout.tv_usec = -1; 228 n = sizeof(data4); 229 if (select(wport4 + 1, &set, NULL, NULL, &timeout) == 0 230 || (port4 = accept(wport4, (struct sockaddr *)&data4, &n)) < 0) { 231 close(wport4); 232 wport4 = -1; 233 syslog(LOG_INFO, "active mode data connection failed"); 234 return -1; 235 } 236 237 /* ask active connection to client */ 238 sa = (struct sockaddr *)&data6; 239 port6 = socket(sa->sa_family, SOCK_STREAM, 0); 240 if (port6 == -1) { 241 close(port4); 242 close(wport4); 243 port4 = wport4 = -1; 244 syslog(LOG_INFO, "active mode data connection failed"); 245 return -1; 246 } 247 error = connect(port6, sa, sa->sa_len); 248 if (port6 == -1) { 249 close(port6); 250 close(port4); 251 close(wport4); 252 port6 = port4 = wport4 = -1; 253 syslog(LOG_INFO, "active mode data connection failed"); 254 return -1; 255 } 256 257 syslog(LOG_INFO, "active mode data connection established"); 258 return 0; 259} 260 261static int 262ftp_passiveconn() 263{ 264 int n; 265 int error; 266 fd_set set; 267 struct timeval timeout; 268 struct sockaddr *sa; 269 270 /* get passive connection from client */ 271 FD_ZERO(&set); 272 FD_SET(wport6, &set); 273 timeout.tv_sec = 120; 274 timeout.tv_usec = 0; 275 n = sizeof(data6); 276 if (select(wport6 + 1, &set, NULL, NULL, &timeout) == 0 277 || (port6 = accept(wport6, (struct sockaddr *)&data6, &n)) < 0) { 278 close(wport6); 279 wport6 = -1; 280 syslog(LOG_INFO, "passive mode data connection failed"); 281 return -1; 282 } 283 284 /* ask passive connection to server */ 285 sa = (struct sockaddr *)&data4; 286 port4 = socket(sa->sa_family, SOCK_STREAM, 0); 287 if (port4 == -1) { 288 close(wport6); 289 close(port6); 290 wport6 = port6 = -1; 291 syslog(LOG_INFO, "passive mode data connection failed"); 292 return -1; 293 } 294 error = connect(port4, sa, sa->sa_len); 295 if (port4 == -1) { 296 close(wport6); 297 close(port4); 298 close(port6); 299 wport6 = port4 = port6 = -1; 300 syslog(LOG_INFO, "passive mode data connection failed"); 301 return -1; 302 } 303 304 syslog(LOG_INFO, "passive mode data connection established"); 305 return 0; 306} 307 308static int 309ftp_copy(int src, int dst) 310{ 311 int error, atmark; 312 int n; 313 314 /* OOB data handling */ 315 error = ioctl(src, SIOCATMARK, &atmark); 316 if (error != -1 && atmark == 1) { 317 n = read(src, rbuf, 1); 318 if (n == -1) 319 goto bad; 320 send(dst, rbuf, n, MSG_OOB); 321#if 0 322 n = read(src, rbuf, sizeof(rbuf)); 323 if (n == -1) 324 goto bad; 325 write(dst, rbuf, n); 326 return n; 327#endif 328 } 329 330 n = read(src, rbuf, sizeof(rbuf)); 331 switch (n) { 332 case -1: 333 case 0: 334 return n; 335 default: 336 write(dst, rbuf, n); 337 return n; 338 } 339 340 bad: 341 exit_failure(ERRSTR); 342 /*NOTREACHED*/ 343 return 0; /* to make gcc happy */ 344} 345 346static int 347ftp_copyresult(int src, int dst, enum state state) 348{ 349 int error, atmark; 350 int n; 351 char *param; 352 int code; 353 354 /* OOB data handling */ 355 error = ioctl(src, SIOCATMARK, &atmark); 356 if (error != -1 && atmark == 1) { 357 n = read(src, rbuf, 1); 358 if (n == -1) 359 goto bad; 360 send(dst, rbuf, n, MSG_OOB); 361#if 0 362 n = read(src, rbuf, sizeof(rbuf)); 363 if (n == -1) 364 goto bad; 365 write(dst, rbuf, n); 366 return n; 367#endif 368 } 369 370 n = read(src, rbuf, sizeof(rbuf)); 371 if (n <= 0) 372 return n; 373 rbuf[n] = '\0'; 374 375 /* 376 * parse argument 377 */ 378 { 379 char *p; 380 int i; 381 382 p = rbuf; 383 for (i = 0; i < 3; i++) { 384 if (!isdigit(*p)) { 385 /* invalid reply */ 386 write(dst, rbuf, n); 387 return n; 388 } 389 p++; 390 } 391 if (!isspace(*p)) { 392 /* invalid reply */ 393 write(dst, rbuf, n); 394 return n; 395 } 396 code = atoi(rbuf); 397 param = p; 398 /* param points to first non-command token, if any */ 399 while (*param && isspace(*param)) 400 param++; 401 if (!*param) 402 param = NULL; 403 } 404 405 switch (state) { 406 case NONE: 407 if (!passivemode && rbuf[0] == '1') { 408 if (ftp_activeconn() < 0) { 409 n = snprintf(rbuf, sizeof(rbuf), 410 "425 Cannot open data connetion\r\n"); 411 } 412 } 413 write(dst, rbuf, n); 414 return n; 415 case LPRT: 416 case EPRT: 417 /* expecting "200 PORT command successful." */ 418 if (code == 200) { 419 char *p; 420 421 p = strstr(rbuf, "PORT"); 422 if (p) { 423 p[0] = (state == LPRT) ? 'L' : 'E'; 424 p[1] = 'P'; 425 } 426 } else { 427 close(wport4); 428 wport4 = -1; 429 } 430 write(dst, rbuf, n); 431 return n; 432#ifdef FAITH4 433 case PORT: 434 /* expecting "200 EPRT command successful." */ 435 if (code == 200) { 436 char *p; 437 438 p = strstr(rbuf, "EPRT"); 439 if (p) { 440 p[0] = 'P'; 441 p[1] = 'O'; 442 } 443 } else { 444 close(wport4); 445 wport4 = -1; 446 } 447 write(dst, rbuf, n); 448 return n; 449#endif 450 case LPSV: 451 case EPSV: 452 /* 453 * expecting "227 Entering Passive Mode (x,x,x,x,x,x,x)" 454 * (in some cases result comes without paren) 455 */ 456 if (code != 227) { 457passivefail0: 458 close(wport6); 459 wport6 = -1; 460 write(dst, rbuf, n); 461 return n; 462 } 463 464 { 465 unsigned int ho[4], po[2]; 466 struct sockaddr_in *sin; 467 struct sockaddr_in6 *sin6; 468 u_short port; 469 char *p; 470 471 /* 472 * PASV result -> LPSV/EPSV result 473 */ 474 p = param; 475 while (*p && *p != '(' && !isdigit(*p)) /*)*/ 476 p++; 477 if (!*p) 478 goto passivefail0; /*XXX*/ 479 if (*p == '(') /*)*/ 480 p++; 481 n = sscanf(p, "%u,%u,%u,%u,%u,%u", 482 &ho[0], &ho[1], &ho[2], &ho[3], &po[0], &po[1]); 483 if (n != 6) 484 goto passivefail0; /*XXX*/ 485 486 /* keep PORT parameter */ 487 memset(&data4, 0, sizeof(data4)); 488 sin = (struct sockaddr_in *)&data4; 489 sin->sin_len = sizeof(*sin); 490 sin->sin_family = AF_INET; 491 sin->sin_addr.s_addr = 0; 492 for (n = 0; n < 4; n++) { 493 sin->sin_addr.s_addr |= 494 htonl((ho[n] & 0xff) << ((3 - n) * 8)); 495 } 496 sin->sin_port = htons(((po[0] & 0xff) << 8) | (po[1] & 0xff)); 497 498 /* get ready for passive data connection */ 499 memset(&data6, 0, sizeof(data6)); 500 sin6 = (struct sockaddr_in6 *)&data6; 501 sin6->sin6_len = sizeof(*sin6); 502 sin6->sin6_family = AF_INET6; 503 wport6 = socket(sin6->sin6_family, SOCK_STREAM, 0); 504 if (wport6 == -1) { 505passivefail: 506 n = snprintf(sbuf, sizeof(sbuf), 507 "500 could not translate from PASV\r\n"); 508 write(src, sbuf, n); 509 return n; 510 } 511#ifdef IPV6_FAITH 512 { 513 int on = 1; 514 error = setsockopt(wport6, IPPROTO_IPV6, IPV6_FAITH, 515 &on, sizeof(on)); 516 if (error == -1) 517 exit_failure("setsockopt(IPV6_FAITH): %s", ERRSTR); 518 } 519#endif 520 error = bind(wport6, (struct sockaddr *)sin6, sin6->sin6_len); 521 if (error == -1) { 522 close(wport6); 523 wport6 = -1; 524 goto passivefail; 525 } 526 error = listen(wport6, 1); 527 if (error == -1) { 528 close(wport6); 529 wport6 = -1; 530 goto passivefail; 531 } 532 533 /* transmit LPSV or EPSV */ 534 /* 535 * addr from dst, port from wport6 536 */ 537 n = sizeof(data6); 538 error = getsockname(wport6, (struct sockaddr *)&data6, &n); 539 if (error == -1) { 540 close(wport6); 541 wport6 = -1; 542 goto passivefail; 543 } 544 sin6 = (struct sockaddr_in6 *)&data6; 545 port = sin6->sin6_port; 546 547 n = sizeof(data6); 548 error = getsockname(dst, (struct sockaddr *)&data6, &n); 549 if (error == -1) { 550 close(wport6); 551 wport6 = -1; 552 goto passivefail; 553 } 554 sin6 = (struct sockaddr_in6 *)&data6; 555 sin6->sin6_port = port; 556 557 if (state == LPSV) { 558 char *a, *p; 559 560 a = (char *)&sin6->sin6_addr; 561 p = (char *)&sin6->sin6_port; 562 n = snprintf(sbuf, sizeof(sbuf), 563"228 Entering Long Passive Mode (%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d)\r\n", 564 6, 16, UC(a[0]), UC(a[1]), UC(a[2]), UC(a[3]), 565 UC(a[4]), UC(a[5]), UC(a[6]), UC(a[7]), 566 UC(a[8]), UC(a[9]), UC(a[10]), UC(a[11]), 567 UC(a[12]), UC(a[13]), UC(a[14]), UC(a[15]), 568 2, UC(p[0]), UC(p[1])); 569 write(dst, sbuf, n); 570 passivemode = 1; 571 return n; 572 } else { 573 n = snprintf(sbuf, sizeof(sbuf), 574"229 Entering Extended Passive Mode (|||%d|)\r\n", 575 ntohs(sin6->sin6_port)); 576 write(dst, sbuf, n); 577 passivemode = 1; 578 return n; 579 } 580 } 581#ifdef FAITH4 582 case PASV: 583 /* expecting "229 Entering Extended Passive Mode (|||x|)" */ 584 if (code != 229) { 585passivefail1: 586 close(wport6); 587 wport6 = -1; 588 write(dst, rbuf, n); 589 return n; 590 } 591 592 { 593 u_short port; 594 char *p; 595 struct sockaddr_in *sin; 596 struct sockaddr_in6 *sin6; 597 598 /* 599 * EPSV result -> PORT result 600 */ 601 p = param; 602 while (*p && *p != '(') /*)*/ 603 p++; 604 if (!*p) 605 goto passivefail1; /*XXX*/ 606 p++; 607 n = sscanf(p, "|||%hu|", &port); 608 if (n != 1) 609 goto passivefail1; /*XXX*/ 610 611 /* keep EPRT parameter */ 612 n = sizeof(data4); 613 error = getpeername(src, (struct sockaddr *)&data4, &n); 614 if (error == -1) 615 goto passivefail1; /*XXX*/ 616 sin6 = (struct sockaddr_in6 *)&data4; 617 sin6->sin6_port = htons(port); 618 619 /* get ready for passive data connection */ 620 memset(&data6, 0, sizeof(data6)); 621 sin = (struct sockaddr_in *)&data6; 622 sin->sin_len = sizeof(*sin); 623 sin->sin_family = AF_INET; 624 wport6 = socket(sin->sin_family, SOCK_STREAM, 0); 625 if (wport6 == -1) { 626passivefail2: 627 n = snprintf(sbuf, sizeof(sbuf), 628 "500 could not translate from EPSV\r\n"); 629 write(src, sbuf, n); 630 return n; 631 } 632#ifdef IP_FAITH 633 { 634 int on = 1; 635 error = setsockopt(wport6, IPPROTO_IP, IP_FAITH, 636 &on, sizeof(on)); 637 if (error == -1) 638 exit_error("setsockopt(IP_FAITH): %s", ERRSTR); 639 } 640#endif 641 error = bind(wport6, (struct sockaddr *)sin, sin->sin_len); 642 if (error == -1) { 643 close(wport6); 644 wport6 = -1; 645 goto passivefail2; 646 } 647 error = listen(wport6, 1); 648 if (error == -1) { 649 close(wport6); 650 wport6 = -1; 651 goto passivefail2; 652 } 653 654 /* transmit PORT */ 655 /* 656 * addr from dst, port from wport6 657 */ 658 n = sizeof(data6); 659 error = getsockname(wport6, (struct sockaddr *)&data6, &n); 660 if (error == -1) { 661 close(wport6); 662 wport6 = -1; 663 goto passivefail2; 664 } 665 sin = (struct sockaddr_in *)&data6; 666 port = sin->sin_port; 667 668 n = sizeof(data6); 669 error = getsockname(dst, (struct sockaddr *)&data6, &n); 670 if (error == -1) { 671 close(wport6); 672 wport6 = -1; 673 goto passivefail2; 674 } 675 sin = (struct sockaddr_in *)&data6; 676 sin->sin_port = port; 677 678 { 679 char *a, *p; 680 681 a = (char *)&sin->sin_addr; 682 p = (char *)&sin->sin_port; 683 n = snprintf(sbuf, sizeof(sbuf), 684"227 Entering Passive Mode (%d,%d,%d,%d,%d,%d)\r\n", 685 UC(a[0]), UC(a[1]), UC(a[2]), UC(a[3]), 686 UC(p[0]), UC(p[1])); 687 write(dst, sbuf, n); 688 passivemode = 1; 689 return n; 690 } 691 } 692#endif /* FAITH4 */ 693 } 694 695 bad: 696 exit_failure(ERRSTR); 697 /*NOTREACHED*/ 698 return 0; /* to make gcc happy */ 699} 700 701static int 702ftp_copycommand(int src, int dst, enum state *state) 703{ 704 int error, atmark; 705 int n; 706 unsigned int af, hal, ho[16], pal, po[2]; 707 char *a, *p; 708 char cmd[5], *param; 709 struct sockaddr_in *sin; 710 struct sockaddr_in6 *sin6; 711 enum state nstate; 712 char ch; 713 714 /* OOB data handling */ 715 error = ioctl(src, SIOCATMARK, &atmark); 716 if (error != -1 && atmark == 1) { 717 n = read(src, rbuf, 1); 718 if (n == -1) 719 goto bad; 720 send(dst, rbuf, n, MSG_OOB); 721#if 0 722 n = read(src, rbuf, sizeof(rbuf)); 723 if (n == -1) 724 goto bad; 725 write(dst, rbuf, n); 726 return n; 727#endif 728 } 729 730 n = read(src, rbuf, sizeof(rbuf)); 731 if (n <= 0) 732 return n; 733 rbuf[n] = '\0'; 734 735 if (n < 4) { 736 write(dst, rbuf, n); 737 return n; 738 } 739 740 /* 741 * parse argument 742 */ 743 { 744 char *p, *q; 745 int i; 746 747 p = rbuf; 748 q = cmd; 749 for (i = 0; i < 4; i++) { 750 if (!isalpha(*p)) { 751 /* invalid command */ 752 write(dst, rbuf, n); 753 return n; 754 } 755 *q++ = islower(*p) ? toupper(*p) : *p; 756 p++; 757 } 758 if (!isspace(*p)) { 759 /* invalid command */ 760 write(dst, rbuf, n); 761 return n; 762 } 763 *q = '\0'; 764 param = p; 765 /* param points to first non-command token, if any */ 766 while (*param && isspace(*param)) 767 param++; 768 if (!*param) 769 param = NULL; 770 } 771 772 *state = NONE; 773 774 if (strcmp(cmd, "LPRT") == 0 && param) { 775 /* 776 * LPRT -> PORT 777 */ 778 nstate = LPRT; 779 780 close(wport4); 781 close(wport6); 782 close(port4); 783 close(port6); 784 wport4 = wport6 = port4 = port6 = -1; 785 786 if (epsvall) { 787 n = snprintf(sbuf, sizeof(sbuf), "501 %s disallowed in EPSV ALL\r\n", 788 cmd); 789 write(src, sbuf, n); 790 return n; 791 } 792 793 n = sscanf(param, 794"%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u", 795 &af, &hal, &ho[0], &ho[1], &ho[2], &ho[3], 796 &ho[4], &ho[5], &ho[6], &ho[7], 797 &ho[8], &ho[9], &ho[10], &ho[11], 798 &ho[12], &ho[13], &ho[14], &ho[15], 799 &pal, &po[0], &po[1]); 800 if (n != 21 || af != 6 || hal != 16|| pal != 2) { 801 n = snprintf(sbuf, sizeof(sbuf), 802 "501 illegal parameter to LPRT\r\n"); 803 write(src, sbuf, n); 804 return n; 805 } 806 807 /* keep LPRT parameter */ 808 memset(&data6, 0, sizeof(data6)); 809 sin6 = (struct sockaddr_in6 *)&data6; 810 sin6->sin6_len = sizeof(*sin6); 811 sin6->sin6_family = AF_INET6; 812 for (n = 0; n < 16; n++) 813 sin6->sin6_addr.s6_addr[n] = ho[n]; 814 sin6->sin6_port = htons(((po[0] & 0xff) << 8) | (po[1] & 0xff)); 815 816sendport: 817 /* get ready for active data connection */ 818 n = sizeof(data4); 819 error = getsockname(dst, (struct sockaddr *)&data4, &n); 820 if (error == -1) { 821lprtfail: 822 n = snprintf(sbuf, sizeof(sbuf), 823 "500 could not translate to PORT\r\n"); 824 write(src, sbuf, n); 825 return n; 826 } 827 if (((struct sockaddr *)&data4)->sa_family != AF_INET) 828 goto lprtfail; 829 sin = (struct sockaddr_in *)&data4; 830 sin->sin_port = 0; 831 wport4 = socket(sin->sin_family, SOCK_STREAM, 0); 832 if (wport4 == -1) 833 goto lprtfail; 834 error = bind(wport4, (struct sockaddr *)sin, sin->sin_len); 835 if (error == -1) { 836 close(wport4); 837 wport4 = -1; 838 goto lprtfail; 839 } 840 error = listen(wport4, 1); 841 if (error == -1) { 842 close(wport4); 843 wport4 = -1; 844 goto lprtfail; 845 } 846 847 /* transmit PORT */ 848 n = sizeof(data4); 849 error = getsockname(wport4, (struct sockaddr *)&data4, &n); 850 if (error == -1) { 851 close(wport4); 852 wport4 = -1; 853 goto lprtfail; 854 } 855 if (((struct sockaddr *)&data4)->sa_family != AF_INET) { 856 close(wport4); 857 wport4 = -1; 858 goto lprtfail; 859 } 860 sin = (struct sockaddr_in *)&data4; 861 a = (char *)&sin->sin_addr; 862 p = (char *)&sin->sin_port; 863 n = snprintf(sbuf, sizeof(sbuf), "PORT %d,%d,%d,%d,%d,%d\r\n", 864 UC(a[0]), UC(a[1]), UC(a[2]), UC(a[3]), 865 UC(p[0]), UC(p[1])); 866 write(dst, sbuf, n); 867 *state = nstate; 868 passivemode = 0; 869 return n; 870 } else if (strcmp(cmd, "EPRT") == 0 && param) { 871 /* 872 * EPRT -> PORT 873 */ 874 char *afp, *hostp, *portp; 875 struct addrinfo hints, *res; 876 877 nstate = EPRT; 878 879 close(wport4); 880 close(wport6); 881 close(port4); 882 close(port6); 883 wport4 = wport6 = port4 = port6 = -1; 884 885 if (epsvall) { 886 n = snprintf(sbuf, sizeof(sbuf), "501 %s disallowed in EPSV ALL\r\n", 887 cmd); 888 write(src, sbuf, n); 889 return n; 890 } 891 892 p = param; 893 ch = *p++; /* boundary character */ 894 afp = p; 895 while (*p && *p != ch) 896 p++; 897 if (!*p) { 898eprtparamfail: 899 n = snprintf(sbuf, sizeof(sbuf), 900 "501 illegal parameter to EPRT\r\n"); 901 write(src, sbuf, n); 902 return n; 903 } 904 *p++ = '\0'; 905 hostp = p; 906 while (*p && *p != ch) 907 p++; 908 if (!*p) 909 goto eprtparamfail; 910 *p++ = '\0'; 911 portp = p; 912 while (*p && *p != ch) 913 p++; 914 if (!*p) 915 goto eprtparamfail; 916 *p++ = '\0'; 917 918 n = sscanf(afp, "%d", &af); 919 if (n != 1 || af != 2) { 920 n = snprintf(sbuf, sizeof(sbuf), 921 "501 unsupported address family to EPRT\r\n"); 922 write(src, sbuf, n); 923 return n; 924 } 925 memset(&hints, 0, sizeof(hints)); 926 hints.ai_family = AF_UNSPEC; 927 hints.ai_socktype = SOCK_STREAM; 928 error = getaddrinfo(hostp, portp, &hints, &res); 929 if (error) { 930 n = snprintf(sbuf, sizeof(sbuf), 931 "501 EPRT: %s\r\n", gai_strerror(error)); 932 write(src, sbuf, n); 933 return n; 934 } 935 if (res->ai_next) { 936 n = snprintf(sbuf, sizeof(sbuf), 937 "501 EPRT: %s resolved to multiple addresses\r\n", hostp); 938 write(src, sbuf, n); 939 return n; 940 } 941 942 memcpy(&data6, res->ai_addr, res->ai_addrlen); 943 944 goto sendport; 945 } else if (strcmp(cmd, "LPSV") == 0 && !param) { 946 /* 947 * LPSV -> PASV 948 */ 949 nstate = LPSV; 950 951 close(wport4); 952 close(wport6); 953 close(port4); 954 close(port6); 955 wport4 = wport6 = port4 = port6 = -1; 956 957 if (epsvall) { 958 n = snprintf(sbuf, sizeof(sbuf), "501 %s disallowed in EPSV ALL\r\n", 959 cmd); 960 write(src, sbuf, n); 961 return n; 962 } 963 964 /* transmit PASV */ 965 n = snprintf(sbuf, sizeof(sbuf), "PASV\r\n"); 966 write(dst, sbuf, n); 967 *state = LPSV; 968 passivemode = 0; /* to be set to 1 later */ 969 return n; 970 } else if (strcmp(cmd, "EPSV") == 0 && !param) { 971 /* 972 * EPSV -> PASV 973 */ 974 close(wport4); 975 close(wport6); 976 close(port4); 977 close(port6); 978 wport4 = wport6 = port4 = port6 = -1; 979 980 n = snprintf(sbuf, sizeof(sbuf), "PASV\r\n"); 981 write(dst, sbuf, n); 982 *state = EPSV; 983 passivemode = 0; /* to be set to 1 later */ 984 return n; 985 } else if (strcmp(cmd, "EPSV") == 0 && param 986 && strncasecmp(param, "ALL", 3) == 0 && isspace(param[3])) { 987 /* 988 * EPSV ALL 989 */ 990 epsvall = 1; 991 n = snprintf(sbuf, sizeof(sbuf), "200 EPSV ALL command successful.\r\n"); 992 write(src, sbuf, n); 993 return n; 994#ifdef FAITH4 995 } else if (strcmp(cmd, "PORT") == 0 && param) { 996 /* 997 * PORT -> EPRT 998 */ 999 char host[NI_MAXHOST], serv[NI_MAXSERV]; 1000 1001 nstate = PORT; 1002 1003 close(wport4); 1004 close(wport6); 1005 close(port4); 1006 close(port6); 1007 wport4 = wport6 = port4 = port6 = -1; 1008 1009 p = param; 1010 n = sscanf(p, "%u,%u,%u,%u,%u,%u", 1011 &ho[0], &ho[1], &ho[2], &ho[3], &po[0], &po[1]); 1012 if (n != 6) { 1013 n = snprintf(sbuf, sizeof(sbuf), 1014 "501 illegal parameter to PORT\r\n"); 1015 write(src, sbuf, n); 1016 return n; 1017 } 1018 1019 memset(&data6, 0, sizeof(data6)); 1020 sin = (struct sockaddr_in *)&data6; 1021 sin->sin_len = sizeof(*sin); 1022 sin->sin_family = AF_INET; 1023 sin->sin_addr.s_addr = htonl( 1024 ((ho[0] & 0xff) << 24) | ((ho[1] & 0xff) << 16) | 1025 ((ho[2] & 0xff) << 8) | (ho[3] & 0xff)); 1026 sin->sin_port = htons(((po[0] & 0xff) << 8) | (po[1] & 0xff)); 1027 1028 /* get ready for active data connection */ 1029 n = sizeof(data4); 1030 error = getsockname(dst, (struct sockaddr *)&data4, &n); 1031 if (error == -1) { 1032portfail: 1033 n = snprintf(sbuf, sizeof(sbuf), 1034 "500 could not translate to EPRT\r\n"); 1035 write(src, sbuf, n); 1036 return n; 1037 } 1038 if (((struct sockaddr *)&data4)->sa_family != AF_INET6) 1039 goto portfail; 1040 1041 ((struct sockaddr_in6 *)&data4)->sin6_port = 0; 1042 sa = (struct sockaddr *)&data4; 1043 wport4 = socket(sa->sa_family, SOCK_STREAM, 0); 1044 if (wport4 == -1) 1045 goto portfail; 1046 error = bind(wport4, sa, sa->sa_len); 1047 if (error == -1) { 1048 close(wport4); 1049 wport4 = -1; 1050 goto portfail; 1051 } 1052 error = listen(wport4, 1); 1053 if (error == -1) { 1054 close(wport4); 1055 wport4 = -1; 1056 goto portfail; 1057 } 1058 1059 /* transmit EPRT */ 1060 n = sizeof(data4); 1061 error = getsockname(wport4, (struct sockaddr *)&data4, &n); 1062 if (error == -1) { 1063 close(wport4); 1064 wport4 = -1; 1065 goto portfail; 1066 } 1067 af = 2; 1068 sa = (struct sockaddr *)&data4; 1069 if (getnameinfo(sa, sa->sa_len, host, sizeof(host), 1070 serv, sizeof(serv), NI_NUMERICHOST | NI_NUMERICSERV)) { 1071 close(wport4); 1072 wport4 = -1; 1073 goto portfail; 1074 } 1075 n = snprintf(sbuf, sizeof(sbuf), "EPRT |%d|%s|%s|\r\n", af, host, serv); 1076 write(dst, sbuf, n); 1077 *state = nstate; 1078 passivemode = 0; 1079 return n; 1080 } else if (strcmp(cmd, "PASV") == 0 && !param) { 1081 /* 1082 * PASV -> EPSV 1083 */ 1084 1085 nstate = PASV; 1086 1087 close(wport4); 1088 close(wport6); 1089 close(port4); 1090 close(port6); 1091 wport4 = wport6 = port4 = port6 = -1; 1092 1093 /* transmit EPSV */ 1094 n = snprintf(sbuf, sizeof(sbuf), "EPSV\r\n"); 1095 write(dst, sbuf, n); 1096 *state = PASV; 1097 passivemode = 0; /* to be set to 1 later */ 1098 return n; 1099#else /* FAITH4 */ 1100 } else if (strcmp(cmd, "PORT") == 0 || strcmp(cmd, "PASV") == 0) { 1101 /* 1102 * reject PORT/PASV 1103 */ 1104 n = snprintf(sbuf, sizeof(sbuf), "502 %s not implemented.\r\n", cmd); 1105 write(src, sbuf, n); 1106 return n; 1107#endif /* FAITH4 */ 1108 } else if (passivemode 1109 && (strcmp(cmd, "STOR") == 0 1110 || strcmp(cmd, "STOU") == 0 1111 || strcmp(cmd, "RETR") == 0 1112 || strcmp(cmd, "LIST") == 0 1113 || strcmp(cmd, "NLST") == 0 1114 || strcmp(cmd, "APPE") == 0)) { 1115 /* 1116 * commands with data transfer. need to care about passive 1117 * mode data connection. 1118 */ 1119 1120 if (ftp_passiveconn() < 0) { 1121 n = snprintf(sbuf, sizeof(sbuf), "425 Cannot open data connetion\r\n"); 1122 write(src, sbuf, n); 1123 } else { 1124 /* simply relay the command */ 1125 write(dst, rbuf, n); 1126 } 1127 1128 *state = NONE; 1129 return n; 1130 } else { 1131 /* simply relay it */ 1132 *state = NONE; 1133 write(dst, rbuf, n); 1134 return n; 1135 } 1136 1137 bad: 1138 exit_failure(ERRSTR); 1139 /*NOTREACHED*/ 1140 return 0; /* to make gcc happy */ 1141} 1142