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