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