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