ftp.c revision 65994
162655Skris/* $KAME$ */ 262655Skris 356668Sshin/* 456668Sshin * Copyright (C) 1997 and 1998 WIDE Project. 556668Sshin * All rights reserved. 662655Skris * 756668Sshin * Redistribution and use in source and binary forms, with or without 856668Sshin * modification, are permitted provided that the following conditions 956668Sshin * are met: 1056668Sshin * 1. Redistributions of source code must retain the above copyright 1156668Sshin * notice, this list of conditions and the following disclaimer. 1256668Sshin * 2. Redistributions in binary form must reproduce the above copyright 1356668Sshin * notice, this list of conditions and the following disclaimer in the 1456668Sshin * documentation and/or other materials provided with the distribution. 1556668Sshin * 3. Neither the name of the project nor the names of its contributors 1656668Sshin * may be used to endorse or promote products derived from this software 1756668Sshin * without specific prior written permission. 1862655Skris * 1956668Sshin * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 2056668Sshin * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2156668Sshin * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2256668Sshin * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 2356668Sshin * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2456668Sshin * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2556668Sshin * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2656668Sshin * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2756668Sshin * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2856668Sshin * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2956668Sshin * SUCH DAMAGE. 3056668Sshin * 3156668Sshin * $FreeBSD: head/usr.sbin/faithd/ftp.c 65994 2000-09-17 16:44:51Z ume $ 3256668Sshin */ 3356668Sshin 3456668Sshin#include <sys/param.h> 3556668Sshin#include <sys/types.h> 3656668Sshin#include <sys/socket.h> 3756668Sshin#include <sys/ioctl.h> 3856668Sshin#include <sys/time.h> 3956668Sshin 4056668Sshin#include <stdio.h> 4156668Sshin#include <stdlib.h> 4256668Sshin#include <string.h> 4356668Sshin#include <syslog.h> 4456668Sshin#include <unistd.h> 4556668Sshin#include <errno.h> 4656668Sshin#include <ctype.h> 4756668Sshin 4856668Sshin#include <netinet/in.h> 4956668Sshin#include <arpa/inet.h> 5056668Sshin#include <netdb.h> 5156668Sshin 5256668Sshin#include "faithd.h" 5356668Sshin 5456668Sshinstatic char rbuf[MSS]; 5556668Sshinstatic char sbuf[MSS]; 5656668Sshinstatic int passivemode = 0; 5756668Sshinstatic int wport4 = -1; /* listen() to active */ 5856668Sshinstatic int wport6 = -1; /* listen() to passive */ 5956668Sshinstatic int port4 = -1; /* active: inbound passive: outbound */ 6056668Sshinstatic int port6 = -1; /* active: outbound passive: inbound */ 6156668Sshinstatic struct sockaddr_storage data4; /* server data address */ 6256668Sshinstatic struct sockaddr_storage data6; /* client data address */ 6356668Sshinstatic int epsvall = 0; 6456668Sshin 6556668Sshin#ifdef FAITH4 6656668Sshinenum state { NONE, LPRT, EPRT, PORT, LPSV, EPSV, PASV }; 6756668Sshin#else 6856668Sshinenum state { NONE, LPRT, EPRT, LPSV, EPSV }; 6956668Sshin#endif 7056668Sshin 7156668Sshinstatic int ftp_activeconn __P((void)); 7256668Sshinstatic int ftp_passiveconn __P((void)); 7356668Sshinstatic int ftp_copy __P((int, int)); 7456668Sshinstatic int ftp_copyresult __P((int, int, enum state)); 7556668Sshinstatic int ftp_copycommand __P((int, int, enum state *)); 7656668Sshin 7756668Sshinvoid 7856668Sshinftp_relay(int ctl6, int ctl4) 7956668Sshin{ 8056668Sshin fd_set readfds; 8156668Sshin int error; 8256668Sshin enum state state = NONE; 8356668Sshin struct timeval tv; 8456668Sshin 8556668Sshin syslog(LOG_INFO, "starting ftp control connection"); 8656668Sshin 8756668Sshin for (;;) { 8856668Sshin FD_ZERO(&readfds); 8956668Sshin FD_SET(ctl4, &readfds); 9056668Sshin FD_SET(ctl6, &readfds); 9156668Sshin if (0 <= port4) 9256668Sshin FD_SET(port4, &readfds); 9356668Sshin if (0 <= port6) 9456668Sshin FD_SET(port6, &readfds); 9556668Sshin#if 0 9656668Sshin if (0 <= wport4) 9756668Sshin FD_SET(wport4, &readfds); 9856668Sshin if (0 <= wport6) 9956668Sshin FD_SET(wport6, &readfds); 10056668Sshin#endif 10156668Sshin tv.tv_sec = FAITH_TIMEOUT; 10256668Sshin tv.tv_usec = 0; 10356668Sshin 10456668Sshin error = select(256, &readfds, NULL, NULL, &tv); 10556668Sshin if (error == -1) 10656668Sshin exit_failure("select: %s", ERRSTR); 10756668Sshin else if (error == 0) 10856668Sshin exit_failure("connection timeout"); 10956668Sshin 11056668Sshin /* 11156668Sshin * The order of the following checks does (slightly) matter. 11256668Sshin * It is important to visit all checks (do not use "continue"), 11356668Sshin * otherwise some of the pipe may become full and we cannot 11456668Sshin * relay correctly. 11556668Sshin */ 11656668Sshin if (FD_ISSET(ctl6, &readfds)) { 11756668Sshin /* 11856668Sshin * copy control connection from the client. 11956668Sshin * command translation is necessary. 12056668Sshin */ 12156668Sshin error = ftp_copycommand(ctl6, ctl4, &state); 12256668Sshin 12356668Sshin switch (error) { 12456668Sshin case -1: 12556668Sshin goto bad; 12656668Sshin case 0: 12756668Sshin close(ctl4); 12856668Sshin close(ctl6); 12956668Sshin exit_success("terminating ftp control connection"); 13056668Sshin /*NOTREACHED*/ 13156668Sshin default: 13256668Sshin break; 13356668Sshin } 13456668Sshin } 13556668Sshin if (FD_ISSET(ctl4, &readfds)) { 13656668Sshin /* 13756668Sshin * copy control connection from the server 13856668Sshin * translation of result code is necessary. 13956668Sshin */ 14056668Sshin error = ftp_copyresult(ctl4, ctl6, state); 14156668Sshin 14256668Sshin switch (error) { 14356668Sshin case -1: 14456668Sshin goto bad; 14556668Sshin case 0: 14656668Sshin close(ctl4); 14756668Sshin close(ctl6); 14856668Sshin exit_success("terminating ftp control connection"); 14956668Sshin /*NOTREACHED*/ 15056668Sshin default: 15156668Sshin break; 15256668Sshin } 15356668Sshin } 15456668Sshin if (0 <= port4 && 0 <= port6 && FD_ISSET(port4, &readfds)) { 15556668Sshin /* 15656668Sshin * copy data connection. 15756668Sshin * no special treatment necessary. 15856668Sshin */ 15956668Sshin if (FD_ISSET(port4, &readfds)) 16056668Sshin error = ftp_copy(port4, port6); 16156668Sshin switch (error) { 16256668Sshin case -1: 16356668Sshin goto bad; 16456668Sshin case 0: 16556668Sshin close(port4); 16656668Sshin close(port6); 16756668Sshin port4 = port6 = -1; 16856668Sshin syslog(LOG_INFO, "terminating data connection"); 16956668Sshin break; 17056668Sshin default: 17156668Sshin break; 17256668Sshin } 17356668Sshin } 17456668Sshin if (0 <= port4 && 0 <= port6 && FD_ISSET(port6, &readfds)) { 17556668Sshin /* 17656668Sshin * copy data connection. 17756668Sshin * no special treatment necessary. 17856668Sshin */ 17956668Sshin if (FD_ISSET(port6, &readfds)) 18056668Sshin error = ftp_copy(port6, port4); 18156668Sshin switch (error) { 18256668Sshin case -1: 18356668Sshin goto bad; 18456668Sshin case 0: 18556668Sshin close(port4); 18656668Sshin close(port6); 18756668Sshin port4 = port6 = -1; 18856668Sshin syslog(LOG_INFO, "terminating data connection"); 18956668Sshin break; 19056668Sshin default: 19156668Sshin break; 19256668Sshin } 19356668Sshin } 19456668Sshin#if 0 19556668Sshin if (wport4 && FD_ISSET(wport4, &readfds)) { 19656668Sshin /* 19756668Sshin * establish active data connection from the server. 19856668Sshin */ 19956668Sshin ftp_activeconn(); 20056668Sshin } 20156668Sshin if (wport6 && FD_ISSET(wport6, &readfds)) { 20256668Sshin /* 20356668Sshin * establish passive data connection from the client. 20456668Sshin */ 20556668Sshin ftp_passiveconn(); 20656668Sshin } 20756668Sshin#endif 20856668Sshin } 20956668Sshin 21056668Sshin bad: 21156668Sshin exit_failure(ERRSTR); 21256668Sshin} 21356668Sshin 21456668Sshinstatic int 21556668Sshinftp_activeconn() 21656668Sshin{ 21756668Sshin int n; 21856668Sshin int error; 21956668Sshin fd_set set; 22056668Sshin struct timeval timeout; 22156668Sshin struct sockaddr *sa; 22256668Sshin 22356668Sshin /* get active connection from server */ 22456668Sshin FD_ZERO(&set); 22556668Sshin FD_SET(wport4, &set); 22656668Sshin timeout.tv_sec = 120; 22756668Sshin timeout.tv_usec = -1; 22856668Sshin n = sizeof(data4); 22956668Sshin if (select(wport4 + 1, &set, NULL, NULL, &timeout) == 0 23056668Sshin || (port4 = accept(wport4, (struct sockaddr *)&data4, &n)) < 0) { 23156668Sshin close(wport4); 23256668Sshin wport4 = -1; 23356668Sshin syslog(LOG_INFO, "active mode data connection failed"); 23456668Sshin return -1; 23556668Sshin } 23656668Sshin 23756668Sshin /* ask active connection to client */ 23856668Sshin sa = (struct sockaddr *)&data6; 23956668Sshin port6 = socket(sa->sa_family, SOCK_STREAM, 0); 24056668Sshin if (port6 == -1) { 24156668Sshin close(port4); 24256668Sshin close(wport4); 24356668Sshin port4 = wport4 = -1; 24456668Sshin syslog(LOG_INFO, "active mode data connection failed"); 24556668Sshin return -1; 24656668Sshin } 24756668Sshin error = connect(port6, sa, sa->sa_len); 24856668Sshin if (port6 == -1) { 24956668Sshin close(port6); 25056668Sshin close(port4); 25156668Sshin close(wport4); 25256668Sshin port6 = port4 = wport4 = -1; 25356668Sshin syslog(LOG_INFO, "active mode data connection failed"); 25456668Sshin return -1; 25556668Sshin } 25656668Sshin 25756668Sshin syslog(LOG_INFO, "active mode data connection established"); 25856668Sshin return 0; 25956668Sshin} 26056668Sshin 26156668Sshinstatic int 26256668Sshinftp_passiveconn() 26356668Sshin{ 26456668Sshin int n; 26556668Sshin int error; 26656668Sshin fd_set set; 26756668Sshin struct timeval timeout; 26856668Sshin struct sockaddr *sa; 26956668Sshin 27056668Sshin /* get passive connection from client */ 27156668Sshin FD_ZERO(&set); 27256668Sshin FD_SET(wport6, &set); 27356668Sshin timeout.tv_sec = 120; 27456668Sshin timeout.tv_usec = 0; 27556668Sshin n = sizeof(data6); 27656668Sshin if (select(wport6 + 1, &set, NULL, NULL, &timeout) == 0 27756668Sshin || (port6 = accept(wport6, (struct sockaddr *)&data6, &n)) < 0) { 27856668Sshin close(wport6); 27956668Sshin wport6 = -1; 28056668Sshin syslog(LOG_INFO, "passive mode data connection failed"); 28156668Sshin return -1; 28256668Sshin } 28356668Sshin 28456668Sshin /* ask passive connection to server */ 28556668Sshin sa = (struct sockaddr *)&data4; 28656668Sshin port4 = socket(sa->sa_family, SOCK_STREAM, 0); 28756668Sshin if (port4 == -1) { 28856668Sshin close(wport6); 28956668Sshin close(port6); 29056668Sshin wport6 = port6 = -1; 29156668Sshin syslog(LOG_INFO, "passive mode data connection failed"); 29256668Sshin return -1; 29356668Sshin } 29456668Sshin error = connect(port4, sa, sa->sa_len); 29556668Sshin if (port4 == -1) { 29656668Sshin close(wport6); 29756668Sshin close(port4); 29856668Sshin close(port6); 29956668Sshin wport6 = port4 = port6 = -1; 30056668Sshin syslog(LOG_INFO, "passive mode data connection failed"); 30156668Sshin return -1; 30256668Sshin } 30356668Sshin 30456668Sshin syslog(LOG_INFO, "passive mode data connection established"); 30556668Sshin return 0; 30656668Sshin} 30756668Sshin 30856668Sshinstatic int 30956668Sshinftp_copy(int src, int dst) 31056668Sshin{ 31156668Sshin int error, atmark; 31256668Sshin int n; 31356668Sshin 31456668Sshin /* OOB data handling */ 31556668Sshin error = ioctl(src, SIOCATMARK, &atmark); 31656668Sshin if (error != -1 && atmark == 1) { 31756668Sshin n = read(src, rbuf, 1); 31856668Sshin if (n == -1) 31956668Sshin goto bad; 32056668Sshin send(dst, rbuf, n, MSG_OOB); 32156668Sshin#if 0 32256668Sshin n = read(src, rbuf, sizeof(rbuf)); 32356668Sshin if (n == -1) 32456668Sshin goto bad; 32556668Sshin write(dst, rbuf, n); 32656668Sshin return n; 32756668Sshin#endif 32856668Sshin } 32956668Sshin 33056668Sshin n = read(src, rbuf, sizeof(rbuf)); 33156668Sshin switch (n) { 33256668Sshin case -1: 33356668Sshin case 0: 33456668Sshin return n; 33556668Sshin default: 33656668Sshin write(dst, rbuf, n); 33756668Sshin return n; 33856668Sshin } 33956668Sshin 34056668Sshin bad: 34156668Sshin exit_failure(ERRSTR); 34256668Sshin /*NOTREACHED*/ 34356668Sshin return 0; /* to make gcc happy */ 34456668Sshin} 34556668Sshin 34656668Sshinstatic int 34756668Sshinftp_copyresult(int src, int dst, enum state state) 34856668Sshin{ 34956668Sshin int error, atmark; 35056668Sshin int n; 35156668Sshin char *param; 35256668Sshin int code; 35356668Sshin 35456668Sshin /* OOB data handling */ 35556668Sshin error = ioctl(src, SIOCATMARK, &atmark); 35656668Sshin if (error != -1 && atmark == 1) { 35756668Sshin n = read(src, rbuf, 1); 35856668Sshin if (n == -1) 35956668Sshin goto bad; 36056668Sshin send(dst, rbuf, n, MSG_OOB); 36156668Sshin#if 0 36256668Sshin n = read(src, rbuf, sizeof(rbuf)); 36356668Sshin if (n == -1) 36456668Sshin goto bad; 36556668Sshin write(dst, rbuf, n); 36656668Sshin return n; 36756668Sshin#endif 36856668Sshin } 36956668Sshin 37056668Sshin n = read(src, rbuf, sizeof(rbuf)); 37156668Sshin if (n <= 0) 37256668Sshin return n; 37356668Sshin rbuf[n] = '\0'; 37456668Sshin 37556668Sshin /* 37656668Sshin * parse argument 37756668Sshin */ 37856668Sshin { 37956668Sshin char *p; 38056668Sshin int i; 38156668Sshin 38256668Sshin p = rbuf; 38356668Sshin for (i = 0; i < 3; i++) { 38456668Sshin if (!isdigit(*p)) { 38556668Sshin /* invalid reply */ 38656668Sshin write(dst, rbuf, n); 38756668Sshin return n; 38856668Sshin } 38956668Sshin p++; 39056668Sshin } 39156668Sshin if (!isspace(*p)) { 39256668Sshin /* invalid reply */ 39356668Sshin write(dst, rbuf, n); 39456668Sshin return n; 39556668Sshin } 39656668Sshin code = atoi(rbuf); 39756668Sshin param = p; 39856668Sshin /* param points to first non-command token, if any */ 39956668Sshin while (*param && isspace(*param)) 40056668Sshin param++; 40156668Sshin if (!*param) 40256668Sshin param = NULL; 40356668Sshin } 40456668Sshin 40556668Sshin switch (state) { 40656668Sshin case NONE: 40756668Sshin if (!passivemode && rbuf[0] == '1') { 40856668Sshin if (ftp_activeconn() < 0) { 40956668Sshin n = snprintf(rbuf, sizeof(rbuf), 41062655Skris "425 Cannot open data connetion\r\n"); 41156668Sshin } 41256668Sshin } 41356668Sshin write(dst, rbuf, n); 41456668Sshin return n; 41556668Sshin case LPRT: 41656668Sshin case EPRT: 41756668Sshin /* expecting "200 PORT command successful." */ 41856668Sshin if (code == 200) { 41956668Sshin char *p; 42056668Sshin 42156668Sshin p = strstr(rbuf, "PORT"); 42256668Sshin if (p) { 42356668Sshin p[0] = (state == LPRT) ? 'L' : 'E'; 42456668Sshin p[1] = 'P'; 42556668Sshin } 42656668Sshin } else { 42756668Sshin close(wport4); 42856668Sshin wport4 = -1; 42956668Sshin } 43056668Sshin write(dst, rbuf, n); 43156668Sshin return n; 43256668Sshin#ifdef FAITH4 43356668Sshin case PORT: 43456668Sshin /* expecting "200 EPRT command successful." */ 43556668Sshin if (code == 200) { 43656668Sshin char *p; 43756668Sshin 43856668Sshin p = strstr(rbuf, "EPRT"); 43956668Sshin if (p) { 44056668Sshin p[0] = 'P'; 44156668Sshin p[1] = 'O'; 44256668Sshin } 44356668Sshin } else { 44456668Sshin close(wport4); 44556668Sshin wport4 = -1; 44656668Sshin } 44756668Sshin write(dst, rbuf, n); 44856668Sshin return n; 44956668Sshin#endif 45056668Sshin case LPSV: 45156668Sshin case EPSV: 45265994Sume /* 45365994Sume * expecting "227 Entering Passive Mode (x,x,x,x,x,x,x)" 45465994Sume * (in some cases result comes without paren) 45565994Sume */ 45656668Sshin if (code != 227) { 45756668Sshinpassivefail0: 45856668Sshin close(wport6); 45956668Sshin wport6 = -1; 46056668Sshin write(dst, rbuf, n); 46156668Sshin return n; 46256668Sshin } 46356668Sshin 46456668Sshin { 46556668Sshin unsigned int ho[4], po[2]; 46656668Sshin struct sockaddr_in *sin; 46756668Sshin struct sockaddr_in6 *sin6; 46856668Sshin u_short port; 46956668Sshin char *p; 47056668Sshin 47156668Sshin /* 47256668Sshin * PASV result -> LPSV/EPSV result 47356668Sshin */ 47456668Sshin p = param; 47565994Sume while (*p && *p != '(' && !isdigit(*p)) /*)*/ 47656668Sshin p++; 47756668Sshin if (!*p) 47856668Sshin goto passivefail0; /*XXX*/ 47965994Sume if (*p == '(') /*)*/ 48065994Sume p++; 48156668Sshin n = sscanf(p, "%u,%u,%u,%u,%u,%u", 48256668Sshin &ho[0], &ho[1], &ho[2], &ho[3], &po[0], &po[1]); 48356668Sshin if (n != 6) 48456668Sshin goto passivefail0; /*XXX*/ 48556668Sshin 48656668Sshin /* keep PORT parameter */ 48756668Sshin memset(&data4, 0, sizeof(data4)); 48856668Sshin sin = (struct sockaddr_in *)&data4; 48956668Sshin sin->sin_len = sizeof(*sin); 49056668Sshin sin->sin_family = AF_INET; 49156668Sshin sin->sin_addr.s_addr = 0; 49256668Sshin for (n = 0; n < 4; n++) { 49356668Sshin sin->sin_addr.s_addr |= 49456668Sshin htonl((ho[n] & 0xff) << ((3 - n) * 8)); 49556668Sshin } 49656668Sshin sin->sin_port = htons(((po[0] & 0xff) << 8) | (po[1] & 0xff)); 49756668Sshin 49856668Sshin /* get ready for passive data connection */ 49956668Sshin memset(&data6, 0, sizeof(data6)); 50056668Sshin sin6 = (struct sockaddr_in6 *)&data6; 50156668Sshin sin6->sin6_len = sizeof(*sin6); 50256668Sshin sin6->sin6_family = AF_INET6; 50356668Sshin wport6 = socket(sin6->sin6_family, SOCK_STREAM, 0); 50456668Sshin if (wport6 == -1) { 50556668Sshinpassivefail: 50656668Sshin n = snprintf(sbuf, sizeof(sbuf), 50756668Sshin "500 could not translate from PASV\r\n"); 50856668Sshin write(src, sbuf, n); 50956668Sshin return n; 51056668Sshin } 51156668Sshin#ifdef IPV6_FAITH 51256668Sshin { 51356668Sshin int on = 1; 51456668Sshin error = setsockopt(wport6, IPPROTO_IPV6, IPV6_FAITH, 51556668Sshin &on, sizeof(on)); 51656668Sshin if (error == -1) 51756668Sshin exit_error("setsockopt(IPV6_FAITH): %s", ERRSTR); 51856668Sshin } 51956668Sshin#endif 52056668Sshin error = bind(wport6, (struct sockaddr *)sin6, sin6->sin6_len); 52156668Sshin if (error == -1) { 52256668Sshin close(wport6); 52356668Sshin wport6 = -1; 52456668Sshin goto passivefail; 52556668Sshin } 52656668Sshin error = listen(wport6, 1); 52756668Sshin if (error == -1) { 52856668Sshin close(wport6); 52956668Sshin wport6 = -1; 53056668Sshin goto passivefail; 53156668Sshin } 53256668Sshin 53356668Sshin /* transmit LPSV or EPSV */ 53456668Sshin /* 53556668Sshin * addr from dst, port from wport6 53656668Sshin */ 53756668Sshin n = sizeof(data6); 53856668Sshin error = getsockname(wport6, (struct sockaddr *)&data6, &n); 53956668Sshin if (error == -1) { 54056668Sshin close(wport6); 54156668Sshin wport6 = -1; 54256668Sshin goto passivefail; 54356668Sshin } 54456668Sshin sin6 = (struct sockaddr_in6 *)&data6; 54556668Sshin port = sin6->sin6_port; 54656668Sshin 54756668Sshin n = sizeof(data6); 54856668Sshin error = getsockname(dst, (struct sockaddr *)&data6, &n); 54956668Sshin if (error == -1) { 55056668Sshin close(wport6); 55156668Sshin wport6 = -1; 55256668Sshin goto passivefail; 55356668Sshin } 55456668Sshin sin6 = (struct sockaddr_in6 *)&data6; 55556668Sshin sin6->sin6_port = port; 55656668Sshin 55756668Sshin if (state == LPSV) { 55856668Sshin char *a, *p; 55956668Sshin 56056668Sshin a = (char *)&sin6->sin6_addr; 56156668Sshin p = (char *)&sin6->sin6_port; 56256668Sshin n = snprintf(sbuf, sizeof(sbuf), 56356668Sshin"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", 56462655Skris 6, 16, UC(a[0]), UC(a[1]), UC(a[2]), UC(a[3]), 56562655Skris UC(a[4]), UC(a[5]), UC(a[6]), UC(a[7]), 56662655Skris UC(a[8]), UC(a[9]), UC(a[10]), UC(a[11]), 56762655Skris UC(a[12]), UC(a[13]), UC(a[14]), UC(a[15]), 56856668Sshin 2, UC(p[0]), UC(p[1])); 56956668Sshin write(dst, sbuf, n); 57056668Sshin passivemode = 1; 57156668Sshin return n; 57256668Sshin } else { 57356668Sshin n = snprintf(sbuf, sizeof(sbuf), 57456668Sshin"229 Entering Extended Passive Mode (|||%d|)\r\n", 57556668Sshin ntohs(sin6->sin6_port)); 57656668Sshin write(dst, sbuf, n); 57756668Sshin passivemode = 1; 57856668Sshin return n; 57956668Sshin } 58056668Sshin } 58156668Sshin#ifdef FAITH4 58256668Sshin case PASV: 58356668Sshin /* expecting "229 Entering Extended Passive Mode (|||x|)" */ 58456668Sshin if (code != 229) { 58556668Sshinpassivefail1: 58656668Sshin close(wport6); 58756668Sshin wport6 = -1; 58856668Sshin write(dst, rbuf, n); 58956668Sshin return n; 59056668Sshin } 59156668Sshin 59256668Sshin { 59356668Sshin u_short port; 59456668Sshin char *p; 59556668Sshin struct sockaddr_in *sin; 59656668Sshin struct sockaddr_in6 *sin6; 59756668Sshin 59856668Sshin /* 59956668Sshin * EPSV result -> PORT result 60056668Sshin */ 60156668Sshin p = param; 60265994Sume while (*p && *p != '(') /*)*/ 60356668Sshin p++; 60456668Sshin if (!*p) 60556668Sshin goto passivefail1; /*XXX*/ 60656668Sshin p++; 60756668Sshin n = sscanf(p, "|||%hu|", &port); 60856668Sshin if (n != 1) 60956668Sshin goto passivefail1; /*XXX*/ 61056668Sshin 61156668Sshin /* keep EPRT parameter */ 61256668Sshin n = sizeof(data4); 61356668Sshin error = getpeername(src, (struct sockaddr *)&data4, &n); 61456668Sshin if (error == -1) 61556668Sshin goto passivefail1; /*XXX*/ 61656668Sshin sin6 = (struct sockaddr_in6 *)&data4; 61756668Sshin sin6->sin6_port = htons(port); 61856668Sshin 61956668Sshin /* get ready for passive data connection */ 62056668Sshin memset(&data6, 0, sizeof(data6)); 62156668Sshin sin = (struct sockaddr_in *)&data6; 62256668Sshin sin->sin_len = sizeof(*sin); 62356668Sshin sin->sin_family = AF_INET; 62456668Sshin wport6 = socket(sin->sin_family, SOCK_STREAM, 0); 62556668Sshin if (wport6 == -1) { 62656668Sshinpassivefail2: 62756668Sshin n = snprintf(sbuf, sizeof(sbuf), 62856668Sshin "500 could not translate from EPSV\r\n"); 62956668Sshin write(src, sbuf, n); 63056668Sshin return n; 63156668Sshin } 63256668Sshin#ifdef IP_FAITH 63356668Sshin { 63456668Sshin int on = 1; 63556668Sshin error = setsockopt(wport6, IPPROTO_IP, IP_FAITH, 63656668Sshin &on, sizeof(on)); 63756668Sshin if (error == -1) 63856668Sshin exit_error("setsockopt(IP_FAITH): %s", ERRSTR); 63956668Sshin } 64056668Sshin#endif 64156668Sshin error = bind(wport6, (struct sockaddr *)sin, sin->sin_len); 64256668Sshin if (error == -1) { 64356668Sshin close(wport6); 64456668Sshin wport6 = -1; 64556668Sshin goto passivefail2; 64656668Sshin } 64756668Sshin error = listen(wport6, 1); 64856668Sshin if (error == -1) { 64956668Sshin close(wport6); 65056668Sshin wport6 = -1; 65156668Sshin goto passivefail2; 65256668Sshin } 65356668Sshin 65456668Sshin /* transmit PORT */ 65556668Sshin /* 65656668Sshin * addr from dst, port from wport6 65756668Sshin */ 65856668Sshin n = sizeof(data6); 65956668Sshin error = getsockname(wport6, (struct sockaddr *)&data6, &n); 66056668Sshin if (error == -1) { 66156668Sshin close(wport6); 66256668Sshin wport6 = -1; 66356668Sshin goto passivefail2; 66456668Sshin } 66556668Sshin sin = (struct sockaddr_in *)&data6; 66656668Sshin port = sin->sin_port; 66756668Sshin 66856668Sshin n = sizeof(data6); 66956668Sshin error = getsockname(dst, (struct sockaddr *)&data6, &n); 67056668Sshin if (error == -1) { 67156668Sshin close(wport6); 67256668Sshin wport6 = -1; 67356668Sshin goto passivefail2; 67456668Sshin } 67556668Sshin sin = (struct sockaddr_in *)&data6; 67656668Sshin sin->sin_port = port; 67756668Sshin 67856668Sshin { 67956668Sshin char *a, *p; 68056668Sshin 68156668Sshin a = (char *)&sin->sin_addr; 68256668Sshin p = (char *)&sin->sin_port; 68356668Sshin n = snprintf(sbuf, sizeof(sbuf), 68456668Sshin"227 Entering Passive Mode (%d,%d,%d,%d,%d,%d)\r\n", 68562655Skris UC(a[0]), UC(a[1]), UC(a[2]), UC(a[3]), 68656668Sshin UC(p[0]), UC(p[1])); 68756668Sshin write(dst, sbuf, n); 68856668Sshin passivemode = 1; 68956668Sshin return n; 69056668Sshin } 69156668Sshin } 69256668Sshin#endif /* FAITH4 */ 69356668Sshin } 69456668Sshin 69556668Sshin bad: 69656668Sshin exit_failure(ERRSTR); 69756668Sshin /*NOTREACHED*/ 69856668Sshin return 0; /* to make gcc happy */ 69956668Sshin} 70056668Sshin 70156668Sshinstatic int 70256668Sshinftp_copycommand(int src, int dst, enum state *state) 70356668Sshin{ 70456668Sshin int error, atmark; 70556668Sshin int n; 70656668Sshin unsigned int af, hal, ho[16], pal, po[2]; 70756668Sshin char *a, *p; 70856668Sshin char cmd[5], *param; 70956668Sshin struct sockaddr_in *sin; 71056668Sshin struct sockaddr_in6 *sin6; 71156668Sshin enum state nstate; 71256668Sshin char ch; 71356668Sshin 71456668Sshin /* OOB data handling */ 71556668Sshin error = ioctl(src, SIOCATMARK, &atmark); 71656668Sshin if (error != -1 && atmark == 1) { 71756668Sshin n = read(src, rbuf, 1); 71856668Sshin if (n == -1) 71956668Sshin goto bad; 72056668Sshin send(dst, rbuf, n, MSG_OOB); 72156668Sshin#if 0 72256668Sshin n = read(src, rbuf, sizeof(rbuf)); 72356668Sshin if (n == -1) 72456668Sshin goto bad; 72556668Sshin write(dst, rbuf, n); 72656668Sshin return n; 72756668Sshin#endif 72856668Sshin } 72956668Sshin 73056668Sshin n = read(src, rbuf, sizeof(rbuf)); 73156668Sshin if (n <= 0) 73256668Sshin return n; 73356668Sshin rbuf[n] = '\0'; 73456668Sshin 73556668Sshin if (n < 4) { 73656668Sshin write(dst, rbuf, n); 73756668Sshin return n; 73856668Sshin } 73956668Sshin 74056668Sshin /* 74156668Sshin * parse argument 74256668Sshin */ 74356668Sshin { 74456668Sshin char *p, *q; 74556668Sshin int i; 74656668Sshin 74756668Sshin p = rbuf; 74856668Sshin q = cmd; 74956668Sshin for (i = 0; i < 4; i++) { 75056668Sshin if (!isalpha(*p)) { 75156668Sshin /* invalid command */ 75256668Sshin write(dst, rbuf, n); 75356668Sshin return n; 75456668Sshin } 75556668Sshin *q++ = islower(*p) ? toupper(*p) : *p; 75656668Sshin p++; 75756668Sshin } 75856668Sshin if (!isspace(*p)) { 75956668Sshin /* invalid command */ 76056668Sshin write(dst, rbuf, n); 76156668Sshin return n; 76256668Sshin } 76356668Sshin *q = '\0'; 76456668Sshin param = p; 76556668Sshin /* param points to first non-command token, if any */ 76656668Sshin while (*param && isspace(*param)) 76756668Sshin param++; 76856668Sshin if (!*param) 76956668Sshin param = NULL; 77056668Sshin } 77156668Sshin 77256668Sshin *state = NONE; 77356668Sshin 77456668Sshin if (strcmp(cmd, "LPRT") == 0 && param) { 77556668Sshin /* 77656668Sshin * LPRT -> PORT 77756668Sshin */ 77856668Sshin nstate = LPRT; 77956668Sshin 78056668Sshin close(wport4); 78156668Sshin close(wport6); 78256668Sshin close(port4); 78356668Sshin close(port6); 78456668Sshin wport4 = wport6 = port4 = port6 = -1; 78556668Sshin 78656668Sshin if (epsvall) { 78756668Sshin n = snprintf(sbuf, sizeof(sbuf), "501 %s disallowed in EPSV ALL\r\n", 78856668Sshin cmd); 78956668Sshin write(src, sbuf, n); 79056668Sshin return n; 79156668Sshin } 79256668Sshin 79356668Sshin n = sscanf(param, 79456668Sshin"%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u", 79556668Sshin &af, &hal, &ho[0], &ho[1], &ho[2], &ho[3], 79656668Sshin &ho[4], &ho[5], &ho[6], &ho[7], 79756668Sshin &ho[8], &ho[9], &ho[10], &ho[11], 79856668Sshin &ho[12], &ho[13], &ho[14], &ho[15], 79956668Sshin &pal, &po[0], &po[1]); 80056668Sshin if (n != 21 || af != 6 || hal != 16|| pal != 2) { 80156668Sshin n = snprintf(sbuf, sizeof(sbuf), 80256668Sshin "501 illegal parameter to LPRT\r\n"); 80356668Sshin write(src, sbuf, n); 80456668Sshin return n; 80556668Sshin } 80656668Sshin 80756668Sshin /* keep LPRT parameter */ 80856668Sshin memset(&data6, 0, sizeof(data6)); 80956668Sshin sin6 = (struct sockaddr_in6 *)&data6; 81056668Sshin sin6->sin6_len = sizeof(*sin6); 81156668Sshin sin6->sin6_family = AF_INET6; 81256668Sshin for (n = 0; n < 16; n++) 81356668Sshin sin6->sin6_addr.s6_addr[n] = ho[n]; 81456668Sshin sin6->sin6_port = htons(((po[0] & 0xff) << 8) | (po[1] & 0xff)); 81556668Sshin 81656668Sshinsendport: 81756668Sshin /* get ready for active data connection */ 81856668Sshin n = sizeof(data4); 81956668Sshin error = getsockname(dst, (struct sockaddr *)&data4, &n); 82056668Sshin if (error == -1) { 82156668Sshinlprtfail: 82256668Sshin n = snprintf(sbuf, sizeof(sbuf), 82356668Sshin "500 could not translate to PORT\r\n"); 82456668Sshin write(src, sbuf, n); 82556668Sshin return n; 82656668Sshin } 82756668Sshin if (((struct sockaddr *)&data4)->sa_family != AF_INET) 82856668Sshin goto lprtfail; 82956668Sshin sin = (struct sockaddr_in *)&data4; 83056668Sshin sin->sin_port = 0; 83156668Sshin wport4 = socket(sin->sin_family, SOCK_STREAM, 0); 83256668Sshin if (wport4 == -1) 83356668Sshin goto lprtfail; 83456668Sshin error = bind(wport4, (struct sockaddr *)sin, sin->sin_len); 83556668Sshin if (error == -1) { 83656668Sshin close(wport4); 83756668Sshin wport4 = -1; 83856668Sshin goto lprtfail; 83956668Sshin } 84056668Sshin error = listen(wport4, 1); 84156668Sshin if (error == -1) { 84256668Sshin close(wport4); 84356668Sshin wport4 = -1; 84456668Sshin goto lprtfail; 84556668Sshin } 84656668Sshin 84756668Sshin /* transmit PORT */ 84856668Sshin n = sizeof(data4); 84956668Sshin error = getsockname(wport4, (struct sockaddr *)&data4, &n); 85056668Sshin if (error == -1) { 85156668Sshin close(wport4); 85256668Sshin wport4 = -1; 85356668Sshin goto lprtfail; 85456668Sshin } 85556668Sshin if (((struct sockaddr *)&data4)->sa_family != AF_INET) { 85656668Sshin close(wport4); 85756668Sshin wport4 = -1; 85856668Sshin goto lprtfail; 85956668Sshin } 86056668Sshin sin = (struct sockaddr_in *)&data4; 86156668Sshin a = (char *)&sin->sin_addr; 86256668Sshin p = (char *)&sin->sin_port; 86356668Sshin n = snprintf(sbuf, sizeof(sbuf), "PORT %d,%d,%d,%d,%d,%d\r\n", 86456668Sshin UC(a[0]), UC(a[1]), UC(a[2]), UC(a[3]), 86556668Sshin UC(p[0]), UC(p[1])); 86656668Sshin write(dst, sbuf, n); 86756668Sshin *state = nstate; 86856668Sshin passivemode = 0; 86956668Sshin return n; 87056668Sshin } else if (strcmp(cmd, "EPRT") == 0 && param) { 87156668Sshin /* 87256668Sshin * EPRT -> PORT 87356668Sshin */ 87456668Sshin char *afp, *hostp, *portp; 87556668Sshin struct addrinfo hints, *res; 87656668Sshin 87756668Sshin nstate = EPRT; 87856668Sshin 87956668Sshin close(wport4); 88056668Sshin close(wport6); 88156668Sshin close(port4); 88256668Sshin close(port6); 88356668Sshin wport4 = wport6 = port4 = port6 = -1; 88456668Sshin 88556668Sshin if (epsvall) { 88656668Sshin n = snprintf(sbuf, sizeof(sbuf), "501 %s disallowed in EPSV ALL\r\n", 88756668Sshin cmd); 88856668Sshin write(src, sbuf, n); 88956668Sshin return n; 89056668Sshin } 89156668Sshin 89256668Sshin p = param; 89356668Sshin ch = *p++; /* boundary character */ 89456668Sshin afp = p; 89556668Sshin while (*p && *p != ch) 89656668Sshin p++; 89756668Sshin if (!*p) { 89856668Sshineprtparamfail: 89956668Sshin n = snprintf(sbuf, sizeof(sbuf), 90056668Sshin "501 illegal parameter to EPRT\r\n"); 90156668Sshin write(src, sbuf, n); 90256668Sshin return n; 90356668Sshin } 90456668Sshin *p++ = '\0'; 90556668Sshin hostp = p; 90656668Sshin while (*p && *p != ch) 90756668Sshin p++; 90856668Sshin if (!*p) 90956668Sshin goto eprtparamfail; 91056668Sshin *p++ = '\0'; 91156668Sshin portp = p; 91256668Sshin while (*p && *p != ch) 91356668Sshin p++; 91456668Sshin if (!*p) 91556668Sshin goto eprtparamfail; 91656668Sshin *p++ = '\0'; 91756668Sshin 91856668Sshin n = sscanf(afp, "%d", &af); 91956668Sshin if (n != 1 || af != 2) { 92056668Sshin n = snprintf(sbuf, sizeof(sbuf), 92156668Sshin "501 unsupported address family to EPRT\r\n"); 92256668Sshin write(src, sbuf, n); 92356668Sshin return n; 92456668Sshin } 92556668Sshin memset(&hints, 0, sizeof(hints)); 92656668Sshin hints.ai_family = AF_UNSPEC; 92756668Sshin error = getaddrinfo(hostp, portp, &hints, &res); 92856668Sshin if (error) { 92956668Sshin n = snprintf(sbuf, sizeof(sbuf), 93062655Skris "501 EPRT: %s\r\n", gai_strerror(error)); 93156668Sshin write(src, sbuf, n); 93256668Sshin return n; 93356668Sshin } 93456668Sshin if (res->ai_next) { 93556668Sshin n = snprintf(sbuf, sizeof(sbuf), 93656668Sshin "501 EPRT: %s resolved to multiple addresses\r\n", hostp); 93756668Sshin write(src, sbuf, n); 93856668Sshin return n; 93956668Sshin } 94056668Sshin 94156668Sshin memcpy(&data6, res->ai_addr, res->ai_addrlen); 94256668Sshin 94356668Sshin goto sendport; 94456668Sshin } else if (strcmp(cmd, "LPSV") == 0 && !param) { 94556668Sshin /* 94656668Sshin * LPSV -> PASV 94756668Sshin */ 94856668Sshin nstate = LPSV; 94956668Sshin 95056668Sshin close(wport4); 95156668Sshin close(wport6); 95256668Sshin close(port4); 95356668Sshin close(port6); 95456668Sshin wport4 = wport6 = port4 = port6 = -1; 95556668Sshin 95656668Sshin if (epsvall) { 95756668Sshin n = snprintf(sbuf, sizeof(sbuf), "501 %s disallowed in EPSV ALL\r\n", 95856668Sshin cmd); 95956668Sshin write(src, sbuf, n); 96056668Sshin return n; 96156668Sshin } 96256668Sshin 96356668Sshin /* transmit PASV */ 96456668Sshin n = snprintf(sbuf, sizeof(sbuf), "PASV\r\n"); 96556668Sshin write(dst, sbuf, n); 96656668Sshin *state = LPSV; 96756668Sshin passivemode = 0; /* to be set to 1 later */ 96856668Sshin return n; 96956668Sshin } else if (strcmp(cmd, "EPSV") == 0 && !param) { 97056668Sshin /* 97156668Sshin * EPSV -> PASV 97256668Sshin */ 97356668Sshin close(wport4); 97456668Sshin close(wport6); 97556668Sshin close(port4); 97656668Sshin close(port6); 97756668Sshin wport4 = wport6 = port4 = port6 = -1; 97856668Sshin 97956668Sshin n = snprintf(sbuf, sizeof(sbuf), "PASV\r\n"); 98056668Sshin write(dst, sbuf, n); 98156668Sshin *state = EPSV; 98256668Sshin passivemode = 0; /* to be set to 1 later */ 98356668Sshin return n; 98456668Sshin } else if (strcmp(cmd, "EPSV") == 0 && param 98556668Sshin && strncasecmp(param, "ALL", 3) == 0 && isspace(param[3])) { 98656668Sshin /* 98756668Sshin * EPSV ALL 98856668Sshin */ 98956668Sshin epsvall = 1; 99056668Sshin n = snprintf(sbuf, sizeof(sbuf), "200 EPSV ALL command successful.\r\n"); 99156668Sshin write(src, sbuf, n); 99256668Sshin return n; 99356668Sshin#ifdef FAITH4 99456668Sshin } else if (strcmp(cmd, "PORT") == 0 && param) { 99556668Sshin /* 99656668Sshin * PORT -> EPRT 99756668Sshin */ 99856668Sshin char host[NI_MAXHOST], serv[NI_MAXSERV]; 99956668Sshin 100056668Sshin nstate = PORT; 100156668Sshin 100256668Sshin close(wport4); 100356668Sshin close(wport6); 100456668Sshin close(port4); 100556668Sshin close(port6); 100656668Sshin wport4 = wport6 = port4 = port6 = -1; 100756668Sshin 100856668Sshin p = param; 100956668Sshin n = sscanf(p, "%u,%u,%u,%u,%u,%u", 101056668Sshin &ho[0], &ho[1], &ho[2], &ho[3], &po[0], &po[1]); 101156668Sshin if (n != 6) { 101256668Sshin n = snprintf(sbuf, sizeof(sbuf), 101356668Sshin "501 illegal parameter to PORT\r\n"); 101456668Sshin write(src, sbuf, n); 101556668Sshin return n; 101656668Sshin } 101756668Sshin 101856668Sshin memset(&data6, 0, sizeof(data6)); 101956668Sshin sin = (struct sockaddr_in *)&data6; 102056668Sshin sin->sin_len = sizeof(*sin); 102156668Sshin sin->sin_family = AF_INET; 102256668Sshin sin->sin_addr.s_addr = htonl( 102356668Sshin ((ho[0] & 0xff) << 24) | ((ho[1] & 0xff) << 16) | 102456668Sshin ((ho[2] & 0xff) << 8) | (ho[3] & 0xff)); 102556668Sshin sin->sin_port = htons(((po[0] & 0xff) << 8) | (po[1] & 0xff)); 102656668Sshin 102756668Sshin /* get ready for active data connection */ 102856668Sshin n = sizeof(data4); 102956668Sshin error = getsockname(dst, (struct sockaddr *)&data4, &n); 103056668Sshin if (error == -1) { 103156668Sshinportfail: 103256668Sshin n = snprintf(sbuf, sizeof(sbuf), 103356668Sshin "500 could not translate to EPRT\r\n"); 103456668Sshin write(src, sbuf, n); 103556668Sshin return n; 103656668Sshin } 103756668Sshin if (((struct sockaddr *)&data4)->sa_family != AF_INET6) 103856668Sshin goto portfail; 103956668Sshin 104056668Sshin ((struct sockaddr_in6 *)&data4)->sin6_port = 0; 104156668Sshin sa = (struct sockaddr *)&data4; 104256668Sshin wport4 = socket(sa->sa_family, SOCK_STREAM, 0); 104356668Sshin if (wport4 == -1) 104456668Sshin goto portfail; 104556668Sshin error = bind(wport4, sa, sa->sa_len); 104656668Sshin if (error == -1) { 104756668Sshin close(wport4); 104856668Sshin wport4 = -1; 104956668Sshin goto portfail; 105056668Sshin } 105156668Sshin error = listen(wport4, 1); 105256668Sshin if (error == -1) { 105356668Sshin close(wport4); 105456668Sshin wport4 = -1; 105556668Sshin goto portfail; 105656668Sshin } 105756668Sshin 105856668Sshin /* transmit EPRT */ 105956668Sshin n = sizeof(data4); 106056668Sshin error = getsockname(wport4, (struct sockaddr *)&data4, &n); 106156668Sshin if (error == -1) { 106256668Sshin close(wport4); 106356668Sshin wport4 = -1; 106456668Sshin goto portfail; 106556668Sshin } 106656668Sshin af = 2; 106756668Sshin sa = (struct sockaddr *)&data4; 106856668Sshin if (getnameinfo(sa, sa->sa_len, host, sizeof(host), 106956668Sshin serv, sizeof(serv), NI_NUMERICHOST | NI_NUMERICSERV)) { 107056668Sshin close(wport4); 107156668Sshin wport4 = -1; 107256668Sshin goto portfail; 107356668Sshin } 107456668Sshin n = snprintf(sbuf, sizeof(sbuf), "EPRT |%d|%s|%s|\r\n", af, host, serv); 107556668Sshin write(dst, sbuf, n); 107656668Sshin *state = nstate; 107756668Sshin passivemode = 0; 107856668Sshin return n; 107956668Sshin } else if (strcmp(cmd, "PASV") == 0 && !param) { 108056668Sshin /* 108156668Sshin * PASV -> EPSV 108256668Sshin */ 108356668Sshin 108456668Sshin nstate = PASV; 108556668Sshin 108656668Sshin close(wport4); 108756668Sshin close(wport6); 108856668Sshin close(port4); 108956668Sshin close(port6); 109056668Sshin wport4 = wport6 = port4 = port6 = -1; 109156668Sshin 109256668Sshin /* transmit EPSV */ 109356668Sshin n = snprintf(sbuf, sizeof(sbuf), "EPSV\r\n"); 109456668Sshin write(dst, sbuf, n); 109556668Sshin *state = PASV; 109656668Sshin passivemode = 0; /* to be set to 1 later */ 109756668Sshin return n; 109856668Sshin#else /* FAITH4 */ 109956668Sshin } else if (strcmp(cmd, "PORT") == 0 || strcmp(cmd, "PASV") == 0) { 110056668Sshin /* 110156668Sshin * reject PORT/PASV 110256668Sshin */ 110356668Sshin n = snprintf(sbuf, sizeof(sbuf), "502 %s not implemented.\r\n", cmd); 110456668Sshin write(src, sbuf, n); 110556668Sshin return n; 110656668Sshin#endif /* FAITH4 */ 110756668Sshin } else if (passivemode 110856668Sshin && (strcmp(cmd, "STOR") == 0 110956668Sshin || strcmp(cmd, "STOU") == 0 111056668Sshin || strcmp(cmd, "RETR") == 0 111156668Sshin || strcmp(cmd, "LIST") == 0 111256668Sshin || strcmp(cmd, "NLST") == 0 111356668Sshin || strcmp(cmd, "APPE") == 0)) { 111456668Sshin /* 111556668Sshin * commands with data transfer. need to care about passive 111656668Sshin * mode data connection. 111756668Sshin */ 111856668Sshin 111956668Sshin if (ftp_passiveconn() < 0) { 112056668Sshin n = snprintf(sbuf, sizeof(sbuf), "425 Cannot open data connetion\r\n"); 112156668Sshin write(src, sbuf, n); 112256668Sshin } else { 112356668Sshin /* simply relay the command */ 112456668Sshin write(dst, rbuf, n); 112556668Sshin } 112656668Sshin 112756668Sshin *state = NONE; 112856668Sshin return n; 112956668Sshin } else { 113056668Sshin /* simply relay it */ 113156668Sshin *state = NONE; 113256668Sshin write(dst, rbuf, n); 113356668Sshin return n; 113456668Sshin } 113556668Sshin 113656668Sshin bad: 113756668Sshin exit_failure(ERRSTR); 113856668Sshin /*NOTREACHED*/ 113956668Sshin return 0; /* to make gcc happy */ 114056668Sshin} 1141