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 FTPSENDF(x,y,z) if((result = Curl_ftpsendf(x,y,z)) != CURLE_OK) \
167 #define PPSENDF(x,y,z) if((result = Curl_pp_sendf(x,y,z)) != CURLE_OK) \
172 * FTP protocol handler.
175 const struct Curl_handler Curl_handler_ftp = {
177 ftp_setup_connection, /* setup_connection */
180 ftp_do_more, /* do_more */
181 ftp_connect, /* connect_it */
182 ftp_multi_statemach, /* connecting */
183 ftp_doing, /* doing */
184 ftp_getsock, /* proto_getsock */
185 ftp_getsock, /* doing_getsock */
186 ftp_domore_getsock, /* domore_getsock */
187 ZERO_NULL, /* perform_getsock */
188 ftp_disconnect, /* disconnect */
189 ZERO_NULL, /* readwrite */
190 PORT_FTP, /* defport */
191 CURLPROTO_FTP, /* protocol */
192 PROTOPT_DUAL | PROTOPT_CLOSEACTION | PROTOPT_NEEDSPWD
193 | PROTOPT_NOURLQUERY /* flags */
199 * FTPS protocol handler.
202 const struct Curl_handler Curl_handler_ftps = {
204 ftp_setup_connection, /* setup_connection */
207 ftp_do_more, /* do_more */
208 ftp_connect, /* connect_it */
209 ftp_multi_statemach, /* connecting */
210 ftp_doing, /* doing */
211 ftp_getsock, /* proto_getsock */
212 ftp_getsock, /* doing_getsock */
213 ftp_domore_getsock, /* domore_getsock */
214 ZERO_NULL, /* perform_getsock */
215 ftp_disconnect, /* disconnect */
216 ZERO_NULL, /* readwrite */
217 PORT_FTPS, /* defport */
218 CURLPROTO_FTP | CURLPROTO_FTPS, /* protocol */
219 PROTOPT_SSL | PROTOPT_DUAL | PROTOPT_CLOSEACTION |
220 PROTOPT_NEEDSPWD | PROTOPT_NOURLQUERY /* flags */
224 #ifndef CURL_DISABLE_HTTP
226 * HTTP-proxyed FTP protocol handler.
229 static const struct Curl_handler Curl_handler_ftp_proxy = {
231 ZERO_NULL, /* setup_connection */
232 Curl_http, /* do_it */
233 Curl_http_done, /* done */
234 ZERO_NULL, /* do_more */
235 ZERO_NULL, /* connect_it */
236 ZERO_NULL, /* connecting */
237 ZERO_NULL, /* doing */
238 ZERO_NULL, /* proto_getsock */
239 ZERO_NULL, /* doing_getsock */
240 ZERO_NULL, /* domore_getsock */
241 ZERO_NULL, /* perform_getsock */
242 ZERO_NULL, /* disconnect */
243 ZERO_NULL, /* readwrite */
244 PORT_FTP, /* defport */
245 CURLPROTO_HTTP, /* protocol */
246 PROTOPT_NONE /* flags */
252 * HTTP-proxyed FTPS protocol handler.
255 static const struct Curl_handler Curl_handler_ftps_proxy = {
257 ZERO_NULL, /* setup_connection */
258 Curl_http, /* do_it */
259 Curl_http_done, /* done */
260 ZERO_NULL, /* do_more */
261 ZERO_NULL, /* connect_it */
262 ZERO_NULL, /* connecting */
263 ZERO_NULL, /* doing */
264 ZERO_NULL, /* proto_getsock */
265 ZERO_NULL, /* doing_getsock */
266 ZERO_NULL, /* domore_getsock */
267 ZERO_NULL, /* perform_getsock */
268 ZERO_NULL, /* disconnect */
269 ZERO_NULL, /* readwrite */
270 PORT_FTPS, /* defport */
271 CURLPROTO_HTTP, /* protocol */
272 PROTOPT_NONE /* flags */
279 * NOTE: back in the old days, we added code in the FTP code that made NOBODY
280 * requests on files respond with headers passed to the client/stdout that
281 * looked like HTTP ones.
283 * This approach is not very elegant, it causes confusion and is error-prone.
284 * It is subject for removal at the next (or at least a future) soname bump.
285 * Until then you can test the effects of the removal by undefining the
286 * following define named CURL_FTP_HTTPSTYLE_HEAD.
288 #define CURL_FTP_HTTPSTYLE_HEAD 1
290 static void freedirs(struct ftp_conn *ftpc)
294 for(i=0; i < ftpc->dirdepth; i++) {
310 /* Returns non-zero if the given string contains CR (\r) or LF (\n),
311 which are not allowed within RFC 959 <string>.
312 Note: The input string is in the client's encoding which might
313 not be ASCII, so escape sequences \r & \n must be used instead
314 of hex values 0x0d & 0x0a.
316 static bool isBadFtpString(const char *string)
318 return ((NULL != strchr(string, '\r')) ||
319 (NULL != strchr(string, '\n'))) ? TRUE : FALSE;
322 /***********************************************************************
324 * AcceptServerConnect()
326 * After connection request is received from the server this function is
327 * called to accept the connection and close the listening socket
330 static CURLcode AcceptServerConnect(struct connectdata *conn)
332 struct SessionHandle *data = conn->data;
333 curl_socket_t sock = conn->sock[SECONDARYSOCKET];
334 curl_socket_t s = CURL_SOCKET_BAD;
336 struct Curl_sockaddr_storage add;
338 struct sockaddr_in add;
340 curl_socklen_t size = (curl_socklen_t) sizeof(add);
342 if(0 == getsockname(sock, (struct sockaddr *) &add, &size)) {
345 s=accept(sock, (struct sockaddr *) &add, &size);
347 Curl_closesocket(conn, sock); /* close the first socket */
349 if(CURL_SOCKET_BAD == s) {
350 failf(data, "Error accept()ing server connect");
351 return CURLE_FTP_PORT_FAILED;
353 infof(data, "Connection accepted from server\n");
355 conn->sock[SECONDARYSOCKET] = s;
356 curlx_nonblock(s, TRUE); /* enable non-blocking */
357 conn->sock_accepted[SECONDARYSOCKET] = TRUE;
359 if(data->set.fsockopt) {
362 /* activate callback for setting socket options */
363 error = data->set.fsockopt(data->set.sockopt_client,
365 CURLSOCKTYPE_ACCEPT);
368 Curl_closesocket(conn, s); /* close the socket and bail out */
369 conn->sock[SECONDARYSOCKET] = CURL_SOCKET_BAD;
370 return CURLE_ABORTED_BY_CALLBACK;
379 * ftp_timeleft_accept() returns the amount of milliseconds left allowed for
380 * waiting server to connect. If the value is negative, the timeout time has
383 * The start time is stored in progress.t_acceptdata - as set with
384 * Curl_pgrsTime(..., TIMER_STARTACCEPT);
387 static long ftp_timeleft_accept(struct SessionHandle *data)
389 long timeout_ms = DEFAULT_ACCEPT_TIMEOUT;
393 if(data->set.accepttimeout > 0)
394 timeout_ms = data->set.accepttimeout;
398 /* check if the generic timeout possibly is set shorter */
399 other = Curl_timeleft(data, &now, FALSE);
400 if(other && (other < timeout_ms))
401 /* note that this also works fine for when other happens to be negative
402 due to it already having elapsed */
405 /* subtract elapsed time */
406 timeout_ms -= Curl_tvdiff(now, data->progress.t_acceptdata);
408 /* avoid returning 0 as that means no timeout! */
416 /***********************************************************************
418 * ReceivedServerConnect()
420 * After allowing server to connect to us from data port, this function
421 * checks both data connection for connection establishment and ctrl
422 * connection for a negative response regarding a failure in connecting
425 static CURLcode ReceivedServerConnect(struct connectdata *conn, bool *received)
427 struct SessionHandle *data = conn->data;
428 curl_socket_t ctrl_sock = conn->sock[FIRSTSOCKET];
429 curl_socket_t data_sock = conn->sock[SECONDARYSOCKET];
430 struct ftp_conn *ftpc = &conn->proto.ftpc;
431 struct pingpong *pp = &ftpc->pp;
439 timeout_ms = ftp_timeleft_accept(data);
440 infof(data, "Checking for server connect\n");
442 /* if a timeout was already reached, bail out */
443 failf(data, "Accept timeout occurred while waiting server connect");
444 return CURLE_FTP_ACCEPT_TIMEOUT;
447 /* First check whether there is a cached response from server */
448 if(pp->cache_size && pp->cache && pp->cache[0] > '3') {
449 /* Data connection could not be established, let's return */
450 infof(data, "There is negative response in cache while serv connect\n");
451 Curl_GetFTPResponse(&nread, conn, &ftpcode);
452 return CURLE_FTP_ACCEPT_FAILED;
455 result = Curl_socket_check(ctrl_sock, data_sock, CURL_SOCKET_BAD, 0);
457 /* see if the connection request is already here */
461 failf(data, "Error while waiting for server connect");
462 return CURLE_FTP_ACCEPT_FAILED;
463 case 0: /* Server connect is not received yet */
467 if(result & CURL_CSELECT_IN2) {
468 infof(data, "Ready to accept data connection from server\n");
471 else if(result & CURL_CSELECT_IN) {
472 infof(data, "Ctrl conn has data while waiting for data conn\n");
473 Curl_GetFTPResponse(&nread, conn, &ftpcode);
476 return CURLE_FTP_ACCEPT_FAILED;
478 return CURLE_FTP_WEIRD_SERVER_REPLY;
488 /***********************************************************************
492 * After connection from server is accepted this function is called to
493 * setup transfer parameters and initiate the data transfer.
496 static CURLcode InitiateTransfer(struct connectdata *conn)
498 struct SessionHandle *data = conn->data;
499 struct FTP *ftp = data->state.proto.ftp;
500 CURLcode result = CURLE_OK;
502 if(conn->ssl[SECONDARYSOCKET].use) {
503 /* since we only have a plaintext TCP connection here, we must now
504 * do the TLS stuff */
505 infof(data, "Doing the SSL/TLS handshake on the data stream\n");
506 result = Curl_ssl_connect(conn, SECONDARYSOCKET);
511 if(conn->proto.ftpc.state_saved == FTP_STOR) {
512 *(ftp->bytecountp)=0;
514 /* When we know we're uploading a specified file, we can get the file
515 size prior to the actual upload. */
517 Curl_pgrsSetUploadSize(data, data->set.infilesize);
519 /* set the SO_SNDBUF for the secondary socket for those who need it */
520 Curl_sndbufset(conn->sock[SECONDARYSOCKET]);
522 Curl_setup_transfer(conn, -1, -1, FALSE, NULL, /* no download */
523 SECONDARYSOCKET, ftp->bytecountp);
527 Curl_setup_transfer(conn, SECONDARYSOCKET,
528 conn->proto.ftpc.retr_size_saved, FALSE,
529 ftp->bytecountp, -1, NULL); /* no upload here */
532 conn->proto.ftpc.pp.pending_resp = TRUE; /* expect server response */
533 state(conn, FTP_STOP);
538 /***********************************************************************
540 * AllowServerConnect()
542 * When we've issue the PORT command, we have told the server to connect to
543 * us. This function checks whether data connection is established if so it is
547 static CURLcode AllowServerConnect(struct connectdata *conn, bool *connected)
549 struct SessionHandle *data = conn->data;
551 CURLcode ret = CURLE_OK;
554 infof(data, "Preparing for accepting server on data port\n");
556 /* Save the time we start accepting server connect */
557 Curl_pgrsTime(data, TIMER_STARTACCEPT);
559 timeout_ms = ftp_timeleft_accept(data);
561 /* if a timeout was already reached, bail out */
562 failf(data, "Accept timeout occurred while waiting server connect");
563 return CURLE_FTP_ACCEPT_TIMEOUT;
566 /* see if the connection request is already here */
567 ret = ReceivedServerConnect(conn, connected);
572 ret = AcceptServerConnect(conn);
576 ret = InitiateTransfer(conn);
581 /* Add timeout to multi handle and break out of the loop */
582 if(ret == CURLE_OK && *connected == FALSE) {
583 if(data->set.accepttimeout > 0)
584 Curl_expire(data, data->set.accepttimeout);
586 Curl_expire(data, DEFAULT_ACCEPT_TIMEOUT);
593 /* macro to check for a three-digit ftp status code at the start of the
595 #define STATUSCODE(line) (ISDIGIT(line[0]) && ISDIGIT(line[1]) && \
598 /* macro to check for the last line in an FTP server response */
599 #define LASTLINE(line) (STATUSCODE(line) && (' ' == line[3]))
601 static int ftp_endofresp(struct pingpong *pp,
604 char *line = pp->linestart_resp;
605 size_t len = pp->nread_resp;
607 if((len > 3) && LASTLINE(line)) {
608 *code = curlx_sltosi(strtol(line, NULL, 10));
614 static CURLcode ftp_readresp(curl_socket_t sockfd,
616 int *ftpcode, /* return the ftp-code if done */
617 size_t *size) /* size of the response */
619 struct connectdata *conn = pp->conn;
620 struct SessionHandle *data = conn->data;
621 #if defined(HAVE_KRB4) || defined(HAVE_GSSAPI)
622 char * const buf = data->state.buffer;
624 CURLcode result = CURLE_OK;
627 result = Curl_pp_readresp(sockfd, pp, &code, size);
629 #if defined(HAVE_KRB4) || defined(HAVE_GSSAPI)
630 /* handle the security-oriented responses 6xx ***/
631 /* FIXME: some errorchecking perhaps... ***/
634 code = Curl_sec_read_msg(conn, buf, PROT_SAFE);
637 code = Curl_sec_read_msg(conn, buf, PROT_PRIVATE);
640 code = Curl_sec_read_msg(conn, buf, PROT_CONFIDENTIAL);
643 /* normal ftp stuff we pass through! */
648 /* store the latest code for later retrieval */
649 data->info.httpcode=code;
655 /* 421 means "Service not available, closing control connection." and FTP
656 * servers use it to signal that idle session timeout has been exceeded.
657 * If we ignored the response, it could end up hanging in some cases.
659 * This response code can come at any point so having it treated
660 * generically is a good idea.
662 infof(data, "We got a 421 - timeout!\n");
663 state(conn, FTP_STOP);
664 return CURLE_OPERATION_TIMEDOUT;
670 /* --- parse FTP server responses --- */
673 * Curl_GetFTPResponse() is a BLOCKING function to read the full response
674 * from a server after a command.
678 CURLcode Curl_GetFTPResponse(ssize_t *nreadp, /* return number of bytes read */
679 struct connectdata *conn,
680 int *ftpcode) /* return the ftp-code */
683 * We cannot read just one byte per read() and then go back to select() as
684 * the OpenSSL read() doesn't grok that properly.
686 * Alas, read as much as possible, split up into lines, use the ending
687 * line in a response or continue reading. */
689 curl_socket_t sockfd = conn->sock[FIRSTSOCKET];
690 long timeout; /* timeout in milliseconds */
692 struct SessionHandle *data = conn->data;
693 CURLcode result = CURLE_OK;
694 struct ftp_conn *ftpc = &conn->proto.ftpc;
695 struct pingpong *pp = &ftpc->pp;
698 int value_to_be_ignored=0;
701 *ftpcode = 0; /* 0 for errors */
703 /* make the pointer point to something for the rest of this function */
704 ftpcode = &value_to_be_ignored;
708 while(!*ftpcode && !result) {
709 /* check and reset timeout value every lap */
710 timeout = Curl_pp_state_timeout(pp);
713 failf(data, "FTP response timeout");
714 return CURLE_OPERATION_TIMEDOUT; /* already too little time */
717 interval_ms = 1000; /* use 1 second timeout intervals */
718 if(timeout < interval_ms)
719 interval_ms = timeout;
722 * Since this function is blocking, we need to wait here for input on the
723 * connection and only then we call the response reading function. We do
724 * timeout at least every second to make the timeout check run.
726 * A caution here is that the ftp_readresp() function has a cache that may
727 * contain pieces of a response from the previous invoke and we need to
728 * make sure we don't just wait for input while there is unhandled data in
729 * that cache. But also, if the cache is there, we call ftp_readresp() and
730 * the cache wasn't good enough to continue we must not just busy-loop
731 * around this function.
735 if(pp->cache && (cache_skip < 2)) {
737 * There's a cache left since before. We then skipping the wait for
738 * socket action, unless this is the same cache like the previous round
739 * as then the cache was deemed not enough to act on and we then need to
740 * wait for more data anyway.
744 switch (Curl_socket_ready(sockfd, CURL_SOCKET_BAD, interval_ms)) {
745 case -1: /* select() error, stop reading */
746 failf(data, "FTP response aborted due to select/poll error: %d",
748 return CURLE_RECV_ERROR;
750 case 0: /* timeout */
751 if(Curl_pgrsUpdate(conn))
752 return CURLE_ABORTED_BY_CALLBACK;
753 continue; /* just continue in our loop for the timeout duration */
755 default: /* for clarity */
759 result = ftp_readresp(sockfd, pp, ftpcode, &nread);
763 if(!nread && pp->cache)
764 /* bump cache skip counter as on repeated skips we must wait for more
768 /* when we got data or there is no cache left, we reset the cache skip
774 } /* while there's buffer left and loop is requested */
776 pp->pending_resp = FALSE;
781 /* This is the ONLY way to change FTP state! */
782 static void _state(struct connectdata *conn,
789 #if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
790 /* for debug purposes */
791 static const char * const names[]={
829 struct ftp_conn *ftpc = &conn->proto.ftpc;
830 #if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
831 if(ftpc->state != newstate)
832 infof(conn->data, "FTP %p (line %d) state change from %s to %s\n",
833 ftpc, lineno, names[ftpc->state], names[newstate]);
835 ftpc->state = newstate;
838 static CURLcode ftp_state_user(struct connectdata *conn)
841 struct FTP *ftp = conn->data->state.proto.ftp;
843 PPSENDF(&conn->proto.ftpc.pp, "USER %s", ftp->user?ftp->user:"");
845 state(conn, FTP_USER);
846 conn->data->state.ftp_trying_alternative = FALSE;
851 static CURLcode ftp_state_pwd(struct connectdata *conn)
855 /* send PWD to discover our entry point */
856 PPSENDF(&conn->proto.ftpc.pp, "PWD", NULL);
857 state(conn, FTP_PWD);
862 /* For the FTP "protocol connect" and "doing" phases only */
863 static int ftp_getsock(struct connectdata *conn,
864 curl_socket_t *socks,
867 return Curl_pp_getsock(&conn->proto.ftpc.pp, socks, numsocks);
870 /* For the FTP "DO_MORE" phase only */
871 static int ftp_domore_getsock(struct connectdata *conn, curl_socket_t *socks,
874 struct ftp_conn *ftpc = &conn->proto.ftpc;
877 return GETSOCK_BLANK;
879 /* When in DO_MORE state, we could be either waiting for us to connect to a
880 remote site, or we could wait for that site to connect to us. Or just
881 handle ordinary commands.
883 When waiting for a connect, we will be in FTP_STOP state and then we wait
884 for the secondary socket to become writeable. If we're in another state,
885 we're still handling commands on the control (primary) connection.
889 switch(ftpc->state) {
893 return Curl_pp_getsock(&conn->proto.ftpc.pp, socks, numsocks);
896 socks[0] = conn->sock[SECONDARYSOCKET];
897 if(ftpc->wait_data_conn) {
898 socks[1] = conn->sock[FIRSTSOCKET];
899 return GETSOCK_READSOCK(0) | GETSOCK_READSOCK(1);
902 return GETSOCK_READSOCK(0);
905 /* This is called after the FTP_QUOTE state is passed.
907 ftp_state_cwd() sends the range of CWD commands to the server to change to
908 the correct directory. It may also need to send MKD commands to create
909 missing ones, if that option is enabled.
911 static CURLcode ftp_state_cwd(struct connectdata *conn)
913 CURLcode result = CURLE_OK;
914 struct ftp_conn *ftpc = &conn->proto.ftpc;
917 /* already done and fine */
918 result = ftp_state_post_cwd(conn);
920 ftpc->count2 = 0; /* count2 counts failed CWDs */
922 /* count3 is set to allow a MKD to fail once. In the case when first CWD
923 fails and then MKD fails (due to another session raced it to create the
924 dir) this then allows for a second try to CWD to it */
925 ftpc->count3 = (conn->data->set.ftp_create_missing_dirs==2)?1:0;
927 if(conn->bits.reuse && ftpc->entrypath) {
928 /* This is a re-used connection. Since we change directory to where the
929 transfer is taking place, we must first get back to the original dir
930 where we ended up after login: */
931 ftpc->count1 = 0; /* we count this as the first path, then we add one
932 for all upcoming ones in the ftp->dirs[] array */
933 PPSENDF(&conn->proto.ftpc.pp, "CWD %s", ftpc->entrypath);
934 state(conn, FTP_CWD);
939 /* issue the first CWD, the rest is sent when the CWD responses are
941 PPSENDF(&conn->proto.ftpc.pp, "CWD %s", ftpc->dirs[ftpc->count1 -1]);
942 state(conn, FTP_CWD);
945 /* No CWD necessary */
946 result = ftp_state_post_cwd(conn);
959 static CURLcode ftp_state_use_port(struct connectdata *conn,
960 ftpport fcmd) /* start with this */
963 CURLcode result = CURLE_OK;
964 struct ftp_conn *ftpc = &conn->proto.ftpc;
965 struct SessionHandle *data=conn->data;
966 curl_socket_t portsock= CURL_SOCKET_BAD;
967 char myhost[256] = "";
969 struct Curl_sockaddr_storage ss;
970 Curl_addrinfo *res, *ai;
971 curl_socklen_t sslen;
972 char hbuf[NI_MAXHOST];
973 struct sockaddr *sa=(struct sockaddr *)&ss;
974 struct sockaddr_in * const sa4 = (void *)sa;
976 struct sockaddr_in6 * const sa6 = (void *)sa;
979 static const char mode[][5] = { "EPRT", "PORT" };
983 char *string_ftpport = data->set.str[STRING_FTPPORT];
984 struct Curl_dns_entry *h=NULL;
985 unsigned short port_min = 0;
986 unsigned short port_max = 0;
988 bool possibly_non_local = TRUE;
992 /* Step 1, figure out what is requested,
994 * (ipv4|ipv6|domain|interface)?(:port(-range)?)?
997 if(data->set.str[STRING_FTPPORT] &&
998 (strlen(data->set.str[STRING_FTPPORT]) > 1)) {
1001 size_t addrlen = INET6_ADDRSTRLEN > strlen(string_ftpport) ?
1002 INET6_ADDRSTRLEN : strlen(string_ftpport);
1004 size_t addrlen = INET_ADDRSTRLEN > strlen(string_ftpport) ?
1005 INET_ADDRSTRLEN : strlen(string_ftpport);
1007 char *ip_start = string_ftpport;
1008 char *ip_end = NULL;
1009 char *port_start = NULL;
1010 char *port_sep = NULL;
1012 addr = calloc(addrlen+1, 1);
1014 return CURLE_OUT_OF_MEMORY;
1017 if(*string_ftpport == '[') {
1018 /* [ipv6]:port(-range) */
1019 ip_start = string_ftpport + 1;
1020 if((ip_end = strchr(string_ftpport, ']')) != NULL )
1021 strncpy(addr, ip_start, ip_end - ip_start);
1025 if(*string_ftpport == ':') {
1027 ip_end = string_ftpport;
1029 else if((ip_end = strchr(string_ftpport, ':')) != NULL) {
1030 /* either ipv6 or (ipv4|domain|interface):port(-range) */
1032 if(Curl_inet_pton(AF_INET6, string_ftpport, sa6) == 1) {
1034 port_min = port_max = 0;
1035 strcpy(addr, string_ftpport);
1036 ip_end = NULL; /* this got no port ! */
1040 /* (ipv4|domain|interface):port(-range) */
1041 strncpy(addr, string_ftpport, ip_end - ip_start );
1044 /* ipv4|interface */
1045 strcpy(addr, string_ftpport);
1047 /* parse the port */
1048 if(ip_end != NULL) {
1049 if((port_start = strchr(ip_end, ':')) != NULL) {
1050 port_min = curlx_ultous(strtoul(port_start+1, NULL, 10));
1051 if((port_sep = strchr(port_start, '-')) != NULL) {
1052 port_max = curlx_ultous(strtoul(port_sep + 1, NULL, 10));
1055 port_max = port_min;
1059 /* correct errors like:
1061 * :-4711 , in this case port_min is (unsigned)-1,
1062 * therefore port_min > port_max for all cases
1063 * but port_max = (unsigned)-1
1065 if(port_min > port_max )
1066 port_min = port_max = 0;
1070 /* attempt to get the address of the given interface name */
1071 if(!Curl_if2ip(conn->ip_addr->ai_family, addr,
1072 hbuf, sizeof(hbuf)))
1073 /* not an interface, use the given string as host name instead */
1076 host = hbuf; /* use the hbuf for host name */
1079 /* there was only a port(-range) given, default the host */
1081 } /* data->set.ftpport */
1084 /* not an interface and not a host name, get default by extracting
1085 the IP from the control connection */
1088 if(getsockname(conn->sock[FIRSTSOCKET], sa, &sslen)) {
1089 failf(data, "getsockname() failed: %s",
1090 Curl_strerror(conn, SOCKERRNO) );
1091 Curl_safefree(addr);
1092 return CURLE_FTP_PORT_FAILED;
1094 switch(sa->sa_family) {
1097 Curl_inet_ntop(sa->sa_family, &sa6->sin6_addr, hbuf, sizeof(hbuf));
1101 Curl_inet_ntop(sa->sa_family, &sa4->sin_addr, hbuf, sizeof(hbuf));
1104 host = hbuf; /* use this host name */
1105 possibly_non_local = FALSE; /* we know it is local now */
1108 /* resolv ip/host to ip */
1109 rc = Curl_resolv(conn, host, 0, &h);
1110 if(rc == CURLRESOLV_PENDING)
1111 (void)Curl_resolver_wait_resolv(conn, &h);
1114 /* when we return from this function, we can forget about this entry
1115 to we can unlock it now already */
1116 Curl_resolv_unlock(data, h);
1119 res = NULL; /* failure! */
1122 failf(data, "failed to resolve the address provided to PORT: %s", host);
1123 Curl_safefree(addr);
1124 return CURLE_FTP_PORT_FAILED;
1127 Curl_safefree(addr);
1130 /* step 2, create a socket for the requested address */
1132 portsock = CURL_SOCKET_BAD;
1134 for(ai = res; ai; ai = ai->ai_next) {
1135 result = Curl_socket(conn, ai, NULL, &portsock);
1143 failf(data, "socket failure: %s", Curl_strerror(conn, error));
1144 return CURLE_FTP_PORT_FAILED;
1147 /* step 3, bind to a suitable local address */
1149 memcpy(sa, ai->ai_addr, ai->ai_addrlen);
1150 sslen = ai->ai_addrlen;
1152 for(port = port_min; port <= port_max;) {
1153 if(sa->sa_family == AF_INET)
1154 sa4->sin_port = htons(port);
1157 sa6->sin6_port = htons(port);
1159 /* Try binding the given address. */
1160 if(bind(portsock, sa, sslen) ) {
1163 if(possibly_non_local && (error == EADDRNOTAVAIL)) {
1164 /* The requested bind address is not local. Use the address used for
1165 * the control connection instead and restart the port loop
1168 infof(data, "bind(port=%hu) on non-local address failed: %s\n", port,
1169 Curl_strerror(conn, error) );
1172 if(getsockname(conn->sock[FIRSTSOCKET], sa, &sslen)) {
1173 failf(data, "getsockname() failed: %s",
1174 Curl_strerror(conn, SOCKERRNO) );
1175 Curl_closesocket(conn, portsock);
1176 return CURLE_FTP_PORT_FAILED;
1179 possibly_non_local = FALSE; /* don't try this again */
1182 else if(error != EADDRINUSE && error != EACCES) {
1183 failf(data, "bind(port=%hu) failed: %s", port,
1184 Curl_strerror(conn, error) );
1185 Curl_closesocket(conn, portsock);
1186 return CURLE_FTP_PORT_FAILED;
1195 /* maybe all ports were in use already*/
1196 if(port > port_max) {
1197 failf(data, "bind() failed, we ran out of ports!");
1198 Curl_closesocket(conn, portsock);
1199 return CURLE_FTP_PORT_FAILED;
1202 /* get the name again after the bind() so that we can extract the
1203 port number it uses now */
1205 if(getsockname(portsock, (struct sockaddr *)sa, &sslen)) {
1206 failf(data, "getsockname() failed: %s",
1207 Curl_strerror(conn, SOCKERRNO) );
1208 Curl_closesocket(conn, portsock);
1209 return CURLE_FTP_PORT_FAILED;
1212 /* step 4, listen on the socket */
1214 if(listen(portsock, 1)) {
1215 failf(data, "socket failure: %s", Curl_strerror(conn, SOCKERRNO));
1216 Curl_closesocket(conn, portsock);
1217 return CURLE_FTP_PORT_FAILED;
1220 /* step 5, send the proper FTP command */
1222 /* get a plain printable version of the numerical address to work with
1224 Curl_printable_address(ai, myhost, sizeof(myhost));
1227 if(!conn->bits.ftp_use_eprt && conn->bits.ipv6)
1228 /* EPRT is disabled but we are connected to a IPv6 host, so we ignore the
1229 request and enable EPRT again! */
1230 conn->bits.ftp_use_eprt = TRUE;
1233 for(; fcmd != DONE; fcmd++) {
1235 if(!conn->bits.ftp_use_eprt && (EPRT == fcmd))
1236 /* if disabled, goto next */
1239 if((PORT == fcmd) && sa->sa_family != AF_INET)
1240 /* PORT is ipv4 only */
1243 switch (sa->sa_family) {
1245 port = ntohs(sa4->sin_port);
1249 port = ntohs(sa6->sin6_port);
1253 continue; /* might as well skip this */
1258 * Two fine examples from RFC2428;
1260 * EPRT |1|132.235.1.2|6275|
1262 * EPRT |2|1080::8:800:200C:417A|5282|
1265 result = Curl_pp_sendf(&ftpc->pp, "%s |%d|%s|%hu|", mode[fcmd],
1266 sa->sa_family == AF_INET?1:2,
1269 failf(data, "Failure sending EPRT command: %s",
1270 curl_easy_strerror(result));
1271 Curl_closesocket(conn, portsock);
1272 /* don't retry using PORT */
1273 ftpc->count1 = PORT;
1275 state(conn, FTP_STOP);
1280 else if(PORT == fcmd) {
1281 char *source = myhost;
1284 /* translate x.x.x.x to x,x,x,x */
1285 while(source && *source) {
1294 snprintf(dest, 20, ",%d,%d", (int)(port>>8), (int)(port&0xff));
1296 result = Curl_pp_sendf(&ftpc->pp, "%s %s", mode[fcmd], tmp);
1298 failf(data, "Failure sending PORT command: %s",
1299 curl_easy_strerror(result));
1300 Curl_closesocket(conn, portsock);
1302 state(conn, FTP_STOP);
1309 /* store which command was sent */
1310 ftpc->count1 = fcmd;
1312 /* we set the secondary socket variable to this for now, it is only so that
1313 the cleanup function will close it in case we fail before the true
1314 secondary stuff is made */
1315 if(CURL_SOCKET_BAD != conn->sock[SECONDARYSOCKET])
1316 Curl_closesocket(conn, conn->sock[SECONDARYSOCKET]);
1317 conn->sock[SECONDARYSOCKET] = portsock;
1319 /* this tcpconnect assignment below is a hackish work-around to make the
1320 multi interface with active FTP work - as it will not wait for a
1321 (passive) connect in Curl_is_connected().
1323 The *proper* fix is to make sure that the active connection from the
1324 server is done in a non-blocking way. Currently, it is still BLOCKING.
1326 conn->bits.tcpconnect[SECONDARYSOCKET] = TRUE;
1328 state(conn, FTP_PORT);
1332 static CURLcode ftp_state_use_pasv(struct connectdata *conn)
1334 struct ftp_conn *ftpc = &conn->proto.ftpc;
1335 CURLcode result = CURLE_OK;
1337 Here's the excecutive summary on what to do:
1339 PASV is RFC959, expect:
1340 227 Entering Passive Mode (a1,a2,a3,a4,p1,p2)
1342 LPSV is RFC1639, expect:
1343 228 Entering Long Passive Mode (4,4,a1,a2,a3,a4,2,p1,p2)
1345 EPSV is RFC2428, expect:
1346 229 Entering Extended Passive Mode (|||port|)
1350 static const char mode[][5] = { "EPSV", "PASV" };
1354 if(!conn->bits.ftp_use_epsv && conn->bits.ipv6)
1355 /* EPSV is disabled but we are connected to a IPv6 host, so we ignore the
1356 request and enable EPSV again! */
1357 conn->bits.ftp_use_epsv = TRUE;
1360 modeoff = conn->bits.ftp_use_epsv?0:1;
1362 PPSENDF(&ftpc->pp, "%s", mode[modeoff]);
1364 ftpc->count1 = modeoff;
1365 state(conn, FTP_PASV);
1366 infof(conn->data, "Connect data stream passively\n");
1371 /* REST is the last command in the chain of commands when a "head"-like
1372 request is made. Thus, if an actual transfer is to be made this is where
1373 we take off for real. */
1374 static CURLcode ftp_state_post_rest(struct connectdata *conn)
1376 CURLcode result = CURLE_OK;
1377 struct FTP *ftp = conn->data->state.proto.ftp;
1378 struct SessionHandle *data = conn->data;
1380 if(ftp->transfer != FTPTRANSFER_BODY) {
1381 /* doesn't transfer any data */
1383 /* still possibly do PRE QUOTE jobs */
1384 state(conn, FTP_RETR_PREQUOTE);
1385 result = ftp_state_quote(conn, TRUE, FTP_RETR_PREQUOTE);
1387 else if(data->set.ftp_use_port) {
1388 /* We have chosen to use the PORT (or similar) command */
1389 result = ftp_state_use_port(conn, EPRT);
1392 /* We have chosen (this is default) to use the PASV (or similar) command */
1393 if(data->set.ftp_use_pret) {
1394 /* The user has requested that we send a PRET command
1395 to prepare the server for the upcoming PASV */
1396 if(!conn->proto.ftpc.file) {
1397 PPSENDF(&conn->proto.ftpc.pp, "PRET %s",
1398 data->set.str[STRING_CUSTOMREQUEST]?
1399 data->set.str[STRING_CUSTOMREQUEST]:
1400 (data->set.ftp_list_only?"NLST":"LIST"));
1402 else if(data->set.upload) {
1403 PPSENDF(&conn->proto.ftpc.pp, "PRET STOR %s", conn->proto.ftpc.file);
1406 PPSENDF(&conn->proto.ftpc.pp, "PRET RETR %s", conn->proto.ftpc.file);
1408 state(conn, FTP_PRET);
1411 result = ftp_state_use_pasv(conn);
1417 static CURLcode ftp_state_post_size(struct connectdata *conn)
1419 CURLcode result = CURLE_OK;
1420 struct FTP *ftp = conn->data->state.proto.ftp;
1421 struct ftp_conn *ftpc = &conn->proto.ftpc;
1423 if((ftp->transfer != FTPTRANSFER_BODY) && ftpc->file) {
1424 /* if a "head"-like request is being made (on a file) */
1426 /* Determine if server can respond to REST command and therefore
1427 whether it supports range */
1428 PPSENDF(&conn->proto.ftpc.pp, "REST %d", 0);
1430 state(conn, FTP_REST);
1433 result = ftp_state_post_rest(conn);
1438 static CURLcode ftp_state_post_type(struct connectdata *conn)
1440 CURLcode result = CURLE_OK;
1441 struct FTP *ftp = conn->data->state.proto.ftp;
1442 struct ftp_conn *ftpc = &conn->proto.ftpc;
1444 if((ftp->transfer == FTPTRANSFER_INFO) && ftpc->file) {
1445 /* if a "head"-like request is being made (on a file) */
1447 /* we know ftpc->file is a valid pointer to a file name */
1448 PPSENDF(&ftpc->pp, "SIZE %s", ftpc->file);
1450 state(conn, FTP_SIZE);
1453 result = ftp_state_post_size(conn);
1458 static CURLcode ftp_state_post_listtype(struct connectdata *conn)
1460 CURLcode result = CURLE_OK;
1461 struct SessionHandle *data = conn->data;
1463 /* If this output is to be machine-parsed, the NLST command might be better
1464 to use, since the LIST command output is not specified or standard in any
1465 way. It has turned out that the NLST list output is not the same on all
1466 servers either... */
1469 if FTPFILE_NOCWD was specified, we are currently in
1470 the user's home directory, so we should add the path
1471 as argument for the LIST / NLST / or custom command.
1472 Whether the server will support this, is uncertain.
1474 The other ftp_filemethods will CWD into dir/dir/ first and
1475 then just do LIST (in that case: nothing to do here)
1477 char *cmd,*lstArg,*slashPos;
1480 if((data->set.ftp_filemethod == FTPFILE_NOCWD) &&
1482 data->state.path[0] &&
1483 strchr(data->state.path,'/')) {
1485 lstArg = strdup(data->state.path);
1487 return CURLE_OUT_OF_MEMORY;
1489 /* Check if path does not end with /, as then we cut off the file part */
1490 if(lstArg[strlen(lstArg) - 1] != '/') {
1492 /* chop off the file part if format is dir/dir/file */
1493 slashPos = strrchr(lstArg,'/');
1495 *(slashPos+1) = '\0';
1499 cmd = aprintf( "%s%s%s",
1500 data->set.str[STRING_CUSTOMREQUEST]?
1501 data->set.str[STRING_CUSTOMREQUEST]:
1502 (data->set.ftp_list_only?"NLST":"LIST"),
1504 lstArg? lstArg: "" );
1509 return CURLE_OUT_OF_MEMORY;
1512 result = Curl_pp_sendf(&conn->proto.ftpc.pp, "%s", cmd);
1519 if(result != CURLE_OK)
1522 state(conn, FTP_LIST);
1527 static CURLcode ftp_state_post_retrtype(struct connectdata *conn)
1529 CURLcode result = CURLE_OK;
1531 /* We've sent the TYPE, now we must send the list of prequote strings */
1533 result = ftp_state_quote(conn, TRUE, FTP_RETR_PREQUOTE);
1538 static CURLcode ftp_state_post_stortype(struct connectdata *conn)
1540 CURLcode result = CURLE_OK;
1542 /* We've sent the TYPE, now we must send the list of prequote strings */
1544 result = ftp_state_quote(conn, TRUE, FTP_STOR_PREQUOTE);
1549 static CURLcode ftp_state_post_mdtm(struct connectdata *conn)
1551 CURLcode result = CURLE_OK;
1552 struct FTP *ftp = conn->data->state.proto.ftp;
1553 struct SessionHandle *data = conn->data;
1554 struct ftp_conn *ftpc = &conn->proto.ftpc;
1556 /* If we have selected NOBODY and HEADER, it means that we only want file
1557 information. Which in FTP can't be much more than the file size and
1559 if(data->set.opt_no_body && ftpc->file &&
1560 ftp_need_type(conn, data->set.prefer_ascii)) {
1561 /* The SIZE command is _not_ RFC 959 specified, and therefor many servers
1562 may not support it! It is however the only way we have to get a file's
1565 ftp->transfer = FTPTRANSFER_INFO;
1566 /* this means no actual transfer will be made */
1568 /* Some servers return different sizes for different modes, and thus we
1569 must set the proper type before we check the size */
1570 result = ftp_nb_type(conn, data->set.prefer_ascii, FTP_TYPE);
1575 result = ftp_state_post_type(conn);
1580 /* This is called after the CWD commands have been done in the beginning of
1582 static CURLcode ftp_state_post_cwd(struct connectdata *conn)
1584 CURLcode result = CURLE_OK;
1585 struct SessionHandle *data = conn->data;
1586 struct ftp_conn *ftpc = &conn->proto.ftpc;
1588 /* Requested time of file or time-depended transfer? */
1589 if((data->set.get_filetime || data->set.timecondition) && ftpc->file) {
1591 /* we have requested to get the modified-time of the file, this is a white
1592 spot as the MDTM is not mentioned in RFC959 */
1593 PPSENDF(&ftpc->pp, "MDTM %s", ftpc->file);
1595 state(conn, FTP_MDTM);
1598 result = ftp_state_post_mdtm(conn);
1604 /* This is called after the TYPE and possible quote commands have been sent */
1605 static CURLcode ftp_state_ul_setup(struct connectdata *conn,
1608 CURLcode result = CURLE_OK;
1609 struct FTP *ftp = conn->data->state.proto.ftp;
1610 struct SessionHandle *data = conn->data;
1611 struct ftp_conn *ftpc = &conn->proto.ftpc;
1612 int seekerr = CURL_SEEKFUNC_OK;
1614 if((data->state.resume_from && !sizechecked) ||
1615 ((data->state.resume_from > 0) && sizechecked)) {
1616 /* we're about to continue the uploading of a file */
1617 /* 1. get already existing file's size. We use the SIZE command for this
1618 which may not exist in the server! The SIZE command is not in
1621 /* 2. This used to set REST. But since we can do append, we
1622 don't another ftp command. We just skip the source file
1623 offset and then we APPEND the rest on the file instead */
1625 /* 3. pass file-size number of bytes in the source file */
1626 /* 4. lower the infilesize counter */
1627 /* => transfer as usual */
1629 if(data->state.resume_from < 0 ) {
1630 /* Got no given size to start from, figure it out */
1631 PPSENDF(&ftpc->pp, "SIZE %s", ftpc->file);
1632 state(conn, FTP_STOR_SIZE);
1637 data->set.ftp_append = TRUE;
1639 /* Let's read off the proper amount of bytes from the input. */
1640 if(conn->seek_func) {
1641 seekerr = conn->seek_func(conn->seek_client, data->state.resume_from,
1645 if(seekerr != CURL_SEEKFUNC_OK) {
1646 if(seekerr != CURL_SEEKFUNC_CANTSEEK) {
1647 failf(data, "Could not seek stream");
1648 return CURLE_FTP_COULDNT_USE_REST;
1650 /* seekerr == CURL_SEEKFUNC_CANTSEEK (can't seek to offset) */
1652 curl_off_t passed=0;
1654 size_t readthisamountnow =
1655 (data->state.resume_from - passed > CURL_OFF_T_C(BUFSIZE)) ?
1656 BUFSIZE : curlx_sotouz(data->state.resume_from - passed);
1658 size_t actuallyread =
1659 conn->fread_func(data->state.buffer, 1, readthisamountnow,
1662 passed += actuallyread;
1663 if((actuallyread == 0) || (actuallyread > readthisamountnow)) {
1664 /* this checks for greater-than only to make sure that the
1665 CURL_READFUNC_ABORT return code still aborts */
1666 failf(data, "Failed to read data");
1667 return CURLE_FTP_COULDNT_USE_REST;
1669 } while(passed < data->state.resume_from);
1672 /* now, decrease the size of the read */
1673 if(data->set.infilesize>0) {
1674 data->set.infilesize -= data->state.resume_from;
1676 if(data->set.infilesize <= 0) {
1677 infof(data, "File already completely uploaded\n");
1679 /* no data to transfer */
1680 Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
1682 /* Set ->transfer so that we won't get any error in
1683 * ftp_done() because we didn't transfer anything! */
1684 ftp->transfer = FTPTRANSFER_NONE;
1686 state(conn, FTP_STOP);
1690 /* we've passed, proceed as normal */
1693 PPSENDF(&ftpc->pp, data->set.ftp_append?"APPE %s":"STOR %s",
1696 state(conn, FTP_STOR);
1701 static CURLcode ftp_state_quote(struct connectdata *conn,
1705 CURLcode result = CURLE_OK;
1706 struct SessionHandle *data = conn->data;
1707 struct FTP *ftp = data->state.proto.ftp;
1708 struct ftp_conn *ftpc = &conn->proto.ftpc;
1710 struct curl_slist *item;
1715 item = data->set.quote;
1717 case FTP_RETR_PREQUOTE:
1718 case FTP_STOR_PREQUOTE:
1719 item = data->set.prequote;
1722 item = data->set.postquote;
1728 * 'count1' to iterate over the commands to send
1729 * 'count2' to store wether to allow commands to fail
1740 /* Skip count1 items in the linked list */
1741 while((i< ftpc->count1) && item) {
1746 char *cmd = item->data;
1749 ftpc->count2 = 1; /* the sent command is allowed to fail */
1752 ftpc->count2 = 0; /* failure means cancel operation */
1754 PPSENDF(&ftpc->pp, "%s", cmd);
1755 state(conn, instate);
1761 /* No more quote to send, continue to ... */
1765 result = ftp_state_cwd(conn);
1767 case FTP_RETR_PREQUOTE:
1768 if(ftp->transfer != FTPTRANSFER_BODY)
1769 state(conn, FTP_STOP);
1771 if(ftpc->known_filesize != -1) {
1772 Curl_pgrsSetDownloadSize(data, ftpc->known_filesize);
1773 result = ftp_state_post_retr_size(conn, ftpc->known_filesize);
1776 PPSENDF(&ftpc->pp, "SIZE %s", ftpc->file);
1777 state(conn, FTP_RETR_SIZE);
1781 case FTP_STOR_PREQUOTE:
1782 result = ftp_state_ul_setup(conn, FALSE);
1792 /* called from ftp_state_pasv_resp to switch to PASV in case of EPSV
1794 static CURLcode ftp_epsv_disable(struct connectdata *conn)
1796 CURLcode result = CURLE_OK;
1797 infof(conn->data, "got positive EPSV response, but can't connect. "
1798 "Disabling EPSV\n");
1799 /* disable it for next transfer */
1800 conn->bits.ftp_use_epsv = FALSE;
1801 conn->data->state.errorbuf = FALSE; /* allow error message to get
1803 PPSENDF(&conn->proto.ftpc.pp, "PASV", NULL);
1804 conn->proto.ftpc.count1++;
1805 /* remain in the FTP_PASV state */
1809 static CURLcode ftp_state_pasv_resp(struct connectdata *conn,
1812 struct ftp_conn *ftpc = &conn->proto.ftpc;
1814 struct SessionHandle *data=conn->data;
1815 Curl_addrinfo *conninfo;
1816 struct Curl_dns_entry *addr=NULL;
1818 unsigned short connectport; /* the local port connect() should use! */
1819 unsigned short newport=0; /* remote port */
1822 /* newhost must be able to hold a full IP-style address in ASCII, which
1823 in the IPv6 case means 5*8-1 = 39 letters */
1824 #define NEWHOST_BUFSIZE 48
1825 char newhost[NEWHOST_BUFSIZE];
1826 char *str=&data->state.buffer[4]; /* start on the first letter */
1828 if((ftpc->count1 == 0) &&
1830 /* positive EPSV response */
1831 char *ptr = strchr(str, '(');
1836 if(5 == sscanf(ptr, "%c%c%c%u%c",
1842 const char sep1 = separator[0];
1845 /* The four separators should be identical, or else this is an oddly
1846 formatted reply and we bail out immediately. */
1847 for(i=1; i<4; i++) {
1848 if(separator[i] != sep1) {
1849 ptr=NULL; /* set to NULL to signal error */
1854 failf(data, "Illegal port number in EPSV reply");
1855 return CURLE_FTP_WEIRD_PASV_REPLY;
1858 newport = (unsigned short)(num & 0xffff);
1860 if(conn->bits.tunnel_proxy ||
1861 conn->proxytype == CURLPROXY_SOCKS5 ||
1862 conn->proxytype == CURLPROXY_SOCKS5_HOSTNAME ||
1863 conn->proxytype == CURLPROXY_SOCKS4 ||
1864 conn->proxytype == CURLPROXY_SOCKS4A)
1865 /* proxy tunnel -> use other host info because ip_addr_str is the
1866 proxy address not the ftp host */
1867 snprintf(newhost, sizeof(newhost), "%s", conn->host.name);
1869 /* use the same IP we are already connected to */
1870 snprintf(newhost, NEWHOST_BUFSIZE, "%s", conn->ip_addr_str);
1877 failf(data, "Weirdly formatted EPSV reply");
1878 return CURLE_FTP_WEIRD_PASV_REPLY;
1881 else if((ftpc->count1 == 1) &&
1883 /* positive PASV response */
1888 * Scan for a sequence of six comma-separated numbers and use them as
1889 * IP+port indicators.
1891 * Found reply-strings include:
1892 * "227 Entering Passive Mode (127,0,0,1,4,51)"
1893 * "227 Data transfer will passively listen to 127,0,0,1,4,51"
1894 * "227 Entering passive mode. 127,0,0,1,4,51"
1897 if(6 == sscanf(str, "%d,%d,%d,%d,%d,%d",
1898 &ip[0], &ip[1], &ip[2], &ip[3],
1899 &port[0], &port[1]))
1905 failf(data, "Couldn't interpret the 227-response");
1906 return CURLE_FTP_WEIRD_227_FORMAT;
1909 /* we got OK from server */
1910 if(data->set.ftp_skip_ip) {
1911 /* told to ignore the remotely given IP but instead use the one we used
1912 for the control connection */
1913 infof(data, "Skips %d.%d.%d.%d for data connection, uses %s instead\n",
1914 ip[0], ip[1], ip[2], ip[3],
1916 if(conn->bits.tunnel_proxy ||
1917 conn->proxytype == CURLPROXY_SOCKS5 ||
1918 conn->proxytype == CURLPROXY_SOCKS5_HOSTNAME ||
1919 conn->proxytype == CURLPROXY_SOCKS4 ||
1920 conn->proxytype == CURLPROXY_SOCKS4A)
1921 /* proxy tunnel -> use other host info because ip_addr_str is the
1922 proxy address not the ftp host */
1923 snprintf(newhost, sizeof(newhost), "%s", conn->host.name);
1925 snprintf(newhost, sizeof(newhost), "%s", conn->ip_addr_str);
1928 snprintf(newhost, sizeof(newhost),
1929 "%d.%d.%d.%d", ip[0], ip[1], ip[2], ip[3]);
1930 newport = (unsigned short)(((port[0]<<8) + port[1]) & 0xffff);
1932 else if(ftpc->count1 == 0) {
1933 /* EPSV failed, move on to PASV */
1935 /* disable it for next transfer */
1936 conn->bits.ftp_use_epsv = FALSE;
1937 infof(data, "disabling EPSV usage\n");
1939 PPSENDF(&ftpc->pp, "PASV", NULL);
1941 /* remain in the FTP_PASV state */
1945 failf(data, "Bad PASV/EPSV response: %03d", ftpcode);
1946 return CURLE_FTP_WEIRD_PASV_REPLY;
1949 if(data->set.str[STRING_PROXY] && *data->set.str[STRING_PROXY]) {
1951 * This is a tunnel through a http proxy and we need to connect to the
1954 * We don't want to rely on a former host lookup that might've expired
1955 * now, instead we remake the lookup here and now!
1957 rc = Curl_resolv(conn, conn->proxy.name, (int)conn->port, &addr);
1958 if(rc == CURLRESOLV_PENDING)
1959 /* BLOCKING, ignores the return code but 'addr' will be NULL in
1961 (void)Curl_resolver_wait_resolv(conn, &addr);
1964 (unsigned short)conn->port; /* we connect to the proxy's port */
1967 failf(data, "Can't resolve proxy host %s:%hu",
1968 conn->proxy.name, connectport);
1969 return CURLE_FTP_CANT_GET_HOST;
1973 /* normal, direct, ftp connection */
1974 rc = Curl_resolv(conn, newhost, newport, &addr);
1975 if(rc == CURLRESOLV_PENDING)
1977 (void)Curl_resolver_wait_resolv(conn, &addr);
1979 connectport = newport; /* we connect to the remote port */
1982 failf(data, "Can't resolve new host %s:%hu", newhost, connectport);
1983 return CURLE_FTP_CANT_GET_HOST;
1987 result = Curl_connecthost(conn,
1989 &conn->sock[SECONDARYSOCKET],
1993 Curl_resolv_unlock(data, addr); /* we're done using this address */
1996 if(ftpc->count1 == 0 && ftpcode == 229)
1997 return ftp_epsv_disable(conn);
2002 conn->bits.tcpconnect[SECONDARYSOCKET] = connected;
2005 * When this is used from the multi interface, this might've returned with
2006 * the 'connected' set to FALSE and thus we are now awaiting a non-blocking
2007 * connect to connect and we should not be "hanging" here waiting.
2010 if(data->set.verbose)
2011 /* this just dumps information about this second connection */
2012 ftp_pasv_verbose(conn, conninfo, newhost, connectport);
2014 switch(conn->proxytype) {
2015 /* FIX: this MUST wait for a proper connect first if 'connected' is
2017 case CURLPROXY_SOCKS5:
2018 case CURLPROXY_SOCKS5_HOSTNAME:
2019 result = Curl_SOCKS5(conn->proxyuser, conn->proxypasswd, newhost, newport,
2020 SECONDARYSOCKET, conn);
2022 case CURLPROXY_SOCKS4:
2023 result = Curl_SOCKS4(conn->proxyuser, newhost, newport,
2024 SECONDARYSOCKET, conn, FALSE);
2026 case CURLPROXY_SOCKS4A:
2027 result = Curl_SOCKS4(conn->proxyuser, newhost, newport,
2028 SECONDARYSOCKET, conn, TRUE);
2030 case CURLPROXY_HTTP:
2031 case CURLPROXY_HTTP_1_0:
2032 /* do nothing here. handled later. */
2035 failf(data, "unknown proxytype option given");
2036 result = CURLE_COULDNT_CONNECT;
2041 if(ftpc->count1 == 0 && ftpcode == 229)
2042 return ftp_epsv_disable(conn);
2046 if(conn->bits.tunnel_proxy && conn->bits.httpproxy) {
2047 /* FIX: this MUST wait for a proper connect first if 'connected' is
2051 /* We want "seamless" FTP operations through HTTP proxy tunnel */
2053 /* Curl_proxyCONNECT is based on a pointer to a struct HTTP at the member
2054 * conn->proto.http; we want FTP through HTTP and we have to change the
2055 * member temporarily for connecting to the HTTP proxy. After
2056 * Curl_proxyCONNECT we have to set back the member to the original struct
2059 struct HTTP http_proxy;
2060 struct FTP *ftp_save = data->state.proto.ftp;
2061 memset(&http_proxy, 0, sizeof(http_proxy));
2062 data->state.proto.http = &http_proxy;
2064 result = Curl_proxyCONNECT(conn, SECONDARYSOCKET, newhost, newport);
2066 data->state.proto.ftp = ftp_save;
2071 if(conn->tunnel_state[SECONDARYSOCKET] != TUNNEL_COMPLETE) {
2072 /* the CONNECT procedure is not complete, the tunnel is not yet up */
2073 state(conn, FTP_STOP); /* this phase is completed */
2074 conn->bits.tcpconnect[SECONDARYSOCKET] = FALSE;
2080 conn->bits.tcpconnect[SECONDARYSOCKET] = TRUE;
2082 conn->bits.do_more = TRUE;
2083 state(conn, FTP_STOP); /* this phase is completed */
2088 static CURLcode ftp_state_port_resp(struct connectdata *conn,
2091 struct SessionHandle *data = conn->data;
2092 struct ftp_conn *ftpc = &conn->proto.ftpc;
2093 ftpport fcmd = (ftpport)ftpc->count1;
2094 CURLcode result = CURLE_OK;
2096 if(ftpcode != 200) {
2097 /* the command failed */
2100 infof(data, "disabling EPRT usage\n");
2101 conn->bits.ftp_use_eprt = FALSE;
2106 failf(data, "Failed to do PORT");
2107 result = CURLE_FTP_PORT_FAILED;
2111 result = ftp_state_use_port(conn, fcmd);
2114 infof(data, "Connect data stream actively\n");
2115 state(conn, FTP_STOP); /* end of DO phase */
2116 result = ftp_dophase_done(conn, FALSE);
2122 static CURLcode ftp_state_mdtm_resp(struct connectdata *conn,
2125 CURLcode result = CURLE_OK;
2126 struct SessionHandle *data=conn->data;
2127 struct FTP *ftp = data->state.proto.ftp;
2128 struct ftp_conn *ftpc = &conn->proto.ftpc;
2133 /* we got a time. Format should be: "YYYYMMDDHHMMSS[.sss]" where the
2134 last .sss part is optional and means fractions of a second */
2135 int year, month, day, hour, minute, second;
2136 char *buf = data->state.buffer;
2137 if(6 == sscanf(buf+4, "%04d%02d%02d%02d%02d%02d",
2138 &year, &month, &day, &hour, &minute, &second)) {
2139 /* we have a time, reformat it */
2140 time_t secs=time(NULL);
2141 /* using the good old yacc/bison yuck */
2142 snprintf(buf, sizeof(conn->data->state.buffer),
2143 "%04d%02d%02d %02d:%02d:%02d GMT",
2144 year, month, day, hour, minute, second);
2145 /* now, convert this into a time() value: */
2146 data->info.filetime = (long)curl_getdate(buf, &secs);
2149 #ifdef CURL_FTP_HTTPSTYLE_HEAD
2150 /* If we asked for a time of the file and we actually got one as well,
2151 we "emulate" a HTTP-style header in our output. */
2153 if(data->set.opt_no_body &&
2155 data->set.get_filetime &&
2156 (data->info.filetime>=0) ) {
2157 time_t filetime = (time_t)data->info.filetime;
2159 const struct tm *tm = &buffer;
2161 result = Curl_gmtime(filetime, &buffer);
2165 /* format: "Tue, 15 Nov 1994 12:45:26" */
2166 snprintf(buf, BUFSIZE-1,
2167 "Last-Modified: %s, %02d %s %4d %02d:%02d:%02d GMT\r\n",
2168 Curl_wkday[tm->tm_wday?tm->tm_wday-1:6],
2170 Curl_month[tm->tm_mon],
2175 result = Curl_client_write(conn, CLIENTWRITE_BOTH, buf, 0);
2178 } /* end of a ridiculous amount of conditionals */
2183 infof(data, "unsupported MDTM reply format\n");
2185 case 550: /* "No such file or directory" */
2186 failf(data, "Given file does not exist");
2187 result = CURLE_FTP_COULDNT_RETR_FILE;
2191 if(data->set.timecondition) {
2192 if((data->info.filetime > 0) && (data->set.timevalue > 0)) {
2193 switch(data->set.timecondition) {
2194 case CURL_TIMECOND_IFMODSINCE:
2196 if(data->info.filetime <= data->set.timevalue) {
2197 infof(data, "The requested document is not new enough\n");
2198 ftp->transfer = FTPTRANSFER_NONE; /* mark to not transfer data */
2199 data->info.timecond = TRUE;
2200 state(conn, FTP_STOP);
2204 case CURL_TIMECOND_IFUNMODSINCE:
2205 if(data->info.filetime > data->set.timevalue) {
2206 infof(data, "The requested document is not old enough\n");
2207 ftp->transfer = FTPTRANSFER_NONE; /* mark to not transfer data */
2208 data->info.timecond = TRUE;
2209 state(conn, FTP_STOP);
2216 infof(data, "Skipping time comparison\n");
2221 result = ftp_state_post_mdtm(conn);
2226 static CURLcode ftp_state_type_resp(struct connectdata *conn,
2230 CURLcode result = CURLE_OK;
2231 struct SessionHandle *data=conn->data;
2233 if(ftpcode/100 != 2) {
2234 /* "sasserftpd" and "(u)r(x)bot ftpd" both responds with 226 after a
2235 successful 'TYPE I'. While that is not as RFC959 says, it is still a
2236 positive response code and we allow that. */
2237 failf(data, "Couldn't set desired mode");
2238 return CURLE_FTP_COULDNT_SET_TYPE;
2241 infof(data, "Got a %03d response code instead of the assumed 200\n",
2244 if(instate == FTP_TYPE)
2245 result = ftp_state_post_type(conn);
2246 else if(instate == FTP_LIST_TYPE)
2247 result = ftp_state_post_listtype(conn);
2248 else if(instate == FTP_RETR_TYPE)
2249 result = ftp_state_post_retrtype(conn);
2250 else if(instate == FTP_STOR_TYPE)
2251 result = ftp_state_post_stortype(conn);
2256 static CURLcode ftp_state_post_retr_size(struct connectdata *conn,
2257 curl_off_t filesize)
2259 CURLcode result = CURLE_OK;
2260 struct SessionHandle *data=conn->data;
2261 struct FTP *ftp = data->state.proto.ftp;
2262 struct ftp_conn *ftpc = &conn->proto.ftpc;
2264 if(data->set.max_filesize && (filesize > data->set.max_filesize)) {
2265 failf(data, "Maximum file size exceeded");
2266 return CURLE_FILESIZE_EXCEEDED;
2268 ftp->downloadsize = filesize;
2270 if(data->state.resume_from) {
2271 /* We always (attempt to) get the size of downloads, so it is done before
2272 this even when not doing resumes. */
2273 if(filesize == -1) {
2274 infof(data, "ftp server doesn't support SIZE\n");
2275 /* We couldn't get the size and therefore we can't know if there really
2276 is a part of the file left to get, although the server will just
2277 close the connection when we start the connection so it won't cause
2278 us any harm, just not make us exit as nicely. */
2281 /* We got a file size report, so we check that there actually is a
2282 part of the file left to get, or else we go home. */
2283 if(data->state.resume_from< 0) {
2284 /* We're supposed to download the last abs(from) bytes */
2285 if(filesize < -data->state.resume_from) {
2286 failf(data, "Offset (%" FORMAT_OFF_T
2287 ") was beyond file size (%" FORMAT_OFF_T ")",
2288 data->state.resume_from, filesize);
2289 return CURLE_BAD_DOWNLOAD_RESUME;
2291 /* convert to size to download */
2292 ftp->downloadsize = -data->state.resume_from;
2293 /* download from where? */
2294 data->state.resume_from = filesize - ftp->downloadsize;
2297 if(filesize < data->state.resume_from) {
2298 failf(data, "Offset (%" FORMAT_OFF_T
2299 ") was beyond file size (%" FORMAT_OFF_T ")",
2300 data->state.resume_from, filesize);
2301 return CURLE_BAD_DOWNLOAD_RESUME;
2303 /* Now store the number of bytes we are expected to download */
2304 ftp->downloadsize = filesize-data->state.resume_from;
2308 if(ftp->downloadsize == 0) {
2309 /* no data to transfer */
2310 Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
2311 infof(data, "File already completely downloaded\n");
2313 /* Set ->transfer so that we won't get any error in ftp_done()
2314 * because we didn't transfer the any file */
2315 ftp->transfer = FTPTRANSFER_NONE;
2316 state(conn, FTP_STOP);
2320 /* Set resume file transfer offset */
2321 infof(data, "Instructs server to resume from offset %" FORMAT_OFF_T
2322 "\n", data->state.resume_from);
2324 PPSENDF(&ftpc->pp, "REST %" FORMAT_OFF_T, data->state.resume_from);
2326 state(conn, FTP_RETR_REST);
2331 PPSENDF(&ftpc->pp, "RETR %s", ftpc->file);
2332 state(conn, FTP_RETR);
2338 static CURLcode ftp_state_size_resp(struct connectdata *conn,
2342 CURLcode result = CURLE_OK;
2343 struct SessionHandle *data=conn->data;
2344 curl_off_t filesize;
2345 char *buf = data->state.buffer;
2347 /* get the size from the ascii string: */
2348 filesize = (ftpcode == 213)?curlx_strtoofft(buf+4, NULL, 0):-1;
2350 if(instate == FTP_SIZE) {
2351 #ifdef CURL_FTP_HTTPSTYLE_HEAD
2352 if(-1 != filesize) {
2353 snprintf(buf, sizeof(data->state.buffer),
2354 "Content-Length: %" FORMAT_OFF_T "\r\n", filesize);
2355 result = Curl_client_write(conn, CLIENTWRITE_BOTH, buf, 0);
2360 Curl_pgrsSetDownloadSize(data, filesize);
2361 result = ftp_state_post_size(conn);
2363 else if(instate == FTP_RETR_SIZE) {
2364 Curl_pgrsSetDownloadSize(data, filesize);
2365 result = ftp_state_post_retr_size(conn, filesize);
2367 else if(instate == FTP_STOR_SIZE) {
2368 data->state.resume_from = filesize;
2369 result = ftp_state_ul_setup(conn, TRUE);
2375 static CURLcode ftp_state_rest_resp(struct connectdata *conn,
2379 CURLcode result = CURLE_OK;
2380 struct ftp_conn *ftpc = &conn->proto.ftpc;
2385 #ifdef CURL_FTP_HTTPSTYLE_HEAD
2386 if(ftpcode == 350) {
2387 char buffer[24]= { "Accept-ranges: bytes\r\n" };
2388 result = Curl_client_write(conn, CLIENTWRITE_BOTH, buffer, 0);
2393 result = ftp_state_post_rest(conn);
2397 if(ftpcode != 350) {
2398 failf(conn->data, "Couldn't use REST");
2399 result = CURLE_FTP_COULDNT_USE_REST;
2402 PPSENDF(&ftpc->pp, "RETR %s", ftpc->file);
2403 state(conn, FTP_RETR);
2411 static CURLcode ftp_state_stor_resp(struct connectdata *conn,
2412 int ftpcode, ftpstate instate)
2414 CURLcode result = CURLE_OK;
2415 struct SessionHandle *data = conn->data;
2418 failf(data, "Failed FTP upload: %0d", ftpcode);
2419 state(conn, FTP_STOP);
2420 /* oops, we never close the sockets! */
2421 return CURLE_UPLOAD_FAILED;
2424 conn->proto.ftpc.state_saved = instate;
2426 /* PORT means we are now awaiting the server to connect to us. */
2427 if(data->set.ftp_use_port) {
2430 result = AllowServerConnect(conn, &connected);
2435 struct ftp_conn *ftpc = &conn->proto.ftpc;
2436 infof(data, "Data conn was not available immediately\n");
2437 ftpc->wait_data_conn = TRUE;
2443 return InitiateTransfer(conn);
2446 /* for LIST and RETR responses */
2447 static CURLcode ftp_state_get_resp(struct connectdata *conn,
2451 CURLcode result = CURLE_OK;
2452 struct SessionHandle *data = conn->data;
2453 struct FTP *ftp = data->state.proto.ftp;
2454 char *buf = data->state.buffer;
2456 if((ftpcode == 150) || (ftpcode == 125)) {
2460 150 Opening BINARY mode data connection for /etc/passwd (2241
2461 bytes). (ok, the file is being transferred)
2464 150 Opening ASCII mode data connection for /bin/ls
2467 150 ASCII data connection for /bin/ls (137.167.104.91,37445) (0 bytes).
2470 150 Opening ASCII mode data connection for [file] (0.0.0.0,0) (545 bytes)
2473 125 Data connection already open; Transfer starting. */
2475 curl_off_t size=-1; /* default unknown size */
2479 * It appears that there are FTP-servers that return size 0 for files when
2480 * SIZE is used on the file while being in BINARY mode. To work around
2481 * that (stupid) behavior, we attempt to parse the RETR response even if
2482 * the SIZE returned size zero.
2484 * Debugging help from Salvatore Sorrentino on February 26, 2003.
2487 if((instate != FTP_LIST) &&
2488 !data->set.prefer_ascii &&
2489 (ftp->downloadsize < 1)) {
2491 * It seems directory listings either don't show the size or very
2492 * often uses size 0 anyway. ASCII transfers may very well turn out
2493 * that the transferred amount of data is not the same as this line
2494 * tells, why using this number in those cases only confuses us.
2496 * Example D above makes this parsing a little tricky */
2498 bytes=strstr(buf, " bytes");
2500 long in=(long)(bytes-buf);
2501 /* this is a hint there is size information in there! ;-) */
2503 /* scan for the left parenthesis and break there */
2506 /* skip only digits */
2507 if(!ISDIGIT(*bytes)) {
2511 /* one more estep backwards */
2514 /* if we have nothing but digits: */
2516 /* get the number! */
2517 size = curlx_strtoofft(bytes, NULL, 0);
2521 else if(ftp->downloadsize > -1)
2522 size = ftp->downloadsize;
2524 if(size > data->req.maxdownload && data->req.maxdownload > 0)
2525 size = data->req.size = data->req.maxdownload;
2526 else if((instate != FTP_LIST) && (data->set.prefer_ascii))
2527 size = -1; /* kludge for servers that understate ASCII mode file size */
2529 infof(data, "Maxdownload = %" FORMAT_OFF_T "\n", data->req.maxdownload);
2531 if(instate != FTP_LIST)
2532 infof(data, "Getting file with size: %" FORMAT_OFF_T "\n", size);
2535 conn->proto.ftpc.state_saved = instate;
2536 conn->proto.ftpc.retr_size_saved = size;
2538 if(data->set.ftp_use_port) {
2541 result = AllowServerConnect(conn, &connected);
2546 struct ftp_conn *ftpc = &conn->proto.ftpc;
2547 infof(data, "Data conn was not available immediately\n");
2548 state(conn, FTP_STOP);
2549 ftpc->wait_data_conn = TRUE;
2553 return InitiateTransfer(conn);
2556 if((instate == FTP_LIST) && (ftpcode == 450)) {
2557 /* simply no matching files in the dir listing */
2558 ftp->transfer = FTPTRANSFER_NONE; /* don't download anything */
2559 state(conn, FTP_STOP); /* this phase is over */
2562 failf(data, "RETR response: %03d", ftpcode);
2563 return instate == FTP_RETR && ftpcode == 550?
2564 CURLE_REMOTE_FILE_NOT_FOUND:
2565 CURLE_FTP_COULDNT_RETR_FILE;
2572 /* after USER, PASS and ACCT */
2573 static CURLcode ftp_state_loggedin(struct connectdata *conn)
2575 CURLcode result = CURLE_OK;
2578 if(conn->data->set.krb) {
2579 /* We may need to issue a KAUTH here to have access to the files
2580 * do it if user supplied a password
2582 if(conn->passwd && *conn->passwd) {
2584 result = Curl_krb_kauth(conn);
2590 if(conn->ssl[FIRSTSOCKET].use) {
2591 /* PBSZ = PROTECTION BUFFER SIZE.
2593 The 'draft-murray-auth-ftp-ssl' (draft 12, page 7) says:
2595 Specifically, the PROT command MUST be preceded by a PBSZ
2596 command and a PBSZ command MUST be preceded by a successful
2597 security data exchange (the TLS negotiation in this case)
2599 ... (and on page 8):
2601 Thus the PBSZ command must still be issued, but must have a
2602 parameter of '0' to indicate that no buffering is taking place
2603 and the data connection should not be encapsulated.
2605 PPSENDF(&conn->proto.ftpc.pp, "PBSZ %d", 0);
2606 state(conn, FTP_PBSZ);
2609 result = ftp_state_pwd(conn);
2614 /* for USER and PASS responses */
2615 static CURLcode ftp_state_user_resp(struct connectdata *conn,
2619 CURLcode result = CURLE_OK;
2620 struct SessionHandle *data = conn->data;
2621 struct FTP *ftp = data->state.proto.ftp;
2622 struct ftp_conn *ftpc = &conn->proto.ftpc;
2623 (void)instate; /* no use for this yet */
2625 /* some need password anyway, and others just return 2xx ignored */
2626 if((ftpcode == 331) && (ftpc->state == FTP_USER)) {
2627 /* 331 Password required for ...
2628 (the server requires to send the user's password too) */
2629 PPSENDF(&ftpc->pp, "PASS %s", ftp->passwd?ftp->passwd:"");
2630 state(conn, FTP_PASS);
2632 else if(ftpcode/100 == 2) {
2633 /* 230 User ... logged in.
2634 (the user logged in with or without password) */
2635 result = ftp_state_loggedin(conn);
2637 else if(ftpcode == 332) {
2638 if(data->set.str[STRING_FTP_ACCOUNT]) {
2639 PPSENDF(&ftpc->pp, "ACCT %s", data->set.str[STRING_FTP_ACCOUNT]);
2640 state(conn, FTP_ACCT);
2643 failf(data, "ACCT requested but none available");
2644 result = CURLE_LOGIN_DENIED;
2648 /* All other response codes, like:
2650 530 User ... access denied
2651 (the server denies to log the specified user) */
2653 if(conn->data->set.str[STRING_FTP_ALTERNATIVE_TO_USER] &&
2654 !conn->data->state.ftp_trying_alternative) {
2655 /* Ok, USER failed. Let's try the supplied command. */
2656 PPSENDF(&conn->proto.ftpc.pp, "%s",
2657 conn->data->set.str[STRING_FTP_ALTERNATIVE_TO_USER]);
2658 conn->data->state.ftp_trying_alternative = TRUE;
2659 state(conn, FTP_USER);
2663 failf(data, "Access denied: %03d", ftpcode);
2664 result = CURLE_LOGIN_DENIED;
2670 /* for ACCT response */
2671 static CURLcode ftp_state_acct_resp(struct connectdata *conn,
2674 CURLcode result = CURLE_OK;
2675 struct SessionHandle *data = conn->data;
2676 if(ftpcode != 230) {
2677 failf(data, "ACCT rejected by server: %03d", ftpcode);
2678 result = CURLE_FTP_WEIRD_PASS_REPLY; /* FIX */
2681 result = ftp_state_loggedin(conn);
2687 static CURLcode ftp_statemach_act(struct connectdata *conn)
2690 curl_socket_t sock = conn->sock[FIRSTSOCKET];
2691 struct SessionHandle *data=conn->data;
2693 struct ftp_conn *ftpc = &conn->proto.ftpc;
2694 struct pingpong *pp = &ftpc->pp;
2695 static const char ftpauth[][4] = { "SSL", "TLS" };
2699 return Curl_pp_flushsend(pp);
2701 result = ftp_readresp(sock, pp, &ftpcode, &nread);
2706 /* we have now received a full FTP server response */
2707 switch(ftpc->state) {
2709 if(ftpcode != 220) {
2710 failf(data, "Got a %03d ftp-server response when 220 was expected",
2712 return CURLE_FTP_WEIRD_SERVER_REPLY;
2715 /* We have received a 220 response fine, now we proceed. */
2716 #if defined(HAVE_KRB4) || defined(HAVE_GSSAPI)
2718 /* If not anonymous login, try a secure login. Note that this
2719 procedure is still BLOCKING. */
2721 Curl_sec_request_prot(conn, "private");
2722 /* We set private first as default, in case the line below fails to
2723 set a valid level */
2724 Curl_sec_request_prot(conn, data->set.str[STRING_KRB_LEVEL]);
2726 if(Curl_sec_login(conn) != CURLE_OK)
2727 infof(data, "Logging in with password in cleartext!\n");
2729 infof(data, "Authentication successful\n");
2733 if(data->set.use_ssl && !conn->ssl[FIRSTSOCKET].use) {
2734 /* We don't have a SSL/TLS connection yet, but FTPS is
2735 requested. Try a FTPS connection now */
2738 switch(data->set.ftpsslauth) {
2739 case CURLFTPAUTH_DEFAULT:
2740 case CURLFTPAUTH_SSL:
2741 ftpc->count2 = 1; /* add one to get next */
2744 case CURLFTPAUTH_TLS:
2745 ftpc->count2 = -1; /* subtract one to get next */
2749 failf(data, "unsupported parameter to CURLOPT_FTPSSLAUTH: %d",
2750 (int)data->set.ftpsslauth);
2751 return CURLE_UNKNOWN_OPTION; /* we don't know what to do */
2753 PPSENDF(&ftpc->pp, "AUTH %s", ftpauth[ftpc->count1]);
2754 state(conn, FTP_AUTH);
2757 result = ftp_state_user(conn);
2765 /* we have gotten the response to a previous AUTH command */
2767 /* RFC2228 (page 5) says:
2769 * If the server is willing to accept the named security mechanism,
2770 * and does not require any security data, it must respond with
2771 * reply code 234/334.
2774 if((ftpcode == 234) || (ftpcode == 334)) {
2775 /* Curl_ssl_connect is BLOCKING */
2776 result = Curl_ssl_connect(conn, FIRSTSOCKET);
2777 if(CURLE_OK == result) {
2778 conn->ssl[SECONDARYSOCKET].use = FALSE; /* clear-text data */
2779 result = ftp_state_user(conn);
2782 else if(ftpc->count3 < 1) {
2784 ftpc->count1 += ftpc->count2; /* get next attempt */
2785 result = Curl_pp_sendf(&ftpc->pp, "AUTH %s", ftpauth[ftpc->count1]);
2786 /* remain in this same state */
2789 if(data->set.use_ssl > CURLUSESSL_TRY)
2790 /* we failed and CURLUSESSL_CONTROL or CURLUSESSL_ALL is set */
2791 result = CURLE_USE_SSL_FAILED;
2793 /* ignore the failure and continue */
2794 result = ftp_state_user(conn);
2803 result = ftp_state_user_resp(conn, ftpcode, ftpc->state);
2807 result = ftp_state_acct_resp(conn, ftpcode);
2811 PPSENDF(&ftpc->pp, "PROT %c",
2812 data->set.use_ssl == CURLUSESSL_CONTROL ? 'C' : 'P');
2813 state(conn, FTP_PROT);
2818 if(ftpcode/100 == 2)
2819 /* We have enabled SSL for the data connection! */
2820 conn->ssl[SECONDARYSOCKET].use =
2821 (data->set.use_ssl != CURLUSESSL_CONTROL) ? TRUE : FALSE;
2822 /* FTP servers typically responds with 500 if they decide to reject
2824 else if(data->set.use_ssl > CURLUSESSL_CONTROL)
2825 /* we failed and bails out */
2826 return CURLE_USE_SSL_FAILED;
2828 if(data->set.ftp_ccc) {
2829 /* CCC - Clear Command Channel
2831 PPSENDF(&ftpc->pp, "CCC", NULL);
2832 state(conn, FTP_CCC);
2835 result = ftp_state_pwd(conn);
2843 /* First shut down the SSL layer (note: this call will block) */
2844 result = Curl_ssl_shutdown(conn, FIRSTSOCKET);
2847 failf(conn->data, "Failed to clear the command channel (CCC)");
2852 /* Then continue as normal */
2853 result = ftp_state_pwd(conn);
2859 if(ftpcode == 257) {
2860 char *ptr=&data->state.buffer[4]; /* start on the first letter */
2864 dir = malloc(nread + 1);
2866 return CURLE_OUT_OF_MEMORY;
2868 /* Reply format is like
2869 257<space>"<directory-name>"<space><commentary> and the RFC959
2872 The directory name can contain any character; embedded
2873 double-quotes should be escaped by double-quotes (the
2874 "quote-doubling" convention).
2877 /* it started good */
2879 for(store = dir; *ptr;) {
2881 if('\"' == ptr[1]) {
2882 /* "quote-doubling" */
2888 *store = '\0'; /* zero terminate */
2889 break; /* get out of this loop */
2898 /* If the path name does not look like an absolute path (i.e.: it
2899 does not start with a '/'), we probably need some server-dependent
2900 adjustments. For example, this is the case when connecting to
2901 an OS400 FTP server: this server supports two name syntaxes,
2902 the default one being incompatible with standard pathes. In
2903 addition, this server switches automatically to the regular path
2904 syntax when one is encountered in a command: this results in
2905 having an entrypath in the wrong syntax when later used in CWD.
2906 The method used here is to check the server OS: we do it only
2907 if the path name looks strange to minimize overhead on other
2910 if(!ftpc->server_os && dir[0] != '/') {
2912 result = Curl_pp_sendf(&ftpc->pp, "SYST", NULL);
2913 if(result != CURLE_OK) {
2917 Curl_safefree(ftpc->entrypath);
2918 ftpc->entrypath = dir; /* remember this */
2919 infof(data, "Entry path is '%s'\n", ftpc->entrypath);
2920 /* also save it where getinfo can access it: */
2921 data->state.most_recent_ftp_entrypath = ftpc->entrypath;
2922 state(conn, FTP_SYST);
2926 Curl_safefree(ftpc->entrypath);
2927 ftpc->entrypath = dir; /* remember this */
2928 infof(data, "Entry path is '%s'\n", ftpc->entrypath);
2929 /* also save it where getinfo can access it: */
2930 data->state.most_recent_ftp_entrypath = ftpc->entrypath;
2933 /* couldn't get the path */
2935 infof(data, "Failed to figure out path\n");
2938 state(conn, FTP_STOP); /* we are done with the CONNECT phase! */
2939 DEBUGF(infof(data, "protocol connect phase DONE\n"));
2943 if(ftpcode == 215) {
2944 char *ptr=&data->state.buffer[4]; /* start on the first letter */
2948 os = malloc(nread + 1);
2950 return CURLE_OUT_OF_MEMORY;
2952 /* Reply format is like
2953 215<space><OS-name><space><commentary>
2957 for(store = os; *ptr && *ptr != ' ';)
2959 *store = '\0'; /* zero terminate */
2961 /* Check for special servers here. */
2963 if(strequal(os, "OS/400")) {
2964 /* Force OS400 name format 1. */
2965 result = Curl_pp_sendf(&ftpc->pp, "SITE NAMEFMT 1", NULL);
2966 if(result != CURLE_OK) {
2970 /* remember target server OS */
2971 Curl_safefree(ftpc->server_os);
2972 ftpc->server_os = os;
2973 state(conn, FTP_NAMEFMT);
2977 /* Nothing special for the target server. */
2978 /* remember target server OS */
2979 Curl_safefree(ftpc->server_os);
2980 ftpc->server_os = os;
2984 /* Cannot identify server OS. Continue anyway and cross fingers. */
2987 state(conn, FTP_STOP); /* we are done with the CONNECT phase! */
2988 DEBUGF(infof(data, "protocol connect phase DONE\n"));
2992 if(ftpcode == 250) {
2993 /* Name format change successful: reload initial path. */
2994 ftp_state_pwd(conn);
2998 state(conn, FTP_STOP); /* we are done with the CONNECT phase! */
2999 DEBUGF(infof(data, "protocol connect phase DONE\n"));
3004 case FTP_RETR_PREQUOTE:
3005 case FTP_STOR_PREQUOTE:
3006 if((ftpcode >= 400) && !ftpc->count2) {
3007 /* failure response code, and not allowed to fail */
3008 failf(conn->data, "QUOT command failed with %03d", ftpcode);
3009 return CURLE_QUOTE_ERROR;
3011 result = ftp_state_quote(conn, FALSE, ftpc->state);
3018 if(ftpcode/100 != 2) {
3019 /* failure to CWD there */
3020 if(conn->data->set.ftp_create_missing_dirs &&
3021 ftpc->count1 && !ftpc->count2) {
3023 ftpc->count2++; /* counter to prevent CWD-MKD loops */
3024 PPSENDF(&ftpc->pp, "MKD %s", ftpc->dirs[ftpc->count1 - 1]);
3025 state(conn, FTP_MKD);
3028 /* return failure */
3029 failf(data, "Server denied you to change to the given directory");
3030 ftpc->cwdfail = TRUE; /* don't remember this path as we failed
3032 return CURLE_REMOTE_ACCESS_DENIED;
3038 if(++ftpc->count1 <= ftpc->dirdepth) {
3040 PPSENDF(&ftpc->pp, "CWD %s", ftpc->dirs[ftpc->count1 - 1]);
3043 result = ftp_state_post_cwd(conn);
3051 if((ftpcode/100 != 2) && !ftpc->count3--) {
3052 /* failure to MKD the dir */
3053 failf(data, "Failed to MKD dir: %03d", ftpcode);
3054 return CURLE_REMOTE_ACCESS_DENIED;
3056 state(conn, FTP_CWD);
3058 PPSENDF(&ftpc->pp, "CWD %s", ftpc->dirs[ftpc->count1 - 1]);
3062 result = ftp_state_mdtm_resp(conn, ftpcode);
3069 result = ftp_state_type_resp(conn, ftpcode, ftpc->state);
3075 result = ftp_state_size_resp(conn, ftpcode, ftpc->state);
3080 result = ftp_state_rest_resp(conn, ftpcode, ftpc->state);
3084 if(ftpcode != 200) {
3085 /* there only is this one standard OK return code. */
3086 failf(data, "PRET command not accepted: %03d", ftpcode);
3087 return CURLE_FTP_PRET_FAILED;
3089 result = ftp_state_use_pasv(conn);
3093 result = ftp_state_pasv_resp(conn, ftpcode);
3097 result = ftp_state_port_resp(conn, ftpcode);
3102 result = ftp_state_get_resp(conn, ftpcode, ftpc->state);
3106 result = ftp_state_stor_resp(conn, ftpcode, ftpc->state);
3110 /* fallthrough, just stop! */
3112 /* internal error */
3113 state(conn, FTP_STOP);
3122 /* called repeatedly until done from multi.c */
3123 static CURLcode ftp_multi_statemach(struct connectdata *conn,
3126 struct ftp_conn *ftpc = &conn->proto.ftpc;
3127 CURLcode result = Curl_pp_multi_statemach(&ftpc->pp);
3129 /* Check for the state outside of the Curl_socket_ready() return code checks
3130 since at times we are in fact already in this state when this function
3132 *done = (ftpc->state == FTP_STOP) ? TRUE : FALSE;
3137 static CURLcode ftp_easy_statemach(struct connectdata *conn)
3139 struct ftp_conn *ftpc = &conn->proto.ftpc;
3140 struct pingpong *pp = &ftpc->pp;
3141 CURLcode result = CURLE_OK;
3143 while(ftpc->state != FTP_STOP) {
3144 result = Curl_pp_easy_statemach(pp);
3153 * Allocate and initialize the struct FTP for the current SessionHandle. If
3157 #if defined(__INTEL_COMPILER) && (__INTEL_COMPILER == 910) && \
3158 defined(__OPTIMIZE__) && defined(__unix__) && defined(__i386__)
3159 /* workaround icc 9.1 optimizer issue */
3160 #pragma optimize("", off)
3163 static CURLcode ftp_init(struct connectdata *conn)
3167 if(NULL == conn->data->state.proto.ftp) {
3168 conn->data->state.proto.ftp = malloc(sizeof(struct FTP));
3169 if(NULL == conn->data->state.proto.ftp)
3170 return CURLE_OUT_OF_MEMORY;
3173 ftp = conn->data->state.proto.ftp;
3175 /* get some initial data into the ftp struct */
3176 ftp->bytecountp = &conn->data->req.bytecount;
3177 ftp->transfer = FTPTRANSFER_BODY;
3178 ftp->downloadsize = 0;
3180 /* No need to duplicate user+password, the connectdata struct won't change
3181 during a session, but we re-init them here since on subsequent inits
3182 since the conn struct may have changed or been replaced.
3184 ftp->user = conn->user;
3185 ftp->passwd = conn->passwd;
3186 if(isBadFtpString(ftp->user))
3187 return CURLE_URL_MALFORMAT;
3188 if(isBadFtpString(ftp->passwd))
3189 return CURLE_URL_MALFORMAT;
3191 conn->proto.ftpc.known_filesize = -1; /* unknown size for now */
3196 #if defined(__INTEL_COMPILER) && (__INTEL_COMPILER == 910) && \
3197 defined(__OPTIMIZE__) && defined(__unix__) && defined(__i386__)
3198 /* workaround icc 9.1 optimizer issue */
3199 #pragma optimize("", on)
3203 * ftp_connect() should do everything that is to be considered a part of
3204 * the connection phase.
3206 * The variable 'done' points to will be TRUE if the protocol-layer connect
3207 * phase is done when this function returns, or FALSE is not. When called as
3208 * a part of the easy interface, it will always be TRUE.
3210 static CURLcode ftp_connect(struct connectdata *conn,
3211 bool *done) /* see description above */
3214 struct ftp_conn *ftpc = &conn->proto.ftpc;
3215 struct pingpong *pp = &ftpc->pp;
3217 *done = FALSE; /* default to not done yet */
3219 /* If there already is a protocol-specific struct allocated for this
3220 sessionhandle, deal with it */
3221 Curl_reset_reqproto(conn);
3223 result = ftp_init(conn);
3224 if(CURLE_OK != result)
3227 /* We always support persistent connections on ftp */
3228 conn->bits.close = FALSE;
3230 pp->response_time = RESP_TIMEOUT; /* set default response time-out */
3231 pp->statemach_act = ftp_statemach_act;
3232 pp->endofresp = ftp_endofresp;
3235 if(conn->handler->flags & PROTOPT_SSL) {
3237 result = Curl_ssl_connect(conn, FIRSTSOCKET);
3242 Curl_pp_init(pp); /* init the generic pingpong data */
3244 /* When we connect, we start in the state where we await the 220
3246 state(conn, FTP_WAIT220);
3248 result = ftp_multi_statemach(conn, done);
3253 /***********************************************************************
3257 * The DONE function. This does what needs to be done after a single DO has
3260 * Input argument is already checked for validity.
3262 static CURLcode ftp_done(struct connectdata *conn, CURLcode status,
3265 struct SessionHandle *data = conn->data;
3266 struct FTP *ftp = data->state.proto.ftp;
3267 struct ftp_conn *ftpc = &conn->proto.ftpc;
3268 struct pingpong *pp = &ftpc->pp;
3271 CURLcode result = CURLE_OK;
3272 bool was_ctl_valid = ftpc->ctl_valid;
3274 const char *path_to_use = data->state.path;
3277 /* When the easy handle is removed from the multi while libcurl is still
3278 * trying to resolve the host name, it seems that the ftp struct is not
3279 * yet initialized, but the removal action calls Curl_done() which calls
3280 * this function. So we simply return success if no ftp pointer is set.
3285 case CURLE_BAD_DOWNLOAD_RESUME:
3286 case CURLE_FTP_WEIRD_PASV_REPLY:
3287 case CURLE_FTP_PORT_FAILED:
3288 case CURLE_FTP_ACCEPT_FAILED:
3289 case CURLE_FTP_ACCEPT_TIMEOUT:
3290 case CURLE_FTP_COULDNT_SET_TYPE:
3291 case CURLE_FTP_COULDNT_RETR_FILE:
3292 case CURLE_PARTIAL_FILE:
3293 case CURLE_UPLOAD_FAILED:
3294 case CURLE_REMOTE_ACCESS_DENIED:
3295 case CURLE_FILESIZE_EXCEEDED:
3296 case CURLE_REMOTE_FILE_NOT_FOUND:
3297 case CURLE_WRITE_ERROR:
3298 /* the connection stays alive fine even though this happened */
3300 case CURLE_OK: /* doesn't affect the control connection's status */
3302 ftpc->ctl_valid = was_ctl_valid;
3305 /* until we cope better with prematurely ended requests, let them
3306 * fallback as if in complete failure */
3307 default: /* by default, an error means the control connection is
3308 wedged and should not be used anymore */
3309 ftpc->ctl_valid = FALSE;
3310 ftpc->cwdfail = TRUE; /* set this TRUE to prevent us to remember the
3311 current path, as this connection is going */
3312 conn->bits.close = TRUE; /* marked for closure */
3313 result = status; /* use the already set error code */
3317 /* now store a copy of the directory we are in */
3319 free(ftpc->prevpath);
3321 if(data->set.wildcardmatch) {
3322 if(data->set.chunk_end && ftpc->file) {
3323 data->set.chunk_end(data->wildcard.customptr);
3325 ftpc->known_filesize = -1;
3328 /* get the "raw" path */
3329 path = curl_easy_unescape(data, path_to_use, 0, NULL);
3331 /* out of memory, but we can limp along anyway (and should try to
3332 * since we may already be in the out of memory cleanup path) */
3334 result = CURLE_OUT_OF_MEMORY;
3335 ftpc->ctl_valid = FALSE; /* mark control connection as bad */
3336 conn->bits.close = TRUE; /* mark for connection closure */
3337 ftpc->prevpath = NULL; /* no path remembering */
3340 size_t flen = ftpc->file?strlen(ftpc->file):0; /* file is "raw" already */
3341 size_t dlen = strlen(path)-flen;
3342 if(!ftpc->cwdfail) {
3343 if(dlen && (data->set.ftp_filemethod != FTPFILE_NOCWD)) {
3344 ftpc->prevpath = path;
3346 /* if 'path' is not the whole string */
3347 ftpc->prevpath[dlen]=0; /* terminate */
3350 /* we never changed dir */
3351 ftpc->prevpath=strdup("");
3355 infof(data, "Remembering we are in dir \"%s\"\n", ftpc->prevpath);
3358 ftpc->prevpath = NULL; /* no path */
3362 /* free the dir tree and file parts */
3365 /* shut down the socket to inform the server we're done */
3368 shutdown(conn->sock[SECONDARYSOCKET],2); /* SD_BOTH */
3371 if(conn->sock[SECONDARYSOCKET] != CURL_SOCKET_BAD) {
3372 if(!result && ftpc->dont_check && data->req.maxdownload > 0)
3373 /* partial download completed */
3374 result = Curl_pp_sendf(pp, "ABOR");
3376 failf(data, "Failure sending ABOR command: %s",
3377 curl_easy_strerror(result));
3378 ftpc->ctl_valid = FALSE; /* mark control connection as bad */
3379 conn->bits.close = TRUE; /* mark for connection closure */
3382 if(conn->ssl[SECONDARYSOCKET].use) {
3383 /* The secondary socket is using SSL so we must close down that part
3384 first before we close the socket for real */
3385 Curl_ssl_close(conn, SECONDARYSOCKET);
3387 /* Note that we keep "use" set to TRUE since that (next) connection is
3388 still requested to use SSL */
3390 if(CURL_SOCKET_BAD != conn->sock[SECONDARYSOCKET]) {
3391 Curl_closesocket(conn, conn->sock[SECONDARYSOCKET]);
3392 conn->sock[SECONDARYSOCKET] = CURL_SOCKET_BAD;
3393 conn->bits.tcpconnect[SECONDARYSOCKET] = FALSE;
3397 if(!result && (ftp->transfer == FTPTRANSFER_BODY) && ftpc->ctl_valid &&
3398 pp->pending_resp && !premature) {
3400 * Let's see what the server says about the transfer we just performed,
3401 * but lower the timeout as sometimes this connection has died while the
3402 * data has been transferred. This happens when doing through NATs etc that
3403 * abandon old silent connections.
3405 long old_time = pp->response_time;
3407 pp->response_time = 60*1000; /* give it only a minute for now */
3408 pp->response = Curl_tvnow(); /* timeout relative now */
3410 result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
3412 pp->response_time = old_time; /* set this back to previous value */
3414 if(!nread && (CURLE_OPERATION_TIMEDOUT == result)) {
3415 failf(data, "control connection looks dead");
3416 ftpc->ctl_valid = FALSE; /* mark control connection as bad */
3417 conn->bits.close = TRUE; /* mark for closure */
3423 if(ftpc->dont_check && data->req.maxdownload > 0) {
3424 /* we have just sent ABOR and there is no reliable way to check if it was
3425 * successful or not; we have to close the connection now */
3426 infof(data, "partial download completed, closing connection\n");
3427 conn->bits.close = TRUE; /* mark for closure */
3431 if(!ftpc->dont_check) {
3432 /* 226 Transfer complete, 250 Requested file action okay, completed. */
3433 if((ftpcode != 226) && (ftpcode != 250)) {
3434 failf(data, "server did not report OK, got %d", ftpcode);
3435 result = CURLE_PARTIAL_FILE;
3440 if(result || premature)
3441 /* the response code from the transfer showed an error already so no
3442 use checking further */
3444 else if(data->set.upload) {
3445 if((-1 != data->set.infilesize) &&
3446 (data->set.infilesize != *ftp->bytecountp) &&
3448 (ftp->transfer == FTPTRANSFER_BODY)) {
3449 failf(data, "Uploaded unaligned file size (%" FORMAT_OFF_T
3450 " out of %" FORMAT_OFF_T " bytes)",
3451 *ftp->bytecountp, data->set.infilesize);
3452 result = CURLE_PARTIAL_FILE;
3456 if((-1 != data->req.size) &&
3457 (data->req.size != *ftp->bytecountp) &&
3458 #ifdef CURL_DO_LINEEND_CONV
3459 /* Most FTP servers don't adjust their file SIZE response for CRLFs, so
3460 * we'll check to see if the discrepancy can be explained by the number
3461 * of CRLFs we've changed to LFs.
3463 ((data->req.size + data->state.crlf_conversions) !=
3464 *ftp->bytecountp) &&
3465 #endif /* CURL_DO_LINEEND_CONV */
3466 (data->req.maxdownload != *ftp->bytecountp)) {
3467 failf(data, "Received only partial file: %" FORMAT_OFF_T " bytes",
3469 result = CURLE_PARTIAL_FILE;
3471 else if(!ftpc->dont_check &&
3472 !*ftp->bytecountp &&
3473 (data->req.size>0)) {
3474 failf(data, "No data was received!");
3475 result = CURLE_FTP_COULDNT_RETR_FILE;
3479 /* clear these for next connection */
3480 ftp->transfer = FTPTRANSFER_BODY;
3481 ftpc->dont_check = FALSE;
3483 /* Send any post-transfer QUOTE strings? */
3484 if(!status && !result && !premature && data->set.postquote)
3485 result = ftp_sendquote(conn, data->set.postquote);
3490 /***********************************************************************
3494 * Where a 'quote' means a list of custom commands to send to the server.
3495 * The quote list is passed as an argument.
3501 CURLcode ftp_sendquote(struct connectdata *conn, struct curl_slist *quote)
3503 struct curl_slist *item;
3507 struct ftp_conn *ftpc = &conn->proto.ftpc;
3508 struct pingpong *pp = &ftpc->pp;
3513 char *cmd = item->data;
3514 bool acceptfail = FALSE;
3516 /* if a command starts with an asterisk, which a legal FTP command never
3517 can, the command will be allowed to fail without it causing any
3518 aborts or cancels etc. It will cause libcurl to act as if the command
3519 is successful, whatever the server reponds. */
3526 FTPSENDF(conn, "%s", cmd);
3528 pp->response = Curl_tvnow(); /* timeout relative now */
3530 result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
3534 if(!acceptfail && (ftpcode >= 400)) {
3535 failf(conn->data, "QUOT string not accepted: %s", cmd);
3536 return CURLE_QUOTE_ERROR;
3546 /***********************************************************************
3550 * Returns TRUE if we in the current situation should send TYPE
3552 static int ftp_need_type(struct connectdata *conn,
3555 return conn->proto.ftpc.transfertype != (ascii_wanted?'A':'I');
3558 /***********************************************************************
3562 * Set TYPE. We only deal with ASCII or BINARY so this function
3564 * If the transfer type is not sent, simulate on OK response in newstate
3566 static CURLcode ftp_nb_type(struct connectdata *conn,
3567 bool ascii, ftpstate newstate)
3569 struct ftp_conn *ftpc = &conn->proto.ftpc;
3571 char want = (char)(ascii?'A':'I');
3573 if(ftpc->transfertype == want) {
3574 state(conn, newstate);
3575 return ftp_state_type_resp(conn, 200, newstate);
3578 PPSENDF(&ftpc->pp, "TYPE %c", want);
3579 state(conn, newstate);
3581 /* keep track of our current transfer type */
3582 ftpc->transfertype = want;
3586 /***************************************************************************
3588 * ftp_pasv_verbose()
3590 * This function only outputs some informationals about this second connection
3591 * when we've issued a PASV command before and thus we have connected to a
3592 * possibly new IP address.
3595 #ifndef CURL_DISABLE_VERBOSE_STRINGS
3597 ftp_pasv_verbose(struct connectdata *conn,
3599 char *newhost, /* ascii version */
3603 Curl_printable_address(ai, buf, sizeof(buf));
3604 infof(conn->data, "Connecting to %s (%s) port %d\n", newhost, buf, port);
3609 Check if this is a range download, and if so, set the internal variables
3613 static CURLcode ftp_range(struct connectdata *conn)
3615 curl_off_t from, to;
3618 struct SessionHandle *data = conn->data;
3619 struct ftp_conn *ftpc = &conn->proto.ftpc;
3621 if(data->state.use_range && data->state.range) {
3622 from=curlx_strtoofft(data->state.range, &ptr, 0);
3623 while(*ptr && (ISSPACE(*ptr) || (*ptr=='-')))
3625 to=curlx_strtoofft(ptr, &ptr2, 0);
3627 /* we didn't get any digit */
3630 if((-1 == to) && (from>=0)) {
3632 data->state.resume_from = from;
3633 DEBUGF(infof(conn->data, "FTP RANGE %" FORMAT_OFF_T " to end of file\n",
3638 data->req.maxdownload = -from;
3639 data->state.resume_from = from;
3640 DEBUGF(infof(conn->data, "FTP RANGE the last %" FORMAT_OFF_T " bytes\n",
3645 data->req.maxdownload = (to-from)+1; /* include last byte */
3646 data->state.resume_from = from;
3647 DEBUGF(infof(conn->data, "FTP RANGE from %" FORMAT_OFF_T
3648 " getting %" FORMAT_OFF_T " bytes\n",
3649 from, data->req.maxdownload));
3651 DEBUGF(infof(conn->data, "range-download from %" FORMAT_OFF_T
3652 " to %" FORMAT_OFF_T ", totally %" FORMAT_OFF_T " bytes\n",
3653 from, to, data->req.maxdownload));
3654 ftpc->dont_check = TRUE; /* dont check for successful transfer */
3657 data->req.maxdownload = -1;
3665 * This function shall be called when the second FTP (data) connection is
3669 static CURLcode ftp_do_more(struct connectdata *conn, bool *complete)
3671 struct SessionHandle *data=conn->data;
3672 struct ftp_conn *ftpc = &conn->proto.ftpc;
3673 CURLcode result = CURLE_OK;
3674 bool connected = FALSE;
3676 /* the ftp struct is inited in ftp_connect() */
3677 struct FTP *ftp = data->state.proto.ftp;
3681 /* if the second connection isn't done yet, wait for it */
3682 if(!conn->bits.tcpconnect[SECONDARYSOCKET]) {
3683 if(conn->tunnel_state[SECONDARYSOCKET] == TUNNEL_CONNECT) {
3684 /* As we're in TUNNEL_CONNECT state now, we know the proxy name and port
3685 aren't used so we blank their arguments. TODO: make this nicer */
3686 result = Curl_proxyCONNECT(conn, SECONDARYSOCKET, NULL, 0);
3691 result = Curl_is_connected(conn, SECONDARYSOCKET, &connected);
3693 /* Ready to do more? */
3695 DEBUGF(infof(data, "DO-MORE connected phase starts\n"));
3702 /* already in a state so skip the intial commands.
3703 They are only done to kickstart the do_more state */
3704 result = ftp_multi_statemach(conn, complete);
3706 /* if we got an error or if we don't wait for a data connection return
3708 if(result || (ftpc->wait_data_conn != TRUE))
3711 if(ftpc->wait_data_conn)
3712 /* if we reach the end of the FTP state machine here, *complete will be
3713 TRUE but so is ftpc->wait_data_conn, which says we need to wait for
3714 the data connection and therefore we're not actually complete */
3718 if(ftp->transfer <= FTPTRANSFER_INFO) {
3719 /* a transfer is about to take place, or if not a file name was given
3720 so we'll do a SIZE on it later and then we need the right TYPE first */
3722 if(ftpc->wait_data_conn == TRUE) {
3725 result = ReceivedServerConnect(conn, &serv_conned);
3727 return result; /* Failed to accept data connection */
3730 /* It looks data connection is established */
3731 result = AcceptServerConnect(conn);
3732 ftpc->wait_data_conn = FALSE;
3734 result = InitiateTransfer(conn);
3740 else if(data->set.upload) {
3741 result = ftp_nb_type(conn, data->set.prefer_ascii, FTP_STOR_TYPE);
3745 result = ftp_multi_statemach(conn, complete);
3749 ftp->downloadsize = -1; /* unknown as of yet */
3751 result = ftp_range(conn);
3754 else if(data->set.ftp_list_only || !ftpc->file) {
3755 /* The specified path ends with a slash, and therefore we think this
3756 is a directory that is requested, use LIST. But before that we
3757 need to set ASCII transfer mode. */
3759 /* But only if a body transfer was requested. */
3760 if(ftp->transfer == FTPTRANSFER_BODY) {
3761 result = ftp_nb_type(conn, TRUE, FTP_LIST_TYPE);
3765 /* otherwise just fall through */
3768 result = ftp_nb_type(conn, data->set.prefer_ascii, FTP_RETR_TYPE);
3773 result = ftp_multi_statemach(conn, complete);
3778 if((result == CURLE_OK) && (ftp->transfer != FTPTRANSFER_BODY))
3779 /* no data to transfer. FIX: it feels like a kludge to have this here
3781 Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
3783 if(!ftpc->wait_data_conn) {
3784 /* no waiting for the data connection so this is now complete */
3786 DEBUGF(infof(data, "DO-MORE phase ends with %d\n", (int)result));
3794 /***********************************************************************
3798 * This is the actual DO function for FTP. Get a file/directory according to
3799 * the options previously setup.
3803 CURLcode ftp_perform(struct connectdata *conn,
3804 bool *connected, /* connect status after PASV / PORT */
3807 /* this is FTP and no proxy */
3808 CURLcode result=CURLE_OK;
3810 DEBUGF(infof(conn->data, "DO phase starts\n"));
3812 if(conn->data->set.opt_no_body) {
3813 /* requested no body means no transfer... */
3814 struct FTP *ftp = conn->data->state.proto.ftp;
3815 ftp->transfer = FTPTRANSFER_INFO;
3818 *dophase_done = FALSE; /* not done yet */
3820 /* start the first command in the DO phase */
3821 result = ftp_state_quote(conn, TRUE, FTP_QUOTE);
3825 /* run the state-machine */
3826 result = ftp_multi_statemach(conn, dophase_done);
3828 *connected = conn->bits.tcpconnect[FIRSTSOCKET];
3831 DEBUGF(infof(conn->data, "DO phase is complete1\n"));
3836 static void wc_data_dtor(void *ptr)
3838 struct ftp_wc_tmpdata *tmp = ptr;
3840 Curl_ftp_parselist_data_free(&tmp->parser);
3844 static CURLcode init_wc_data(struct connectdata *conn)
3847 char *path = conn->data->state.path;
3848 struct WildcardData *wildcard = &(conn->data->wildcard);
3849 CURLcode ret = CURLE_OK;
3850 struct ftp_wc_tmpdata *ftp_tmp;
3852 last_slash = strrchr(conn->data->state.path, '/');
3855 if(last_slash[0] == '\0') {
3856 wildcard->state = CURLWC_CLEAN;
3857 ret = ftp_parse_url_path(conn);
3861 wildcard->pattern = strdup(last_slash);
3862 if(!wildcard->pattern)
3863 return CURLE_OUT_OF_MEMORY;
3864 last_slash[0] = '\0'; /* cut file from path */
3867 else { /* there is only 'wildcard pattern' or nothing */
3869 wildcard->pattern = strdup(path);
3870 if(!wildcard->pattern)
3871 return CURLE_OUT_OF_MEMORY;
3874 else { /* only list */
3875 wildcard->state = CURLWC_CLEAN;
3876 ret = ftp_parse_url_path(conn);
3881 /* program continues only if URL is not ending with slash, allocate needed
3882 resources for wildcard transfer */
3884 /* allocate ftp protocol specific temporary wildcard data */
3885 ftp_tmp = calloc(1, sizeof(struct ftp_wc_tmpdata));
3887 Curl_safefree(wildcard->pattern);
3888 return CURLE_OUT_OF_MEMORY;
3891 /* INITIALIZE parselist structure */
3892 ftp_tmp->parser = Curl_ftp_parselist_data_alloc();
3893 if(!ftp_tmp->parser) {
3894 Curl_safefree(wildcard->pattern);
3895 Curl_safefree(ftp_tmp);
3896 return CURLE_OUT_OF_MEMORY;
3899 wildcard->tmp = ftp_tmp; /* put it to the WildcardData tmp pointer */
3900 wildcard->tmp_dtor = wc_data_dtor;
3902 /* wildcard does not support NOCWD option (assert it?) */
3903 if(conn->data->set.ftp_filemethod == FTPFILE_NOCWD)
3904 conn->data->set.ftp_filemethod = FTPFILE_MULTICWD;
3906 /* try to parse ftp url */
3907 ret = ftp_parse_url_path(conn);
3909 Curl_safefree(wildcard->pattern);
3910 wildcard->tmp_dtor(wildcard->tmp);
3911 wildcard->tmp_dtor = ZERO_NULL;
3912 wildcard->tmp = NULL;
3916 wildcard->path = strdup(conn->data->state.path);
3917 if(!wildcard->path) {
3918 Curl_safefree(wildcard->pattern);
3919 wildcard->tmp_dtor(wildcard->tmp);
3920 wildcard->tmp_dtor = ZERO_NULL;
3921 wildcard->tmp = NULL;
3922 return CURLE_OUT_OF_MEMORY;
3925 /* backup old write_function */
3926 ftp_tmp->backup.write_function = conn->data->set.fwrite_func;
3927 /* parsing write function */
3928 conn->data->set.fwrite_func = Curl_ftp_parselist;
3929 /* backup old file descriptor */
3930 ftp_tmp->backup.file_descriptor = conn->data->set.out;
3931 /* let the writefunc callback know what curl pointer is working with */
3932 conn->data->set.out = conn;
3934 infof(conn->data, "Wildcard - Parsing started\n");
3938 /* This is called recursively */
3939 static CURLcode wc_statemach(struct connectdata *conn)
3941 struct WildcardData * const wildcard = &(conn->data->wildcard);
3942 CURLcode ret = CURLE_OK;
3944 switch (wildcard->state) {
3946 ret = init_wc_data(conn);
3947 if(wildcard->state == CURLWC_CLEAN)
3951 wildcard->state = ret ? CURLWC_ERROR : CURLWC_MATCHING;
3954 case CURLWC_MATCHING: {
3955 /* In this state is LIST response successfully parsed, so lets restore
3956 previous WRITEFUNCTION callback and WRITEDATA pointer */
3957 struct ftp_wc_tmpdata *ftp_tmp = wildcard->tmp;
3958 conn->data->set.fwrite_func = ftp_tmp->backup.write_function;
3959 conn->data->set.out = ftp_tmp->backup.file_descriptor;
3960 ftp_tmp->backup.write_function = ZERO_NULL;
3961 ftp_tmp->backup.file_descriptor = NULL;
3962 wildcard->state = CURLWC_DOWNLOADING;
3964 if(Curl_ftp_parselist_geterror(ftp_tmp->parser)) {
3965 /* error found in LIST parsing */
3966 wildcard->state = CURLWC_CLEAN;
3967 return wc_statemach(conn);
3969 else if(wildcard->filelist->size == 0) {
3970 /* no corresponding file */
3971 wildcard->state = CURLWC_CLEAN;
3972 return CURLE_REMOTE_FILE_NOT_FOUND;
3974 return wc_statemach(conn);
3977 case CURLWC_DOWNLOADING: {
3978 /* filelist has at least one file, lets get first one */
3979 struct ftp_conn *ftpc = &conn->proto.ftpc;
3980 struct curl_fileinfo *finfo = wildcard->filelist->head->ptr;
3981 char *tmp_path = malloc(strlen(conn->data->state.path) +
3982 strlen(finfo->filename) + 1);
3984 return CURLE_OUT_OF_MEMORY;
3988 /* make full path to matched file */
3989 strcat(tmp_path, wildcard->path);
3990 strcat(tmp_path, finfo->filename);
3991 /* switch default "state.pathbuffer" and tmp_path, good to see
3992 ftp_parse_url_path function to understand this trick */
3993 Curl_safefree(conn->data->state.pathbuffer);
3994 conn->data->state.pathbuffer = tmp_path;
3995 conn->data->state.path = tmp_path;
3997 infof(conn->data, "Wildcard - START of \"%s\"\n", finfo->filename);
3998 if(conn->data->set.chunk_bgn) {
3999 long userresponse = conn->data->set.chunk_bgn(
4000 finfo, wildcard->customptr, (int)wildcard->filelist->size);
4001 switch(userresponse) {
4002 case CURL_CHUNK_BGN_FUNC_SKIP:
4003 infof(conn->data, "Wildcard - \"%s\" skipped by user\n",
4005 wildcard->state = CURLWC_SKIP;
4006 return wc_statemach(conn);
4007 case CURL_CHUNK_BGN_FUNC_FAIL:
4008 return CURLE_CHUNK_FAILED;
4012 if(finfo->filetype != CURLFILETYPE_FILE) {
4013 wildcard->state = CURLWC_SKIP;
4014 return wc_statemach(conn);
4017 if(finfo->flags & CURLFINFOFLAG_KNOWN_SIZE)
4018 ftpc->known_filesize = finfo->size;
4020 ret = ftp_parse_url_path(conn);
4025 /* we don't need the Curl_fileinfo of first file anymore */
4026 Curl_llist_remove(wildcard->filelist, wildcard->filelist->head, NULL);
4028 if(wildcard->filelist->size == 0) { /* remains only one file to down. */
4029 wildcard->state = CURLWC_CLEAN;
4030 /* after that will be ftp_do called once again and no transfer
4031 will be done because of CURLWC_CLEAN state */
4037 if(conn->data->set.chunk_end)
4038 conn->data->set.chunk_end(conn->data->wildcard.customptr);
4039 Curl_llist_remove(wildcard->filelist, wildcard->filelist->head, NULL);
4040 wildcard->state = (wildcard->filelist->size == 0) ?
4041 CURLWC_CLEAN : CURLWC_DOWNLOADING;
4042 return wc_statemach(conn);
4045 case CURLWC_CLEAN: {
4046 struct ftp_wc_tmpdata *ftp_tmp = wildcard->tmp;
4049 ret = Curl_ftp_parselist_geterror(ftp_tmp->parser);
4051 wildcard->state = ret ? CURLWC_ERROR : CURLWC_DONE;
4062 /***********************************************************************
4066 * This function is registered as 'curl_do' function. It decodes the path
4067 * parts etc as a wrapper to the actual DO function (ftp_perform).
4069 * The input argument is already checked for validity.
4071 static CURLcode ftp_do(struct connectdata *conn, bool *done)
4073 CURLcode retcode = CURLE_OK;
4074 struct ftp_conn *ftpc = &conn->proto.ftpc;
4076 *done = FALSE; /* default to false */
4077 ftpc->wait_data_conn = FALSE; /* default to no such wait */
4080 Since connections can be re-used between SessionHandles, this might be a
4081 connection already existing but on a fresh SessionHandle struct so we must
4082 make sure we have a good 'struct FTP' to play with. For new connections,
4083 the struct FTP is allocated and setup in the ftp_connect() function.
4085 Curl_reset_reqproto(conn);
4086 retcode = ftp_init(conn);
4090 if(conn->data->set.wildcardmatch) {
4091 retcode = wc_statemach(conn);
4092 if(conn->data->wildcard.state == CURLWC_SKIP ||
4093 conn->data->wildcard.state == CURLWC_DONE) {
4094 /* do not call ftp_regular_transfer */
4097 if(retcode) /* error, loop or skipping the file */
4100 else { /* no wildcard FSM needed */
4101 retcode = ftp_parse_url_path(conn);
4106 retcode = ftp_regular_transfer(conn, done);
4112 CURLcode Curl_ftpsendf(struct connectdata *conn,
4113 const char *fmt, ...)
4115 ssize_t bytes_written;
4116 #define SBUF_SIZE 1024
4120 CURLcode res = CURLE_OK;
4121 #if defined(HAVE_KRB4) || defined(HAVE_GSSAPI)
4122 enum protection_level data_sec = conn->data_prot;
4127 vsnprintf(s, SBUF_SIZE-3, fmt, ap);
4130 strcat(s, "\r\n"); /* append a trailing CRLF */
4133 write_len = strlen(s);
4135 res = Curl_convert_to_network(conn->data, s, write_len);
4136 /* Curl_convert_to_network calls failf if unsuccessful */
4141 #if defined(HAVE_KRB4) || defined(HAVE_GSSAPI)
4142 conn->data_prot = PROT_CMD;
4144 res = Curl_write(conn, conn->sock[FIRSTSOCKET], sptr, write_len,
4146 #if defined(HAVE_KRB4) || defined(HAVE_GSSAPI)
4147 DEBUGASSERT(data_sec > PROT_NONE && data_sec < PROT_LAST);
4148 conn->data_prot = data_sec;
4154 if(conn->data->set.verbose)
4155 Curl_debug(conn->data, CURLINFO_HEADER_OUT,
4156 sptr, (size_t)bytes_written, conn);
4158 if(bytes_written != (ssize_t)write_len) {
4159 write_len -= bytes_written;
4160 sptr += bytes_written;
4169 /***********************************************************************
4173 * This should be called before calling sclose() on an ftp control connection
4174 * (not data connections). We should then wait for the response from the
4175 * server before returning. The calling code should then try to close the
4179 static CURLcode ftp_quit(struct connectdata *conn)
4181 CURLcode result = CURLE_OK;
4183 if(conn->proto.ftpc.ctl_valid) {
4184 result = Curl_pp_sendf(&conn->proto.ftpc.pp, "QUIT", NULL);
4186 failf(conn->data, "Failure sending QUIT command: %s",
4187 curl_easy_strerror(result));
4188 conn->proto.ftpc.ctl_valid = FALSE; /* mark control connection as bad */
4189 conn->bits.close = TRUE; /* mark for connection closure */
4190 state(conn, FTP_STOP);
4194 state(conn, FTP_QUIT);
4196 result = ftp_easy_statemach(conn);
4202 /***********************************************************************
4206 * Disconnect from an FTP server. Cleanup protocol-specific per-connection
4207 * resources. BLOCKING.
4209 static CURLcode ftp_disconnect(struct connectdata *conn, bool dead_connection)
4211 struct ftp_conn *ftpc= &conn->proto.ftpc;
4212 struct pingpong *pp = &ftpc->pp;
4214 /* We cannot send quit unconditionally. If this connection is stale or
4215 bad in any way, sending quit and waiting around here will make the
4216 disconnect wait in vain and cause more problems than we need to.
4218 ftp_quit() will check the state of ftp->ctl_valid. If it's ok it
4219 will try to send the QUIT command, otherwise it will just return.
4222 ftpc->ctl_valid = FALSE;
4224 /* The FTP session may or may not have been allocated/setup at this point! */
4225 (void)ftp_quit(conn); /* ignore errors on the QUIT */
4227 if(ftpc->entrypath) {
4228 struct SessionHandle *data = conn->data;
4229 if(data->state.most_recent_ftp_entrypath == ftpc->entrypath) {
4230 data->state.most_recent_ftp_entrypath = NULL;
4232 free(ftpc->entrypath);
4233 ftpc->entrypath = NULL;
4237 if(ftpc->prevpath) {
4238 free(ftpc->prevpath);
4239 ftpc->prevpath = NULL;
4241 if(ftpc->server_os) {
4242 free(ftpc->server_os);
4243 ftpc->server_os = NULL;
4246 Curl_pp_disconnect(pp);
4248 #if defined(HAVE_KRB4) || defined(HAVE_GSSAPI)
4255 /***********************************************************************
4257 * ftp_parse_url_path()
4259 * Parse the URL path into separate path components.
4263 CURLcode ftp_parse_url_path(struct connectdata *conn)
4265 struct SessionHandle *data = conn->data;
4266 /* the ftp struct is already inited in ftp_connect() */
4267 struct FTP *ftp = data->state.proto.ftp;
4268 struct ftp_conn *ftpc = &conn->proto.ftpc;
4269 const char *slash_pos; /* position of the first '/' char in curpos */
4270 const char *path_to_use = data->state.path;
4271 const char *cur_pos;
4272 const char *filename = NULL;
4274 cur_pos = path_to_use; /* current position in path. point at the begin
4275 of next path component */
4277 ftpc->ctl_valid = FALSE;
4278 ftpc->cwdfail = FALSE;
4280 switch(data->set.ftp_filemethod) {
4282 /* fastest, but less standard-compliant */
4285 The best time to check whether the path is a file or directory is right
4288 the first condition in the if() right here, is there just in case
4289 someone decides to set path to NULL one day
4291 if(data->state.path &&
4292 data->state.path[0] &&
4293 (data->state.path[strlen(data->state.path) - 1] != '/') )
4294 filename = data->state.path; /* this is a full file path */
4296 ftpc->file is not used anywhere other than for operations on a file.
4297 In other words, never for directory operations.
4298 So we can safely leave filename as NULL here and use it as a
4299 argument in dir/file decisions.
4303 case FTPFILE_SINGLECWD:
4304 /* get the last slash */
4305 if(!path_to_use[0]) {
4306 /* no dir, no file */
4310 slash_pos=strrchr(cur_pos, '/');
4311 if(slash_pos || !*cur_pos) {
4312 ftpc->dirs = calloc(1, sizeof(ftpc->dirs[0]));
4314 return CURLE_OUT_OF_MEMORY;
4316 ftpc->dirs[0] = curl_easy_unescape(conn->data, slash_pos ? cur_pos : "/",
4318 curlx_sztosi(slash_pos-cur_pos) : 1,
4320 if(!ftpc->dirs[0]) {
4322 return CURLE_OUT_OF_MEMORY;
4324 ftpc->dirdepth = 1; /* we consider it to be a single dir */
4325 filename = slash_pos ? slash_pos+1 : cur_pos; /* rest is file name */
4328 filename = cur_pos; /* this is a file name only */
4331 default: /* allow pretty much anything */
4332 case FTPFILE_MULTICWD:
4334 ftpc->diralloc = 5; /* default dir depth to allocate */
4335 ftpc->dirs = calloc(ftpc->diralloc, sizeof(ftpc->dirs[0]));
4337 return CURLE_OUT_OF_MEMORY;
4339 /* we have a special case for listing the root dir only */
4340 if(strequal(path_to_use, "/")) {
4341 cur_pos++; /* make it point to the zero byte */
4342 ftpc->dirs[0] = strdup("/");
4346 /* parse the URL path into separate path components */
4347 while((slash_pos = strchr(cur_pos, '/')) != NULL) {
4348 /* 1 or 0 pointer offset to indicate absolute directory */
4349 ssize_t absolute_dir = ((cur_pos - data->state.path > 0) &&
4350 (ftpc->dirdepth == 0))?1:0;
4352 /* seek out the next path component */
4353 if(slash_pos-cur_pos) {
4354 /* we skip empty path components, like "x//y" since the FTP command
4355 CWD requires a parameter and a non-existent parameter a) doesn't
4356 work on many servers and b) has no effect on the others. */
4357 int len = curlx_sztosi(slash_pos - cur_pos + absolute_dir);
4358 ftpc->dirs[ftpc->dirdepth] =
4359 curl_easy_unescape(conn->data, cur_pos - absolute_dir, len, NULL);
4360 if(!ftpc->dirs[ftpc->dirdepth]) { /* run out of memory ... */
4361 failf(data, "no memory");
4363 return CURLE_OUT_OF_MEMORY;
4365 if(isBadFtpString(ftpc->dirs[ftpc->dirdepth])) {
4366 free(ftpc->dirs[ftpc->dirdepth]);
4368 return CURLE_URL_MALFORMAT;
4372 cur_pos = slash_pos + 1; /* jump to the rest of the string */
4376 cur_pos = slash_pos + 1; /* jump to the rest of the string */
4377 if(++ftpc->dirdepth >= ftpc->diralloc) {
4380 ftpc->diralloc *= 2; /* double the size each time */
4381 bigger = realloc(ftpc->dirs, ftpc->diralloc * sizeof(ftpc->dirs[0]));
4384 return CURLE_OUT_OF_MEMORY;
4386 ftpc->dirs = bigger;
4390 filename = cur_pos; /* the rest is the file name */
4394 if(filename && *filename) {
4395 ftpc->file = curl_easy_unescape(conn->data, filename, 0, NULL);
4396 if(NULL == ftpc->file) {
4398 failf(data, "no memory");
4399 return CURLE_OUT_OF_MEMORY;
4401 if(isBadFtpString(ftpc->file)) {
4403 return CURLE_URL_MALFORMAT;
4407 ftpc->file=NULL; /* instead of point to a zero byte, we make it a NULL
4410 if(data->set.upload && !ftpc->file && (ftp->transfer == FTPTRANSFER_BODY)) {
4411 /* We need a file name when uploading. Return error! */
4412 failf(data, "Uploading to a URL without a file name!");
4413 return CURLE_URL_MALFORMAT;
4416 ftpc->cwddone = FALSE; /* default to not done */
4418 if(ftpc->prevpath) {
4419 /* prevpath is "raw" so we convert the input path before we compare the
4422 char *path = curl_easy_unescape(conn->data, data->state.path, 0, &dlen);
4425 return CURLE_OUT_OF_MEMORY;
4428 dlen -= ftpc->file?curlx_uztosi(strlen(ftpc->file)):0;
4429 if((dlen == curlx_uztosi(strlen(ftpc->prevpath))) &&
4430 strnequal(path, ftpc->prevpath, dlen)) {
4431 infof(data, "Request has same path as previous transfer\n");
4432 ftpc->cwddone = TRUE;
4440 /* call this when the DO phase has completed */
4441 static CURLcode ftp_dophase_done(struct connectdata *conn,
4444 struct FTP *ftp = conn->data->state.proto.ftp;
4445 struct ftp_conn *ftpc = &conn->proto.ftpc;
4449 CURLcode result = ftp_do_more(conn, &completed);
4452 if(conn->sock[SECONDARYSOCKET] != CURL_SOCKET_BAD) {
4453 /* close the second socket if it was created already */
4454 Curl_closesocket(conn, conn->sock[SECONDARYSOCKET]);
4455 conn->sock[SECONDARYSOCKET] = CURL_SOCKET_BAD;
4461 if(ftp->transfer != FTPTRANSFER_BODY)
4462 /* no data to transfer */
4463 Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
4465 /* since we didn't connect now, we want do_more to get called */
4466 conn->bits.do_more = TRUE;
4468 ftpc->ctl_valid = TRUE; /* seems good */
4473 /* called from multi.c while DOing */
4474 static CURLcode ftp_doing(struct connectdata *conn,
4477 CURLcode result = ftp_multi_statemach(conn, dophase_done);
4480 DEBUGF(infof(conn->data, "DO phase failed\n"));
4481 else if(*dophase_done) {
4482 result = ftp_dophase_done(conn, FALSE /* not connected */);
4484 DEBUGF(infof(conn->data, "DO phase is complete2\n"));
4489 /***********************************************************************
4491 * ftp_regular_transfer()
4493 * The input argument is already checked for validity.
4495 * Performs all commands done before a regular transfer between a local and a
4498 * ftp->ctl_valid starts out as FALSE, and gets set to TRUE if we reach the
4499 * ftp_done() function without finding any major problem.
4502 CURLcode ftp_regular_transfer(struct connectdata *conn,
4505 CURLcode result=CURLE_OK;
4506 bool connected=FALSE;
4507 struct SessionHandle *data = conn->data;
4508 struct ftp_conn *ftpc = &conn->proto.ftpc;
4509 data->req.size = -1; /* make sure this is unknown at this point */
4511 Curl_pgrsSetUploadCounter(data, 0);
4512 Curl_pgrsSetDownloadCounter(data, 0);
4513 Curl_pgrsSetUploadSize(data, 0);
4514 Curl_pgrsSetDownloadSize(data, 0);
4516 ftpc->ctl_valid = TRUE; /* starts good */
4518 result = ftp_perform(conn,
4519 &connected, /* have we connected after PASV/PORT */
4520 dophase_done); /* all commands in the DO-phase done? */
4522 if(CURLE_OK == result) {
4525 /* the DO phase has not completed yet */
4528 result = ftp_dophase_done(conn, connected);
4539 static CURLcode ftp_setup_connection(struct connectdata * conn)
4541 struct SessionHandle *data = conn->data;
4545 if(conn->bits.httpproxy && !data->set.tunnel_thru_httpproxy) {
4546 /* Unless we have asked to tunnel ftp operations through the proxy, we
4547 switch and use HTTP operations only */
4548 #ifndef CURL_DISABLE_HTTP
4549 if(conn->handler == &Curl_handler_ftp)
4550 conn->handler = &Curl_handler_ftp_proxy;
4553 conn->handler = &Curl_handler_ftps_proxy;
4555 failf(data, "FTPS not supported!");
4556 return CURLE_UNSUPPORTED_PROTOCOL;
4560 * We explicitly mark this connection as persistent here as we're doing
4561 * FTP over HTTP and thus we accidentally avoid setting this value
4564 conn->bits.close = FALSE;
4566 failf(data, "FTP over http proxy requires HTTP support built-in!");
4567 return CURLE_UNSUPPORTED_PROTOCOL;
4571 data->state.path++; /* don't include the initial slash */
4572 data->state.slash_removed = TRUE; /* we've skipped the slash */
4574 /* FTP URLs support an extension like ";type=<typecode>" that
4575 * we'll try to get now! */
4576 type = strstr(data->state.path, ";type=");
4579 type = strstr(conn->host.rawalloc, ";type=");
4582 *type = 0; /* it was in the middle of the hostname */
4583 command = Curl_raw_toupper(type[6]);
4584 conn->bits.type_set = TRUE;
4587 case 'A': /* ASCII mode */
4588 data->set.prefer_ascii = TRUE;
4591 case 'D': /* directory mode */
4592 data->set.ftp_list_only = TRUE;
4595 case 'I': /* binary mode */
4597 /* switch off ASCII */
4598 data->set.prefer_ascii = FALSE;
4606 #endif /* CURL_DISABLE_FTP */