1 /***************************************************************************
3 * Project ___| | | | _ \| |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
8 * Copyright (C) 1998 - 2016, 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 https://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 #include "strtoofft.h"
65 #include "vtls/vtls.h"
68 #include "inet_ntop.h"
69 #include "inet_pton.h"
71 #include "parsedate.h" /* for the week day and month names */
72 #include "sockaddr.h" /* required for Curl_sockaddr_storage */
76 #include "speedcheck.h"
78 #include "http_proxy.h"
79 #include "non-ascii.h"
80 /* The last 3 #include files should be in this order */
81 #include "curl_printf.h"
82 #include "curl_memory.h"
86 #define NI_MAXHOST 1025
88 #ifndef INET_ADDRSTRLEN
89 #define INET_ADDRSTRLEN 16
92 #ifdef CURL_DISABLE_VERBOSE_STRINGS
93 #define ftp_pasv_verbose(a,b,c,d) Curl_nop_stmt
96 /* Local API functions */
98 static void _state(struct connectdata *conn,
100 #define state(x,y) _state(x,y)
102 static void _state(struct connectdata *conn,
105 #define state(x,y) _state(x,y,__LINE__)
108 static CURLcode ftp_sendquote(struct connectdata *conn,
109 struct curl_slist *quote);
110 static CURLcode ftp_quit(struct connectdata *conn);
111 static CURLcode ftp_parse_url_path(struct connectdata *conn);
112 static CURLcode ftp_regular_transfer(struct connectdata *conn, bool *done);
113 #ifndef CURL_DISABLE_VERBOSE_STRINGS
114 static void ftp_pasv_verbose(struct connectdata *conn,
116 char *newhost, /* ascii version */
119 static CURLcode ftp_state_prepare_transfer(struct connectdata *conn);
120 static CURLcode ftp_state_mdtm(struct connectdata *conn);
121 static CURLcode ftp_state_quote(struct connectdata *conn,
122 bool init, ftpstate instate);
123 static CURLcode ftp_nb_type(struct connectdata *conn,
124 bool ascii, ftpstate newstate);
125 static int ftp_need_type(struct connectdata *conn,
127 static CURLcode ftp_do(struct connectdata *conn, bool *done);
128 static CURLcode ftp_done(struct connectdata *conn,
129 CURLcode, bool premature);
130 static CURLcode ftp_connect(struct connectdata *conn, bool *done);
131 static CURLcode ftp_disconnect(struct connectdata *conn, bool dead_connection);
132 static CURLcode ftp_do_more(struct connectdata *conn, int *completed);
133 static CURLcode ftp_multi_statemach(struct connectdata *conn, bool *done);
134 static int ftp_getsock(struct connectdata *conn, curl_socket_t *socks,
136 static int ftp_domore_getsock(struct connectdata *conn, curl_socket_t *socks,
138 static CURLcode ftp_doing(struct connectdata *conn,
140 static CURLcode ftp_setup_connection(struct connectdata * conn);
142 static CURLcode init_wc_data(struct connectdata *conn);
143 static CURLcode wc_statemach(struct connectdata *conn);
145 static void wc_data_dtor(void *ptr);
147 static CURLcode ftp_state_retr(struct connectdata *conn, curl_off_t filesize);
149 static CURLcode ftp_readresp(curl_socket_t sockfd,
153 static CURLcode ftp_dophase_done(struct connectdata *conn,
156 /* easy-to-use macro: */
157 #define PPSENDF(x,y,z) result = Curl_pp_sendf(x,y,z); \
163 * FTP protocol handler.
166 const struct Curl_handler Curl_handler_ftp = {
168 ftp_setup_connection, /* setup_connection */
171 ftp_do_more, /* do_more */
172 ftp_connect, /* connect_it */
173 ftp_multi_statemach, /* connecting */
174 ftp_doing, /* doing */
175 ftp_getsock, /* proto_getsock */
176 ftp_getsock, /* doing_getsock */
177 ftp_domore_getsock, /* domore_getsock */
178 ZERO_NULL, /* perform_getsock */
179 ftp_disconnect, /* disconnect */
180 ZERO_NULL, /* readwrite */
181 PORT_FTP, /* defport */
182 CURLPROTO_FTP, /* protocol */
183 PROTOPT_DUAL | PROTOPT_CLOSEACTION | PROTOPT_NEEDSPWD
184 | PROTOPT_NOURLQUERY /* flags */
190 * FTPS protocol handler.
193 const struct Curl_handler Curl_handler_ftps = {
195 ftp_setup_connection, /* setup_connection */
198 ftp_do_more, /* do_more */
199 ftp_connect, /* connect_it */
200 ftp_multi_statemach, /* connecting */
201 ftp_doing, /* doing */
202 ftp_getsock, /* proto_getsock */
203 ftp_getsock, /* doing_getsock */
204 ftp_domore_getsock, /* domore_getsock */
205 ZERO_NULL, /* perform_getsock */
206 ftp_disconnect, /* disconnect */
207 ZERO_NULL, /* readwrite */
208 PORT_FTPS, /* defport */
209 CURLPROTO_FTPS, /* protocol */
210 PROTOPT_SSL | PROTOPT_DUAL | PROTOPT_CLOSEACTION |
211 PROTOPT_NEEDSPWD | PROTOPT_NOURLQUERY /* flags */
215 #ifndef CURL_DISABLE_HTTP
217 * HTTP-proxyed FTP protocol handler.
220 static const struct Curl_handler Curl_handler_ftp_proxy = {
222 Curl_http_setup_conn, /* setup_connection */
223 Curl_http, /* do_it */
224 Curl_http_done, /* done */
225 ZERO_NULL, /* do_more */
226 ZERO_NULL, /* connect_it */
227 ZERO_NULL, /* connecting */
228 ZERO_NULL, /* doing */
229 ZERO_NULL, /* proto_getsock */
230 ZERO_NULL, /* doing_getsock */
231 ZERO_NULL, /* domore_getsock */
232 ZERO_NULL, /* perform_getsock */
233 ZERO_NULL, /* disconnect */
234 ZERO_NULL, /* readwrite */
235 PORT_FTP, /* defport */
236 CURLPROTO_HTTP, /* protocol */
237 PROTOPT_NONE /* flags */
243 * HTTP-proxyed FTPS protocol handler.
246 static const struct Curl_handler Curl_handler_ftps_proxy = {
248 Curl_http_setup_conn, /* setup_connection */
249 Curl_http, /* do_it */
250 Curl_http_done, /* done */
251 ZERO_NULL, /* do_more */
252 ZERO_NULL, /* connect_it */
253 ZERO_NULL, /* connecting */
254 ZERO_NULL, /* doing */
255 ZERO_NULL, /* proto_getsock */
256 ZERO_NULL, /* doing_getsock */
257 ZERO_NULL, /* domore_getsock */
258 ZERO_NULL, /* perform_getsock */
259 ZERO_NULL, /* disconnect */
260 ZERO_NULL, /* readwrite */
261 PORT_FTPS, /* defport */
262 CURLPROTO_HTTP, /* protocol */
263 PROTOPT_NONE /* flags */
268 static void close_secondarysocket(struct connectdata *conn)
270 if(CURL_SOCKET_BAD != conn->sock[SECONDARYSOCKET]) {
271 Curl_closesocket(conn, conn->sock[SECONDARYSOCKET]);
272 conn->sock[SECONDARYSOCKET] = CURL_SOCKET_BAD;
274 conn->bits.tcpconnect[SECONDARYSOCKET] = FALSE;
275 conn->tunnel_state[SECONDARYSOCKET] = TUNNEL_INIT;
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++) {
302 Curl_safefree(ftpc->file);
304 /* no longer of any use */
305 Curl_safefree(ftpc->newhost);
308 /* Returns non-zero if the given string contains CR (\r) or LF (\n),
309 which are not allowed within RFC 959 <string>.
310 Note: The input string is in the client's encoding which might
311 not be ASCII, so escape sequences \r & \n must be used instead
312 of hex values 0x0d & 0x0a.
314 static bool isBadFtpString(const char *string)
316 return ((NULL != strchr(string, '\r')) ||
317 (NULL != strchr(string, '\n'))) ? TRUE : FALSE;
320 /***********************************************************************
322 * AcceptServerConnect()
324 * After connection request is received from the server this function is
325 * called to accept the connection and close the listening socket
328 static CURLcode AcceptServerConnect(struct connectdata *conn)
330 struct Curl_easy *data = conn->data;
331 curl_socket_t sock = conn->sock[SECONDARYSOCKET];
332 curl_socket_t s = CURL_SOCKET_BAD;
334 struct Curl_sockaddr_storage add;
336 struct sockaddr_in add;
338 curl_socklen_t size = (curl_socklen_t) sizeof(add);
340 if(0 == getsockname(sock, (struct sockaddr *) &add, &size)) {
343 s=accept(sock, (struct sockaddr *) &add, &size);
345 Curl_closesocket(conn, sock); /* close the first socket */
347 if(CURL_SOCKET_BAD == s) {
348 failf(data, "Error accept()ing server connect");
349 return CURLE_FTP_PORT_FAILED;
351 infof(data, "Connection accepted from server\n");
352 /* when this happens within the DO state it is important that we mark us as
353 not needing DO_MORE anymore */
354 conn->bits.do_more = FALSE;
356 conn->sock[SECONDARYSOCKET] = s;
357 (void)curlx_nonblock(s, TRUE); /* enable non-blocking */
358 conn->sock_accepted[SECONDARYSOCKET] = TRUE;
360 if(data->set.fsockopt) {
363 /* activate callback for setting socket options */
364 error = data->set.fsockopt(data->set.sockopt_client,
366 CURLSOCKTYPE_ACCEPT);
369 close_secondarysocket(conn);
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 time_t ftp_timeleft_accept(struct Curl_easy *data)
389 time_t 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 Curl_easy *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_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 Curl_easy *data = conn->data;
499 struct FTP *ftp = data->req.protop;
500 CURLcode result = CURLE_OK;
502 if(conn->bits.ftp_use_data_ssl) {
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->state.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 Curl_easy *data = conn->data;
551 CURLcode result = 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 result = ReceivedServerConnect(conn, connected);
572 result = AcceptServerConnect(conn);
576 result = InitiateTransfer(conn);
581 /* Add timeout to multi handle and break out of the loop */
582 if(!result && *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 bool ftp_endofresp(struct connectdata *conn, char *line, size_t len,
606 if((len > 3) && LASTLINE(line)) {
607 *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 Curl_easy *data = conn->data;
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_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 time_t timeout; /* timeout in milliseconds */
692 struct Curl_easy *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.
743 else if(!Curl_conn_data_pending(conn, FIRSTSOCKET)) {
744 switch(SOCKET_READABLE(sockfd, 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 #if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
782 /* for debug purposes */
783 static const char * const ftp_state_names[]={
822 /* This is the ONLY way to change FTP state! */
823 static void _state(struct connectdata *conn,
830 struct ftp_conn *ftpc = &conn->proto.ftpc;
832 #if defined(DEBUGBUILD)
834 #if defined(CURL_DISABLE_VERBOSE_STRINGS)
837 if(ftpc->state != newstate)
838 infof(conn->data, "FTP %p (line %d) state change from %s to %s\n",
839 (void *)ftpc, lineno, ftp_state_names[ftpc->state],
840 ftp_state_names[newstate]);
844 ftpc->state = newstate;
847 static CURLcode ftp_state_user(struct connectdata *conn)
850 struct FTP *ftp = conn->data->req.protop;
852 PPSENDF(&conn->proto.ftpc.pp, "USER %s", ftp->user?ftp->user:"");
854 state(conn, FTP_USER);
855 conn->data->state.ftp_trying_alternative = FALSE;
860 static CURLcode ftp_state_pwd(struct connectdata *conn)
864 /* send PWD to discover our entry point */
865 PPSENDF(&conn->proto.ftpc.pp, "%s", "PWD");
866 state(conn, FTP_PWD);
871 /* For the FTP "protocol connect" and "doing" phases only */
872 static int ftp_getsock(struct connectdata *conn,
873 curl_socket_t *socks,
876 return Curl_pp_getsock(&conn->proto.ftpc.pp, socks, numsocks);
879 /* For the FTP "DO_MORE" phase only */
880 static int ftp_domore_getsock(struct connectdata *conn, curl_socket_t *socks,
883 struct ftp_conn *ftpc = &conn->proto.ftpc;
886 return GETSOCK_BLANK;
888 /* When in DO_MORE state, we could be either waiting for us to connect to a
889 * remote site, or we could wait for that site to connect to us. Or just
890 * handle ordinary commands.
893 if(FTP_STOP == ftpc->state) {
894 int bits = GETSOCK_READSOCK(0);
896 /* if stopped and still in this state, then we're also waiting for a
897 connect on the secondary connection */
898 socks[0] = conn->sock[FIRSTSOCKET];
900 if(!conn->data->set.ftp_use_port) {
903 /* PORT is used to tell the server to connect to us, and during that we
904 don't do happy eyeballs, but we do if we connect to the server */
905 for(s=1, i=0; i<2; i++) {
906 if(conn->tempsock[i] != CURL_SOCKET_BAD) {
907 socks[s] = conn->tempsock[i];
908 bits |= GETSOCK_WRITESOCK(s++);
913 socks[1] = conn->sock[SECONDARYSOCKET];
914 bits |= GETSOCK_WRITESOCK(1) | GETSOCK_READSOCK(1);
920 return Curl_pp_getsock(&conn->proto.ftpc.pp, socks, numsocks);
923 /* This is called after the FTP_QUOTE state is passed.
925 ftp_state_cwd() sends the range of CWD commands to the server to change to
926 the correct directory. It may also need to send MKD commands to create
927 missing ones, if that option is enabled.
929 static CURLcode ftp_state_cwd(struct connectdata *conn)
931 CURLcode result = CURLE_OK;
932 struct ftp_conn *ftpc = &conn->proto.ftpc;
935 /* already done and fine */
936 result = ftp_state_mdtm(conn);
938 ftpc->count2 = 0; /* count2 counts failed CWDs */
940 /* count3 is set to allow a MKD to fail once. In the case when first CWD
941 fails and then MKD fails (due to another session raced it to create the
942 dir) this then allows for a second try to CWD to it */
943 ftpc->count3 = (conn->data->set.ftp_create_missing_dirs==2)?1:0;
945 if(conn->bits.reuse && ftpc->entrypath) {
946 /* This is a re-used connection. Since we change directory to where the
947 transfer is taking place, we must first get back to the original dir
948 where we ended up after login: */
949 ftpc->count1 = 0; /* we count this as the first path, then we add one
950 for all upcoming ones in the ftp->dirs[] array */
951 PPSENDF(&conn->proto.ftpc.pp, "CWD %s", ftpc->entrypath);
952 state(conn, FTP_CWD);
957 /* issue the first CWD, the rest is sent when the CWD responses are
959 PPSENDF(&conn->proto.ftpc.pp, "CWD %s", ftpc->dirs[ftpc->count1 -1]);
960 state(conn, FTP_CWD);
963 /* No CWD necessary */
964 result = ftp_state_mdtm(conn);
977 static CURLcode ftp_state_use_port(struct connectdata *conn,
978 ftpport fcmd) /* start with this */
981 CURLcode result = CURLE_OK;
982 struct ftp_conn *ftpc = &conn->proto.ftpc;
983 struct Curl_easy *data=conn->data;
984 curl_socket_t portsock= CURL_SOCKET_BAD;
985 char myhost[256] = "";
987 struct Curl_sockaddr_storage ss;
988 Curl_addrinfo *res, *ai;
989 curl_socklen_t sslen;
990 char hbuf[NI_MAXHOST];
991 struct sockaddr *sa=(struct sockaddr *)&ss;
992 struct sockaddr_in * const sa4 = (void *)sa;
994 struct sockaddr_in6 * const sa6 = (void *)sa;
997 static const char mode[][5] = { "EPRT", "PORT" };
1001 char *string_ftpport = data->set.str[STRING_FTPPORT];
1002 struct Curl_dns_entry *h=NULL;
1003 unsigned short port_min = 0;
1004 unsigned short port_max = 0;
1005 unsigned short port;
1006 bool possibly_non_local = TRUE;
1010 /* Step 1, figure out what is requested,
1012 * (ipv4|ipv6|domain|interface)?(:port(-range)?)?
1015 if(data->set.str[STRING_FTPPORT] &&
1016 (strlen(data->set.str[STRING_FTPPORT]) > 1)) {
1019 size_t addrlen = INET6_ADDRSTRLEN > strlen(string_ftpport) ?
1020 INET6_ADDRSTRLEN : strlen(string_ftpport);
1022 size_t addrlen = INET_ADDRSTRLEN > strlen(string_ftpport) ?
1023 INET_ADDRSTRLEN : strlen(string_ftpport);
1025 char *ip_start = string_ftpport;
1026 char *ip_end = NULL;
1027 char *port_start = NULL;
1028 char *port_sep = NULL;
1030 addr = calloc(addrlen+1, 1);
1032 return CURLE_OUT_OF_MEMORY;
1035 if(*string_ftpport == '[') {
1036 /* [ipv6]:port(-range) */
1037 ip_start = string_ftpport + 1;
1038 ip_end = strchr(string_ftpport, ']');
1040 strncpy(addr, ip_start, ip_end - ip_start);
1044 if(*string_ftpport == ':') {
1046 ip_end = string_ftpport;
1049 ip_end = strchr(string_ftpport, ':');
1051 /* either ipv6 or (ipv4|domain|interface):port(-range) */
1053 if(Curl_inet_pton(AF_INET6, string_ftpport, sa6) == 1) {
1055 port_min = port_max = 0;
1056 strcpy(addr, string_ftpport);
1057 ip_end = NULL; /* this got no port ! */
1061 /* (ipv4|domain|interface):port(-range) */
1062 strncpy(addr, string_ftpport, ip_end - ip_start);
1065 /* ipv4|interface */
1066 strcpy(addr, string_ftpport);
1069 /* parse the port */
1070 if(ip_end != NULL) {
1071 port_start = strchr(ip_end, ':');
1073 port_min = curlx_ultous(strtoul(port_start+1, NULL, 10));
1074 port_sep = strchr(port_start, '-');
1076 port_max = curlx_ultous(strtoul(port_sep + 1, NULL, 10));
1079 port_max = port_min;
1083 /* correct errors like:
1085 * :-4711, in this case port_min is (unsigned)-1,
1086 * therefore port_min > port_max for all cases
1087 * but port_max = (unsigned)-1
1089 if(port_min > port_max)
1090 port_min = port_max = 0;
1094 /* attempt to get the address of the given interface name */
1095 switch(Curl_if2ip(conn->ip_addr->ai_family,
1096 Curl_ipv6_scope(conn->ip_addr->ai_addr),
1097 conn->scope_id, addr, hbuf, sizeof(hbuf))) {
1098 case IF2IP_NOT_FOUND:
1099 /* not an interface, use the given string as host name instead */
1102 case IF2IP_AF_NOT_SUPPORTED:
1103 return CURLE_FTP_PORT_FAILED;
1105 host = hbuf; /* use the hbuf for host name */
1109 /* there was only a port(-range) given, default the host */
1111 } /* data->set.ftpport */
1114 /* not an interface and not a host name, get default by extracting
1115 the IP from the control connection */
1118 if(getsockname(conn->sock[FIRSTSOCKET], sa, &sslen)) {
1119 failf(data, "getsockname() failed: %s",
1120 Curl_strerror(conn, SOCKERRNO) );
1122 return CURLE_FTP_PORT_FAILED;
1124 switch(sa->sa_family) {
1127 Curl_inet_ntop(sa->sa_family, &sa6->sin6_addr, hbuf, sizeof(hbuf));
1131 Curl_inet_ntop(sa->sa_family, &sa4->sin_addr, hbuf, sizeof(hbuf));
1134 host = hbuf; /* use this host name */
1135 possibly_non_local = FALSE; /* we know it is local now */
1138 /* resolv ip/host to ip */
1139 rc = Curl_resolv(conn, host, 0, &h);
1140 if(rc == CURLRESOLV_PENDING)
1141 (void)Curl_resolver_wait_resolv(conn, &h);
1144 /* when we return from this function, we can forget about this entry
1145 to we can unlock it now already */
1146 Curl_resolv_unlock(data, h);
1149 res = NULL; /* failure! */
1152 failf(data, "failed to resolve the address provided to PORT: %s", host);
1154 return CURLE_FTP_PORT_FAILED;
1160 /* step 2, create a socket for the requested address */
1162 portsock = CURL_SOCKET_BAD;
1164 for(ai = res; ai; ai = ai->ai_next) {
1165 result = Curl_socket(conn, ai, NULL, &portsock);
1173 failf(data, "socket failure: %s", Curl_strerror(conn, error));
1174 return CURLE_FTP_PORT_FAILED;
1177 /* step 3, bind to a suitable local address */
1179 memcpy(sa, ai->ai_addr, ai->ai_addrlen);
1180 sslen = ai->ai_addrlen;
1182 for(port = port_min; port <= port_max;) {
1183 if(sa->sa_family == AF_INET)
1184 sa4->sin_port = htons(port);
1187 sa6->sin6_port = htons(port);
1189 /* Try binding the given address. */
1190 if(bind(portsock, sa, sslen) ) {
1193 if(possibly_non_local && (error == EADDRNOTAVAIL)) {
1194 /* The requested bind address is not local. Use the address used for
1195 * the control connection instead and restart the port loop
1198 infof(data, "bind(port=%hu) on non-local address failed: %s\n", port,
1199 Curl_strerror(conn, error) );
1202 if(getsockname(conn->sock[FIRSTSOCKET], sa, &sslen)) {
1203 failf(data, "getsockname() failed: %s",
1204 Curl_strerror(conn, SOCKERRNO) );
1205 Curl_closesocket(conn, portsock);
1206 return CURLE_FTP_PORT_FAILED;
1209 possibly_non_local = FALSE; /* don't try this again */
1212 else if(error != EADDRINUSE && error != EACCES) {
1213 failf(data, "bind(port=%hu) failed: %s", port,
1214 Curl_strerror(conn, error) );
1215 Curl_closesocket(conn, portsock);
1216 return CURLE_FTP_PORT_FAILED;
1225 /* maybe all ports were in use already*/
1226 if(port > port_max) {
1227 failf(data, "bind() failed, we ran out of ports!");
1228 Curl_closesocket(conn, portsock);
1229 return CURLE_FTP_PORT_FAILED;
1232 /* get the name again after the bind() so that we can extract the
1233 port number it uses now */
1235 if(getsockname(portsock, (struct sockaddr *)sa, &sslen)) {
1236 failf(data, "getsockname() failed: %s",
1237 Curl_strerror(conn, SOCKERRNO) );
1238 Curl_closesocket(conn, portsock);
1239 return CURLE_FTP_PORT_FAILED;
1242 /* step 4, listen on the socket */
1244 if(listen(portsock, 1)) {
1245 failf(data, "socket failure: %s", Curl_strerror(conn, SOCKERRNO));
1246 Curl_closesocket(conn, portsock);
1247 return CURLE_FTP_PORT_FAILED;
1250 /* step 5, send the proper FTP command */
1252 /* get a plain printable version of the numerical address to work with
1254 Curl_printable_address(ai, myhost, sizeof(myhost));
1257 if(!conn->bits.ftp_use_eprt && conn->bits.ipv6)
1258 /* EPRT is disabled but we are connected to a IPv6 host, so we ignore the
1259 request and enable EPRT again! */
1260 conn->bits.ftp_use_eprt = TRUE;
1263 for(; fcmd != DONE; fcmd++) {
1265 if(!conn->bits.ftp_use_eprt && (EPRT == fcmd))
1266 /* if disabled, goto next */
1269 if((PORT == fcmd) && sa->sa_family != AF_INET)
1270 /* PORT is IPv4 only */
1273 switch(sa->sa_family) {
1275 port = ntohs(sa4->sin_port);
1279 port = ntohs(sa6->sin6_port);
1283 continue; /* might as well skip this */
1288 * Two fine examples from RFC2428;
1290 * EPRT |1|132.235.1.2|6275|
1292 * EPRT |2|1080::8:800:200C:417A|5282|
1295 result = Curl_pp_sendf(&ftpc->pp, "%s |%d|%s|%hu|", mode[fcmd],
1296 sa->sa_family == AF_INET?1:2,
1299 failf(data, "Failure sending EPRT command: %s",
1300 curl_easy_strerror(result));
1301 Curl_closesocket(conn, portsock);
1302 /* don't retry using PORT */
1303 ftpc->count1 = PORT;
1305 state(conn, FTP_STOP);
1310 else if(PORT == fcmd) {
1311 char *source = myhost;
1314 /* translate x.x.x.x to x,x,x,x */
1315 while(source && *source) {
1324 snprintf(dest, 20, ",%d,%d", (int)(port>>8), (int)(port&0xff));
1326 result = Curl_pp_sendf(&ftpc->pp, "%s %s", mode[fcmd], tmp);
1328 failf(data, "Failure sending PORT command: %s",
1329 curl_easy_strerror(result));
1330 Curl_closesocket(conn, portsock);
1332 state(conn, FTP_STOP);
1339 /* store which command was sent */
1340 ftpc->count1 = fcmd;
1342 close_secondarysocket(conn);
1344 /* we set the secondary socket variable to this for now, it is only so that
1345 the cleanup function will close it in case we fail before the true
1346 secondary stuff is made */
1347 conn->sock[SECONDARYSOCKET] = portsock;
1349 /* this tcpconnect assignment below is a hackish work-around to make the
1350 multi interface with active FTP work - as it will not wait for a
1351 (passive) connect in Curl_is_connected().
1353 The *proper* fix is to make sure that the active connection from the
1354 server is done in a non-blocking way. Currently, it is still BLOCKING.
1356 conn->bits.tcpconnect[SECONDARYSOCKET] = TRUE;
1358 state(conn, FTP_PORT);
1362 static CURLcode ftp_state_use_pasv(struct connectdata *conn)
1364 struct ftp_conn *ftpc = &conn->proto.ftpc;
1365 CURLcode result = CURLE_OK;
1367 Here's the excecutive summary on what to do:
1369 PASV is RFC959, expect:
1370 227 Entering Passive Mode (a1,a2,a3,a4,p1,p2)
1372 LPSV is RFC1639, expect:
1373 228 Entering Long Passive Mode (4,4,a1,a2,a3,a4,2,p1,p2)
1375 EPSV is RFC2428, expect:
1376 229 Entering Extended Passive Mode (|||port|)
1380 static const char mode[][5] = { "EPSV", "PASV" };
1384 if(!conn->bits.ftp_use_epsv && conn->bits.ipv6)
1385 /* EPSV is disabled but we are connected to a IPv6 host, so we ignore the
1386 request and enable EPSV again! */
1387 conn->bits.ftp_use_epsv = TRUE;
1390 modeoff = conn->bits.ftp_use_epsv?0:1;
1392 PPSENDF(&ftpc->pp, "%s", mode[modeoff]);
1394 ftpc->count1 = modeoff;
1395 state(conn, FTP_PASV);
1396 infof(conn->data, "Connect data stream passively\n");
1402 * ftp_state_prepare_transfer() starts PORT, PASV or PRET etc.
1404 * REST is the last command in the chain of commands when a "head"-like
1405 * request is made. Thus, if an actual transfer is to be made this is where we
1406 * take off for real.
1408 static CURLcode ftp_state_prepare_transfer(struct connectdata *conn)
1410 CURLcode result = CURLE_OK;
1411 struct FTP *ftp = conn->data->req.protop;
1412 struct Curl_easy *data = conn->data;
1414 if(ftp->transfer != FTPTRANSFER_BODY) {
1415 /* doesn't transfer any data */
1417 /* still possibly do PRE QUOTE jobs */
1418 state(conn, FTP_RETR_PREQUOTE);
1419 result = ftp_state_quote(conn, TRUE, FTP_RETR_PREQUOTE);
1421 else if(data->set.ftp_use_port) {
1422 /* We have chosen to use the PORT (or similar) command */
1423 result = ftp_state_use_port(conn, EPRT);
1426 /* We have chosen (this is default) to use the PASV (or similar) command */
1427 if(data->set.ftp_use_pret) {
1428 /* The user has requested that we send a PRET command
1429 to prepare the server for the upcoming PASV */
1430 if(!conn->proto.ftpc.file) {
1431 PPSENDF(&conn->proto.ftpc.pp, "PRET %s",
1432 data->set.str[STRING_CUSTOMREQUEST]?
1433 data->set.str[STRING_CUSTOMREQUEST]:
1434 (data->set.ftp_list_only?"NLST":"LIST"));
1436 else if(data->set.upload) {
1437 PPSENDF(&conn->proto.ftpc.pp, "PRET STOR %s", conn->proto.ftpc.file);
1440 PPSENDF(&conn->proto.ftpc.pp, "PRET RETR %s", conn->proto.ftpc.file);
1442 state(conn, FTP_PRET);
1445 result = ftp_state_use_pasv(conn);
1451 static CURLcode ftp_state_rest(struct connectdata *conn)
1453 CURLcode result = CURLE_OK;
1454 struct FTP *ftp = conn->data->req.protop;
1455 struct ftp_conn *ftpc = &conn->proto.ftpc;
1457 if((ftp->transfer != FTPTRANSFER_BODY) && ftpc->file) {
1458 /* if a "head"-like request is being made (on a file) */
1460 /* Determine if server can respond to REST command and therefore
1461 whether it supports range */
1462 PPSENDF(&conn->proto.ftpc.pp, "REST %d", 0);
1464 state(conn, FTP_REST);
1467 result = ftp_state_prepare_transfer(conn);
1472 static CURLcode ftp_state_size(struct connectdata *conn)
1474 CURLcode result = CURLE_OK;
1475 struct FTP *ftp = conn->data->req.protop;
1476 struct ftp_conn *ftpc = &conn->proto.ftpc;
1478 if((ftp->transfer == FTPTRANSFER_INFO) && ftpc->file) {
1479 /* if a "head"-like request is being made (on a file) */
1481 /* we know ftpc->file is a valid pointer to a file name */
1482 PPSENDF(&ftpc->pp, "SIZE %s", ftpc->file);
1484 state(conn, FTP_SIZE);
1487 result = ftp_state_rest(conn);
1492 static CURLcode ftp_state_list(struct connectdata *conn)
1494 CURLcode result = CURLE_OK;
1495 struct Curl_easy *data = conn->data;
1497 /* If this output is to be machine-parsed, the NLST command might be better
1498 to use, since the LIST command output is not specified or standard in any
1499 way. It has turned out that the NLST list output is not the same on all
1500 servers either... */
1503 if FTPFILE_NOCWD was specified, we are currently in
1504 the user's home directory, so we should add the path
1505 as argument for the LIST / NLST / or custom command.
1506 Whether the server will support this, is uncertain.
1508 The other ftp_filemethods will CWD into dir/dir/ first and
1509 then just do LIST (in that case: nothing to do here)
1511 char *cmd, *lstArg, *slashPos;
1514 if((data->set.ftp_filemethod == FTPFILE_NOCWD) &&
1516 data->state.path[0] &&
1517 strchr(data->state.path, '/')) {
1519 lstArg = strdup(data->state.path);
1521 return CURLE_OUT_OF_MEMORY;
1523 /* Check if path does not end with /, as then we cut off the file part */
1524 if(lstArg[strlen(lstArg) - 1] != '/') {
1526 /* chop off the file part if format is dir/dir/file */
1527 slashPos = strrchr(lstArg, '/');
1529 *(slashPos+1) = '\0';
1533 cmd = aprintf("%s%s%s",
1534 data->set.str[STRING_CUSTOMREQUEST]?
1535 data->set.str[STRING_CUSTOMREQUEST]:
1536 (data->set.ftp_list_only?"NLST":"LIST"),
1538 lstArg? lstArg: "");
1542 return CURLE_OUT_OF_MEMORY;
1545 result = Curl_pp_sendf(&conn->proto.ftpc.pp, "%s", cmd);
1553 state(conn, FTP_LIST);
1558 static CURLcode ftp_state_retr_prequote(struct connectdata *conn)
1560 CURLcode result = CURLE_OK;
1562 /* We've sent the TYPE, now we must send the list of prequote strings */
1564 result = ftp_state_quote(conn, TRUE, FTP_RETR_PREQUOTE);
1569 static CURLcode ftp_state_stor_prequote(struct connectdata *conn)
1571 CURLcode result = CURLE_OK;
1573 /* We've sent the TYPE, now we must send the list of prequote strings */
1575 result = ftp_state_quote(conn, TRUE, FTP_STOR_PREQUOTE);
1580 static CURLcode ftp_state_type(struct connectdata *conn)
1582 CURLcode result = CURLE_OK;
1583 struct FTP *ftp = conn->data->req.protop;
1584 struct Curl_easy *data = conn->data;
1585 struct ftp_conn *ftpc = &conn->proto.ftpc;
1587 /* If we have selected NOBODY and HEADER, it means that we only want file
1588 information. Which in FTP can't be much more than the file size and
1590 if(data->set.opt_no_body && ftpc->file &&
1591 ftp_need_type(conn, data->set.prefer_ascii)) {
1592 /* The SIZE command is _not_ RFC 959 specified, and therefor many servers
1593 may not support it! It is however the only way we have to get a file's
1596 ftp->transfer = FTPTRANSFER_INFO;
1597 /* this means no actual transfer will be made */
1599 /* Some servers return different sizes for different modes, and thus we
1600 must set the proper type before we check the size */
1601 result = ftp_nb_type(conn, data->set.prefer_ascii, FTP_TYPE);
1606 result = ftp_state_size(conn);
1611 /* This is called after the CWD commands have been done in the beginning of
1613 static CURLcode ftp_state_mdtm(struct connectdata *conn)
1615 CURLcode result = CURLE_OK;
1616 struct Curl_easy *data = conn->data;
1617 struct ftp_conn *ftpc = &conn->proto.ftpc;
1619 /* Requested time of file or time-depended transfer? */
1620 if((data->set.get_filetime || data->set.timecondition) && ftpc->file) {
1622 /* we have requested to get the modified-time of the file, this is a white
1623 spot as the MDTM is not mentioned in RFC959 */
1624 PPSENDF(&ftpc->pp, "MDTM %s", ftpc->file);
1626 state(conn, FTP_MDTM);
1629 result = ftp_state_type(conn);
1635 /* This is called after the TYPE and possible quote commands have been sent */
1636 static CURLcode ftp_state_ul_setup(struct connectdata *conn,
1639 CURLcode result = CURLE_OK;
1640 struct FTP *ftp = conn->data->req.protop;
1641 struct Curl_easy *data = conn->data;
1642 struct ftp_conn *ftpc = &conn->proto.ftpc;
1643 int seekerr = CURL_SEEKFUNC_OK;
1645 if((data->state.resume_from && !sizechecked) ||
1646 ((data->state.resume_from > 0) && sizechecked)) {
1647 /* we're about to continue the uploading of a file */
1648 /* 1. get already existing file's size. We use the SIZE command for this
1649 which may not exist in the server! The SIZE command is not in
1652 /* 2. This used to set REST. But since we can do append, we
1653 don't another ftp command. We just skip the source file
1654 offset and then we APPEND the rest on the file instead */
1656 /* 3. pass file-size number of bytes in the source file */
1657 /* 4. lower the infilesize counter */
1658 /* => transfer as usual */
1660 if(data->state.resume_from < 0) {
1661 /* Got no given size to start from, figure it out */
1662 PPSENDF(&ftpc->pp, "SIZE %s", ftpc->file);
1663 state(conn, FTP_STOR_SIZE);
1668 data->set.ftp_append = TRUE;
1670 /* Let's read off the proper amount of bytes from the input. */
1671 if(conn->seek_func) {
1672 seekerr = conn->seek_func(conn->seek_client, data->state.resume_from,
1676 if(seekerr != CURL_SEEKFUNC_OK) {
1677 if(seekerr != CURL_SEEKFUNC_CANTSEEK) {
1678 failf(data, "Could not seek stream");
1679 return CURLE_FTP_COULDNT_USE_REST;
1681 /* seekerr == CURL_SEEKFUNC_CANTSEEK (can't seek to offset) */
1683 curl_off_t passed=0;
1685 size_t readthisamountnow =
1686 (data->state.resume_from - passed > CURL_OFF_T_C(BUFSIZE)) ?
1687 BUFSIZE : curlx_sotouz(data->state.resume_from - passed);
1689 size_t actuallyread =
1690 data->state.fread_func(data->state.buffer, 1, readthisamountnow,
1693 passed += actuallyread;
1694 if((actuallyread == 0) || (actuallyread > readthisamountnow)) {
1695 /* this checks for greater-than only to make sure that the
1696 CURL_READFUNC_ABORT return code still aborts */
1697 failf(data, "Failed to read data");
1698 return CURLE_FTP_COULDNT_USE_REST;
1700 } while(passed < data->state.resume_from);
1703 /* now, decrease the size of the read */
1704 if(data->state.infilesize>0) {
1705 data->state.infilesize -= data->state.resume_from;
1707 if(data->state.infilesize <= 0) {
1708 infof(data, "File already completely uploaded\n");
1710 /* no data to transfer */
1711 Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
1713 /* Set ->transfer so that we won't get any error in
1714 * ftp_done() because we didn't transfer anything! */
1715 ftp->transfer = FTPTRANSFER_NONE;
1717 state(conn, FTP_STOP);
1721 /* we've passed, proceed as normal */
1724 PPSENDF(&ftpc->pp, data->set.ftp_append?"APPE %s":"STOR %s",
1727 state(conn, FTP_STOR);
1732 static CURLcode ftp_state_quote(struct connectdata *conn,
1736 CURLcode result = CURLE_OK;
1737 struct Curl_easy *data = conn->data;
1738 struct FTP *ftp = data->req.protop;
1739 struct ftp_conn *ftpc = &conn->proto.ftpc;
1741 struct curl_slist *item;
1746 item = data->set.quote;
1748 case FTP_RETR_PREQUOTE:
1749 case FTP_STOR_PREQUOTE:
1750 item = data->set.prequote;
1753 item = data->set.postquote;
1759 * 'count1' to iterate over the commands to send
1760 * 'count2' to store wether to allow commands to fail
1771 /* Skip count1 items in the linked list */
1772 while((i< ftpc->count1) && item) {
1777 char *cmd = item->data;
1780 ftpc->count2 = 1; /* the sent command is allowed to fail */
1783 ftpc->count2 = 0; /* failure means cancel operation */
1785 PPSENDF(&ftpc->pp, "%s", cmd);
1786 state(conn, instate);
1792 /* No more quote to send, continue to ... */
1796 result = ftp_state_cwd(conn);
1798 case FTP_RETR_PREQUOTE:
1799 if(ftp->transfer != FTPTRANSFER_BODY)
1800 state(conn, FTP_STOP);
1802 if(ftpc->known_filesize != -1) {
1803 Curl_pgrsSetDownloadSize(data, ftpc->known_filesize);
1804 result = ftp_state_retr(conn, ftpc->known_filesize);
1807 if(data->set.ignorecl) {
1808 /* This code is to support download of growing files. It prevents
1809 the state machine from requesting the file size from the
1810 server. With an unknown file size the download continues until
1811 the server terminates it, otherwise the client stops if the
1812 received byte count exceeds the reported file size. Set option
1813 CURLOPT_IGNORE_CONTENT_LENGTH to 1 to enable this behavior.*/
1814 PPSENDF(&ftpc->pp, "RETR %s", ftpc->file);
1815 state(conn, FTP_RETR);
1818 PPSENDF(&ftpc->pp, "SIZE %s", ftpc->file);
1819 state(conn, FTP_RETR_SIZE);
1824 case FTP_STOR_PREQUOTE:
1825 result = ftp_state_ul_setup(conn, FALSE);
1835 /* called from ftp_state_pasv_resp to switch to PASV in case of EPSV
1837 static CURLcode ftp_epsv_disable(struct connectdata *conn)
1839 CURLcode result = CURLE_OK;
1841 if(conn->bits.ipv6) {
1842 /* We can't disable EPSV when doing IPv6, so this is instead a fail */
1843 failf(conn->data, "Failed EPSV attempt, exiting\n");
1844 return CURLE_WEIRD_SERVER_REPLY;
1847 infof(conn->data, "Failed EPSV attempt. Disabling EPSV\n");
1848 /* disable it for next transfer */
1849 conn->bits.ftp_use_epsv = FALSE;
1850 conn->data->state.errorbuf = FALSE; /* allow error message to get
1852 PPSENDF(&conn->proto.ftpc.pp, "%s", "PASV");
1853 conn->proto.ftpc.count1++;
1854 /* remain in/go to the FTP_PASV state */
1855 state(conn, FTP_PASV);
1860 static char *control_address(struct connectdata *conn)
1862 /* Returns the control connection IP address.
1863 If a proxy tunnel is used, returns the original host name instead, because
1864 the effective control connection address is the proxy address,
1865 not the ftp host. */
1866 if(conn->bits.tunnel_proxy || conn->bits.socksproxy)
1867 return conn->host.name;
1869 return conn->ip_addr_str;
1872 static CURLcode ftp_state_pasv_resp(struct connectdata *conn,
1875 struct ftp_conn *ftpc = &conn->proto.ftpc;
1877 struct Curl_easy *data=conn->data;
1878 struct Curl_dns_entry *addr=NULL;
1880 unsigned short connectport; /* the local port connect() should use! */
1881 char *str=&data->state.buffer[4]; /* start on the first letter */
1883 /* if we come here again, make sure the former name is cleared */
1884 Curl_safefree(ftpc->newhost);
1886 if((ftpc->count1 == 0) &&
1888 /* positive EPSV response */
1889 char *ptr = strchr(str, '(');
1894 if(5 == sscanf(ptr, "%c%c%c%u%c",
1900 const char sep1 = separator[0];
1903 /* The four separators should be identical, or else this is an oddly
1904 formatted reply and we bail out immediately. */
1905 for(i=1; i<4; i++) {
1906 if(separator[i] != sep1) {
1907 ptr=NULL; /* set to NULL to signal error */
1912 failf(data, "Illegal port number in EPSV reply");
1913 return CURLE_FTP_WEIRD_PASV_REPLY;
1916 ftpc->newport = (unsigned short)(num & 0xffff);
1917 ftpc->newhost = strdup(control_address(conn));
1919 return CURLE_OUT_OF_MEMORY;
1926 failf(data, "Weirdly formatted EPSV reply");
1927 return CURLE_FTP_WEIRD_PASV_REPLY;
1930 else if((ftpc->count1 == 1) &&
1932 /* positive PASV response */
1937 * Scan for a sequence of six comma-separated numbers and use them as
1938 * IP+port indicators.
1940 * Found reply-strings include:
1941 * "227 Entering Passive Mode (127,0,0,1,4,51)"
1942 * "227 Data transfer will passively listen to 127,0,0,1,4,51"
1943 * "227 Entering passive mode. 127,0,0,1,4,51"
1946 if(6 == sscanf(str, "%d,%d,%d,%d,%d,%d",
1947 &ip[0], &ip[1], &ip[2], &ip[3],
1948 &port[0], &port[1]))
1954 failf(data, "Couldn't interpret the 227-response");
1955 return CURLE_FTP_WEIRD_227_FORMAT;
1958 /* we got OK from server */
1959 if(data->set.ftp_skip_ip) {
1960 /* told to ignore the remotely given IP but instead use the host we used
1961 for the control connection */
1962 infof(data, "Skip %d.%d.%d.%d for data connection, re-use %s instead\n",
1963 ip[0], ip[1], ip[2], ip[3],
1965 ftpc->newhost = strdup(control_address(conn));
1968 ftpc->newhost = aprintf("%d.%d.%d.%d", ip[0], ip[1], ip[2], ip[3]);
1971 return CURLE_OUT_OF_MEMORY;
1973 ftpc->newport = (unsigned short)(((port[0]<<8) + port[1]) & 0xffff);
1975 else if(ftpc->count1 == 0) {
1976 /* EPSV failed, move on to PASV */
1977 return ftp_epsv_disable(conn);
1980 failf(data, "Bad PASV/EPSV response: %03d", ftpcode);
1981 return CURLE_FTP_WEIRD_PASV_REPLY;
1984 if(conn->bits.proxy) {
1986 * This connection uses a proxy and we need to connect to the proxy again
1987 * here. We don't want to rely on a former host lookup that might've
1988 * expired now, instead we remake the lookup here and now!
1990 const char * const host_name = conn->bits.socksproxy ?
1991 conn->socks_proxy.host.name : conn->http_proxy.host.name;
1992 rc = Curl_resolv(conn, host_name, (int)conn->port, &addr);
1993 if(rc == CURLRESOLV_PENDING)
1994 /* BLOCKING, ignores the return code but 'addr' will be NULL in
1996 (void)Curl_resolver_wait_resolv(conn, &addr);
1999 (unsigned short)conn->port; /* we connect to the proxy's port */
2002 failf(data, "Can't resolve proxy host %s:%hu", host_name, connectport);
2003 return CURLE_COULDNT_RESOLVE_PROXY;
2007 /* normal, direct, ftp connection */
2008 rc = Curl_resolv(conn, ftpc->newhost, ftpc->newport, &addr);
2009 if(rc == CURLRESOLV_PENDING)
2011 (void)Curl_resolver_wait_resolv(conn, &addr);
2013 connectport = ftpc->newport; /* we connect to the remote port */
2016 failf(data, "Can't resolve new host %s:%hu", ftpc->newhost, connectport);
2017 return CURLE_FTP_CANT_GET_HOST;
2021 conn->bits.tcpconnect[SECONDARYSOCKET] = FALSE;
2022 result = Curl_connecthost(conn, addr);
2025 Curl_resolv_unlock(data, addr); /* we're done using this address */
2026 if(ftpc->count1 == 0 && ftpcode == 229)
2027 return ftp_epsv_disable(conn);
2034 * When this is used from the multi interface, this might've returned with
2035 * the 'connected' set to FALSE and thus we are now awaiting a non-blocking
2036 * connect to connect.
2039 if(data->set.verbose)
2040 /* this just dumps information about this second connection */
2041 ftp_pasv_verbose(conn, addr->addr, ftpc->newhost, connectport);
2043 Curl_safefree(conn->secondaryhostname);
2044 conn->secondaryhostname = strdup(ftpc->newhost);
2045 conn->secondary_port = ftpc->newport;
2047 Curl_resolv_unlock(data, addr); /* we're done using this address */
2048 conn->bits.do_more = TRUE;
2049 state(conn, FTP_STOP); /* this phase is completed */
2054 static CURLcode ftp_state_port_resp(struct connectdata *conn,
2057 struct Curl_easy *data = conn->data;
2058 struct ftp_conn *ftpc = &conn->proto.ftpc;
2059 ftpport fcmd = (ftpport)ftpc->count1;
2060 CURLcode result = CURLE_OK;
2062 /* The FTP spec tells a positive response should have code 200.
2063 Be more permissive here to tolerate deviant servers. */
2064 if(ftpcode / 100 != 2) {
2065 /* the command failed */
2068 infof(data, "disabling EPRT usage\n");
2069 conn->bits.ftp_use_eprt = FALSE;
2074 failf(data, "Failed to do PORT");
2075 result = CURLE_FTP_PORT_FAILED;
2079 result = ftp_state_use_port(conn, fcmd);
2082 infof(data, "Connect data stream actively\n");
2083 state(conn, FTP_STOP); /* end of DO phase */
2084 result = ftp_dophase_done(conn, FALSE);
2090 static CURLcode ftp_state_mdtm_resp(struct connectdata *conn,
2093 CURLcode result = CURLE_OK;
2094 struct Curl_easy *data=conn->data;
2095 struct FTP *ftp = data->req.protop;
2096 struct ftp_conn *ftpc = &conn->proto.ftpc;
2101 /* we got a time. Format should be: "YYYYMMDDHHMMSS[.sss]" where the
2102 last .sss part is optional and means fractions of a second */
2103 int year, month, day, hour, minute, second;
2104 char *buf = data->state.buffer;
2105 if(6 == sscanf(buf+4, "%04d%02d%02d%02d%02d%02d",
2106 &year, &month, &day, &hour, &minute, &second)) {
2107 /* we have a time, reformat it */
2108 time_t secs=time(NULL);
2109 /* using the good old yacc/bison yuck */
2110 snprintf(buf, CURL_BUFSIZE(conn->data->set.buffer_size),
2111 "%04d%02d%02d %02d:%02d:%02d GMT",
2112 year, month, day, hour, minute, second);
2113 /* now, convert this into a time() value: */
2114 data->info.filetime = (long)curl_getdate(buf, &secs);
2117 #ifdef CURL_FTP_HTTPSTYLE_HEAD
2118 /* If we asked for a time of the file and we actually got one as well,
2119 we "emulate" a HTTP-style header in our output. */
2121 if(data->set.opt_no_body &&
2123 data->set.get_filetime &&
2124 (data->info.filetime>=0) ) {
2125 time_t filetime = (time_t)data->info.filetime;
2127 const struct tm *tm = &buffer;
2129 result = Curl_gmtime(filetime, &buffer);
2133 /* format: "Tue, 15 Nov 1994 12:45:26" */
2134 snprintf(buf, BUFSIZE-1,
2135 "Last-Modified: %s, %02d %s %4d %02d:%02d:%02d GMT\r\n",
2136 Curl_wkday[tm->tm_wday?tm->tm_wday-1:6],
2138 Curl_month[tm->tm_mon],
2143 result = Curl_client_write(conn, CLIENTWRITE_BOTH, buf, 0);
2146 } /* end of a ridiculous amount of conditionals */
2151 infof(data, "unsupported MDTM reply format\n");
2153 case 550: /* "No such file or directory" */
2154 failf(data, "Given file does not exist");
2155 result = CURLE_FTP_COULDNT_RETR_FILE;
2159 if(data->set.timecondition) {
2160 if((data->info.filetime > 0) && (data->set.timevalue > 0)) {
2161 switch(data->set.timecondition) {
2162 case CURL_TIMECOND_IFMODSINCE:
2164 if(data->info.filetime <= data->set.timevalue) {
2165 infof(data, "The requested document is not new enough\n");
2166 ftp->transfer = FTPTRANSFER_NONE; /* mark to not transfer data */
2167 data->info.timecond = TRUE;
2168 state(conn, FTP_STOP);
2172 case CURL_TIMECOND_IFUNMODSINCE:
2173 if(data->info.filetime > data->set.timevalue) {
2174 infof(data, "The requested document is not old enough\n");
2175 ftp->transfer = FTPTRANSFER_NONE; /* mark to not transfer data */
2176 data->info.timecond = TRUE;
2177 state(conn, FTP_STOP);
2184 infof(data, "Skipping time comparison\n");
2189 result = ftp_state_type(conn);
2194 static CURLcode ftp_state_type_resp(struct connectdata *conn,
2198 CURLcode result = CURLE_OK;
2199 struct Curl_easy *data=conn->data;
2201 if(ftpcode/100 != 2) {
2202 /* "sasserftpd" and "(u)r(x)bot ftpd" both responds with 226 after a
2203 successful 'TYPE I'. While that is not as RFC959 says, it is still a
2204 positive response code and we allow that. */
2205 failf(data, "Couldn't set desired mode");
2206 return CURLE_FTP_COULDNT_SET_TYPE;
2209 infof(data, "Got a %03d response code instead of the assumed 200\n",
2212 if(instate == FTP_TYPE)
2213 result = ftp_state_size(conn);
2214 else if(instate == FTP_LIST_TYPE)
2215 result = ftp_state_list(conn);
2216 else if(instate == FTP_RETR_TYPE)
2217 result = ftp_state_retr_prequote(conn);
2218 else if(instate == FTP_STOR_TYPE)
2219 result = ftp_state_stor_prequote(conn);
2224 static CURLcode ftp_state_retr(struct connectdata *conn,
2225 curl_off_t filesize)
2227 CURLcode result = CURLE_OK;
2228 struct Curl_easy *data=conn->data;
2229 struct FTP *ftp = data->req.protop;
2230 struct ftp_conn *ftpc = &conn->proto.ftpc;
2232 if(data->set.max_filesize && (filesize > data->set.max_filesize)) {
2233 failf(data, "Maximum file size exceeded");
2234 return CURLE_FILESIZE_EXCEEDED;
2236 ftp->downloadsize = filesize;
2238 if(data->state.resume_from) {
2239 /* We always (attempt to) get the size of downloads, so it is done before
2240 this even when not doing resumes. */
2241 if(filesize == -1) {
2242 infof(data, "ftp server doesn't support SIZE\n");
2243 /* We couldn't get the size and therefore we can't know if there really
2244 is a part of the file left to get, although the server will just
2245 close the connection when we start the connection so it won't cause
2246 us any harm, just not make us exit as nicely. */
2249 /* We got a file size report, so we check that there actually is a
2250 part of the file left to get, or else we go home. */
2251 if(data->state.resume_from< 0) {
2252 /* We're supposed to download the last abs(from) bytes */
2253 if(filesize < -data->state.resume_from) {
2254 failf(data, "Offset (%" CURL_FORMAT_CURL_OFF_T
2255 ") was beyond file size (%" CURL_FORMAT_CURL_OFF_T ")",
2256 data->state.resume_from, filesize);
2257 return CURLE_BAD_DOWNLOAD_RESUME;
2259 /* convert to size to download */
2260 ftp->downloadsize = -data->state.resume_from;
2261 /* download from where? */
2262 data->state.resume_from = filesize - ftp->downloadsize;
2265 if(filesize < data->state.resume_from) {
2266 failf(data, "Offset (%" CURL_FORMAT_CURL_OFF_T
2267 ") was beyond file size (%" CURL_FORMAT_CURL_OFF_T ")",
2268 data->state.resume_from, filesize);
2269 return CURLE_BAD_DOWNLOAD_RESUME;
2271 /* Now store the number of bytes we are expected to download */
2272 ftp->downloadsize = filesize-data->state.resume_from;
2276 if(ftp->downloadsize == 0) {
2277 /* no data to transfer */
2278 Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
2279 infof(data, "File already completely downloaded\n");
2281 /* Set ->transfer so that we won't get any error in ftp_done()
2282 * because we didn't transfer the any file */
2283 ftp->transfer = FTPTRANSFER_NONE;
2284 state(conn, FTP_STOP);
2288 /* Set resume file transfer offset */
2289 infof(data, "Instructs server to resume from offset %"
2290 CURL_FORMAT_CURL_OFF_T "\n", data->state.resume_from);
2292 PPSENDF(&ftpc->pp, "REST %" CURL_FORMAT_CURL_OFF_T,
2293 data->state.resume_from);
2295 state(conn, FTP_RETR_REST);
2299 PPSENDF(&ftpc->pp, "RETR %s", ftpc->file);
2300 state(conn, FTP_RETR);
2306 static CURLcode ftp_state_size_resp(struct connectdata *conn,
2310 CURLcode result = CURLE_OK;
2311 struct Curl_easy *data=conn->data;
2312 curl_off_t filesize;
2313 char *buf = data->state.buffer;
2315 /* get the size from the ascii string: */
2316 filesize = (ftpcode == 213)?curlx_strtoofft(buf+4, NULL, 0):-1;
2318 if(instate == FTP_SIZE) {
2319 #ifdef CURL_FTP_HTTPSTYLE_HEAD
2320 if(-1 != filesize) {
2321 snprintf(buf, CURL_BUFSIZE(data->set.buffer_size),
2322 "Content-Length: %" CURL_FORMAT_CURL_OFF_T "\r\n", filesize);
2323 result = Curl_client_write(conn, CLIENTWRITE_BOTH, buf, 0);
2328 Curl_pgrsSetDownloadSize(data, filesize);
2329 result = ftp_state_rest(conn);
2331 else if(instate == FTP_RETR_SIZE) {
2332 Curl_pgrsSetDownloadSize(data, filesize);
2333 result = ftp_state_retr(conn, filesize);
2335 else if(instate == FTP_STOR_SIZE) {
2336 data->state.resume_from = filesize;
2337 result = ftp_state_ul_setup(conn, TRUE);
2343 static CURLcode ftp_state_rest_resp(struct connectdata *conn,
2347 CURLcode result = CURLE_OK;
2348 struct ftp_conn *ftpc = &conn->proto.ftpc;
2353 #ifdef CURL_FTP_HTTPSTYLE_HEAD
2354 if(ftpcode == 350) {
2355 char buffer[24]= { "Accept-ranges: bytes\r\n" };
2356 result = Curl_client_write(conn, CLIENTWRITE_BOTH, buffer, 0);
2361 result = ftp_state_prepare_transfer(conn);
2365 if(ftpcode != 350) {
2366 failf(conn->data, "Couldn't use REST");
2367 result = CURLE_FTP_COULDNT_USE_REST;
2370 PPSENDF(&ftpc->pp, "RETR %s", ftpc->file);
2371 state(conn, FTP_RETR);
2379 static CURLcode ftp_state_stor_resp(struct connectdata *conn,
2380 int ftpcode, ftpstate instate)
2382 CURLcode result = CURLE_OK;
2383 struct Curl_easy *data = conn->data;
2386 failf(data, "Failed FTP upload: %0d", ftpcode);
2387 state(conn, FTP_STOP);
2388 /* oops, we never close the sockets! */
2389 return CURLE_UPLOAD_FAILED;
2392 conn->proto.ftpc.state_saved = instate;
2394 /* PORT means we are now awaiting the server to connect to us. */
2395 if(data->set.ftp_use_port) {
2398 state(conn, FTP_STOP); /* no longer in STOR state */
2400 result = AllowServerConnect(conn, &connected);
2405 struct ftp_conn *ftpc = &conn->proto.ftpc;
2406 infof(data, "Data conn was not available immediately\n");
2407 ftpc->wait_data_conn = TRUE;
2413 return InitiateTransfer(conn);
2416 /* for LIST and RETR responses */
2417 static CURLcode ftp_state_get_resp(struct connectdata *conn,
2421 CURLcode result = CURLE_OK;
2422 struct Curl_easy *data = conn->data;
2423 struct FTP *ftp = data->req.protop;
2424 char *buf = data->state.buffer;
2426 if((ftpcode == 150) || (ftpcode == 125)) {
2430 150 Opening BINARY mode data connection for /etc/passwd (2241
2431 bytes). (ok, the file is being transferred)
2434 150 Opening ASCII mode data connection for /bin/ls
2437 150 ASCII data connection for /bin/ls (137.167.104.91,37445) (0 bytes).
2440 150 Opening ASCII mode data connection for [file] (0.0.0.0,0) (545 bytes)
2443 125 Data connection already open; Transfer starting. */
2445 curl_off_t size=-1; /* default unknown size */
2449 * It appears that there are FTP-servers that return size 0 for files when
2450 * SIZE is used on the file while being in BINARY mode. To work around
2451 * that (stupid) behavior, we attempt to parse the RETR response even if
2452 * the SIZE returned size zero.
2454 * Debugging help from Salvatore Sorrentino on February 26, 2003.
2457 if((instate != FTP_LIST) &&
2458 !data->set.prefer_ascii &&
2459 (ftp->downloadsize < 1)) {
2461 * It seems directory listings either don't show the size or very
2462 * often uses size 0 anyway. ASCII transfers may very well turn out
2463 * that the transferred amount of data is not the same as this line
2464 * tells, why using this number in those cases only confuses us.
2466 * Example D above makes this parsing a little tricky */
2468 bytes=strstr(buf, " bytes");
2470 long in=(long)(bytes-buf);
2471 /* this is a hint there is size information in there! ;-) */
2473 /* scan for the left parenthesis and break there */
2476 /* skip only digits */
2477 if(!ISDIGIT(*bytes)) {
2481 /* one more estep backwards */
2484 /* if we have nothing but digits: */
2486 /* get the number! */
2487 size = curlx_strtoofft(bytes, NULL, 0);
2491 else if(ftp->downloadsize > -1)
2492 size = ftp->downloadsize;
2494 if(size > data->req.maxdownload && data->req.maxdownload > 0)
2495 size = data->req.size = data->req.maxdownload;
2496 else if((instate != FTP_LIST) && (data->set.prefer_ascii))
2497 size = -1; /* kludge for servers that understate ASCII mode file size */
2499 infof(data, "Maxdownload = %" CURL_FORMAT_CURL_OFF_T "\n",
2500 data->req.maxdownload);
2502 if(instate != FTP_LIST)
2503 infof(data, "Getting file with size: %" CURL_FORMAT_CURL_OFF_T "\n",
2507 conn->proto.ftpc.state_saved = instate;
2508 conn->proto.ftpc.retr_size_saved = size;
2510 if(data->set.ftp_use_port) {
2513 result = AllowServerConnect(conn, &connected);
2518 struct ftp_conn *ftpc = &conn->proto.ftpc;
2519 infof(data, "Data conn was not available immediately\n");
2520 state(conn, FTP_STOP);
2521 ftpc->wait_data_conn = TRUE;
2525 return InitiateTransfer(conn);
2528 if((instate == FTP_LIST) && (ftpcode == 450)) {
2529 /* simply no matching files in the dir listing */
2530 ftp->transfer = FTPTRANSFER_NONE; /* don't download anything */
2531 state(conn, FTP_STOP); /* this phase is over */
2534 failf(data, "RETR response: %03d", ftpcode);
2535 return instate == FTP_RETR && ftpcode == 550?
2536 CURLE_REMOTE_FILE_NOT_FOUND:
2537 CURLE_FTP_COULDNT_RETR_FILE;
2544 /* after USER, PASS and ACCT */
2545 static CURLcode ftp_state_loggedin(struct connectdata *conn)
2547 CURLcode result = CURLE_OK;
2549 if(conn->ssl[FIRSTSOCKET].use) {
2550 /* PBSZ = PROTECTION BUFFER SIZE.
2552 The 'draft-murray-auth-ftp-ssl' (draft 12, page 7) says:
2554 Specifically, the PROT command MUST be preceded by a PBSZ
2555 command and a PBSZ command MUST be preceded by a successful
2556 security data exchange (the TLS negotiation in this case)
2558 ... (and on page 8):
2560 Thus the PBSZ command must still be issued, but must have a
2561 parameter of '0' to indicate that no buffering is taking place
2562 and the data connection should not be encapsulated.
2564 PPSENDF(&conn->proto.ftpc.pp, "PBSZ %d", 0);
2565 state(conn, FTP_PBSZ);
2568 result = ftp_state_pwd(conn);
2573 /* for USER and PASS responses */
2574 static CURLcode ftp_state_user_resp(struct connectdata *conn,
2578 CURLcode result = CURLE_OK;
2579 struct Curl_easy *data = conn->data;
2580 struct FTP *ftp = data->req.protop;
2581 struct ftp_conn *ftpc = &conn->proto.ftpc;
2582 (void)instate; /* no use for this yet */
2584 /* some need password anyway, and others just return 2xx ignored */
2585 if((ftpcode == 331) && (ftpc->state == FTP_USER)) {
2586 /* 331 Password required for ...
2587 (the server requires to send the user's password too) */
2588 PPSENDF(&ftpc->pp, "PASS %s", ftp->passwd?ftp->passwd:"");
2589 state(conn, FTP_PASS);
2591 else if(ftpcode/100 == 2) {
2592 /* 230 User ... logged in.
2593 (the user logged in with or without password) */
2594 result = ftp_state_loggedin(conn);
2596 else if(ftpcode == 332) {
2597 if(data->set.str[STRING_FTP_ACCOUNT]) {
2598 PPSENDF(&ftpc->pp, "ACCT %s", data->set.str[STRING_FTP_ACCOUNT]);
2599 state(conn, FTP_ACCT);
2602 failf(data, "ACCT requested but none available");
2603 result = CURLE_LOGIN_DENIED;
2607 /* All other response codes, like:
2609 530 User ... access denied
2610 (the server denies to log the specified user) */
2612 if(conn->data->set.str[STRING_FTP_ALTERNATIVE_TO_USER] &&
2613 !conn->data->state.ftp_trying_alternative) {
2614 /* Ok, USER failed. Let's try the supplied command. */
2615 PPSENDF(&conn->proto.ftpc.pp, "%s",
2616 conn->data->set.str[STRING_FTP_ALTERNATIVE_TO_USER]);
2617 conn->data->state.ftp_trying_alternative = TRUE;
2618 state(conn, FTP_USER);
2622 failf(data, "Access denied: %03d", ftpcode);
2623 result = CURLE_LOGIN_DENIED;
2629 /* for ACCT response */
2630 static CURLcode ftp_state_acct_resp(struct connectdata *conn,
2633 CURLcode result = CURLE_OK;
2634 struct Curl_easy *data = conn->data;
2635 if(ftpcode != 230) {
2636 failf(data, "ACCT rejected by server: %03d", ftpcode);
2637 result = CURLE_FTP_WEIRD_PASS_REPLY; /* FIX */
2640 result = ftp_state_loggedin(conn);
2646 static CURLcode ftp_statemach_act(struct connectdata *conn)
2649 curl_socket_t sock = conn->sock[FIRSTSOCKET];
2650 struct Curl_easy *data=conn->data;
2652 struct ftp_conn *ftpc = &conn->proto.ftpc;
2653 struct pingpong *pp = &ftpc->pp;
2654 static const char ftpauth[][4] = { "SSL", "TLS" };
2658 return Curl_pp_flushsend(pp);
2660 result = ftp_readresp(sock, pp, &ftpcode, &nread);
2665 /* we have now received a full FTP server response */
2666 switch(ftpc->state) {
2669 /* 230 User logged in - already! */
2670 return ftp_state_user_resp(conn, ftpcode, ftpc->state);
2671 else if(ftpcode != 220) {
2672 failf(data, "Got a %03d ftp-server response when 220 was expected",
2674 return CURLE_WEIRD_SERVER_REPLY;
2677 /* We have received a 220 response fine, now we proceed. */
2680 /* If not anonymous login, try a secure login. Note that this
2681 procedure is still BLOCKING. */
2683 Curl_sec_request_prot(conn, "private");
2684 /* We set private first as default, in case the line below fails to
2685 set a valid level */
2686 Curl_sec_request_prot(conn, data->set.str[STRING_KRB_LEVEL]);
2688 if(Curl_sec_login(conn))
2689 infof(data, "Logging in with password in cleartext!\n");
2691 infof(data, "Authentication successful\n");
2695 if(data->set.use_ssl &&
2696 (!conn->ssl[FIRSTSOCKET].use ||
2697 (conn->bits.proxy_ssl_connected[FIRSTSOCKET] &&
2698 !conn->proxy_ssl[FIRSTSOCKET].use))) {
2699 /* We don't have a SSL/TLS connection yet, but FTPS is
2700 requested. Try a FTPS connection now */
2703 switch(data->set.ftpsslauth) {
2704 case CURLFTPAUTH_DEFAULT:
2705 case CURLFTPAUTH_SSL:
2706 ftpc->count2 = 1; /* add one to get next */
2709 case CURLFTPAUTH_TLS:
2710 ftpc->count2 = -1; /* subtract one to get next */
2714 failf(data, "unsupported parameter to CURLOPT_FTPSSLAUTH: %d",
2715 (int)data->set.ftpsslauth);
2716 return CURLE_UNKNOWN_OPTION; /* we don't know what to do */
2718 PPSENDF(&ftpc->pp, "AUTH %s", ftpauth[ftpc->count1]);
2719 state(conn, FTP_AUTH);
2722 result = ftp_state_user(conn);
2730 /* we have gotten the response to a previous AUTH command */
2732 /* RFC2228 (page 5) says:
2734 * If the server is willing to accept the named security mechanism,
2735 * and does not require any security data, it must respond with
2736 * reply code 234/334.
2739 if((ftpcode == 234) || (ftpcode == 334)) {
2740 /* Curl_ssl_connect is BLOCKING */
2741 result = Curl_ssl_connect(conn, FIRSTSOCKET);
2743 conn->bits.ftp_use_data_ssl = FALSE; /* clear-text data */
2744 result = ftp_state_user(conn);
2747 else if(ftpc->count3 < 1) {
2749 ftpc->count1 += ftpc->count2; /* get next attempt */
2750 result = Curl_pp_sendf(&ftpc->pp, "AUTH %s", ftpauth[ftpc->count1]);
2751 /* remain in this same state */
2754 if(data->set.use_ssl > CURLUSESSL_TRY)
2755 /* we failed and CURLUSESSL_CONTROL or CURLUSESSL_ALL is set */
2756 result = CURLE_USE_SSL_FAILED;
2758 /* ignore the failure and continue */
2759 result = ftp_state_user(conn);
2768 result = ftp_state_user_resp(conn, ftpcode, ftpc->state);
2772 result = ftp_state_acct_resp(conn, ftpcode);
2776 PPSENDF(&ftpc->pp, "PROT %c",
2777 data->set.use_ssl == CURLUSESSL_CONTROL ? 'C' : 'P');
2778 state(conn, FTP_PROT);
2783 if(ftpcode/100 == 2)
2784 /* We have enabled SSL for the data connection! */
2785 conn->bits.ftp_use_data_ssl =
2786 (data->set.use_ssl != CURLUSESSL_CONTROL) ? TRUE : FALSE;
2787 /* FTP servers typically responds with 500 if they decide to reject
2789 else if(data->set.use_ssl > CURLUSESSL_CONTROL)
2790 /* we failed and bails out */
2791 return CURLE_USE_SSL_FAILED;
2793 if(data->set.ftp_ccc) {
2794 /* CCC - Clear Command Channel
2796 PPSENDF(&ftpc->pp, "%s", "CCC");
2797 state(conn, FTP_CCC);
2800 result = ftp_state_pwd(conn);
2808 /* First shut down the SSL layer (note: this call will block) */
2809 result = Curl_ssl_shutdown(conn, FIRSTSOCKET);
2812 failf(conn->data, "Failed to clear the command channel (CCC)");
2817 /* Then continue as normal */
2818 result = ftp_state_pwd(conn);
2824 if(ftpcode == 257) {
2825 char *ptr=&data->state.buffer[4]; /* start on the first letter */
2826 const size_t buf_size = CURL_BUFSIZE(data->set.buffer_size);
2830 dir = malloc(nread + 1);
2832 return CURLE_OUT_OF_MEMORY;
2834 /* Reply format is like
2835 257<space>[rubbish]"<directory-name>"<space><commentary> and the
2838 The directory name can contain any character; embedded
2839 double-quotes should be escaped by double-quotes (the
2840 "quote-doubling" convention).
2843 /* scan for the first double-quote for non-standard responses */
2844 while(ptr < &data->state.buffer[buf_size]
2845 && *ptr != '\n' && *ptr != '\0' && *ptr != '"')
2849 /* it started good */
2851 for(store = dir; *ptr;) {
2853 if('\"' == ptr[1]) {
2854 /* "quote-doubling" */
2860 *store = '\0'; /* zero terminate */
2861 break; /* get out of this loop */
2870 /* If the path name does not look like an absolute path (i.e.: it
2871 does not start with a '/'), we probably need some server-dependent
2872 adjustments. For example, this is the case when connecting to
2873 an OS400 FTP server: this server supports two name syntaxes,
2874 the default one being incompatible with standard pathes. In
2875 addition, this server switches automatically to the regular path
2876 syntax when one is encountered in a command: this results in
2877 having an entrypath in the wrong syntax when later used in CWD.
2878 The method used here is to check the server OS: we do it only
2879 if the path name looks strange to minimize overhead on other
2882 if(!ftpc->server_os && dir[0] != '/') {
2884 result = Curl_pp_sendf(&ftpc->pp, "%s", "SYST");
2889 Curl_safefree(ftpc->entrypath);
2890 ftpc->entrypath = dir; /* remember this */
2891 infof(data, "Entry path is '%s'\n", ftpc->entrypath);
2892 /* also save it where getinfo can access it: */
2893 data->state.most_recent_ftp_entrypath = ftpc->entrypath;
2894 state(conn, FTP_SYST);
2898 Curl_safefree(ftpc->entrypath);
2899 ftpc->entrypath = dir; /* remember this */
2900 infof(data, "Entry path is '%s'\n", ftpc->entrypath);
2901 /* also save it where getinfo can access it: */
2902 data->state.most_recent_ftp_entrypath = ftpc->entrypath;
2905 /* couldn't get the path */
2907 infof(data, "Failed to figure out path\n");
2910 state(conn, FTP_STOP); /* we are done with the CONNECT phase! */
2911 DEBUGF(infof(data, "protocol connect phase DONE\n"));
2915 if(ftpcode == 215) {
2916 char *ptr=&data->state.buffer[4]; /* start on the first letter */
2920 os = malloc(nread + 1);
2922 return CURLE_OUT_OF_MEMORY;
2924 /* Reply format is like
2925 215<space><OS-name><space><commentary>
2929 for(store = os; *ptr && *ptr != ' ';)
2931 *store = '\0'; /* zero terminate */
2933 /* Check for special servers here. */
2935 if(strcasecompare(os, "OS/400")) {
2936 /* Force OS400 name format 1. */
2937 result = Curl_pp_sendf(&ftpc->pp, "%s", "SITE NAMEFMT 1");
2942 /* remember target server OS */
2943 Curl_safefree(ftpc->server_os);
2944 ftpc->server_os = os;
2945 state(conn, FTP_NAMEFMT);
2949 /* Nothing special for the target server. */
2950 /* remember target server OS */
2951 Curl_safefree(ftpc->server_os);
2952 ftpc->server_os = os;
2956 /* Cannot identify server OS. Continue anyway and cross fingers. */
2959 state(conn, FTP_STOP); /* we are done with the CONNECT phase! */
2960 DEBUGF(infof(data, "protocol connect phase DONE\n"));
2964 if(ftpcode == 250) {
2965 /* Name format change successful: reload initial path. */
2966 ftp_state_pwd(conn);
2970 state(conn, FTP_STOP); /* we are done with the CONNECT phase! */
2971 DEBUGF(infof(data, "protocol connect phase DONE\n"));
2976 case FTP_RETR_PREQUOTE:
2977 case FTP_STOR_PREQUOTE:
2978 if((ftpcode >= 400) && !ftpc->count2) {
2979 /* failure response code, and not allowed to fail */
2980 failf(conn->data, "QUOT command failed with %03d", ftpcode);
2981 return CURLE_QUOTE_ERROR;
2983 result = ftp_state_quote(conn, FALSE, ftpc->state);
2990 if(ftpcode/100 != 2) {
2991 /* failure to CWD there */
2992 if(conn->data->set.ftp_create_missing_dirs &&
2993 ftpc->count1 && !ftpc->count2) {
2995 ftpc->count2++; /* counter to prevent CWD-MKD loops */
2996 PPSENDF(&ftpc->pp, "MKD %s", ftpc->dirs[ftpc->count1 - 1]);
2997 state(conn, FTP_MKD);
3000 /* return failure */
3001 failf(data, "Server denied you to change to the given directory");
3002 ftpc->cwdfail = TRUE; /* don't remember this path as we failed
3004 return CURLE_REMOTE_ACCESS_DENIED;
3010 if(++ftpc->count1 <= ftpc->dirdepth) {
3012 PPSENDF(&ftpc->pp, "CWD %s", ftpc->dirs[ftpc->count1 - 1]);
3015 result = ftp_state_mdtm(conn);
3023 if((ftpcode/100 != 2) && !ftpc->count3--) {
3024 /* failure to MKD the dir */
3025 failf(data, "Failed to MKD dir: %03d", ftpcode);
3026 return CURLE_REMOTE_ACCESS_DENIED;
3028 state(conn, FTP_CWD);
3030 PPSENDF(&ftpc->pp, "CWD %s", ftpc->dirs[ftpc->count1 - 1]);
3034 result = ftp_state_mdtm_resp(conn, ftpcode);
3041 result = ftp_state_type_resp(conn, ftpcode, ftpc->state);
3047 result = ftp_state_size_resp(conn, ftpcode, ftpc->state);
3052 result = ftp_state_rest_resp(conn, ftpcode, ftpc->state);
3056 if(ftpcode != 200) {
3057 /* there only is this one standard OK return code. */
3058 failf(data, "PRET command not accepted: %03d", ftpcode);
3059 return CURLE_FTP_PRET_FAILED;
3061 result = ftp_state_use_pasv(conn);
3065 result = ftp_state_pasv_resp(conn, ftpcode);
3069 result = ftp_state_port_resp(conn, ftpcode);
3074 result = ftp_state_get_resp(conn, ftpcode, ftpc->state);
3078 result = ftp_state_stor_resp(conn, ftpcode, ftpc->state);
3082 /* fallthrough, just stop! */
3084 /* internal error */
3085 state(conn, FTP_STOP);
3094 /* called repeatedly until done from multi.c */
3095 static CURLcode ftp_multi_statemach(struct connectdata *conn,
3098 struct ftp_conn *ftpc = &conn->proto.ftpc;
3099 CURLcode result = Curl_pp_statemach(&ftpc->pp, FALSE);
3101 /* Check for the state outside of the Curl_socket_check() return code checks
3102 since at times we are in fact already in this state when this function
3104 *done = (ftpc->state == FTP_STOP) ? TRUE : FALSE;
3109 static CURLcode ftp_block_statemach(struct connectdata *conn)
3111 struct ftp_conn *ftpc = &conn->proto.ftpc;
3112 struct pingpong *pp = &ftpc->pp;
3113 CURLcode result = CURLE_OK;
3115 while(ftpc->state != FTP_STOP) {
3116 result = Curl_pp_statemach(pp, TRUE);
3125 * ftp_connect() should do everything that is to be considered a part of
3126 * the connection phase.
3128 * The variable 'done' points to will be TRUE if the protocol-layer connect
3129 * phase is done when this function returns, or FALSE if not.
3132 static CURLcode ftp_connect(struct connectdata *conn,
3133 bool *done) /* see description above */
3136 struct ftp_conn *ftpc = &conn->proto.ftpc;
3137 struct pingpong *pp = &ftpc->pp;
3139 *done = FALSE; /* default to not done yet */
3141 /* We always support persistent connections on ftp */
3142 connkeep(conn, "FTP default");
3144 pp->response_time = RESP_TIMEOUT; /* set default response time-out */
3145 pp->statemach_act = ftp_statemach_act;
3146 pp->endofresp = ftp_endofresp;
3149 if(conn->handler->flags & PROTOPT_SSL) {
3151 result = Curl_ssl_connect(conn, FIRSTSOCKET);
3156 Curl_pp_init(pp); /* init the generic pingpong data */
3158 /* When we connect, we start in the state where we await the 220
3160 state(conn, FTP_WAIT220);
3162 result = ftp_multi_statemach(conn, done);
3167 /***********************************************************************
3171 * The DONE function. This does what needs to be done after a single DO has
3174 * Input argument is already checked for validity.
3176 static CURLcode ftp_done(struct connectdata *conn, CURLcode status,
3179 struct Curl_easy *data = conn->data;
3180 struct FTP *ftp = data->req.protop;
3181 struct ftp_conn *ftpc = &conn->proto.ftpc;
3182 struct pingpong *pp = &ftpc->pp;
3185 CURLcode result = CURLE_OK;
3187 const char *path_to_use = data->state.path;
3193 case CURLE_BAD_DOWNLOAD_RESUME:
3194 case CURLE_FTP_WEIRD_PASV_REPLY:
3195 case CURLE_FTP_PORT_FAILED:
3196 case CURLE_FTP_ACCEPT_FAILED:
3197 case CURLE_FTP_ACCEPT_TIMEOUT:
3198 case CURLE_FTP_COULDNT_SET_TYPE:
3199 case CURLE_FTP_COULDNT_RETR_FILE:
3200 case CURLE_PARTIAL_FILE:
3201 case CURLE_UPLOAD_FAILED:
3202 case CURLE_REMOTE_ACCESS_DENIED:
3203 case CURLE_FILESIZE_EXCEEDED:
3204 case CURLE_REMOTE_FILE_NOT_FOUND:
3205 case CURLE_WRITE_ERROR:
3206 /* the connection stays alive fine even though this happened */
3208 case CURLE_OK: /* doesn't affect the control connection's status */
3212 /* until we cope better with prematurely ended requests, let them
3213 * fallback as if in complete failure */
3214 default: /* by default, an error means the control connection is
3215 wedged and should not be used anymore */
3216 ftpc->ctl_valid = FALSE;
3217 ftpc->cwdfail = TRUE; /* set this TRUE to prevent us to remember the
3218 current path, as this connection is going */
3219 connclose(conn, "FTP ended with bad error code");
3220 result = status; /* use the already set error code */
3224 /* now store a copy of the directory we are in */
3225 free(ftpc->prevpath);
3227 if(data->set.wildcardmatch) {
3228 if(data->set.chunk_end && ftpc->file) {
3229 data->set.chunk_end(data->wildcard.customptr);
3231 ftpc->known_filesize = -1;
3235 /* get the "raw" path */
3236 result = Curl_urldecode(data, path_to_use, 0, &path, NULL, FALSE);
3238 /* We can limp along anyway (and should try to since we may already be in
3239 * the error path) */
3240 ftpc->ctl_valid = FALSE; /* mark control connection as bad */
3241 connclose(conn, "FTP: out of memory!"); /* mark for connection closure */
3242 ftpc->prevpath = NULL; /* no path remembering */
3245 size_t flen = ftpc->file?strlen(ftpc->file):0; /* file is "raw" already */
3246 size_t dlen = strlen(path)-flen;
3247 if(!ftpc->cwdfail) {
3248 if(dlen && (data->set.ftp_filemethod != FTPFILE_NOCWD)) {
3249 ftpc->prevpath = path;
3251 /* if 'path' is not the whole string */
3252 ftpc->prevpath[dlen]=0; /* terminate */
3255 /* we never changed dir */
3256 ftpc->prevpath=strdup("");
3260 infof(data, "Remembering we are in dir \"%s\"\n", ftpc->prevpath);
3263 ftpc->prevpath = NULL; /* no path */
3267 /* free the dir tree and file parts */
3270 /* shut down the socket to inform the server we're done */
3273 shutdown(conn->sock[SECONDARYSOCKET], 2); /* SD_BOTH */
3276 if(conn->sock[SECONDARYSOCKET] != CURL_SOCKET_BAD) {
3277 if(!result && ftpc->dont_check && data->req.maxdownload > 0) {
3278 /* partial download completed */
3279 result = Curl_pp_sendf(pp, "%s", "ABOR");
3281 failf(data, "Failure sending ABOR command: %s",
3282 curl_easy_strerror(result));
3283 ftpc->ctl_valid = FALSE; /* mark control connection as bad */
3284 connclose(conn, "ABOR command failed"); /* connection closure */
3288 if(conn->ssl[SECONDARYSOCKET].use) {
3289 /* The secondary socket is using SSL so we must close down that part
3290 first before we close the socket for real */
3291 Curl_ssl_close(conn, SECONDARYSOCKET);
3293 /* Note that we keep "use" set to TRUE since that (next) connection is
3294 still requested to use SSL */
3296 close_secondarysocket(conn);
3299 if(!result && (ftp->transfer == FTPTRANSFER_BODY) && ftpc->ctl_valid &&
3300 pp->pending_resp && !premature) {
3302 * Let's see what the server says about the transfer we just performed,
3303 * but lower the timeout as sometimes this connection has died while the
3304 * data has been transferred. This happens when doing through NATs etc that
3305 * abandon old silent connections.
3307 long old_time = pp->response_time;
3309 pp->response_time = 60*1000; /* give it only a minute for now */
3310 pp->response = Curl_tvnow(); /* timeout relative now */
3312 result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
3314 pp->response_time = old_time; /* set this back to previous value */
3316 if(!nread && (CURLE_OPERATION_TIMEDOUT == result)) {
3317 failf(data, "control connection looks dead");
3318 ftpc->ctl_valid = FALSE; /* mark control connection as bad */
3319 connclose(conn, "Timeout or similar in FTP DONE operation"); /* close */
3325 if(ftpc->dont_check && data->req.maxdownload > 0) {
3326 /* we have just sent ABOR and there is no reliable way to check if it was
3327 * successful or not; we have to close the connection now */
3328 infof(data, "partial download completed, closing connection\n");
3329 connclose(conn, "Partial download with no ability to check");
3333 if(!ftpc->dont_check) {
3334 /* 226 Transfer complete, 250 Requested file action okay, completed. */
3335 if((ftpcode != 226) && (ftpcode != 250)) {
3336 failf(data, "server did not report OK, got %d", ftpcode);
3337 result = CURLE_PARTIAL_FILE;
3342 if(result || premature)
3343 /* the response code from the transfer showed an error already so no
3344 use checking further */
3346 else if(data->set.upload) {
3347 if((-1 != data->state.infilesize) &&
3348 (data->state.infilesize != *ftp->bytecountp) &&
3350 (ftp->transfer == FTPTRANSFER_BODY)) {
3351 failf(data, "Uploaded unaligned file size (%" CURL_FORMAT_CURL_OFF_T
3352 " out of %" CURL_FORMAT_CURL_OFF_T " bytes)",
3353 *ftp->bytecountp, data->state.infilesize);
3354 result = CURLE_PARTIAL_FILE;
3358 if((-1 != data->req.size) &&
3359 (data->req.size != *ftp->bytecountp) &&
3360 #ifdef CURL_DO_LINEEND_CONV
3361 /* Most FTP servers don't adjust their file SIZE response for CRLFs, so
3362 * we'll check to see if the discrepancy can be explained by the number
3363 * of CRLFs we've changed to LFs.
3365 ((data->req.size + data->state.crlf_conversions) !=
3366 *ftp->bytecountp) &&
3367 #endif /* CURL_DO_LINEEND_CONV */
3368 (data->req.maxdownload != *ftp->bytecountp)) {
3369 failf(data, "Received only partial file: %" CURL_FORMAT_CURL_OFF_T
3370 " bytes", *ftp->bytecountp);
3371 result = CURLE_PARTIAL_FILE;
3373 else if(!ftpc->dont_check &&
3374 !*ftp->bytecountp &&
3375 (data->req.size>0)) {
3376 failf(data, "No data was received!");
3377 result = CURLE_FTP_COULDNT_RETR_FILE;
3381 /* clear these for next connection */
3382 ftp->transfer = FTPTRANSFER_BODY;
3383 ftpc->dont_check = FALSE;
3385 /* Send any post-transfer QUOTE strings? */
3386 if(!status && !result && !premature && data->set.postquote)
3387 result = ftp_sendquote(conn, data->set.postquote);
3392 /***********************************************************************
3396 * Where a 'quote' means a list of custom commands to send to the server.
3397 * The quote list is passed as an argument.
3403 CURLcode ftp_sendquote(struct connectdata *conn, struct curl_slist *quote)
3405 struct curl_slist *item;
3409 struct ftp_conn *ftpc = &conn->proto.ftpc;
3410 struct pingpong *pp = &ftpc->pp;
3415 char *cmd = item->data;
3416 bool acceptfail = FALSE;
3418 /* if a command starts with an asterisk, which a legal FTP command never
3419 can, the command will be allowed to fail without it causing any
3420 aborts or cancels etc. It will cause libcurl to act as if the command
3421 is successful, whatever the server reponds. */
3428 PPSENDF(&conn->proto.ftpc.pp, "%s", cmd);
3430 pp->response = Curl_tvnow(); /* timeout relative now */
3432 result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
3436 if(!acceptfail && (ftpcode >= 400)) {
3437 failf(conn->data, "QUOT string not accepted: %s", cmd);
3438 return CURLE_QUOTE_ERROR;
3448 /***********************************************************************
3452 * Returns TRUE if we in the current situation should send TYPE
3454 static int ftp_need_type(struct connectdata *conn,
3457 return conn->proto.ftpc.transfertype != (ascii_wanted?'A':'I');
3460 /***********************************************************************
3464 * Set TYPE. We only deal with ASCII or BINARY so this function
3466 * If the transfer type is not sent, simulate on OK response in newstate
3468 static CURLcode ftp_nb_type(struct connectdata *conn,
3469 bool ascii, ftpstate newstate)
3471 struct ftp_conn *ftpc = &conn->proto.ftpc;
3473 char want = (char)(ascii?'A':'I');
3475 if(ftpc->transfertype == want) {
3476 state(conn, newstate);
3477 return ftp_state_type_resp(conn, 200, newstate);
3480 PPSENDF(&ftpc->pp, "TYPE %c", want);
3481 state(conn, newstate);
3483 /* keep track of our current transfer type */
3484 ftpc->transfertype = want;
3488 /***************************************************************************
3490 * ftp_pasv_verbose()
3492 * This function only outputs some informationals about this second connection
3493 * when we've issued a PASV command before and thus we have connected to a
3494 * possibly new IP address.
3497 #ifndef CURL_DISABLE_VERBOSE_STRINGS
3499 ftp_pasv_verbose(struct connectdata *conn,
3501 char *newhost, /* ascii version */
3505 Curl_printable_address(ai, buf, sizeof(buf));
3506 infof(conn->data, "Connecting to %s (%s) port %d\n", newhost, buf, port);
3511 Check if this is a range download, and if so, set the internal variables
3515 static CURLcode ftp_range(struct connectdata *conn)
3517 curl_off_t from, to;
3520 struct Curl_easy *data = conn->data;
3521 struct ftp_conn *ftpc = &conn->proto.ftpc;
3523 if(data->state.use_range && data->state.range) {
3524 from=curlx_strtoofft(data->state.range, &ptr, 0);
3525 while(*ptr && (ISSPACE(*ptr) || (*ptr=='-')))
3527 to=curlx_strtoofft(ptr, &ptr2, 0);
3529 /* we didn't get any digit */
3532 if((-1 == to) && (from>=0)) {
3534 data->state.resume_from = from;
3535 DEBUGF(infof(conn->data, "FTP RANGE %" CURL_FORMAT_CURL_OFF_T
3536 " to end of file\n", from));
3540 data->req.maxdownload = -from;
3541 data->state.resume_from = from;
3542 DEBUGF(infof(conn->data, "FTP RANGE the last %" CURL_FORMAT_CURL_OFF_T
3543 " bytes\n", -from));
3547 data->req.maxdownload = (to-from)+1; /* include last byte */
3548 data->state.resume_from = from;
3549 DEBUGF(infof(conn->data, "FTP RANGE from %" CURL_FORMAT_CURL_OFF_T
3550 " getting %" CURL_FORMAT_CURL_OFF_T " bytes\n",
3551 from, data->req.maxdownload));
3553 DEBUGF(infof(conn->data, "range-download from %" CURL_FORMAT_CURL_OFF_T
3554 " to %" CURL_FORMAT_CURL_OFF_T ", totally %"
3555 CURL_FORMAT_CURL_OFF_T " bytes\n",
3556 from, to, data->req.maxdownload));
3557 ftpc->dont_check = TRUE; /* dont check for successful transfer */
3560 data->req.maxdownload = -1;
3568 * This function shall be called when the second FTP (data) connection is
3571 * 'complete' can return 0 for incomplete, 1 for done and -1 for go back
3572 * (which basically is only for when PASV is being sent to retry a failed
3576 static CURLcode ftp_do_more(struct connectdata *conn, int *completep)
3578 struct Curl_easy *data=conn->data;
3579 struct ftp_conn *ftpc = &conn->proto.ftpc;
3580 CURLcode result = CURLE_OK;
3581 bool connected = FALSE;
3582 bool complete = FALSE;
3584 /* the ftp struct is inited in ftp_connect() */
3585 struct FTP *ftp = data->req.protop;
3587 /* if the second connection isn't done yet, wait for it */
3588 if(!conn->bits.tcpconnect[SECONDARYSOCKET]) {
3589 if(conn->tunnel_state[SECONDARYSOCKET] == TUNNEL_CONNECT) {
3590 /* As we're in TUNNEL_CONNECT state now, we know the proxy name and port
3591 aren't used so we blank their arguments. TODO: make this nicer */
3592 result = Curl_proxyCONNECT(conn, SECONDARYSOCKET, NULL, 0, FALSE);
3597 result = Curl_is_connected(conn, SECONDARYSOCKET, &connected);
3599 /* Ready to do more? */
3601 DEBUGF(infof(data, "DO-MORE connected phase starts\n"));
3604 if(result && (ftpc->count1 == 0)) {
3605 *completep = -1; /* go back to DOING please */
3606 /* this is a EPSV connect failing, try PASV instead */
3607 return ftp_epsv_disable(conn);
3613 result = Curl_proxy_connect(conn, SECONDARYSOCKET);
3617 if(CONNECT_SECONDARYSOCKET_PROXY_SSL())
3620 if(conn->bits.tunnel_proxy && conn->bits.httpproxy &&
3621 conn->tunnel_state[SECONDARYSOCKET] != TUNNEL_COMPLETE)
3626 /* already in a state so skip the intial commands.
3627 They are only done to kickstart the do_more state */
3628 result = ftp_multi_statemach(conn, &complete);
3630 *completep = (int)complete;
3632 /* if we got an error or if we don't wait for a data connection return
3634 if(result || (ftpc->wait_data_conn != TRUE))
3637 if(ftpc->wait_data_conn)
3638 /* if we reach the end of the FTP state machine here, *complete will be
3639 TRUE but so is ftpc->wait_data_conn, which says we need to wait for
3640 the data connection and therefore we're not actually complete */
3644 if(ftp->transfer <= FTPTRANSFER_INFO) {
3645 /* a transfer is about to take place, or if not a file name was given
3646 so we'll do a SIZE on it later and then we need the right TYPE first */
3648 if(ftpc->wait_data_conn == TRUE) {
3651 result = ReceivedServerConnect(conn, &serv_conned);
3653 return result; /* Failed to accept data connection */
3656 /* It looks data connection is established */
3657 result = AcceptServerConnect(conn);
3658 ftpc->wait_data_conn = FALSE;
3660 result = InitiateTransfer(conn);
3665 *completep = 1; /* this state is now complete when the server has
3666 connected back to us */
3669 else if(data->set.upload) {
3670 result = ftp_nb_type(conn, data->set.prefer_ascii, FTP_STOR_TYPE);
3674 result = ftp_multi_statemach(conn, &complete);
3675 if(ftpc->wait_data_conn)
3676 /* if we reach the end of the FTP state machine here, *complete will be
3677 TRUE but so is ftpc->wait_data_conn, which says we need to wait for
3678 the data connection and therefore we're not actually complete */
3681 *completep = (int)complete;
3685 ftp->downloadsize = -1; /* unknown as of yet */
3687 result = ftp_range(conn);
3690 else if(data->set.ftp_list_only || !ftpc->file) {
3691 /* The specified path ends with a slash, and therefore we think this
3692 is a directory that is requested, use LIST. But before that we
3693 need to set ASCII transfer mode. */
3695 /* But only if a body transfer was requested. */
3696 if(ftp->transfer == FTPTRANSFER_BODY) {
3697 result = ftp_nb_type(conn, TRUE, FTP_LIST_TYPE);
3701 /* otherwise just fall through */
3704 result = ftp_nb_type(conn, data->set.prefer_ascii, FTP_RETR_TYPE);
3709 result = ftp_multi_statemach(conn, &complete);
3710 *completep = (int)complete;
3715 if(!result && (ftp->transfer != FTPTRANSFER_BODY))
3716 /* no data to transfer. FIX: it feels like a kludge to have this here
3718 Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
3720 if(!ftpc->wait_data_conn) {
3721 /* no waiting for the data connection so this is now complete */
3723 DEBUGF(infof(data, "DO-MORE phase ends with %d\n", (int)result));
3731 /***********************************************************************
3735 * This is the actual DO function for FTP. Get a file/directory according to
3736 * the options previously setup.
3740 CURLcode ftp_perform(struct connectdata *conn,
3741 bool *connected, /* connect status after PASV / PORT */
3744 /* this is FTP and no proxy */
3745 CURLcode result=CURLE_OK;
3747 DEBUGF(infof(conn->data, "DO phase starts\n"));
3749 if(conn->data->set.opt_no_body) {
3750 /* requested no body means no transfer... */
3751 struct FTP *ftp = conn->data->req.protop;
3752 ftp->transfer = FTPTRANSFER_INFO;
3755 *dophase_done = FALSE; /* not done yet */
3757 /* start the first command in the DO phase */
3758 result = ftp_state_quote(conn, TRUE, FTP_QUOTE);
3762 /* run the state-machine */
3763 result = ftp_multi_statemach(conn, dophase_done);
3765 *connected = conn->bits.tcpconnect[SECONDARYSOCKET];
3767 infof(conn->data, "ftp_perform ends with SECONDARY: %d\n", *connected);
3770 DEBUGF(infof(conn->data, "DO phase is complete1\n"));
3775 static void wc_data_dtor(void *ptr)
3777 struct ftp_wc_tmpdata *tmp = ptr;
3779 Curl_ftp_parselist_data_free(&tmp->parser);
3783 static CURLcode init_wc_data(struct connectdata *conn)
3786 char *path = conn->data->state.path;
3787 struct WildcardData *wildcard = &(conn->data->wildcard);
3788 CURLcode result = CURLE_OK;
3789 struct ftp_wc_tmpdata *ftp_tmp;
3791 last_slash = strrchr(conn->data->state.path, '/');
3794 if(last_slash[0] == '\0') {
3795 wildcard->state = CURLWC_CLEAN;
3796 result = ftp_parse_url_path(conn);
3800 wildcard->pattern = strdup(last_slash);
3801 if(!wildcard->pattern)
3802 return CURLE_OUT_OF_MEMORY;
3803 last_slash[0] = '\0'; /* cut file from path */
3806 else { /* there is only 'wildcard pattern' or nothing */
3808 wildcard->pattern = strdup(path);
3809 if(!wildcard->pattern)
3810 return CURLE_OUT_OF_MEMORY;
3813 else { /* only list */
3814 wildcard->state = CURLWC_CLEAN;
3815 result = ftp_parse_url_path(conn);
3820 /* program continues only if URL is not ending with slash, allocate needed
3821 resources for wildcard transfer */
3823 /* allocate ftp protocol specific temporary wildcard data */
3824 ftp_tmp = calloc(1, sizeof(struct ftp_wc_tmpdata));
3826 Curl_safefree(wildcard->pattern);
3827 return CURLE_OUT_OF_MEMORY;
3830 /* INITIALIZE parselist structure */
3831 ftp_tmp->parser = Curl_ftp_parselist_data_alloc();
3832 if(!ftp_tmp->parser) {
3833 Curl_safefree(wildcard->pattern);
3835 return CURLE_OUT_OF_MEMORY;
3838 wildcard->tmp = ftp_tmp; /* put it to the WildcardData tmp pointer */
3839 wildcard->tmp_dtor = wc_data_dtor;
3841 /* wildcard does not support NOCWD option (assert it?) */
3842 if(conn->data->set.ftp_filemethod == FTPFILE_NOCWD)
3843 conn->data->set.ftp_filemethod = FTPFILE_MULTICWD;
3845 /* try to parse ftp url */
3846 result = ftp_parse_url_path(conn);
3848 Curl_safefree(wildcard->pattern);
3849 wildcard->tmp_dtor(wildcard->tmp);
3850 wildcard->tmp_dtor = ZERO_NULL;
3851 wildcard->tmp = NULL;
3855 wildcard->path = strdup(conn->data->state.path);
3856 if(!wildcard->path) {
3857 Curl_safefree(wildcard->pattern);
3858 wildcard->tmp_dtor(wildcard->tmp);
3859 wildcard->tmp_dtor = ZERO_NULL;
3860 wildcard->tmp = NULL;
3861 return CURLE_OUT_OF_MEMORY;
3864 /* backup old write_function */
3865 ftp_tmp->backup.write_function = conn->data->set.fwrite_func;
3866 /* parsing write function */
3867 conn->data->set.fwrite_func = Curl_ftp_parselist;
3868 /* backup old file descriptor */
3869 ftp_tmp->backup.file_descriptor = conn->data->set.out;
3870 /* let the writefunc callback know what curl pointer is working with */
3871 conn->data->set.out = conn;
3873 infof(conn->data, "Wildcard - Parsing started\n");
3877 /* This is called recursively */
3878 static CURLcode wc_statemach(struct connectdata *conn)
3880 struct WildcardData * const wildcard = &(conn->data->wildcard);
3881 CURLcode result = CURLE_OK;
3883 switch(wildcard->state) {
3885 result = init_wc_data(conn);
3886 if(wildcard->state == CURLWC_CLEAN)
3890 wildcard->state = result ? CURLWC_ERROR : CURLWC_MATCHING;
3893 case CURLWC_MATCHING: {
3894 /* In this state is LIST response successfully parsed, so lets restore
3895 previous WRITEFUNCTION callback and WRITEDATA pointer */
3896 struct ftp_wc_tmpdata *ftp_tmp = wildcard->tmp;
3897 conn->data->set.fwrite_func = ftp_tmp->backup.write_function;
3898 conn->data->set.out = ftp_tmp->backup.file_descriptor;
3899 ftp_tmp->backup.write_function = ZERO_NULL;
3900 ftp_tmp->backup.file_descriptor = NULL;
3901 wildcard->state = CURLWC_DOWNLOADING;
3903 if(Curl_ftp_parselist_geterror(ftp_tmp->parser)) {
3904 /* error found in LIST parsing */
3905 wildcard->state = CURLWC_CLEAN;
3906 return wc_statemach(conn);
3908 else if(wildcard->filelist->size == 0) {
3909 /* no corresponding file */
3910 wildcard->state = CURLWC_CLEAN;
3911 return CURLE_REMOTE_FILE_NOT_FOUND;
3913 return wc_statemach(conn);
3916 case CURLWC_DOWNLOADING: {
3917 /* filelist has at least one file, lets get first one */
3918 struct ftp_conn *ftpc = &conn->proto.ftpc;
3919 struct curl_fileinfo *finfo = wildcard->filelist->head->ptr;
3921 char *tmp_path = aprintf("%s%s", wildcard->path, finfo->filename);
3923 return CURLE_OUT_OF_MEMORY;
3925 /* switch default "state.pathbuffer" and tmp_path, good to see
3926 ftp_parse_url_path function to understand this trick */
3927 Curl_safefree(conn->data->state.pathbuffer);
3928 conn->data->state.pathbuffer = tmp_path;
3929 conn->data->state.path = tmp_path;
3931 infof(conn->data, "Wildcard - START of \"%s\"\n", finfo->filename);
3932 if(conn->data->set.chunk_bgn) {
3933 long userresponse = conn->data->set.chunk_bgn(
3934 finfo, wildcard->customptr, (int)wildcard->filelist->size);
3935 switch(userresponse) {
3936 case CURL_CHUNK_BGN_FUNC_SKIP:
3937 infof(conn->data, "Wildcard - \"%s\" skipped by user\n",
3939 wildcard->state = CURLWC_SKIP;
3940 return wc_statemach(conn);
3941 case CURL_CHUNK_BGN_FUNC_FAIL:
3942 return CURLE_CHUNK_FAILED;
3946 if(finfo->filetype != CURLFILETYPE_FILE) {
3947 wildcard->state = CURLWC_SKIP;
3948 return wc_statemach(conn);
3951 if(finfo->flags & CURLFINFOFLAG_KNOWN_SIZE)
3952 ftpc->known_filesize = finfo->size;
3954 result = ftp_parse_url_path(conn);
3958 /* we don't need the Curl_fileinfo of first file anymore */
3959 Curl_llist_remove(wildcard->filelist, wildcard->filelist->head, NULL);
3961 if(wildcard->filelist->size == 0) { /* remains only one file to down. */
3962 wildcard->state = CURLWC_CLEAN;
3963 /* after that will be ftp_do called once again and no transfer
3964 will be done because of CURLWC_CLEAN state */
3970 if(conn->data->set.chunk_end)
3971 conn->data->set.chunk_end(conn->data->wildcard.customptr);
3972 Curl_llist_remove(wildcard->filelist, wildcard->filelist->head, NULL);
3973 wildcard->state = (wildcard->filelist->size == 0) ?
3974 CURLWC_CLEAN : CURLWC_DOWNLOADING;
3975 return wc_statemach(conn);
3978 case CURLWC_CLEAN: {
3979 struct ftp_wc_tmpdata *ftp_tmp = wildcard->tmp;
3982 result = Curl_ftp_parselist_geterror(ftp_tmp->parser);
3984 wildcard->state = result ? CURLWC_ERROR : CURLWC_DONE;
3995 /***********************************************************************
3999 * This function is registered as 'curl_do' function. It decodes the path
4000 * parts etc as a wrapper to the actual DO function (ftp_perform).
4002 * The input argument is already checked for validity.
4004 static CURLcode ftp_do(struct connectdata *conn, bool *done)
4006 CURLcode result = CURLE_OK;
4007 struct ftp_conn *ftpc = &conn->proto.ftpc;
4009 *done = FALSE; /* default to false */
4010 ftpc->wait_data_conn = FALSE; /* default to no such wait */
4012 if(conn->data->set.wildcardmatch) {
4013 result = wc_statemach(conn);
4014 if(conn->data->wildcard.state == CURLWC_SKIP ||
4015 conn->data->wildcard.state == CURLWC_DONE) {
4016 /* do not call ftp_regular_transfer */
4019 if(result) /* error, loop or skipping the file */
4022 else { /* no wildcard FSM needed */
4023 result = ftp_parse_url_path(conn);
4028 result = ftp_regular_transfer(conn, done);
4034 CURLcode Curl_ftpsend(struct connectdata *conn, const char *cmd)
4036 ssize_t bytes_written;
4037 #define SBUF_SIZE 1024
4041 CURLcode result = CURLE_OK;
4043 enum protection_level data_sec = conn->data_prot;
4046 write_len = strlen(cmd);
4047 if(write_len > (sizeof(s) -3))
4048 return CURLE_BAD_FUNCTION_ARGUMENT;
4050 strcpy(&s[write_len], "\r\n"); /* append a trailing CRLF */
4055 result = Curl_convert_to_network(conn->data, s, write_len);
4056 /* Curl_convert_to_network calls failf if unsuccessful */
4062 conn->data_prot = PROT_CMD;
4064 result = Curl_write(conn, conn->sock[FIRSTSOCKET], sptr, write_len,
4067 DEBUGASSERT(data_sec > PROT_NONE && data_sec < PROT_LAST);
4068 conn->data_prot = data_sec;
4074 if(conn->data->set.verbose)
4075 Curl_debug(conn->data, CURLINFO_HEADER_OUT,
4076 sptr, (size_t)bytes_written, conn);
4078 if(bytes_written != (ssize_t)write_len) {
4079 write_len -= bytes_written;
4080 sptr += bytes_written;
4089 /***********************************************************************
4093 * This should be called before calling sclose() on an ftp control connection
4094 * (not data connections). We should then wait for the response from the
4095 * server before returning. The calling code should then try to close the
4099 static CURLcode ftp_quit(struct connectdata *conn)
4101 CURLcode result = CURLE_OK;
4103 if(conn->proto.ftpc.ctl_valid) {
4104 result = Curl_pp_sendf(&conn->proto.ftpc.pp, "%s", "QUIT");
4106 failf(conn->data, "Failure sending QUIT command: %s",
4107 curl_easy_strerror(result));
4108 conn->proto.ftpc.ctl_valid = FALSE; /* mark control connection as bad */
4109 connclose(conn, "QUIT command failed"); /* mark for connection closure */
4110 state(conn, FTP_STOP);
4114 state(conn, FTP_QUIT);
4116 result = ftp_block_statemach(conn);
4122 /***********************************************************************
4126 * Disconnect from an FTP server. Cleanup protocol-specific per-connection
4127 * resources. BLOCKING.
4129 static CURLcode ftp_disconnect(struct connectdata *conn, bool dead_connection)
4131 struct ftp_conn *ftpc= &conn->proto.ftpc;
4132 struct pingpong *pp = &ftpc->pp;
4134 /* We cannot send quit unconditionally. If this connection is stale or
4135 bad in any way, sending quit and waiting around here will make the
4136 disconnect wait in vain and cause more problems than we need to.
4138 ftp_quit() will check the state of ftp->ctl_valid. If it's ok it
4139 will try to send the QUIT command, otherwise it will just return.
4142 ftpc->ctl_valid = FALSE;
4144 /* The FTP session may or may not have been allocated/setup at this point! */
4145 (void)ftp_quit(conn); /* ignore errors on the QUIT */
4147 if(ftpc->entrypath) {
4148 struct Curl_easy *data = conn->data;
4149 if(data->state.most_recent_ftp_entrypath == ftpc->entrypath) {
4150 data->state.most_recent_ftp_entrypath = NULL;
4152 free(ftpc->entrypath);
4153 ftpc->entrypath = NULL;
4157 free(ftpc->prevpath);
4158 ftpc->prevpath = NULL;
4159 free(ftpc->server_os);
4160 ftpc->server_os = NULL;
4162 Curl_pp_disconnect(pp);
4171 /***********************************************************************
4173 * ftp_parse_url_path()
4175 * Parse the URL path into separate path components.
4179 CURLcode ftp_parse_url_path(struct connectdata *conn)
4181 struct Curl_easy *data = conn->data;
4182 /* the ftp struct is already inited in ftp_connect() */
4183 struct FTP *ftp = data->req.protop;
4184 struct ftp_conn *ftpc = &conn->proto.ftpc;
4185 const char *slash_pos; /* position of the first '/' char in curpos */
4186 const char *path_to_use = data->state.path;
4187 const char *cur_pos;
4188 const char *filename = NULL;
4190 cur_pos = path_to_use; /* current position in path. point at the begin of
4191 next path component */
4193 ftpc->ctl_valid = FALSE;
4194 ftpc->cwdfail = FALSE;
4196 switch(data->set.ftp_filemethod) {
4198 /* fastest, but less standard-compliant */
4201 The best time to check whether the path is a file or directory is right
4204 the first condition in the if() right here, is there just in case
4205 someone decides to set path to NULL one day
4207 if(path_to_use[0] &&
4208 (path_to_use[strlen(path_to_use) - 1] != '/') )
4209 filename = path_to_use; /* this is a full file path */
4212 ftpc->file is not used anywhere other than for operations on a file.
4213 In other words, never for directory operations.
4214 So we can safely leave filename as NULL here and use it as a
4215 argument in dir/file decisions.
4220 case FTPFILE_SINGLECWD:
4221 /* get the last slash */
4222 if(!path_to_use[0]) {
4223 /* no dir, no file */
4227 slash_pos=strrchr(cur_pos, '/');
4228 if(slash_pos || !*cur_pos) {
4229 size_t dirlen = slash_pos-cur_pos;
4232 ftpc->dirs = calloc(1, sizeof(ftpc->dirs[0]));
4234 return CURLE_OUT_OF_MEMORY;
4239 result = Curl_urldecode(conn->data, slash_pos ? cur_pos : "/",
4240 slash_pos ? dirlen : 1,
4241 &ftpc->dirs[0], NULL,
4247 ftpc->dirdepth = 1; /* we consider it to be a single dir */
4248 filename = slash_pos ? slash_pos+1 : cur_pos; /* rest is file name */
4251 filename = cur_pos; /* this is a file name only */
4254 default: /* allow pretty much anything */
4255 case FTPFILE_MULTICWD:
4257 ftpc->diralloc = 5; /* default dir depth to allocate */
4258 ftpc->dirs = calloc(ftpc->diralloc, sizeof(ftpc->dirs[0]));
4260 return CURLE_OUT_OF_MEMORY;
4262 /* we have a special case for listing the root dir only */
4263 if(!strcmp(path_to_use, "/")) {
4264 cur_pos++; /* make it point to the zero byte */
4265 ftpc->dirs[0] = strdup("/");
4269 /* parse the URL path into separate path components */
4270 while((slash_pos = strchr(cur_pos, '/')) != NULL) {
4271 /* 1 or 0 pointer offset to indicate absolute directory */
4272 ssize_t absolute_dir = ((cur_pos - data->state.path > 0) &&
4273 (ftpc->dirdepth == 0))?1:0;
4275 /* seek out the next path component */
4276 if(slash_pos-cur_pos) {
4277 /* we skip empty path components, like "x//y" since the FTP command
4278 CWD requires a parameter and a non-existent parameter a) doesn't
4279 work on many servers and b) has no effect on the others. */
4280 size_t len = slash_pos - cur_pos + absolute_dir;
4282 Curl_urldecode(conn->data, cur_pos - absolute_dir, len,
4283 &ftpc->dirs[ftpc->dirdepth], NULL,
4286 free(ftpc->dirs[ftpc->dirdepth]);
4292 cur_pos = slash_pos + 1; /* jump to the rest of the string */
4293 if(!ftpc->dirdepth) {
4294 /* path starts with a slash, add that as a directory */
4295 ftpc->dirs[ftpc->dirdepth] = strdup("/");
4296 if(!ftpc->dirs[ftpc->dirdepth++]) { /* run out of memory ... */
4297 failf(data, "no memory");
4299 return CURLE_OUT_OF_MEMORY;
4305 cur_pos = slash_pos + 1; /* jump to the rest of the string */
4306 if(++ftpc->dirdepth >= ftpc->diralloc) {
4309 ftpc->diralloc *= 2; /* double the size each time */
4310 bigger = realloc(ftpc->dirs, ftpc->diralloc * sizeof(ftpc->dirs[0]));
4313 return CURLE_OUT_OF_MEMORY;
4315 ftpc->dirs = bigger;
4319 filename = cur_pos; /* the rest is the file name */
4323 if(filename && *filename) {
4325 Curl_urldecode(conn->data, filename, 0, &ftpc->file, NULL, TRUE);
4333 ftpc->file=NULL; /* instead of point to a zero byte, we make it a NULL
4336 if(data->set.upload && !ftpc->file && (ftp->transfer == FTPTRANSFER_BODY)) {
4337 /* We need a file name when uploading. Return error! */
4338 failf(data, "Uploading to a URL without a file name!");
4339 return CURLE_URL_MALFORMAT;
4342 ftpc->cwddone = FALSE; /* default to not done */
4344 if(ftpc->prevpath) {
4345 /* prevpath is "raw" so we convert the input path before we compare the
4350 Curl_urldecode(conn->data, data->state.path, 0, &path, &dlen, FALSE);
4356 dlen -= ftpc->file?strlen(ftpc->file):0;
4357 if((dlen == strlen(ftpc->prevpath)) &&
4358 !strncmp(path, ftpc->prevpath, dlen)) {
4359 infof(data, "Request has same path as previous transfer\n");
4360 ftpc->cwddone = TRUE;
4368 /* call this when the DO phase has completed */
4369 static CURLcode ftp_dophase_done(struct connectdata *conn,
4372 struct FTP *ftp = conn->data->req.protop;
4373 struct ftp_conn *ftpc = &conn->proto.ftpc;
4377 CURLcode result = ftp_do_more(conn, &completed);
4380 close_secondarysocket(conn);
4385 if(ftp->transfer != FTPTRANSFER_BODY)
4386 /* no data to transfer */
4387 Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
4389 /* since we didn't connect now, we want do_more to get called */
4390 conn->bits.do_more = TRUE;
4392 ftpc->ctl_valid = TRUE; /* seems good */
4397 /* called from multi.c while DOing */
4398 static CURLcode ftp_doing(struct connectdata *conn,
4401 CURLcode result = ftp_multi_statemach(conn, dophase_done);
4404 DEBUGF(infof(conn->data, "DO phase failed\n"));
4405 else if(*dophase_done) {
4406 result = ftp_dophase_done(conn, FALSE /* not connected */);
4408 DEBUGF(infof(conn->data, "DO phase is complete2\n"));
4413 /***********************************************************************
4415 * ftp_regular_transfer()
4417 * The input argument is already checked for validity.
4419 * Performs all commands done before a regular transfer between a local and a
4422 * ftp->ctl_valid starts out as FALSE, and gets set to TRUE if we reach the
4423 * ftp_done() function without finding any major problem.
4426 CURLcode ftp_regular_transfer(struct connectdata *conn,
4429 CURLcode result=CURLE_OK;
4430 bool connected=FALSE;
4431 struct Curl_easy *data = conn->data;
4432 struct ftp_conn *ftpc = &conn->proto.ftpc;
4433 data->req.size = -1; /* make sure this is unknown at this point */
4435 Curl_pgrsSetUploadCounter(data, 0);
4436 Curl_pgrsSetDownloadCounter(data, 0);
4437 Curl_pgrsSetUploadSize(data, -1);
4438 Curl_pgrsSetDownloadSize(data, -1);
4440 ftpc->ctl_valid = TRUE; /* starts good */
4442 result = ftp_perform(conn,
4443 &connected, /* have we connected after PASV/PORT */
4444 dophase_done); /* all commands in the DO-phase done? */
4449 /* the DO phase has not completed yet */
4452 result = ftp_dophase_done(conn, connected);
4463 static CURLcode ftp_setup_connection(struct connectdata *conn)
4465 struct Curl_easy *data = conn->data;
4470 if(conn->bits.httpproxy && !data->set.tunnel_thru_httpproxy) {
4471 /* Unless we have asked to tunnel ftp operations through the proxy, we
4472 switch and use HTTP operations only */
4473 #ifndef CURL_DISABLE_HTTP
4474 if(conn->handler == &Curl_handler_ftp)
4475 conn->handler = &Curl_handler_ftp_proxy;
4478 conn->handler = &Curl_handler_ftps_proxy;
4480 failf(data, "FTPS not supported!");
4481 return CURLE_UNSUPPORTED_PROTOCOL;
4484 /* set it up as a HTTP connection instead */
4485 return conn->handler->setup_connection(conn);
4487 failf(data, "FTP over http proxy requires HTTP support built-in!");
4488 return CURLE_UNSUPPORTED_PROTOCOL;
4492 conn->data->req.protop = ftp = malloc(sizeof(struct FTP));
4494 return CURLE_OUT_OF_MEMORY;
4496 data->state.path++; /* don't include the initial slash */
4497 data->state.slash_removed = TRUE; /* we've skipped the slash */
4499 /* FTP URLs support an extension like ";type=<typecode>" that
4500 * we'll try to get now! */
4501 type = strstr(data->state.path, ";type=");
4504 type = strstr(conn->host.rawalloc, ";type=");
4507 *type = 0; /* it was in the middle of the hostname */
4508 command = Curl_raw_toupper(type[6]);
4509 conn->bits.type_set = TRUE;
4512 case 'A': /* ASCII mode */
4513 data->set.prefer_ascii = TRUE;
4516 case 'D': /* directory mode */
4517 data->set.ftp_list_only = TRUE;
4520 case 'I': /* binary mode */
4522 /* switch off ASCII */
4523 data->set.prefer_ascii = FALSE;
4528 /* get some initial data into the ftp struct */
4529 ftp->bytecountp = &conn->data->req.bytecount;
4530 ftp->transfer = FTPTRANSFER_BODY;
4531 ftp->downloadsize = 0;
4533 /* No need to duplicate user+password, the connectdata struct won't change
4534 during a session, but we re-init them here since on subsequent inits
4535 since the conn struct may have changed or been replaced.
4537 ftp->user = conn->user;
4538 ftp->passwd = conn->passwd;
4539 if(isBadFtpString(ftp->user))
4540 return CURLE_URL_MALFORMAT;
4541 if(isBadFtpString(ftp->passwd))
4542 return CURLE_URL_MALFORMAT;
4544 conn->proto.ftpc.known_filesize = -1; /* unknown size for now */
4549 #endif /* CURL_DISABLE_FTP */