1 /***************************************************************************
3 * Project ___| | | | _ \| |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
8 * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al.
10 * This software is licensed as described in the file COPYING, which
11 * you should have received as part of this distribution. The terms
12 * are also available at http://curl.haxx.se/docs/copyright.html.
14 * You may opt to use, copy, modify, merge, publish, distribute and/or sell
15 * copies of the Software, and permit persons to whom the Software is
16 * furnished to do so, under the terms of the COPYING file.
18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19 * KIND, either express or implied.
21 ***************************************************************************/
25 #ifndef CURL_DISABLE_FTP
36 #ifdef HAVE_SYS_SOCKET_H
37 #include <sys/socket.h>
39 #ifdef HAVE_NETINET_IN_H
40 #include <netinet/in.h>
42 #ifdef HAVE_ARPA_INET_H
43 #include <arpa/inet.h>
46 #include <sys/utsname.h>
56 #if (defined(NETWARE) && defined(__NOVELL_LIBC__))
58 #define in_addr_t unsigned long
61 #include <curl/curl.h>
69 #include "http.h" /* for HTTP proxy tunnel stuff */
73 #include "ftplistparser.h"
75 #if defined(HAVE_KRB4) || defined(HAVE_GSSAPI)
79 #include "strtoofft.h"
84 #include "inet_ntop.h"
85 #include "inet_pton.h"
87 #include "parsedate.h" /* for the week day and month names */
88 #include "sockaddr.h" /* required for Curl_sockaddr_storage */
92 #include "speedcheck.h"
94 #include "http_proxy.h"
95 #include "non-ascii.h"
97 #define _MPRINTF_REPLACE /* use our functions only */
98 #include <curl/mprintf.h>
100 #include "curl_memory.h"
101 /* The last #include file should be: */
102 #include "memdebug.h"
105 #define NI_MAXHOST 1025
107 #ifndef INET_ADDRSTRLEN
108 #define INET_ADDRSTRLEN 16
111 #ifdef CURL_DISABLE_VERBOSE_STRINGS
112 #define ftp_pasv_verbose(a,b,c,d) do { } while(0)
115 /* Local API functions */
116 static CURLcode ftp_sendquote(struct connectdata *conn,
117 struct curl_slist *quote);
118 static CURLcode ftp_quit(struct connectdata *conn);
119 static CURLcode ftp_parse_url_path(struct connectdata *conn);
120 static CURLcode ftp_regular_transfer(struct connectdata *conn, bool *done);
121 #ifndef CURL_DISABLE_VERBOSE_STRINGS
122 static void ftp_pasv_verbose(struct connectdata *conn,
124 char *newhost, /* ascii version */
127 static CURLcode ftp_state_post_rest(struct connectdata *conn);
128 static CURLcode ftp_state_post_cwd(struct connectdata *conn);
129 static CURLcode ftp_state_quote(struct connectdata *conn,
130 bool init, ftpstate instate);
131 static CURLcode ftp_nb_type(struct connectdata *conn,
132 bool ascii, ftpstate newstate);
133 static int ftp_need_type(struct connectdata *conn,
135 static CURLcode ftp_do(struct connectdata *conn, bool *done);
136 static CURLcode ftp_done(struct connectdata *conn,
137 CURLcode, bool premature);
138 static CURLcode ftp_connect(struct connectdata *conn, bool *done);
139 static CURLcode ftp_disconnect(struct connectdata *conn, bool dead_connection);
140 static CURLcode ftp_nextconnect(struct connectdata *conn);
141 static CURLcode ftp_multi_statemach(struct connectdata *conn, bool *done);
142 static int ftp_getsock(struct connectdata *conn,
143 curl_socket_t *socks,
145 static CURLcode ftp_doing(struct connectdata *conn,
147 static CURLcode ftp_setup_connection(struct connectdata * conn);
149 static CURLcode init_wc_data(struct connectdata *conn);
150 static CURLcode wc_statemach(struct connectdata *conn);
152 static void wc_data_dtor(void *ptr);
154 static CURLcode ftp_state_post_retr_size(struct connectdata *conn,
155 curl_off_t filesize);
157 /* easy-to-use macro: */
158 #define FTPSENDF(x,y,z) if((result = Curl_ftpsendf(x,y,z)) != CURLE_OK) \
160 #define PPSENDF(x,y,z) if((result = Curl_pp_sendf(x,y,z)) != CURLE_OK) \
165 * FTP protocol handler.
168 const struct Curl_handler Curl_handler_ftp = {
170 ftp_setup_connection, /* setup_connection */
173 ftp_nextconnect, /* do_more */
174 ftp_connect, /* connect_it */
175 ftp_multi_statemach, /* connecting */
176 ftp_doing, /* doing */
177 ftp_getsock, /* proto_getsock */
178 ftp_getsock, /* doing_getsock */
179 ZERO_NULL, /* perform_getsock */
180 ftp_disconnect, /* disconnect */
181 PORT_FTP, /* defport */
182 CURLPROTO_FTP, /* protocol */
183 PROTOPT_DUAL | PROTOPT_CLOSEACTION /* flags */
189 * FTPS protocol handler.
192 const struct Curl_handler Curl_handler_ftps = {
194 ftp_setup_connection, /* setup_connection */
197 ftp_nextconnect, /* do_more */
198 ftp_connect, /* connect_it */
199 ftp_multi_statemach, /* connecting */
200 ftp_doing, /* doing */
201 ftp_getsock, /* proto_getsock */
202 ftp_getsock, /* doing_getsock */
203 ZERO_NULL, /* perform_getsock */
204 ftp_disconnect, /* disconnect */
205 PORT_FTPS, /* defport */
206 CURLPROTO_FTP | CURLPROTO_FTPS, /* protocol */
207 PROTOPT_SSL | PROTOPT_DUAL | PROTOPT_CLOSEACTION /* flags */
211 #ifndef CURL_DISABLE_HTTP
213 * HTTP-proxyed FTP protocol handler.
216 static const struct Curl_handler Curl_handler_ftp_proxy = {
218 ZERO_NULL, /* setup_connection */
219 Curl_http, /* do_it */
220 Curl_http_done, /* done */
221 ZERO_NULL, /* do_more */
222 ZERO_NULL, /* connect_it */
223 ZERO_NULL, /* connecting */
224 ZERO_NULL, /* doing */
225 ZERO_NULL, /* proto_getsock */
226 ZERO_NULL, /* doing_getsock */
227 ZERO_NULL, /* perform_getsock */
228 ZERO_NULL, /* disconnect */
229 PORT_FTP, /* defport */
230 CURLPROTO_HTTP, /* protocol */
231 PROTOPT_NONE /* flags */
237 * HTTP-proxyed FTPS protocol handler.
240 static const struct Curl_handler Curl_handler_ftps_proxy = {
242 ZERO_NULL, /* setup_connection */
243 Curl_http, /* do_it */
244 Curl_http_done, /* done */
245 ZERO_NULL, /* do_more */
246 ZERO_NULL, /* connect_it */
247 ZERO_NULL, /* connecting */
248 ZERO_NULL, /* doing */
249 ZERO_NULL, /* proto_getsock */
250 ZERO_NULL, /* doing_getsock */
251 ZERO_NULL, /* perform_getsock */
252 ZERO_NULL, /* disconnect */
253 PORT_FTPS, /* defport */
254 CURLPROTO_HTTP, /* protocol */
255 PROTOPT_NONE /* flags */
262 * NOTE: back in the old days, we added code in the FTP code that made NOBODY
263 * requests on files respond with headers passed to the client/stdout that
264 * looked like HTTP ones.
266 * This approach is not very elegant, it causes confusion and is error-prone.
267 * It is subject for removal at the next (or at least a future) soname bump.
268 * Until then you can test the effects of the removal by undefining the
269 * following define named CURL_FTP_HTTPSTYLE_HEAD.
271 #define CURL_FTP_HTTPSTYLE_HEAD 1
273 static void freedirs(struct ftp_conn *ftpc)
277 for(i=0; i < ftpc->dirdepth; i++){
293 /* Returns non-zero if the given string contains CR (\r) or LF (\n),
294 which are not allowed within RFC 959 <string>.
295 Note: The input string is in the client's encoding which might
296 not be ASCII, so escape sequences \r & \n must be used instead
297 of hex values 0x0d & 0x0a.
299 static bool isBadFtpString(const char *string)
301 return (bool)((NULL != strchr(string, '\r')) ||
302 (NULL != strchr(string, '\n')));
305 /***********************************************************************
307 * AllowServerConnect()
309 * When we've issue the PORT command, we have told the server to connect
310 * to us. This function will sit and wait here until the server has
314 static CURLcode AllowServerConnect(struct connectdata *conn)
316 struct SessionHandle *data = conn->data;
317 curl_socket_t sock = conn->sock[SECONDARYSOCKET];
320 curl_socket_t s = CURL_SOCKET_BAD;
322 struct Curl_sockaddr_storage add;
324 struct sockaddr_in add;
326 curl_socklen_t size = (curl_socklen_t) sizeof(add);
329 timeout_ms = Curl_timeleft(data, NULL, TRUE);
332 /* if a timeout was already reached, bail out */
333 failf(data, "Timeout while waiting for server connect");
334 return CURLE_OPERATION_TIMEDOUT;
337 interval_ms = 1000; /* use 1 second timeout intervals */
338 if(timeout_ms < interval_ms)
339 interval_ms = timeout_ms;
341 switch (Curl_socket_ready(sock, CURL_SOCKET_BAD, (int)interval_ms)) {
344 failf(data, "Error while waiting for server connect");
345 return CURLE_FTP_PORT_FAILED;
346 case 0: /* timeout */
349 /* we have received data here */
350 if(0 == getsockname(sock, (struct sockaddr *) &add, &size)) {
353 s=accept(sock, (struct sockaddr *) &add, &size);
355 sclose(sock); /* close the first socket */
357 if(CURL_SOCKET_BAD == s) {
358 failf(data, "Error accept()ing server connect");
359 return CURLE_FTP_PORT_FAILED;
361 infof(data, "Connection accepted from server\n");
363 conn->sock[SECONDARYSOCKET] = s;
364 curlx_nonblock(s, TRUE); /* enable non-blocking */
368 /* never reaches this point */
371 /* macro to check for a three-digit ftp status code at the start of the
373 #define STATUSCODE(line) (ISDIGIT(line[0]) && ISDIGIT(line[1]) && \
376 /* macro to check for the last line in an FTP server response */
377 #define LASTLINE(line) (STATUSCODE(line) && (' ' == line[3]))
379 static int ftp_endofresp(struct pingpong *pp,
382 char *line = pp->linestart_resp;
383 size_t len = pp->nread_resp;
385 if((len > 3) && LASTLINE(line)) {
386 *code = curlx_sltosi(strtol(line, NULL, 10));
392 static CURLcode ftp_readresp(curl_socket_t sockfd,
394 int *ftpcode, /* return the ftp-code if done */
395 size_t *size) /* size of the response */
397 struct connectdata *conn = pp->conn;
398 #if defined(HAVE_KRB4) || defined(HAVE_GSSAPI)
399 struct SessionHandle *data = conn->data;
400 char * const buf = data->state.buffer;
402 CURLcode result = CURLE_OK;
405 result = Curl_pp_readresp(sockfd, pp, &code, size);
407 #if defined(HAVE_KRB4) || defined(HAVE_GSSAPI)
408 /* handle the security-oriented responses 6xx ***/
409 /* FIXME: some errorchecking perhaps... ***/
412 code = Curl_sec_read_msg(conn, buf, PROT_SAFE);
415 code = Curl_sec_read_msg(conn, buf, PROT_PRIVATE);
418 code = Curl_sec_read_msg(conn, buf, PROT_CONFIDENTIAL);
421 /* normal ftp stuff we pass through! */
426 /* store the latest code for later retrieval */
427 conn->data->info.httpcode=code;
433 /* 421 means "Service not available, closing control connection." and FTP
434 * servers use it to signal that idle session timeout has been exceeded.
435 * If we ignored the response, it could end up hanging in some cases. */
436 return CURLE_OPERATION_TIMEDOUT;
441 /* --- parse FTP server responses --- */
444 * Curl_GetFTPResponse() is a BLOCKING function to read the full response
445 * from a server after a command.
449 CURLcode Curl_GetFTPResponse(ssize_t *nreadp, /* return number of bytes read */
450 struct connectdata *conn,
451 int *ftpcode) /* return the ftp-code */
454 * We cannot read just one byte per read() and then go back to select() as
455 * the OpenSSL read() doesn't grok that properly.
457 * Alas, read as much as possible, split up into lines, use the ending
458 * line in a response or continue reading. */
460 curl_socket_t sockfd = conn->sock[FIRSTSOCKET];
461 long timeout; /* timeout in milliseconds */
463 struct SessionHandle *data = conn->data;
464 CURLcode result = CURLE_OK;
465 struct ftp_conn *ftpc = &conn->proto.ftpc;
466 struct pingpong *pp = &ftpc->pp;
469 int value_to_be_ignored=0;
472 *ftpcode = 0; /* 0 for errors */
474 /* make the pointer point to something for the rest of this function */
475 ftpcode = &value_to_be_ignored;
479 while(!*ftpcode && !result) {
480 /* check and reset timeout value every lap */
481 timeout = Curl_pp_state_timeout(pp);
484 failf(data, "FTP response timeout");
485 return CURLE_OPERATION_TIMEDOUT; /* already too little time */
488 interval_ms = 1000; /* use 1 second timeout intervals */
489 if(timeout < interval_ms)
490 interval_ms = timeout;
493 * Since this function is blocking, we need to wait here for input on the
494 * connection and only then we call the response reading function. We do
495 * timeout at least every second to make the timeout check run.
497 * A caution here is that the ftp_readresp() function has a cache that may
498 * contain pieces of a response from the previous invoke and we need to
499 * make sure we don't just wait for input while there is unhandled data in
500 * that cache. But also, if the cache is there, we call ftp_readresp() and
501 * the cache wasn't good enough to continue we must not just busy-loop
502 * around this function.
506 if(pp->cache && (cache_skip < 2)) {
508 * There's a cache left since before. We then skipping the wait for
509 * socket action, unless this is the same cache like the previous round
510 * as then the cache was deemed not enough to act on and we then need to
511 * wait for more data anyway.
515 switch (Curl_socket_ready(sockfd, CURL_SOCKET_BAD, (int)interval_ms)) {
516 case -1: /* select() error, stop reading */
517 failf(data, "FTP response aborted due to select/poll error: %d",
519 return CURLE_RECV_ERROR;
521 case 0: /* timeout */
522 if(Curl_pgrsUpdate(conn))
523 return CURLE_ABORTED_BY_CALLBACK;
524 continue; /* just continue in our loop for the timeout duration */
526 default: /* for clarity */
530 result = ftp_readresp(sockfd, pp, ftpcode, &nread);
534 if(!nread && pp->cache)
535 /* bump cache skip counter as on repeated skips we must wait for more
539 /* when we got data or there is no cache left, we reset the cache skip
545 } /* while there's buffer left and loop is requested */
547 pp->pending_resp = FALSE;
552 /* This is the ONLY way to change FTP state! */
553 static void state(struct connectdata *conn,
556 #if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
557 /* for debug purposes */
558 static const char * const names[]={
596 struct ftp_conn *ftpc = &conn->proto.ftpc;
597 #if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
598 if(ftpc->state != newstate)
599 infof(conn->data, "FTP %p state change from %s to %s\n",
600 ftpc, names[ftpc->state], names[newstate]);
602 ftpc->state = newstate;
605 static CURLcode ftp_state_user(struct connectdata *conn)
608 struct FTP *ftp = conn->data->state.proto.ftp;
610 PPSENDF(&conn->proto.ftpc.pp, "USER %s", ftp->user?ftp->user:"");
612 state(conn, FTP_USER);
613 conn->data->state.ftp_trying_alternative = FALSE;
618 static CURLcode ftp_state_pwd(struct connectdata *conn)
622 /* send PWD to discover our entry point */
623 PPSENDF(&conn->proto.ftpc.pp, "PWD", NULL);
624 state(conn, FTP_PWD);
629 /* For the FTP "protocol connect" and "doing" phases only */
630 static int ftp_getsock(struct connectdata *conn,
631 curl_socket_t *socks,
634 return Curl_pp_getsock(&conn->proto.ftpc.pp, socks, numsocks);
637 /* This is called after the FTP_QUOTE state is passed.
639 ftp_state_cwd() sends the range of CWD commands to the server to change to
640 the correct directory. It may also need to send MKD commands to create
641 missing ones, if that option is enabled.
643 static CURLcode ftp_state_cwd(struct connectdata *conn)
645 CURLcode result = CURLE_OK;
646 struct ftp_conn *ftpc = &conn->proto.ftpc;
649 /* already done and fine */
650 result = ftp_state_post_cwd(conn);
652 ftpc->count2 = 0; /* count2 counts failed CWDs */
654 /* count3 is set to allow a MKD to fail once. In the case when first CWD
655 fails and then MKD fails (due to another session raced it to create the
656 dir) this then allows for a second try to CWD to it */
657 ftpc->count3 = (conn->data->set.ftp_create_missing_dirs==2)?1:0;
659 if(conn->bits.reuse && ftpc->entrypath) {
660 /* This is a re-used connection. Since we change directory to where the
661 transfer is taking place, we must first get back to the original dir
662 where we ended up after login: */
663 ftpc->count1 = 0; /* we count this as the first path, then we add one
664 for all upcoming ones in the ftp->dirs[] array */
665 PPSENDF(&conn->proto.ftpc.pp, "CWD %s", ftpc->entrypath);
666 state(conn, FTP_CWD);
671 /* issue the first CWD, the rest is sent when the CWD responses are
673 PPSENDF(&conn->proto.ftpc.pp, "CWD %s", ftpc->dirs[ftpc->count1 -1]);
674 state(conn, FTP_CWD);
677 /* No CWD necessary */
678 result = ftp_state_post_cwd(conn);
691 static CURLcode ftp_state_use_port(struct connectdata *conn,
692 ftpport fcmd) /* start with this */
695 CURLcode result = CURLE_OK;
696 struct ftp_conn *ftpc = &conn->proto.ftpc;
697 struct SessionHandle *data=conn->data;
698 curl_socket_t portsock= CURL_SOCKET_BAD;
699 char myhost[256] = "";
701 struct Curl_sockaddr_storage ss;
702 Curl_addrinfo *res, *ai;
703 curl_socklen_t sslen;
704 char hbuf[NI_MAXHOST];
705 struct sockaddr *sa=(struct sockaddr *)&ss;
706 struct sockaddr_in * const sa4 = (void *)sa;
708 struct sockaddr_in6 * const sa6 = (void *)sa;
711 static const char mode[][5] = { "EPRT", "PORT" };
715 char *string_ftpport = data->set.str[STRING_FTPPORT];
716 struct Curl_dns_entry *h=NULL;
717 unsigned short port_min = 0;
718 unsigned short port_max = 0;
723 /* Step 1, figure out what is requested,
725 * (ipv4|ipv6|domain|interface)?(:port(-range)?)?
728 if(data->set.str[STRING_FTPPORT] &&
729 (strlen(data->set.str[STRING_FTPPORT]) > 1)) {
732 size_t addrlen = INET6_ADDRSTRLEN > strlen(string_ftpport) ?
733 INET6_ADDRSTRLEN : strlen(string_ftpport);
735 size_t addrlen = INET_ADDRSTRLEN > strlen(string_ftpport) ?
736 INET_ADDRSTRLEN : strlen(string_ftpport);
738 char *ip_start = string_ftpport;
740 char *port_start = NULL;
741 char *port_sep = NULL;
743 addr = calloc(addrlen+1, 1);
745 return CURLE_OUT_OF_MEMORY;
748 if(*string_ftpport == '[') {
749 /* [ipv6]:port(-range) */
750 ip_start = string_ftpport + 1;
751 if((ip_end = strchr(string_ftpport, ']')) != NULL )
752 strncpy(addr, ip_start, ip_end - ip_start);
756 if( *string_ftpport == ':') {
758 ip_end = string_ftpport;
760 else if( (ip_end = strchr(string_ftpport, ':')) != NULL) {
761 /* either ipv6 or (ipv4|domain|interface):port(-range) */
763 if(Curl_inet_pton(AF_INET6, string_ftpport, sa6) == 1) {
765 port_min = port_max = 0;
766 strcpy(addr, string_ftpport);
767 ip_end = NULL; /* this got no port ! */
771 /* (ipv4|domain|interface):port(-range) */
772 strncpy(addr, string_ftpport, ip_end - ip_start );
776 strcpy(addr, string_ftpport);
779 if( ip_end != NULL ) {
780 if((port_start = strchr(ip_end, ':')) != NULL) {
781 port_min = curlx_ultous(strtoul(port_start+1, NULL, 10));
782 if((port_sep = strchr(port_start, '-')) != NULL) {
783 port_max = curlx_ultous(strtoul(port_sep + 1, NULL, 10));
790 /* correct errors like:
792 * :-4711 , in this case port_min is (unsigned)-1,
793 * therefore port_min > port_max for all cases
794 * but port_max = (unsigned)-1
796 if(port_min > port_max )
797 port_min = port_max = 0;
801 /* attempt to get the address of the given interface name */
802 if(!Curl_if2ip(conn->ip_addr->ai_family, addr,
804 /* not an interface, use the given string as host name instead */
807 host = hbuf; /* use the hbuf for host name */
809 /* there was only a port(-range) given, default the host */
811 } /* data->set.ftpport */
814 /* not an interface and not a host name, get default by extracting
815 the IP from the control connection */
818 if(getsockname(conn->sock[FIRSTSOCKET], sa, &sslen)) {
819 failf(data, "getsockname() failed: %s",
820 Curl_strerror(conn, SOCKERRNO) );
823 return CURLE_FTP_PORT_FAILED;
825 switch(sa->sa_family) {
828 Curl_inet_ntop(sa->sa_family, &sa6->sin6_addr, hbuf, sizeof(hbuf));
832 Curl_inet_ntop(sa->sa_family, &sa4->sin_addr, hbuf, sizeof(hbuf));
835 host = hbuf; /* use this host name */
838 /* resolv ip/host to ip */
839 rc = Curl_resolv(conn, host, 0, &h);
840 if(rc == CURLRESOLV_PENDING)
841 (void)Curl_resolver_wait_resolv(conn, &h);
844 /* when we return from this function, we can forget about this entry
845 to we can unlock it now already */
846 Curl_resolv_unlock(data, h);
849 res = NULL; /* failure! */
855 failf(data, "Curl_resolv failed, we can not recover!");
856 return CURLE_FTP_PORT_FAILED;
859 /* step 2, create a socket for the requested address */
861 portsock = CURL_SOCKET_BAD;
863 for(ai = res; ai; ai = ai->ai_next) {
865 * Workaround for AIX5 getaddrinfo() problem (it doesn't set ai_socktype):
867 if(ai->ai_socktype == 0)
868 ai->ai_socktype = conn->socktype;
870 portsock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
871 if(portsock == CURL_SOCKET_BAD) {
878 failf(data, "socket failure: %s", Curl_strerror(conn, error));
879 return CURLE_FTP_PORT_FAILED;
882 /* step 3, bind to a suitable local address */
884 memcpy(sa, ai->ai_addr, ai->ai_addrlen);
885 sslen = ai->ai_addrlen;
887 for( port = port_min; port <= port_max; ) {
888 if( sa->sa_family == AF_INET )
889 sa4->sin_port = htons(port);
892 sa6->sin6_port = htons(port);
894 /* Try binding the given address. */
895 if(bind(portsock, sa, sslen) ) {
898 if(error == EADDRNOTAVAIL) {
900 /* The requested bind address is not local. Use the address used for
901 * the control connection instead and restart the port loop
903 failf(data, "bind(port=%hu) failed: %s", port,
904 Curl_strerror(conn, error) );
907 if(getsockname(conn->sock[FIRSTSOCKET], sa, &sslen)) {
908 failf(data, "getsockname() failed: %s",
909 Curl_strerror(conn, SOCKERRNO) );
911 return CURLE_FTP_PORT_FAILED;
916 else if(error != EADDRINUSE && error != EACCES) {
917 failf(data, "bind(port=%hu) failed: %s", port,
918 Curl_strerror(conn, error) );
920 return CURLE_FTP_PORT_FAILED;
929 /* maybe all ports were in use already*/
930 if(port > port_max) {
931 failf(data, "bind() failed, we ran out of ports!");
933 return CURLE_FTP_PORT_FAILED;
936 /* get the name again after the bind() so that we can extract the
937 port number it uses now */
939 if(getsockname(portsock, (struct sockaddr *)sa, &sslen)) {
940 failf(data, "getsockname() failed: %s",
941 Curl_strerror(conn, SOCKERRNO) );
943 return CURLE_FTP_PORT_FAILED;
946 /* step 4, listen on the socket */
948 if(listen(portsock, 1)) {
949 failf(data, "socket failure: %s", Curl_strerror(conn, SOCKERRNO));
951 return CURLE_FTP_PORT_FAILED;
954 /* step 5, send the proper FTP command */
956 /* get a plain printable version of the numerical address to work with
958 Curl_printable_address(ai, myhost, sizeof(myhost));
961 if(!conn->bits.ftp_use_eprt && conn->bits.ipv6)
962 /* EPRT is disabled but we are connected to a IPv6 host, so we ignore the
963 request and enable EPRT again! */
964 conn->bits.ftp_use_eprt = TRUE;
967 for(; fcmd != DONE; fcmd++) {
969 if(!conn->bits.ftp_use_eprt && (EPRT == fcmd))
970 /* if disabled, goto next */
973 if((PORT == fcmd) && sa->sa_family != AF_INET)
974 /* PORT is ipv4 only */
977 switch (sa->sa_family) {
979 port = ntohs(sa4->sin_port);
983 port = ntohs(sa6->sin6_port);
987 continue; /* might as well skip this */
992 * Two fine examples from RFC2428;
994 * EPRT |1|132.235.1.2|6275|
996 * EPRT |2|1080::8:800:200C:417A|5282|
999 result = Curl_pp_sendf(&ftpc->pp, "%s |%d|%s|%hu|", mode[fcmd],
1000 sa->sa_family == AF_INET?1:2,
1006 else if(PORT == fcmd) {
1007 char *source = myhost;
1010 /* translate x.x.x.x to x,x,x,x */
1011 while(source && *source) {
1020 snprintf(dest, 20, ",%d,%d", (int)(port>>8), (int)(port&0xff));
1022 result = Curl_pp_sendf(&ftpc->pp, "%s %s", mode[fcmd], tmp);
1029 /* store which command was sent */
1030 ftpc->count1 = fcmd;
1032 /* we set the secondary socket variable to this for now, it is only so that
1033 the cleanup function will close it in case we fail before the true
1034 secondary stuff is made */
1035 if(CURL_SOCKET_BAD != conn->sock[SECONDARYSOCKET])
1036 sclose(conn->sock[SECONDARYSOCKET]);
1037 conn->sock[SECONDARYSOCKET] = portsock;
1039 /* this tcpconnect assignment below is a hackish work-around to make the
1040 multi interface with active FTP work - as it will not wait for a
1041 (passive) connect in Curl_is_connected().
1043 The *proper* fix is to make sure that the active connection from the
1044 server is done in a non-blocking way. Currently, it is still BLOCKING.
1046 conn->bits.tcpconnect = TRUE;
1048 state(conn, FTP_PORT);
1052 static CURLcode ftp_state_use_pasv(struct connectdata *conn)
1054 struct ftp_conn *ftpc = &conn->proto.ftpc;
1055 CURLcode result = CURLE_OK;
1057 Here's the excecutive summary on what to do:
1059 PASV is RFC959, expect:
1060 227 Entering Passive Mode (a1,a2,a3,a4,p1,p2)
1062 LPSV is RFC1639, expect:
1063 228 Entering Long Passive Mode (4,4,a1,a2,a3,a4,2,p1,p2)
1065 EPSV is RFC2428, expect:
1066 229 Entering Extended Passive Mode (|||port|)
1070 static const char mode[][5] = { "EPSV", "PASV" };
1074 if(!conn->bits.ftp_use_epsv && conn->bits.ipv6)
1075 /* EPSV is disabled but we are connected to a IPv6 host, so we ignore the
1076 request and enable EPSV again! */
1077 conn->bits.ftp_use_epsv = TRUE;
1080 modeoff = conn->bits.ftp_use_epsv?0:1;
1082 PPSENDF(&ftpc->pp, "%s", mode[modeoff]);
1084 ftpc->count1 = modeoff;
1085 state(conn, FTP_PASV);
1086 infof(conn->data, "Connect data stream passively\n");
1091 /* REST is the last command in the chain of commands when a "head"-like
1092 request is made. Thus, if an actual transfer is to be made this is where
1093 we take off for real. */
1094 static CURLcode ftp_state_post_rest(struct connectdata *conn)
1096 CURLcode result = CURLE_OK;
1097 struct FTP *ftp = conn->data->state.proto.ftp;
1098 struct SessionHandle *data = conn->data;
1100 if(ftp->transfer != FTPTRANSFER_BODY) {
1101 /* doesn't transfer any data */
1103 /* still possibly do PRE QUOTE jobs */
1104 state(conn, FTP_RETR_PREQUOTE);
1105 result = ftp_state_quote(conn, TRUE, FTP_RETR_PREQUOTE);
1107 else if(data->set.ftp_use_port) {
1108 /* We have chosen to use the PORT (or similar) command */
1109 result = ftp_state_use_port(conn, EPRT);
1112 /* We have chosen (this is default) to use the PASV (or similar) command */
1113 if(data->set.ftp_use_pret) {
1114 /* The user has requested that we send a PRET command
1115 to prepare the server for the upcoming PASV */
1116 if(!conn->proto.ftpc.file) {
1117 PPSENDF(&conn->proto.ftpc.pp, "PRET %s",
1118 data->set.str[STRING_CUSTOMREQUEST]?
1119 data->set.str[STRING_CUSTOMREQUEST]:
1120 (data->set.ftp_list_only?"NLST":"LIST"));
1122 else if(data->set.upload) {
1123 PPSENDF(&conn->proto.ftpc.pp, "PRET STOR %s", conn->proto.ftpc.file);
1126 PPSENDF(&conn->proto.ftpc.pp, "PRET RETR %s", conn->proto.ftpc.file);
1128 state(conn, FTP_PRET);
1131 result = ftp_state_use_pasv(conn);
1137 static CURLcode ftp_state_post_size(struct connectdata *conn)
1139 CURLcode result = CURLE_OK;
1140 struct FTP *ftp = conn->data->state.proto.ftp;
1141 struct ftp_conn *ftpc = &conn->proto.ftpc;
1143 if((ftp->transfer != FTPTRANSFER_BODY) && ftpc->file) {
1144 /* if a "head"-like request is being made (on a file) */
1146 /* Determine if server can respond to REST command and therefore
1147 whether it supports range */
1148 PPSENDF(&conn->proto.ftpc.pp, "REST %d", 0);
1150 state(conn, FTP_REST);
1153 result = ftp_state_post_rest(conn);
1158 static CURLcode ftp_state_post_type(struct connectdata *conn)
1160 CURLcode result = CURLE_OK;
1161 struct FTP *ftp = conn->data->state.proto.ftp;
1162 struct ftp_conn *ftpc = &conn->proto.ftpc;
1164 if((ftp->transfer == FTPTRANSFER_INFO) && ftpc->file) {
1165 /* if a "head"-like request is being made (on a file) */
1167 /* we know ftpc->file is a valid pointer to a file name */
1168 PPSENDF(&ftpc->pp, "SIZE %s", ftpc->file);
1170 state(conn, FTP_SIZE);
1173 result = ftp_state_post_size(conn);
1178 static CURLcode ftp_state_post_listtype(struct connectdata *conn)
1180 CURLcode result = CURLE_OK;
1181 struct SessionHandle *data = conn->data;
1183 /* If this output is to be machine-parsed, the NLST command might be better
1184 to use, since the LIST command output is not specified or standard in any
1185 way. It has turned out that the NLST list output is not the same on all
1186 servers either... */
1189 if FTPFILE_NOCWD was specified, we are currently in
1190 the user's home directory, so we should add the path
1191 as argument for the LIST / NLST / or custom command.
1192 Whether the server will support this, is uncertain.
1194 The other ftp_filemethods will CWD into dir/dir/ first and
1195 then just do LIST (in that case: nothing to do here)
1197 char *cmd,*lstArg,*slashPos;
1200 if((data->set.ftp_filemethod == FTPFILE_NOCWD) &&
1202 data->state.path[0] &&
1203 strchr(data->state.path,'/')) {
1205 lstArg = strdup(data->state.path);
1207 return CURLE_OUT_OF_MEMORY;
1209 /* Check if path does not end with /, as then we cut off the file part */
1210 if(lstArg[strlen(lstArg) - 1] != '/') {
1212 /* chop off the file part if format is dir/dir/file */
1213 slashPos = strrchr(lstArg,'/');
1215 *(slashPos+1) = '\0';
1219 cmd = aprintf( "%s%s%s",
1220 data->set.str[STRING_CUSTOMREQUEST]?
1221 data->set.str[STRING_CUSTOMREQUEST]:
1222 (data->set.ftp_list_only?"NLST":"LIST"),
1224 lstArg? lstArg: "" );
1229 return CURLE_OUT_OF_MEMORY;
1232 PPSENDF(&conn->proto.ftpc.pp, "%s",cmd);
1239 state(conn, FTP_LIST);
1244 static CURLcode ftp_state_post_retrtype(struct connectdata *conn)
1246 CURLcode result = CURLE_OK;
1248 /* We've sent the TYPE, now we must send the list of prequote strings */
1250 result = ftp_state_quote(conn, TRUE, FTP_RETR_PREQUOTE);
1255 static CURLcode ftp_state_post_stortype(struct connectdata *conn)
1257 CURLcode result = CURLE_OK;
1259 /* We've sent the TYPE, now we must send the list of prequote strings */
1261 result = ftp_state_quote(conn, TRUE, FTP_STOR_PREQUOTE);
1266 static CURLcode ftp_state_post_mdtm(struct connectdata *conn)
1268 CURLcode result = CURLE_OK;
1269 struct FTP *ftp = conn->data->state.proto.ftp;
1270 struct SessionHandle *data = conn->data;
1271 struct ftp_conn *ftpc = &conn->proto.ftpc;
1273 /* If we have selected NOBODY and HEADER, it means that we only want file
1274 information. Which in FTP can't be much more than the file size and
1276 if(data->set.opt_no_body && ftpc->file &&
1277 ftp_need_type(conn, data->set.prefer_ascii)) {
1278 /* The SIZE command is _not_ RFC 959 specified, and therefor many servers
1279 may not support it! It is however the only way we have to get a file's
1282 ftp->transfer = FTPTRANSFER_INFO;
1283 /* this means no actual transfer will be made */
1285 /* Some servers return different sizes for different modes, and thus we
1286 must set the proper type before we check the size */
1287 result = ftp_nb_type(conn, data->set.prefer_ascii, FTP_TYPE);
1292 result = ftp_state_post_type(conn);
1297 /* This is called after the CWD commands have been done in the beginning of
1299 static CURLcode ftp_state_post_cwd(struct connectdata *conn)
1301 CURLcode result = CURLE_OK;
1302 struct SessionHandle *data = conn->data;
1303 struct ftp_conn *ftpc = &conn->proto.ftpc;
1305 /* Requested time of file or time-depended transfer? */
1306 if((data->set.get_filetime || data->set.timecondition) && ftpc->file) {
1308 /* we have requested to get the modified-time of the file, this is a white
1309 spot as the MDTM is not mentioned in RFC959 */
1310 PPSENDF(&ftpc->pp, "MDTM %s", ftpc->file);
1312 state(conn, FTP_MDTM);
1315 result = ftp_state_post_mdtm(conn);
1321 /* This is called after the TYPE and possible quote commands have been sent */
1322 static CURLcode ftp_state_ul_setup(struct connectdata *conn,
1325 CURLcode result = CURLE_OK;
1326 struct FTP *ftp = conn->data->state.proto.ftp;
1327 struct SessionHandle *data = conn->data;
1328 struct ftp_conn *ftpc = &conn->proto.ftpc;
1329 int seekerr = CURL_SEEKFUNC_OK;
1331 if((data->state.resume_from && !sizechecked) ||
1332 ((data->state.resume_from > 0) && sizechecked)) {
1333 /* we're about to continue the uploading of a file */
1334 /* 1. get already existing file's size. We use the SIZE command for this
1335 which may not exist in the server! The SIZE command is not in
1338 /* 2. This used to set REST. But since we can do append, we
1339 don't another ftp command. We just skip the source file
1340 offset and then we APPEND the rest on the file instead */
1342 /* 3. pass file-size number of bytes in the source file */
1343 /* 4. lower the infilesize counter */
1344 /* => transfer as usual */
1346 if(data->state.resume_from < 0 ) {
1347 /* Got no given size to start from, figure it out */
1348 PPSENDF(&ftpc->pp, "SIZE %s", ftpc->file);
1349 state(conn, FTP_STOR_SIZE);
1354 data->set.ftp_append = TRUE;
1356 /* Let's read off the proper amount of bytes from the input. */
1357 if(conn->seek_func) {
1358 seekerr = conn->seek_func(conn->seek_client, data->state.resume_from,
1362 if(seekerr != CURL_SEEKFUNC_OK) {
1363 if(seekerr != CURL_SEEKFUNC_CANTSEEK) {
1364 failf(data, "Could not seek stream");
1365 return CURLE_FTP_COULDNT_USE_REST;
1367 /* seekerr == CURL_SEEKFUNC_CANTSEEK (can't seek to offset) */
1369 curl_off_t passed=0;
1371 size_t readthisamountnow =
1372 (data->state.resume_from - passed > CURL_OFF_T_C(BUFSIZE)) ?
1373 BUFSIZE : curlx_sotouz(data->state.resume_from - passed);
1375 size_t actuallyread =
1376 conn->fread_func(data->state.buffer, 1, readthisamountnow,
1379 passed += actuallyread;
1380 if((actuallyread == 0) || (actuallyread > readthisamountnow)) {
1381 /* this checks for greater-than only to make sure that the
1382 CURL_READFUNC_ABORT return code still aborts */
1383 failf(data, "Failed to read data");
1384 return CURLE_FTP_COULDNT_USE_REST;
1386 } while(passed < data->state.resume_from);
1389 /* now, decrease the size of the read */
1390 if(data->set.infilesize>0) {
1391 data->set.infilesize -= data->state.resume_from;
1393 if(data->set.infilesize <= 0) {
1394 infof(data, "File already completely uploaded\n");
1396 /* no data to transfer */
1397 Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
1399 /* Set ->transfer so that we won't get any error in
1400 * ftp_done() because we didn't transfer anything! */
1401 ftp->transfer = FTPTRANSFER_NONE;
1403 state(conn, FTP_STOP);
1407 /* we've passed, proceed as normal */
1410 PPSENDF(&ftpc->pp, data->set.ftp_append?"APPE %s":"STOR %s",
1413 state(conn, FTP_STOR);
1418 static CURLcode ftp_state_quote(struct connectdata *conn,
1422 CURLcode result = CURLE_OK;
1423 struct SessionHandle *data = conn->data;
1424 struct FTP *ftp = data->state.proto.ftp;
1425 struct ftp_conn *ftpc = &conn->proto.ftpc;
1427 struct curl_slist *item;
1432 item = data->set.quote;
1434 case FTP_RETR_PREQUOTE:
1435 case FTP_STOR_PREQUOTE:
1436 item = data->set.prequote;
1439 item = data->set.postquote;
1445 * 'count1' to iterate over the commands to send
1446 * 'count2' to store wether to allow commands to fail
1457 /* Skip count1 items in the linked list */
1458 while((i< ftpc->count1) && item) {
1463 char *cmd = item->data;
1466 ftpc->count2 = 1; /* the sent command is allowed to fail */
1469 ftpc->count2 = 0; /* failure means cancel operation */
1471 PPSENDF(&ftpc->pp, "%s", cmd);
1472 state(conn, instate);
1478 /* No more quote to send, continue to ... */
1482 result = ftp_state_cwd(conn);
1484 case FTP_RETR_PREQUOTE:
1485 if(ftp->transfer != FTPTRANSFER_BODY)
1486 state(conn, FTP_STOP);
1488 if(ftpc->known_filesize != -1) {
1489 Curl_pgrsSetDownloadSize(data, ftpc->known_filesize);
1490 result = ftp_state_post_retr_size(conn, ftpc->known_filesize);
1493 PPSENDF(&ftpc->pp, "SIZE %s", ftpc->file);
1494 state(conn, FTP_RETR_SIZE);
1498 case FTP_STOR_PREQUOTE:
1499 result = ftp_state_ul_setup(conn, FALSE);
1509 static CURLcode ftp_state_pasv_resp(struct connectdata *conn,
1512 struct ftp_conn *ftpc = &conn->proto.ftpc;
1514 struct SessionHandle *data=conn->data;
1515 Curl_addrinfo *conninfo;
1516 struct Curl_dns_entry *addr=NULL;
1518 unsigned short connectport; /* the local port connect() should use! */
1519 unsigned short newport=0; /* remote port */
1522 /* newhost must be able to hold a full IP-style address in ASCII, which
1523 in the IPv6 case means 5*8-1 = 39 letters */
1524 #define NEWHOST_BUFSIZE 48
1525 char newhost[NEWHOST_BUFSIZE];
1526 char *str=&data->state.buffer[4]; /* start on the first letter */
1528 if((ftpc->count1 == 0) &&
1530 /* positive EPSV response */
1531 char *ptr = strchr(str, '(');
1536 if(5 == sscanf(ptr, "%c%c%c%u%c",
1542 const char sep1 = separator[0];
1545 /* The four separators should be identical, or else this is an oddly
1546 formatted reply and we bail out immediately. */
1547 for(i=1; i<4; i++) {
1548 if(separator[i] != sep1) {
1549 ptr=NULL; /* set to NULL to signal error */
1554 newport = (unsigned short)(num & 0xffff);
1556 if(conn->bits.tunnel_proxy ||
1557 data->set.proxytype == CURLPROXY_SOCKS5 ||
1558 data->set.proxytype == CURLPROXY_SOCKS5_HOSTNAME ||
1559 data->set.proxytype == CURLPROXY_SOCKS4 ||
1560 data->set.proxytype == CURLPROXY_SOCKS4A)
1561 /* proxy tunnel -> use other host info because ip_addr_str is the
1562 proxy address not the ftp host */
1563 snprintf(newhost, sizeof(newhost), "%s", conn->host.name);
1565 /* use the same IP we are already connected to */
1566 snprintf(newhost, NEWHOST_BUFSIZE, "%s", conn->ip_addr_str);
1573 failf(data, "Weirdly formatted EPSV reply");
1574 return CURLE_FTP_WEIRD_PASV_REPLY;
1577 else if((ftpc->count1 == 1) &&
1579 /* positive PASV response */
1584 * Scan for a sequence of six comma-separated numbers and use them as
1585 * IP+port indicators.
1587 * Found reply-strings include:
1588 * "227 Entering Passive Mode (127,0,0,1,4,51)"
1589 * "227 Data transfer will passively listen to 127,0,0,1,4,51"
1590 * "227 Entering passive mode. 127,0,0,1,4,51"
1593 if(6 == sscanf(str, "%d,%d,%d,%d,%d,%d",
1594 &ip[0], &ip[1], &ip[2], &ip[3],
1595 &port[0], &port[1]))
1601 failf(data, "Couldn't interpret the 227-response");
1602 return CURLE_FTP_WEIRD_227_FORMAT;
1605 /* we got OK from server */
1606 if(data->set.ftp_skip_ip) {
1607 /* told to ignore the remotely given IP but instead use the one we used
1608 for the control connection */
1609 infof(data, "Skips %d.%d.%d.%d for data connection, uses %s instead\n",
1610 ip[0], ip[1], ip[2], ip[3],
1612 if(conn->bits.tunnel_proxy ||
1613 data->set.proxytype == CURLPROXY_SOCKS5 ||
1614 data->set.proxytype == CURLPROXY_SOCKS5_HOSTNAME ||
1615 data->set.proxytype == CURLPROXY_SOCKS4 ||
1616 data->set.proxytype == CURLPROXY_SOCKS4A)
1617 /* proxy tunnel -> use other host info because ip_addr_str is the
1618 proxy address not the ftp host */
1619 snprintf(newhost, sizeof(newhost), "%s", conn->host.name);
1621 snprintf(newhost, sizeof(newhost), "%s", conn->ip_addr_str);
1624 snprintf(newhost, sizeof(newhost),
1625 "%d.%d.%d.%d", ip[0], ip[1], ip[2], ip[3]);
1626 newport = (unsigned short)(((port[0]<<8) + port[1]) & 0xffff);
1628 else if(ftpc->count1 == 0) {
1629 /* EPSV failed, move on to PASV */
1631 /* disable it for next transfer */
1632 conn->bits.ftp_use_epsv = FALSE;
1633 infof(data, "disabling EPSV usage\n");
1635 PPSENDF(&ftpc->pp, "PASV", NULL);
1637 /* remain in the FTP_PASV state */
1641 failf(data, "Bad PASV/EPSV response: %03d", ftpcode);
1642 return CURLE_FTP_WEIRD_PASV_REPLY;
1645 if(data->set.str[STRING_PROXY] && *data->set.str[STRING_PROXY]) {
1647 * This is a tunnel through a http proxy and we need to connect to the
1650 * We don't want to rely on a former host lookup that might've expired
1651 * now, instead we remake the lookup here and now!
1653 rc = Curl_resolv(conn, conn->proxy.name, (int)conn->port, &addr);
1654 if(rc == CURLRESOLV_PENDING)
1655 /* BLOCKING, ignores the return code but 'addr' will be NULL in
1657 (void)Curl_resolver_wait_resolv(conn, &addr);
1660 (unsigned short)conn->port; /* we connect to the proxy's port */
1663 failf(data, "Can't resolve proxy host %s:%hu",
1664 conn->proxy.name, connectport);
1665 return CURLE_FTP_CANT_GET_HOST;
1669 /* normal, direct, ftp connection */
1670 rc = Curl_resolv(conn, newhost, newport, &addr);
1671 if(rc == CURLRESOLV_PENDING)
1673 (void)Curl_resolver_wait_resolv(conn, &addr);
1675 connectport = newport; /* we connect to the remote port */
1678 failf(data, "Can't resolve new host %s:%hu", newhost, connectport);
1679 return CURLE_FTP_CANT_GET_HOST;
1683 result = Curl_connecthost(conn,
1685 &conn->sock[SECONDARYSOCKET],
1689 Curl_resolv_unlock(data, addr); /* we're done using this address */
1691 if(result && ftpc->count1 == 0 && ftpcode == 229) {
1692 infof(data, "got positive EPSV response, but can't connect. "
1693 "Disabling EPSV\n");
1694 /* disable it for next transfer */
1695 conn->bits.ftp_use_epsv = FALSE;
1696 data->state.errorbuf = FALSE; /* allow error message to get rewritten */
1697 PPSENDF(&ftpc->pp, "PASV", NULL);
1699 /* remain in the FTP_PASV state */
1706 conn->bits.tcpconnect = connected; /* simply TRUE or FALSE */
1709 * When this is used from the multi interface, this might've returned with
1710 * the 'connected' set to FALSE and thus we are now awaiting a non-blocking
1711 * connect to connect and we should not be "hanging" here waiting.
1714 if(data->set.verbose)
1715 /* this just dumps information about this second connection */
1716 ftp_pasv_verbose(conn, conninfo, newhost, connectport);
1718 switch(data->set.proxytype) {
1719 /* FIX: this MUST wait for a proper connect first if 'connected' is
1721 case CURLPROXY_SOCKS5:
1722 case CURLPROXY_SOCKS5_HOSTNAME:
1723 result = Curl_SOCKS5(conn->proxyuser, conn->proxypasswd, newhost, newport,
1724 SECONDARYSOCKET, conn);
1726 case CURLPROXY_SOCKS4:
1727 result = Curl_SOCKS4(conn->proxyuser, newhost, newport,
1728 SECONDARYSOCKET, conn, FALSE);
1730 case CURLPROXY_SOCKS4A:
1731 result = Curl_SOCKS4(conn->proxyuser, newhost, newport,
1732 SECONDARYSOCKET, conn, TRUE);
1734 case CURLPROXY_HTTP:
1735 case CURLPROXY_HTTP_1_0:
1736 /* do nothing here. handled later. */
1739 failf(data, "unknown proxytype option given");
1740 result = CURLE_COULDNT_CONNECT;
1744 if(conn->bits.tunnel_proxy && conn->bits.httpproxy) {
1745 /* FIX: this MUST wait for a proper connect first if 'connected' is
1749 /* We want "seamless" FTP operations through HTTP proxy tunnel */
1751 /* Curl_proxyCONNECT is based on a pointer to a struct HTTP at the member
1752 * conn->proto.http; we want FTP through HTTP and we have to change the
1753 * member temporarily for connecting to the HTTP proxy. After
1754 * Curl_proxyCONNECT we have to set back the member to the original struct
1757 struct HTTP http_proxy;
1758 struct FTP *ftp_save = data->state.proto.ftp;
1759 memset(&http_proxy, 0, sizeof(http_proxy));
1760 data->state.proto.http = &http_proxy;
1762 result = Curl_proxyCONNECT(conn, SECONDARYSOCKET, newhost, newport);
1764 data->state.proto.ftp = ftp_save;
1766 if(CURLE_OK != result)
1771 state(conn, FTP_STOP); /* this phase is completed */
1776 static CURLcode ftp_state_port_resp(struct connectdata *conn,
1779 struct SessionHandle *data = conn->data;
1780 struct ftp_conn *ftpc = &conn->proto.ftpc;
1781 ftpport fcmd = (ftpport)ftpc->count1;
1782 CURLcode result = CURLE_OK;
1784 if(ftpcode != 200) {
1785 /* the command failed */
1788 infof(data, "disabling EPRT usage\n");
1789 conn->bits.ftp_use_eprt = FALSE;
1794 failf(data, "Failed to do PORT");
1795 result = CURLE_FTP_PORT_FAILED;
1799 result = ftp_state_use_port(conn, fcmd);
1802 infof(data, "Connect data stream actively\n");
1803 state(conn, FTP_STOP); /* end of DO phase */
1809 static CURLcode ftp_state_mdtm_resp(struct connectdata *conn,
1812 CURLcode result = CURLE_OK;
1813 struct SessionHandle *data=conn->data;
1814 struct FTP *ftp = data->state.proto.ftp;
1815 struct ftp_conn *ftpc = &conn->proto.ftpc;
1820 /* we got a time. Format should be: "YYYYMMDDHHMMSS[.sss]" where the
1821 last .sss part is optional and means fractions of a second */
1822 int year, month, day, hour, minute, second;
1823 char *buf = data->state.buffer;
1824 if(6 == sscanf(buf+4, "%04d%02d%02d%02d%02d%02d",
1825 &year, &month, &day, &hour, &minute, &second)) {
1826 /* we have a time, reformat it */
1827 time_t secs=time(NULL);
1828 /* using the good old yacc/bison yuck */
1829 snprintf(buf, sizeof(conn->data->state.buffer),
1830 "%04d%02d%02d %02d:%02d:%02d GMT",
1831 year, month, day, hour, minute, second);
1832 /* now, convert this into a time() value: */
1833 data->info.filetime = (long)curl_getdate(buf, &secs);
1836 #ifdef CURL_FTP_HTTPSTYLE_HEAD
1837 /* If we asked for a time of the file and we actually got one as well,
1838 we "emulate" a HTTP-style header in our output. */
1840 if(data->set.opt_no_body &&
1842 data->set.get_filetime &&
1843 (data->info.filetime>=0) ) {
1844 time_t filetime = (time_t)data->info.filetime;
1846 const struct tm *tm = &buffer;
1848 result = Curl_gmtime(filetime, &buffer);
1852 /* format: "Tue, 15 Nov 1994 12:45:26" */
1853 snprintf(buf, BUFSIZE-1,
1854 "Last-Modified: %s, %02d %s %4d %02d:%02d:%02d GMT\r\n",
1855 Curl_wkday[tm->tm_wday?tm->tm_wday-1:6],
1857 Curl_month[tm->tm_mon],
1862 result = Curl_client_write(conn, CLIENTWRITE_BOTH, buf, 0);
1865 } /* end of a ridiculous amount of conditionals */
1870 infof(data, "unsupported MDTM reply format\n");
1872 case 550: /* "No such file or directory" */
1873 failf(data, "Given file does not exist");
1874 result = CURLE_FTP_COULDNT_RETR_FILE;
1878 if(data->set.timecondition) {
1879 if((data->info.filetime > 0) && (data->set.timevalue > 0)) {
1880 switch(data->set.timecondition) {
1881 case CURL_TIMECOND_IFMODSINCE:
1883 if(data->info.filetime <= data->set.timevalue) {
1884 infof(data, "The requested document is not new enough\n");
1885 ftp->transfer = FTPTRANSFER_NONE; /* mark to not transfer data */
1886 data->info.timecond = TRUE;
1887 state(conn, FTP_STOP);
1891 case CURL_TIMECOND_IFUNMODSINCE:
1892 if(data->info.filetime > data->set.timevalue) {
1893 infof(data, "The requested document is not old enough\n");
1894 ftp->transfer = FTPTRANSFER_NONE; /* mark to not transfer data */
1895 data->info.timecond = TRUE;
1896 state(conn, FTP_STOP);
1903 infof(data, "Skipping time comparison\n");
1908 result = ftp_state_post_mdtm(conn);
1913 static CURLcode ftp_state_type_resp(struct connectdata *conn,
1917 CURLcode result = CURLE_OK;
1918 struct SessionHandle *data=conn->data;
1920 if(ftpcode/100 != 2) {
1921 /* "sasserftpd" and "(u)r(x)bot ftpd" both responds with 226 after a
1922 successful 'TYPE I'. While that is not as RFC959 says, it is still a
1923 positive response code and we allow that. */
1924 failf(data, "Couldn't set desired mode");
1925 return CURLE_FTP_COULDNT_SET_TYPE;
1928 infof(data, "Got a %03d response code instead of the assumed 200\n",
1931 if(instate == FTP_TYPE)
1932 result = ftp_state_post_type(conn);
1933 else if(instate == FTP_LIST_TYPE)
1934 result = ftp_state_post_listtype(conn);
1935 else if(instate == FTP_RETR_TYPE)
1936 result = ftp_state_post_retrtype(conn);
1937 else if(instate == FTP_STOR_TYPE)
1938 result = ftp_state_post_stortype(conn);
1943 static CURLcode ftp_state_post_retr_size(struct connectdata *conn,
1944 curl_off_t filesize)
1946 CURLcode result = CURLE_OK;
1947 struct SessionHandle *data=conn->data;
1948 struct FTP *ftp = data->state.proto.ftp;
1949 struct ftp_conn *ftpc = &conn->proto.ftpc;
1951 if(data->set.max_filesize && (filesize > data->set.max_filesize)) {
1952 failf(data, "Maximum file size exceeded");
1953 return CURLE_FILESIZE_EXCEEDED;
1955 ftp->downloadsize = filesize;
1957 if(data->state.resume_from) {
1958 /* We always (attempt to) get the size of downloads, so it is done before
1959 this even when not doing resumes. */
1960 if(filesize == -1) {
1961 infof(data, "ftp server doesn't support SIZE\n");
1962 /* We couldn't get the size and therefore we can't know if there really
1963 is a part of the file left to get, although the server will just
1964 close the connection when we start the connection so it won't cause
1965 us any harm, just not make us exit as nicely. */
1968 /* We got a file size report, so we check that there actually is a
1969 part of the file left to get, or else we go home. */
1970 if(data->state.resume_from< 0) {
1971 /* We're supposed to download the last abs(from) bytes */
1972 if(filesize < -data->state.resume_from) {
1973 failf(data, "Offset (%" FORMAT_OFF_T
1974 ") was beyond file size (%" FORMAT_OFF_T ")",
1975 data->state.resume_from, filesize);
1976 return CURLE_BAD_DOWNLOAD_RESUME;
1978 /* convert to size to download */
1979 ftp->downloadsize = -data->state.resume_from;
1980 /* download from where? */
1981 data->state.resume_from = filesize - ftp->downloadsize;
1984 if(filesize < data->state.resume_from) {
1985 failf(data, "Offset (%" FORMAT_OFF_T
1986 ") was beyond file size (%" FORMAT_OFF_T ")",
1987 data->state.resume_from, filesize);
1988 return CURLE_BAD_DOWNLOAD_RESUME;
1990 /* Now store the number of bytes we are expected to download */
1991 ftp->downloadsize = filesize-data->state.resume_from;
1995 if(ftp->downloadsize == 0) {
1996 /* no data to transfer */
1997 Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
1998 infof(data, "File already completely downloaded\n");
2000 /* Set ->transfer so that we won't get any error in ftp_done()
2001 * because we didn't transfer the any file */
2002 ftp->transfer = FTPTRANSFER_NONE;
2003 state(conn, FTP_STOP);
2007 /* Set resume file transfer offset */
2008 infof(data, "Instructs server to resume from offset %" FORMAT_OFF_T
2009 "\n", data->state.resume_from);
2011 PPSENDF(&ftpc->pp, "REST %" FORMAT_OFF_T, data->state.resume_from);
2013 state(conn, FTP_RETR_REST);
2018 PPSENDF(&ftpc->pp, "RETR %s", ftpc->file);
2019 state(conn, FTP_RETR);
2025 static CURLcode ftp_state_size_resp(struct connectdata *conn,
2029 CURLcode result = CURLE_OK;
2030 struct SessionHandle *data=conn->data;
2031 curl_off_t filesize;
2032 char *buf = data->state.buffer;
2034 /* get the size from the ascii string: */
2035 filesize = (ftpcode == 213)?curlx_strtoofft(buf+4, NULL, 0):-1;
2037 if(instate == FTP_SIZE) {
2038 #ifdef CURL_FTP_HTTPSTYLE_HEAD
2039 if(-1 != filesize) {
2040 snprintf(buf, sizeof(data->state.buffer),
2041 "Content-Length: %" FORMAT_OFF_T "\r\n", filesize);
2042 result = Curl_client_write(conn, CLIENTWRITE_BOTH, buf, 0);
2047 Curl_pgrsSetDownloadSize(data, filesize);
2048 result = ftp_state_post_size(conn);
2050 else if(instate == FTP_RETR_SIZE) {
2051 Curl_pgrsSetDownloadSize(data, filesize);
2052 result = ftp_state_post_retr_size(conn, filesize);
2054 else if(instate == FTP_STOR_SIZE) {
2055 data->state.resume_from = filesize;
2056 result = ftp_state_ul_setup(conn, TRUE);
2062 static CURLcode ftp_state_rest_resp(struct connectdata *conn,
2066 CURLcode result = CURLE_OK;
2067 struct ftp_conn *ftpc = &conn->proto.ftpc;
2072 #ifdef CURL_FTP_HTTPSTYLE_HEAD
2073 if(ftpcode == 350) {
2074 char buffer[24]= { "Accept-ranges: bytes\r\n" };
2075 result = Curl_client_write(conn, CLIENTWRITE_BOTH, buffer, 0);
2080 result = ftp_state_post_rest(conn);
2084 if(ftpcode != 350) {
2085 failf(conn->data, "Couldn't use REST");
2086 result = CURLE_FTP_COULDNT_USE_REST;
2089 PPSENDF(&ftpc->pp, "RETR %s", ftpc->file);
2090 state(conn, FTP_RETR);
2098 static CURLcode ftp_state_stor_resp(struct connectdata *conn,
2101 CURLcode result = CURLE_OK;
2102 struct SessionHandle *data = conn->data;
2103 struct FTP *ftp = data->state.proto.ftp;
2106 failf(data, "Failed FTP upload: %0d", ftpcode);
2107 /* oops, we never close the sockets! */
2108 return CURLE_UPLOAD_FAILED;
2111 if(data->set.ftp_use_port) {
2113 /* PORT means we are now awaiting the server to connect to us. */
2114 result = AllowServerConnect(conn);
2119 if(conn->ssl[SECONDARYSOCKET].use) {
2120 /* since we only have a plaintext TCP connection here, we must now
2122 infof(data, "Doing the SSL/TLS handshake on the data stream\n");
2124 result = Curl_ssl_connect(conn, SECONDARYSOCKET);
2129 *(ftp->bytecountp)=0;
2131 /* When we know we're uploading a specified file, we can get the file
2132 size prior to the actual upload. */
2134 Curl_pgrsSetUploadSize(data, data->set.infilesize);
2136 /* set the SO_SNDBUF for the secondary socket for those who need it */
2137 Curl_sndbufset(conn->sock[SECONDARYSOCKET]);
2139 Curl_setup_transfer(conn, -1, -1, FALSE, NULL, /* no download */
2140 SECONDARYSOCKET, ftp->bytecountp);
2141 state(conn, FTP_STOP);
2143 conn->proto.ftpc.pp.pending_resp = TRUE; /* expect a server response */
2148 /* for LIST and RETR responses */
2149 static CURLcode ftp_state_get_resp(struct connectdata *conn,
2153 CURLcode result = CURLE_OK;
2154 struct SessionHandle *data = conn->data;
2155 struct FTP *ftp = data->state.proto.ftp;
2156 char *buf = data->state.buffer;
2158 if((ftpcode == 150) || (ftpcode == 125)) {
2162 150 Opening BINARY mode data connection for /etc/passwd (2241
2163 bytes). (ok, the file is being transferred)
2166 150 Opening ASCII mode data connection for /bin/ls
2169 150 ASCII data connection for /bin/ls (137.167.104.91,37445) (0 bytes).
2172 150 Opening ASCII mode data connection for [file] (0.0.0.0,0) (545 bytes)
2175 125 Data connection already open; Transfer starting. */
2177 curl_off_t size=-1; /* default unknown size */
2181 * It appears that there are FTP-servers that return size 0 for files when
2182 * SIZE is used on the file while being in BINARY mode. To work around
2183 * that (stupid) behavior, we attempt to parse the RETR response even if
2184 * the SIZE returned size zero.
2186 * Debugging help from Salvatore Sorrentino on February 26, 2003.
2189 if((instate != FTP_LIST) &&
2190 !data->set.prefer_ascii &&
2191 (ftp->downloadsize < 1)) {
2193 * It seems directory listings either don't show the size or very
2194 * often uses size 0 anyway. ASCII transfers may very well turn out
2195 * that the transferred amount of data is not the same as this line
2196 * tells, why using this number in those cases only confuses us.
2198 * Example D above makes this parsing a little tricky */
2200 bytes=strstr(buf, " bytes");
2202 long in=(long)(bytes-buf);
2203 /* this is a hint there is size information in there! ;-) */
2205 /* scan for the left parenthesis and break there */
2208 /* skip only digits */
2209 if(!ISDIGIT(*bytes)) {
2213 /* one more estep backwards */
2216 /* if we have nothing but digits: */
2218 /* get the number! */
2219 size = curlx_strtoofft(bytes, NULL, 0);
2223 else if(ftp->downloadsize > -1)
2224 size = ftp->downloadsize;
2226 if(data->set.ftp_use_port) {
2228 result = AllowServerConnect(conn);
2233 if(conn->ssl[SECONDARYSOCKET].use) {
2234 /* since we only have a plaintext TCP connection here, we must now
2236 infof(data, "Doing the SSL/TLS handshake on the data stream\n");
2237 result = Curl_ssl_connect(conn, SECONDARYSOCKET);
2242 if(size > data->req.maxdownload && data->req.maxdownload > 0)
2243 size = data->req.size = data->req.maxdownload;
2244 else if((instate != FTP_LIST) && (data->set.prefer_ascii))
2245 size = -1; /* kludge for servers that understate ASCII mode file size */
2247 infof(data, "Maxdownload = %" FORMAT_OFF_T "\n", data->req.maxdownload);
2249 if(instate != FTP_LIST)
2250 infof(data, "Getting file with size: %" FORMAT_OFF_T "\n", size);
2253 Curl_setup_transfer(conn, SECONDARYSOCKET, size, FALSE,
2254 ftp->bytecountp, -1, NULL); /* no upload here */
2256 conn->proto.ftpc.pp.pending_resp = TRUE; /* expect server response */
2257 state(conn, FTP_STOP);
2260 if((instate == FTP_LIST) && (ftpcode == 450)) {
2261 /* simply no matching files in the dir listing */
2262 ftp->transfer = FTPTRANSFER_NONE; /* don't download anything */
2263 state(conn, FTP_STOP); /* this phase is over */
2266 failf(data, "RETR response: %03d", ftpcode);
2267 return instate == FTP_RETR && ftpcode == 550?
2268 CURLE_REMOTE_FILE_NOT_FOUND:
2269 CURLE_FTP_COULDNT_RETR_FILE;
2276 /* after USER, PASS and ACCT */
2277 static CURLcode ftp_state_loggedin(struct connectdata *conn)
2279 CURLcode result = CURLE_OK;
2282 if(conn->data->set.krb) {
2283 /* We may need to issue a KAUTH here to have access to the files
2284 * do it if user supplied a password
2286 if(conn->passwd && *conn->passwd) {
2288 result = Curl_krb_kauth(conn);
2294 if(conn->ssl[FIRSTSOCKET].use) {
2295 /* PBSZ = PROTECTION BUFFER SIZE.
2297 The 'draft-murray-auth-ftp-ssl' (draft 12, page 7) says:
2299 Specifically, the PROT command MUST be preceded by a PBSZ
2300 command and a PBSZ command MUST be preceded by a successful
2301 security data exchange (the TLS negotiation in this case)
2303 ... (and on page 8):
2305 Thus the PBSZ command must still be issued, but must have a
2306 parameter of '0' to indicate that no buffering is taking place
2307 and the data connection should not be encapsulated.
2309 PPSENDF(&conn->proto.ftpc.pp, "PBSZ %d", 0);
2310 state(conn, FTP_PBSZ);
2313 result = ftp_state_pwd(conn);
2318 /* for USER and PASS responses */
2319 static CURLcode ftp_state_user_resp(struct connectdata *conn,
2323 CURLcode result = CURLE_OK;
2324 struct SessionHandle *data = conn->data;
2325 struct FTP *ftp = data->state.proto.ftp;
2326 struct ftp_conn *ftpc = &conn->proto.ftpc;
2327 (void)instate; /* no use for this yet */
2329 /* some need password anyway, and others just return 2xx ignored */
2330 if((ftpcode == 331) && (ftpc->state == FTP_USER)) {
2331 /* 331 Password required for ...
2332 (the server requires to send the user's password too) */
2333 PPSENDF(&ftpc->pp, "PASS %s", ftp->passwd?ftp->passwd:"");
2334 state(conn, FTP_PASS);
2336 else if(ftpcode/100 == 2) {
2337 /* 230 User ... logged in.
2338 (the user logged in with or without password) */
2339 result = ftp_state_loggedin(conn);
2341 else if(ftpcode == 332) {
2342 if(data->set.str[STRING_FTP_ACCOUNT]) {
2343 PPSENDF(&ftpc->pp, "ACCT %s", data->set.str[STRING_FTP_ACCOUNT]);
2344 state(conn, FTP_ACCT);
2347 failf(data, "ACCT requested but none available");
2348 result = CURLE_LOGIN_DENIED;
2352 /* All other response codes, like:
2354 530 User ... access denied
2355 (the server denies to log the specified user) */
2357 if(conn->data->set.str[STRING_FTP_ALTERNATIVE_TO_USER] &&
2358 !conn->data->state.ftp_trying_alternative) {
2359 /* Ok, USER failed. Let's try the supplied command. */
2360 PPSENDF(&conn->proto.ftpc.pp, "%s",
2361 conn->data->set.str[STRING_FTP_ALTERNATIVE_TO_USER]);
2362 conn->data->state.ftp_trying_alternative = TRUE;
2363 state(conn, FTP_USER);
2367 failf(data, "Access denied: %03d", ftpcode);
2368 result = CURLE_LOGIN_DENIED;
2374 /* for ACCT response */
2375 static CURLcode ftp_state_acct_resp(struct connectdata *conn,
2378 CURLcode result = CURLE_OK;
2379 struct SessionHandle *data = conn->data;
2380 if(ftpcode != 230) {
2381 failf(data, "ACCT rejected by server: %03d", ftpcode);
2382 result = CURLE_FTP_WEIRD_PASS_REPLY; /* FIX */
2385 result = ftp_state_loggedin(conn);
2391 static CURLcode ftp_statemach_act(struct connectdata *conn)
2394 curl_socket_t sock = conn->sock[FIRSTSOCKET];
2395 struct SessionHandle *data=conn->data;
2397 struct ftp_conn *ftpc = &conn->proto.ftpc;
2398 struct pingpong *pp = &ftpc->pp;
2399 static const char ftpauth[][4] = { "SSL", "TLS" };
2403 return Curl_pp_flushsend(pp);
2405 /* we read a piece of response */
2406 result = ftp_readresp(sock, pp, &ftpcode, &nread);
2411 /* we have now received a full FTP server response */
2412 switch(ftpc->state) {
2414 if(ftpcode != 220) {
2415 failf(data, "Got a %03d ftp-server response when 220 was expected",
2417 return CURLE_FTP_WEIRD_SERVER_REPLY;
2420 /* We have received a 220 response fine, now we proceed. */
2421 #if defined(HAVE_KRB4) || defined(HAVE_GSSAPI)
2423 /* If not anonymous login, try a secure login. Note that this
2424 procedure is still BLOCKING. */
2426 Curl_sec_request_prot(conn, "private");
2427 /* We set private first as default, in case the line below fails to
2428 set a valid level */
2429 Curl_sec_request_prot(conn, data->set.str[STRING_KRB_LEVEL]);
2431 if(Curl_sec_login(conn) != CURLE_OK)
2432 infof(data, "Logging in with password in cleartext!\n");
2434 infof(data, "Authentication successful\n");
2438 if(data->set.ftp_ssl && !conn->ssl[FIRSTSOCKET].use) {
2439 /* We don't have a SSL/TLS connection yet, but FTPS is
2440 requested. Try a FTPS connection now */
2443 switch(data->set.ftpsslauth) {
2444 case CURLFTPAUTH_DEFAULT:
2445 case CURLFTPAUTH_SSL:
2446 ftpc->count2 = 1; /* add one to get next */
2449 case CURLFTPAUTH_TLS:
2450 ftpc->count2 = -1; /* subtract one to get next */
2454 failf(data, "unsupported parameter to CURLOPT_FTPSSLAUTH: %d",
2455 (int)data->set.ftpsslauth);
2456 return CURLE_UNKNOWN_OPTION; /* we don't know what to do */
2458 PPSENDF(&ftpc->pp, "AUTH %s", ftpauth[ftpc->count1]);
2459 state(conn, FTP_AUTH);
2462 result = ftp_state_user(conn);
2470 /* we have gotten the response to a previous AUTH command */
2472 /* RFC2228 (page 5) says:
2474 * If the server is willing to accept the named security mechanism,
2475 * and does not require any security data, it must respond with
2476 * reply code 234/334.
2479 if((ftpcode == 234) || (ftpcode == 334)) {
2480 /* Curl_ssl_connect is BLOCKING */
2481 result = Curl_ssl_connect(conn, FIRSTSOCKET);
2482 if(CURLE_OK == result) {
2483 conn->ssl[SECONDARYSOCKET].use = FALSE; /* clear-text data */
2484 result = ftp_state_user(conn);
2487 else if(ftpc->count3 < 1) {
2489 ftpc->count1 += ftpc->count2; /* get next attempt */
2490 result = Curl_pp_sendf(&ftpc->pp, "AUTH %s", ftpauth[ftpc->count1]);
2491 /* remain in this same state */
2494 if(data->set.ftp_ssl > CURLUSESSL_TRY)
2495 /* we failed and CURLUSESSL_CONTROL or CURLUSESSL_ALL is set */
2496 result = CURLE_USE_SSL_FAILED;
2498 /* ignore the failure and continue */
2499 result = ftp_state_user(conn);
2508 result = ftp_state_user_resp(conn, ftpcode, ftpc->state);
2512 result = ftp_state_acct_resp(conn, ftpcode);
2516 PPSENDF(&ftpc->pp, "PROT %c",
2517 data->set.ftp_ssl == CURLUSESSL_CONTROL ? 'C' : 'P');
2518 state(conn, FTP_PROT);
2523 if(ftpcode/100 == 2)
2524 /* We have enabled SSL for the data connection! */
2525 conn->ssl[SECONDARYSOCKET].use =
2526 (bool)(data->set.ftp_ssl != CURLUSESSL_CONTROL);
2527 /* FTP servers typically responds with 500 if they decide to reject
2529 else if(data->set.ftp_ssl > CURLUSESSL_CONTROL)
2530 /* we failed and bails out */
2531 return CURLE_USE_SSL_FAILED;
2533 if(data->set.ftp_ccc) {
2534 /* CCC - Clear Command Channel
2536 PPSENDF(&ftpc->pp, "CCC", NULL);
2537 state(conn, FTP_CCC);
2540 result = ftp_state_pwd(conn);
2548 /* First shut down the SSL layer (note: this call will block) */
2549 result = Curl_ssl_shutdown(conn, FIRSTSOCKET);
2552 failf(conn->data, "Failed to clear the command channel (CCC)");
2557 /* Then continue as normal */
2558 result = ftp_state_pwd(conn);
2564 if(ftpcode == 257) {
2565 char *ptr=&data->state.buffer[4]; /* start on the first letter */
2569 dir = malloc(nread + 1);
2571 return CURLE_OUT_OF_MEMORY;
2573 /* Reply format is like
2574 257<space>"<directory-name>"<space><commentary> and the RFC959
2577 The directory name can contain any character; embedded
2578 double-quotes should be escaped by double-quotes (the
2579 "quote-doubling" convention).
2582 /* it started good */
2584 for(store = dir; *ptr;) {
2586 if('\"' == ptr[1]) {
2587 /* "quote-doubling" */
2593 *store = '\0'; /* zero terminate */
2594 break; /* get out of this loop */
2603 free(ftpc->entrypath);
2604 ftpc->entrypath =dir; /* remember this */
2605 infof(data, "Entry path is '%s'\n", ftpc->entrypath);
2606 /* also save it where getinfo can access it: */
2607 data->state.most_recent_ftp_entrypath = ftpc->entrypath;
2609 /* If the path name does not look like an absolute path (i.e.: it
2610 does not start with a '/'), we probably need some server-dependent
2611 adjustments. For example, this is the case when connecting to
2612 an OS400 FTP server: this server supports two name syntaxes,
2613 the default one being incompatible with standard pathes. In
2614 addition, this server switches automatically to the regular path
2615 syntax when one is encountered in a command: this results in
2616 having an entrypath in the wrong syntax when later used in CWD.
2617 The method used here is to check the server OS: we do it only
2618 if the path name looks strange to minimize overhead on other
2621 if(!ftpc->server_os && ftpc->entrypath[0] != '/') {
2622 PPSENDF(&ftpc->pp, "SYST", NULL);
2623 state(conn, FTP_SYST);
2628 /* couldn't get the path */
2630 infof(data, "Failed to figure out path\n");
2633 state(conn, FTP_STOP); /* we are done with the CONNECT phase! */
2634 DEBUGF(infof(data, "protocol connect phase DONE\n"));
2638 if(ftpcode == 215) {
2639 char *ptr=&data->state.buffer[4]; /* start on the first letter */
2643 os = malloc(nread + 1);
2645 return CURLE_OUT_OF_MEMORY;
2647 /* Reply format is like
2648 215<space><OS-name><space><commentary>
2652 for(store = os; *ptr && *ptr != ' ';)
2654 *store = '\0'; /* zero terminate */
2655 ftpc->server_os = os;
2657 /* Check for special servers here. */
2659 if(strequal(ftpc->server_os, "OS/400")) {
2660 /* Force OS400 name format 1. */
2661 PPSENDF(&ftpc->pp, "SITE NAMEFMT 1", NULL);
2662 state(conn, FTP_NAMEFMT);
2666 /* Nothing special for the target server. */
2670 /* Cannot identify server OS. Continue anyway and cross fingers. */
2673 state(conn, FTP_STOP); /* we are done with the CONNECT phase! */
2674 DEBUGF(infof(data, "protocol connect phase DONE\n"));
2678 if(ftpcode == 250) {
2679 /* Name format change successful: reload initial path. */
2680 ftp_state_pwd(conn);
2684 state(conn, FTP_STOP); /* we are done with the CONNECT phase! */
2685 DEBUGF(infof(data, "protocol connect phase DONE\n"));
2690 case FTP_RETR_PREQUOTE:
2691 case FTP_STOR_PREQUOTE:
2692 if((ftpcode >= 400) && !ftpc->count2) {
2693 /* failure response code, and not allowed to fail */
2694 failf(conn->data, "QUOT command failed with %03d", ftpcode);
2695 return CURLE_QUOTE_ERROR;
2697 result = ftp_state_quote(conn, FALSE, ftpc->state);
2704 if(ftpcode/100 != 2) {
2705 /* failure to CWD there */
2706 if(conn->data->set.ftp_create_missing_dirs &&
2707 ftpc->count1 && !ftpc->count2) {
2709 ftpc->count2++; /* counter to prevent CWD-MKD loops */
2710 PPSENDF(&ftpc->pp, "MKD %s", ftpc->dirs[ftpc->count1 - 1]);
2711 state(conn, FTP_MKD);
2714 /* return failure */
2715 failf(data, "Server denied you to change to the given directory");
2716 ftpc->cwdfail = TRUE; /* don't remember this path as we failed
2718 return CURLE_REMOTE_ACCESS_DENIED;
2724 if(++ftpc->count1 <= ftpc->dirdepth) {
2726 PPSENDF(&ftpc->pp, "CWD %s", ftpc->dirs[ftpc->count1 - 1]);
2729 result = ftp_state_post_cwd(conn);
2737 if((ftpcode/100 != 2) && !ftpc->count3--) {
2738 /* failure to MKD the dir */
2739 failf(data, "Failed to MKD dir: %03d", ftpcode);
2740 return CURLE_REMOTE_ACCESS_DENIED;
2742 state(conn, FTP_CWD);
2744 PPSENDF(&ftpc->pp, "CWD %s", ftpc->dirs[ftpc->count1 - 1]);
2748 result = ftp_state_mdtm_resp(conn, ftpcode);
2755 result = ftp_state_type_resp(conn, ftpcode, ftpc->state);
2761 result = ftp_state_size_resp(conn, ftpcode, ftpc->state);
2766 result = ftp_state_rest_resp(conn, ftpcode, ftpc->state);
2770 if(ftpcode != 200) {
2771 /* there only is this one standard OK return code. */
2772 failf(data, "PRET command not accepted: %03d", ftpcode);
2773 return CURLE_FTP_PRET_FAILED;
2775 result = ftp_state_use_pasv(conn);
2779 result = ftp_state_pasv_resp(conn, ftpcode);
2783 result = ftp_state_port_resp(conn, ftpcode);
2788 result = ftp_state_get_resp(conn, ftpcode, ftpc->state);
2792 result = ftp_state_stor_resp(conn, ftpcode);
2796 /* fallthrough, just stop! */
2798 /* internal error */
2799 state(conn, FTP_STOP);
2808 /* called repeatedly until done from multi.c */
2809 static CURLcode ftp_multi_statemach(struct connectdata *conn,
2812 struct ftp_conn *ftpc = &conn->proto.ftpc;
2813 CURLcode result = Curl_pp_multi_statemach(&ftpc->pp);
2815 /* Check for the state outside of the Curl_socket_ready() return code checks
2816 since at times we are in fact already in this state when this function
2818 *done = (bool)(ftpc->state == FTP_STOP);
2823 static CURLcode ftp_easy_statemach(struct connectdata *conn)
2825 struct ftp_conn *ftpc = &conn->proto.ftpc;
2826 struct pingpong *pp = &ftpc->pp;
2827 CURLcode result = CURLE_OK;
2829 while(ftpc->state != FTP_STOP) {
2830 result = Curl_pp_easy_statemach(pp);
2839 * Allocate and initialize the struct FTP for the current SessionHandle. If
2843 #if defined(__INTEL_COMPILER) && (__INTEL_COMPILER == 910) && \
2844 defined(__OPTIMIZE__) && defined(__unix__) && defined(__i386__)
2845 /* workaround icc 9.1 optimizer issue */
2846 #pragma optimize("", off)
2849 static CURLcode ftp_init(struct connectdata *conn)
2853 if(NULL == conn->data->state.proto.ftp) {
2854 conn->data->state.proto.ftp = malloc(sizeof(struct FTP));
2855 if(NULL == conn->data->state.proto.ftp)
2856 return CURLE_OUT_OF_MEMORY;
2859 ftp = conn->data->state.proto.ftp;
2861 /* get some initial data into the ftp struct */
2862 ftp->bytecountp = &conn->data->req.bytecount;
2863 ftp->transfer = FTPTRANSFER_BODY;
2864 ftp->downloadsize = 0;
2866 /* No need to duplicate user+password, the connectdata struct won't change
2867 during a session, but we re-init them here since on subsequent inits
2868 since the conn struct may have changed or been replaced.
2870 ftp->user = conn->user;
2871 ftp->passwd = conn->passwd;
2872 if(TRUE == isBadFtpString(ftp->user))
2873 return CURLE_URL_MALFORMAT;
2874 if(TRUE == isBadFtpString(ftp->passwd))
2875 return CURLE_URL_MALFORMAT;
2877 conn->proto.ftpc.known_filesize = -1; /* unknown size for now */
2882 #if defined(__INTEL_COMPILER) && (__INTEL_COMPILER == 910) && \
2883 defined(__OPTIMIZE__) && defined(__unix__) && defined(__i386__)
2884 /* workaround icc 9.1 optimizer issue */
2885 #pragma optimize("", on)
2889 * ftp_connect() should do everything that is to be considered a part of
2890 * the connection phase.
2892 * The variable 'done' points to will be TRUE if the protocol-layer connect
2893 * phase is done when this function returns, or FALSE is not. When called as
2894 * a part of the easy interface, it will always be TRUE.
2896 static CURLcode ftp_connect(struct connectdata *conn,
2897 bool *done) /* see description above */
2900 struct ftp_conn *ftpc = &conn->proto.ftpc;
2901 struct SessionHandle *data=conn->data;
2902 struct pingpong *pp = &ftpc->pp;
2904 *done = FALSE; /* default to not done yet */
2906 /* If there already is a protocol-specific struct allocated for this
2907 sessionhandle, deal with it */
2908 Curl_reset_reqproto(conn);
2910 result = ftp_init(conn);
2911 if(CURLE_OK != result)
2914 /* We always support persistent connections on ftp */
2915 conn->bits.close = FALSE;
2917 pp->response_time = RESP_TIMEOUT; /* set default response time-out */
2918 pp->statemach_act = ftp_statemach_act;
2919 pp->endofresp = ftp_endofresp;
2922 if(conn->bits.tunnel_proxy && conn->bits.httpproxy) {
2923 /* for FTP over HTTP proxy */
2924 struct HTTP http_proxy;
2925 struct FTP *ftp_save;
2928 /* We want "seamless" FTP operations through HTTP proxy tunnel */
2930 /* Curl_proxyCONNECT is based on a pointer to a struct HTTP at the member
2931 * conn->proto.http; we want FTP through HTTP and we have to change the
2932 * member temporarily for connecting to the HTTP proxy. After
2933 * Curl_proxyCONNECT we have to set back the member to the original struct
2936 ftp_save = data->state.proto.ftp;
2937 memset(&http_proxy, 0, sizeof(http_proxy));
2938 data->state.proto.http = &http_proxy;
2940 result = Curl_proxyCONNECT(conn, FIRSTSOCKET,
2941 conn->host.name, conn->remote_port);
2943 data->state.proto.ftp = ftp_save;
2945 if(CURLE_OK != result)
2949 if(conn->handler->protocol & CURLPROTO_FTPS) {
2951 /* FTPS is simply ftp with SSL for the control channel */
2952 /* now, perform the SSL initialization for this socket */
2953 result = Curl_ssl_connect(conn, FIRSTSOCKET);
2958 Curl_pp_init(pp); /* init the generic pingpong data */
2960 /* When we connect, we start in the state where we await the 220
2962 state(conn, FTP_WAIT220);
2964 if(data->state.used_interface == Curl_if_multi)
2965 result = ftp_multi_statemach(conn, done);
2967 result = ftp_easy_statemach(conn);
2975 /***********************************************************************
2979 * The DONE function. This does what needs to be done after a single DO has
2982 * Input argument is already checked for validity.
2984 static CURLcode ftp_done(struct connectdata *conn, CURLcode status,
2987 struct SessionHandle *data = conn->data;
2988 struct FTP *ftp = data->state.proto.ftp;
2989 struct ftp_conn *ftpc = &conn->proto.ftpc;
2990 struct pingpong *pp = &ftpc->pp;
2993 CURLcode result=CURLE_OK;
2994 bool was_ctl_valid = ftpc->ctl_valid;
2996 const char *path_to_use = data->state.path;
2999 /* When the easy handle is removed from the multi while libcurl is still
3000 * trying to resolve the host name, it seems that the ftp struct is not
3001 * yet initialized, but the removal action calls Curl_done() which calls
3002 * this function. So we simply return success if no ftp pointer is set.
3007 case CURLE_BAD_DOWNLOAD_RESUME:
3008 case CURLE_FTP_WEIRD_PASV_REPLY:
3009 case CURLE_FTP_PORT_FAILED:
3010 case CURLE_FTP_COULDNT_SET_TYPE:
3011 case CURLE_FTP_COULDNT_RETR_FILE:
3012 case CURLE_UPLOAD_FAILED:
3013 case CURLE_REMOTE_ACCESS_DENIED:
3014 case CURLE_FILESIZE_EXCEEDED:
3015 case CURLE_REMOTE_FILE_NOT_FOUND:
3016 case CURLE_WRITE_ERROR:
3017 /* the connection stays alive fine even though this happened */
3019 case CURLE_OK: /* doesn't affect the control connection's status */
3021 ftpc->ctl_valid = was_ctl_valid;
3024 /* until we cope better with prematurely ended requests, let them
3025 * fallback as if in complete failure */
3026 default: /* by default, an error means the control connection is
3027 wedged and should not be used anymore */
3028 ftpc->ctl_valid = FALSE;
3029 ftpc->cwdfail = TRUE; /* set this TRUE to prevent us to remember the
3030 current path, as this connection is going */
3031 conn->bits.close = TRUE; /* marked for closure */
3032 result = status; /* use the already set error code */
3036 /* now store a copy of the directory we are in */
3038 free(ftpc->prevpath);
3040 if(data->set.wildcardmatch) {
3041 if(data->set.chunk_end && ftpc->file) {
3042 data->set.chunk_end(data->wildcard.customptr);
3044 ftpc->known_filesize = -1;
3047 /* get the "raw" path */
3048 path = curl_easy_unescape(data, path_to_use, 0, NULL);
3050 /* out of memory, but we can limp along anyway (and should try to
3051 * since we're in the out of memory cleanup path) */
3052 ftpc->prevpath = NULL; /* no path */
3055 size_t flen = ftpc->file?strlen(ftpc->file):0; /* file is "raw" already */
3056 size_t dlen = strlen(path)-flen;
3057 if(!ftpc->cwdfail) {
3058 if(dlen && (data->set.ftp_filemethod != FTPFILE_NOCWD)) {
3059 ftpc->prevpath = path;
3061 /* if 'path' is not the whole string */
3062 ftpc->prevpath[dlen]=0; /* terminate */
3065 /* we never changed dir */
3066 ftpc->prevpath=strdup("");
3070 infof(data, "Remembering we are in dir \"%s\"\n", ftpc->prevpath);
3073 ftpc->prevpath = NULL; /* no path */
3077 /* free the dir tree and file parts */
3080 /* shut down the socket to inform the server we're done */
3083 shutdown(conn->sock[SECONDARYSOCKET],2); /* SD_BOTH */
3086 if(conn->sock[SECONDARYSOCKET] != CURL_SOCKET_BAD) {
3087 if(!result && ftpc->dont_check && data->req.maxdownload > 0)
3088 /* partial download completed */
3089 result = Curl_pp_sendf(pp, "ABOR");
3091 if(conn->ssl[SECONDARYSOCKET].use) {
3092 /* The secondary socket is using SSL so we must close down that part
3093 first before we close the socket for real */
3094 Curl_ssl_close(conn, SECONDARYSOCKET);
3096 /* Note that we keep "use" set to TRUE since that (next) connection is
3097 still requested to use SSL */
3099 if(CURL_SOCKET_BAD != conn->sock[SECONDARYSOCKET]) {
3100 sclose(conn->sock[SECONDARYSOCKET]);
3101 conn->sock[SECONDARYSOCKET] = CURL_SOCKET_BAD;
3105 if(!result && (ftp->transfer == FTPTRANSFER_BODY) && ftpc->ctl_valid &&
3106 pp->pending_resp && !premature) {
3108 * Let's see what the server says about the transfer we just performed,
3109 * but lower the timeout as sometimes this connection has died while the
3110 * data has been transferred. This happens when doing through NATs etc that
3111 * abandon old silent connections.
3113 long old_time = pp->response_time;
3115 pp->response_time = 60*1000; /* give it only a minute for now */
3116 pp->response = Curl_tvnow(); /* timeout relative now */
3118 result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
3120 pp->response_time = old_time; /* set this back to previous value */
3122 if(!nread && (CURLE_OPERATION_TIMEDOUT == result)) {
3123 failf(data, "control connection looks dead");
3124 ftpc->ctl_valid = FALSE; /* mark control connection as bad */
3125 conn->bits.close = TRUE; /* mark for closure */
3131 if(ftpc->dont_check && data->req.maxdownload > 0) {
3132 /* we have just sent ABOR and there is no reliable way to check if it was
3133 * successful or not; we have to close the connection now */
3134 infof(data, "partial download completed, closing connection\n");
3135 conn->bits.close = TRUE; /* mark for closure */
3139 if(!ftpc->dont_check) {
3140 /* 226 Transfer complete, 250 Requested file action okay, completed. */
3141 if((ftpcode != 226) && (ftpcode != 250)) {
3142 failf(data, "server did not report OK, got %d", ftpcode);
3143 result = CURLE_PARTIAL_FILE;
3148 if(result || premature)
3149 /* the response code from the transfer showed an error already so no
3150 use checking further */
3152 else if(data->set.upload) {
3153 if((-1 != data->set.infilesize) &&
3154 (data->set.infilesize != *ftp->bytecountp) &&
3156 (ftp->transfer == FTPTRANSFER_BODY)) {
3157 failf(data, "Uploaded unaligned file size (%" FORMAT_OFF_T
3158 " out of %" FORMAT_OFF_T " bytes)",
3159 *ftp->bytecountp, data->set.infilesize);
3160 result = CURLE_PARTIAL_FILE;
3164 if((-1 != data->req.size) &&
3165 (data->req.size != *ftp->bytecountp) &&
3166 #ifdef CURL_DO_LINEEND_CONV
3167 /* Most FTP servers don't adjust their file SIZE response for CRLFs, so
3168 * we'll check to see if the discrepancy can be explained by the number
3169 * of CRLFs we've changed to LFs.
3171 ((data->req.size + data->state.crlf_conversions) !=
3172 *ftp->bytecountp) &&
3173 #endif /* CURL_DO_LINEEND_CONV */
3174 (data->req.maxdownload != *ftp->bytecountp)) {
3175 failf(data, "Received only partial file: %" FORMAT_OFF_T " bytes",
3177 result = CURLE_PARTIAL_FILE;
3179 else if(!ftpc->dont_check &&
3180 !*ftp->bytecountp &&
3181 (data->req.size>0)) {
3182 failf(data, "No data was received!");
3183 result = CURLE_FTP_COULDNT_RETR_FILE;
3187 /* clear these for next connection */
3188 ftp->transfer = FTPTRANSFER_BODY;
3189 ftpc->dont_check = FALSE;
3191 /* Send any post-transfer QUOTE strings? */
3192 if(!status && !result && !premature && data->set.postquote)
3193 result = ftp_sendquote(conn, data->set.postquote);
3198 /***********************************************************************
3202 * Where a 'quote' means a list of custom commands to send to the server.
3203 * The quote list is passed as an argument.
3209 CURLcode ftp_sendquote(struct connectdata *conn, struct curl_slist *quote)
3211 struct curl_slist *item;
3215 struct ftp_conn *ftpc = &conn->proto.ftpc;
3216 struct pingpong *pp = &ftpc->pp;
3221 char *cmd = item->data;
3222 bool acceptfail = FALSE;
3224 /* if a command starts with an asterisk, which a legal FTP command never
3225 can, the command will be allowed to fail without it causing any
3226 aborts or cancels etc. It will cause libcurl to act as if the command
3227 is successful, whatever the server reponds. */
3234 FTPSENDF(conn, "%s", cmd);
3236 pp->response = Curl_tvnow(); /* timeout relative now */
3238 result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
3242 if(!acceptfail && (ftpcode >= 400)) {
3243 failf(conn->data, "QUOT string not accepted: %s", cmd);
3244 return CURLE_QUOTE_ERROR;
3254 /***********************************************************************
3258 * Returns TRUE if we in the current situation should send TYPE
3260 static int ftp_need_type(struct connectdata *conn,
3263 return conn->proto.ftpc.transfertype != (ascii_wanted?'A':'I');
3266 /***********************************************************************
3270 * Set TYPE. We only deal with ASCII or BINARY so this function
3272 * If the transfer type is not sent, simulate on OK response in newstate
3274 static CURLcode ftp_nb_type(struct connectdata *conn,
3275 bool ascii, ftpstate newstate)
3277 struct ftp_conn *ftpc = &conn->proto.ftpc;
3279 char want = (char)(ascii?'A':'I');
3281 if(ftpc->transfertype == want) {
3282 state(conn, newstate);
3283 return ftp_state_type_resp(conn, 200, newstate);
3286 PPSENDF(&ftpc->pp, "TYPE %c", want);
3287 state(conn, newstate);
3289 /* keep track of our current transfer type */
3290 ftpc->transfertype = want;
3294 /***************************************************************************
3296 * ftp_pasv_verbose()
3298 * This function only outputs some informationals about this second connection
3299 * when we've issued a PASV command before and thus we have connected to a
3300 * possibly new IP address.
3303 #ifndef CURL_DISABLE_VERBOSE_STRINGS
3305 ftp_pasv_verbose(struct connectdata *conn,
3307 char *newhost, /* ascii version */
3311 Curl_printable_address(ai, buf, sizeof(buf));
3312 infof(conn->data, "Connecting to %s (%s) port %d\n", newhost, buf, port);
3317 Check if this is a range download, and if so, set the internal variables
3321 static CURLcode ftp_range(struct connectdata *conn)
3323 curl_off_t from, to;
3326 struct SessionHandle *data = conn->data;
3327 struct ftp_conn *ftpc = &conn->proto.ftpc;
3329 if(data->state.use_range && data->state.range) {
3330 from=curlx_strtoofft(data->state.range, &ptr, 0);
3331 while(*ptr && (ISSPACE(*ptr) || (*ptr=='-')))
3333 to=curlx_strtoofft(ptr, &ptr2, 0);
3335 /* we didn't get any digit */
3338 if((-1 == to) && (from>=0)) {
3340 data->state.resume_from = from;
3341 DEBUGF(infof(conn->data, "FTP RANGE %" FORMAT_OFF_T " to end of file\n",
3346 data->req.maxdownload = -from;
3347 data->state.resume_from = from;
3348 DEBUGF(infof(conn->data, "FTP RANGE the last %" FORMAT_OFF_T " bytes\n",
3353 data->req.maxdownload = (to-from)+1; /* include last byte */
3354 data->state.resume_from = from;
3355 DEBUGF(infof(conn->data, "FTP RANGE from %" FORMAT_OFF_T
3356 " getting %" FORMAT_OFF_T " bytes\n",
3357 from, data->req.maxdownload));
3359 DEBUGF(infof(conn->data, "range-download from %" FORMAT_OFF_T
3360 " to %" FORMAT_OFF_T ", totally %" FORMAT_OFF_T " bytes\n",
3361 from, to, data->req.maxdownload));
3362 ftpc->dont_check = TRUE; /* dont check for successful transfer */
3365 data->req.maxdownload = -1;
3373 * This function shall be called when the second FTP (data) connection is
3377 static CURLcode ftp_nextconnect(struct connectdata *conn)
3379 struct SessionHandle *data=conn->data;
3380 struct ftp_conn *ftpc = &conn->proto.ftpc;
3381 CURLcode result = CURLE_OK;
3383 /* the ftp struct is inited in ftp_connect() */
3384 struct FTP *ftp = data->state.proto.ftp;
3386 DEBUGF(infof(data, "DO-MORE phase starts\n"));
3388 if(ftp->transfer <= FTPTRANSFER_INFO) {
3389 /* a transfer is about to take place, or if not a file name was given
3390 so we'll do a SIZE on it later and then we need the right TYPE first */
3392 if(data->set.upload) {
3393 result = ftp_nb_type(conn, data->set.prefer_ascii, FTP_STOR_TYPE);
3399 ftp->downloadsize = -1; /* unknown as of yet */
3401 result = ftp_range(conn);
3404 else if(data->set.ftp_list_only || !ftpc->file) {
3405 /* The specified path ends with a slash, and therefore we think this
3406 is a directory that is requested, use LIST. But before that we
3407 need to set ASCII transfer mode. */
3409 /* But only if a body transfer was requested. */
3410 if(ftp->transfer == FTPTRANSFER_BODY) {
3411 result = ftp_nb_type(conn, TRUE, FTP_LIST_TYPE);
3415 /* otherwise just fall through */
3418 result = ftp_nb_type(conn, data->set.prefer_ascii, FTP_RETR_TYPE);
3423 result = ftp_easy_statemach(conn);
3426 if((result == CURLE_OK) && (ftp->transfer != FTPTRANSFER_BODY))
3427 /* no data to transfer. FIX: it feels like a kludge to have this here
3429 Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
3431 /* end of transfer */
3432 DEBUGF(infof(data, "DO-MORE phase ends with %d\n", (int)result));
3439 /***********************************************************************
3443 * This is the actual DO function for FTP. Get a file/directory according to
3444 * the options previously setup.
3448 CURLcode ftp_perform(struct connectdata *conn,
3449 bool *connected, /* connect status after PASV / PORT */
3452 /* this is FTP and no proxy */
3453 CURLcode result=CURLE_OK;
3455 DEBUGF(infof(conn->data, "DO phase starts\n"));
3457 if(conn->data->set.opt_no_body) {
3458 /* requested no body means no transfer... */
3459 struct FTP *ftp = conn->data->state.proto.ftp;
3460 ftp->transfer = FTPTRANSFER_INFO;
3464 *dophase_done = FALSE; /* not done yet */
3466 /* start the first command in the DO phase */
3467 result = ftp_state_quote(conn, TRUE, FTP_QUOTE);
3471 /* run the state-machine */
3472 if(conn->data->state.used_interface == Curl_if_multi)
3473 result = ftp_multi_statemach(conn, dophase_done);
3475 result = ftp_easy_statemach(conn);
3476 *dophase_done = TRUE; /* with the easy interface we are done here */
3478 *connected = conn->bits.tcpconnect;
3481 DEBUGF(infof(conn->data, "DO phase is complete\n"));
3486 static void wc_data_dtor(void *ptr)
3488 struct ftp_wc_tmpdata *tmp = ptr;
3490 Curl_ftp_parselist_data_free(&tmp->parser);
3494 static CURLcode init_wc_data(struct connectdata *conn)
3497 char *path = conn->data->state.path;
3498 struct WildcardData *wildcard = &(conn->data->wildcard);
3499 CURLcode ret = CURLE_OK;
3500 struct ftp_wc_tmpdata *ftp_tmp;
3502 last_slash = strrchr(conn->data->state.path, '/');
3505 if(last_slash[0] == '\0') {
3506 wildcard->state = CURLWC_CLEAN;
3507 ret = ftp_parse_url_path(conn);
3511 wildcard->pattern = strdup(last_slash);
3512 if(!wildcard->pattern)
3513 return CURLE_OUT_OF_MEMORY;
3514 last_slash[0] = '\0'; /* cut file from path */
3517 else { /* there is only 'wildcard pattern' or nothing */
3519 wildcard->pattern = strdup(path);
3520 if(!wildcard->pattern)
3521 return CURLE_OUT_OF_MEMORY;
3524 else { /* only list */
3525 wildcard->state = CURLWC_CLEAN;
3526 ret = ftp_parse_url_path(conn);
3531 /* program continues only if URL is not ending with slash, allocate needed
3532 resources for wildcard transfer */
3534 /* allocate ftp protocol specific temporary wildcard data */
3535 ftp_tmp = malloc(sizeof(struct ftp_wc_tmpdata));
3537 return CURLE_OUT_OF_MEMORY;
3540 /* INITIALIZE parselist structure */
3541 ftp_tmp->parser = Curl_ftp_parselist_data_alloc();
3542 if(!ftp_tmp->parser) {
3544 return CURLE_OUT_OF_MEMORY;
3547 wildcard->tmp = ftp_tmp; /* put it to the WildcardData tmp pointer */
3548 wildcard->tmp_dtor = wc_data_dtor;
3550 /* wildcard does not support NOCWD option (assert it?) */
3551 if(conn->data->set.ftp_filemethod == FTPFILE_NOCWD)
3552 conn->data->set.ftp_filemethod = FTPFILE_MULTICWD;
3554 /* try to parse ftp url */
3555 ret = ftp_parse_url_path(conn);
3560 /* backup old write_function */
3561 ftp_tmp->backup.write_function = conn->data->set.fwrite_func;
3562 /* parsing write function */
3563 conn->data->set.fwrite_func = Curl_ftp_parselist;
3564 /* backup old file descriptor */
3565 ftp_tmp->backup.file_descriptor = conn->data->set.out;
3566 /* let the writefunc callback know what curl pointer is working with */
3567 conn->data->set.out = conn;
3569 wildcard->path = strdup(conn->data->state.path);
3570 if(!wildcard->path) {
3571 return CURLE_OUT_OF_MEMORY;
3574 infof(conn->data, "Wildcard - Parsing started\n");
3578 /* This is called recursively */
3579 static CURLcode wc_statemach(struct connectdata *conn)
3581 struct WildcardData * const wildcard = &(conn->data->wildcard);
3582 CURLcode ret = CURLE_OK;
3584 switch (wildcard->state) {
3586 ret = init_wc_data(conn);
3587 if(wildcard->state == CURLWC_CLEAN)
3591 wildcard->state = ret ? CURLWC_ERROR : CURLWC_MATCHING;
3594 case CURLWC_MATCHING: {
3595 /* In this state is LIST response successfully parsed, so lets restore
3596 previous WRITEFUNCTION callback and WRITEDATA pointer */
3597 struct ftp_wc_tmpdata *ftp_tmp = wildcard->tmp;
3598 conn->data->set.fwrite_func = ftp_tmp->backup.write_function;
3599 conn->data->set.out = ftp_tmp->backup.file_descriptor;
3600 wildcard->state = CURLWC_DOWNLOADING;
3602 if(Curl_ftp_parselist_geterror(ftp_tmp->parser)) {
3603 /* error found in LIST parsing */
3604 wildcard->state = CURLWC_CLEAN;
3605 return wc_statemach(conn);
3607 else if(wildcard->filelist->size == 0) {
3608 /* no corresponding file */
3609 wildcard->state = CURLWC_CLEAN;
3610 return CURLE_REMOTE_FILE_NOT_FOUND;
3612 return wc_statemach(conn);
3615 case CURLWC_DOWNLOADING: {
3616 /* filelist has at least one file, lets get first one */
3617 struct ftp_conn *ftpc = &conn->proto.ftpc;
3618 struct curl_fileinfo *finfo = wildcard->filelist->head->ptr;
3619 char *tmp_path = malloc(strlen(conn->data->state.path) +
3620 strlen(finfo->filename) + 1);
3622 return CURLE_OUT_OF_MEMORY;
3626 /* make full path to matched file */
3627 strcat(tmp_path, wildcard->path);
3628 strcat(tmp_path, finfo->filename);
3629 /* switch default "state.pathbuffer" and tmp_path, good to see
3630 ftp_parse_url_path function to understand this trick */
3631 if(conn->data->state.pathbuffer)
3632 free(conn->data->state.pathbuffer);
3633 conn->data->state.pathbuffer = tmp_path;
3634 conn->data->state.path = tmp_path;
3636 infof(conn->data, "Wildcard - START of \"%s\"\n", finfo->filename);
3637 if(conn->data->set.chunk_bgn) {
3638 long userresponse = conn->data->set.chunk_bgn(
3639 finfo, wildcard->customptr, (int)wildcard->filelist->size);
3640 switch(userresponse) {
3641 case CURL_CHUNK_BGN_FUNC_SKIP:
3642 infof(conn->data, "Wildcard - \"%s\" skipped by user\n",
3644 wildcard->state = CURLWC_SKIP;
3645 return wc_statemach(conn);
3646 case CURL_CHUNK_BGN_FUNC_FAIL:
3647 return CURLE_CHUNK_FAILED;
3651 if(finfo->filetype != CURLFILETYPE_FILE) {
3652 wildcard->state = CURLWC_SKIP;
3653 return wc_statemach(conn);
3656 if(finfo->flags & CURLFINFOFLAG_KNOWN_SIZE)
3657 ftpc->known_filesize = finfo->size;
3659 ret = ftp_parse_url_path(conn);
3664 /* we don't need the Curl_fileinfo of first file anymore */
3665 Curl_llist_remove(wildcard->filelist, wildcard->filelist->head, NULL);
3667 if(wildcard->filelist->size == 0) { /* remains only one file to down. */
3668 wildcard->state = CURLWC_CLEAN;
3669 /* after that will be ftp_do called once again and no transfer
3670 will be done because of CURLWC_CLEAN state */
3676 if(conn->data->set.chunk_end)
3677 conn->data->set.chunk_end(conn->data->wildcard.customptr);
3678 Curl_llist_remove(wildcard->filelist, wildcard->filelist->head, NULL);
3679 wildcard->state = (wildcard->filelist->size == 0) ?
3680 CURLWC_CLEAN : CURLWC_DOWNLOADING;
3681 return wc_statemach(conn);
3684 case CURLWC_CLEAN: {
3685 struct ftp_wc_tmpdata *ftp_tmp = wildcard->tmp;
3688 ret = Curl_ftp_parselist_geterror(ftp_tmp->parser);
3690 wildcard->state = ret ? CURLWC_ERROR : CURLWC_DONE;
3701 /***********************************************************************
3705 * This function is registered as 'curl_do' function. It decodes the path
3706 * parts etc as a wrapper to the actual DO function (ftp_perform).
3708 * The input argument is already checked for validity.
3710 static CURLcode ftp_do(struct connectdata *conn, bool *done)
3712 CURLcode retcode = CURLE_OK;
3714 *done = FALSE; /* default to false */
3717 Since connections can be re-used between SessionHandles, this might be a
3718 connection already existing but on a fresh SessionHandle struct so we must
3719 make sure we have a good 'struct FTP' to play with. For new connections,
3720 the struct FTP is allocated and setup in the ftp_connect() function.
3722 Curl_reset_reqproto(conn);
3723 retcode = ftp_init(conn);
3727 if(conn->data->set.wildcardmatch) {
3728 retcode = wc_statemach(conn);
3729 if(conn->data->wildcard.state == CURLWC_SKIP ||
3730 conn->data->wildcard.state == CURLWC_DONE) {
3731 /* do not call ftp_regular_transfer */
3734 if(retcode) /* error, loop or skipping the file */
3737 else { /* no wildcard FSM needed */
3738 retcode = ftp_parse_url_path(conn);
3743 retcode = ftp_regular_transfer(conn, done);
3749 CURLcode Curl_ftpsendf(struct connectdata *conn,
3750 const char *fmt, ...)
3752 ssize_t bytes_written;
3753 #define SBUF_SIZE 1024
3757 CURLcode res = CURLE_OK;
3758 #if defined(HAVE_KRB4) || defined(HAVE_GSSAPI)
3759 enum protection_level data_sec = conn->data_prot;
3764 vsnprintf(s, SBUF_SIZE-3, fmt, ap);
3767 strcat(s, "\r\n"); /* append a trailing CRLF */
3770 write_len = strlen(s);
3772 res = Curl_convert_to_network(conn->data, s, write_len);
3773 /* Curl_convert_to_network calls failf if unsuccessful */
3778 #if defined(HAVE_KRB4) || defined(HAVE_GSSAPI)
3779 conn->data_prot = PROT_CMD;
3781 res = Curl_write(conn, conn->sock[FIRSTSOCKET], sptr, write_len,
3783 #if defined(HAVE_KRB4) || defined(HAVE_GSSAPI)
3784 DEBUGASSERT(data_sec > PROT_NONE && data_sec < PROT_LAST);
3785 conn->data_prot = data_sec;
3791 if(conn->data->set.verbose)
3792 Curl_debug(conn->data, CURLINFO_HEADER_OUT,
3793 sptr, (size_t)bytes_written, conn);
3795 if(bytes_written != (ssize_t)write_len) {
3796 write_len -= bytes_written;
3797 sptr += bytes_written;
3806 /***********************************************************************
3810 * This should be called before calling sclose() on an ftp control connection
3811 * (not data connections). We should then wait for the response from the
3812 * server before returning. The calling code should then try to close the
3816 static CURLcode ftp_quit(struct connectdata *conn)
3818 CURLcode result = CURLE_OK;
3820 if(conn->proto.ftpc.ctl_valid) {
3821 PPSENDF(&conn->proto.ftpc.pp, "QUIT", NULL);
3822 state(conn, FTP_QUIT);
3824 result = ftp_easy_statemach(conn);
3830 /***********************************************************************
3834 * Disconnect from an FTP server. Cleanup protocol-specific per-connection
3835 * resources. BLOCKING.
3837 static CURLcode ftp_disconnect(struct connectdata *conn, bool dead_connection)
3839 struct ftp_conn *ftpc= &conn->proto.ftpc;
3840 struct pingpong *pp = &ftpc->pp;
3842 /* We cannot send quit unconditionally. If this connection is stale or
3843 bad in any way, sending quit and waiting around here will make the
3844 disconnect wait in vain and cause more problems than we need to.
3846 ftp_quit() will check the state of ftp->ctl_valid. If it's ok it
3847 will try to send the QUIT command, otherwise it will just return.
3850 ftpc->ctl_valid = FALSE;
3852 /* The FTP session may or may not have been allocated/setup at this point! */
3853 (void)ftp_quit(conn); /* ignore errors on the QUIT */
3855 if(ftpc->entrypath) {
3856 struct SessionHandle *data = conn->data;
3857 if(data->state.most_recent_ftp_entrypath == ftpc->entrypath) {
3858 data->state.most_recent_ftp_entrypath = NULL;
3860 free(ftpc->entrypath);
3861 ftpc->entrypath = NULL;
3865 if(ftpc->prevpath) {
3866 free(ftpc->prevpath);
3867 ftpc->prevpath = NULL;
3869 if(ftpc->server_os) {
3870 free(ftpc->server_os);
3871 ftpc->server_os = NULL;
3874 Curl_pp_disconnect(pp);
3876 #if defined(HAVE_KRB4) || defined(HAVE_GSSAPI)
3883 /***********************************************************************
3885 * ftp_parse_url_path()
3887 * Parse the URL path into separate path components.
3891 CURLcode ftp_parse_url_path(struct connectdata *conn)
3893 struct SessionHandle *data = conn->data;
3894 /* the ftp struct is already inited in ftp_connect() */
3895 struct FTP *ftp = data->state.proto.ftp;
3896 struct ftp_conn *ftpc = &conn->proto.ftpc;
3897 const char *slash_pos; /* position of the first '/' char in curpos */
3898 const char *path_to_use = data->state.path;
3899 const char *cur_pos;
3900 const char *filename = NULL;
3902 cur_pos = path_to_use; /* current position in path. point at the begin
3903 of next path component */
3905 ftpc->ctl_valid = FALSE;
3906 ftpc->cwdfail = FALSE;
3908 switch(data->set.ftp_filemethod) {
3910 /* fastest, but less standard-compliant */
3913 The best time to check whether the path is a file or directory is right
3916 the first condition in the if() right here, is there just in case
3917 someone decides to set path to NULL one day
3919 if(data->state.path &&
3920 data->state.path[0] &&
3921 (data->state.path[strlen(data->state.path) - 1] != '/') )
3922 filename = data->state.path; /* this is a full file path */
3924 ftpc->file is not used anywhere other than for operations on a file.
3925 In other words, never for directory operations.
3926 So we can safely leave filename as NULL here and use it as a
3927 argument in dir/file decisions.
3931 case FTPFILE_SINGLECWD:
3932 /* get the last slash */
3933 if(!path_to_use[0]) {
3934 /* no dir, no file */
3938 slash_pos=strrchr(cur_pos, '/');
3939 if(slash_pos || !*cur_pos) {
3940 ftpc->dirs = calloc(1, sizeof(ftpc->dirs[0]));
3942 return CURLE_OUT_OF_MEMORY;
3944 ftpc->dirs[0] = curl_easy_unescape(conn->data, slash_pos ? cur_pos : "/",
3945 slash_pos?(int)(slash_pos-cur_pos):1,
3947 if(!ftpc->dirs[0]) {
3949 return CURLE_OUT_OF_MEMORY;
3951 ftpc->dirdepth = 1; /* we consider it to be a single dir */
3952 filename = slash_pos ? slash_pos+1 : cur_pos; /* rest is file name */
3955 filename = cur_pos; /* this is a file name only */
3958 default: /* allow pretty much anything */
3959 case FTPFILE_MULTICWD:
3961 ftpc->diralloc = 5; /* default dir depth to allocate */
3962 ftpc->dirs = calloc(ftpc->diralloc, sizeof(ftpc->dirs[0]));
3964 return CURLE_OUT_OF_MEMORY;
3966 /* we have a special case for listing the root dir only */
3967 if(strequal(path_to_use, "/")) {
3968 cur_pos++; /* make it point to the zero byte */
3969 ftpc->dirs[0] = strdup("/");
3973 /* parse the URL path into separate path components */
3974 while((slash_pos = strchr(cur_pos, '/')) != NULL) {
3975 /* 1 or 0 pointer offset to indicate absolute directory */
3976 ssize_t absolute_dir = ((cur_pos - data->state.path > 0) &&
3977 (ftpc->dirdepth == 0))?1:0;
3979 /* seek out the next path component */
3980 if(slash_pos-cur_pos) {
3981 /* we skip empty path components, like "x//y" since the FTP command
3982 CWD requires a parameter and a non-existent parameter a) doesn't
3983 work on many servers and b) has no effect on the others. */
3984 int len = (int)(slash_pos - cur_pos + absolute_dir);
3985 ftpc->dirs[ftpc->dirdepth] =
3986 curl_easy_unescape(conn->data, cur_pos - absolute_dir, len, NULL);
3987 if(!ftpc->dirs[ftpc->dirdepth]) { /* run out of memory ... */
3988 failf(data, "no memory");
3990 return CURLE_OUT_OF_MEMORY;
3992 if(isBadFtpString(ftpc->dirs[ftpc->dirdepth])) {
3993 free(ftpc->dirs[ftpc->dirdepth]);
3995 return CURLE_URL_MALFORMAT;
3999 cur_pos = slash_pos + 1; /* jump to the rest of the string */
4003 cur_pos = slash_pos + 1; /* jump to the rest of the string */
4004 if(++ftpc->dirdepth >= ftpc->diralloc) {
4007 ftpc->diralloc *= 2; /* double the size each time */
4008 bigger = realloc(ftpc->dirs, ftpc->diralloc * sizeof(ftpc->dirs[0]));
4011 return CURLE_OUT_OF_MEMORY;
4013 ftpc->dirs = (char **)bigger;
4017 filename = cur_pos; /* the rest is the file name */
4021 if(filename && *filename) {
4022 ftpc->file = curl_easy_unescape(conn->data, filename, 0, NULL);
4023 if(NULL == ftpc->file) {
4025 failf(data, "no memory");
4026 return CURLE_OUT_OF_MEMORY;
4028 if(isBadFtpString(ftpc->file)) {
4030 return CURLE_URL_MALFORMAT;
4034 ftpc->file=NULL; /* instead of point to a zero byte, we make it a NULL
4037 if(data->set.upload && !ftpc->file && (ftp->transfer == FTPTRANSFER_BODY)) {
4038 /* We need a file name when uploading. Return error! */
4039 failf(data, "Uploading to a URL without a file name!");
4040 return CURLE_URL_MALFORMAT;
4043 ftpc->cwddone = FALSE; /* default to not done */
4045 if(ftpc->prevpath) {
4046 /* prevpath is "raw" so we convert the input path before we compare the
4049 char *path = curl_easy_unescape(conn->data, data->state.path, 0, &dlen);
4052 return CURLE_OUT_OF_MEMORY;
4055 dlen -= ftpc->file?(int)strlen(ftpc->file):0;
4056 if((dlen == (int)strlen(ftpc->prevpath)) &&
4057 strnequal(path, ftpc->prevpath, dlen)) {
4058 infof(data, "Request has same path as previous transfer\n");
4059 ftpc->cwddone = TRUE;
4067 /* call this when the DO phase has completed */
4068 static CURLcode ftp_dophase_done(struct connectdata *conn,
4071 CURLcode result = CURLE_OK;
4072 struct FTP *ftp = conn->data->state.proto.ftp;
4073 struct ftp_conn *ftpc = &conn->proto.ftpc;
4076 result = ftp_nextconnect(conn);
4078 if(result && (conn->sock[SECONDARYSOCKET] != CURL_SOCKET_BAD)) {
4079 /* Failure detected, close the second socket if it was created already */
4080 sclose(conn->sock[SECONDARYSOCKET]);
4081 conn->sock[SECONDARYSOCKET] = CURL_SOCKET_BAD;
4085 if(ftp->transfer != FTPTRANSFER_BODY)
4086 /* no data to transfer */
4087 Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
4089 /* since we didn't connect now, we want do_more to get called */
4090 conn->bits.do_more = TRUE;
4092 ftpc->ctl_valid = TRUE; /* seems good */
4097 /* called from multi.c while DOing */
4098 static CURLcode ftp_doing(struct connectdata *conn,
4102 result = ftp_multi_statemach(conn, dophase_done);
4105 result = ftp_dophase_done(conn, FALSE /* not connected */);
4107 DEBUGF(infof(conn->data, "DO phase is complete\n"));
4112 /***********************************************************************
4114 * ftp_regular_transfer()
4116 * The input argument is already checked for validity.
4118 * Performs all commands done before a regular transfer between a local and a
4121 * ftp->ctl_valid starts out as FALSE, and gets set to TRUE if we reach the
4122 * ftp_done() function without finding any major problem.
4125 CURLcode ftp_regular_transfer(struct connectdata *conn,
4128 CURLcode result=CURLE_OK;
4129 bool connected=FALSE;
4130 struct SessionHandle *data = conn->data;
4131 struct ftp_conn *ftpc = &conn->proto.ftpc;
4132 data->req.size = -1; /* make sure this is unknown at this point */
4134 Curl_pgrsSetUploadCounter(data, 0);
4135 Curl_pgrsSetDownloadCounter(data, 0);
4136 Curl_pgrsSetUploadSize(data, 0);
4137 Curl_pgrsSetDownloadSize(data, 0);
4139 ftpc->ctl_valid = TRUE; /* starts good */
4141 result = ftp_perform(conn,
4142 &connected, /* have we connected after PASV/PORT */
4143 dophase_done); /* all commands in the DO-phase done? */
4145 if(CURLE_OK == result) {
4148 /* the DO phase has not completed yet */
4151 result = ftp_dophase_done(conn, connected);
4161 static CURLcode ftp_setup_connection(struct connectdata * conn)
4163 struct SessionHandle *data = conn->data;
4167 if(conn->bits.httpproxy && !data->set.tunnel_thru_httpproxy) {
4168 /* Unless we have asked to tunnel ftp operations through the proxy, we
4169 switch and use HTTP operations only */
4170 #ifndef CURL_DISABLE_HTTP
4171 if(conn->handler == &Curl_handler_ftp)
4172 conn->handler = &Curl_handler_ftp_proxy;
4175 conn->handler = &Curl_handler_ftps_proxy;
4177 failf(data, "FTPS not supported!");
4178 return CURLE_UNSUPPORTED_PROTOCOL;
4182 * We explicitly mark this connection as persistent here as we're doing
4183 * FTP over HTTP and thus we accidentally avoid setting this value
4186 conn->bits.close = FALSE;
4188 failf(data, "FTP over http proxy requires HTTP support built-in!");
4189 return CURLE_UNSUPPORTED_PROTOCOL;
4193 data->state.path++; /* don't include the initial slash */
4194 data->state.slash_removed = TRUE; /* we've skipped the slash */
4196 /* FTP URLs support an extension like ";type=<typecode>" that
4197 * we'll try to get now! */
4198 type = strstr(data->state.path, ";type=");
4201 type = strstr(conn->host.rawalloc, ";type=");
4204 *type = 0; /* it was in the middle of the hostname */
4205 command = Curl_raw_toupper(type[6]);
4206 conn->bits.type_set = TRUE;
4209 case 'A': /* ASCII mode */
4210 data->set.prefer_ascii = TRUE;
4213 case 'D': /* directory mode */
4214 data->set.ftp_list_only = TRUE;
4217 case 'I': /* binary mode */
4219 /* switch off ASCII */
4220 data->set.prefer_ascii = FALSE;
4228 #endif /* CURL_DISABLE_FTP */