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