summaryrefslogtreecommitdiff
path: root/libs/libcurl/src/ftp.c
diff options
context:
space:
mode:
Diffstat (limited to 'libs/libcurl/src/ftp.c')
-rw-r--r--libs/libcurl/src/ftp.c199
1 files changed, 95 insertions, 104 deletions
diff --git a/libs/libcurl/src/ftp.c b/libs/libcurl/src/ftp.c
index cee0d97c59..03678ac20c 100644
--- a/libs/libcurl/src/ftp.c
+++ b/libs/libcurl/src/ftp.c
@@ -72,6 +72,7 @@
#include "warnless.h"
#include "http_proxy.h"
#include "socks.h"
+#include "strdup.h"
/* The last 3 #include files should be in this order */
#include "curl_printf.h"
#include "curl_memory.h"
@@ -167,7 +168,7 @@ const struct Curl_handler Curl_handler_ftp = {
ftp_domore_getsock, /* domore_getsock */
ZERO_NULL, /* perform_getsock */
ftp_disconnect, /* disconnect */
- ZERO_NULL, /* readwrite */
+ ZERO_NULL, /* write_resp */
ZERO_NULL, /* connection_check */
ZERO_NULL, /* attach connection */
PORT_FTP, /* defport */
@@ -198,7 +199,7 @@ const struct Curl_handler Curl_handler_ftps = {
ftp_domore_getsock, /* domore_getsock */
ZERO_NULL, /* perform_getsock */
ftp_disconnect, /* disconnect */
- ZERO_NULL, /* readwrite */
+ ZERO_NULL, /* write_resp */
ZERO_NULL, /* connection_check */
ZERO_NULL, /* attach connection */
PORT_FTPS, /* defport */
@@ -362,10 +363,11 @@ static CURLcode ReceivedServerConnect(struct Curl_easy *data, bool *received)
curl_socket_t data_sock = conn->sock[SECONDARYSOCKET];
struct ftp_conn *ftpc = &conn->proto.ftpc;
struct pingpong *pp = &ftpc->pp;
- int result;
+ int socketstate = 0;
timediff_t timeout_ms;
ssize_t nread;
int ftpcode;
+ bool response = FALSE;
*received = FALSE;
@@ -378,17 +380,21 @@ static CURLcode ReceivedServerConnect(struct Curl_easy *data, bool *received)
}
/* First check whether there is a cached response from server */
- if(pp->cache_size && pp->cache && pp->cache[0] > '3') {
+ if(Curl_dyn_len(&pp->recvbuf) && (*Curl_dyn_ptr(&pp->recvbuf) > '3')) {
/* Data connection could not be established, let's return */
infof(data, "There is negative response in cache while serv connect");
(void)Curl_GetFTPResponse(data, &nread, &ftpcode);
return CURLE_FTP_ACCEPT_FAILED;
}
- result = Curl_socket_check(ctrl_sock, data_sock, CURL_SOCKET_BAD, 0);
+ if(pp->overflow)
+ /* there is pending control data still in the buffer to read */
+ response = TRUE;
+ else
+ socketstate = Curl_socket_check(ctrl_sock, data_sock, CURL_SOCKET_BAD, 0);
/* see if the connection request is already here */
- switch(result) {
+ switch(socketstate) {
case -1: /* error */
/* let's die here */
failf(data, "Error while waiting for server connect");
@@ -396,23 +402,23 @@ static CURLcode ReceivedServerConnect(struct Curl_easy *data, bool *received)
case 0: /* Server connect is not received yet */
break; /* loop */
default:
-
- if(result & CURL_CSELECT_IN2) {
+ if(socketstate & CURL_CSELECT_IN2) {
infof(data, "Ready to accept data connection from server");
*received = TRUE;
}
- else if(result & CURL_CSELECT_IN) {
- infof(data, "Ctrl conn has data while waiting for data conn");
- (void)Curl_GetFTPResponse(data, &nread, &ftpcode);
-
- if(ftpcode/100 > 3)
- return CURLE_FTP_ACCEPT_FAILED;
+ else if(socketstate & CURL_CSELECT_IN)
+ response = TRUE;
+ break;
+ }
+ if(response) {
+ infof(data, "Ctrl conn has data while waiting for data conn");
+ (void)Curl_GetFTPResponse(data, &nread, &ftpcode);
- return CURLE_WEIRD_SERVER_REPLY;
- }
+ if(ftpcode/100 > 3)
+ return CURLE_FTP_ACCEPT_FAILED;
- break;
- } /* switch() */
+ return CURLE_WEIRD_SERVER_REPLY;
+ }
return CURLE_OK;
}
@@ -553,7 +559,7 @@ static CURLcode ftp_readresp(struct Curl_easy *data,
#ifdef HAVE_GSSAPI
{
struct connectdata *conn = data->conn;
- char * const buf = data->state.buffer;
+ char * const buf = Curl_dyn_ptr(&data->conn->proto.ftpc.pp.recvbuf);
/* handle the security-oriented responses 6xx ***/
switch(code) {
@@ -659,7 +665,7 @@ CURLcode Curl_GetFTPResponse(struct Curl_easy *data,
*
*/
- if(pp->cache && (cache_skip < 2)) {
+ if(Curl_dyn_len(&pp->recvbuf) && (cache_skip < 2)) {
/*
* There's a cache left since before. We then skipping the wait for
* socket action, unless this is the same cache like the previous round
@@ -687,7 +693,7 @@ CURLcode Curl_GetFTPResponse(struct Curl_easy *data,
if(result)
break;
- if(!nread && pp->cache)
+ if(!nread && Curl_dyn_len(&pp->recvbuf))
/* bump cache skip counter as on repeated skips we must wait for more
data */
cache_skip++;
@@ -926,6 +932,8 @@ static CURLcode ftp_state_use_port(struct Curl_easy *data,
bool possibly_non_local = TRUE;
char buffer[STRERROR_LEN];
char *addr = NULL;
+ size_t addrlen = 0;
+ char ipstr[50];
/* Step 1, figure out what is requested,
* accepted format :
@@ -934,32 +942,17 @@ static CURLcode ftp_state_use_port(struct Curl_easy *data,
if(data->set.str[STRING_FTPPORT] &&
(strlen(data->set.str[STRING_FTPPORT]) > 1)) {
-
-#ifdef ENABLE_IPV6
- size_t addrlen = INET6_ADDRSTRLEN > strlen(string_ftpport) ?
- INET6_ADDRSTRLEN : strlen(string_ftpport);
-#else
- size_t addrlen = INET_ADDRSTRLEN > strlen(string_ftpport) ?
- INET_ADDRSTRLEN : strlen(string_ftpport);
-#endif
- char *ip_start = string_ftpport;
char *ip_end = NULL;
- char *port_start = NULL;
- char *port_sep = NULL;
-
- addr = calloc(1, addrlen + 1);
- if(!addr) {
- result = CURLE_OUT_OF_MEMORY;
- goto out;
- }
#ifdef ENABLE_IPV6
if(*string_ftpport == '[') {
/* [ipv6]:port(-range) */
- ip_start = string_ftpport + 1;
- ip_end = strchr(string_ftpport, ']');
- if(ip_end)
- strncpy(addr, ip_start, ip_end - ip_start);
+ char *ip_start = string_ftpport + 1;
+ ip_end = strchr(ip_start, ']');
+ if(ip_end) {
+ addrlen = ip_end - ip_start;
+ addr = ip_start;
+ }
}
else
#endif
@@ -969,28 +962,27 @@ static CURLcode ftp_state_use_port(struct Curl_easy *data,
}
else {
ip_end = strchr(string_ftpport, ':');
+ addr = string_ftpport;
if(ip_end) {
/* either ipv6 or (ipv4|domain|interface):port(-range) */
+ addrlen = ip_end - string_ftpport;
#ifdef ENABLE_IPV6
if(Curl_inet_pton(AF_INET6, string_ftpport, &sa6->sin6_addr) == 1) {
/* ipv6 */
port_min = port_max = 0;
- strcpy(addr, string_ftpport);
ip_end = NULL; /* this got no port ! */
}
- else
#endif
- /* (ipv4|domain|interface):port(-range) */
- strncpy(addr, string_ftpport, ip_end - ip_start);
}
else
/* ipv4|interface */
- strcpy(addr, string_ftpport);
+ addrlen = strlen(string_ftpport);
}
/* parse the port */
if(ip_end) {
- port_start = strchr(ip_end, ':');
+ char *port_sep = NULL;
+ char *port_start = strchr(ip_end, ':');
if(port_start) {
port_min = curlx_ultous(strtoul(port_start + 1, NULL, 10));
port_sep = strchr(port_start, '-');
@@ -1011,22 +1003,29 @@ static CURLcode ftp_state_use_port(struct Curl_easy *data,
if(port_min > port_max)
port_min = port_max = 0;
- if(*addr != '\0') {
+ if(addrlen) {
+ DEBUGASSERT(addr);
+ if(addrlen >= sizeof(ipstr))
+ goto out;
+ memcpy(ipstr, addr, addrlen);
+ ipstr[addrlen] = 0;
+
/* attempt to get the address of the given interface name */
switch(Curl_if2ip(conn->remote_addr->family,
#ifdef ENABLE_IPV6
Curl_ipv6_scope(&conn->remote_addr->sa_addr),
conn->scope_id,
#endif
- addr, hbuf, sizeof(hbuf))) {
+ ipstr, hbuf, sizeof(hbuf))) {
case IF2IP_NOT_FOUND:
/* not an interface, use the given string as host name instead */
- host = addr;
+ host = ipstr;
break;
case IF2IP_AF_NOT_SUPPORTED:
goto out;
case IF2IP_FOUND:
host = hbuf; /* use the hbuf for host name */
+ break;
}
}
else
@@ -1266,7 +1265,6 @@ out:
}
if(portsock != CURL_SOCKET_BAD)
Curl_socket_close(data, conn, portsock);
- free(addr);
return result;
}
@@ -1589,13 +1587,14 @@ static CURLcode ftp_state_ul_setup(struct Curl_easy *data,
}
/* seekerr == CURL_SEEKFUNC_CANTSEEK (can't seek to offset) */
do {
+ char scratch[4*1024];
size_t readthisamountnow =
- (data->state.resume_from - passed > data->set.buffer_size) ?
- (size_t)data->set.buffer_size :
+ (data->state.resume_from - passed > (curl_off_t)sizeof(scratch)) ?
+ sizeof(scratch) :
curlx_sotouz(data->state.resume_from - passed);
size_t actuallyread =
- data->state.fread_func(data->state.buffer, 1, readthisamountnow,
+ data->state.fread_func(scratch, 1, readthisamountnow,
data->state.in);
passed += actuallyread;
@@ -1828,7 +1827,9 @@ static CURLcode ftp_state_pasv_resp(struct Curl_easy *data,
struct Curl_dns_entry *addr = NULL;
enum resolve_t rc;
unsigned short connectport; /* the local port connect() should use! */
- char *str = &data->state.buffer[4]; /* start on the first letter */
+ struct pingpong *pp = &ftpc->pp;
+ char *str =
+ Curl_dyn_ptr(&pp->recvbuf) + 4; /* start on the first letter */
/* if we come here again, make sure the former name is cleared */
Curl_safefree(ftpc->newhost);
@@ -2106,8 +2107,9 @@ static CURLcode ftp_state_mdtm_resp(struct Curl_easy *data,
/* we got a time. Format should be: "YYYYMMDDHHMMSS[.sss]" where the
last .sss part is optional and means fractions of a second */
int year, month, day, hour, minute, second;
- if(ftp_213_date(&data->state.buffer[4],
- &year, &month, &day, &hour, &minute, &second)) {
+ struct pingpong *pp = &ftpc->pp;
+ char *resp = Curl_dyn_ptr(&pp->recvbuf) + 4;
+ if(ftp_213_date(resp, &year, &month, &day, &hour, &minute, &second)) {
/* we have a time, reformat it */
char timebuf[24];
msnprintf(timebuf, sizeof(timebuf),
@@ -2318,7 +2320,8 @@ static CURLcode ftp_state_size_resp(struct Curl_easy *data,
{
CURLcode result = CURLE_OK;
curl_off_t filesize = -1;
- char *buf = data->state.buffer;
+ char *buf = Curl_dyn_ptr(&data->conn->proto.ftpc.pp.recvbuf);
+ size_t len = data->conn->proto.ftpc.pp.nfinal;
/* get the size from the ascii string: */
if(ftpcode == 213) {
@@ -2326,13 +2329,13 @@ static CURLcode ftp_state_size_resp(struct Curl_easy *data,
for all the digits at the end of the response and parse only those as a
number. */
char *start = &buf[4];
- char *fdigit = strchr(start, '\r');
+ char *fdigit = memchr(start, '\r', len);
if(fdigit) {
- do
+ fdigit--;
+ if(*fdigit == '\n')
+ fdigit--;
+ while(ISDIGIT(fdigit[-1]) && (fdigit > start))
fdigit--;
- while(ISDIGIT(*fdigit) && (fdigit > start));
- if(!ISDIGIT(*fdigit))
- fdigit++;
}
else
fdigit = start;
@@ -2501,7 +2504,7 @@ static CURLcode ftp_state_get_resp(struct Curl_easy *data,
*
* Example D above makes this parsing a little tricky */
char *bytes;
- char *buf = data->state.buffer;
+ char *buf = Curl_dyn_ptr(&conn->proto.ftpc.pp.recvbuf);
bytes = strstr(buf, " bytes");
if(bytes) {
long in = (long)(--bytes-buf);
@@ -2770,7 +2773,7 @@ static CURLcode ftp_statemachine(struct Curl_easy *data,
case FTP_AUTH:
/* we have gotten the response to a previous AUTH command */
- if(pp->cache_size)
+ if(pp->overflow)
return CURLE_WEIRD_SERVER_REPLY; /* Forbid pipelining in response. */
/* RFC2228 (page 5) says:
@@ -2868,14 +2871,11 @@ static CURLcode ftp_statemachine(struct Curl_easy *data,
case FTP_PWD:
if(ftpcode == 257) {
- char *ptr = &data->state.buffer[4]; /* start on the first letter */
- const size_t buf_size = data->set.buffer_size;
- char *dir;
+ char *ptr = Curl_dyn_ptr(&pp->recvbuf) + 4; /* start on the first
+ letter */
bool entry_extracted = FALSE;
-
- dir = malloc(nread + 1);
- if(!dir)
- return CURLE_OUT_OF_MEMORY;
+ struct dynbuf out;
+ Curl_dyn_init(&out, 1000);
/* Reply format is like
257<space>[rubbish]"<directory-name>"<space><commentary> and the
@@ -2887,33 +2887,30 @@ static CURLcode ftp_statemachine(struct Curl_easy *data,
*/
/* scan for the first double-quote for non-standard responses */
- while(ptr < &data->state.buffer[buf_size]
- && *ptr != '\n' && *ptr != '\0' && *ptr != '"')
+ while(*ptr != '\n' && *ptr != '\0' && *ptr != '"')
ptr++;
if('\"' == *ptr) {
/* it started good */
- char *store;
- ptr++;
- for(store = dir; *ptr;) {
+ for(ptr++; *ptr; ptr++) {
if('\"' == *ptr) {
if('\"' == ptr[1]) {
/* "quote-doubling" */
- *store = ptr[1];
+ result = Curl_dyn_addn(&out, &ptr[1], 1);
ptr++;
}
else {
/* end of path */
- entry_extracted = TRUE;
+ if(Curl_dyn_len(&out))
+ entry_extracted = TRUE;
break; /* get out of this loop */
}
}
else
- *store = *ptr;
- store++;
- ptr++;
+ result = Curl_dyn_addn(&out, ptr, 1);
+ if(result)
+ return result;
}
- *store = '\0'; /* null-terminate */
}
if(entry_extracted) {
/* If the path name does not look like an absolute path (i.e.: it
@@ -2927,6 +2924,7 @@ static CURLcode ftp_statemachine(struct Curl_easy *data,
The method used here is to check the server OS: we do it only
if the path name looks strange to minimize overhead on other
systems. */
+ char *dir = Curl_dyn_ptr(&out);
if(!ftpc->server_os && dir[0] != '/') {
result = Curl_pp_sendf(data, &ftpc->pp, "%s", "SYST");
@@ -2951,7 +2949,7 @@ static CURLcode ftp_statemachine(struct Curl_easy *data,
}
else {
/* couldn't get the path */
- free(dir);
+ Curl_dyn_free(&out);
infof(data, "Failed to figure out path");
}
}
@@ -2961,25 +2959,23 @@ static CURLcode ftp_statemachine(struct Curl_easy *data,
case FTP_SYST:
if(ftpcode == 215) {
- char *ptr = &data->state.buffer[4]; /* start on the first letter */
+ char *ptr = Curl_dyn_ptr(&pp->recvbuf) + 4; /* start on the first
+ letter */
char *os;
- char *store;
-
- os = malloc(nread + 1);
- if(!os)
- return CURLE_OUT_OF_MEMORY;
+ char *start;
/* Reply format is like
215<space><OS-name><space><commentary>
*/
while(*ptr == ' ')
ptr++;
- for(store = os; *ptr && *ptr != ' ';)
- *store++ = *ptr++;
- *store = '\0'; /* null-terminate */
+ for(start = ptr; *ptr && *ptr != ' '; ptr++)
+ ;
+ os = Curl_memdup0(start, ptr - start);
+ if(!os)
+ return CURLE_OUT_OF_MEMORY;
/* Check for special servers here. */
-
if(strcasecompare(os, "OS/400")) {
/* Force OS400 name format 1. */
result = Curl_pp_sendf(data, &ftpc->pp, "%s", "SITE NAMEFMT 1");
@@ -3131,7 +3127,6 @@ static CURLcode ftp_statemachine(struct Curl_easy *data,
break;
case FTP_QUIT:
- /* fallthrough, just stop! */
default:
/* internal error */
ftp_state(data, FTP_STOP);
@@ -3206,8 +3201,7 @@ static CURLcode ftp_connect(struct Curl_easy *data,
conn->bits.ftp_use_control_ssl = TRUE;
}
- Curl_pp_setup(pp); /* once per transfer */
- Curl_pp_init(data, pp); /* init the generic pingpong data */
+ Curl_pp_init(pp); /* once per transfer */
/* When we connect, we start in the state where we await the 220
response */
@@ -3258,14 +3252,13 @@ static CURLcode ftp_done(struct Curl_easy *data, CURLcode status,
case CURLE_REMOTE_FILE_NOT_FOUND:
case CURLE_WRITE_ERROR:
/* the connection stays alive fine even though this happened */
- /* fall-through */
case CURLE_OK: /* doesn't affect the control connection's status */
if(!premature)
break;
/* until we cope better with prematurely ended requests, let them
* fallback as if in complete failure */
- /* FALLTHROUGH */
+ FALLTHROUGH();
default: /* by default, an error means the control connection is
wedged and should not be used anymore */
ftpc->ctl_valid = FALSE;
@@ -4177,13 +4170,12 @@ CURLcode ftp_parse_url_path(struct Curl_easy *data)
return CURLE_OUT_OF_MEMORY;
}
- ftpc->dirs[0] = calloc(1, dirlen + 1);
+ ftpc->dirs[0] = Curl_memdup0(rawPath, dirlen);
if(!ftpc->dirs[0]) {
free(rawPath);
return CURLE_OUT_OF_MEMORY;
}
- strncpy(ftpc->dirs[0], rawPath, dirlen);
ftpc->dirdepth = 1; /* we consider it to be a single dir */
fileName = slashPos + 1; /* rest is file name */
}
@@ -4222,12 +4214,11 @@ CURLcode ftp_parse_url_path(struct Curl_easy *data)
CWD requires a parameter and a non-existent parameter a) doesn't
work on many servers and b) has no effect on the others. */
if(compLen > 0) {
- char *comp = calloc(1, compLen + 1);
+ char *comp = Curl_memdup0(curPos, compLen);
if(!comp) {
free(rawPath);
return CURLE_OUT_OF_MEMORY;
}
- strncpy(comp, curPos, compLen);
ftpc->dirs[ftpc->dirdepth++] = comp;
}
curPos = slashPos + 1;