1 /***************************************************************************
3 * Project ___| | | | _ \| |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
8 * Copyright (C) 1998 - 2013, Daniel Stenberg, <daniel@haxx.se>, et al.
10 * This software is licensed as described in the file COPYING, which
11 * you should have received as part of this distribution. The terms
12 * are also available at http://curl.haxx.se/docs/copyright.html.
14 * You may opt to use, copy, modify, merge, publish, distribute and/or sell
15 * copies of the Software, and permit persons to whom the Software is
16 * furnished to do so, under the terms of the COPYING file.
18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19 * KIND, either express or implied.
21 ***************************************************************************/
23 #include "curl_setup.h"
25 #ifndef CURL_DISABLE_FTP
27 #ifdef HAVE_NETINET_IN_H
28 #include <netinet/in.h>
30 #ifdef HAVE_ARPA_INET_H
31 #include <arpa/inet.h>
34 #include <sys/utsname.h>
44 #if (defined(NETWARE) && defined(__NOVELL_LIBC__))
46 #define in_addr_t unsigned long
49 #include <curl/curl.h>
57 #include "http.h" /* for HTTP proxy tunnel stuff */
61 #include "ftplistparser.h"
63 #if defined(HAVE_KRB4) || defined(HAVE_GSSAPI)
67 #include "strtoofft.h"
72 #include "inet_ntop.h"
73 #include "inet_pton.h"
75 #include "parsedate.h" /* for the week day and month names */
76 #include "sockaddr.h" /* required for Curl_sockaddr_storage */
80 #include "speedcheck.h"
82 #include "http_proxy.h"
83 #include "non-ascii.h"
85 #define _MPRINTF_REPLACE /* use our functions only */
86 #include <curl/mprintf.h>
88 #include "curl_memory.h"
89 /* The last #include file should be: */
93 #define NI_MAXHOST 1025
95 #ifndef INET_ADDRSTRLEN
96 #define INET_ADDRSTRLEN 16
99 #ifdef CURL_DISABLE_VERBOSE_STRINGS
100 #define ftp_pasv_verbose(a,b,c,d) Curl_nop_stmt
103 /* Local API functions */
105 static void _state(struct connectdata *conn,
107 #define state(x,y) _state(x,y)
109 static void _state(struct connectdata *conn,
112 #define state(x,y) _state(x,y,__LINE__)
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, bool dead_connection);
139 static CURLcode ftp_do_more(struct connectdata *conn, bool *completed);
140 static CURLcode ftp_multi_statemach(struct connectdata *conn, bool *done);
141 static int ftp_getsock(struct connectdata *conn, curl_socket_t *socks,
143 static int ftp_domore_getsock(struct connectdata *conn, curl_socket_t *socks,
145 static CURLcode ftp_doing(struct connectdata *conn,
147 static CURLcode ftp_setup_connection(struct connectdata * conn);
149 static CURLcode init_wc_data(struct connectdata *conn);
150 static CURLcode wc_statemach(struct connectdata *conn);
152 static void wc_data_dtor(void *ptr);
154 static CURLcode ftp_state_post_retr_size(struct connectdata *conn,
155 curl_off_t filesize);
157 static CURLcode ftp_readresp(curl_socket_t sockfd,
161 static CURLcode ftp_dophase_done(struct connectdata *conn,
164 /* easy-to-use macro: */
165 #define PPSENDF(x,y,z) if((result = Curl_pp_sendf(x,y,z)) != CURLE_OK) \
170 * FTP protocol handler.
173 const struct Curl_handler Curl_handler_ftp = {
175 ftp_setup_connection, /* setup_connection */
178 ftp_do_more, /* do_more */
179 ftp_connect, /* connect_it */
180 ftp_multi_statemach, /* connecting */
181 ftp_doing, /* doing */
182 ftp_getsock, /* proto_getsock */
183 ftp_getsock, /* doing_getsock */
184 ftp_domore_getsock, /* domore_getsock */
185 ZERO_NULL, /* perform_getsock */
186 ftp_disconnect, /* disconnect */
187 ZERO_NULL, /* readwrite */
188 PORT_FTP, /* defport */
189 CURLPROTO_FTP, /* protocol */
190 PROTOPT_DUAL | PROTOPT_CLOSEACTION | PROTOPT_NEEDSPWD
191 | PROTOPT_NOURLQUERY /* flags */
197 * FTPS protocol handler.
200 const struct Curl_handler Curl_handler_ftps = {
202 ftp_setup_connection, /* setup_connection */
205 ftp_do_more, /* do_more */
206 ftp_connect, /* connect_it */
207 ftp_multi_statemach, /* connecting */
208 ftp_doing, /* doing */
209 ftp_getsock, /* proto_getsock */
210 ftp_getsock, /* doing_getsock */
211 ftp_domore_getsock, /* domore_getsock */
212 ZERO_NULL, /* perform_getsock */
213 ftp_disconnect, /* disconnect */
214 ZERO_NULL, /* readwrite */
215 PORT_FTPS, /* defport */
216 CURLPROTO_FTP | CURLPROTO_FTPS, /* protocol */
217 PROTOPT_SSL | PROTOPT_DUAL | PROTOPT_CLOSEACTION |
218 PROTOPT_NEEDSPWD | PROTOPT_NOURLQUERY /* flags */
222 #ifndef CURL_DISABLE_HTTP
224 * HTTP-proxyed FTP protocol handler.
227 static const struct Curl_handler Curl_handler_ftp_proxy = {
229 ZERO_NULL, /* setup_connection */
230 Curl_http, /* do_it */
231 Curl_http_done, /* done */
232 ZERO_NULL, /* do_more */
233 ZERO_NULL, /* connect_it */
234 ZERO_NULL, /* connecting */
235 ZERO_NULL, /* doing */
236 ZERO_NULL, /* proto_getsock */
237 ZERO_NULL, /* doing_getsock */
238 ZERO_NULL, /* domore_getsock */
239 ZERO_NULL, /* perform_getsock */
240 ZERO_NULL, /* disconnect */
241 ZERO_NULL, /* readwrite */
242 PORT_FTP, /* defport */
243 CURLPROTO_HTTP, /* protocol */
244 PROTOPT_NONE /* flags */
250 * HTTP-proxyed FTPS protocol handler.
253 static const struct Curl_handler Curl_handler_ftps_proxy = {
255 ZERO_NULL, /* setup_connection */
256 Curl_http, /* do_it */
257 Curl_http_done, /* done */
258 ZERO_NULL, /* do_more */
259 ZERO_NULL, /* connect_it */
260 ZERO_NULL, /* connecting */
261 ZERO_NULL, /* doing */
262 ZERO_NULL, /* proto_getsock */
263 ZERO_NULL, /* doing_getsock */
264 ZERO_NULL, /* domore_getsock */
265 ZERO_NULL, /* perform_getsock */
266 ZERO_NULL, /* disconnect */
267 ZERO_NULL, /* readwrite */
268 PORT_FTPS, /* defport */
269 CURLPROTO_HTTP, /* protocol */
270 PROTOPT_NONE /* flags */
277 * NOTE: back in the old days, we added code in the FTP code that made NOBODY
278 * requests on files respond with headers passed to the client/stdout that
279 * looked like HTTP ones.
281 * This approach is not very elegant, it causes confusion and is error-prone.
282 * It is subject for removal at the next (or at least a future) soname bump.
283 * Until then you can test the effects of the removal by undefining the
284 * following define named CURL_FTP_HTTPSTYLE_HEAD.
286 #define CURL_FTP_HTTPSTYLE_HEAD 1
288 static void freedirs(struct ftp_conn *ftpc)
292 for(i=0; i < ftpc->dirdepth; i++) {
308 /* Returns non-zero if the given string contains CR (\r) or LF (\n),
309 which are not allowed within RFC 959 <string>.
310 Note: The input string is in the client's encoding which might
311 not be ASCII, so escape sequences \r & \n must be used instead
312 of hex values 0x0d & 0x0a.
314 static bool isBadFtpString(const char *string)
316 return ((NULL != strchr(string, '\r')) ||
317 (NULL != strchr(string, '\n'))) ? TRUE : FALSE;
320 /***********************************************************************
322 * AcceptServerConnect()
324 * After connection request is received from the server this function is
325 * called to accept the connection and close the listening socket
328 static CURLcode AcceptServerConnect(struct connectdata *conn)
330 struct SessionHandle *data = conn->data;
331 curl_socket_t sock = conn->sock[SECONDARYSOCKET];
332 curl_socket_t s = CURL_SOCKET_BAD;
334 struct Curl_sockaddr_storage add;
336 struct sockaddr_in add;
338 curl_socklen_t size = (curl_socklen_t) sizeof(add);
340 if(0 == getsockname(sock, (struct sockaddr *) &add, &size)) {
343 s=accept(sock, (struct sockaddr *) &add, &size);
345 Curl_closesocket(conn, sock); /* close the first socket */
347 if(CURL_SOCKET_BAD == s) {
348 failf(data, "Error accept()ing server connect");
349 return CURLE_FTP_PORT_FAILED;
351 infof(data, "Connection accepted from server\n");
353 conn->sock[SECONDARYSOCKET] = s;
354 curlx_nonblock(s, TRUE); /* enable non-blocking */
355 conn->sock_accepted[SECONDARYSOCKET] = TRUE;
357 if(data->set.fsockopt) {
360 /* activate callback for setting socket options */
361 error = data->set.fsockopt(data->set.sockopt_client,
363 CURLSOCKTYPE_ACCEPT);
366 Curl_closesocket(conn, s); /* close the socket and bail out */
367 conn->sock[SECONDARYSOCKET] = CURL_SOCKET_BAD;
368 return CURLE_ABORTED_BY_CALLBACK;
377 * ftp_timeleft_accept() returns the amount of milliseconds left allowed for
378 * waiting server to connect. If the value is negative, the timeout time has
381 * The start time is stored in progress.t_acceptdata - as set with
382 * Curl_pgrsTime(..., TIMER_STARTACCEPT);
385 static long ftp_timeleft_accept(struct SessionHandle *data)
387 long timeout_ms = DEFAULT_ACCEPT_TIMEOUT;
391 if(data->set.accepttimeout > 0)
392 timeout_ms = data->set.accepttimeout;
396 /* check if the generic timeout possibly is set shorter */
397 other = Curl_timeleft(data, &now, FALSE);
398 if(other && (other < timeout_ms))
399 /* note that this also works fine for when other happens to be negative
400 due to it already having elapsed */
403 /* subtract elapsed time */
404 timeout_ms -= Curl_tvdiff(now, data->progress.t_acceptdata);
406 /* avoid returning 0 as that means no timeout! */
414 /***********************************************************************
416 * ReceivedServerConnect()
418 * After allowing server to connect to us from data port, this function
419 * checks both data connection for connection establishment and ctrl
420 * connection for a negative response regarding a failure in connecting
423 static CURLcode ReceivedServerConnect(struct connectdata *conn, bool *received)
425 struct SessionHandle *data = conn->data;
426 curl_socket_t ctrl_sock = conn->sock[FIRSTSOCKET];
427 curl_socket_t data_sock = conn->sock[SECONDARYSOCKET];
428 struct ftp_conn *ftpc = &conn->proto.ftpc;
429 struct pingpong *pp = &ftpc->pp;
437 timeout_ms = ftp_timeleft_accept(data);
438 infof(data, "Checking for server connect\n");
440 /* if a timeout was already reached, bail out */
441 failf(data, "Accept timeout occurred while waiting server connect");
442 return CURLE_FTP_ACCEPT_TIMEOUT;
445 /* First check whether there is a cached response from server */
446 if(pp->cache_size && pp->cache && pp->cache[0] > '3') {
447 /* Data connection could not be established, let's return */
448 infof(data, "There is negative response in cache while serv connect\n");
449 Curl_GetFTPResponse(&nread, conn, &ftpcode);
450 return CURLE_FTP_ACCEPT_FAILED;
453 result = Curl_socket_check(ctrl_sock, data_sock, CURL_SOCKET_BAD, 0);
455 /* see if the connection request is already here */
459 failf(data, "Error while waiting for server connect");
460 return CURLE_FTP_ACCEPT_FAILED;
461 case 0: /* Server connect is not received yet */
465 if(result & CURL_CSELECT_IN2) {
466 infof(data, "Ready to accept data connection from server\n");
469 else if(result & CURL_CSELECT_IN) {
470 infof(data, "Ctrl conn has data while waiting for data conn\n");
471 Curl_GetFTPResponse(&nread, conn, &ftpcode);
474 return CURLE_FTP_ACCEPT_FAILED;
476 return CURLE_FTP_WEIRD_SERVER_REPLY;
486 /***********************************************************************
490 * After connection from server is accepted this function is called to
491 * setup transfer parameters and initiate the data transfer.
494 static CURLcode InitiateTransfer(struct connectdata *conn)
496 struct SessionHandle *data = conn->data;
497 struct FTP *ftp = data->state.proto.ftp;
498 CURLcode result = CURLE_OK;
500 if(conn->ssl[SECONDARYSOCKET].use) {
501 /* since we only have a plaintext TCP connection here, we must now
502 * do the TLS stuff */
503 infof(data, "Doing the SSL/TLS handshake on the data stream\n");
504 result = Curl_ssl_connect(conn, SECONDARYSOCKET);
509 if(conn->proto.ftpc.state_saved == FTP_STOR) {
510 *(ftp->bytecountp)=0;
512 /* When we know we're uploading a specified file, we can get the file
513 size prior to the actual upload. */
515 Curl_pgrsSetUploadSize(data, data->set.infilesize);
517 /* set the SO_SNDBUF for the secondary socket for those who need it */
518 Curl_sndbufset(conn->sock[SECONDARYSOCKET]);
520 Curl_setup_transfer(conn, -1, -1, FALSE, NULL, /* no download */
521 SECONDARYSOCKET, ftp->bytecountp);
525 Curl_setup_transfer(conn, SECONDARYSOCKET,
526 conn->proto.ftpc.retr_size_saved, FALSE,
527 ftp->bytecountp, -1, NULL); /* no upload here */
530 conn->proto.ftpc.pp.pending_resp = TRUE; /* expect server response */
531 state(conn, FTP_STOP);
536 /***********************************************************************
538 * AllowServerConnect()
540 * When we've issue the PORT command, we have told the server to connect to
541 * us. This function checks whether data connection is established if so it is
545 static CURLcode AllowServerConnect(struct connectdata *conn, bool *connected)
547 struct SessionHandle *data = conn->data;
549 CURLcode ret = CURLE_OK;
552 infof(data, "Preparing for accepting server on data port\n");
554 /* Save the time we start accepting server connect */
555 Curl_pgrsTime(data, TIMER_STARTACCEPT);
557 timeout_ms = ftp_timeleft_accept(data);
559 /* if a timeout was already reached, bail out */
560 failf(data, "Accept timeout occurred while waiting server connect");
561 return CURLE_FTP_ACCEPT_TIMEOUT;
564 /* see if the connection request is already here */
565 ret = ReceivedServerConnect(conn, connected);
570 ret = AcceptServerConnect(conn);
574 ret = InitiateTransfer(conn);
579 /* Add timeout to multi handle and break out of the loop */
580 if(ret == CURLE_OK && *connected == FALSE) {
581 if(data->set.accepttimeout > 0)
582 Curl_expire(data, data->set.accepttimeout);
584 Curl_expire(data, DEFAULT_ACCEPT_TIMEOUT);
591 /* macro to check for a three-digit ftp status code at the start of the
593 #define STATUSCODE(line) (ISDIGIT(line[0]) && ISDIGIT(line[1]) && \
596 /* macro to check for the last line in an FTP server response */
597 #define LASTLINE(line) (STATUSCODE(line) && (' ' == line[3]))
599 static bool ftp_endofresp(struct connectdata *conn, char *line, size_t len,
604 if((len > 3) && LASTLINE(line)) {
605 *code = curlx_sltosi(strtol(line, NULL, 10));
612 static CURLcode ftp_readresp(curl_socket_t sockfd,
614 int *ftpcode, /* return the ftp-code if done */
615 size_t *size) /* size of the response */
617 struct connectdata *conn = pp->conn;
618 struct SessionHandle *data = conn->data;
619 #if defined(HAVE_KRB4) || defined(HAVE_GSSAPI)
620 char * const buf = data->state.buffer;
622 CURLcode result = CURLE_OK;
625 result = Curl_pp_readresp(sockfd, pp, &code, size);
627 #if defined(HAVE_KRB4) || defined(HAVE_GSSAPI)
628 /* handle the security-oriented responses 6xx ***/
629 /* FIXME: some errorchecking perhaps... ***/
632 code = Curl_sec_read_msg(conn, buf, PROT_SAFE);
635 code = Curl_sec_read_msg(conn, buf, PROT_PRIVATE);
638 code = Curl_sec_read_msg(conn, buf, PROT_CONFIDENTIAL);
641 /* normal ftp stuff we pass through! */
646 /* store the latest code for later retrieval */
647 data->info.httpcode=code;
653 /* 421 means "Service not available, closing control connection." and FTP
654 * servers use it to signal that idle session timeout has been exceeded.
655 * If we ignored the response, it could end up hanging in some cases.
657 * This response code can come at any point so having it treated
658 * generically is a good idea.
660 infof(data, "We got a 421 - timeout!\n");
661 state(conn, FTP_STOP);
662 return CURLE_OPERATION_TIMEDOUT;
668 /* --- parse FTP server responses --- */
671 * Curl_GetFTPResponse() is a BLOCKING function to read the full response
672 * from a server after a command.
676 CURLcode Curl_GetFTPResponse(ssize_t *nreadp, /* return number of bytes read */
677 struct connectdata *conn,
678 int *ftpcode) /* return the ftp-code */
681 * We cannot read just one byte per read() and then go back to select() as
682 * the OpenSSL read() doesn't grok that properly.
684 * Alas, read as much as possible, split up into lines, use the ending
685 * line in a response or continue reading. */
687 curl_socket_t sockfd = conn->sock[FIRSTSOCKET];
688 long timeout; /* timeout in milliseconds */
690 struct SessionHandle *data = conn->data;
691 CURLcode result = CURLE_OK;
692 struct ftp_conn *ftpc = &conn->proto.ftpc;
693 struct pingpong *pp = &ftpc->pp;
696 int value_to_be_ignored=0;
699 *ftpcode = 0; /* 0 for errors */
701 /* make the pointer point to something for the rest of this function */
702 ftpcode = &value_to_be_ignored;
706 while(!*ftpcode && !result) {
707 /* check and reset timeout value every lap */
708 timeout = Curl_pp_state_timeout(pp);
711 failf(data, "FTP response timeout");
712 return CURLE_OPERATION_TIMEDOUT; /* already too little time */
715 interval_ms = 1000; /* use 1 second timeout intervals */
716 if(timeout < interval_ms)
717 interval_ms = timeout;
720 * Since this function is blocking, we need to wait here for input on the
721 * connection and only then we call the response reading function. We do
722 * timeout at least every second to make the timeout check run.
724 * A caution here is that the ftp_readresp() function has a cache that may
725 * contain pieces of a response from the previous invoke and we need to
726 * make sure we don't just wait for input while there is unhandled data in
727 * that cache. But also, if the cache is there, we call ftp_readresp() and
728 * the cache wasn't good enough to continue we must not just busy-loop
729 * around this function.
733 if(pp->cache && (cache_skip < 2)) {
735 * There's a cache left since before. We then skipping the wait for
736 * socket action, unless this is the same cache like the previous round
737 * as then the cache was deemed not enough to act on and we then need to
738 * wait for more data anyway.
742 switch (Curl_socket_ready(sockfd, CURL_SOCKET_BAD, interval_ms)) {
743 case -1: /* select() error, stop reading */
744 failf(data, "FTP response aborted due to select/poll error: %d",
746 return CURLE_RECV_ERROR;
748 case 0: /* timeout */
749 if(Curl_pgrsUpdate(conn))
750 return CURLE_ABORTED_BY_CALLBACK;
751 continue; /* just continue in our loop for the timeout duration */
753 default: /* for clarity */
757 result = ftp_readresp(sockfd, pp, ftpcode, &nread);
761 if(!nread && pp->cache)
762 /* bump cache skip counter as on repeated skips we must wait for more
766 /* when we got data or there is no cache left, we reset the cache skip
772 } /* while there's buffer left and loop is requested */
774 pp->pending_resp = FALSE;
779 /* This is the ONLY way to change FTP state! */
780 static void _state(struct connectdata *conn,
787 #if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
788 /* for debug purposes */
789 static const char * const names[]={
827 struct ftp_conn *ftpc = &conn->proto.ftpc;
828 #if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
829 if(ftpc->state != newstate)
830 infof(conn->data, "FTP %p (line %d) state change from %s to %s\n",
831 ftpc, lineno, names[ftpc->state], names[newstate]);
833 ftpc->state = newstate;
836 static CURLcode ftp_state_user(struct connectdata *conn)
839 struct FTP *ftp = conn->data->state.proto.ftp;
841 PPSENDF(&conn->proto.ftpc.pp, "USER %s", ftp->user?ftp->user:"");
843 state(conn, FTP_USER);
844 conn->data->state.ftp_trying_alternative = FALSE;
849 static CURLcode ftp_state_pwd(struct connectdata *conn)
853 /* send PWD to discover our entry point */
854 PPSENDF(&conn->proto.ftpc.pp, "PWD", NULL);
855 state(conn, FTP_PWD);
860 /* For the FTP "protocol connect" and "doing" phases only */
861 static int ftp_getsock(struct connectdata *conn,
862 curl_socket_t *socks,
865 return Curl_pp_getsock(&conn->proto.ftpc.pp, socks, numsocks);
868 /* For the FTP "DO_MORE" phase only */
869 static int ftp_domore_getsock(struct connectdata *conn, curl_socket_t *socks,
872 struct ftp_conn *ftpc = &conn->proto.ftpc;
875 return GETSOCK_BLANK;
877 /* When in DO_MORE state, we could be either waiting for us to connect to a
878 remote site, or we could wait for that site to connect to us. Or just
879 handle ordinary commands.
881 When waiting for a connect, we will be in FTP_STOP state and then we wait
882 for the secondary socket to become writeable. If we're in another state,
883 we're still handling commands on the control (primary) connection.
887 switch(ftpc->state) {
891 return Curl_pp_getsock(&conn->proto.ftpc.pp, socks, numsocks);
894 socks[0] = conn->sock[SECONDARYSOCKET];
895 if(ftpc->wait_data_conn) {
896 socks[1] = conn->sock[FIRSTSOCKET];
897 return GETSOCK_READSOCK(0) | GETSOCK_READSOCK(1);
900 return GETSOCK_READSOCK(0);
903 /* This is called after the FTP_QUOTE state is passed.
905 ftp_state_cwd() sends the range of CWD commands to the server to change to
906 the correct directory. It may also need to send MKD commands to create
907 missing ones, if that option is enabled.
909 static CURLcode ftp_state_cwd(struct connectdata *conn)
911 CURLcode result = CURLE_OK;
912 struct ftp_conn *ftpc = &conn->proto.ftpc;
915 /* already done and fine */
916 result = ftp_state_post_cwd(conn);
918 ftpc->count2 = 0; /* count2 counts failed CWDs */
920 /* count3 is set to allow a MKD to fail once. In the case when first CWD
921 fails and then MKD fails (due to another session raced it to create the
922 dir) this then allows for a second try to CWD to it */
923 ftpc->count3 = (conn->data->set.ftp_create_missing_dirs==2)?1:0;
925 if(conn->bits.reuse && ftpc->entrypath) {
926 /* This is a re-used connection. Since we change directory to where the
927 transfer is taking place, we must first get back to the original dir
928 where we ended up after login: */
929 ftpc->count1 = 0; /* we count this as the first path, then we add one
930 for all upcoming ones in the ftp->dirs[] array */
931 PPSENDF(&conn->proto.ftpc.pp, "CWD %s", ftpc->entrypath);
932 state(conn, FTP_CWD);
937 /* issue the first CWD, the rest is sent when the CWD responses are
939 PPSENDF(&conn->proto.ftpc.pp, "CWD %s", ftpc->dirs[ftpc->count1 -1]);
940 state(conn, FTP_CWD);
943 /* No CWD necessary */
944 result = ftp_state_post_cwd(conn);
957 static CURLcode ftp_state_use_port(struct connectdata *conn,
958 ftpport fcmd) /* start with this */
961 CURLcode result = CURLE_OK;
962 struct ftp_conn *ftpc = &conn->proto.ftpc;
963 struct SessionHandle *data=conn->data;
964 curl_socket_t portsock= CURL_SOCKET_BAD;
965 char myhost[256] = "";
967 struct Curl_sockaddr_storage ss;
968 Curl_addrinfo *res, *ai;
969 curl_socklen_t sslen;
970 char hbuf[NI_MAXHOST];
971 struct sockaddr *sa=(struct sockaddr *)&ss;
972 struct sockaddr_in * const sa4 = (void *)sa;
974 struct sockaddr_in6 * const sa6 = (void *)sa;
977 static const char mode[][5] = { "EPRT", "PORT" };
981 char *string_ftpport = data->set.str[STRING_FTPPORT];
982 struct Curl_dns_entry *h=NULL;
983 unsigned short port_min = 0;
984 unsigned short port_max = 0;
986 bool possibly_non_local = TRUE;
990 /* Step 1, figure out what is requested,
992 * (ipv4|ipv6|domain|interface)?(:port(-range)?)?
995 if(data->set.str[STRING_FTPPORT] &&
996 (strlen(data->set.str[STRING_FTPPORT]) > 1)) {
999 size_t addrlen = INET6_ADDRSTRLEN > strlen(string_ftpport) ?
1000 INET6_ADDRSTRLEN : strlen(string_ftpport);
1002 size_t addrlen = INET_ADDRSTRLEN > strlen(string_ftpport) ?
1003 INET_ADDRSTRLEN : strlen(string_ftpport);
1005 char *ip_start = string_ftpport;
1006 char *ip_end = NULL;
1007 char *port_start = NULL;
1008 char *port_sep = NULL;
1010 addr = calloc(addrlen+1, 1);
1012 return CURLE_OUT_OF_MEMORY;
1015 if(*string_ftpport == '[') {
1016 /* [ipv6]:port(-range) */
1017 ip_start = string_ftpport + 1;
1018 if((ip_end = strchr(string_ftpport, ']')) != NULL )
1019 strncpy(addr, ip_start, ip_end - ip_start);
1023 if(*string_ftpport == ':') {
1025 ip_end = string_ftpport;
1027 else if((ip_end = strchr(string_ftpport, ':')) != NULL) {
1028 /* either ipv6 or (ipv4|domain|interface):port(-range) */
1030 if(Curl_inet_pton(AF_INET6, string_ftpport, sa6) == 1) {
1032 port_min = port_max = 0;
1033 strcpy(addr, string_ftpport);
1034 ip_end = NULL; /* this got no port ! */
1038 /* (ipv4|domain|interface):port(-range) */
1039 strncpy(addr, string_ftpport, ip_end - ip_start );
1042 /* ipv4|interface */
1043 strcpy(addr, string_ftpport);
1045 /* parse the port */
1046 if(ip_end != NULL) {
1047 if((port_start = strchr(ip_end, ':')) != NULL) {
1048 port_min = curlx_ultous(strtoul(port_start+1, NULL, 10));
1049 if((port_sep = strchr(port_start, '-')) != NULL) {
1050 port_max = curlx_ultous(strtoul(port_sep + 1, NULL, 10));
1053 port_max = port_min;
1057 /* correct errors like:
1059 * :-4711 , in this case port_min is (unsigned)-1,
1060 * therefore port_min > port_max for all cases
1061 * but port_max = (unsigned)-1
1063 if(port_min > port_max )
1064 port_min = port_max = 0;
1068 /* attempt to get the address of the given interface name */
1069 if(!Curl_if2ip(conn->ip_addr->ai_family, addr,
1070 hbuf, sizeof(hbuf)))
1071 /* not an interface, use the given string as host name instead */
1074 host = hbuf; /* use the hbuf for host name */
1077 /* there was only a port(-range) given, default the host */
1079 } /* data->set.ftpport */
1082 /* not an interface and not a host name, get default by extracting
1083 the IP from the control connection */
1086 if(getsockname(conn->sock[FIRSTSOCKET], sa, &sslen)) {
1087 failf(data, "getsockname() failed: %s",
1088 Curl_strerror(conn, SOCKERRNO) );
1089 Curl_safefree(addr);
1090 return CURLE_FTP_PORT_FAILED;
1092 switch(sa->sa_family) {
1095 Curl_inet_ntop(sa->sa_family, &sa6->sin6_addr, hbuf, sizeof(hbuf));
1099 Curl_inet_ntop(sa->sa_family, &sa4->sin_addr, hbuf, sizeof(hbuf));
1102 host = hbuf; /* use this host name */
1103 possibly_non_local = FALSE; /* we know it is local now */
1106 /* resolv ip/host to ip */
1107 rc = Curl_resolv(conn, host, 0, &h);
1108 if(rc == CURLRESOLV_PENDING)
1109 (void)Curl_resolver_wait_resolv(conn, &h);
1112 /* when we return from this function, we can forget about this entry
1113 to we can unlock it now already */
1114 Curl_resolv_unlock(data, h);
1117 res = NULL; /* failure! */
1120 failf(data, "failed to resolve the address provided to PORT: %s", host);
1121 Curl_safefree(addr);
1122 return CURLE_FTP_PORT_FAILED;
1125 Curl_safefree(addr);
1128 /* step 2, create a socket for the requested address */
1130 portsock = CURL_SOCKET_BAD;
1132 for(ai = res; ai; ai = ai->ai_next) {
1133 result = Curl_socket(conn, ai, NULL, &portsock);
1141 failf(data, "socket failure: %s", Curl_strerror(conn, error));
1142 return CURLE_FTP_PORT_FAILED;
1145 /* step 3, bind to a suitable local address */
1147 memcpy(sa, ai->ai_addr, ai->ai_addrlen);
1148 sslen = ai->ai_addrlen;
1150 for(port = port_min; port <= port_max;) {
1151 if(sa->sa_family == AF_INET)
1152 sa4->sin_port = htons(port);
1155 sa6->sin6_port = htons(port);
1157 /* Try binding the given address. */
1158 if(bind(portsock, sa, sslen) ) {
1161 if(possibly_non_local && (error == EADDRNOTAVAIL)) {
1162 /* The requested bind address is not local. Use the address used for
1163 * the control connection instead and restart the port loop
1166 infof(data, "bind(port=%hu) on non-local address failed: %s\n", port,
1167 Curl_strerror(conn, error) );
1170 if(getsockname(conn->sock[FIRSTSOCKET], sa, &sslen)) {
1171 failf(data, "getsockname() failed: %s",
1172 Curl_strerror(conn, SOCKERRNO) );
1173 Curl_closesocket(conn, portsock);
1174 return CURLE_FTP_PORT_FAILED;
1177 possibly_non_local = FALSE; /* don't try this again */
1180 else if(error != EADDRINUSE && error != EACCES) {
1181 failf(data, "bind(port=%hu) failed: %s", port,
1182 Curl_strerror(conn, error) );
1183 Curl_closesocket(conn, portsock);
1184 return CURLE_FTP_PORT_FAILED;
1193 /* maybe all ports were in use already*/
1194 if(port > port_max) {
1195 failf(data, "bind() failed, we ran out of ports!");
1196 Curl_closesocket(conn, portsock);
1197 return CURLE_FTP_PORT_FAILED;
1200 /* get the name again after the bind() so that we can extract the
1201 port number it uses now */
1203 if(getsockname(portsock, (struct sockaddr *)sa, &sslen)) {
1204 failf(data, "getsockname() failed: %s",
1205 Curl_strerror(conn, SOCKERRNO) );
1206 Curl_closesocket(conn, portsock);
1207 return CURLE_FTP_PORT_FAILED;
1210 /* step 4, listen on the socket */
1212 if(listen(portsock, 1)) {
1213 failf(data, "socket failure: %s", Curl_strerror(conn, SOCKERRNO));
1214 Curl_closesocket(conn, portsock);
1215 return CURLE_FTP_PORT_FAILED;
1218 /* step 5, send the proper FTP command */
1220 /* get a plain printable version of the numerical address to work with
1222 Curl_printable_address(ai, myhost, sizeof(myhost));
1225 if(!conn->bits.ftp_use_eprt && conn->bits.ipv6)
1226 /* EPRT is disabled but we are connected to a IPv6 host, so we ignore the
1227 request and enable EPRT again! */
1228 conn->bits.ftp_use_eprt = TRUE;
1231 for(; fcmd != DONE; fcmd++) {
1233 if(!conn->bits.ftp_use_eprt && (EPRT == fcmd))
1234 /* if disabled, goto next */
1237 if((PORT == fcmd) && sa->sa_family != AF_INET)
1238 /* PORT is ipv4 only */
1241 switch (sa->sa_family) {
1243 port = ntohs(sa4->sin_port);
1247 port = ntohs(sa6->sin6_port);
1251 continue; /* might as well skip this */
1256 * Two fine examples from RFC2428;
1258 * EPRT |1|132.235.1.2|6275|
1260 * EPRT |2|1080::8:800:200C:417A|5282|
1263 result = Curl_pp_sendf(&ftpc->pp, "%s |%d|%s|%hu|", mode[fcmd],
1264 sa->sa_family == AF_INET?1:2,
1267 failf(data, "Failure sending EPRT command: %s",
1268 curl_easy_strerror(result));
1269 Curl_closesocket(conn, portsock);
1270 /* don't retry using PORT */
1271 ftpc->count1 = PORT;
1273 state(conn, FTP_STOP);
1278 else if(PORT == fcmd) {
1279 char *source = myhost;
1282 /* translate x.x.x.x to x,x,x,x */
1283 while(source && *source) {
1292 snprintf(dest, 20, ",%d,%d", (int)(port>>8), (int)(port&0xff));
1294 result = Curl_pp_sendf(&ftpc->pp, "%s %s", mode[fcmd], tmp);
1296 failf(data, "Failure sending PORT command: %s",
1297 curl_easy_strerror(result));
1298 Curl_closesocket(conn, portsock);
1300 state(conn, FTP_STOP);
1307 /* store which command was sent */
1308 ftpc->count1 = fcmd;
1310 /* we set the secondary socket variable to this for now, it is only so that
1311 the cleanup function will close it in case we fail before the true
1312 secondary stuff is made */
1313 if(CURL_SOCKET_BAD != conn->sock[SECONDARYSOCKET])
1314 Curl_closesocket(conn, conn->sock[SECONDARYSOCKET]);
1315 conn->sock[SECONDARYSOCKET] = portsock;
1317 /* this tcpconnect assignment below is a hackish work-around to make the
1318 multi interface with active FTP work - as it will not wait for a
1319 (passive) connect in Curl_is_connected().
1321 The *proper* fix is to make sure that the active connection from the
1322 server is done in a non-blocking way. Currently, it is still BLOCKING.
1324 conn->bits.tcpconnect[SECONDARYSOCKET] = TRUE;
1326 state(conn, FTP_PORT);
1330 static CURLcode ftp_state_use_pasv(struct connectdata *conn)
1332 struct ftp_conn *ftpc = &conn->proto.ftpc;
1333 CURLcode result = CURLE_OK;
1335 Here's the excecutive summary on what to do:
1337 PASV is RFC959, expect:
1338 227 Entering Passive Mode (a1,a2,a3,a4,p1,p2)
1340 LPSV is RFC1639, expect:
1341 228 Entering Long Passive Mode (4,4,a1,a2,a3,a4,2,p1,p2)
1343 EPSV is RFC2428, expect:
1344 229 Entering Extended Passive Mode (|||port|)
1348 static const char mode[][5] = { "EPSV", "PASV" };
1352 if(!conn->bits.ftp_use_epsv && conn->bits.ipv6)
1353 /* EPSV is disabled but we are connected to a IPv6 host, so we ignore the
1354 request and enable EPSV again! */
1355 conn->bits.ftp_use_epsv = TRUE;
1358 modeoff = conn->bits.ftp_use_epsv?0:1;
1360 PPSENDF(&ftpc->pp, "%s", mode[modeoff]);
1362 ftpc->count1 = modeoff;
1363 state(conn, FTP_PASV);
1364 infof(conn->data, "Connect data stream passively\n");
1369 /* REST is the last command in the chain of commands when a "head"-like
1370 request is made. Thus, if an actual transfer is to be made this is where
1371 we take off for real. */
1372 static CURLcode ftp_state_post_rest(struct connectdata *conn)
1374 CURLcode result = CURLE_OK;
1375 struct FTP *ftp = conn->data->state.proto.ftp;
1376 struct SessionHandle *data = conn->data;
1378 if(ftp->transfer != FTPTRANSFER_BODY) {
1379 /* doesn't transfer any data */
1381 /* still possibly do PRE QUOTE jobs */
1382 state(conn, FTP_RETR_PREQUOTE);
1383 result = ftp_state_quote(conn, TRUE, FTP_RETR_PREQUOTE);
1385 else if(data->set.ftp_use_port) {
1386 /* We have chosen to use the PORT (or similar) command */
1387 result = ftp_state_use_port(conn, EPRT);
1390 /* We have chosen (this is default) to use the PASV (or similar) command */
1391 if(data->set.ftp_use_pret) {
1392 /* The user has requested that we send a PRET command
1393 to prepare the server for the upcoming PASV */
1394 if(!conn->proto.ftpc.file) {
1395 PPSENDF(&conn->proto.ftpc.pp, "PRET %s",
1396 data->set.str[STRING_CUSTOMREQUEST]?
1397 data->set.str[STRING_CUSTOMREQUEST]:
1398 (data->set.ftp_list_only?"NLST":"LIST"));
1400 else if(data->set.upload) {
1401 PPSENDF(&conn->proto.ftpc.pp, "PRET STOR %s", conn->proto.ftpc.file);
1404 PPSENDF(&conn->proto.ftpc.pp, "PRET RETR %s", conn->proto.ftpc.file);
1406 state(conn, FTP_PRET);
1409 result = ftp_state_use_pasv(conn);
1415 static CURLcode ftp_state_post_size(struct connectdata *conn)
1417 CURLcode result = CURLE_OK;
1418 struct FTP *ftp = conn->data->state.proto.ftp;
1419 struct ftp_conn *ftpc = &conn->proto.ftpc;
1421 if((ftp->transfer != FTPTRANSFER_BODY) && ftpc->file) {
1422 /* if a "head"-like request is being made (on a file) */
1424 /* Determine if server can respond to REST command and therefore
1425 whether it supports range */
1426 PPSENDF(&conn->proto.ftpc.pp, "REST %d", 0);
1428 state(conn, FTP_REST);
1431 result = ftp_state_post_rest(conn);
1436 static CURLcode ftp_state_post_type(struct connectdata *conn)
1438 CURLcode result = CURLE_OK;
1439 struct FTP *ftp = conn->data->state.proto.ftp;
1440 struct ftp_conn *ftpc = &conn->proto.ftpc;
1442 if((ftp->transfer == FTPTRANSFER_INFO) && ftpc->file) {
1443 /* if a "head"-like request is being made (on a file) */
1445 /* we know ftpc->file is a valid pointer to a file name */
1446 PPSENDF(&ftpc->pp, "SIZE %s", ftpc->file);
1448 state(conn, FTP_SIZE);
1451 result = ftp_state_post_size(conn);
1456 static CURLcode ftp_state_post_listtype(struct connectdata *conn)
1458 CURLcode result = CURLE_OK;
1459 struct SessionHandle *data = conn->data;
1461 /* If this output is to be machine-parsed, the NLST command might be better
1462 to use, since the LIST command output is not specified or standard in any
1463 way. It has turned out that the NLST list output is not the same on all
1464 servers either... */
1467 if FTPFILE_NOCWD was specified, we are currently in
1468 the user's home directory, so we should add the path
1469 as argument for the LIST / NLST / or custom command.
1470 Whether the server will support this, is uncertain.
1472 The other ftp_filemethods will CWD into dir/dir/ first and
1473 then just do LIST (in that case: nothing to do here)
1475 char *cmd,*lstArg,*slashPos;
1478 if((data->set.ftp_filemethod == FTPFILE_NOCWD) &&
1480 data->state.path[0] &&
1481 strchr(data->state.path,'/')) {
1483 lstArg = strdup(data->state.path);
1485 return CURLE_OUT_OF_MEMORY;
1487 /* Check if path does not end with /, as then we cut off the file part */
1488 if(lstArg[strlen(lstArg) - 1] != '/') {
1490 /* chop off the file part if format is dir/dir/file */
1491 slashPos = strrchr(lstArg,'/');
1493 *(slashPos+1) = '\0';
1497 cmd = aprintf( "%s%s%s",
1498 data->set.str[STRING_CUSTOMREQUEST]?
1499 data->set.str[STRING_CUSTOMREQUEST]:
1500 (data->set.ftp_list_only?"NLST":"LIST"),
1502 lstArg? lstArg: "" );
1507 return CURLE_OUT_OF_MEMORY;
1510 result = Curl_pp_sendf(&conn->proto.ftpc.pp, "%s", cmd);
1517 if(result != CURLE_OK)
1520 state(conn, FTP_LIST);
1525 static CURLcode ftp_state_post_retrtype(struct connectdata *conn)
1527 CURLcode result = CURLE_OK;
1529 /* We've sent the TYPE, now we must send the list of prequote strings */
1531 result = ftp_state_quote(conn, TRUE, FTP_RETR_PREQUOTE);
1536 static CURLcode ftp_state_post_stortype(struct connectdata *conn)
1538 CURLcode result = CURLE_OK;
1540 /* We've sent the TYPE, now we must send the list of prequote strings */
1542 result = ftp_state_quote(conn, TRUE, FTP_STOR_PREQUOTE);
1547 static CURLcode ftp_state_post_mdtm(struct connectdata *conn)
1549 CURLcode result = CURLE_OK;
1550 struct FTP *ftp = conn->data->state.proto.ftp;
1551 struct SessionHandle *data = conn->data;
1552 struct ftp_conn *ftpc = &conn->proto.ftpc;
1554 /* If we have selected NOBODY and HEADER, it means that we only want file
1555 information. Which in FTP can't be much more than the file size and
1557 if(data->set.opt_no_body && ftpc->file &&
1558 ftp_need_type(conn, data->set.prefer_ascii)) {
1559 /* The SIZE command is _not_ RFC 959 specified, and therefor many servers
1560 may not support it! It is however the only way we have to get a file's
1563 ftp->transfer = FTPTRANSFER_INFO;
1564 /* this means no actual transfer will be made */
1566 /* Some servers return different sizes for different modes, and thus we
1567 must set the proper type before we check the size */
1568 result = ftp_nb_type(conn, data->set.prefer_ascii, FTP_TYPE);
1573 result = ftp_state_post_type(conn);
1578 /* This is called after the CWD commands have been done in the beginning of
1580 static CURLcode ftp_state_post_cwd(struct connectdata *conn)
1582 CURLcode result = CURLE_OK;
1583 struct SessionHandle *data = conn->data;
1584 struct ftp_conn *ftpc = &conn->proto.ftpc;
1586 /* Requested time of file or time-depended transfer? */
1587 if((data->set.get_filetime || data->set.timecondition) && ftpc->file) {
1589 /* we have requested to get the modified-time of the file, this is a white
1590 spot as the MDTM is not mentioned in RFC959 */
1591 PPSENDF(&ftpc->pp, "MDTM %s", ftpc->file);
1593 state(conn, FTP_MDTM);
1596 result = ftp_state_post_mdtm(conn);
1602 /* This is called after the TYPE and possible quote commands have been sent */
1603 static CURLcode ftp_state_ul_setup(struct connectdata *conn,
1606 CURLcode result = CURLE_OK;
1607 struct FTP *ftp = conn->data->state.proto.ftp;
1608 struct SessionHandle *data = conn->data;
1609 struct ftp_conn *ftpc = &conn->proto.ftpc;
1610 int seekerr = CURL_SEEKFUNC_OK;
1612 if((data->state.resume_from && !sizechecked) ||
1613 ((data->state.resume_from > 0) && sizechecked)) {
1614 /* we're about to continue the uploading of a file */
1615 /* 1. get already existing file's size. We use the SIZE command for this
1616 which may not exist in the server! The SIZE command is not in
1619 /* 2. This used to set REST. But since we can do append, we
1620 don't another ftp command. We just skip the source file
1621 offset and then we APPEND the rest on the file instead */
1623 /* 3. pass file-size number of bytes in the source file */
1624 /* 4. lower the infilesize counter */
1625 /* => transfer as usual */
1627 if(data->state.resume_from < 0 ) {
1628 /* Got no given size to start from, figure it out */
1629 PPSENDF(&ftpc->pp, "SIZE %s", ftpc->file);
1630 state(conn, FTP_STOR_SIZE);
1635 data->set.ftp_append = TRUE;
1637 /* Let's read off the proper amount of bytes from the input. */
1638 if(conn->seek_func) {
1639 seekerr = conn->seek_func(conn->seek_client, data->state.resume_from,
1643 if(seekerr != CURL_SEEKFUNC_OK) {
1644 if(seekerr != CURL_SEEKFUNC_CANTSEEK) {
1645 failf(data, "Could not seek stream");
1646 return CURLE_FTP_COULDNT_USE_REST;
1648 /* seekerr == CURL_SEEKFUNC_CANTSEEK (can't seek to offset) */
1650 curl_off_t passed=0;
1652 size_t readthisamountnow =
1653 (data->state.resume_from - passed > CURL_OFF_T_C(BUFSIZE)) ?
1654 BUFSIZE : curlx_sotouz(data->state.resume_from - passed);
1656 size_t actuallyread =
1657 conn->fread_func(data->state.buffer, 1, readthisamountnow,
1660 passed += actuallyread;
1661 if((actuallyread == 0) || (actuallyread > readthisamountnow)) {
1662 /* this checks for greater-than only to make sure that the
1663 CURL_READFUNC_ABORT return code still aborts */
1664 failf(data, "Failed to read data");
1665 return CURLE_FTP_COULDNT_USE_REST;
1667 } while(passed < data->state.resume_from);
1670 /* now, decrease the size of the read */
1671 if(data->set.infilesize>0) {
1672 data->set.infilesize -= data->state.resume_from;
1674 if(data->set.infilesize <= 0) {
1675 infof(data, "File already completely uploaded\n");
1677 /* no data to transfer */
1678 Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
1680 /* Set ->transfer so that we won't get any error in
1681 * ftp_done() because we didn't transfer anything! */
1682 ftp->transfer = FTPTRANSFER_NONE;
1684 state(conn, FTP_STOP);
1688 /* we've passed, proceed as normal */
1691 PPSENDF(&ftpc->pp, data->set.ftp_append?"APPE %s":"STOR %s",
1694 state(conn, FTP_STOR);
1699 static CURLcode ftp_state_quote(struct connectdata *conn,
1703 CURLcode result = CURLE_OK;
1704 struct SessionHandle *data = conn->data;
1705 struct FTP *ftp = data->state.proto.ftp;
1706 struct ftp_conn *ftpc = &conn->proto.ftpc;
1708 struct curl_slist *item;
1713 item = data->set.quote;
1715 case FTP_RETR_PREQUOTE:
1716 case FTP_STOR_PREQUOTE:
1717 item = data->set.prequote;
1720 item = data->set.postquote;
1726 * 'count1' to iterate over the commands to send
1727 * 'count2' to store wether to allow commands to fail
1738 /* Skip count1 items in the linked list */
1739 while((i< ftpc->count1) && item) {
1744 char *cmd = item->data;
1747 ftpc->count2 = 1; /* the sent command is allowed to fail */
1750 ftpc->count2 = 0; /* failure means cancel operation */
1752 PPSENDF(&ftpc->pp, "%s", cmd);
1753 state(conn, instate);
1759 /* No more quote to send, continue to ... */
1763 result = ftp_state_cwd(conn);
1765 case FTP_RETR_PREQUOTE:
1766 if(ftp->transfer != FTPTRANSFER_BODY)
1767 state(conn, FTP_STOP);
1769 if(ftpc->known_filesize != -1) {
1770 Curl_pgrsSetDownloadSize(data, ftpc->known_filesize);
1771 result = ftp_state_post_retr_size(conn, ftpc->known_filesize);
1774 PPSENDF(&ftpc->pp, "SIZE %s", ftpc->file);
1775 state(conn, FTP_RETR_SIZE);
1779 case FTP_STOR_PREQUOTE:
1780 result = ftp_state_ul_setup(conn, FALSE);
1790 /* called from ftp_state_pasv_resp to switch to PASV in case of EPSV
1792 static CURLcode ftp_epsv_disable(struct connectdata *conn)
1794 CURLcode result = CURLE_OK;
1795 infof(conn->data, "got positive EPSV response, but can't connect. "
1796 "Disabling EPSV\n");
1797 /* disable it for next transfer */
1798 conn->bits.ftp_use_epsv = FALSE;
1799 conn->data->state.errorbuf = FALSE; /* allow error message to get
1801 PPSENDF(&conn->proto.ftpc.pp, "PASV", NULL);
1802 conn->proto.ftpc.count1++;
1803 /* remain in the FTP_PASV state */
1807 static CURLcode ftp_state_pasv_resp(struct connectdata *conn,
1810 struct ftp_conn *ftpc = &conn->proto.ftpc;
1812 struct SessionHandle *data=conn->data;
1813 Curl_addrinfo *conninfo;
1814 struct Curl_dns_entry *addr=NULL;
1816 unsigned short connectport; /* the local port connect() should use! */
1817 unsigned short newport=0; /* remote port */
1820 /* newhost must be able to hold a full IP-style address in ASCII, which
1821 in the IPv6 case means 5*8-1 = 39 letters */
1822 #define NEWHOST_BUFSIZE 48
1823 char newhost[NEWHOST_BUFSIZE];
1824 char *str=&data->state.buffer[4]; /* start on the first letter */
1826 if((ftpc->count1 == 0) &&
1828 /* positive EPSV response */
1829 char *ptr = strchr(str, '(');
1834 if(5 == sscanf(ptr, "%c%c%c%u%c",
1840 const char sep1 = separator[0];
1843 /* The four separators should be identical, or else this is an oddly
1844 formatted reply and we bail out immediately. */
1845 for(i=1; i<4; i++) {
1846 if(separator[i] != sep1) {
1847 ptr=NULL; /* set to NULL to signal error */
1852 failf(data, "Illegal port number in EPSV reply");
1853 return CURLE_FTP_WEIRD_PASV_REPLY;
1856 newport = (unsigned short)(num & 0xffff);
1858 if(conn->bits.tunnel_proxy ||
1859 conn->proxytype == CURLPROXY_SOCKS5 ||
1860 conn->proxytype == CURLPROXY_SOCKS5_HOSTNAME ||
1861 conn->proxytype == CURLPROXY_SOCKS4 ||
1862 conn->proxytype == CURLPROXY_SOCKS4A)
1863 /* proxy tunnel -> use other host info because ip_addr_str is the
1864 proxy address not the ftp host */
1865 snprintf(newhost, sizeof(newhost), "%s", conn->host.name);
1867 /* use the same IP we are already connected to */
1868 snprintf(newhost, NEWHOST_BUFSIZE, "%s", conn->ip_addr_str);
1875 failf(data, "Weirdly formatted EPSV reply");
1876 return CURLE_FTP_WEIRD_PASV_REPLY;
1879 else if((ftpc->count1 == 1) &&
1881 /* positive PASV response */
1886 * Scan for a sequence of six comma-separated numbers and use them as
1887 * IP+port indicators.
1889 * Found reply-strings include:
1890 * "227 Entering Passive Mode (127,0,0,1,4,51)"
1891 * "227 Data transfer will passively listen to 127,0,0,1,4,51"
1892 * "227 Entering passive mode. 127,0,0,1,4,51"
1895 if(6 == sscanf(str, "%d,%d,%d,%d,%d,%d",
1896 &ip[0], &ip[1], &ip[2], &ip[3],
1897 &port[0], &port[1]))
1903 failf(data, "Couldn't interpret the 227-response");
1904 return CURLE_FTP_WEIRD_227_FORMAT;
1907 /* we got OK from server */
1908 if(data->set.ftp_skip_ip) {
1909 /* told to ignore the remotely given IP but instead use the one we used
1910 for the control connection */
1911 infof(data, "Skips %d.%d.%d.%d for data connection, uses %s instead\n",
1912 ip[0], ip[1], ip[2], ip[3],
1914 if(conn->bits.tunnel_proxy ||
1915 conn->proxytype == CURLPROXY_SOCKS5 ||
1916 conn->proxytype == CURLPROXY_SOCKS5_HOSTNAME ||
1917 conn->proxytype == CURLPROXY_SOCKS4 ||
1918 conn->proxytype == CURLPROXY_SOCKS4A)
1919 /* proxy tunnel -> use other host info because ip_addr_str is the
1920 proxy address not the ftp host */
1921 snprintf(newhost, sizeof(newhost), "%s", conn->host.name);
1923 snprintf(newhost, sizeof(newhost), "%s", conn->ip_addr_str);
1926 snprintf(newhost, sizeof(newhost),
1927 "%d.%d.%d.%d", ip[0], ip[1], ip[2], ip[3]);
1928 newport = (unsigned short)(((port[0]<<8) + port[1]) & 0xffff);
1930 else if(ftpc->count1 == 0) {
1931 /* EPSV failed, move on to PASV */
1933 /* disable it for next transfer */
1934 conn->bits.ftp_use_epsv = FALSE;
1935 infof(data, "disabling EPSV usage\n");
1937 PPSENDF(&ftpc->pp, "PASV", NULL);
1939 /* remain in the FTP_PASV state */
1943 failf(data, "Bad PASV/EPSV response: %03d", ftpcode);
1944 return CURLE_FTP_WEIRD_PASV_REPLY;
1947 if(data->set.str[STRING_PROXY] && *data->set.str[STRING_PROXY]) {
1949 * This is a tunnel through a http proxy and we need to connect to the
1952 * We don't want to rely on a former host lookup that might've expired
1953 * now, instead we remake the lookup here and now!
1955 rc = Curl_resolv(conn, conn->proxy.name, (int)conn->port, &addr);
1956 if(rc == CURLRESOLV_PENDING)
1957 /* BLOCKING, ignores the return code but 'addr' will be NULL in
1959 (void)Curl_resolver_wait_resolv(conn, &addr);
1962 (unsigned short)conn->port; /* we connect to the proxy's port */
1965 failf(data, "Can't resolve proxy host %s:%hu",
1966 conn->proxy.name, connectport);
1967 return CURLE_FTP_CANT_GET_HOST;
1971 /* normal, direct, ftp connection */
1972 rc = Curl_resolv(conn, newhost, newport, &addr);
1973 if(rc == CURLRESOLV_PENDING)
1975 (void)Curl_resolver_wait_resolv(conn, &addr);
1977 connectport = newport; /* we connect to the remote port */
1980 failf(data, "Can't resolve new host %s:%hu", newhost, connectport);
1981 return CURLE_FTP_CANT_GET_HOST;
1985 result = Curl_connecthost(conn,
1987 &conn->sock[SECONDARYSOCKET],
1991 Curl_resolv_unlock(data, addr); /* we're done using this address */
1994 if(ftpc->count1 == 0 && ftpcode == 229)
1995 return ftp_epsv_disable(conn);
2000 conn->bits.tcpconnect[SECONDARYSOCKET] = connected;
2003 * When this is used from the multi interface, this might've returned with
2004 * the 'connected' set to FALSE and thus we are now awaiting a non-blocking
2005 * connect to connect and we should not be "hanging" here waiting.
2008 if(data->set.verbose)
2009 /* this just dumps information about this second connection */
2010 ftp_pasv_verbose(conn, conninfo, newhost, connectport);
2012 switch(conn->proxytype) {
2013 /* FIX: this MUST wait for a proper connect first if 'connected' is
2015 case CURLPROXY_SOCKS5:
2016 case CURLPROXY_SOCKS5_HOSTNAME:
2017 result = Curl_SOCKS5(conn->proxyuser, conn->proxypasswd, newhost, newport,
2018 SECONDARYSOCKET, conn);
2020 case CURLPROXY_SOCKS4:
2021 result = Curl_SOCKS4(conn->proxyuser, newhost, newport,
2022 SECONDARYSOCKET, conn, FALSE);
2024 case CURLPROXY_SOCKS4A:
2025 result = Curl_SOCKS4(conn->proxyuser, newhost, newport,
2026 SECONDARYSOCKET, conn, TRUE);
2028 case CURLPROXY_HTTP:
2029 case CURLPROXY_HTTP_1_0:
2030 /* do nothing here. handled later. */
2033 failf(data, "unknown proxytype option given");
2034 result = CURLE_COULDNT_CONNECT;
2039 if(ftpc->count1 == 0 && ftpcode == 229)
2040 return ftp_epsv_disable(conn);
2044 if(conn->bits.tunnel_proxy && conn->bits.httpproxy) {
2045 /* FIX: this MUST wait for a proper connect first if 'connected' is
2049 /* We want "seamless" FTP operations through HTTP proxy tunnel */
2051 /* Curl_proxyCONNECT is based on a pointer to a struct HTTP at the member
2052 * conn->proto.http; we want FTP through HTTP and we have to change the
2053 * member temporarily for connecting to the HTTP proxy. After
2054 * Curl_proxyCONNECT we have to set back the member to the original struct
2057 struct HTTP http_proxy;
2058 struct FTP *ftp_save = data->state.proto.ftp;
2059 memset(&http_proxy, 0, sizeof(http_proxy));
2060 data->state.proto.http = &http_proxy;
2062 result = Curl_proxyCONNECT(conn, SECONDARYSOCKET, newhost, newport);
2064 data->state.proto.ftp = ftp_save;
2069 if(conn->tunnel_state[SECONDARYSOCKET] != TUNNEL_COMPLETE) {
2070 /* the CONNECT procedure is not complete, the tunnel is not yet up */
2071 state(conn, FTP_STOP); /* this phase is completed */
2072 conn->bits.tcpconnect[SECONDARYSOCKET] = FALSE;
2078 conn->bits.tcpconnect[SECONDARYSOCKET] = TRUE;
2080 conn->bits.do_more = TRUE;
2081 state(conn, FTP_STOP); /* this phase is completed */
2086 static CURLcode ftp_state_port_resp(struct connectdata *conn,
2089 struct SessionHandle *data = conn->data;
2090 struct ftp_conn *ftpc = &conn->proto.ftpc;
2091 ftpport fcmd = (ftpport)ftpc->count1;
2092 CURLcode result = CURLE_OK;
2094 if(ftpcode != 200) {
2095 /* the command failed */
2098 infof(data, "disabling EPRT usage\n");
2099 conn->bits.ftp_use_eprt = FALSE;
2104 failf(data, "Failed to do PORT");
2105 result = CURLE_FTP_PORT_FAILED;
2109 result = ftp_state_use_port(conn, fcmd);
2112 infof(data, "Connect data stream actively\n");
2113 state(conn, FTP_STOP); /* end of DO phase */
2114 result = ftp_dophase_done(conn, FALSE);
2120 static CURLcode ftp_state_mdtm_resp(struct connectdata *conn,
2123 CURLcode result = CURLE_OK;
2124 struct SessionHandle *data=conn->data;
2125 struct FTP *ftp = data->state.proto.ftp;
2126 struct ftp_conn *ftpc = &conn->proto.ftpc;
2131 /* we got a time. Format should be: "YYYYMMDDHHMMSS[.sss]" where the
2132 last .sss part is optional and means fractions of a second */
2133 int year, month, day, hour, minute, second;
2134 char *buf = data->state.buffer;
2135 if(6 == sscanf(buf+4, "%04d%02d%02d%02d%02d%02d",
2136 &year, &month, &day, &hour, &minute, &second)) {
2137 /* we have a time, reformat it */
2138 time_t secs=time(NULL);
2139 /* using the good old yacc/bison yuck */
2140 snprintf(buf, sizeof(conn->data->state.buffer),
2141 "%04d%02d%02d %02d:%02d:%02d GMT",
2142 year, month, day, hour, minute, second);
2143 /* now, convert this into a time() value: */
2144 data->info.filetime = (long)curl_getdate(buf, &secs);
2147 #ifdef CURL_FTP_HTTPSTYLE_HEAD
2148 /* If we asked for a time of the file and we actually got one as well,
2149 we "emulate" a HTTP-style header in our output. */
2151 if(data->set.opt_no_body &&
2153 data->set.get_filetime &&
2154 (data->info.filetime>=0) ) {
2155 time_t filetime = (time_t)data->info.filetime;
2157 const struct tm *tm = &buffer;
2159 result = Curl_gmtime(filetime, &buffer);
2163 /* format: "Tue, 15 Nov 1994 12:45:26" */
2164 snprintf(buf, BUFSIZE-1,
2165 "Last-Modified: %s, %02d %s %4d %02d:%02d:%02d GMT\r\n",
2166 Curl_wkday[tm->tm_wday?tm->tm_wday-1:6],
2168 Curl_month[tm->tm_mon],
2173 result = Curl_client_write(conn, CLIENTWRITE_BOTH, buf, 0);
2176 } /* end of a ridiculous amount of conditionals */
2181 infof(data, "unsupported MDTM reply format\n");
2183 case 550: /* "No such file or directory" */
2184 failf(data, "Given file does not exist");
2185 result = CURLE_FTP_COULDNT_RETR_FILE;
2189 if(data->set.timecondition) {
2190 if((data->info.filetime > 0) && (data->set.timevalue > 0)) {
2191 switch(data->set.timecondition) {
2192 case CURL_TIMECOND_IFMODSINCE:
2194 if(data->info.filetime <= data->set.timevalue) {
2195 infof(data, "The requested document is not new enough\n");
2196 ftp->transfer = FTPTRANSFER_NONE; /* mark to not transfer data */
2197 data->info.timecond = TRUE;
2198 state(conn, FTP_STOP);
2202 case CURL_TIMECOND_IFUNMODSINCE:
2203 if(data->info.filetime > data->set.timevalue) {
2204 infof(data, "The requested document is not old enough\n");
2205 ftp->transfer = FTPTRANSFER_NONE; /* mark to not transfer data */
2206 data->info.timecond = TRUE;
2207 state(conn, FTP_STOP);
2214 infof(data, "Skipping time comparison\n");
2219 result = ftp_state_post_mdtm(conn);
2224 static CURLcode ftp_state_type_resp(struct connectdata *conn,
2228 CURLcode result = CURLE_OK;
2229 struct SessionHandle *data=conn->data;
2231 if(ftpcode/100 != 2) {
2232 /* "sasserftpd" and "(u)r(x)bot ftpd" both responds with 226 after a
2233 successful 'TYPE I'. While that is not as RFC959 says, it is still a
2234 positive response code and we allow that. */
2235 failf(data, "Couldn't set desired mode");
2236 return CURLE_FTP_COULDNT_SET_TYPE;
2239 infof(data, "Got a %03d response code instead of the assumed 200\n",
2242 if(instate == FTP_TYPE)
2243 result = ftp_state_post_type(conn);
2244 else if(instate == FTP_LIST_TYPE)
2245 result = ftp_state_post_listtype(conn);
2246 else if(instate == FTP_RETR_TYPE)
2247 result = ftp_state_post_retrtype(conn);
2248 else if(instate == FTP_STOR_TYPE)
2249 result = ftp_state_post_stortype(conn);
2254 static CURLcode ftp_state_post_retr_size(struct connectdata *conn,
2255 curl_off_t filesize)
2257 CURLcode result = CURLE_OK;
2258 struct SessionHandle *data=conn->data;
2259 struct FTP *ftp = data->state.proto.ftp;
2260 struct ftp_conn *ftpc = &conn->proto.ftpc;
2262 if(data->set.max_filesize && (filesize > data->set.max_filesize)) {
2263 failf(data, "Maximum file size exceeded");
2264 return CURLE_FILESIZE_EXCEEDED;
2266 ftp->downloadsize = filesize;
2268 if(data->state.resume_from) {
2269 /* We always (attempt to) get the size of downloads, so it is done before
2270 this even when not doing resumes. */
2271 if(filesize == -1) {
2272 infof(data, "ftp server doesn't support SIZE\n");
2273 /* We couldn't get the size and therefore we can't know if there really
2274 is a part of the file left to get, although the server will just
2275 close the connection when we start the connection so it won't cause
2276 us any harm, just not make us exit as nicely. */
2279 /* We got a file size report, so we check that there actually is a
2280 part of the file left to get, or else we go home. */
2281 if(data->state.resume_from< 0) {
2282 /* We're supposed to download the last abs(from) bytes */
2283 if(filesize < -data->state.resume_from) {
2284 failf(data, "Offset (%" FORMAT_OFF_T
2285 ") was beyond file size (%" FORMAT_OFF_T ")",
2286 data->state.resume_from, filesize);
2287 return CURLE_BAD_DOWNLOAD_RESUME;
2289 /* convert to size to download */
2290 ftp->downloadsize = -data->state.resume_from;
2291 /* download from where? */
2292 data->state.resume_from = filesize - ftp->downloadsize;
2295 if(filesize < data->state.resume_from) {
2296 failf(data, "Offset (%" FORMAT_OFF_T
2297 ") was beyond file size (%" FORMAT_OFF_T ")",
2298 data->state.resume_from, filesize);
2299 return CURLE_BAD_DOWNLOAD_RESUME;
2301 /* Now store the number of bytes we are expected to download */
2302 ftp->downloadsize = filesize-data->state.resume_from;
2306 if(ftp->downloadsize == 0) {
2307 /* no data to transfer */
2308 Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
2309 infof(data, "File already completely downloaded\n");
2311 /* Set ->transfer so that we won't get any error in ftp_done()
2312 * because we didn't transfer the any file */
2313 ftp->transfer = FTPTRANSFER_NONE;
2314 state(conn, FTP_STOP);
2318 /* Set resume file transfer offset */
2319 infof(data, "Instructs server to resume from offset %" FORMAT_OFF_T
2320 "\n", data->state.resume_from);
2322 PPSENDF(&ftpc->pp, "REST %" FORMAT_OFF_T, data->state.resume_from);
2324 state(conn, FTP_RETR_REST);
2329 PPSENDF(&ftpc->pp, "RETR %s", ftpc->file);
2330 state(conn, FTP_RETR);
2336 static CURLcode ftp_state_size_resp(struct connectdata *conn,
2340 CURLcode result = CURLE_OK;
2341 struct SessionHandle *data=conn->data;
2342 curl_off_t filesize;
2343 char *buf = data->state.buffer;
2345 /* get the size from the ascii string: */
2346 filesize = (ftpcode == 213)?curlx_strtoofft(buf+4, NULL, 0):-1;
2348 if(instate == FTP_SIZE) {
2349 #ifdef CURL_FTP_HTTPSTYLE_HEAD
2350 if(-1 != filesize) {
2351 snprintf(buf, sizeof(data->state.buffer),
2352 "Content-Length: %" FORMAT_OFF_T "\r\n", filesize);
2353 result = Curl_client_write(conn, CLIENTWRITE_BOTH, buf, 0);
2358 Curl_pgrsSetDownloadSize(data, filesize);
2359 result = ftp_state_post_size(conn);
2361 else if(instate == FTP_RETR_SIZE) {
2362 Curl_pgrsSetDownloadSize(data, filesize);
2363 result = ftp_state_post_retr_size(conn, filesize);
2365 else if(instate == FTP_STOR_SIZE) {
2366 data->state.resume_from = filesize;
2367 result = ftp_state_ul_setup(conn, TRUE);
2373 static CURLcode ftp_state_rest_resp(struct connectdata *conn,
2377 CURLcode result = CURLE_OK;
2378 struct ftp_conn *ftpc = &conn->proto.ftpc;
2383 #ifdef CURL_FTP_HTTPSTYLE_HEAD
2384 if(ftpcode == 350) {
2385 char buffer[24]= { "Accept-ranges: bytes\r\n" };
2386 result = Curl_client_write(conn, CLIENTWRITE_BOTH, buffer, 0);
2391 result = ftp_state_post_rest(conn);
2395 if(ftpcode != 350) {
2396 failf(conn->data, "Couldn't use REST");
2397 result = CURLE_FTP_COULDNT_USE_REST;
2400 PPSENDF(&ftpc->pp, "RETR %s", ftpc->file);
2401 state(conn, FTP_RETR);
2409 static CURLcode ftp_state_stor_resp(struct connectdata *conn,
2410 int ftpcode, ftpstate instate)
2412 CURLcode result = CURLE_OK;
2413 struct SessionHandle *data = conn->data;
2416 failf(data, "Failed FTP upload: %0d", ftpcode);
2417 state(conn, FTP_STOP);
2418 /* oops, we never close the sockets! */
2419 return CURLE_UPLOAD_FAILED;
2422 conn->proto.ftpc.state_saved = instate;
2424 /* PORT means we are now awaiting the server to connect to us. */
2425 if(data->set.ftp_use_port) {
2428 result = AllowServerConnect(conn, &connected);
2433 struct ftp_conn *ftpc = &conn->proto.ftpc;
2434 infof(data, "Data conn was not available immediately\n");
2435 ftpc->wait_data_conn = TRUE;
2441 return InitiateTransfer(conn);
2444 /* for LIST and RETR responses */
2445 static CURLcode ftp_state_get_resp(struct connectdata *conn,
2449 CURLcode result = CURLE_OK;
2450 struct SessionHandle *data = conn->data;
2451 struct FTP *ftp = data->state.proto.ftp;
2452 char *buf = data->state.buffer;
2454 if((ftpcode == 150) || (ftpcode == 125)) {
2458 150 Opening BINARY mode data connection for /etc/passwd (2241
2459 bytes). (ok, the file is being transferred)
2462 150 Opening ASCII mode data connection for /bin/ls
2465 150 ASCII data connection for /bin/ls (137.167.104.91,37445) (0 bytes).
2468 150 Opening ASCII mode data connection for [file] (0.0.0.0,0) (545 bytes)
2471 125 Data connection already open; Transfer starting. */
2473 curl_off_t size=-1; /* default unknown size */
2477 * It appears that there are FTP-servers that return size 0 for files when
2478 * SIZE is used on the file while being in BINARY mode. To work around
2479 * that (stupid) behavior, we attempt to parse the RETR response even if
2480 * the SIZE returned size zero.
2482 * Debugging help from Salvatore Sorrentino on February 26, 2003.
2485 if((instate != FTP_LIST) &&
2486 !data->set.prefer_ascii &&
2487 (ftp->downloadsize < 1)) {
2489 * It seems directory listings either don't show the size or very
2490 * often uses size 0 anyway. ASCII transfers may very well turn out
2491 * that the transferred amount of data is not the same as this line
2492 * tells, why using this number in those cases only confuses us.
2494 * Example D above makes this parsing a little tricky */
2496 bytes=strstr(buf, " bytes");
2498 long in=(long)(bytes-buf);
2499 /* this is a hint there is size information in there! ;-) */
2501 /* scan for the left parenthesis and break there */
2504 /* skip only digits */
2505 if(!ISDIGIT(*bytes)) {
2509 /* one more estep backwards */
2512 /* if we have nothing but digits: */
2514 /* get the number! */
2515 size = curlx_strtoofft(bytes, NULL, 0);
2519 else if(ftp->downloadsize > -1)
2520 size = ftp->downloadsize;
2522 if(size > data->req.maxdownload && data->req.maxdownload > 0)
2523 size = data->req.size = data->req.maxdownload;
2524 else if((instate != FTP_LIST) && (data->set.prefer_ascii))
2525 size = -1; /* kludge for servers that understate ASCII mode file size */
2527 infof(data, "Maxdownload = %" FORMAT_OFF_T "\n", data->req.maxdownload);
2529 if(instate != FTP_LIST)
2530 infof(data, "Getting file with size: %" FORMAT_OFF_T "\n", size);
2533 conn->proto.ftpc.state_saved = instate;
2534 conn->proto.ftpc.retr_size_saved = size;
2536 if(data->set.ftp_use_port) {
2539 result = AllowServerConnect(conn, &connected);
2544 struct ftp_conn *ftpc = &conn->proto.ftpc;
2545 infof(data, "Data conn was not available immediately\n");
2546 state(conn, FTP_STOP);
2547 ftpc->wait_data_conn = TRUE;
2551 return InitiateTransfer(conn);
2554 if((instate == FTP_LIST) && (ftpcode == 450)) {
2555 /* simply no matching files in the dir listing */
2556 ftp->transfer = FTPTRANSFER_NONE; /* don't download anything */
2557 state(conn, FTP_STOP); /* this phase is over */
2560 failf(data, "RETR response: %03d", ftpcode);
2561 return instate == FTP_RETR && ftpcode == 550?
2562 CURLE_REMOTE_FILE_NOT_FOUND:
2563 CURLE_FTP_COULDNT_RETR_FILE;
2570 /* after USER, PASS and ACCT */
2571 static CURLcode ftp_state_loggedin(struct connectdata *conn)
2573 CURLcode result = CURLE_OK;
2576 if(conn->data->set.krb) {
2577 /* We may need to issue a KAUTH here to have access to the files
2578 * do it if user supplied a password
2580 if(conn->passwd && *conn->passwd) {
2582 result = Curl_krb_kauth(conn);
2588 if(conn->ssl[FIRSTSOCKET].use) {
2589 /* PBSZ = PROTECTION BUFFER SIZE.
2591 The 'draft-murray-auth-ftp-ssl' (draft 12, page 7) says:
2593 Specifically, the PROT command MUST be preceded by a PBSZ
2594 command and a PBSZ command MUST be preceded by a successful
2595 security data exchange (the TLS negotiation in this case)
2597 ... (and on page 8):
2599 Thus the PBSZ command must still be issued, but must have a
2600 parameter of '0' to indicate that no buffering is taking place
2601 and the data connection should not be encapsulated.
2603 PPSENDF(&conn->proto.ftpc.pp, "PBSZ %d", 0);
2604 state(conn, FTP_PBSZ);
2607 result = ftp_state_pwd(conn);
2612 /* for USER and PASS responses */
2613 static CURLcode ftp_state_user_resp(struct connectdata *conn,
2617 CURLcode result = CURLE_OK;
2618 struct SessionHandle *data = conn->data;
2619 struct FTP *ftp = data->state.proto.ftp;
2620 struct ftp_conn *ftpc = &conn->proto.ftpc;
2621 (void)instate; /* no use for this yet */
2623 /* some need password anyway, and others just return 2xx ignored */
2624 if((ftpcode == 331) && (ftpc->state == FTP_USER)) {
2625 /* 331 Password required for ...
2626 (the server requires to send the user's password too) */
2627 PPSENDF(&ftpc->pp, "PASS %s", ftp->passwd?ftp->passwd:"");
2628 state(conn, FTP_PASS);
2630 else if(ftpcode/100 == 2) {
2631 /* 230 User ... logged in.
2632 (the user logged in with or without password) */
2633 result = ftp_state_loggedin(conn);
2635 else if(ftpcode == 332) {
2636 if(data->set.str[STRING_FTP_ACCOUNT]) {
2637 PPSENDF(&ftpc->pp, "ACCT %s", data->set.str[STRING_FTP_ACCOUNT]);
2638 state(conn, FTP_ACCT);
2641 failf(data, "ACCT requested but none available");
2642 result = CURLE_LOGIN_DENIED;
2646 /* All other response codes, like:
2648 530 User ... access denied
2649 (the server denies to log the specified user) */
2651 if(conn->data->set.str[STRING_FTP_ALTERNATIVE_TO_USER] &&
2652 !conn->data->state.ftp_trying_alternative) {
2653 /* Ok, USER failed. Let's try the supplied command. */
2654 PPSENDF(&conn->proto.ftpc.pp, "%s",
2655 conn->data->set.str[STRING_FTP_ALTERNATIVE_TO_USER]);
2656 conn->data->state.ftp_trying_alternative = TRUE;
2657 state(conn, FTP_USER);
2661 failf(data, "Access denied: %03d", ftpcode);
2662 result = CURLE_LOGIN_DENIED;
2668 /* for ACCT response */
2669 static CURLcode ftp_state_acct_resp(struct connectdata *conn,
2672 CURLcode result = CURLE_OK;
2673 struct SessionHandle *data = conn->data;
2674 if(ftpcode != 230) {
2675 failf(data, "ACCT rejected by server: %03d", ftpcode);
2676 result = CURLE_FTP_WEIRD_PASS_REPLY; /* FIX */
2679 result = ftp_state_loggedin(conn);
2685 static CURLcode ftp_statemach_act(struct connectdata *conn)
2688 curl_socket_t sock = conn->sock[FIRSTSOCKET];
2689 struct SessionHandle *data=conn->data;
2691 struct ftp_conn *ftpc = &conn->proto.ftpc;
2692 struct pingpong *pp = &ftpc->pp;
2693 static const char ftpauth[][4] = { "SSL", "TLS" };
2697 return Curl_pp_flushsend(pp);
2699 result = ftp_readresp(sock, pp, &ftpcode, &nread);
2704 /* we have now received a full FTP server response */
2705 switch(ftpc->state) {
2707 if(ftpcode != 220) {
2708 failf(data, "Got a %03d ftp-server response when 220 was expected",
2710 return CURLE_FTP_WEIRD_SERVER_REPLY;
2713 /* We have received a 220 response fine, now we proceed. */
2714 #if defined(HAVE_KRB4) || defined(HAVE_GSSAPI)
2716 /* If not anonymous login, try a secure login. Note that this
2717 procedure is still BLOCKING. */
2719 Curl_sec_request_prot(conn, "private");
2720 /* We set private first as default, in case the line below fails to
2721 set a valid level */
2722 Curl_sec_request_prot(conn, data->set.str[STRING_KRB_LEVEL]);
2724 if(Curl_sec_login(conn) != CURLE_OK)
2725 infof(data, "Logging in with password in cleartext!\n");
2727 infof(data, "Authentication successful\n");
2731 if(data->set.use_ssl && !conn->ssl[FIRSTSOCKET].use) {
2732 /* We don't have a SSL/TLS connection yet, but FTPS is
2733 requested. Try a FTPS connection now */
2736 switch(data->set.ftpsslauth) {
2737 case CURLFTPAUTH_DEFAULT:
2738 case CURLFTPAUTH_SSL:
2739 ftpc->count2 = 1; /* add one to get next */
2742 case CURLFTPAUTH_TLS:
2743 ftpc->count2 = -1; /* subtract one to get next */
2747 failf(data, "unsupported parameter to CURLOPT_FTPSSLAUTH: %d",
2748 (int)data->set.ftpsslauth);
2749 return CURLE_UNKNOWN_OPTION; /* we don't know what to do */
2751 PPSENDF(&ftpc->pp, "AUTH %s", ftpauth[ftpc->count1]);
2752 state(conn, FTP_AUTH);
2755 result = ftp_state_user(conn);
2763 /* we have gotten the response to a previous AUTH command */
2765 /* RFC2228 (page 5) says:
2767 * If the server is willing to accept the named security mechanism,
2768 * and does not require any security data, it must respond with
2769 * reply code 234/334.
2772 if((ftpcode == 234) || (ftpcode == 334)) {
2773 /* Curl_ssl_connect is BLOCKING */
2774 result = Curl_ssl_connect(conn, FIRSTSOCKET);
2775 if(CURLE_OK == result) {
2776 conn->ssl[SECONDARYSOCKET].use = FALSE; /* clear-text data */
2777 result = ftp_state_user(conn);
2780 else if(ftpc->count3 < 1) {
2782 ftpc->count1 += ftpc->count2; /* get next attempt */
2783 result = Curl_pp_sendf(&ftpc->pp, "AUTH %s", ftpauth[ftpc->count1]);
2784 /* remain in this same state */
2787 if(data->set.use_ssl > CURLUSESSL_TRY)
2788 /* we failed and CURLUSESSL_CONTROL or CURLUSESSL_ALL is set */
2789 result = CURLE_USE_SSL_FAILED;
2791 /* ignore the failure and continue */
2792 result = ftp_state_user(conn);
2801 result = ftp_state_user_resp(conn, ftpcode, ftpc->state);
2805 result = ftp_state_acct_resp(conn, ftpcode);
2809 PPSENDF(&ftpc->pp, "PROT %c",
2810 data->set.use_ssl == CURLUSESSL_CONTROL ? 'C' : 'P');
2811 state(conn, FTP_PROT);
2816 if(ftpcode/100 == 2)
2817 /* We have enabled SSL for the data connection! */
2818 conn->ssl[SECONDARYSOCKET].use =
2819 (data->set.use_ssl != CURLUSESSL_CONTROL) ? TRUE : FALSE;
2820 /* FTP servers typically responds with 500 if they decide to reject
2822 else if(data->set.use_ssl > CURLUSESSL_CONTROL)
2823 /* we failed and bails out */
2824 return CURLE_USE_SSL_FAILED;
2826 if(data->set.ftp_ccc) {
2827 /* CCC - Clear Command Channel
2829 PPSENDF(&ftpc->pp, "CCC", NULL);
2830 state(conn, FTP_CCC);
2833 result = ftp_state_pwd(conn);
2841 /* First shut down the SSL layer (note: this call will block) */
2842 result = Curl_ssl_shutdown(conn, FIRSTSOCKET);
2845 failf(conn->data, "Failed to clear the command channel (CCC)");
2850 /* Then continue as normal */
2851 result = ftp_state_pwd(conn);
2857 if(ftpcode == 257) {
2858 char *ptr=&data->state.buffer[4]; /* start on the first letter */
2862 dir = malloc(nread + 1);
2864 return CURLE_OUT_OF_MEMORY;
2866 /* Reply format is like
2867 257<space>"<directory-name>"<space><commentary> and the RFC959
2870 The directory name can contain any character; embedded
2871 double-quotes should be escaped by double-quotes (the
2872 "quote-doubling" convention).
2875 /* it started good */
2877 for(store = dir; *ptr;) {
2879 if('\"' == ptr[1]) {
2880 /* "quote-doubling" */
2886 *store = '\0'; /* zero terminate */
2887 break; /* get out of this loop */
2896 /* If the path name does not look like an absolute path (i.e.: it
2897 does not start with a '/'), we probably need some server-dependent
2898 adjustments. For example, this is the case when connecting to
2899 an OS400 FTP server: this server supports two name syntaxes,
2900 the default one being incompatible with standard pathes. In
2901 addition, this server switches automatically to the regular path
2902 syntax when one is encountered in a command: this results in
2903 having an entrypath in the wrong syntax when later used in CWD.
2904 The method used here is to check the server OS: we do it only
2905 if the path name looks strange to minimize overhead on other
2908 if(!ftpc->server_os && dir[0] != '/') {
2910 result = Curl_pp_sendf(&ftpc->pp, "SYST", NULL);
2911 if(result != CURLE_OK) {
2915 Curl_safefree(ftpc->entrypath);
2916 ftpc->entrypath = dir; /* remember this */
2917 infof(data, "Entry path is '%s'\n", ftpc->entrypath);
2918 /* also save it where getinfo can access it: */
2919 data->state.most_recent_ftp_entrypath = ftpc->entrypath;
2920 state(conn, FTP_SYST);
2924 Curl_safefree(ftpc->entrypath);
2925 ftpc->entrypath = dir; /* remember this */
2926 infof(data, "Entry path is '%s'\n", ftpc->entrypath);
2927 /* also save it where getinfo can access it: */
2928 data->state.most_recent_ftp_entrypath = ftpc->entrypath;
2931 /* couldn't get the path */
2933 infof(data, "Failed to figure out path\n");
2936 state(conn, FTP_STOP); /* we are done with the CONNECT phase! */
2937 DEBUGF(infof(data, "protocol connect phase DONE\n"));
2941 if(ftpcode == 215) {
2942 char *ptr=&data->state.buffer[4]; /* start on the first letter */
2946 os = malloc(nread + 1);
2948 return CURLE_OUT_OF_MEMORY;
2950 /* Reply format is like
2951 215<space><OS-name><space><commentary>
2955 for(store = os; *ptr && *ptr != ' ';)
2957 *store = '\0'; /* zero terminate */
2959 /* Check for special servers here. */
2961 if(strequal(os, "OS/400")) {
2962 /* Force OS400 name format 1. */
2963 result = Curl_pp_sendf(&ftpc->pp, "SITE NAMEFMT 1", NULL);
2964 if(result != CURLE_OK) {
2968 /* remember target server OS */
2969 Curl_safefree(ftpc->server_os);
2970 ftpc->server_os = os;
2971 state(conn, FTP_NAMEFMT);
2975 /* Nothing special for the target server. */
2976 /* remember target server OS */
2977 Curl_safefree(ftpc->server_os);
2978 ftpc->server_os = os;
2982 /* Cannot identify server OS. Continue anyway and cross fingers. */
2985 state(conn, FTP_STOP); /* we are done with the CONNECT phase! */
2986 DEBUGF(infof(data, "protocol connect phase DONE\n"));
2990 if(ftpcode == 250) {
2991 /* Name format change successful: reload initial path. */
2992 ftp_state_pwd(conn);
2996 state(conn, FTP_STOP); /* we are done with the CONNECT phase! */
2997 DEBUGF(infof(data, "protocol connect phase DONE\n"));
3002 case FTP_RETR_PREQUOTE:
3003 case FTP_STOR_PREQUOTE:
3004 if((ftpcode >= 400) && !ftpc->count2) {
3005 /* failure response code, and not allowed to fail */
3006 failf(conn->data, "QUOT command failed with %03d", ftpcode);
3007 return CURLE_QUOTE_ERROR;
3009 result = ftp_state_quote(conn, FALSE, ftpc->state);
3016 if(ftpcode/100 != 2) {
3017 /* failure to CWD there */
3018 if(conn->data->set.ftp_create_missing_dirs &&
3019 ftpc->count1 && !ftpc->count2) {
3021 ftpc->count2++; /* counter to prevent CWD-MKD loops */
3022 PPSENDF(&ftpc->pp, "MKD %s", ftpc->dirs[ftpc->count1 - 1]);
3023 state(conn, FTP_MKD);
3026 /* return failure */
3027 failf(data, "Server denied you to change to the given directory");
3028 ftpc->cwdfail = TRUE; /* don't remember this path as we failed
3030 return CURLE_REMOTE_ACCESS_DENIED;
3036 if(++ftpc->count1 <= ftpc->dirdepth) {
3038 PPSENDF(&ftpc->pp, "CWD %s", ftpc->dirs[ftpc->count1 - 1]);
3041 result = ftp_state_post_cwd(conn);
3049 if((ftpcode/100 != 2) && !ftpc->count3--) {
3050 /* failure to MKD the dir */
3051 failf(data, "Failed to MKD dir: %03d", ftpcode);
3052 return CURLE_REMOTE_ACCESS_DENIED;
3054 state(conn, FTP_CWD);
3056 PPSENDF(&ftpc->pp, "CWD %s", ftpc->dirs[ftpc->count1 - 1]);
3060 result = ftp_state_mdtm_resp(conn, ftpcode);
3067 result = ftp_state_type_resp(conn, ftpcode, ftpc->state);
3073 result = ftp_state_size_resp(conn, ftpcode, ftpc->state);
3078 result = ftp_state_rest_resp(conn, ftpcode, ftpc->state);
3082 if(ftpcode != 200) {
3083 /* there only is this one standard OK return code. */
3084 failf(data, "PRET command not accepted: %03d", ftpcode);
3085 return CURLE_FTP_PRET_FAILED;
3087 result = ftp_state_use_pasv(conn);
3091 result = ftp_state_pasv_resp(conn, ftpcode);
3095 result = ftp_state_port_resp(conn, ftpcode);
3100 result = ftp_state_get_resp(conn, ftpcode, ftpc->state);
3104 result = ftp_state_stor_resp(conn, ftpcode, ftpc->state);
3108 /* fallthrough, just stop! */
3110 /* internal error */
3111 state(conn, FTP_STOP);
3120 /* called repeatedly until done from multi.c */
3121 static CURLcode ftp_multi_statemach(struct connectdata *conn,
3124 struct ftp_conn *ftpc = &conn->proto.ftpc;
3125 CURLcode result = Curl_pp_statemach(&ftpc->pp, FALSE);
3127 /* Check for the state outside of the Curl_socket_ready() return code checks
3128 since at times we are in fact already in this state when this function
3130 *done = (ftpc->state == FTP_STOP) ? TRUE : FALSE;
3135 static CURLcode ftp_block_statemach(struct connectdata *conn)
3137 struct ftp_conn *ftpc = &conn->proto.ftpc;
3138 struct pingpong *pp = &ftpc->pp;
3139 CURLcode result = CURLE_OK;
3141 while(ftpc->state != FTP_STOP) {
3142 result = Curl_pp_statemach(pp, TRUE);
3151 * Allocate and initialize the struct FTP for the current SessionHandle. If
3155 #if defined(__INTEL_COMPILER) && (__INTEL_COMPILER == 910) && \
3156 defined(__OPTIMIZE__) && defined(__unix__) && defined(__i386__)
3157 /* workaround icc 9.1 optimizer issue */
3158 #pragma optimize("", off)
3161 static CURLcode ftp_init(struct connectdata *conn)
3165 if(NULL == conn->data->state.proto.ftp) {
3166 conn->data->state.proto.ftp = malloc(sizeof(struct FTP));
3167 if(NULL == conn->data->state.proto.ftp)
3168 return CURLE_OUT_OF_MEMORY;
3171 ftp = conn->data->state.proto.ftp;
3173 /* get some initial data into the ftp struct */
3174 ftp->bytecountp = &conn->data->req.bytecount;
3175 ftp->transfer = FTPTRANSFER_BODY;
3176 ftp->downloadsize = 0;
3178 /* No need to duplicate user+password, the connectdata struct won't change
3179 during a session, but we re-init them here since on subsequent inits
3180 since the conn struct may have changed or been replaced.
3182 ftp->user = conn->user;
3183 ftp->passwd = conn->passwd;
3184 if(isBadFtpString(ftp->user))
3185 return CURLE_URL_MALFORMAT;
3186 if(isBadFtpString(ftp->passwd))
3187 return CURLE_URL_MALFORMAT;
3189 conn->proto.ftpc.known_filesize = -1; /* unknown size for now */
3194 #if defined(__INTEL_COMPILER) && (__INTEL_COMPILER == 910) && \
3195 defined(__OPTIMIZE__) && defined(__unix__) && defined(__i386__)
3196 /* workaround icc 9.1 optimizer issue */
3197 #pragma optimize("", on)
3201 * ftp_connect() should do everything that is to be considered a part of
3202 * the connection phase.
3204 * The variable 'done' points to will be TRUE if the protocol-layer connect
3205 * phase is done when this function returns, or FALSE is not. When called as
3206 * a part of the easy interface, it will always be TRUE.
3208 static CURLcode ftp_connect(struct connectdata *conn,
3209 bool *done) /* see description above */
3212 struct ftp_conn *ftpc = &conn->proto.ftpc;
3213 struct pingpong *pp = &ftpc->pp;
3215 *done = FALSE; /* default to not done yet */
3217 /* If there already is a protocol-specific struct allocated for this
3218 sessionhandle, deal with it */
3219 Curl_reset_reqproto(conn);
3221 result = ftp_init(conn);
3222 if(CURLE_OK != result)
3225 /* We always support persistent connections on ftp */
3226 conn->bits.close = FALSE;
3228 pp->response_time = RESP_TIMEOUT; /* set default response time-out */
3229 pp->statemach_act = ftp_statemach_act;
3230 pp->endofresp = ftp_endofresp;
3233 if(conn->handler->flags & PROTOPT_SSL) {
3235 result = Curl_ssl_connect(conn, FIRSTSOCKET);
3240 Curl_pp_init(pp); /* init the generic pingpong data */
3242 /* When we connect, we start in the state where we await the 220
3244 state(conn, FTP_WAIT220);
3246 result = ftp_multi_statemach(conn, done);
3251 /***********************************************************************
3255 * The DONE function. This does what needs to be done after a single DO has
3258 * Input argument is already checked for validity.
3260 static CURLcode ftp_done(struct connectdata *conn, CURLcode status,
3263 struct SessionHandle *data = conn->data;
3264 struct FTP *ftp = data->state.proto.ftp;
3265 struct ftp_conn *ftpc = &conn->proto.ftpc;
3266 struct pingpong *pp = &ftpc->pp;
3269 CURLcode result = CURLE_OK;
3270 bool was_ctl_valid = ftpc->ctl_valid;
3272 const char *path_to_use = data->state.path;
3275 /* When the easy handle is removed from the multi while libcurl is still
3276 * trying to resolve the host name, it seems that the ftp struct is not
3277 * yet initialized, but the removal action calls Curl_done() which calls
3278 * this function. So we simply return success if no ftp pointer is set.
3283 case CURLE_BAD_DOWNLOAD_RESUME:
3284 case CURLE_FTP_WEIRD_PASV_REPLY:
3285 case CURLE_FTP_PORT_FAILED:
3286 case CURLE_FTP_ACCEPT_FAILED:
3287 case CURLE_FTP_ACCEPT_TIMEOUT:
3288 case CURLE_FTP_COULDNT_SET_TYPE:
3289 case CURLE_FTP_COULDNT_RETR_FILE:
3290 case CURLE_PARTIAL_FILE:
3291 case CURLE_UPLOAD_FAILED:
3292 case CURLE_REMOTE_ACCESS_DENIED:
3293 case CURLE_FILESIZE_EXCEEDED:
3294 case CURLE_REMOTE_FILE_NOT_FOUND:
3295 case CURLE_WRITE_ERROR:
3296 /* the connection stays alive fine even though this happened */
3298 case CURLE_OK: /* doesn't affect the control connection's status */
3300 ftpc->ctl_valid = was_ctl_valid;
3303 /* until we cope better with prematurely ended requests, let them
3304 * fallback as if in complete failure */
3305 default: /* by default, an error means the control connection is
3306 wedged and should not be used anymore */
3307 ftpc->ctl_valid = FALSE;
3308 ftpc->cwdfail = TRUE; /* set this TRUE to prevent us to remember the
3309 current path, as this connection is going */
3310 conn->bits.close = TRUE; /* marked for closure */
3311 result = status; /* use the already set error code */
3315 /* now store a copy of the directory we are in */
3317 free(ftpc->prevpath);
3319 if(data->set.wildcardmatch) {
3320 if(data->set.chunk_end && ftpc->file) {
3321 data->set.chunk_end(data->wildcard.customptr);
3323 ftpc->known_filesize = -1;
3326 /* get the "raw" path */
3327 path = curl_easy_unescape(data, path_to_use, 0, NULL);
3329 /* out of memory, but we can limp along anyway (and should try to
3330 * since we may already be in the out of memory cleanup path) */
3332 result = CURLE_OUT_OF_MEMORY;
3333 ftpc->ctl_valid = FALSE; /* mark control connection as bad */
3334 conn->bits.close = TRUE; /* mark for connection closure */
3335 ftpc->prevpath = NULL; /* no path remembering */
3338 size_t flen = ftpc->file?strlen(ftpc->file):0; /* file is "raw" already */
3339 size_t dlen = strlen(path)-flen;
3340 if(!ftpc->cwdfail) {
3341 if(dlen && (data->set.ftp_filemethod != FTPFILE_NOCWD)) {
3342 ftpc->prevpath = path;
3344 /* if 'path' is not the whole string */
3345 ftpc->prevpath[dlen]=0; /* terminate */
3348 /* we never changed dir */
3349 ftpc->prevpath=strdup("");
3353 infof(data, "Remembering we are in dir \"%s\"\n", ftpc->prevpath);
3356 ftpc->prevpath = NULL; /* no path */
3360 /* free the dir tree and file parts */
3363 /* shut down the socket to inform the server we're done */
3366 shutdown(conn->sock[SECONDARYSOCKET],2); /* SD_BOTH */
3369 if(conn->sock[SECONDARYSOCKET] != CURL_SOCKET_BAD) {
3370 if(!result && ftpc->dont_check && data->req.maxdownload > 0)
3371 /* partial download completed */
3372 result = Curl_pp_sendf(pp, "ABOR");
3374 failf(data, "Failure sending ABOR command: %s",
3375 curl_easy_strerror(result));
3376 ftpc->ctl_valid = FALSE; /* mark control connection as bad */
3377 conn->bits.close = TRUE; /* mark for connection closure */
3380 if(conn->ssl[SECONDARYSOCKET].use) {
3381 /* The secondary socket is using SSL so we must close down that part
3382 first before we close the socket for real */
3383 Curl_ssl_close(conn, SECONDARYSOCKET);
3385 /* Note that we keep "use" set to TRUE since that (next) connection is
3386 still requested to use SSL */
3388 if(CURL_SOCKET_BAD != conn->sock[SECONDARYSOCKET]) {
3389 Curl_closesocket(conn, conn->sock[SECONDARYSOCKET]);
3390 conn->sock[SECONDARYSOCKET] = CURL_SOCKET_BAD;
3391 conn->bits.tcpconnect[SECONDARYSOCKET] = FALSE;
3395 if(!result && (ftp->transfer == FTPTRANSFER_BODY) && ftpc->ctl_valid &&
3396 pp->pending_resp && !premature) {
3398 * Let's see what the server says about the transfer we just performed,
3399 * but lower the timeout as sometimes this connection has died while the
3400 * data has been transferred. This happens when doing through NATs etc that
3401 * abandon old silent connections.
3403 long old_time = pp->response_time;
3405 pp->response_time = 60*1000; /* give it only a minute for now */
3406 pp->response = Curl_tvnow(); /* timeout relative now */
3408 result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
3410 pp->response_time = old_time; /* set this back to previous value */
3412 if(!nread && (CURLE_OPERATION_TIMEDOUT == result)) {
3413 failf(data, "control connection looks dead");
3414 ftpc->ctl_valid = FALSE; /* mark control connection as bad */
3415 conn->bits.close = TRUE; /* mark for closure */
3421 if(ftpc->dont_check && data->req.maxdownload > 0) {
3422 /* we have just sent ABOR and there is no reliable way to check if it was
3423 * successful or not; we have to close the connection now */
3424 infof(data, "partial download completed, closing connection\n");
3425 conn->bits.close = TRUE; /* mark for closure */
3429 if(!ftpc->dont_check) {
3430 /* 226 Transfer complete, 250 Requested file action okay, completed. */
3431 if((ftpcode != 226) && (ftpcode != 250)) {
3432 failf(data, "server did not report OK, got %d", ftpcode);
3433 result = CURLE_PARTIAL_FILE;
3438 if(result || premature)
3439 /* the response code from the transfer showed an error already so no
3440 use checking further */
3442 else if(data->set.upload) {
3443 if((-1 != data->set.infilesize) &&
3444 (data->set.infilesize != *ftp->bytecountp) &&
3446 (ftp->transfer == FTPTRANSFER_BODY)) {
3447 failf(data, "Uploaded unaligned file size (%" FORMAT_OFF_T
3448 " out of %" FORMAT_OFF_T " bytes)",
3449 *ftp->bytecountp, data->set.infilesize);
3450 result = CURLE_PARTIAL_FILE;
3454 if((-1 != data->req.size) &&
3455 (data->req.size != *ftp->bytecountp) &&
3456 #ifdef CURL_DO_LINEEND_CONV
3457 /* Most FTP servers don't adjust their file SIZE response for CRLFs, so
3458 * we'll check to see if the discrepancy can be explained by the number
3459 * of CRLFs we've changed to LFs.
3461 ((data->req.size + data->state.crlf_conversions) !=
3462 *ftp->bytecountp) &&
3463 #endif /* CURL_DO_LINEEND_CONV */
3464 (data->req.maxdownload != *ftp->bytecountp)) {
3465 failf(data, "Received only partial file: %" FORMAT_OFF_T " bytes",
3467 result = CURLE_PARTIAL_FILE;
3469 else if(!ftpc->dont_check &&
3470 !*ftp->bytecountp &&
3471 (data->req.size>0)) {
3472 failf(data, "No data was received!");
3473 result = CURLE_FTP_COULDNT_RETR_FILE;
3477 /* clear these for next connection */
3478 ftp->transfer = FTPTRANSFER_BODY;
3479 ftpc->dont_check = FALSE;
3481 /* Send any post-transfer QUOTE strings? */
3482 if(!status && !result && !premature && data->set.postquote)
3483 result = ftp_sendquote(conn, data->set.postquote);
3488 /***********************************************************************
3492 * Where a 'quote' means a list of custom commands to send to the server.
3493 * The quote list is passed as an argument.
3499 CURLcode ftp_sendquote(struct connectdata *conn, struct curl_slist *quote)
3501 struct curl_slist *item;
3505 struct ftp_conn *ftpc = &conn->proto.ftpc;
3506 struct pingpong *pp = &ftpc->pp;
3511 char *cmd = item->data;
3512 bool acceptfail = FALSE;
3514 /* if a command starts with an asterisk, which a legal FTP command never
3515 can, the command will be allowed to fail without it causing any
3516 aborts or cancels etc. It will cause libcurl to act as if the command
3517 is successful, whatever the server reponds. */
3524 PPSENDF(&conn->proto.ftpc.pp, "%s", cmd);
3526 pp->response = Curl_tvnow(); /* timeout relative now */
3528 result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
3532 if(!acceptfail && (ftpcode >= 400)) {
3533 failf(conn->data, "QUOT string not accepted: %s", cmd);
3534 return CURLE_QUOTE_ERROR;
3544 /***********************************************************************
3548 * Returns TRUE if we in the current situation should send TYPE
3550 static int ftp_need_type(struct connectdata *conn,
3553 return conn->proto.ftpc.transfertype != (ascii_wanted?'A':'I');
3556 /***********************************************************************
3560 * Set TYPE. We only deal with ASCII or BINARY so this function
3562 * If the transfer type is not sent, simulate on OK response in newstate
3564 static CURLcode ftp_nb_type(struct connectdata *conn,
3565 bool ascii, ftpstate newstate)
3567 struct ftp_conn *ftpc = &conn->proto.ftpc;
3569 char want = (char)(ascii?'A':'I');
3571 if(ftpc->transfertype == want) {
3572 state(conn, newstate);
3573 return ftp_state_type_resp(conn, 200, newstate);
3576 PPSENDF(&ftpc->pp, "TYPE %c", want);
3577 state(conn, newstate);
3579 /* keep track of our current transfer type */
3580 ftpc->transfertype = want;
3584 /***************************************************************************
3586 * ftp_pasv_verbose()
3588 * This function only outputs some informationals about this second connection
3589 * when we've issued a PASV command before and thus we have connected to a
3590 * possibly new IP address.
3593 #ifndef CURL_DISABLE_VERBOSE_STRINGS
3595 ftp_pasv_verbose(struct connectdata *conn,
3597 char *newhost, /* ascii version */
3601 Curl_printable_address(ai, buf, sizeof(buf));
3602 infof(conn->data, "Connecting to %s (%s) port %d\n", newhost, buf, port);
3607 Check if this is a range download, and if so, set the internal variables
3611 static CURLcode ftp_range(struct connectdata *conn)
3613 curl_off_t from, to;
3616 struct SessionHandle *data = conn->data;
3617 struct ftp_conn *ftpc = &conn->proto.ftpc;
3619 if(data->state.use_range && data->state.range) {
3620 from=curlx_strtoofft(data->state.range, &ptr, 0);
3621 while(*ptr && (ISSPACE(*ptr) || (*ptr=='-')))
3623 to=curlx_strtoofft(ptr, &ptr2, 0);
3625 /* we didn't get any digit */
3628 if((-1 == to) && (from>=0)) {
3630 data->state.resume_from = from;
3631 DEBUGF(infof(conn->data, "FTP RANGE %" FORMAT_OFF_T " to end of file\n",
3636 data->req.maxdownload = -from;
3637 data->state.resume_from = from;
3638 DEBUGF(infof(conn->data, "FTP RANGE the last %" FORMAT_OFF_T " bytes\n",
3643 data->req.maxdownload = (to-from)+1; /* include last byte */
3644 data->state.resume_from = from;
3645 DEBUGF(infof(conn->data, "FTP RANGE from %" FORMAT_OFF_T
3646 " getting %" FORMAT_OFF_T " bytes\n",
3647 from, data->req.maxdownload));
3649 DEBUGF(infof(conn->data, "range-download from %" FORMAT_OFF_T
3650 " to %" FORMAT_OFF_T ", totally %" FORMAT_OFF_T " bytes\n",
3651 from, to, data->req.maxdownload));
3652 ftpc->dont_check = TRUE; /* dont check for successful transfer */
3655 data->req.maxdownload = -1;
3663 * This function shall be called when the second FTP (data) connection is
3667 static CURLcode ftp_do_more(struct connectdata *conn, bool *complete)
3669 struct SessionHandle *data=conn->data;
3670 struct ftp_conn *ftpc = &conn->proto.ftpc;
3671 CURLcode result = CURLE_OK;
3672 bool connected = FALSE;
3674 /* the ftp struct is inited in ftp_connect() */
3675 struct FTP *ftp = data->state.proto.ftp;
3679 /* if the second connection isn't done yet, wait for it */
3680 if(!conn->bits.tcpconnect[SECONDARYSOCKET]) {
3681 if(conn->tunnel_state[SECONDARYSOCKET] == TUNNEL_CONNECT) {
3682 /* As we're in TUNNEL_CONNECT state now, we know the proxy name and port
3683 aren't used so we blank their arguments. TODO: make this nicer */
3684 result = Curl_proxyCONNECT(conn, SECONDARYSOCKET, NULL, 0);
3689 result = Curl_is_connected(conn, SECONDARYSOCKET, &connected);
3691 /* Ready to do more? */
3693 DEBUGF(infof(data, "DO-MORE connected phase starts\n"));
3700 /* already in a state so skip the intial commands.
3701 They are only done to kickstart the do_more state */
3702 result = ftp_multi_statemach(conn, complete);
3704 /* if we got an error or if we don't wait for a data connection return
3706 if(result || (ftpc->wait_data_conn != TRUE))
3709 if(ftpc->wait_data_conn)
3710 /* if we reach the end of the FTP state machine here, *complete will be
3711 TRUE but so is ftpc->wait_data_conn, which says we need to wait for
3712 the data connection and therefore we're not actually complete */
3716 if(ftp->transfer <= FTPTRANSFER_INFO) {
3717 /* a transfer is about to take place, or if not a file name was given
3718 so we'll do a SIZE on it later and then we need the right TYPE first */
3720 if(ftpc->wait_data_conn == TRUE) {
3723 result = ReceivedServerConnect(conn, &serv_conned);
3725 return result; /* Failed to accept data connection */
3728 /* It looks data connection is established */
3729 result = AcceptServerConnect(conn);
3730 ftpc->wait_data_conn = FALSE;
3732 result = InitiateTransfer(conn);
3738 else if(data->set.upload) {
3739 result = ftp_nb_type(conn, data->set.prefer_ascii, FTP_STOR_TYPE);
3743 result = ftp_multi_statemach(conn, complete);
3747 ftp->downloadsize = -1; /* unknown as of yet */
3749 result = ftp_range(conn);
3752 else if(data->set.ftp_list_only || !ftpc->file) {
3753 /* The specified path ends with a slash, and therefore we think this
3754 is a directory that is requested, use LIST. But before that we
3755 need to set ASCII transfer mode. */
3757 /* But only if a body transfer was requested. */
3758 if(ftp->transfer == FTPTRANSFER_BODY) {
3759 result = ftp_nb_type(conn, TRUE, FTP_LIST_TYPE);
3763 /* otherwise just fall through */
3766 result = ftp_nb_type(conn, data->set.prefer_ascii, FTP_RETR_TYPE);
3771 result = ftp_multi_statemach(conn, complete);
3776 if((result == CURLE_OK) && (ftp->transfer != FTPTRANSFER_BODY))
3777 /* no data to transfer. FIX: it feels like a kludge to have this here
3779 Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
3781 if(!ftpc->wait_data_conn) {
3782 /* no waiting for the data connection so this is now complete */
3784 DEBUGF(infof(data, "DO-MORE phase ends with %d\n", (int)result));
3792 /***********************************************************************
3796 * This is the actual DO function for FTP. Get a file/directory according to
3797 * the options previously setup.
3801 CURLcode ftp_perform(struct connectdata *conn,
3802 bool *connected, /* connect status after PASV / PORT */
3805 /* this is FTP and no proxy */
3806 CURLcode result=CURLE_OK;
3808 DEBUGF(infof(conn->data, "DO phase starts\n"));
3810 if(conn->data->set.opt_no_body) {
3811 /* requested no body means no transfer... */
3812 struct FTP *ftp = conn->data->state.proto.ftp;
3813 ftp->transfer = FTPTRANSFER_INFO;
3816 *dophase_done = FALSE; /* not done yet */
3818 /* start the first command in the DO phase */
3819 result = ftp_state_quote(conn, TRUE, FTP_QUOTE);
3823 /* run the state-machine */
3824 result = ftp_multi_statemach(conn, dophase_done);
3826 *connected = conn->bits.tcpconnect[FIRSTSOCKET];
3829 DEBUGF(infof(conn->data, "DO phase is complete1\n"));
3834 static void wc_data_dtor(void *ptr)
3836 struct ftp_wc_tmpdata *tmp = ptr;
3838 Curl_ftp_parselist_data_free(&tmp->parser);
3842 static CURLcode init_wc_data(struct connectdata *conn)
3845 char *path = conn->data->state.path;
3846 struct WildcardData *wildcard = &(conn->data->wildcard);
3847 CURLcode ret = CURLE_OK;
3848 struct ftp_wc_tmpdata *ftp_tmp;
3850 last_slash = strrchr(conn->data->state.path, '/');
3853 if(last_slash[0] == '\0') {
3854 wildcard->state = CURLWC_CLEAN;
3855 ret = ftp_parse_url_path(conn);
3859 wildcard->pattern = strdup(last_slash);
3860 if(!wildcard->pattern)
3861 return CURLE_OUT_OF_MEMORY;
3862 last_slash[0] = '\0'; /* cut file from path */
3865 else { /* there is only 'wildcard pattern' or nothing */
3867 wildcard->pattern = strdup(path);
3868 if(!wildcard->pattern)
3869 return CURLE_OUT_OF_MEMORY;
3872 else { /* only list */
3873 wildcard->state = CURLWC_CLEAN;
3874 ret = ftp_parse_url_path(conn);
3879 /* program continues only if URL is not ending with slash, allocate needed
3880 resources for wildcard transfer */
3882 /* allocate ftp protocol specific temporary wildcard data */
3883 ftp_tmp = calloc(1, sizeof(struct ftp_wc_tmpdata));
3885 Curl_safefree(wildcard->pattern);
3886 return CURLE_OUT_OF_MEMORY;
3889 /* INITIALIZE parselist structure */
3890 ftp_tmp->parser = Curl_ftp_parselist_data_alloc();
3891 if(!ftp_tmp->parser) {
3892 Curl_safefree(wildcard->pattern);
3893 Curl_safefree(ftp_tmp);
3894 return CURLE_OUT_OF_MEMORY;
3897 wildcard->tmp = ftp_tmp; /* put it to the WildcardData tmp pointer */
3898 wildcard->tmp_dtor = wc_data_dtor;
3900 /* wildcard does not support NOCWD option (assert it?) */
3901 if(conn->data->set.ftp_filemethod == FTPFILE_NOCWD)
3902 conn->data->set.ftp_filemethod = FTPFILE_MULTICWD;
3904 /* try to parse ftp url */
3905 ret = ftp_parse_url_path(conn);
3907 Curl_safefree(wildcard->pattern);
3908 wildcard->tmp_dtor(wildcard->tmp);
3909 wildcard->tmp_dtor = ZERO_NULL;
3910 wildcard->tmp = NULL;
3914 wildcard->path = strdup(conn->data->state.path);
3915 if(!wildcard->path) {
3916 Curl_safefree(wildcard->pattern);
3917 wildcard->tmp_dtor(wildcard->tmp);
3918 wildcard->tmp_dtor = ZERO_NULL;
3919 wildcard->tmp = NULL;
3920 return CURLE_OUT_OF_MEMORY;
3923 /* backup old write_function */
3924 ftp_tmp->backup.write_function = conn->data->set.fwrite_func;
3925 /* parsing write function */
3926 conn->data->set.fwrite_func = Curl_ftp_parselist;
3927 /* backup old file descriptor */
3928 ftp_tmp->backup.file_descriptor = conn->data->set.out;
3929 /* let the writefunc callback know what curl pointer is working with */
3930 conn->data->set.out = conn;
3932 infof(conn->data, "Wildcard - Parsing started\n");
3936 /* This is called recursively */
3937 static CURLcode wc_statemach(struct connectdata *conn)
3939 struct WildcardData * const wildcard = &(conn->data->wildcard);
3940 CURLcode ret = CURLE_OK;
3942 switch (wildcard->state) {
3944 ret = init_wc_data(conn);
3945 if(wildcard->state == CURLWC_CLEAN)
3949 wildcard->state = ret ? CURLWC_ERROR : CURLWC_MATCHING;
3952 case CURLWC_MATCHING: {
3953 /* In this state is LIST response successfully parsed, so lets restore
3954 previous WRITEFUNCTION callback and WRITEDATA pointer */
3955 struct ftp_wc_tmpdata *ftp_tmp = wildcard->tmp;
3956 conn->data->set.fwrite_func = ftp_tmp->backup.write_function;
3957 conn->data->set.out = ftp_tmp->backup.file_descriptor;
3958 ftp_tmp->backup.write_function = ZERO_NULL;
3959 ftp_tmp->backup.file_descriptor = NULL;
3960 wildcard->state = CURLWC_DOWNLOADING;
3962 if(Curl_ftp_parselist_geterror(ftp_tmp->parser)) {
3963 /* error found in LIST parsing */
3964 wildcard->state = CURLWC_CLEAN;
3965 return wc_statemach(conn);
3967 else if(wildcard->filelist->size == 0) {
3968 /* no corresponding file */
3969 wildcard->state = CURLWC_CLEAN;
3970 return CURLE_REMOTE_FILE_NOT_FOUND;
3972 return wc_statemach(conn);
3975 case CURLWC_DOWNLOADING: {
3976 /* filelist has at least one file, lets get first one */
3977 struct ftp_conn *ftpc = &conn->proto.ftpc;
3978 struct curl_fileinfo *finfo = wildcard->filelist->head->ptr;
3980 char *tmp_path = aprintf("%s%s", wildcard->path, finfo->filename);
3982 return CURLE_OUT_OF_MEMORY;
3984 /* switch default "state.pathbuffer" and tmp_path, good to see
3985 ftp_parse_url_path function to understand this trick */
3986 Curl_safefree(conn->data->state.pathbuffer);
3987 conn->data->state.pathbuffer = tmp_path;
3988 conn->data->state.path = tmp_path;
3990 infof(conn->data, "Wildcard - START of \"%s\"\n", finfo->filename);
3991 if(conn->data->set.chunk_bgn) {
3992 long userresponse = conn->data->set.chunk_bgn(
3993 finfo, wildcard->customptr, (int)wildcard->filelist->size);
3994 switch(userresponse) {
3995 case CURL_CHUNK_BGN_FUNC_SKIP:
3996 infof(conn->data, "Wildcard - \"%s\" skipped by user\n",
3998 wildcard->state = CURLWC_SKIP;
3999 return wc_statemach(conn);
4000 case CURL_CHUNK_BGN_FUNC_FAIL:
4001 return CURLE_CHUNK_FAILED;
4005 if(finfo->filetype != CURLFILETYPE_FILE) {
4006 wildcard->state = CURLWC_SKIP;
4007 return wc_statemach(conn);
4010 if(finfo->flags & CURLFINFOFLAG_KNOWN_SIZE)
4011 ftpc->known_filesize = finfo->size;
4013 ret = ftp_parse_url_path(conn);
4018 /* we don't need the Curl_fileinfo of first file anymore */
4019 Curl_llist_remove(wildcard->filelist, wildcard->filelist->head, NULL);
4021 if(wildcard->filelist->size == 0) { /* remains only one file to down. */
4022 wildcard->state = CURLWC_CLEAN;
4023 /* after that will be ftp_do called once again and no transfer
4024 will be done because of CURLWC_CLEAN state */
4030 if(conn->data->set.chunk_end)
4031 conn->data->set.chunk_end(conn->data->wildcard.customptr);
4032 Curl_llist_remove(wildcard->filelist, wildcard->filelist->head, NULL);
4033 wildcard->state = (wildcard->filelist->size == 0) ?
4034 CURLWC_CLEAN : CURLWC_DOWNLOADING;
4035 return wc_statemach(conn);
4038 case CURLWC_CLEAN: {
4039 struct ftp_wc_tmpdata *ftp_tmp = wildcard->tmp;
4042 ret = Curl_ftp_parselist_geterror(ftp_tmp->parser);
4044 wildcard->state = ret ? CURLWC_ERROR : CURLWC_DONE;
4055 /***********************************************************************
4059 * This function is registered as 'curl_do' function. It decodes the path
4060 * parts etc as a wrapper to the actual DO function (ftp_perform).
4062 * The input argument is already checked for validity.
4064 static CURLcode ftp_do(struct connectdata *conn, bool *done)
4066 CURLcode retcode = CURLE_OK;
4067 struct ftp_conn *ftpc = &conn->proto.ftpc;
4069 *done = FALSE; /* default to false */
4070 ftpc->wait_data_conn = FALSE; /* default to no such wait */
4073 Since connections can be re-used between SessionHandles, this might be a
4074 connection already existing but on a fresh SessionHandle struct so we must
4075 make sure we have a good 'struct FTP' to play with. For new connections,
4076 the struct FTP is allocated and setup in the ftp_connect() function.
4078 Curl_reset_reqproto(conn);
4079 retcode = ftp_init(conn);
4083 if(conn->data->set.wildcardmatch) {
4084 retcode = wc_statemach(conn);
4085 if(conn->data->wildcard.state == CURLWC_SKIP ||
4086 conn->data->wildcard.state == CURLWC_DONE) {
4087 /* do not call ftp_regular_transfer */
4090 if(retcode) /* error, loop or skipping the file */
4093 else { /* no wildcard FSM needed */
4094 retcode = ftp_parse_url_path(conn);
4099 retcode = ftp_regular_transfer(conn, done);
4105 CURLcode Curl_ftpsendf(struct connectdata *conn,
4106 const char *fmt, ...)
4108 ssize_t bytes_written;
4109 #define SBUF_SIZE 1024
4113 CURLcode res = CURLE_OK;
4114 #if defined(HAVE_KRB4) || defined(HAVE_GSSAPI)
4115 enum protection_level data_sec = conn->data_prot;
4120 write_len = vsnprintf(s, SBUF_SIZE-3, fmt, ap);
4123 strcpy(&s[write_len], "\r\n"); /* append a trailing CRLF */
4128 res = Curl_convert_to_network(conn->data, s, write_len);
4129 /* Curl_convert_to_network calls failf if unsuccessful */
4134 #if defined(HAVE_KRB4) || defined(HAVE_GSSAPI)
4135 conn->data_prot = PROT_CMD;
4137 res = Curl_write(conn, conn->sock[FIRSTSOCKET], sptr, write_len,
4139 #if defined(HAVE_KRB4) || defined(HAVE_GSSAPI)
4140 DEBUGASSERT(data_sec > PROT_NONE && data_sec < PROT_LAST);
4141 conn->data_prot = data_sec;
4147 if(conn->data->set.verbose)
4148 Curl_debug(conn->data, CURLINFO_HEADER_OUT,
4149 sptr, (size_t)bytes_written, conn);
4151 if(bytes_written != (ssize_t)write_len) {
4152 write_len -= bytes_written;
4153 sptr += bytes_written;
4162 /***********************************************************************
4166 * This should be called before calling sclose() on an ftp control connection
4167 * (not data connections). We should then wait for the response from the
4168 * server before returning. The calling code should then try to close the
4172 static CURLcode ftp_quit(struct connectdata *conn)
4174 CURLcode result = CURLE_OK;
4176 if(conn->proto.ftpc.ctl_valid) {
4177 result = Curl_pp_sendf(&conn->proto.ftpc.pp, "QUIT", NULL);
4179 failf(conn->data, "Failure sending QUIT command: %s",
4180 curl_easy_strerror(result));
4181 conn->proto.ftpc.ctl_valid = FALSE; /* mark control connection as bad */
4182 conn->bits.close = TRUE; /* mark for connection closure */
4183 state(conn, FTP_STOP);
4187 state(conn, FTP_QUIT);
4189 result = ftp_block_statemach(conn);
4195 /***********************************************************************
4199 * Disconnect from an FTP server. Cleanup protocol-specific per-connection
4200 * resources. BLOCKING.
4202 static CURLcode ftp_disconnect(struct connectdata *conn, bool dead_connection)
4204 struct ftp_conn *ftpc= &conn->proto.ftpc;
4205 struct pingpong *pp = &ftpc->pp;
4207 /* We cannot send quit unconditionally. If this connection is stale or
4208 bad in any way, sending quit and waiting around here will make the
4209 disconnect wait in vain and cause more problems than we need to.
4211 ftp_quit() will check the state of ftp->ctl_valid. If it's ok it
4212 will try to send the QUIT command, otherwise it will just return.
4215 ftpc->ctl_valid = FALSE;
4217 /* The FTP session may or may not have been allocated/setup at this point! */
4218 (void)ftp_quit(conn); /* ignore errors on the QUIT */
4220 if(ftpc->entrypath) {
4221 struct SessionHandle *data = conn->data;
4222 if(data->state.most_recent_ftp_entrypath == ftpc->entrypath) {
4223 data->state.most_recent_ftp_entrypath = NULL;
4225 free(ftpc->entrypath);
4226 ftpc->entrypath = NULL;
4230 if(ftpc->prevpath) {
4231 free(ftpc->prevpath);
4232 ftpc->prevpath = NULL;
4234 if(ftpc->server_os) {
4235 free(ftpc->server_os);
4236 ftpc->server_os = NULL;
4239 Curl_pp_disconnect(pp);
4241 #if defined(HAVE_KRB4) || defined(HAVE_GSSAPI)
4248 /***********************************************************************
4250 * ftp_parse_url_path()
4252 * Parse the URL path into separate path components.
4256 CURLcode ftp_parse_url_path(struct connectdata *conn)
4258 struct SessionHandle *data = conn->data;
4259 /* the ftp struct is already inited in ftp_connect() */
4260 struct FTP *ftp = data->state.proto.ftp;
4261 struct ftp_conn *ftpc = &conn->proto.ftpc;
4262 const char *slash_pos; /* position of the first '/' char in curpos */
4263 const char *path_to_use = data->state.path;
4264 const char *cur_pos;
4265 const char *filename = NULL;
4267 cur_pos = path_to_use; /* current position in path. point at the begin
4268 of next path component */
4270 ftpc->ctl_valid = FALSE;
4271 ftpc->cwdfail = FALSE;
4273 switch(data->set.ftp_filemethod) {
4275 /* fastest, but less standard-compliant */
4278 The best time to check whether the path is a file or directory is right
4281 the first condition in the if() right here, is there just in case
4282 someone decides to set path to NULL one day
4284 if(data->state.path &&
4285 data->state.path[0] &&
4286 (data->state.path[strlen(data->state.path) - 1] != '/') )
4287 filename = data->state.path; /* this is a full file path */
4289 ftpc->file is not used anywhere other than for operations on a file.
4290 In other words, never for directory operations.
4291 So we can safely leave filename as NULL here and use it as a
4292 argument in dir/file decisions.
4296 case FTPFILE_SINGLECWD:
4297 /* get the last slash */
4298 if(!path_to_use[0]) {
4299 /* no dir, no file */
4303 slash_pos=strrchr(cur_pos, '/');
4304 if(slash_pos || !*cur_pos) {
4305 ftpc->dirs = calloc(1, sizeof(ftpc->dirs[0]));
4307 return CURLE_OUT_OF_MEMORY;
4309 ftpc->dirs[0] = curl_easy_unescape(conn->data, slash_pos ? cur_pos : "/",
4311 curlx_sztosi(slash_pos-cur_pos) : 1,
4313 if(!ftpc->dirs[0]) {
4315 return CURLE_OUT_OF_MEMORY;
4317 ftpc->dirdepth = 1; /* we consider it to be a single dir */
4318 filename = slash_pos ? slash_pos+1 : cur_pos; /* rest is file name */
4321 filename = cur_pos; /* this is a file name only */
4324 default: /* allow pretty much anything */
4325 case FTPFILE_MULTICWD:
4327 ftpc->diralloc = 5; /* default dir depth to allocate */
4328 ftpc->dirs = calloc(ftpc->diralloc, sizeof(ftpc->dirs[0]));
4330 return CURLE_OUT_OF_MEMORY;
4332 /* we have a special case for listing the root dir only */
4333 if(strequal(path_to_use, "/")) {
4334 cur_pos++; /* make it point to the zero byte */
4335 ftpc->dirs[0] = strdup("/");
4339 /* parse the URL path into separate path components */
4340 while((slash_pos = strchr(cur_pos, '/')) != NULL) {
4341 /* 1 or 0 pointer offset to indicate absolute directory */
4342 ssize_t absolute_dir = ((cur_pos - data->state.path > 0) &&
4343 (ftpc->dirdepth == 0))?1:0;
4345 /* seek out the next path component */
4346 if(slash_pos-cur_pos) {
4347 /* we skip empty path components, like "x//y" since the FTP command
4348 CWD requires a parameter and a non-existent parameter a) doesn't
4349 work on many servers and b) has no effect on the others. */
4350 int len = curlx_sztosi(slash_pos - cur_pos + absolute_dir);
4351 ftpc->dirs[ftpc->dirdepth] =
4352 curl_easy_unescape(conn->data, cur_pos - absolute_dir, len, NULL);
4353 if(!ftpc->dirs[ftpc->dirdepth]) { /* run out of memory ... */
4354 failf(data, "no memory");
4356 return CURLE_OUT_OF_MEMORY;
4358 if(isBadFtpString(ftpc->dirs[ftpc->dirdepth])) {
4359 free(ftpc->dirs[ftpc->dirdepth]);
4361 return CURLE_URL_MALFORMAT;
4365 cur_pos = slash_pos + 1; /* jump to the rest of the string */
4369 cur_pos = slash_pos + 1; /* jump to the rest of the string */
4370 if(++ftpc->dirdepth >= ftpc->diralloc) {
4373 ftpc->diralloc *= 2; /* double the size each time */
4374 bigger = realloc(ftpc->dirs, ftpc->diralloc * sizeof(ftpc->dirs[0]));
4377 return CURLE_OUT_OF_MEMORY;
4379 ftpc->dirs = bigger;
4383 filename = cur_pos; /* the rest is the file name */
4387 if(filename && *filename) {
4388 ftpc->file = curl_easy_unescape(conn->data, filename, 0, NULL);
4389 if(NULL == ftpc->file) {
4391 failf(data, "no memory");
4392 return CURLE_OUT_OF_MEMORY;
4394 if(isBadFtpString(ftpc->file)) {
4396 return CURLE_URL_MALFORMAT;
4400 ftpc->file=NULL; /* instead of point to a zero byte, we make it a NULL
4403 if(data->set.upload && !ftpc->file && (ftp->transfer == FTPTRANSFER_BODY)) {
4404 /* We need a file name when uploading. Return error! */
4405 failf(data, "Uploading to a URL without a file name!");
4406 return CURLE_URL_MALFORMAT;
4409 ftpc->cwddone = FALSE; /* default to not done */
4411 if(ftpc->prevpath) {
4412 /* prevpath is "raw" so we convert the input path before we compare the
4415 char *path = curl_easy_unescape(conn->data, data->state.path, 0, &dlen);
4418 return CURLE_OUT_OF_MEMORY;
4421 dlen -= ftpc->file?curlx_uztosi(strlen(ftpc->file)):0;
4422 if((dlen == curlx_uztosi(strlen(ftpc->prevpath))) &&
4423 strnequal(path, ftpc->prevpath, dlen)) {
4424 infof(data, "Request has same path as previous transfer\n");
4425 ftpc->cwddone = TRUE;
4433 /* call this when the DO phase has completed */
4434 static CURLcode ftp_dophase_done(struct connectdata *conn,
4437 struct FTP *ftp = conn->data->state.proto.ftp;
4438 struct ftp_conn *ftpc = &conn->proto.ftpc;
4442 CURLcode result = ftp_do_more(conn, &completed);
4445 if(conn->sock[SECONDARYSOCKET] != CURL_SOCKET_BAD) {
4446 /* close the second socket if it was created already */
4447 Curl_closesocket(conn, conn->sock[SECONDARYSOCKET]);
4448 conn->sock[SECONDARYSOCKET] = CURL_SOCKET_BAD;
4454 if(ftp->transfer != FTPTRANSFER_BODY)
4455 /* no data to transfer */
4456 Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
4458 /* since we didn't connect now, we want do_more to get called */
4459 conn->bits.do_more = TRUE;
4461 ftpc->ctl_valid = TRUE; /* seems good */
4466 /* called from multi.c while DOing */
4467 static CURLcode ftp_doing(struct connectdata *conn,
4470 CURLcode result = ftp_multi_statemach(conn, dophase_done);
4473 DEBUGF(infof(conn->data, "DO phase failed\n"));
4474 else if(*dophase_done) {
4475 result = ftp_dophase_done(conn, FALSE /* not connected */);
4477 DEBUGF(infof(conn->data, "DO phase is complete2\n"));
4482 /***********************************************************************
4484 * ftp_regular_transfer()
4486 * The input argument is already checked for validity.
4488 * Performs all commands done before a regular transfer between a local and a
4491 * ftp->ctl_valid starts out as FALSE, and gets set to TRUE if we reach the
4492 * ftp_done() function without finding any major problem.
4495 CURLcode ftp_regular_transfer(struct connectdata *conn,
4498 CURLcode result=CURLE_OK;
4499 bool connected=FALSE;
4500 struct SessionHandle *data = conn->data;
4501 struct ftp_conn *ftpc = &conn->proto.ftpc;
4502 data->req.size = -1; /* make sure this is unknown at this point */
4504 Curl_pgrsSetUploadCounter(data, 0);
4505 Curl_pgrsSetDownloadCounter(data, 0);
4506 Curl_pgrsSetUploadSize(data, 0);
4507 Curl_pgrsSetDownloadSize(data, 0);
4509 ftpc->ctl_valid = TRUE; /* starts good */
4511 result = ftp_perform(conn,
4512 &connected, /* have we connected after PASV/PORT */
4513 dophase_done); /* all commands in the DO-phase done? */
4515 if(CURLE_OK == result) {
4518 /* the DO phase has not completed yet */
4521 result = ftp_dophase_done(conn, connected);
4532 static CURLcode ftp_setup_connection(struct connectdata * conn)
4534 struct SessionHandle *data = conn->data;
4538 if(conn->bits.httpproxy && !data->set.tunnel_thru_httpproxy) {
4539 /* Unless we have asked to tunnel ftp operations through the proxy, we
4540 switch and use HTTP operations only */
4541 #ifndef CURL_DISABLE_HTTP
4542 if(conn->handler == &Curl_handler_ftp)
4543 conn->handler = &Curl_handler_ftp_proxy;
4546 conn->handler = &Curl_handler_ftps_proxy;
4548 failf(data, "FTPS not supported!");
4549 return CURLE_UNSUPPORTED_PROTOCOL;
4553 * We explicitly mark this connection as persistent here as we're doing
4554 * FTP over HTTP and thus we accidentally avoid setting this value
4557 conn->bits.close = FALSE;
4559 failf(data, "FTP over http proxy requires HTTP support built-in!");
4560 return CURLE_UNSUPPORTED_PROTOCOL;
4564 data->state.path++; /* don't include the initial slash */
4565 data->state.slash_removed = TRUE; /* we've skipped the slash */
4567 /* FTP URLs support an extension like ";type=<typecode>" that
4568 * we'll try to get now! */
4569 type = strstr(data->state.path, ";type=");
4572 type = strstr(conn->host.rawalloc, ";type=");
4575 *type = 0; /* it was in the middle of the hostname */
4576 command = Curl_raw_toupper(type[6]);
4577 conn->bits.type_set = TRUE;
4580 case 'A': /* ASCII mode */
4581 data->set.prefer_ascii = TRUE;
4584 case 'D': /* directory mode */
4585 data->set.ftp_list_only = TRUE;
4588 case 'I': /* binary mode */
4590 /* switch off ASCII */
4591 data->set.prefer_ascii = FALSE;
4599 #endif /* CURL_DISABLE_FTP */