5
5
* | (__| |_| | _ <| |___
6
6
* \___|\___/|_| \_\_____|
8
* Copyright (C) 1998 - 2008, Daniel Stenberg, <daniel@haxx.se>, et al.
8
* Copyright (C) 1998 - 2009, Daniel Stenberg, <daniel@haxx.se>, et al.
10
10
* This software is licensed as described in the file COPYING, which
11
11
* you should have received as part of this distribution. The terms
84
82
#include "sslgen.h"
85
83
#include "connect.h"
86
84
#include "strerror.h"
88
85
#include "inet_ntop.h"
86
#include "inet_pton.h"
89
87
#include "select.h"
90
88
#include "parsedate.h" /* for the week day and month names */
91
89
#include "sockaddr.h" /* required for Curl_sockaddr_storage */
92
90
#include "multiif.h"
95
#if defined(HAVE_INET_NTOA_R) && !defined(HAVE_INET_NTOA_R_DECL)
96
#include "inet_ntoa_r.h"
99
94
#define _MPRINTF_REPLACE /* use our functions only */
100
95
#include <curl/mprintf.h>
102
98
/* The last #include file should be: */
104
99
#include "memdebug.h"
107
101
#ifdef HAVE_NI_WITHSCOPEID
108
102
#define NIFLAGS NI_NUMERICHOST | NI_NUMERICSERV | NI_WITHSCOPEID
534
533
dash or a space and it is significant */
537
else if(perline && (ftpc->nread_resp > BUFSIZE/2)) {
538
/* We got a large chunk of data and there's still trailing data to
539
take care of, so we put that part in the "cache" and restart */
536
else if(ftpc->nread_resp > BUFSIZE/2) {
537
/* We got a large chunk of data and there's potentially still trailing
538
data to take care of, so we put any such part in the "cache", clear
539
the buffer to make space and restart. */
540
540
clipamount = perline;
829
833
/* already done and fine */
830
834
result = ftp_state_post_cwd(conn);
836
ftpc->count2 = 0; /* count2 counts failed CWDs */
838
/* count3 is set to allow a MKD to fail once. In the case when first CWD
839
fails and then MKD fails (due to another session raced it to create the
840
dir) this then allows for a second try to CWD to it */
841
ftpc->count3 = (conn->data->set.ftp_create_missing_dirs==2)?1:0;
833
843
if(conn->bits.reuse && ftpc->entrypath) {
834
844
/* This is a re-used connection. Since we change directory to where the
835
845
transfer is taking place, we must first get back to the original dir
877
887
* IPv6-specific section
879
889
struct Curl_sockaddr_storage ss;
880
struct addrinfo *res, *ai;
890
Curl_addrinfo *res, *ai;
882
892
char hbuf[NI_MAXHOST];
883
893
struct sockaddr *sa=(struct sockaddr *)&ss;
894
struct sockaddr_in * const sa4 = (void *)sa;
895
struct sockaddr_in6 * const sa6 = (void *)sa;
885
static const char * const mode[] = { "EPRT", "PORT", NULL };
897
static const char mode[][5] = { "EPRT", "PORT" };
894
906
if(data->set.str[STRING_FTPPORT] &&
895
907
(strlen(data->set.str[STRING_FTPPORT]) > 1)) {
896
908
/* attempt to get the address of the given interface name */
897
if(!Curl_if2ip(data->set.str[STRING_FTPPORT], hbuf, sizeof(hbuf)))
909
if(!Curl_if2ip(conn->ip_addr->ai_family, data->set.str[STRING_FTPPORT],
898
911
/* not an interface, use the given string as host name instead */
899
912
host = data->set.str[STRING_FTPPORT];
967
980
/* It failed. Bind the address used for the control connection instead */
968
981
sslen = sizeof(ss);
969
if(getsockname(conn->sock[FIRSTSOCKET],
970
(struct sockaddr *)sa, &sslen)) {
982
if(getsockname(conn->sock[FIRSTSOCKET], sa, &sslen)) {
971
983
failf(data, "getsockname() failed: %s",
972
984
Curl_strerror(conn, SOCKERRNO) );
973
985
sclose(portsock);
977
989
/* set port number to zero to make bind() pick "any" */
978
if(((struct sockaddr *)sa)->sa_family == AF_INET)
979
((struct sockaddr_in *)sa)->sin_port=0;
990
if(sa->sa_family == AF_INET)
981
((struct sockaddr_in6 *)sa)->sin6_port =0;
983
995
if(sslen > (socklen_t)sizeof(ss))
984
996
sslen = sizeof(ss);
986
if(bind(portsock, (struct sockaddr *)sa, sslen)) {
998
if(bind(portsock, sa, sslen)) {
987
999
failf(data, "bind failed: %s", Curl_strerror(conn, SOCKERRNO));
988
1000
sclose(portsock);
989
1001
return CURLE_FTP_PORT_FAILED;
1106
1118
(void)fcmd; /* not used in the IPv4 code */
1107
1119
if(ftpportstr) {
1110
/* First check if the given name is an IP address */
1111
in=inet_addr(ftpportstr);
1113
if(in != CURL_INADDR_NONE)
1122
/* First check if the given string is an IP address */
1123
if(Curl_inet_pton(AF_INET, ftpportstr, &in) > 0) {
1114
1124
/* this is an IPv4 address */
1115
addr = Curl_ip2addr(in, ftpportstr, 0);
1117
if(Curl_if2ip(ftpportstr, myhost, sizeof(myhost))) {
1118
/* The interface to IP conversion provided a dotted address */
1119
in=inet_addr(myhost);
1120
addr = Curl_ip2addr(in, myhost, 0);
1125
addr = Curl_ip2addr(AF_INET, &in, ftpportstr, 0);
1127
/* otherwise check if the given string is an interface */
1128
else if(Curl_if2ip(AF_INET, ftpportstr, myhost, sizeof(myhost))) {
1129
/* The interface to IP conversion provided a dotted address */
1130
if(Curl_inet_pton(AF_INET, myhost, &in) > 0)
1131
addr = Curl_ip2addr(AF_INET, &in, myhost, 0);
1133
else if(strlen(ftpportstr)> 1) {
1134
/* might be a host name! */
1135
struct Curl_dns_entry *h=NULL;
1136
int rc = Curl_resolv(conn, ftpportstr, 0, &h);
1137
if(rc == CURLRESOLV_PENDING)
1139
rc = Curl_wait_for_resolv(conn, &h);
1142
/* when we return from this function, we can forget about this entry
1143
so we can unlock it now already */
1144
Curl_resolv_unlock(data, h);
1146
freeaddr = FALSE; /* make sure we don't free 'addr' in this function
1147
since it points to a DNS cache entry! */
1150
infof(data, "Failed to resolve host name %s\n", ftpportstr);
1122
else if(strlen(ftpportstr)> 1) {
1123
/* might be a host name! */
1124
struct Curl_dns_entry *h=NULL;
1125
int rc = Curl_resolv(conn, ftpportstr, 0, &h);
1126
if(rc == CURLRESOLV_PENDING)
1128
rc = Curl_wait_for_resolv(conn, &h);
1131
/* when we return from this function, we can forget about this entry
1132
so we can unlock it now already */
1133
Curl_resolv_unlock(data, h);
1135
freeaddr = FALSE; /* make sure we don't free 'addr' in this function
1136
since it points to a DNS cache entry! */
1139
infof(data, "Failed to resolve host name %s\n", ftpportstr);
1142
} /* CURL_INADDR_NONE */
1143
1153
} /* ftpportstr */
1830
1846
rc = Curl_wait_for_resolv(conn, &addr);
1833
failf(data, "Can't resolve new host %s:%d", newhost, newport);
1834
return CURLE_FTP_CANT_GET_HOST;
1836
1848
connectport = newport; /* we connect to the remote port */
1851
failf(data, "Can't resolve new host %s:%d", newhost, connectport);
1852
return CURLE_FTP_CANT_GET_HOST;
1839
1856
result = Curl_connecthost(conn,
1872
1889
ftp_pasv_verbose(conn, conninfo, newhost, connectport);
1874
1891
switch(data->set.proxytype) {
1892
#ifndef CURL_DISABLE_PROXY
1875
1893
case CURLPROXY_SOCKS5:
1876
1894
case CURLPROXY_SOCKS5_HOSTNAME:
1877
1895
result = Curl_SOCKS5(conn->proxyuser, conn->proxypasswd, newhost, newport,
1878
1896
SECONDARYSOCKET, conn);
1880
case CURLPROXY_HTTP:
1881
/* do nothing here. handled later. */
1883
1898
case CURLPROXY_SOCKS4:
1884
1899
result = Curl_SOCKS4(conn->proxyuser, newhost, newport,
1885
1900
SECONDARYSOCKET, conn, FALSE);
1888
1903
result = Curl_SOCKS4(conn->proxyuser, newhost, newport,
1889
1904
SECONDARYSOCKET, conn, TRUE);
1906
#endif /* CURL_DISABLE_PROXY */
1907
case CURLPROXY_HTTP:
1908
case CURLPROXY_HTTP_1_0:
1909
/* do nothing here. handled later. */
1892
1912
failf(data, "unknown proxytype option given");
1893
1913
result = CURLE_COULDNT_CONNECT;
1896
#ifndef CURL_DISABLE_HTTP
1916
#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_PROXY)
1897
1917
if(conn->bits.tunnel_proxy && conn->bits.httpproxy) {
1898
1918
/* FIX: this MUST wait for a proper connect first if 'connected' is
2680
/* FIX: check response code */
2682
/* For TLS, the data connection can have one of two security levels.
2684
1) Clear (requested by 'PROT C')
2686
2)Private (requested by 'PROT P')
2688
if(!conn->ssl[SECONDARYSOCKET].use) {
2689
NBFTPSENDF(conn, "PROT %c",
2690
data->set.ftp_ssl == CURLUSESSL_CONTROL ? 'C' : 'P');
2691
state(conn, FTP_PROT);
2694
result = ftp_state_pwd(conn);
2704
NBFTPSENDF(conn, "PROT %c",
2705
data->set.ftp_ssl == CURLUSESSL_CONTROL ? 'C' : 'P');
2706
state(conn, FTP_PROT);
3223
3234
shutdown(conn->sock[SECONDARYSOCKET],2); /* SD_BOTH */
3226
if(conn->ssl[SECONDARYSOCKET].use) {
3227
/* The secondary socket is using SSL so we must close down that part first
3228
before we close the socket for real */
3229
Curl_ssl_close(conn, SECONDARYSOCKET);
3231
/* Note that we keep "use" set to TRUE since that (next) connection is
3232
still requested to use SSL */
3237
if(conn->sock[SECONDARYSOCKET] != CURL_SOCKET_BAD) {
3238
if(conn->ssl[SECONDARYSOCKET].use) {
3239
/* The secondary socket is using SSL so we must close down that part first
3240
before we close the socket for real */
3241
Curl_ssl_close(conn, SECONDARYSOCKET);
3243
/* Note that we keep "use" set to TRUE since that (next) connection is
3244
still requested to use SSL */
3246
sclose(conn->sock[SECONDARYSOCKET]);
3248
conn->sock[SECONDARYSOCKET] = CURL_SOCKET_BAD;
3234
sclose(conn->sock[SECONDARYSOCKET]);
3236
conn->sock[SECONDARYSOCKET] = CURL_SOCKET_BAD;
3238
if((ftp->transfer == FTPTRANSFER_BODY) && !status && !premature) {
3251
if((ftp->transfer == FTPTRANSFER_BODY) && ftpc->ctl_valid &&
3252
ftpc->pending_resp && !premature) {
3240
3254
* Let's see what the server says about the transfer we just performed,
3241
3255
* but lower the timeout as sometimes this connection has died while the
3847
3861
/* the ftp struct is already inited in ftp_connect() */
3848
3862
struct FTP *ftp = data->state.proto.ftp;
3849
3863
struct ftp_conn *ftpc = &conn->proto.ftpc;
3851
char *slash_pos; /* position of the first '/' char in curpos */
3852
char *path_to_use = data->state.path;
3864
const char *slash_pos; /* position of the first '/' char in curpos */
3865
const char *path_to_use = data->state.path;
3866
const char *cur_pos;
3867
const char *filename = NULL;
3855
3869
cur_pos = path_to_use; /* current position in path. point at the begin
3856
3870
of next path component */
3872
3886
if(data->state.path &&
3873
3887
data->state.path[0] &&
3874
3888
(data->state.path[strlen(data->state.path) - 1] != '/') )
3875
ftpc->file = data->state.path; /* this is a full file path */
3889
filename = data->state.path; /* this is a full file path */
3879
3891
ftpc->file is not used anywhere other than for operations on a file.
3880
3892
In other words, never for directory operations.
3881
So we can safely set it to NULL here and use it as a
3893
So we can safely leave filename as NULL here and use it as a
3882
3894
argument in dir/file decisions.
3905
3916
return CURLE_OUT_OF_MEMORY;
3907
3918
ftpc->dirdepth = 1; /* we consider it to be a single dir */
3908
ftpc->file = slash_pos ? slash_pos+1 : cur_pos; /* rest is file name */
3919
filename = slash_pos ? slash_pos+1 : cur_pos; /* rest is file name */
3911
ftpc->file = cur_pos; /* this is a file name only */
3922
filename = cur_pos; /* this is a file name only */
3914
3925
default: /* allow pretty much anything */
3915
3926
case FTPFILE_MULTICWD:
3916
3927
ftpc->dirdepth = 0;
3917
3928
ftpc->diralloc = 5; /* default dir depth to allocate */
3918
ftpc->dirs = (char **)calloc(ftpc->diralloc, sizeof(ftpc->dirs[0]));
3929
ftpc->dirs = calloc(ftpc->diralloc, sizeof(ftpc->dirs[0]));
3919
3930
if(!ftpc->dirs)
3920
3931
return CURLE_OUT_OF_MEMORY;
3973
ftpc->file = cur_pos; /* the rest is the file name */
3984
filename = cur_pos; /* the rest is the file name */
3976
if(ftpc->file && *ftpc->file) {
3977
ftpc->file = curl_easy_unescape(conn->data, ftpc->file, 0, NULL);
3988
if(filename && *filename) {
3989
ftpc->file = curl_easy_unescape(conn->data, filename, 0, NULL);
3978
3990
if(NULL == ftpc->file) {
3979
3991
freedirs(ftpc);
3980
3992
failf(data, "no memory");
4000
4012
if(ftpc->prevpath) {
4001
4013
/* prevpath is "raw" so we convert the input path before we compare the
4003
char *path = curl_easy_unescape(conn->data, data->state.path, 0, NULL);
4016
char *path = curl_easy_unescape(conn->data, data->state.path, 0, &dlen);
4005
4018
freedirs(ftpc);
4006
4019
return CURLE_OUT_OF_MEMORY;
4009
dlen = strlen(path) - (ftpc->file?strlen(ftpc->file):0);
4010
if((dlen == strlen(ftpc->prevpath)) &&
4011
curl_strnequal(path, ftpc->prevpath, dlen)) {
4022
dlen -= ftpc->file?strlen(ftpc->file):0;
4023
if((dlen == (int)strlen(ftpc->prevpath)) &&
4024
strnequal(path, ftpc->prevpath, dlen)) {
4012
4025
infof(data, "Request has same path as previous transfer\n");
4013
4026
ftpc->cwddone = TRUE;