1 /***************************************************************************
3 * Project ___| | | | _ \| |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
8 * Copyright (C) 1998 - 2010, 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.
22 ***************************************************************************/
26 #ifndef CURL_DISABLE_FTP
37 #ifdef HAVE_SYS_SOCKET_H
38 #include <sys/socket.h>
40 #ifdef HAVE_NETINET_IN_H
41 #include <netinet/in.h>
43 #ifdef HAVE_ARPA_INET_H
44 #include <arpa/inet.h>
47 #include <sys/utsname.h>
57 #if (defined(NETWARE) && defined(__NOVELL_LIBC__))
59 #define in_addr_t unsigned long
62 #include <curl/curl.h>
65 #include "easyif.h" /* for Curl_convert_... prototypes */
72 #include "http.h" /* for HTTP proxy tunnel stuff */
76 #if defined(HAVE_KRB4) || defined(HAVE_GSSAPI)
80 #include "strtoofft.h"
85 #include "inet_ntop.h"
86 #include "inet_pton.h"
88 #include "parsedate.h" /* for the week day and month names */
89 #include "sockaddr.h" /* required for Curl_sockaddr_storage */
93 #include "speedcheck.h"
96 #define _MPRINTF_REPLACE /* use our functions only */
97 #include <curl/mprintf.h>
99 #include "curl_memory.h"
100 /* The last #include file should be: */
101 #include "memdebug.h"
104 #define NI_MAXHOST 1025
106 #ifndef INET_ADDRSTRLEN
107 #define INET_ADDRSTRLEN 16
110 #ifdef CURL_DISABLE_VERBOSE_STRINGS
111 #define ftp_pasv_verbose(a,b,c,d) do { } while(0)
114 /* Local API functions */
115 static CURLcode ftp_sendquote(struct connectdata *conn,
116 struct curl_slist *quote);
117 static CURLcode ftp_quit(struct connectdata *conn);
118 static CURLcode ftp_parse_url_path(struct connectdata *conn);
119 static CURLcode ftp_regular_transfer(struct connectdata *conn, bool *done);
120 #ifndef CURL_DISABLE_VERBOSE_STRINGS
121 static void ftp_pasv_verbose(struct connectdata *conn,
123 char *newhost, /* ascii version */
126 static CURLcode ftp_state_post_rest(struct connectdata *conn);
127 static CURLcode ftp_state_post_cwd(struct connectdata *conn);
128 static CURLcode ftp_state_quote(struct connectdata *conn,
129 bool init, ftpstate instate);
130 static CURLcode ftp_nb_type(struct connectdata *conn,
131 bool ascii, ftpstate newstate);
132 static int ftp_need_type(struct connectdata *conn,
134 static CURLcode ftp_do(struct connectdata *conn, bool *done);
135 static CURLcode ftp_done(struct connectdata *conn,
136 CURLcode, bool premature);
137 static CURLcode ftp_connect(struct connectdata *conn, bool *done);
138 static CURLcode ftp_disconnect(struct connectdata *conn);
139 static CURLcode ftp_nextconnect(struct connectdata *conn);
140 static CURLcode ftp_multi_statemach(struct connectdata *conn, bool *done);
141 static int ftp_getsock(struct connectdata *conn,
142 curl_socket_t *socks,
144 static CURLcode ftp_doing(struct connectdata *conn,
146 static CURLcode ftp_setup_connection(struct connectdata * conn);
148 /* easy-to-use macro: */
149 #define FTPSENDF(x,y,z) if((result = Curl_ftpsendf(x,y,z)) != CURLE_OK) \
151 #define PPSENDF(x,y,z) if((result = Curl_pp_sendf(x,y,z)) != CURLE_OK) \
156 * FTP protocol handler.
159 const struct Curl_handler Curl_handler_ftp = {
161 ftp_setup_connection, /* setup_connection */
164 ftp_nextconnect, /* do_more */
165 ftp_connect, /* connect_it */
166 ftp_multi_statemach, /* connecting */
167 ftp_doing, /* doing */
168 ftp_getsock, /* proto_getsock */
169 ftp_getsock, /* doing_getsock */
170 ZERO_NULL, /* perform_getsock */
171 ftp_disconnect, /* disconnect */
172 PORT_FTP, /* defport */
173 PROT_FTP /* protocol */
179 * FTPS protocol handler.
182 const struct Curl_handler Curl_handler_ftps = {
184 ftp_setup_connection, /* setup_connection */
187 ftp_nextconnect, /* do_more */
188 ftp_connect, /* connect_it */
189 ftp_multi_statemach, /* connecting */
190 ftp_doing, /* doing */
191 ftp_getsock, /* proto_getsock */
192 ftp_getsock, /* doing_getsock */
193 ZERO_NULL, /* perform_getsock */
194 ftp_disconnect, /* disconnect */
195 PORT_FTPS, /* defport */
196 PROT_FTP | PROT_FTPS | PROT_SSL /* protocol */
200 #ifndef CURL_DISABLE_HTTP
202 * HTTP-proxyed FTP protocol handler.
205 static const struct Curl_handler Curl_handler_ftp_proxy = {
207 ZERO_NULL, /* setup_connection */
208 Curl_http, /* do_it */
209 Curl_http_done, /* done */
210 ZERO_NULL, /* do_more */
211 ZERO_NULL, /* connect_it */
212 ZERO_NULL, /* connecting */
213 ZERO_NULL, /* doing */
214 ZERO_NULL, /* proto_getsock */
215 ZERO_NULL, /* doing_getsock */
216 ZERO_NULL, /* perform_getsock */
217 ZERO_NULL, /* disconnect */
218 PORT_FTP, /* defport */
219 PROT_HTTP /* protocol */
225 * HTTP-proxyed FTPS protocol handler.
228 static const struct Curl_handler Curl_handler_ftps_proxy = {
230 ZERO_NULL, /* setup_connection */
231 Curl_http, /* do_it */
232 Curl_http_done, /* done */
233 ZERO_NULL, /* do_more */
234 ZERO_NULL, /* connect_it */
235 ZERO_NULL, /* connecting */
236 ZERO_NULL, /* doing */
237 ZERO_NULL, /* proto_getsock */
238 ZERO_NULL, /* doing_getsock */
239 ZERO_NULL, /* perform_getsock */
240 ZERO_NULL, /* disconnect */
241 PORT_FTPS, /* defport */
242 PROT_HTTP /* protocol */
249 * NOTE: back in the old days, we added code in the FTP code that made NOBODY
250 * requests on files respond with headers passed to the client/stdout that
251 * looked like HTTP ones.
253 * This approach is not very elegant, it causes confusion and is error-prone.
254 * It is subject for removal at the next (or at least a future) soname bump.
255 * Until then you can test the effects of the removal by undefining the
256 * following define named CURL_FTP_HTTPSTYLE_HEAD.
258 #define CURL_FTP_HTTPSTYLE_HEAD 1
260 static void freedirs(struct ftp_conn *ftpc)
264 for (i=0; i < ftpc->dirdepth; i++){
280 /* Returns non-zero if the given string contains CR (\r) or LF (\n),
281 which are not allowed within RFC 959 <string>.
282 Note: The input string is in the client's encoding which might
283 not be ASCII, so escape sequences \r & \n must be used instead
284 of hex values 0x0d & 0x0a.
286 static bool isBadFtpString(const char *string)
288 return (bool)((NULL != strchr(string, '\r')) ||
289 (NULL != strchr(string, '\n')));
292 /***********************************************************************
294 * AllowServerConnect()
296 * When we've issue the PORT command, we have told the server to connect
297 * to us. This function will sit and wait here until the server has
301 static CURLcode AllowServerConnect(struct connectdata *conn)
303 struct SessionHandle *data = conn->data;
304 curl_socket_t sock = conn->sock[SECONDARYSOCKET];
307 curl_socket_t s = CURL_SOCKET_BAD;
309 struct Curl_sockaddr_storage add;
311 struct sockaddr_in add;
313 curl_socklen_t size = (curl_socklen_t) sizeof(add);
316 timeout_ms = Curl_timeleft(conn, NULL, TRUE);
318 if(timeout_ms <= 0) {
319 /* if a timeout was already reached, bail out */
320 failf(data, "Timeout while waiting for server connect");
321 return CURLE_OPERATION_TIMEDOUT;
324 interval_ms = 1000; /* use 1 second timeout intervals */
325 if(timeout_ms < interval_ms)
326 interval_ms = timeout_ms;
328 switch (Curl_socket_ready(sock, CURL_SOCKET_BAD, (int)interval_ms)) {
331 failf(data, "Error while waiting for server connect");
332 return CURLE_FTP_PORT_FAILED;
333 case 0: /* timeout */
336 /* we have received data here */
337 if(0 == getsockname(sock, (struct sockaddr *) &add, &size)) {
340 s=accept(sock, (struct sockaddr *) &add, &size);
342 sclose(sock); /* close the first socket */
344 if(CURL_SOCKET_BAD == s) {
345 failf(data, "Error accept()ing server connect");
346 return CURLE_FTP_PORT_FAILED;
348 infof(data, "Connection accepted from server\n");
350 conn->sock[SECONDARYSOCKET] = s;
351 curlx_nonblock(s, TRUE); /* enable non-blocking */
355 /* never reaches this point */
358 /* macro to check for a three-digit ftp status code at the start of the
360 #define STATUSCODE(line) (ISDIGIT(line[0]) && ISDIGIT(line[1]) && \
363 /* macro to check for the last line in an FTP server response */
364 #define LASTLINE(line) (STATUSCODE(line) && (' ' == line[3]))
366 static int ftp_endofresp(struct pingpong *pp,
369 char *line = pp->linestart_resp;
370 size_t len = pp->nread_resp;
372 if((len > 3) && LASTLINE(line)) {
379 static CURLcode ftp_readresp(curl_socket_t sockfd,
381 int *ftpcode, /* return the ftp-code if done */
382 size_t *size) /* size of the response */
384 struct connectdata *conn = pp->conn;
385 #if defined(HAVE_KRB4) || defined(HAVE_GSSAPI)
386 struct SessionHandle *data = conn->data;
387 char * const buf = data->state.buffer;
389 CURLcode result = CURLE_OK;
392 result = Curl_pp_readresp(sockfd, pp, &code, size);
394 #if defined(HAVE_KRB4) || defined(HAVE_GSSAPI)
395 /* handle the security-oriented responses 6xx ***/
396 /* FIXME: some errorchecking perhaps... ***/
399 code = Curl_sec_read_msg(conn, buf, prot_safe);
402 code = Curl_sec_read_msg(conn, buf, prot_private);
405 code = Curl_sec_read_msg(conn, buf, prot_confidential);
408 /* normal ftp stuff we pass through! */
413 /* store the latest code for later retrieval */
414 conn->data->info.httpcode=code;
422 /* --- parse FTP server responses --- */
425 * Curl_GetFTPResponse() is a BLOCKING function to read the full response
426 * from a server after a command.
430 CURLcode Curl_GetFTPResponse(ssize_t *nreadp, /* return number of bytes read */
431 struct connectdata *conn,
432 int *ftpcode) /* return the ftp-code */
435 * We cannot read just one byte per read() and then go back to select() as
436 * the OpenSSL read() doesn't grok that properly.
438 * Alas, read as much as possible, split up into lines, use the ending
439 * line in a response or continue reading. */
441 curl_socket_t sockfd = conn->sock[FIRSTSOCKET];
442 long timeout; /* timeout in milliseconds */
444 struct SessionHandle *data = conn->data;
445 CURLcode result = CURLE_OK;
446 struct ftp_conn *ftpc = &conn->proto.ftpc;
447 struct pingpong *pp = &ftpc->pp;
450 int value_to_be_ignored=0;
453 *ftpcode = 0; /* 0 for errors */
455 /* make the pointer point to something for the rest of this function */
456 ftpcode = &value_to_be_ignored;
460 while(!*ftpcode && !result) {
461 /* check and reset timeout value every lap */
462 timeout = Curl_pp_state_timeout(pp);
465 failf(data, "FTP response timeout");
466 return CURLE_OPERATION_TIMEDOUT; /* already too little time */
469 interval_ms = 1000; /* use 1 second timeout intervals */
470 if(timeout < interval_ms)
471 interval_ms = timeout;
474 * Since this function is blocking, we need to wait here for input on the
475 * connection and only then we call the response reading function. We do
476 * timeout at least every second to make the timeout check run.
478 * A caution here is that the ftp_readresp() function has a cache that may
479 * contain pieces of a response from the previous invoke and we need to
480 * make sure we don't just wait for input while there is unhandled data in
481 * that cache. But also, if the cache is there, we call ftp_readresp() and
482 * the cache wasn't good enough to continue we must not just busy-loop
483 * around this function.
487 if(pp->cache && (cache_skip < 2)) {
489 * There's a cache left since before. We then skipping the wait for
490 * socket action, unless this is the same cache like the previous round
491 * as then the cache was deemed not enough to act on and we then need to
492 * wait for more data anyway.
496 switch (Curl_socket_ready(sockfd, CURL_SOCKET_BAD, (int)interval_ms)) {
497 case -1: /* select() error, stop reading */
498 failf(data, "FTP response aborted due to select/poll error: %d",
500 return CURLE_RECV_ERROR;
502 case 0: /* timeout */
503 if(Curl_pgrsUpdate(conn))
504 return CURLE_ABORTED_BY_CALLBACK;
505 continue; /* just continue in our loop for the timeout duration */
507 default: /* for clarity */
511 result = ftp_readresp(sockfd, pp, ftpcode, &nread);
515 if(!nread && pp->cache)
516 /* bump cache skip counter as on repeated skips we must wait for more
520 /* when we got data or there is no cache left, we reset the cache skip
526 } /* while there's buffer left and loop is requested */
528 pp->pending_resp = FALSE;
533 /* This is the ONLY way to change FTP state! */
534 static void state(struct connectdata *conn,
537 #if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
538 /* for debug purposes */
539 static const char * const names[]={
577 struct ftp_conn *ftpc = &conn->proto.ftpc;
578 #if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
579 if(ftpc->state != newstate)
580 infof(conn->data, "FTP %p state change from %s to %s\n",
581 ftpc, names[ftpc->state], names[newstate]);
583 ftpc->state = newstate;
586 static CURLcode ftp_state_user(struct connectdata *conn)
589 struct FTP *ftp = conn->data->state.proto.ftp;
591 PPSENDF(&conn->proto.ftpc.pp, "USER %s", ftp->user?ftp->user:"");
593 state(conn, FTP_USER);
594 conn->data->state.ftp_trying_alternative = FALSE;
599 static CURLcode ftp_state_pwd(struct connectdata *conn)
603 /* send PWD to discover our entry point */
604 PPSENDF(&conn->proto.ftpc.pp, "PWD", NULL);
605 state(conn, FTP_PWD);
610 /* For the FTP "protocol connect" and "doing" phases only */
611 static int ftp_getsock(struct connectdata *conn,
612 curl_socket_t *socks,
615 return Curl_pp_getsock(&conn->proto.ftpc.pp, socks, numsocks);
618 /* This is called after the FTP_QUOTE state is passed.
620 ftp_state_cwd() sends the range of CWD commands to the server to change to
621 the correct directory. It may also need to send MKD commands to create
622 missing ones, if that option is enabled.
624 static CURLcode ftp_state_cwd(struct connectdata *conn)
626 CURLcode result = CURLE_OK;
627 struct ftp_conn *ftpc = &conn->proto.ftpc;
630 /* already done and fine */
631 result = ftp_state_post_cwd(conn);
633 ftpc->count2 = 0; /* count2 counts failed CWDs */
635 /* count3 is set to allow a MKD to fail once. In the case when first CWD
636 fails and then MKD fails (due to another session raced it to create the
637 dir) this then allows for a second try to CWD to it */
638 ftpc->count3 = (conn->data->set.ftp_create_missing_dirs==2)?1:0;
640 if(conn->bits.reuse && ftpc->entrypath) {
641 /* This is a re-used connection. Since we change directory to where the
642 transfer is taking place, we must first get back to the original dir
643 where we ended up after login: */
644 ftpc->count1 = 0; /* we count this as the first path, then we add one
645 for all upcoming ones in the ftp->dirs[] array */
646 PPSENDF(&conn->proto.ftpc.pp, "CWD %s", ftpc->entrypath);
647 state(conn, FTP_CWD);
652 /* issue the first CWD, the rest is sent when the CWD responses are
654 PPSENDF(&conn->proto.ftpc.pp, "CWD %s", ftpc->dirs[ftpc->count1 -1]);
655 state(conn, FTP_CWD);
658 /* No CWD necessary */
659 result = ftp_state_post_cwd(conn);
672 static CURLcode ftp_state_use_port(struct connectdata *conn,
673 ftpport fcmd) /* start with this */
676 CURLcode result = CURLE_OK;
677 struct ftp_conn *ftpc = &conn->proto.ftpc;
678 struct SessionHandle *data=conn->data;
679 curl_socket_t portsock= CURL_SOCKET_BAD;
680 char myhost[256] = "";
682 struct Curl_sockaddr_storage ss;
683 Curl_addrinfo *res, *ai;
684 curl_socklen_t sslen;
685 char hbuf[NI_MAXHOST];
686 struct sockaddr *sa=(struct sockaddr *)&ss;
687 struct sockaddr_in * const sa4 = (void *)sa;
689 struct sockaddr_in6 * const sa6 = (void *)sa;
692 static const char mode[][5] = { "EPRT", "PORT" };
696 char *string_ftpport = data->set.str[STRING_FTPPORT];
697 struct Curl_dns_entry *h=NULL;
698 unsigned short port_min = 0;
699 unsigned short port_max = 0;
704 /* Step 1, figure out what is requested,
706 * (ipv4|ipv6|domain|interface)?(:port(-range)?)?
709 if(data->set.str[STRING_FTPPORT] &&
710 (strlen(data->set.str[STRING_FTPPORT]) > 1)) {
713 size_t addrlen = INET6_ADDRSTRLEN > strlen(string_ftpport) ?
714 INET6_ADDRSTRLEN : strlen(string_ftpport);
716 size_t addrlen = INET_ADDRSTRLEN > strlen(string_ftpport) ?
717 INET_ADDRSTRLEN : strlen(string_ftpport);
719 char *ip_start = string_ftpport;
721 char *port_start = NULL;
722 char *port_sep = NULL;
724 addr = calloc(addrlen+1, 1);
726 return CURLE_OUT_OF_MEMORY;
729 if(*string_ftpport == '[') {
730 /* [ipv6]:port(-range) */
731 ip_start = string_ftpport + 1;
732 if((ip_end = strchr(string_ftpport, ']')) != NULL )
733 strncpy(addr, ip_start, ip_end - ip_start);
737 if( *string_ftpport == ':') {
739 ip_end = string_ftpport;
741 else if( (ip_end = strchr(string_ftpport, ':')) != NULL) {
742 /* either ipv6 or (ipv4|domain|interface):port(-range) */
744 if(Curl_inet_pton(AF_INET6, string_ftpport, sa6) == 1) {
746 port_min = port_max = 0;
747 strcpy(addr, string_ftpport);
748 ip_end = NULL; /* this got no port ! */
752 /* (ipv4|domain|interface):port(-range) */
753 strncpy(addr, string_ftpport, ip_end - ip_start );
758 strcpy(addr, string_ftpport);
761 if( ip_end != NULL ) {
762 if((port_start = strchr(ip_end, ':')) != NULL) {
763 port_min = curlx_ultous(strtoul(port_start+1, NULL, 10));
764 if((port_sep = strchr(port_start, '-')) != NULL) {
765 port_max = curlx_ultous(strtoul(port_sep + 1, NULL, 10));
772 /* correct errors like:
774 * :-4711 , in this case port_min is (unsigned)-1,
775 * therefore port_min > port_max for all cases
776 * but port_max = (unsigned)-1
778 if(port_min > port_max )
779 port_min = port_max = 0;
783 /* attempt to get the address of the given interface name */
784 if(!Curl_if2ip(conn->ip_addr->ai_family, addr,
786 /* not an interface, use the given string as host name instead */
789 host = hbuf; /* use the hbuf for host name */
791 /* there was only a port(-range) given, default the host */
793 } /* data->set.ftpport */
796 /* not an interface and not a host name, get default by extracting
797 the IP from the control connection */
800 if(getsockname(conn->sock[FIRSTSOCKET], sa, &sslen)) {
801 failf(data, "getsockname() failed: %s",
802 Curl_strerror(conn, SOCKERRNO) );
805 return CURLE_FTP_PORT_FAILED;
807 switch(sa->sa_family)
811 Curl_inet_ntop(sa->sa_family, &sa6->sin6_addr, hbuf, sizeof(hbuf));
815 Curl_inet_ntop(sa->sa_family, &sa4->sin_addr, hbuf, sizeof(hbuf));
818 host = hbuf; /* use this host name */
821 /* resolv ip/host to ip */
822 rc = Curl_resolv(conn, host, 0, &h);
823 if(rc == CURLRESOLV_PENDING)
824 rc = Curl_wait_for_resolv(conn, &h);
827 /* when we return from this function, we can forget about this entry
828 to we can unlock it now already */
829 Curl_resolv_unlock(data, h);
832 res = NULL; /* failure! */
838 failf(data, "Curl_resolv failed, we can not recover!");
839 return CURLE_FTP_PORT_FAILED;
842 /* step 2, create a socket for the requested address */
844 portsock = CURL_SOCKET_BAD;
846 for (ai = res; ai; ai = ai->ai_next) {
848 * Workaround for AIX5 getaddrinfo() problem (it doesn't set ai_socktype):
850 if(ai->ai_socktype == 0)
851 ai->ai_socktype = conn->socktype;
853 portsock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
854 if(portsock == CURL_SOCKET_BAD) {
861 failf(data, "socket failure: %s", Curl_strerror(conn, error));
862 return CURLE_FTP_PORT_FAILED;
865 /* step 3, bind to a suitable local address */
867 memcpy(sa, ai->ai_addr, ai->ai_addrlen);
868 sslen = ai->ai_addrlen;
870 for( port = port_min; port <= port_max; ) {
871 if( sa->sa_family == AF_INET )
872 sa4->sin_port = htons(port);
875 sa6->sin6_port = htons(port);
877 /* Try binding the given address. */
878 if(bind(portsock, sa, sslen) ) {
881 if(error == EADDRNOTAVAIL) {
883 /* The requested bind address is not local. Use the address used for
884 * the control connection instead and restart the port loop
886 failf(data, "bind(port=%hu) failed: %s", port,
887 Curl_strerror(conn, error) );
890 if(getsockname(conn->sock[FIRSTSOCKET], sa, &sslen)) {
891 failf(data, "getsockname() failed: %s",
892 Curl_strerror(conn, SOCKERRNO) );
894 return CURLE_FTP_PORT_FAILED;
899 else if(error != EADDRINUSE && error != EACCES) {
900 failf(data, "bind(port=%hu) failed: %s", port,
901 Curl_strerror(conn, error) );
903 return CURLE_FTP_PORT_FAILED;
912 /* maybe all ports were in use already*/
913 if (port > port_max) {
914 failf(data, "bind() failed, we ran out of ports!");
916 return CURLE_FTP_PORT_FAILED;
919 /* get the name again after the bind() so that we can extract the
920 port number it uses now */
922 if(getsockname(portsock, (struct sockaddr *)sa, &sslen)) {
923 failf(data, "getsockname() failed: %s",
924 Curl_strerror(conn, SOCKERRNO) );
926 return CURLE_FTP_PORT_FAILED;
929 /* step 4, listen on the socket */
931 if(listen(portsock, 1)) {
932 failf(data, "socket failure: %s", Curl_strerror(conn, SOCKERRNO));
934 return CURLE_FTP_PORT_FAILED;
937 /* step 5, send the proper FTP command */
939 /* get a plain printable version of the numerical address to work with
941 Curl_printable_address(ai, myhost, sizeof(myhost));
944 if(!conn->bits.ftp_use_eprt && conn->bits.ipv6)
945 /* EPRT is disabled but we are connected to a IPv6 host, so we ignore the
946 request and enable EPRT again! */
947 conn->bits.ftp_use_eprt = TRUE;
950 for (; fcmd != DONE; fcmd++) {
952 if(!conn->bits.ftp_use_eprt && (EPRT == fcmd))
953 /* if disabled, goto next */
956 if((PORT == fcmd) && sa->sa_family != AF_INET)
957 /* PORT is ipv4 only */
960 switch (sa->sa_family) {
962 port = ntohs(sa4->sin_port);
966 port = ntohs(sa6->sin6_port);
970 continue; /* might as well skip this */
975 * Two fine examples from RFC2428;
977 * EPRT |1|132.235.1.2|6275|
979 * EPRT |2|1080::8:800:200C:417A|5282|
982 result = Curl_pp_sendf(&ftpc->pp, "%s |%d|%s|%hu|", mode[fcmd],
983 sa->sa_family == AF_INET?1:2,
989 else if(PORT == fcmd) {
990 char *source = myhost;
993 /* translate x.x.x.x to x,x,x,x */
994 while(source && *source) {
1003 snprintf(dest, 20, ",%d,%d", (int)(port>>8), (int)(port&0xff));
1005 result = Curl_pp_sendf(&ftpc->pp, "%s %s", mode[fcmd], tmp);
1012 /* store which command was sent */
1013 ftpc->count1 = fcmd;
1015 /* we set the secondary socket variable to this for now, it is only so that
1016 the cleanup function will close it in case we fail before the true
1017 secondary stuff is made */
1018 if(CURL_SOCKET_BAD != conn->sock[SECONDARYSOCKET])
1019 sclose(conn->sock[SECONDARYSOCKET]);
1020 conn->sock[SECONDARYSOCKET] = portsock;
1022 /* this tcpconnect assignment below is a hackish work-around to make the
1023 multi interface with active FTP work - as it will not wait for a
1024 (passive) connect in Curl_is_connected().
1026 The *proper* fix is to make sure that the active connection from the
1027 server is done in a non-blocking way. Currently, it is still BLOCKING.
1029 conn->bits.tcpconnect = TRUE;
1031 state(conn, FTP_PORT);
1035 static CURLcode ftp_state_use_pasv(struct connectdata *conn)
1037 struct ftp_conn *ftpc = &conn->proto.ftpc;
1038 CURLcode result = CURLE_OK;
1040 Here's the excecutive summary on what to do:
1042 PASV is RFC959, expect:
1043 227 Entering Passive Mode (a1,a2,a3,a4,p1,p2)
1045 LPSV is RFC1639, expect:
1046 228 Entering Long Passive Mode (4,4,a1,a2,a3,a4,2,p1,p2)
1048 EPSV is RFC2428, expect:
1049 229 Entering Extended Passive Mode (|||port|)
1053 static const char mode[][5] = { "EPSV", "PASV" };
1057 if(!conn->bits.ftp_use_epsv && conn->bits.ipv6)
1058 /* EPSV is disabled but we are connected to a IPv6 host, so we ignore the
1059 request and enable EPSV again! */
1060 conn->bits.ftp_use_epsv = TRUE;
1063 modeoff = conn->bits.ftp_use_epsv?0:1;
1065 PPSENDF(&ftpc->pp, "%s", mode[modeoff]);
1067 ftpc->count1 = modeoff;
1068 state(conn, FTP_PASV);
1069 infof(conn->data, "Connect data stream passively\n");
1074 /* REST is the last command in the chain of commands when a "head"-like
1075 request is made. Thus, if an actual transfer is to be made this is where
1076 we take off for real. */
1077 static CURLcode ftp_state_post_rest(struct connectdata *conn)
1079 CURLcode result = CURLE_OK;
1080 struct FTP *ftp = conn->data->state.proto.ftp;
1081 struct SessionHandle *data = conn->data;
1083 if(ftp->transfer != FTPTRANSFER_BODY) {
1084 /* doesn't transfer any data */
1086 /* still possibly do PRE QUOTE jobs */
1087 state(conn, FTP_RETR_PREQUOTE);
1088 result = ftp_state_quote(conn, TRUE, FTP_RETR_PREQUOTE);
1090 else if(data->set.ftp_use_port) {
1091 /* We have chosen to use the PORT (or similar) command */
1092 result = ftp_state_use_port(conn, EPRT);
1095 /* We have chosen (this is default) to use the PASV (or similar) command */
1096 if(data->set.ftp_use_pret) {
1097 /* The user has requested that we send a PRET command
1098 to prepare the server for the upcoming PASV */
1099 if(!conn->proto.ftpc.file) {
1100 PPSENDF(&conn->proto.ftpc.pp, "PRET %s",
1101 data->set.str[STRING_CUSTOMREQUEST]?
1102 data->set.str[STRING_CUSTOMREQUEST]:
1103 (data->set.ftp_list_only?"NLST":"LIST"));
1105 else if(data->set.upload) {
1106 PPSENDF(&conn->proto.ftpc.pp, "PRET STOR %s", conn->proto.ftpc.file);
1109 PPSENDF(&conn->proto.ftpc.pp, "PRET RETR %s", conn->proto.ftpc.file);
1111 state(conn, FTP_PRET);
1114 result = ftp_state_use_pasv(conn);
1120 static CURLcode ftp_state_post_size(struct connectdata *conn)
1122 CURLcode result = CURLE_OK;
1123 struct FTP *ftp = conn->data->state.proto.ftp;
1124 struct ftp_conn *ftpc = &conn->proto.ftpc;
1126 if((ftp->transfer != FTPTRANSFER_BODY) && ftpc->file) {
1127 /* if a "head"-like request is being made (on a file) */
1129 /* Determine if server can respond to REST command and therefore
1130 whether it supports range */
1131 PPSENDF(&conn->proto.ftpc.pp, "REST %d", 0);
1133 state(conn, FTP_REST);
1136 result = ftp_state_post_rest(conn);
1141 static CURLcode ftp_state_post_type(struct connectdata *conn)
1143 CURLcode result = CURLE_OK;
1144 struct FTP *ftp = conn->data->state.proto.ftp;
1145 struct ftp_conn *ftpc = &conn->proto.ftpc;
1147 if((ftp->transfer == FTPTRANSFER_INFO) && ftpc->file) {
1148 /* if a "head"-like request is being made (on a file) */
1150 /* we know ftpc->file is a valid pointer to a file name */
1151 PPSENDF(&ftpc->pp, "SIZE %s", ftpc->file);
1153 state(conn, FTP_SIZE);
1156 result = ftp_state_post_size(conn);
1161 static CURLcode ftp_state_post_listtype(struct connectdata *conn)
1163 CURLcode result = CURLE_OK;
1164 struct SessionHandle *data = conn->data;
1166 /* If this output is to be machine-parsed, the NLST command might be better
1167 to use, since the LIST command output is not specified or standard in any
1168 way. It has turned out that the NLST list output is not the same on all
1169 servers either... */
1172 if FTPFILE_NOCWD was specified, we are currently in
1173 the user's home directory, so we should add the path
1174 as argument for the LIST / NLST / or custom command.
1175 Whether the server will support this, is uncertain.
1177 The other ftp_filemethods will CWD into dir/dir/ first and
1178 then just do LIST (in that case: nothing to do here)
1180 char *cmd,*lstArg,*slashPos;
1183 if((data->set.ftp_filemethod == FTPFILE_NOCWD) &&
1185 data->state.path[0] &&
1186 strchr(data->state.path,'/')) {
1188 lstArg = strdup(data->state.path);
1190 return CURLE_OUT_OF_MEMORY;
1192 /* Check if path does not end with /, as then we cut off the file part */
1193 if(lstArg[strlen(lstArg) - 1] != '/') {
1195 /* chop off the file part if format is dir/dir/file */
1196 slashPos = strrchr(lstArg,'/');
1198 *(slashPos+1) = '\0';
1202 cmd = aprintf( "%s%s%s",
1203 data->set.str[STRING_CUSTOMREQUEST]?
1204 data->set.str[STRING_CUSTOMREQUEST]:
1205 (data->set.ftp_list_only?"NLST":"LIST"),
1207 lstArg? lstArg: "" );
1212 return CURLE_OUT_OF_MEMORY;
1215 PPSENDF(&conn->proto.ftpc.pp, "%s",cmd);
1222 state(conn, FTP_LIST);
1227 static CURLcode ftp_state_post_retrtype(struct connectdata *conn)
1229 CURLcode result = CURLE_OK;
1231 /* We've sent the TYPE, now we must send the list of prequote strings */
1233 result = ftp_state_quote(conn, TRUE, FTP_RETR_PREQUOTE);
1238 static CURLcode ftp_state_post_stortype(struct connectdata *conn)
1240 CURLcode result = CURLE_OK;
1242 /* We've sent the TYPE, now we must send the list of prequote strings */
1244 result = ftp_state_quote(conn, TRUE, FTP_STOR_PREQUOTE);
1249 static CURLcode ftp_state_post_mdtm(struct connectdata *conn)
1251 CURLcode result = CURLE_OK;
1252 struct FTP *ftp = conn->data->state.proto.ftp;
1253 struct SessionHandle *data = conn->data;
1254 struct ftp_conn *ftpc = &conn->proto.ftpc;
1256 /* If we have selected NOBODY and HEADER, it means that we only want file
1257 information. Which in FTP can't be much more than the file size and
1259 if(data->set.opt_no_body && ftpc->file &&
1260 ftp_need_type(conn, data->set.prefer_ascii)) {
1261 /* The SIZE command is _not_ RFC 959 specified, and therefor many servers
1262 may not support it! It is however the only way we have to get a file's
1265 ftp->transfer = FTPTRANSFER_INFO;
1266 /* this means no actual transfer will be made */
1268 /* Some servers return different sizes for different modes, and thus we
1269 must set the proper type before we check the size */
1270 result = ftp_nb_type(conn, data->set.prefer_ascii, FTP_TYPE);
1275 result = ftp_state_post_type(conn);
1280 /* This is called after the CWD commands have been done in the beginning of
1282 static CURLcode ftp_state_post_cwd(struct connectdata *conn)
1284 CURLcode result = CURLE_OK;
1285 struct SessionHandle *data = conn->data;
1286 struct ftp_conn *ftpc = &conn->proto.ftpc;
1288 /* Requested time of file or time-depended transfer? */
1289 if((data->set.get_filetime || data->set.timecondition) && ftpc->file) {
1291 /* we have requested to get the modified-time of the file, this is a white
1292 spot as the MDTM is not mentioned in RFC959 */
1293 PPSENDF(&ftpc->pp, "MDTM %s", ftpc->file);
1295 state(conn, FTP_MDTM);
1298 result = ftp_state_post_mdtm(conn);
1304 /* This is called after the TYPE and possible quote commands have been sent */
1305 static CURLcode ftp_state_ul_setup(struct connectdata *conn,
1308 CURLcode result = CURLE_OK;
1309 struct FTP *ftp = conn->data->state.proto.ftp;
1310 struct SessionHandle *data = conn->data;
1311 struct ftp_conn *ftpc = &conn->proto.ftpc;
1312 int seekerr = CURL_SEEKFUNC_OK;
1314 if((data->state.resume_from && !sizechecked) ||
1315 ((data->state.resume_from > 0) && sizechecked)) {
1316 /* we're about to continue the uploading of a file */
1317 /* 1. get already existing file's size. We use the SIZE command for this
1318 which may not exist in the server! The SIZE command is not in
1321 /* 2. This used to set REST. But since we can do append, we
1322 don't another ftp command. We just skip the source file
1323 offset and then we APPEND the rest on the file instead */
1325 /* 3. pass file-size number of bytes in the source file */
1326 /* 4. lower the infilesize counter */
1327 /* => transfer as usual */
1329 if(data->state.resume_from < 0 ) {
1330 /* Got no given size to start from, figure it out */
1331 PPSENDF(&ftpc->pp, "SIZE %s", ftpc->file);
1332 state(conn, FTP_STOR_SIZE);
1337 data->set.ftp_append = TRUE;
1339 /* Let's read off the proper amount of bytes from the input. */
1340 if(conn->seek_func) {
1341 seekerr = conn->seek_func(conn->seek_client, data->state.resume_from,
1345 if(seekerr != CURL_SEEKFUNC_OK) {
1346 if(seekerr != CURL_SEEKFUNC_CANTSEEK) {
1347 failf(data, "Could not seek stream");
1348 return CURLE_FTP_COULDNT_USE_REST;
1350 /* seekerr == CURL_SEEKFUNC_CANTSEEK (can't seek to offset) */
1352 curl_off_t passed=0;
1354 curl_off_t readthisamountnow = (data->state.resume_from - passed);
1355 curl_off_t actuallyread;
1357 if(readthisamountnow > BUFSIZE)
1358 readthisamountnow = BUFSIZE;
1360 actuallyread = (curl_off_t)
1361 conn->fread_func(data->state.buffer, 1, (size_t)readthisamountnow,
1364 passed += actuallyread;
1365 if((actuallyread <= 0) || (actuallyread > readthisamountnow)) {
1366 /* this checks for greater-than only to make sure that the
1367 CURL_READFUNC_ABORT return code still aborts */
1368 failf(data, "Failed to read data");
1369 return CURLE_FTP_COULDNT_USE_REST;
1371 } while(passed < data->state.resume_from);
1374 /* now, decrease the size of the read */
1375 if(data->set.infilesize>0) {
1376 data->set.infilesize -= data->state.resume_from;
1378 if(data->set.infilesize <= 0) {
1379 infof(data, "File already completely uploaded\n");
1381 /* no data to transfer */
1382 result=Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
1384 /* Set ->transfer so that we won't get any error in
1385 * ftp_done() because we didn't transfer anything! */
1386 ftp->transfer = FTPTRANSFER_NONE;
1388 state(conn, FTP_STOP);
1392 /* we've passed, proceed as normal */
1395 PPSENDF(&ftpc->pp, data->set.ftp_append?"APPE %s":"STOR %s",
1398 state(conn, FTP_STOR);
1403 static CURLcode ftp_state_quote(struct connectdata *conn,
1407 CURLcode result = CURLE_OK;
1408 struct SessionHandle *data = conn->data;
1409 struct FTP *ftp = data->state.proto.ftp;
1410 struct ftp_conn *ftpc = &conn->proto.ftpc;
1412 struct curl_slist *item;
1417 item = data->set.quote;
1419 case FTP_RETR_PREQUOTE:
1420 case FTP_STOR_PREQUOTE:
1421 item = data->set.prequote;
1424 item = data->set.postquote;
1436 /* Skip count1 items in the linked list */
1437 while((i< ftpc->count1) && item) {
1442 PPSENDF(&ftpc->pp, "%s", item->data);
1443 state(conn, instate);
1449 /* No more quote to send, continue to ... */
1453 result = ftp_state_cwd(conn);
1455 case FTP_RETR_PREQUOTE:
1456 if(ftp->transfer != FTPTRANSFER_BODY)
1457 state(conn, FTP_STOP);
1459 PPSENDF(&ftpc->pp, "SIZE %s", ftpc->file);
1460 state(conn, FTP_RETR_SIZE);
1463 case FTP_STOR_PREQUOTE:
1464 result = ftp_state_ul_setup(conn, FALSE);
1474 static CURLcode ftp_state_pasv_resp(struct connectdata *conn,
1477 struct ftp_conn *ftpc = &conn->proto.ftpc;
1479 struct SessionHandle *data=conn->data;
1480 Curl_addrinfo *conninfo;
1481 struct Curl_dns_entry *addr=NULL;
1483 unsigned short connectport; /* the local port connect() should use! */
1484 unsigned short newport=0; /* remote port */
1487 /* newhost must be able to hold a full IP-style address in ASCII, which
1488 in the IPv6 case means 5*8-1 = 39 letters */
1489 #define NEWHOST_BUFSIZE 48
1490 char newhost[NEWHOST_BUFSIZE];
1491 char *str=&data->state.buffer[4]; /* start on the first letter */
1493 if((ftpc->count1 == 0) &&
1495 /* positive EPSV response */
1496 char *ptr = strchr(str, '(');
1501 if(5 == sscanf(ptr, "%c%c%c%u%c",
1507 const char sep1 = separator[0];
1510 /* The four separators should be identical, or else this is an oddly
1511 formatted reply and we bail out immediately. */
1512 for(i=1; i<4; i++) {
1513 if(separator[i] != sep1) {
1514 ptr=NULL; /* set to NULL to signal error */
1519 newport = (unsigned short)(num & 0xffff);
1521 if(conn->bits.tunnel_proxy ||
1522 data->set.proxytype == CURLPROXY_SOCKS5 ||
1523 data->set.proxytype == CURLPROXY_SOCKS5_HOSTNAME ||
1524 data->set.proxytype == CURLPROXY_SOCKS4 ||
1525 data->set.proxytype == CURLPROXY_SOCKS4A)
1526 /* proxy tunnel -> use other host info because ip_addr_str is the
1527 proxy address not the ftp host */
1528 snprintf(newhost, sizeof(newhost), "%s", conn->host.name);
1530 /* use the same IP we are already connected to */
1531 snprintf(newhost, NEWHOST_BUFSIZE, "%s", conn->ip_addr_str);
1538 failf(data, "Weirdly formatted EPSV reply");
1539 return CURLE_FTP_WEIRD_PASV_REPLY;
1542 else if((ftpc->count1 == 1) &&
1544 /* positive PASV response */
1549 * Scan for a sequence of six comma-separated numbers and use them as
1550 * IP+port indicators.
1552 * Found reply-strings include:
1553 * "227 Entering Passive Mode (127,0,0,1,4,51)"
1554 * "227 Data transfer will passively listen to 127,0,0,1,4,51"
1555 * "227 Entering passive mode. 127,0,0,1,4,51"
1558 if(6 == sscanf(str, "%d,%d,%d,%d,%d,%d",
1559 &ip[0], &ip[1], &ip[2], &ip[3],
1560 &port[0], &port[1]))
1566 failf(data, "Couldn't interpret the 227-response");
1567 return CURLE_FTP_WEIRD_227_FORMAT;
1570 /* we got OK from server */
1571 if(data->set.ftp_skip_ip) {
1572 /* told to ignore the remotely given IP but instead use the one we used
1573 for the control connection */
1574 infof(data, "Skips %d.%d.%d.%d for data connection, uses %s instead\n",
1575 ip[0], ip[1], ip[2], ip[3],
1577 if(conn->bits.tunnel_proxy ||
1578 data->set.proxytype == CURLPROXY_SOCKS5 ||
1579 data->set.proxytype == CURLPROXY_SOCKS5_HOSTNAME ||
1580 data->set.proxytype == CURLPROXY_SOCKS4 ||
1581 data->set.proxytype == CURLPROXY_SOCKS4A)
1582 /* proxy tunnel -> use other host info because ip_addr_str is the
1583 proxy address not the ftp host */
1584 snprintf(newhost, sizeof(newhost), "%s", conn->host.name);
1586 snprintf(newhost, sizeof(newhost), "%s", conn->ip_addr_str);
1589 snprintf(newhost, sizeof(newhost),
1590 "%d.%d.%d.%d", ip[0], ip[1], ip[2], ip[3]);
1591 newport = (unsigned short)(((port[0]<<8) + port[1]) & 0xffff);
1593 else if(ftpc->count1 == 0) {
1594 /* EPSV failed, move on to PASV */
1596 /* disable it for next transfer */
1597 conn->bits.ftp_use_epsv = FALSE;
1598 infof(data, "disabling EPSV usage\n");
1600 PPSENDF(&ftpc->pp, "PASV", NULL);
1602 /* remain in the FTP_PASV state */
1606 failf(data, "Bad PASV/EPSV response: %03d", ftpcode);
1607 return CURLE_FTP_WEIRD_PASV_REPLY;
1610 if(data->set.str[STRING_PROXY] && *data->set.str[STRING_PROXY]) {
1612 * This is a tunnel through a http proxy and we need to connect to the
1615 * We don't want to rely on a former host lookup that might've expired
1616 * now, instead we remake the lookup here and now!
1618 rc = Curl_resolv(conn, conn->proxy.name, (int)conn->port, &addr);
1619 if(rc == CURLRESOLV_PENDING)
1621 rc = Curl_wait_for_resolv(conn, &addr);
1624 (unsigned short)conn->port; /* we connect to the proxy's port */
1627 failf(data, "Can't resolve proxy host %s:%hu",
1628 conn->proxy.name, connectport);
1629 return CURLE_FTP_CANT_GET_HOST;
1633 /* normal, direct, ftp connection */
1634 rc = Curl_resolv(conn, newhost, newport, &addr);
1635 if(rc == CURLRESOLV_PENDING)
1637 rc = Curl_wait_for_resolv(conn, &addr);
1639 connectport = newport; /* we connect to the remote port */
1642 failf(data, "Can't resolve new host %s:%hu", newhost, connectport);
1643 return CURLE_FTP_CANT_GET_HOST;
1647 result = Curl_connecthost(conn,
1649 &conn->sock[SECONDARYSOCKET],
1653 Curl_resolv_unlock(data, addr); /* we're done using this address */
1655 if(result && ftpc->count1 == 0 && ftpcode == 229) {
1656 infof(data, "got positive EPSV response, but can't connect. "
1657 "Disabling EPSV\n");
1658 /* disable it for next transfer */
1659 conn->bits.ftp_use_epsv = FALSE;
1660 data->state.errorbuf = FALSE; /* allow error message to get rewritten */
1661 PPSENDF(&ftpc->pp, "PASV", NULL);
1663 /* remain in the FTP_PASV state */
1670 conn->bits.tcpconnect = connected; /* simply TRUE or FALSE */
1673 * When this is used from the multi interface, this might've returned with
1674 * the 'connected' set to FALSE and thus we are now awaiting a non-blocking
1675 * connect to connect and we should not be "hanging" here waiting.
1678 if(data->set.verbose)
1679 /* this just dumps information about this second connection */
1680 ftp_pasv_verbose(conn, conninfo, newhost, connectport);
1682 switch(data->set.proxytype) {
1683 #ifndef CURL_DISABLE_PROXY
1684 /* FIX: this MUST wait for a proper connect first if 'connected' is
1686 case CURLPROXY_SOCKS5:
1687 case CURLPROXY_SOCKS5_HOSTNAME:
1688 result = Curl_SOCKS5(conn->proxyuser, conn->proxypasswd, newhost, newport,
1689 SECONDARYSOCKET, conn);
1691 case CURLPROXY_SOCKS4:
1692 result = Curl_SOCKS4(conn->proxyuser, newhost, newport,
1693 SECONDARYSOCKET, conn, FALSE);
1695 case CURLPROXY_SOCKS4A:
1696 result = Curl_SOCKS4(conn->proxyuser, newhost, newport,
1697 SECONDARYSOCKET, conn, TRUE);
1699 #endif /* CURL_DISABLE_PROXY */
1700 case CURLPROXY_HTTP:
1701 case CURLPROXY_HTTP_1_0:
1702 /* do nothing here. handled later. */
1705 failf(data, "unknown proxytype option given");
1706 result = CURLE_COULDNT_CONNECT;
1709 #if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_PROXY)
1710 if(conn->bits.tunnel_proxy && conn->bits.httpproxy) {
1711 /* FIX: this MUST wait for a proper connect first if 'connected' is
1715 /* We want "seamless" FTP operations through HTTP proxy tunnel */
1717 /* Curl_proxyCONNECT is based on a pointer to a struct HTTP at the member
1718 * conn->proto.http; we want FTP through HTTP and we have to change the
1719 * member temporarily for connecting to the HTTP proxy. After
1720 * Curl_proxyCONNECT we have to set back the member to the original struct
1723 struct HTTP http_proxy;
1724 struct FTP *ftp_save = data->state.proto.ftp;
1725 memset(&http_proxy, 0, sizeof(http_proxy));
1726 data->state.proto.http = &http_proxy;
1728 result = Curl_proxyCONNECT(conn, SECONDARYSOCKET, newhost, newport);
1730 data->state.proto.ftp = ftp_save;
1732 if(CURLE_OK != result)
1735 #endif /* !CURL_DISABLE_HTTP && !CURL_DISABLE_PROXY */
1737 state(conn, FTP_STOP); /* this phase is completed */
1742 static CURLcode ftp_state_port_resp(struct connectdata *conn,
1745 struct SessionHandle *data = conn->data;
1746 struct ftp_conn *ftpc = &conn->proto.ftpc;
1747 ftpport fcmd = (ftpport)ftpc->count1;
1748 CURLcode result = CURLE_OK;
1750 if(ftpcode != 200) {
1751 /* the command failed */
1754 infof(data, "disabling EPRT usage\n");
1755 conn->bits.ftp_use_eprt = FALSE;
1760 failf(data, "Failed to do PORT");
1761 result = CURLE_FTP_PORT_FAILED;
1765 result = ftp_state_use_port(conn, fcmd);
1768 infof(data, "Connect data stream actively\n");
1769 state(conn, FTP_STOP); /* end of DO phase */
1775 static CURLcode ftp_state_mdtm_resp(struct connectdata *conn,
1778 CURLcode result = CURLE_OK;
1779 struct SessionHandle *data=conn->data;
1780 struct FTP *ftp = data->state.proto.ftp;
1781 struct ftp_conn *ftpc = &conn->proto.ftpc;
1786 /* we got a time. Format should be: "YYYYMMDDHHMMSS[.sss]" where the
1787 last .sss part is optional and means fractions of a second */
1788 int year, month, day, hour, minute, second;
1789 char *buf = data->state.buffer;
1790 if(6 == sscanf(buf+4, "%04d%02d%02d%02d%02d%02d",
1791 &year, &month, &day, &hour, &minute, &second)) {
1792 /* we have a time, reformat it */
1793 time_t secs=time(NULL);
1794 /* using the good old yacc/bison yuck */
1795 snprintf(buf, sizeof(conn->data->state.buffer),
1796 "%04d%02d%02d %02d:%02d:%02d GMT",
1797 year, month, day, hour, minute, second);
1798 /* now, convert this into a time() value: */
1799 data->info.filetime = (long)curl_getdate(buf, &secs);
1802 #ifdef CURL_FTP_HTTPSTYLE_HEAD
1803 /* If we asked for a time of the file and we actually got one as well,
1804 we "emulate" a HTTP-style header in our output. */
1806 if(data->set.opt_no_body &&
1808 data->set.get_filetime &&
1809 (data->info.filetime>=0) ) {
1811 time_t filetime = (time_t)data->info.filetime;
1812 #ifdef HAVE_GMTIME_R
1814 tm = (struct tm *)gmtime_r(&filetime, &buffer);
1816 tm = gmtime(&filetime);
1818 /* format: "Tue, 15 Nov 1994 12:45:26" */
1819 snprintf(buf, BUFSIZE-1,
1820 "Last-Modified: %s, %02d %s %4d %02d:%02d:%02d GMT\r\n",
1821 Curl_wkday[tm->tm_wday?tm->tm_wday-1:6],
1823 Curl_month[tm->tm_mon],
1828 result = Curl_client_write(conn, CLIENTWRITE_BOTH, buf, 0);
1831 } /* end of a ridiculous amount of conditionals */
1836 infof(data, "unsupported MDTM reply format\n");
1838 case 550: /* "No such file or directory" */
1839 failf(data, "Given file does not exist");
1840 result = CURLE_FTP_COULDNT_RETR_FILE;
1844 if(data->set.timecondition) {
1845 if((data->info.filetime > 0) && (data->set.timevalue > 0)) {
1846 switch(data->set.timecondition) {
1847 case CURL_TIMECOND_IFMODSINCE:
1849 if(data->info.filetime <= data->set.timevalue) {
1850 infof(data, "The requested document is not new enough\n");
1851 ftp->transfer = FTPTRANSFER_NONE; /* mark to not transfer data */
1852 data->info.timecond = TRUE;
1853 state(conn, FTP_STOP);
1857 case CURL_TIMECOND_IFUNMODSINCE:
1858 if(data->info.filetime > data->set.timevalue) {
1859 infof(data, "The requested document is not old enough\n");
1860 ftp->transfer = FTPTRANSFER_NONE; /* mark to not transfer data */
1861 data->info.timecond = TRUE;
1862 state(conn, FTP_STOP);
1869 infof(data, "Skipping time comparison\n");
1874 result = ftp_state_post_mdtm(conn);
1879 static CURLcode ftp_state_type_resp(struct connectdata *conn,
1883 CURLcode result = CURLE_OK;
1884 struct SessionHandle *data=conn->data;
1886 if(ftpcode/100 != 2) {
1887 /* "sasserftpd" and "(u)r(x)bot ftpd" both responds with 226 after a
1888 successful 'TYPE I'. While that is not as RFC959 says, it is still a
1889 positive response code and we allow that. */
1890 failf(data, "Couldn't set desired mode");
1891 return CURLE_FTP_COULDNT_SET_TYPE;
1894 infof(data, "Got a %03d response code instead of the assumed 200\n",
1897 if(instate == FTP_TYPE)
1898 result = ftp_state_post_type(conn);
1899 else if(instate == FTP_LIST_TYPE)
1900 result = ftp_state_post_listtype(conn);
1901 else if(instate == FTP_RETR_TYPE)
1902 result = ftp_state_post_retrtype(conn);
1903 else if(instate == FTP_STOR_TYPE)
1904 result = ftp_state_post_stortype(conn);
1909 static CURLcode ftp_state_post_retr_size(struct connectdata *conn,
1910 curl_off_t filesize)
1912 CURLcode result = CURLE_OK;
1913 struct SessionHandle *data=conn->data;
1914 struct FTP *ftp = data->state.proto.ftp;
1915 struct ftp_conn *ftpc = &conn->proto.ftpc;
1917 if(data->set.max_filesize && (filesize > data->set.max_filesize)) {
1918 failf(data, "Maximum file size exceeded");
1919 return CURLE_FILESIZE_EXCEEDED;
1921 ftp->downloadsize = filesize;
1923 if(data->state.resume_from) {
1924 /* We always (attempt to) get the size of downloads, so it is done before
1925 this even when not doing resumes. */
1926 if(filesize == -1) {
1927 infof(data, "ftp server doesn't support SIZE\n");
1928 /* We couldn't get the size and therefore we can't know if there really
1929 is a part of the file left to get, although the server will just
1930 close the connection when we start the connection so it won't cause
1931 us any harm, just not make us exit as nicely. */
1934 /* We got a file size report, so we check that there actually is a
1935 part of the file left to get, or else we go home. */
1936 if(data->state.resume_from< 0) {
1937 /* We're supposed to download the last abs(from) bytes */
1938 if(filesize < -data->state.resume_from) {
1939 failf(data, "Offset (%" FORMAT_OFF_T
1940 ") was beyond file size (%" FORMAT_OFF_T ")",
1941 data->state.resume_from, filesize);
1942 return CURLE_BAD_DOWNLOAD_RESUME;
1944 /* convert to size to download */
1945 ftp->downloadsize = -data->state.resume_from;
1946 /* download from where? */
1947 data->state.resume_from = filesize - ftp->downloadsize;
1950 if(filesize < data->state.resume_from) {
1951 failf(data, "Offset (%" FORMAT_OFF_T
1952 ") was beyond file size (%" FORMAT_OFF_T ")",
1953 data->state.resume_from, filesize);
1954 return CURLE_BAD_DOWNLOAD_RESUME;
1956 /* Now store the number of bytes we are expected to download */
1957 ftp->downloadsize = filesize-data->state.resume_from;
1961 if(ftp->downloadsize == 0) {
1962 /* no data to transfer */
1963 result = Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
1964 infof(data, "File already completely downloaded\n");
1966 /* Set ->transfer so that we won't get any error in ftp_done()
1967 * because we didn't transfer the any file */
1968 ftp->transfer = FTPTRANSFER_NONE;
1969 state(conn, FTP_STOP);
1973 /* Set resume file transfer offset */
1974 infof(data, "Instructs server to resume from offset %" FORMAT_OFF_T
1975 "\n", data->state.resume_from);
1977 PPSENDF(&ftpc->pp, "REST %" FORMAT_OFF_T, data->state.resume_from);
1979 state(conn, FTP_RETR_REST);
1984 PPSENDF(&ftpc->pp, "RETR %s", ftpc->file);
1985 state(conn, FTP_RETR);
1991 static CURLcode ftp_state_size_resp(struct connectdata *conn,
1995 CURLcode result = CURLE_OK;
1996 struct SessionHandle *data=conn->data;
1997 curl_off_t filesize;
1998 char *buf = data->state.buffer;
2000 /* get the size from the ascii string: */
2001 filesize = (ftpcode == 213)?curlx_strtoofft(buf+4, NULL, 0):-1;
2003 if(instate == FTP_SIZE) {
2004 #ifdef CURL_FTP_HTTPSTYLE_HEAD
2005 if(-1 != filesize) {
2006 snprintf(buf, sizeof(data->state.buffer),
2007 "Content-Length: %" FORMAT_OFF_T "\r\n", filesize);
2008 result = Curl_client_write(conn, CLIENTWRITE_BOTH, buf, 0);
2013 Curl_pgrsSetDownloadSize(data, filesize);
2014 result = ftp_state_post_size(conn);
2016 else if(instate == FTP_RETR_SIZE) {
2017 Curl_pgrsSetDownloadSize(data, filesize);
2018 result = ftp_state_post_retr_size(conn, filesize);
2020 else if(instate == FTP_STOR_SIZE) {
2021 data->state.resume_from = filesize;
2022 result = ftp_state_ul_setup(conn, TRUE);
2028 static CURLcode ftp_state_rest_resp(struct connectdata *conn,
2032 CURLcode result = CURLE_OK;
2033 struct ftp_conn *ftpc = &conn->proto.ftpc;
2038 #ifdef CURL_FTP_HTTPSTYLE_HEAD
2039 if(ftpcode == 350) {
2040 char buffer[24]= { "Accept-ranges: bytes\r\n" };
2041 result = Curl_client_write(conn, CLIENTWRITE_BOTH, buffer, 0);
2046 result = ftp_state_post_rest(conn);
2050 if(ftpcode != 350) {
2051 failf(conn->data, "Couldn't use REST");
2052 result = CURLE_FTP_COULDNT_USE_REST;
2055 PPSENDF(&ftpc->pp, "RETR %s", ftpc->file);
2056 state(conn, FTP_RETR);
2064 static CURLcode ftp_state_stor_resp(struct connectdata *conn,
2067 CURLcode result = CURLE_OK;
2068 struct SessionHandle *data = conn->data;
2069 struct FTP *ftp = data->state.proto.ftp;
2072 failf(data, "Failed FTP upload: %0d", ftpcode);
2073 /* oops, we never close the sockets! */
2074 return CURLE_UPLOAD_FAILED;
2077 if(data->set.ftp_use_port) {
2079 /* PORT means we are now awaiting the server to connect to us. */
2080 result = AllowServerConnect(conn);
2085 if(conn->ssl[SECONDARYSOCKET].use) {
2086 /* since we only have a plaintext TCP connection here, we must now
2088 infof(data, "Doing the SSL/TLS handshake on the data stream\n");
2090 result = Curl_ssl_connect(conn, SECONDARYSOCKET);
2095 *(ftp->bytecountp)=0;
2097 /* When we know we're uploading a specified file, we can get the file
2098 size prior to the actual upload. */
2100 Curl_pgrsSetUploadSize(data, data->set.infilesize);
2102 /* set the SO_SNDBUF for the secondary socket for those who need it */
2103 Curl_sndbufset(conn->sock[SECONDARYSOCKET]);
2105 result = Curl_setup_transfer(conn, -1, -1, FALSE, NULL, /* no download */
2106 SECONDARYSOCKET, ftp->bytecountp);
2107 state(conn, FTP_STOP);
2109 conn->proto.ftpc.pp.pending_resp = TRUE; /* expect a server response */
2114 /* for LIST and RETR responses */
2115 static CURLcode ftp_state_get_resp(struct connectdata *conn,
2119 CURLcode result = CURLE_OK;
2120 struct SessionHandle *data = conn->data;
2121 struct FTP *ftp = data->state.proto.ftp;
2122 char *buf = data->state.buffer;
2124 if((ftpcode == 150) || (ftpcode == 125)) {
2128 150 Opening BINARY mode data connection for /etc/passwd (2241
2129 bytes). (ok, the file is being transfered)
2132 150 Opening ASCII mode data connection for /bin/ls
2135 150 ASCII data connection for /bin/ls (137.167.104.91,37445) (0 bytes).
2138 150 Opening ASCII mode data connection for /linux/fisk/kpanelrc (0.0.0.0,0) (545 bytes).
2141 125 Data connection already open; Transfer starting. */
2143 curl_off_t size=-1; /* default unknown size */
2147 * It appears that there are FTP-servers that return size 0 for files when
2148 * SIZE is used on the file while being in BINARY mode. To work around
2149 * that (stupid) behavior, we attempt to parse the RETR response even if
2150 * the SIZE returned size zero.
2152 * Debugging help from Salvatore Sorrentino on February 26, 2003.
2155 if((instate != FTP_LIST) &&
2156 !data->set.prefer_ascii &&
2157 (ftp->downloadsize < 1)) {
2159 * It seems directory listings either don't show the size or very
2160 * often uses size 0 anyway. ASCII transfers may very well turn out
2161 * that the transfered amount of data is not the same as this line
2162 * tells, why using this number in those cases only confuses us.
2164 * Example D above makes this parsing a little tricky */
2166 bytes=strstr(buf, " bytes");
2168 long in=(long)(bytes-buf);
2169 /* this is a hint there is size information in there! ;-) */
2171 /* scan for the left parenthesis and break there */
2174 /* skip only digits */
2175 if(!ISDIGIT(*bytes)) {
2179 /* one more estep backwards */
2182 /* if we have nothing but digits: */
2184 /* get the number! */
2185 size = curlx_strtoofft(bytes, NULL, 0);
2189 else if(ftp->downloadsize > -1)
2190 size = ftp->downloadsize;
2192 if(data->set.ftp_use_port) {
2194 result = AllowServerConnect(conn);
2199 if(conn->ssl[SECONDARYSOCKET].use) {
2200 /* since we only have a plaintext TCP connection here, we must now
2202 infof(data, "Doing the SSL/TLS handshake on the data stream\n");
2203 result = Curl_ssl_connect(conn, SECONDARYSOCKET);
2208 if(size > data->req.maxdownload && data->req.maxdownload > 0)
2209 size = data->req.size = data->req.maxdownload;
2210 else if((instate != FTP_LIST) && (data->set.prefer_ascii))
2211 size = -1; /* kludge for servers that understate ASCII mode file size */
2213 infof(data, "Maxdownload = %" FORMAT_OFF_T "\n", data->req.maxdownload);
2215 if(instate != FTP_LIST)
2216 infof(data, "Getting file with size: %" FORMAT_OFF_T "\n", size);
2219 result=Curl_setup_transfer(conn, SECONDARYSOCKET, size, FALSE,
2221 -1, NULL); /* no upload here */
2225 conn->proto.ftpc.pp.pending_resp = TRUE; /* expect server response */
2226 state(conn, FTP_STOP);
2229 if((instate == FTP_LIST) && (ftpcode == 450)) {
2230 /* simply no matching files in the dir listing */
2231 ftp->transfer = FTPTRANSFER_NONE; /* don't download anything */
2232 state(conn, FTP_STOP); /* this phase is over */
2235 failf(data, "RETR response: %03d", ftpcode);
2236 return instate == FTP_RETR && ftpcode == 550?
2237 CURLE_REMOTE_FILE_NOT_FOUND:
2238 CURLE_FTP_COULDNT_RETR_FILE;
2245 /* after USER, PASS and ACCT */
2246 static CURLcode ftp_state_loggedin(struct connectdata *conn)
2248 CURLcode result = CURLE_OK;
2251 if(conn->data->set.krb) {
2252 /* We may need to issue a KAUTH here to have access to the files
2253 * do it if user supplied a password
2255 if(conn->passwd && *conn->passwd) {
2257 result = Curl_krb_kauth(conn);
2263 if(conn->ssl[FIRSTSOCKET].use) {
2264 /* PBSZ = PROTECTION BUFFER SIZE.
2266 The 'draft-murray-auth-ftp-ssl' (draft 12, page 7) says:
2268 Specifically, the PROT command MUST be preceded by a PBSZ
2269 command and a PBSZ command MUST be preceded by a successful
2270 security data exchange (the TLS negotiation in this case)
2272 ... (and on page 8):
2274 Thus the PBSZ command must still be issued, but must have a
2275 parameter of '0' to indicate that no buffering is taking place
2276 and the data connection should not be encapsulated.
2278 PPSENDF(&conn->proto.ftpc.pp, "PBSZ %d", 0);
2279 state(conn, FTP_PBSZ);
2282 result = ftp_state_pwd(conn);
2287 /* for USER and PASS responses */
2288 static CURLcode ftp_state_user_resp(struct connectdata *conn,
2292 CURLcode result = CURLE_OK;
2293 struct SessionHandle *data = conn->data;
2294 struct FTP *ftp = data->state.proto.ftp;
2295 struct ftp_conn *ftpc = &conn->proto.ftpc;
2296 (void)instate; /* no use for this yet */
2298 /* some need password anyway, and others just return 2xx ignored */
2299 if((ftpcode == 331) && (ftpc->state == FTP_USER)) {
2300 /* 331 Password required for ...
2301 (the server requires to send the user's password too) */
2302 PPSENDF(&ftpc->pp, "PASS %s", ftp->passwd?ftp->passwd:"");
2303 state(conn, FTP_PASS);
2305 else if(ftpcode/100 == 2) {
2306 /* 230 User ... logged in.
2307 (the user logged in with or without password) */
2308 result = ftp_state_loggedin(conn);
2310 else if(ftpcode == 332) {
2311 if(data->set.str[STRING_FTP_ACCOUNT]) {
2312 PPSENDF(&ftpc->pp, "ACCT %s", data->set.str[STRING_FTP_ACCOUNT]);
2313 state(conn, FTP_ACCT);
2316 failf(data, "ACCT requested but none available");
2317 result = CURLE_LOGIN_DENIED;
2321 /* All other response codes, like:
2323 530 User ... access denied
2324 (the server denies to log the specified user) */
2326 if(conn->data->set.str[STRING_FTP_ALTERNATIVE_TO_USER] &&
2327 !conn->data->state.ftp_trying_alternative) {
2328 /* Ok, USER failed. Let's try the supplied command. */
2329 PPSENDF(&conn->proto.ftpc.pp, "%s",
2330 conn->data->set.str[STRING_FTP_ALTERNATIVE_TO_USER]);
2331 conn->data->state.ftp_trying_alternative = TRUE;
2332 state(conn, FTP_USER);
2336 failf(data, "Access denied: %03d", ftpcode);
2337 result = CURLE_LOGIN_DENIED;
2343 /* for ACCT response */
2344 static CURLcode ftp_state_acct_resp(struct connectdata *conn,
2347 CURLcode result = CURLE_OK;
2348 struct SessionHandle *data = conn->data;
2349 if(ftpcode != 230) {
2350 failf(data, "ACCT rejected by server: %03d", ftpcode);
2351 result = CURLE_FTP_WEIRD_PASS_REPLY; /* FIX */
2354 result = ftp_state_loggedin(conn);
2360 static CURLcode ftp_statemach_act(struct connectdata *conn)
2363 curl_socket_t sock = conn->sock[FIRSTSOCKET];
2364 struct SessionHandle *data=conn->data;
2366 struct ftp_conn *ftpc = &conn->proto.ftpc;
2367 struct pingpong *pp = &ftpc->pp;
2368 static const char ftpauth[][4] = { "SSL", "TLS" };
2372 return Curl_pp_flushsend(pp);
2374 /* we read a piece of response */
2375 result = ftp_readresp(sock, pp, &ftpcode, &nread);
2380 /* we have now received a full FTP server response */
2381 switch(ftpc->state) {
2383 if(ftpcode != 220) {
2384 failf(data, "Got a %03d ftp-server response when 220 was expected",
2386 return CURLE_FTP_WEIRD_SERVER_REPLY;
2389 /* We have received a 220 response fine, now we proceed. */
2390 #if defined(HAVE_KRB4) || defined(HAVE_GSSAPI)
2392 /* If not anonymous login, try a secure login. Note that this
2393 procedure is still BLOCKING. */
2395 Curl_sec_request_prot(conn, "private");
2396 /* We set private first as default, in case the line below fails to
2397 set a valid level */
2398 Curl_sec_request_prot(conn, data->set.str[STRING_KRB_LEVEL]);
2400 if(Curl_sec_login(conn) != 0)
2401 infof(data, "Logging in with password in cleartext!\n");
2403 infof(data, "Authentication successful\n");
2407 if(data->set.ftp_ssl && !conn->ssl[FIRSTSOCKET].use) {
2408 /* We don't have a SSL/TLS connection yet, but FTPS is
2409 requested. Try a FTPS connection now */
2412 switch(data->set.ftpsslauth) {
2413 case CURLFTPAUTH_DEFAULT:
2414 case CURLFTPAUTH_SSL:
2415 ftpc->count2 = 1; /* add one to get next */
2418 case CURLFTPAUTH_TLS:
2419 ftpc->count2 = -1; /* subtract one to get next */
2423 failf(data, "unsupported parameter to CURLOPT_FTPSSLAUTH: %d",
2424 (int)data->set.ftpsslauth);
2425 return CURLE_FAILED_INIT; /* we don't know what to do */
2427 PPSENDF(&ftpc->pp, "AUTH %s", ftpauth[ftpc->count1]);
2428 state(conn, FTP_AUTH);
2431 result = ftp_state_user(conn);
2439 /* we have gotten the response to a previous AUTH command */
2441 /* RFC2228 (page 5) says:
2443 * If the server is willing to accept the named security mechanism,
2444 * and does not require any security data, it must respond with
2445 * reply code 234/334.
2448 if((ftpcode == 234) || (ftpcode == 334)) {
2449 /* Curl_ssl_connect is BLOCKING */
2450 result = Curl_ssl_connect(conn, FIRSTSOCKET);
2451 if(CURLE_OK == result) {
2452 conn->protocol |= PROT_FTPS;
2453 conn->ssl[SECONDARYSOCKET].use = FALSE; /* clear-text data */
2454 result = ftp_state_user(conn);
2457 else if(ftpc->count3 < 1) {
2459 ftpc->count1 += ftpc->count2; /* get next attempt */
2460 result = Curl_pp_sendf(&ftpc->pp, "AUTH %s", ftpauth[ftpc->count1]);
2461 /* remain in this same state */
2464 if(data->set.ftp_ssl > CURLUSESSL_TRY)
2465 /* we failed and CURLUSESSL_CONTROL or CURLUSESSL_ALL is set */
2466 result = CURLE_USE_SSL_FAILED;
2468 /* ignore the failure and continue */
2469 result = ftp_state_user(conn);
2478 result = ftp_state_user_resp(conn, ftpcode, ftpc->state);
2482 result = ftp_state_acct_resp(conn, ftpcode);
2486 PPSENDF(&ftpc->pp, "PROT %c",
2487 data->set.ftp_ssl == CURLUSESSL_CONTROL ? 'C' : 'P');
2488 state(conn, FTP_PROT);
2493 if(ftpcode/100 == 2)
2494 /* We have enabled SSL for the data connection! */
2495 conn->ssl[SECONDARYSOCKET].use =
2496 (bool)(data->set.ftp_ssl != CURLUSESSL_CONTROL);
2497 /* FTP servers typically responds with 500 if they decide to reject
2499 else if(data->set.ftp_ssl > CURLUSESSL_CONTROL)
2500 /* we failed and bails out */
2501 return CURLE_USE_SSL_FAILED;
2503 if(data->set.ftp_ccc) {
2504 /* CCC - Clear Command Channel
2506 PPSENDF(&ftpc->pp, "CCC", NULL);
2507 state(conn, FTP_CCC);
2510 result = ftp_state_pwd(conn);
2518 /* First shut down the SSL layer (note: this call will block) */
2519 result = Curl_ssl_shutdown(conn, FIRSTSOCKET);
2522 failf(conn->data, "Failed to clear the command channel (CCC)");
2527 /* Then continue as normal */
2528 result = ftp_state_pwd(conn);
2534 if(ftpcode == 257) {
2535 char *ptr=&data->state.buffer[4]; /* start on the first letter */
2539 dir = malloc(nread + 1);
2541 return CURLE_OUT_OF_MEMORY;
2543 /* Reply format is like
2544 257<space>"<directory-name>"<space><commentary> and the RFC959
2547 The directory name can contain any character; embedded
2548 double-quotes should be escaped by double-quotes (the
2549 "quote-doubling" convention).
2552 /* it started good */
2554 for (store = dir; *ptr;) {
2556 if('\"' == ptr[1]) {
2557 /* "quote-doubling" */
2563 *store = '\0'; /* zero terminate */
2564 break; /* get out of this loop */
2573 free(ftpc->entrypath);
2574 ftpc->entrypath =dir; /* remember this */
2575 infof(data, "Entry path is '%s'\n", ftpc->entrypath);
2576 /* also save it where getinfo can access it: */
2577 data->state.most_recent_ftp_entrypath = ftpc->entrypath;
2579 /* If the path name does not look like an absolute path (i.e.: it
2580 does not start with a '/'), we probably need some server-dependent
2581 adjustments. For example, this is the case when connecting to
2582 an OS400 FTP server: this server supports two name syntaxes,
2583 the default one being incompatible with standard pathes. In
2584 addition, this server switches automatically to the regular path
2585 syntax when one is encountered in a command: this results in
2586 having an entrypath in the wrong syntax when later used in CWD.
2587 The method used here is to check the server OS: we do it only
2588 if the path name looks strange to minimize overhead on other
2591 if(!ftpc->server_os && ftpc->entrypath[0] != '/') {
2592 PPSENDF(&ftpc->pp, "SYST", NULL);
2593 state(conn, FTP_SYST);
2598 /* couldn't get the path */
2600 infof(data, "Failed to figure out path\n");
2603 state(conn, FTP_STOP); /* we are done with the CONNECT phase! */
2604 DEBUGF(infof(data, "protocol connect phase DONE\n"));
2608 if(ftpcode == 215) {
2609 char *ptr=&data->state.buffer[4]; /* start on the first letter */
2613 os = malloc(nread + 1);
2615 return CURLE_OUT_OF_MEMORY;
2617 /* Reply format is like
2618 215<space><OS-name><space><commentary>
2622 for (store = os; *ptr && *ptr != ' ';)
2624 *store = '\0'; /* zero terminate */
2625 ftpc->server_os = os;
2627 /* Check for special servers here. */
2629 if(strequal(ftpc->server_os, "OS/400")) {
2630 /* Force OS400 name format 1. */
2631 PPSENDF(&ftpc->pp, "SITE NAMEFMT 1", NULL);
2632 state(conn, FTP_NAMEFMT);
2636 /* Nothing special for the target server. */
2640 /* Cannot identify server OS. Continue anyway and cross fingers. */
2643 state(conn, FTP_STOP); /* we are done with the CONNECT phase! */
2644 DEBUGF(infof(data, "protocol connect phase DONE\n"));
2648 if(ftpcode == 250) {
2649 /* Name format change successful: reload initial path. */
2650 ftp_state_pwd(conn);
2654 state(conn, FTP_STOP); /* we are done with the CONNECT phase! */
2655 DEBUGF(infof(data, "protocol connect phase DONE\n"));
2660 case FTP_RETR_PREQUOTE:
2661 case FTP_STOR_PREQUOTE:
2662 if(ftpcode >= 400) {
2663 failf(conn->data, "QUOT command failed with %03d", ftpcode);
2664 return CURLE_QUOTE_ERROR;
2666 result = ftp_state_quote(conn, FALSE, ftpc->state);
2673 if(ftpcode/100 != 2) {
2674 /* failure to CWD there */
2675 if(conn->data->set.ftp_create_missing_dirs &&
2676 ftpc->count1 && !ftpc->count2) {
2678 ftpc->count2++; /* counter to prevent CWD-MKD loops */
2679 PPSENDF(&ftpc->pp, "MKD %s", ftpc->dirs[ftpc->count1 - 1]);
2680 state(conn, FTP_MKD);
2683 /* return failure */
2684 failf(data, "Server denied you to change to the given directory");
2685 ftpc->cwdfail = TRUE; /* don't remember this path as we failed
2687 return CURLE_REMOTE_ACCESS_DENIED;
2693 if(++ftpc->count1 <= ftpc->dirdepth) {
2695 PPSENDF(&ftpc->pp, "CWD %s", ftpc->dirs[ftpc->count1 - 1]);
2698 result = ftp_state_post_cwd(conn);
2706 if((ftpcode/100 != 2) && !ftpc->count3--) {
2707 /* failure to MKD the dir */
2708 failf(data, "Failed to MKD dir: %03d", ftpcode);
2709 return CURLE_REMOTE_ACCESS_DENIED;
2711 state(conn, FTP_CWD);
2713 PPSENDF(&ftpc->pp, "CWD %s", ftpc->dirs[ftpc->count1 - 1]);
2717 result = ftp_state_mdtm_resp(conn, ftpcode);
2724 result = ftp_state_type_resp(conn, ftpcode, ftpc->state);
2730 result = ftp_state_size_resp(conn, ftpcode, ftpc->state);
2735 result = ftp_state_rest_resp(conn, ftpcode, ftpc->state);
2739 if(ftpcode != 200) {
2740 /* there only is this one standard OK return code. */
2741 failf(data, "PRET command not accepted: %03d", ftpcode);
2742 return CURLE_FTP_PRET_FAILED;
2744 result = ftp_state_use_pasv(conn);
2748 result = ftp_state_pasv_resp(conn, ftpcode);
2752 result = ftp_state_port_resp(conn, ftpcode);
2757 result = ftp_state_get_resp(conn, ftpcode, ftpc->state);
2761 result = ftp_state_stor_resp(conn, ftpcode);
2765 /* fallthrough, just stop! */
2767 /* internal error */
2768 state(conn, FTP_STOP);
2777 /* called repeatedly until done from multi.c */
2778 static CURLcode ftp_multi_statemach(struct connectdata *conn,
2781 struct ftp_conn *ftpc = &conn->proto.ftpc;
2782 CURLcode result = Curl_pp_multi_statemach(&ftpc->pp);
2784 /* Check for the state outside of the Curl_socket_ready() return code checks
2785 since at times we are in fact already in this state when this function
2787 *done = (bool)(ftpc->state == FTP_STOP);
2792 static CURLcode ftp_easy_statemach(struct connectdata *conn)
2794 struct ftp_conn *ftpc = &conn->proto.ftpc;
2795 struct pingpong *pp = &ftpc->pp;
2796 CURLcode result = CURLE_OK;
2798 while(ftpc->state != FTP_STOP) {
2799 result = Curl_pp_easy_statemach(pp);
2808 * Allocate and initialize the struct FTP for the current SessionHandle. If
2812 #if defined(__INTEL_COMPILER) && (__INTEL_COMPILER == 910) && \
2813 defined(__OPTIMIZE__) && defined(__unix__) && defined(__i386__)
2814 /* workaround icc 9.1 optimizer issue */
2815 # define vqualifier volatile
2820 static CURLcode ftp_init(struct connectdata *conn)
2822 struct FTP *vqualifier ftp;
2824 if(NULL == conn->data->state.proto.ftp) {
2825 conn->data->state.proto.ftp = malloc(sizeof(struct FTP));
2826 if(NULL == conn->data->state.proto.ftp)
2827 return CURLE_OUT_OF_MEMORY;
2830 ftp = conn->data->state.proto.ftp;
2832 /* get some initial data into the ftp struct */
2833 ftp->bytecountp = &conn->data->req.bytecount;
2834 ftp->transfer = FTPTRANSFER_BODY;
2835 ftp->downloadsize = 0;
2837 /* No need to duplicate user+password, the connectdata struct won't change
2838 during a session, but we re-init them here since on subsequent inits
2839 since the conn struct may have changed or been replaced.
2841 ftp->user = conn->user;
2842 ftp->passwd = conn->passwd;
2843 if(TRUE == isBadFtpString(ftp->user))
2844 return CURLE_URL_MALFORMAT;
2845 if(TRUE == isBadFtpString(ftp->passwd))
2846 return CURLE_URL_MALFORMAT;
2852 * ftp_connect() should do everything that is to be considered a part of
2853 * the connection phase.
2855 * The variable 'done' points to will be TRUE if the protocol-layer connect
2856 * phase is done when this function returns, or FALSE is not. When called as
2857 * a part of the easy interface, it will always be TRUE.
2859 static CURLcode ftp_connect(struct connectdata *conn,
2860 bool *done) /* see description above */
2863 struct ftp_conn *ftpc = &conn->proto.ftpc;
2864 struct SessionHandle *data=conn->data;
2865 struct pingpong *pp = &ftpc->pp;
2867 *done = FALSE; /* default to not done yet */
2869 /* If there already is a protocol-specific struct allocated for this
2870 sessionhandle, deal with it */
2871 Curl_reset_reqproto(conn);
2873 result = ftp_init(conn);
2874 if(CURLE_OK != result)
2877 /* We always support persistant connections on ftp */
2878 conn->bits.close = FALSE;
2880 pp->response_time = RESP_TIMEOUT; /* set default response time-out */
2881 pp->statemach_act = ftp_statemach_act;
2882 pp->endofresp = ftp_endofresp;
2885 #if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_PROXY)
2886 if(conn->bits.tunnel_proxy && conn->bits.httpproxy) {
2887 /* for FTP over HTTP proxy */
2888 struct HTTP http_proxy;
2889 struct FTP *ftp_save;
2892 /* We want "seamless" FTP operations through HTTP proxy tunnel */
2894 /* Curl_proxyCONNECT is based on a pointer to a struct HTTP at the member
2895 * conn->proto.http; we want FTP through HTTP and we have to change the
2896 * member temporarily for connecting to the HTTP proxy. After
2897 * Curl_proxyCONNECT we have to set back the member to the original struct
2900 ftp_save = data->state.proto.ftp;
2901 memset(&http_proxy, 0, sizeof(http_proxy));
2902 data->state.proto.http = &http_proxy;
2904 result = Curl_proxyCONNECT(conn, FIRSTSOCKET,
2905 conn->host.name, conn->remote_port);
2907 data->state.proto.ftp = ftp_save;
2909 if(CURLE_OK != result)
2912 #endif /* !CURL_DISABLE_HTTP && !CURL_DISABLE_PROXY */
2914 if(conn->protocol & PROT_FTPS) {
2916 /* FTPS is simply ftp with SSL for the control channel */
2917 /* now, perform the SSL initialization for this socket */
2918 result = Curl_ssl_connect(conn, FIRSTSOCKET);
2923 Curl_pp_init(pp); /* init the generic pingpong data */
2925 /* When we connect, we start in the state where we await the 220
2927 state(conn, FTP_WAIT220);
2929 if(data->state.used_interface == Curl_if_multi)
2930 result = ftp_multi_statemach(conn, done);
2932 result = ftp_easy_statemach(conn);
2940 /***********************************************************************
2944 * The DONE function. This does what needs to be done after a single DO has
2947 * Input argument is already checked for validity.
2949 static CURLcode ftp_done(struct connectdata *conn, CURLcode status,
2952 struct SessionHandle *data = conn->data;
2953 struct FTP *ftp = data->state.proto.ftp;
2954 struct ftp_conn *ftpc = &conn->proto.ftpc;
2955 struct pingpong *pp = &ftpc->pp;
2958 CURLcode result=CURLE_OK;
2959 bool was_ctl_valid = ftpc->ctl_valid;
2961 const char *path_to_use = data->state.path;
2964 /* When the easy handle is removed from the multi while libcurl is still
2965 * trying to resolve the host name, it seems that the ftp struct is not
2966 * yet initialized, but the removal action calls Curl_done() which calls
2967 * this function. So we simply return success if no ftp pointer is set.
2972 case CURLE_BAD_DOWNLOAD_RESUME:
2973 case CURLE_FTP_WEIRD_PASV_REPLY:
2974 case CURLE_FTP_PORT_FAILED:
2975 case CURLE_FTP_COULDNT_SET_TYPE:
2976 case CURLE_FTP_COULDNT_RETR_FILE:
2977 case CURLE_UPLOAD_FAILED:
2978 case CURLE_REMOTE_ACCESS_DENIED:
2979 case CURLE_FILESIZE_EXCEEDED:
2980 case CURLE_REMOTE_FILE_NOT_FOUND:
2981 case CURLE_WRITE_ERROR:
2982 /* the connection stays alive fine even though this happened */
2984 case CURLE_OK: /* doesn't affect the control connection's status */
2986 ftpc->ctl_valid = was_ctl_valid;
2989 /* until we cope better with prematurely ended requests, let them
2990 * fallback as if in complete failure */
2991 default: /* by default, an error means the control connection is
2992 wedged and should not be used anymore */
2993 ftpc->ctl_valid = FALSE;
2994 ftpc->cwdfail = TRUE; /* set this TRUE to prevent us to remember the
2995 current path, as this connection is going */
2996 conn->bits.close = TRUE; /* marked for closure */
2997 result = status; /* use the already set error code */
3001 /* now store a copy of the directory we are in */
3003 free(ftpc->prevpath);
3005 /* get the "raw" path */
3006 path = curl_easy_unescape(data, path_to_use, 0, NULL);
3008 /* out of memory, but we can limp along anyway (and should try to
3009 * since we're in the out of memory cleanup path) */
3010 ftpc->prevpath = NULL; /* no path */
3013 size_t flen = ftpc->file?strlen(ftpc->file):0; /* file is "raw" already */
3014 size_t dlen = strlen(path)-flen;
3015 if(!ftpc->cwdfail) {
3016 if(dlen && (data->set.ftp_filemethod != FTPFILE_NOCWD)) {
3017 ftpc->prevpath = path;
3019 /* if 'path' is not the whole string */
3020 ftpc->prevpath[dlen]=0; /* terminate */
3023 /* we never changed dir */
3024 ftpc->prevpath=strdup("");
3028 infof(data, "Remembering we are in dir \"%s\"\n", ftpc->prevpath);
3031 ftpc->prevpath = NULL; /* no path */
3035 /* free the dir tree and file parts */
3038 #if defined(HAVE_KRB4) || defined(HAVE_GSSAPI)
3039 Curl_sec_fflush_fd(conn, conn->sock[SECONDARYSOCKET]);
3042 /* shut down the socket to inform the server we're done */
3045 shutdown(conn->sock[SECONDARYSOCKET],2); /* SD_BOTH */
3048 if(conn->sock[SECONDARYSOCKET] != CURL_SOCKET_BAD) {
3049 if(conn->ssl[SECONDARYSOCKET].use) {
3050 /* The secondary socket is using SSL so we must close down that part
3051 first before we close the socket for real */
3052 Curl_ssl_close(conn, SECONDARYSOCKET);
3054 /* Note that we keep "use" set to TRUE since that (next) connection is
3055 still requested to use SSL */
3057 if(CURL_SOCKET_BAD != conn->sock[SECONDARYSOCKET]) {
3058 sclose(conn->sock[SECONDARYSOCKET]);
3059 conn->sock[SECONDARYSOCKET] = CURL_SOCKET_BAD;
3063 if((ftp->transfer == FTPTRANSFER_BODY) && ftpc->ctl_valid &&
3064 pp->pending_resp && !premature) {
3066 * Let's see what the server says about the transfer we just performed,
3067 * but lower the timeout as sometimes this connection has died while the
3068 * data has been transfered. This happens when doing through NATs etc that
3069 * abandon old silent connections.
3071 long old_time = pp->response_time;
3073 pp->response_time = 60*1000; /* give it only a minute for now */
3074 pp->response = Curl_tvnow(); /* timeout relative now */
3076 result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
3078 pp->response_time = old_time; /* set this back to previous value */
3080 if(!nread && (CURLE_OPERATION_TIMEDOUT == result)) {
3081 failf(data, "control connection looks dead");
3082 ftpc->ctl_valid = FALSE; /* mark control connection as bad */
3083 conn->bits.close = TRUE; /* mark for closure */
3089 if(!ftpc->dont_check) {
3090 /* 226 Transfer complete, 250 Requested file action okay, completed. */
3091 if((ftpcode != 226) && (ftpcode != 250)) {
3092 failf(data, "server did not report OK, got %d", ftpcode);
3093 result = CURLE_PARTIAL_FILE;
3098 if(result || premature)
3099 /* the response code from the transfer showed an error already so no
3100 use checking further */
3102 else if(data->set.upload) {
3103 if((-1 != data->set.infilesize) &&
3104 (data->set.infilesize != *ftp->bytecountp) &&
3106 (ftp->transfer == FTPTRANSFER_BODY)) {
3107 failf(data, "Uploaded unaligned file size (%" FORMAT_OFF_T
3108 " out of %" FORMAT_OFF_T " bytes)",
3109 *ftp->bytecountp, data->set.infilesize);
3110 result = CURLE_PARTIAL_FILE;
3114 if((-1 != data->req.size) &&
3115 (data->req.size != *ftp->bytecountp) &&
3116 #ifdef CURL_DO_LINEEND_CONV
3117 /* Most FTP servers don't adjust their file SIZE response for CRLFs, so
3118 * we'll check to see if the discrepancy can be explained by the number
3119 * of CRLFs we've changed to LFs.
3121 ((data->req.size + data->state.crlf_conversions) !=
3122 *ftp->bytecountp) &&
3123 #endif /* CURL_DO_LINEEND_CONV */
3124 (data->req.maxdownload != *ftp->bytecountp)) {
3125 failf(data, "Received only partial file: %" FORMAT_OFF_T " bytes",
3127 result = CURLE_PARTIAL_FILE;
3129 else if(!ftpc->dont_check &&
3130 !*ftp->bytecountp &&
3131 (data->req.size>0)) {
3132 failf(data, "No data was received!");
3133 result = CURLE_FTP_COULDNT_RETR_FILE;
3137 /* clear these for next connection */
3138 ftp->transfer = FTPTRANSFER_BODY;
3139 ftpc->dont_check = FALSE;
3141 /* Send any post-transfer QUOTE strings? */
3142 if(!status && !result && !premature && data->set.postquote)
3143 result = ftp_sendquote(conn, data->set.postquote);
3148 /***********************************************************************
3152 * Where a 'quote' means a list of custom commands to send to the server.
3153 * The quote list is passed as an argument.
3159 CURLcode ftp_sendquote(struct connectdata *conn, struct curl_slist *quote)
3161 struct curl_slist *item;
3169 char *cmd = item->data;
3170 bool acceptfail = FALSE;
3172 /* if a command starts with an asterisk, which a legal FTP command never
3173 can, the command will be allowed to fail without it causing any
3174 aborts or cancels etc. It will cause libcurl to act as if the command
3175 is successful, whatever the server reponds. */
3182 FTPSENDF(conn, "%s", cmd);
3184 result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
3188 if(!acceptfail && (ftpcode >= 400)) {
3189 failf(conn->data, "QUOT string not accepted: %s", cmd);
3190 return CURLE_QUOTE_ERROR;
3200 /***********************************************************************
3204 * Returns TRUE if we in the current situation should send TYPE
3206 static int ftp_need_type(struct connectdata *conn,
3209 return conn->proto.ftpc.transfertype != (ascii_wanted?'A':'I');
3212 /***********************************************************************
3216 * Set TYPE. We only deal with ASCII or BINARY so this function
3218 * If the transfer type is not sent, simulate on OK response in newstate
3220 static CURLcode ftp_nb_type(struct connectdata *conn,
3221 bool ascii, ftpstate newstate)
3223 struct ftp_conn *ftpc = &conn->proto.ftpc;
3225 char want = (char)(ascii?'A':'I');
3227 if(ftpc->transfertype == want) {
3228 state(conn, newstate);
3229 return ftp_state_type_resp(conn, 200, newstate);
3232 PPSENDF(&ftpc->pp, "TYPE %c", want);
3233 state(conn, newstate);
3235 /* keep track of our current transfer type */
3236 ftpc->transfertype = want;
3240 /***************************************************************************
3242 * ftp_pasv_verbose()
3244 * This function only outputs some informationals about this second connection
3245 * when we've issued a PASV command before and thus we have connected to a
3246 * possibly new IP address.
3249 #ifndef CURL_DISABLE_VERBOSE_STRINGS
3251 ftp_pasv_verbose(struct connectdata *conn,
3253 char *newhost, /* ascii version */
3257 Curl_printable_address(ai, buf, sizeof(buf));
3258 infof(conn->data, "Connecting to %s (%s) port %d\n", newhost, buf, port);
3263 Check if this is a range download, and if so, set the internal variables
3267 static CURLcode ftp_range(struct connectdata *conn)
3269 curl_off_t from, to;
3270 curl_off_t totalsize=-1;
3273 struct SessionHandle *data = conn->data;
3274 struct ftp_conn *ftpc = &conn->proto.ftpc;
3276 if(data->state.use_range && data->state.range) {
3277 from=curlx_strtoofft(data->state.range, &ptr, 0);
3278 while(ptr && *ptr && (ISSPACE(*ptr) || (*ptr=='-')))
3280 to=curlx_strtoofft(ptr, &ptr2, 0);
3282 /* we didn't get any digit */
3285 if((-1 == to) && (from>=0)) {
3287 data->state.resume_from = from;
3288 DEBUGF(infof(conn->data, "FTP RANGE %" FORMAT_OFF_T " to end of file\n",
3294 data->req.maxdownload = -from;
3295 data->state.resume_from = from;
3296 DEBUGF(infof(conn->data, "FTP RANGE the last %" FORMAT_OFF_T " bytes\n",
3301 totalsize = to-from;
3302 data->req.maxdownload = totalsize+1; /* include last byte */
3303 data->state.resume_from = from;
3304 DEBUGF(infof(conn->data, "FTP RANGE from %" FORMAT_OFF_T
3305 " getting %" FORMAT_OFF_T " bytes\n",
3306 from, data->req.maxdownload));
3308 DEBUGF(infof(conn->data, "range-download from %" FORMAT_OFF_T
3309 " to %" FORMAT_OFF_T ", totally %" FORMAT_OFF_T " bytes\n",
3310 from, to, data->req.maxdownload));
3311 ftpc->dont_check = TRUE; /* dont check for successful transfer */
3314 data->req.maxdownload = -1;
3322 * This function shall be called when the second FTP (data) connection is
3326 static CURLcode ftp_nextconnect(struct connectdata *conn)
3328 struct SessionHandle *data=conn->data;
3329 struct ftp_conn *ftpc = &conn->proto.ftpc;
3330 CURLcode result = CURLE_OK;
3332 /* the ftp struct is inited in ftp_connect() */
3333 struct FTP *ftp = data->state.proto.ftp;
3335 DEBUGF(infof(data, "DO-MORE phase starts\n"));
3337 if(ftp->transfer <= FTPTRANSFER_INFO) {
3338 /* a transfer is about to take place, or if not a file name was given
3339 so we'll do a SIZE on it later and then we need the right TYPE first */
3341 if(data->set.upload) {
3342 result = ftp_nb_type(conn, data->set.prefer_ascii, FTP_STOR_TYPE);
3348 ftp->downloadsize = -1; /* unknown as of yet */
3350 result = ftp_range(conn);
3353 else if(data->set.ftp_list_only || !ftpc->file) {
3354 /* The specified path ends with a slash, and therefore we think this
3355 is a directory that is requested, use LIST. But before that we
3356 need to set ASCII transfer mode. */
3358 /* But only if a body transfer was requested. */
3359 if(ftp->transfer == FTPTRANSFER_BODY) {
3360 result = ftp_nb_type(conn, TRUE, FTP_LIST_TYPE);
3364 /* otherwise just fall through */
3367 result = ftp_nb_type(conn, data->set.prefer_ascii, FTP_RETR_TYPE);
3372 result = ftp_easy_statemach(conn);
3375 if((result == CURLE_OK) && (ftp->transfer != FTPTRANSFER_BODY))
3376 /* no data to transfer. FIX: it feels like a kludge to have this here
3378 result = Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
3380 /* end of transfer */
3381 DEBUGF(infof(data, "DO-MORE phase ends with %d\n", (int)result));
3388 /***********************************************************************
3392 * This is the actual DO function for FTP. Get a file/directory according to
3393 * the options previously setup.
3397 CURLcode ftp_perform(struct connectdata *conn,
3398 bool *connected, /* connect status after PASV / PORT */
3401 /* this is FTP and no proxy */
3402 CURLcode result=CURLE_OK;
3404 DEBUGF(infof(conn->data, "DO phase starts\n"));
3406 if(conn->data->set.opt_no_body) {
3407 /* requested no body means no transfer... */
3408 struct FTP *ftp = conn->data->state.proto.ftp;
3409 ftp->transfer = FTPTRANSFER_INFO;
3413 *dophase_done = FALSE; /* not done yet */
3415 /* start the first command in the DO phase */
3416 result = ftp_state_quote(conn, TRUE, FTP_QUOTE);
3420 /* run the state-machine */
3421 if(conn->data->state.used_interface == Curl_if_multi)
3422 result = ftp_multi_statemach(conn, dophase_done);
3424 result = ftp_easy_statemach(conn);
3425 *dophase_done = TRUE; /* with the easy interface we are done here */
3427 *connected = conn->bits.tcpconnect;
3430 DEBUGF(infof(conn->data, "DO phase is complete\n"));
3435 /***********************************************************************
3439 * This function is registered as 'curl_do' function. It decodes the path
3440 * parts etc as a wrapper to the actual DO function (ftp_perform).
3442 * The input argument is already checked for validity.
3444 static CURLcode ftp_do(struct connectdata *conn, bool *done)
3446 CURLcode retcode = CURLE_OK;
3448 *done = FALSE; /* default to false */
3451 Since connections can be re-used between SessionHandles, this might be a
3452 connection already existing but on a fresh SessionHandle struct so we must
3453 make sure we have a good 'struct FTP' to play with. For new connections,
3454 the struct FTP is allocated and setup in the ftp_connect() function.
3456 Curl_reset_reqproto(conn);
3457 retcode = ftp_init(conn);
3461 retcode = ftp_parse_url_path(conn);
3465 retcode = ftp_regular_transfer(conn, done);
3471 CURLcode Curl_ftpsendf(struct connectdata *conn,
3472 const char *fmt, ...)
3474 ssize_t bytes_written;
3475 #define SBUF_SIZE 1024
3479 CURLcode res = CURLE_OK;
3480 #if defined(HAVE_KRB4) || defined(HAVE_GSSAPI)
3481 enum protection_level data_sec = conn->data_prot;
3486 vsnprintf(s, SBUF_SIZE-3, fmt, ap);
3489 strcat(s, "\r\n"); /* append a trailing CRLF */
3492 write_len = strlen(s);
3494 #ifdef CURL_DOES_CONVERSIONS
3495 res = Curl_convert_to_network(conn->data, s, write_len);
3496 /* Curl_convert_to_network calls failf if unsuccessful */
3497 if(res != CURLE_OK) {
3500 #endif /* CURL_DOES_CONVERSIONS */
3503 #if defined(HAVE_KRB4) || defined(HAVE_GSSAPI)
3504 conn->data_prot = prot_cmd;
3506 res = Curl_write(conn, conn->sock[FIRSTSOCKET], sptr, write_len,
3508 #if defined(HAVE_KRB4) || defined(HAVE_GSSAPI)
3509 conn->data_prot = data_sec;
3515 if(conn->data->set.verbose)
3516 Curl_debug(conn->data, CURLINFO_HEADER_OUT,
3517 sptr, (size_t)bytes_written, conn);
3519 if(bytes_written != (ssize_t)write_len) {
3520 write_len -= bytes_written;
3521 sptr += bytes_written;
3530 /***********************************************************************
3534 * This should be called before calling sclose() on an ftp control connection
3535 * (not data connections). We should then wait for the response from the
3536 * server before returning. The calling code should then try to close the
3540 static CURLcode ftp_quit(struct connectdata *conn)
3542 CURLcode result = CURLE_OK;
3544 if(conn->proto.ftpc.ctl_valid) {
3545 PPSENDF(&conn->proto.ftpc.pp, "QUIT", NULL);
3546 state(conn, FTP_QUIT);
3548 result = ftp_easy_statemach(conn);
3554 /***********************************************************************
3558 * Disconnect from an FTP server. Cleanup protocol-specific per-connection
3559 * resources. BLOCKING.
3561 static CURLcode ftp_disconnect(struct connectdata *conn)
3563 struct ftp_conn *ftpc= &conn->proto.ftpc;
3564 struct pingpong *pp = &ftpc->pp;
3566 /* We cannot send quit unconditionally. If this connection is stale or
3567 bad in any way, sending quit and waiting around here will make the
3568 disconnect wait in vain and cause more problems than we need to.
3570 ftp_quit() will check the state of ftp->ctl_valid. If it's ok it
3571 will try to send the QUIT command, otherwise it will just return.
3574 /* The FTP session may or may not have been allocated/setup at this point! */
3575 (void)ftp_quit(conn); /* ignore errors on the QUIT */
3577 if(ftpc->entrypath) {
3578 struct SessionHandle *data = conn->data;
3579 if(data->state.most_recent_ftp_entrypath == ftpc->entrypath) {
3580 data->state.most_recent_ftp_entrypath = NULL;
3582 free(ftpc->entrypath);
3583 ftpc->entrypath = NULL;
3587 if(ftpc->prevpath) {
3588 free(ftpc->prevpath);
3589 ftpc->prevpath = NULL;
3591 if(ftpc->server_os) {
3592 free(ftpc->server_os);
3593 ftpc->server_os = NULL;
3596 Curl_pp_disconnect(pp);
3601 /***********************************************************************
3603 * ftp_parse_url_path()
3605 * Parse the URL path into separate path components.
3609 CURLcode ftp_parse_url_path(struct connectdata *conn)
3611 struct SessionHandle *data = conn->data;
3612 /* the ftp struct is already inited in ftp_connect() */
3613 struct FTP *ftp = data->state.proto.ftp;
3614 struct ftp_conn *ftpc = &conn->proto.ftpc;
3615 const char *slash_pos; /* position of the first '/' char in curpos */
3616 const char *path_to_use = data->state.path;
3617 const char *cur_pos;
3618 const char *filename = NULL;
3620 cur_pos = path_to_use; /* current position in path. point at the begin
3621 of next path component */
3623 ftpc->ctl_valid = FALSE;
3624 ftpc->cwdfail = FALSE;
3626 switch(data->set.ftp_filemethod) {
3628 /* fastest, but less standard-compliant */
3631 The best time to check whether the path is a file or directory is right
3634 the first condition in the if() right here, is there just in case
3635 someone decides to set path to NULL one day
3637 if(data->state.path &&
3638 data->state.path[0] &&
3639 (data->state.path[strlen(data->state.path) - 1] != '/') )
3640 filename = data->state.path; /* this is a full file path */
3642 ftpc->file is not used anywhere other than for operations on a file.
3643 In other words, never for directory operations.
3644 So we can safely leave filename as NULL here and use it as a
3645 argument in dir/file decisions.
3649 case FTPFILE_SINGLECWD:
3650 /* get the last slash */
3651 if(!path_to_use[0]) {
3652 /* no dir, no file */
3656 slash_pos=strrchr(cur_pos, '/');
3657 if(slash_pos || !*cur_pos) {
3658 ftpc->dirs = calloc(1, sizeof(ftpc->dirs[0]));
3660 return CURLE_OUT_OF_MEMORY;
3662 ftpc->dirs[0] = curl_easy_unescape(conn->data, slash_pos ? cur_pos : "/",
3663 slash_pos?(int)(slash_pos-cur_pos):1,
3665 if(!ftpc->dirs[0]) {
3667 return CURLE_OUT_OF_MEMORY;
3669 ftpc->dirdepth = 1; /* we consider it to be a single dir */
3670 filename = slash_pos ? slash_pos+1 : cur_pos; /* rest is file name */
3673 filename = cur_pos; /* this is a file name only */
3676 default: /* allow pretty much anything */
3677 case FTPFILE_MULTICWD:
3679 ftpc->diralloc = 5; /* default dir depth to allocate */
3680 ftpc->dirs = calloc(ftpc->diralloc, sizeof(ftpc->dirs[0]));
3682 return CURLE_OUT_OF_MEMORY;
3684 /* we have a special case for listing the root dir only */
3685 if(strequal(path_to_use, "/")) {
3686 cur_pos++; /* make it point to the zero byte */
3687 ftpc->dirs[0] = strdup("/");
3691 /* parse the URL path into separate path components */
3692 while((slash_pos = strchr(cur_pos, '/')) != NULL) {
3693 /* 1 or 0 to indicate absolute directory */
3694 bool absolute_dir = (bool)((cur_pos - data->state.path > 0) &&
3695 (ftpc->dirdepth == 0));
3697 /* seek out the next path component */
3698 if(slash_pos-cur_pos) {
3699 /* we skip empty path components, like "x//y" since the FTP command
3700 CWD requires a parameter and a non-existant parameter a) doesn't
3701 work on many servers and b) has no effect on the others. */
3702 int len = (int)(slash_pos - cur_pos + absolute_dir);
3703 ftpc->dirs[ftpc->dirdepth] =
3704 curl_easy_unescape(conn->data, cur_pos - absolute_dir, len, NULL);
3705 if(!ftpc->dirs[ftpc->dirdepth]) { /* run out of memory ... */
3706 failf(data, "no memory");
3708 return CURLE_OUT_OF_MEMORY;
3710 if(isBadFtpString(ftpc->dirs[ftpc->dirdepth])) {
3711 free(ftpc->dirs[ftpc->dirdepth]);
3713 return CURLE_URL_MALFORMAT;
3717 cur_pos = slash_pos + 1; /* jump to the rest of the string */
3721 cur_pos = slash_pos + 1; /* jump to the rest of the string */
3722 if(++ftpc->dirdepth >= ftpc->diralloc) {
3725 ftpc->diralloc *= 2; /* double the size each time */
3726 bigger = realloc(ftpc->dirs, ftpc->diralloc * sizeof(ftpc->dirs[0]));
3729 return CURLE_OUT_OF_MEMORY;
3731 ftpc->dirs = (char **)bigger;
3735 filename = cur_pos; /* the rest is the file name */
3739 if(filename && *filename) {
3740 ftpc->file = curl_easy_unescape(conn->data, filename, 0, NULL);
3741 if(NULL == ftpc->file) {
3743 failf(data, "no memory");
3744 return CURLE_OUT_OF_MEMORY;
3746 if(isBadFtpString(ftpc->file)) {
3748 return CURLE_URL_MALFORMAT;
3752 ftpc->file=NULL; /* instead of point to a zero byte, we make it a NULL
3755 if(data->set.upload && !ftpc->file && (ftp->transfer == FTPTRANSFER_BODY)) {
3756 /* We need a file name when uploading. Return error! */
3757 failf(data, "Uploading to a URL without a file name!");
3758 return CURLE_URL_MALFORMAT;
3761 ftpc->cwddone = FALSE; /* default to not done */
3763 if(ftpc->prevpath) {
3764 /* prevpath is "raw" so we convert the input path before we compare the
3767 char *path = curl_easy_unescape(conn->data, data->state.path, 0, &dlen);
3770 return CURLE_OUT_OF_MEMORY;
3773 dlen -= ftpc->file?(int)strlen(ftpc->file):0;
3774 if((dlen == (int)strlen(ftpc->prevpath)) &&
3775 strnequal(path, ftpc->prevpath, dlen)) {
3776 infof(data, "Request has same path as previous transfer\n");
3777 ftpc->cwddone = TRUE;
3785 /* call this when the DO phase has completed */
3786 static CURLcode ftp_dophase_done(struct connectdata *conn,
3789 CURLcode result = CURLE_OK;
3790 struct FTP *ftp = conn->data->state.proto.ftp;
3791 struct ftp_conn *ftpc = &conn->proto.ftpc;
3794 result = ftp_nextconnect(conn);
3796 if(result && (conn->sock[SECONDARYSOCKET] != CURL_SOCKET_BAD)) {
3797 /* Failure detected, close the second socket if it was created already */
3798 sclose(conn->sock[SECONDARYSOCKET]);
3799 conn->sock[SECONDARYSOCKET] = CURL_SOCKET_BAD;
3803 if(ftp->transfer != FTPTRANSFER_BODY)
3804 /* no data to transfer */
3805 result=Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
3807 /* since we didn't connect now, we want do_more to get called */
3808 conn->bits.do_more = TRUE;
3810 ftpc->ctl_valid = TRUE; /* seems good */
3815 /* called from multi.c while DOing */
3816 static CURLcode ftp_doing(struct connectdata *conn,
3820 result = ftp_multi_statemach(conn, dophase_done);
3823 result = ftp_dophase_done(conn, FALSE /* not connected */);
3825 DEBUGF(infof(conn->data, "DO phase is complete\n"));
3830 /***********************************************************************
3832 * ftp_regular_transfer()
3834 * The input argument is already checked for validity.
3836 * Performs all commands done before a regular transfer between a local and a
3839 * ftp->ctl_valid starts out as FALSE, and gets set to TRUE if we reach the
3840 * ftp_done() function without finding any major problem.
3843 CURLcode ftp_regular_transfer(struct connectdata *conn,
3846 CURLcode result=CURLE_OK;
3847 bool connected=FALSE;
3848 struct SessionHandle *data = conn->data;
3849 struct ftp_conn *ftpc = &conn->proto.ftpc;
3850 data->req.size = -1; /* make sure this is unknown at this point */
3852 Curl_pgrsSetUploadCounter(data, 0);
3853 Curl_pgrsSetDownloadCounter(data, 0);
3854 Curl_pgrsSetUploadSize(data, 0);
3855 Curl_pgrsSetDownloadSize(data, 0);
3857 ftpc->ctl_valid = TRUE; /* starts good */
3859 result = ftp_perform(conn,
3860 &connected, /* have we connected after PASV/PORT */
3861 dophase_done); /* all commands in the DO-phase done? */
3863 if(CURLE_OK == result) {
3866 /* the DO phase has not completed yet */
3869 result = ftp_dophase_done(conn, connected);
3879 static CURLcode ftp_setup_connection(struct connectdata * conn)
3881 struct SessionHandle *data = conn->data;
3885 if(conn->bits.httpproxy && !data->set.tunnel_thru_httpproxy) {
3886 /* Unless we have asked to tunnel ftp operations through the proxy, we
3887 switch and use HTTP operations only */
3888 #ifndef CURL_DISABLE_HTTP
3889 if(conn->handler == &Curl_handler_ftp)
3890 conn->handler = &Curl_handler_ftp_proxy;
3893 conn->handler = &Curl_handler_ftps_proxy;
3895 failf(data, "FTPS not supported!");
3896 return CURLE_UNSUPPORTED_PROTOCOL;
3900 * We explicitly mark this connection as persistent here as we're doing
3901 * FTP over HTTP and thus we accidentally avoid setting this value
3904 conn->bits.close = FALSE;
3906 failf(data, "FTP over http proxy requires HTTP support built-in!");
3907 return CURLE_UNSUPPORTED_PROTOCOL;
3911 data->state.path++; /* don't include the initial slash */
3913 /* FTP URLs support an extension like ";type=<typecode>" that
3914 * we'll try to get now! */
3915 type = strstr(data->state.path, ";type=");
3918 type = strstr(conn->host.rawalloc, ";type=");
3921 *type = 0; /* it was in the middle of the hostname */
3922 command = Curl_raw_toupper(type[6]);
3925 case 'A': /* ASCII mode */
3926 data->set.prefer_ascii = TRUE;
3929 case 'D': /* directory mode */
3930 data->set.ftp_list_only = TRUE;
3933 case 'I': /* binary mode */
3935 /* switch off ASCII */
3936 data->set.prefer_ascii = FALSE;
3944 #endif /* CURL_DISABLE_FTP */