1 /***************************************************************************
3 * Project ___| | | | _ \| |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
8 * Copyright (C) 1998 - 2018, 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"
62 #include "curl_range.h"
64 #include "strtoofft.h"
66 #include "vtls/vtls.h"
69 #include "inet_ntop.h"
70 #include "inet_pton.h"
72 #include "parsedate.h" /* for the week day and month names */
73 #include "sockaddr.h" /* required for Curl_sockaddr_storage */
77 #include "speedcheck.h"
79 #include "http_proxy.h"
80 #include "non-ascii.h"
81 /* The last 3 #include files should be in this order */
82 #include "curl_printf.h"
83 #include "curl_memory.h"
87 #define NI_MAXHOST 1025
89 #ifndef INET_ADDRSTRLEN
90 #define INET_ADDRSTRLEN 16
93 #ifdef CURL_DISABLE_VERBOSE_STRINGS
94 #define ftp_pasv_verbose(a,b,c,d) Curl_nop_stmt
97 /* Local API functions */
99 static void _state(struct connectdata *conn,
101 #define state(x,y) _state(x,y)
103 static void _state(struct connectdata *conn,
106 #define state(x,y) _state(x,y,__LINE__)
109 static CURLcode ftp_sendquote(struct connectdata *conn,
110 struct curl_slist *quote);
111 static CURLcode ftp_quit(struct connectdata *conn);
112 static CURLcode ftp_parse_url_path(struct connectdata *conn);
113 static CURLcode ftp_regular_transfer(struct connectdata *conn, bool *done);
114 #ifndef CURL_DISABLE_VERBOSE_STRINGS
115 static void ftp_pasv_verbose(struct connectdata *conn,
117 char *newhost, /* ascii version */
120 static CURLcode ftp_state_prepare_transfer(struct connectdata *conn);
121 static CURLcode ftp_state_mdtm(struct connectdata *conn);
122 static CURLcode ftp_state_quote(struct connectdata *conn,
123 bool init, ftpstate instate);
124 static CURLcode ftp_nb_type(struct connectdata *conn,
125 bool ascii, ftpstate newstate);
126 static int ftp_need_type(struct connectdata *conn,
128 static CURLcode ftp_do(struct connectdata *conn, bool *done);
129 static CURLcode ftp_done(struct connectdata *conn,
130 CURLcode, bool premature);
131 static CURLcode ftp_connect(struct connectdata *conn, bool *done);
132 static CURLcode ftp_disconnect(struct connectdata *conn, bool dead_connection);
133 static CURLcode ftp_do_more(struct connectdata *conn, int *completed);
134 static CURLcode ftp_multi_statemach(struct connectdata *conn, bool *done);
135 static int ftp_getsock(struct connectdata *conn, curl_socket_t *socks,
137 static int ftp_domore_getsock(struct connectdata *conn, curl_socket_t *socks,
139 static CURLcode ftp_doing(struct connectdata *conn,
141 static CURLcode ftp_setup_connection(struct connectdata * conn);
143 static CURLcode init_wc_data(struct connectdata *conn);
144 static CURLcode wc_statemach(struct connectdata *conn);
146 static void wc_data_dtor(void *ptr);
148 static CURLcode ftp_state_retr(struct connectdata *conn, curl_off_t filesize);
150 static CURLcode ftp_readresp(curl_socket_t sockfd,
154 static CURLcode ftp_dophase_done(struct connectdata *conn,
157 /* easy-to-use macro: */
158 #define PPSENDF(x,y,z) result = Curl_pp_sendf(x,y,z); \
164 * FTP protocol handler.
167 const struct Curl_handler Curl_handler_ftp = {
169 ftp_setup_connection, /* setup_connection */
172 ftp_do_more, /* do_more */
173 ftp_connect, /* connect_it */
174 ftp_multi_statemach, /* connecting */
175 ftp_doing, /* doing */
176 ftp_getsock, /* proto_getsock */
177 ftp_getsock, /* doing_getsock */
178 ftp_domore_getsock, /* domore_getsock */
179 ZERO_NULL, /* perform_getsock */
180 ftp_disconnect, /* disconnect */
181 ZERO_NULL, /* readwrite */
182 ZERO_NULL, /* connection_check */
183 PORT_FTP, /* defport */
184 CURLPROTO_FTP, /* protocol */
185 PROTOPT_DUAL | PROTOPT_CLOSEACTION | PROTOPT_NEEDSPWD |
186 PROTOPT_NOURLQUERY | PROTOPT_PROXY_AS_HTTP |
187 PROTOPT_WILDCARD /* flags */
193 * FTPS protocol handler.
196 const struct Curl_handler Curl_handler_ftps = {
198 ftp_setup_connection, /* setup_connection */
201 ftp_do_more, /* do_more */
202 ftp_connect, /* connect_it */
203 ftp_multi_statemach, /* connecting */
204 ftp_doing, /* doing */
205 ftp_getsock, /* proto_getsock */
206 ftp_getsock, /* doing_getsock */
207 ftp_domore_getsock, /* domore_getsock */
208 ZERO_NULL, /* perform_getsock */
209 ftp_disconnect, /* disconnect */
210 ZERO_NULL, /* readwrite */
211 ZERO_NULL, /* connection_check */
212 PORT_FTPS, /* defport */
213 CURLPROTO_FTPS, /* protocol */
214 PROTOPT_SSL | PROTOPT_DUAL | PROTOPT_CLOSEACTION |
215 PROTOPT_NEEDSPWD | PROTOPT_NOURLQUERY | PROTOPT_WILDCARD /* flags */
219 static void close_secondarysocket(struct connectdata *conn)
221 if(CURL_SOCKET_BAD != conn->sock[SECONDARYSOCKET]) {
222 Curl_closesocket(conn, conn->sock[SECONDARYSOCKET]);
223 conn->sock[SECONDARYSOCKET] = CURL_SOCKET_BAD;
225 conn->bits.tcpconnect[SECONDARYSOCKET] = FALSE;
229 * NOTE: back in the old days, we added code in the FTP code that made NOBODY
230 * requests on files respond with headers passed to the client/stdout that
231 * looked like HTTP ones.
233 * This approach is not very elegant, it causes confusion and is error-prone.
234 * It is subject for removal at the next (or at least a future) soname bump.
235 * Until then you can test the effects of the removal by undefining the
236 * following define named CURL_FTP_HTTPSTYLE_HEAD.
238 #define CURL_FTP_HTTPSTYLE_HEAD 1
240 static void freedirs(struct ftp_conn *ftpc)
244 for(i = 0; i < ftpc->dirdepth; i++) {
246 ftpc->dirs[i] = NULL;
252 Curl_safefree(ftpc->file);
254 /* no longer of any use */
255 Curl_safefree(ftpc->newhost);
258 /* Returns non-zero if the given string contains CR (\r) or LF (\n),
259 which are not allowed within RFC 959 <string>.
260 Note: The input string is in the client's encoding which might
261 not be ASCII, so escape sequences \r & \n must be used instead
262 of hex values 0x0d & 0x0a.
264 static bool isBadFtpString(const char *string)
266 return ((NULL != strchr(string, '\r')) ||
267 (NULL != strchr(string, '\n'))) ? TRUE : FALSE;
270 /***********************************************************************
272 * AcceptServerConnect()
274 * After connection request is received from the server this function is
275 * called to accept the connection and close the listening socket
278 static CURLcode AcceptServerConnect(struct connectdata *conn)
280 struct Curl_easy *data = conn->data;
281 curl_socket_t sock = conn->sock[SECONDARYSOCKET];
282 curl_socket_t s = CURL_SOCKET_BAD;
284 struct Curl_sockaddr_storage add;
286 struct sockaddr_in add;
288 curl_socklen_t size = (curl_socklen_t) sizeof(add);
290 if(0 == getsockname(sock, (struct sockaddr *) &add, &size)) {
293 s = accept(sock, (struct sockaddr *) &add, &size);
295 Curl_closesocket(conn, sock); /* close the first socket */
297 if(CURL_SOCKET_BAD == s) {
298 failf(data, "Error accept()ing server connect");
299 return CURLE_FTP_PORT_FAILED;
301 infof(data, "Connection accepted from server\n");
302 /* when this happens within the DO state it is important that we mark us as
303 not needing DO_MORE anymore */
304 conn->bits.do_more = FALSE;
306 conn->sock[SECONDARYSOCKET] = s;
307 (void)curlx_nonblock(s, TRUE); /* enable non-blocking */
308 conn->sock_accepted[SECONDARYSOCKET] = TRUE;
310 if(data->set.fsockopt) {
313 /* activate callback for setting socket options */
314 Curl_set_in_callback(data, true);
315 error = data->set.fsockopt(data->set.sockopt_client,
317 CURLSOCKTYPE_ACCEPT);
318 Curl_set_in_callback(data, false);
321 close_secondarysocket(conn);
322 return CURLE_ABORTED_BY_CALLBACK;
331 * ftp_timeleft_accept() returns the amount of milliseconds left allowed for
332 * waiting server to connect. If the value is negative, the timeout time has
335 * The start time is stored in progress.t_acceptdata - as set with
336 * Curl_pgrsTime(..., TIMER_STARTACCEPT);
339 static timediff_t ftp_timeleft_accept(struct Curl_easy *data)
341 timediff_t timeout_ms = DEFAULT_ACCEPT_TIMEOUT;
345 if(data->set.accepttimeout > 0)
346 timeout_ms = data->set.accepttimeout;
350 /* check if the generic timeout possibly is set shorter */
351 other = Curl_timeleft(data, &now, FALSE);
352 if(other && (other < timeout_ms))
353 /* note that this also works fine for when other happens to be negative
354 due to it already having elapsed */
357 /* subtract elapsed time */
358 timeout_ms -= Curl_timediff(now, data->progress.t_acceptdata);
360 /* avoid returning 0 as that means no timeout! */
368 /***********************************************************************
370 * ReceivedServerConnect()
372 * After allowing server to connect to us from data port, this function
373 * checks both data connection for connection establishment and ctrl
374 * connection for a negative response regarding a failure in connecting
377 static CURLcode ReceivedServerConnect(struct connectdata *conn, bool *received)
379 struct Curl_easy *data = conn->data;
380 curl_socket_t ctrl_sock = conn->sock[FIRSTSOCKET];
381 curl_socket_t data_sock = conn->sock[SECONDARYSOCKET];
382 struct ftp_conn *ftpc = &conn->proto.ftpc;
383 struct pingpong *pp = &ftpc->pp;
391 timeout_ms = ftp_timeleft_accept(data);
392 infof(data, "Checking for server connect\n");
394 /* if a timeout was already reached, bail out */
395 failf(data, "Accept timeout occurred while waiting server connect");
396 return CURLE_FTP_ACCEPT_TIMEOUT;
399 /* First check whether there is a cached response from server */
400 if(pp->cache_size && pp->cache && pp->cache[0] > '3') {
401 /* Data connection could not be established, let's return */
402 infof(data, "There is negative response in cache while serv connect\n");
403 Curl_GetFTPResponse(&nread, conn, &ftpcode);
404 return CURLE_FTP_ACCEPT_FAILED;
407 result = Curl_socket_check(ctrl_sock, data_sock, CURL_SOCKET_BAD, 0);
409 /* see if the connection request is already here */
413 failf(data, "Error while waiting for server connect");
414 return CURLE_FTP_ACCEPT_FAILED;
415 case 0: /* Server connect is not received yet */
419 if(result & CURL_CSELECT_IN2) {
420 infof(data, "Ready to accept data connection from server\n");
423 else if(result & CURL_CSELECT_IN) {
424 infof(data, "Ctrl conn has data while waiting for data conn\n");
425 Curl_GetFTPResponse(&nread, conn, &ftpcode);
428 return CURLE_FTP_ACCEPT_FAILED;
430 return CURLE_WEIRD_SERVER_REPLY;
440 /***********************************************************************
444 * After connection from server is accepted this function is called to
445 * setup transfer parameters and initiate the data transfer.
448 static CURLcode InitiateTransfer(struct connectdata *conn)
450 struct Curl_easy *data = conn->data;
451 struct FTP *ftp = data->req.protop;
452 CURLcode result = CURLE_OK;
454 if(conn->bits.ftp_use_data_ssl) {
455 /* since we only have a plaintext TCP connection here, we must now
456 * do the TLS stuff */
457 infof(data, "Doing the SSL/TLS handshake on the data stream\n");
458 result = Curl_ssl_connect(conn, SECONDARYSOCKET);
463 if(conn->proto.ftpc.state_saved == FTP_STOR) {
464 *(ftp->bytecountp) = 0;
466 /* When we know we're uploading a specified file, we can get the file
467 size prior to the actual upload. */
469 Curl_pgrsSetUploadSize(data, data->state.infilesize);
471 /* set the SO_SNDBUF for the secondary socket for those who need it */
472 Curl_sndbufset(conn->sock[SECONDARYSOCKET]);
474 Curl_setup_transfer(conn, -1, -1, FALSE, NULL, /* no download */
475 SECONDARYSOCKET, ftp->bytecountp);
479 Curl_setup_transfer(conn, SECONDARYSOCKET,
480 conn->proto.ftpc.retr_size_saved, FALSE,
481 ftp->bytecountp, -1, NULL); /* no upload here */
484 conn->proto.ftpc.pp.pending_resp = TRUE; /* expect server response */
485 state(conn, FTP_STOP);
490 /***********************************************************************
492 * AllowServerConnect()
494 * When we've issue the PORT command, we have told the server to connect to
495 * us. This function checks whether data connection is established if so it is
499 static CURLcode AllowServerConnect(struct connectdata *conn, bool *connected)
501 struct Curl_easy *data = conn->data;
503 CURLcode result = CURLE_OK;
506 infof(data, "Preparing for accepting server on data port\n");
508 /* Save the time we start accepting server connect */
509 Curl_pgrsTime(data, TIMER_STARTACCEPT);
511 timeout_ms = ftp_timeleft_accept(data);
513 /* if a timeout was already reached, bail out */
514 failf(data, "Accept timeout occurred while waiting server connect");
515 return CURLE_FTP_ACCEPT_TIMEOUT;
518 /* see if the connection request is already here */
519 result = ReceivedServerConnect(conn, connected);
524 result = AcceptServerConnect(conn);
528 result = InitiateTransfer(conn);
533 /* Add timeout to multi handle and break out of the loop */
534 if(!result && *connected == FALSE) {
535 Curl_expire(data, data->set.accepttimeout > 0 ?
536 data->set.accepttimeout: DEFAULT_ACCEPT_TIMEOUT, 0);
543 /* macro to check for a three-digit ftp status code at the start of the
545 #define STATUSCODE(line) (ISDIGIT(line[0]) && ISDIGIT(line[1]) && \
548 /* macro to check for the last line in an FTP server response */
549 #define LASTLINE(line) (STATUSCODE(line) && (' ' == line[3]))
551 static bool ftp_endofresp(struct connectdata *conn, char *line, size_t len,
556 if((len > 3) && LASTLINE(line)) {
557 *code = curlx_sltosi(strtol(line, NULL, 10));
564 static CURLcode ftp_readresp(curl_socket_t sockfd,
566 int *ftpcode, /* return the ftp-code if done */
567 size_t *size) /* size of the response */
569 struct connectdata *conn = pp->conn;
570 struct Curl_easy *data = conn->data;
572 char * const buf = data->state.buffer;
574 CURLcode result = CURLE_OK;
577 result = Curl_pp_readresp(sockfd, pp, &code, size);
579 #if defined(HAVE_GSSAPI)
580 /* handle the security-oriented responses 6xx ***/
581 /* FIXME: some errorchecking perhaps... ***/
584 code = Curl_sec_read_msg(conn, buf, PROT_SAFE);
587 code = Curl_sec_read_msg(conn, buf, PROT_PRIVATE);
590 code = Curl_sec_read_msg(conn, buf, PROT_CONFIDENTIAL);
593 /* normal ftp stuff we pass through! */
598 /* store the latest code for later retrieval */
599 data->info.httpcode = code;
605 /* 421 means "Service not available, closing control connection." and FTP
606 * servers use it to signal that idle session timeout has been exceeded.
607 * If we ignored the response, it could end up hanging in some cases.
609 * This response code can come at any point so having it treated
610 * generically is a good idea.
612 infof(data, "We got a 421 - timeout!\n");
613 state(conn, FTP_STOP);
614 return CURLE_OPERATION_TIMEDOUT;
620 /* --- parse FTP server responses --- */
623 * Curl_GetFTPResponse() is a BLOCKING function to read the full response
624 * from a server after a command.
628 CURLcode Curl_GetFTPResponse(ssize_t *nreadp, /* return number of bytes read */
629 struct connectdata *conn,
630 int *ftpcode) /* return the ftp-code */
633 * We cannot read just one byte per read() and then go back to select() as
634 * the OpenSSL read() doesn't grok that properly.
636 * Alas, read as much as possible, split up into lines, use the ending
637 * line in a response or continue reading. */
639 curl_socket_t sockfd = conn->sock[FIRSTSOCKET];
640 time_t timeout; /* timeout in milliseconds */
642 struct Curl_easy *data = conn->data;
643 CURLcode result = CURLE_OK;
644 struct ftp_conn *ftpc = &conn->proto.ftpc;
645 struct pingpong *pp = &ftpc->pp;
648 int value_to_be_ignored = 0;
651 *ftpcode = 0; /* 0 for errors */
653 /* make the pointer point to something for the rest of this function */
654 ftpcode = &value_to_be_ignored;
658 while(!*ftpcode && !result) {
659 /* check and reset timeout value every lap */
660 timeout = Curl_pp_state_timeout(pp);
663 failf(data, "FTP response timeout");
664 return CURLE_OPERATION_TIMEDOUT; /* already too little time */
667 interval_ms = 1000; /* use 1 second timeout intervals */
668 if(timeout < interval_ms)
669 interval_ms = timeout;
672 * Since this function is blocking, we need to wait here for input on the
673 * connection and only then we call the response reading function. We do
674 * timeout at least every second to make the timeout check run.
676 * A caution here is that the ftp_readresp() function has a cache that may
677 * contain pieces of a response from the previous invoke and we need to
678 * make sure we don't just wait for input while there is unhandled data in
679 * that cache. But also, if the cache is there, we call ftp_readresp() and
680 * the cache wasn't good enough to continue we must not just busy-loop
681 * around this function.
685 if(pp->cache && (cache_skip < 2)) {
687 * There's a cache left since before. We then skipping the wait for
688 * socket action, unless this is the same cache like the previous round
689 * as then the cache was deemed not enough to act on and we then need to
690 * wait for more data anyway.
693 else if(!Curl_conn_data_pending(conn, FIRSTSOCKET)) {
694 switch(SOCKET_READABLE(sockfd, interval_ms)) {
695 case -1: /* select() error, stop reading */
696 failf(data, "FTP response aborted due to select/poll error: %d",
698 return CURLE_RECV_ERROR;
700 case 0: /* timeout */
701 if(Curl_pgrsUpdate(conn))
702 return CURLE_ABORTED_BY_CALLBACK;
703 continue; /* just continue in our loop for the timeout duration */
705 default: /* for clarity */
709 result = ftp_readresp(sockfd, pp, ftpcode, &nread);
713 if(!nread && pp->cache)
714 /* bump cache skip counter as on repeated skips we must wait for more
718 /* when we got data or there is no cache left, we reset the cache skip
724 } /* while there's buffer left and loop is requested */
726 pp->pending_resp = FALSE;
731 #if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
732 /* for debug purposes */
733 static const char * const ftp_state_names[]={
772 /* This is the ONLY way to change FTP state! */
773 static void _state(struct connectdata *conn,
780 struct ftp_conn *ftpc = &conn->proto.ftpc;
782 #if defined(DEBUGBUILD)
784 #if defined(CURL_DISABLE_VERBOSE_STRINGS)
787 if(ftpc->state != newstate)
788 infof(conn->data, "FTP %p (line %d) state change from %s to %s\n",
789 (void *)ftpc, lineno, ftp_state_names[ftpc->state],
790 ftp_state_names[newstate]);
794 ftpc->state = newstate;
797 static CURLcode ftp_state_user(struct connectdata *conn)
800 struct FTP *ftp = conn->data->req.protop;
802 PPSENDF(&conn->proto.ftpc.pp, "USER %s", ftp->user?ftp->user:"");
804 state(conn, FTP_USER);
805 conn->data->state.ftp_trying_alternative = FALSE;
810 static CURLcode ftp_state_pwd(struct connectdata *conn)
814 /* send PWD to discover our entry point */
815 PPSENDF(&conn->proto.ftpc.pp, "%s", "PWD");
816 state(conn, FTP_PWD);
821 /* For the FTP "protocol connect" and "doing" phases only */
822 static int ftp_getsock(struct connectdata *conn,
823 curl_socket_t *socks,
826 return Curl_pp_getsock(&conn->proto.ftpc.pp, socks, numsocks);
829 /* For the FTP "DO_MORE" phase only */
830 static int ftp_domore_getsock(struct connectdata *conn, curl_socket_t *socks,
833 struct ftp_conn *ftpc = &conn->proto.ftpc;
836 return GETSOCK_BLANK;
838 /* When in DO_MORE state, we could be either waiting for us to connect to a
839 * remote site, or we could wait for that site to connect to us. Or just
840 * handle ordinary commands.
843 if(FTP_STOP == ftpc->state) {
844 int bits = GETSOCK_READSOCK(0);
846 /* if stopped and still in this state, then we're also waiting for a
847 connect on the secondary connection */
848 socks[0] = conn->sock[FIRSTSOCKET];
850 if(!conn->data->set.ftp_use_port) {
853 /* PORT is used to tell the server to connect to us, and during that we
854 don't do happy eyeballs, but we do if we connect to the server */
855 for(s = 1, i = 0; i<2; i++) {
856 if(conn->tempsock[i] != CURL_SOCKET_BAD) {
857 socks[s] = conn->tempsock[i];
858 bits |= GETSOCK_WRITESOCK(s++);
863 socks[1] = conn->sock[SECONDARYSOCKET];
864 bits |= GETSOCK_WRITESOCK(1) | GETSOCK_READSOCK(1);
869 return Curl_pp_getsock(&conn->proto.ftpc.pp, socks, numsocks);
872 /* This is called after the FTP_QUOTE state is passed.
874 ftp_state_cwd() sends the range of CWD commands to the server to change to
875 the correct directory. It may also need to send MKD commands to create
876 missing ones, if that option is enabled.
878 static CURLcode ftp_state_cwd(struct connectdata *conn)
880 CURLcode result = CURLE_OK;
881 struct ftp_conn *ftpc = &conn->proto.ftpc;
884 /* already done and fine */
885 result = ftp_state_mdtm(conn);
887 ftpc->count2 = 0; /* count2 counts failed CWDs */
889 /* count3 is set to allow a MKD to fail once. In the case when first CWD
890 fails and then MKD fails (due to another session raced it to create the
891 dir) this then allows for a second try to CWD to it */
892 ftpc->count3 = (conn->data->set.ftp_create_missing_dirs == 2)?1:0;
894 if((conn->data->set.ftp_filemethod == FTPFILE_NOCWD) && !ftpc->cwdcount)
895 /* No CWD necessary */
896 result = ftp_state_mdtm(conn);
897 else if(conn->bits.reuse && ftpc->entrypath) {
898 /* This is a re-used connection. Since we change directory to where the
899 transfer is taking place, we must first get back to the original dir
900 where we ended up after login: */
901 ftpc->cwdcount = 0; /* we count this as the first path, then we add one
902 for all upcoming ones in the ftp->dirs[] array */
903 PPSENDF(&conn->proto.ftpc.pp, "CWD %s", ftpc->entrypath);
904 state(conn, FTP_CWD);
909 /* issue the first CWD, the rest is sent when the CWD responses are
911 PPSENDF(&conn->proto.ftpc.pp, "CWD %s", ftpc->dirs[ftpc->cwdcount -1]);
912 state(conn, FTP_CWD);
915 /* No CWD necessary */
916 result = ftp_state_mdtm(conn);
929 static CURLcode ftp_state_use_port(struct connectdata *conn,
930 ftpport fcmd) /* start with this */
933 CURLcode result = CURLE_OK;
934 struct ftp_conn *ftpc = &conn->proto.ftpc;
935 struct Curl_easy *data = conn->data;
936 curl_socket_t portsock = CURL_SOCKET_BAD;
937 char myhost[256] = "";
939 struct Curl_sockaddr_storage ss;
940 Curl_addrinfo *res, *ai;
941 curl_socklen_t sslen;
942 char hbuf[NI_MAXHOST];
943 struct sockaddr *sa = (struct sockaddr *)&ss;
944 struct sockaddr_in * const sa4 = (void *)sa;
946 struct sockaddr_in6 * const sa6 = (void *)sa;
949 static const char mode[][5] = { "EPRT", "PORT" };
953 char *string_ftpport = data->set.str[STRING_FTPPORT];
954 struct Curl_dns_entry *h = NULL;
955 unsigned short port_min = 0;
956 unsigned short port_max = 0;
958 bool possibly_non_local = TRUE;
962 /* Step 1, figure out what is requested,
964 * (ipv4|ipv6|domain|interface)?(:port(-range)?)?
967 if(data->set.str[STRING_FTPPORT] &&
968 (strlen(data->set.str[STRING_FTPPORT]) > 1)) {
971 size_t addrlen = INET6_ADDRSTRLEN > strlen(string_ftpport) ?
972 INET6_ADDRSTRLEN : strlen(string_ftpport);
974 size_t addrlen = INET_ADDRSTRLEN > strlen(string_ftpport) ?
975 INET_ADDRSTRLEN : strlen(string_ftpport);
977 char *ip_start = string_ftpport;
979 char *port_start = NULL;
980 char *port_sep = NULL;
982 addr = calloc(addrlen + 1, 1);
984 return CURLE_OUT_OF_MEMORY;
987 if(*string_ftpport == '[') {
988 /* [ipv6]:port(-range) */
989 ip_start = string_ftpport + 1;
990 ip_end = strchr(string_ftpport, ']');
992 strncpy(addr, ip_start, ip_end - ip_start);
996 if(*string_ftpport == ':') {
998 ip_end = string_ftpport;
1001 ip_end = strchr(string_ftpport, ':');
1003 /* either ipv6 or (ipv4|domain|interface):port(-range) */
1005 if(Curl_inet_pton(AF_INET6, string_ftpport, sa6) == 1) {
1007 port_min = port_max = 0;
1008 strcpy(addr, string_ftpport);
1009 ip_end = NULL; /* this got no port ! */
1013 /* (ipv4|domain|interface):port(-range) */
1014 strncpy(addr, string_ftpport, ip_end - ip_start);
1017 /* ipv4|interface */
1018 strcpy(addr, string_ftpport);
1021 /* parse the port */
1022 if(ip_end != NULL) {
1023 port_start = strchr(ip_end, ':');
1025 port_min = curlx_ultous(strtoul(port_start + 1, NULL, 10));
1026 port_sep = strchr(port_start, '-');
1028 port_max = curlx_ultous(strtoul(port_sep + 1, NULL, 10));
1031 port_max = port_min;
1035 /* correct errors like:
1037 * :-4711, in this case port_min is (unsigned)-1,
1038 * therefore port_min > port_max for all cases
1039 * but port_max = (unsigned)-1
1041 if(port_min > port_max)
1042 port_min = port_max = 0;
1046 /* attempt to get the address of the given interface name */
1047 switch(Curl_if2ip(conn->ip_addr->ai_family,
1048 Curl_ipv6_scope(conn->ip_addr->ai_addr),
1049 conn->scope_id, addr, hbuf, sizeof(hbuf))) {
1050 case IF2IP_NOT_FOUND:
1051 /* not an interface, use the given string as host name instead */
1054 case IF2IP_AF_NOT_SUPPORTED:
1055 return CURLE_FTP_PORT_FAILED;
1057 host = hbuf; /* use the hbuf for host name */
1061 /* there was only a port(-range) given, default the host */
1063 } /* data->set.ftpport */
1066 /* not an interface and not a host name, get default by extracting
1067 the IP from the control connection */
1070 if(getsockname(conn->sock[FIRSTSOCKET], sa, &sslen)) {
1071 failf(data, "getsockname() failed: %s",
1072 Curl_strerror(conn, SOCKERRNO) );
1074 return CURLE_FTP_PORT_FAILED;
1076 switch(sa->sa_family) {
1079 Curl_inet_ntop(sa->sa_family, &sa6->sin6_addr, hbuf, sizeof(hbuf));
1083 Curl_inet_ntop(sa->sa_family, &sa4->sin_addr, hbuf, sizeof(hbuf));
1086 host = hbuf; /* use this host name */
1087 possibly_non_local = FALSE; /* we know it is local now */
1090 /* resolv ip/host to ip */
1091 rc = Curl_resolv(conn, host, 0, &h);
1092 if(rc == CURLRESOLV_PENDING)
1093 (void)Curl_resolver_wait_resolv(conn, &h);
1096 /* when we return from this function, we can forget about this entry
1097 to we can unlock it now already */
1098 Curl_resolv_unlock(data, h);
1101 res = NULL; /* failure! */
1104 failf(data, "failed to resolve the address provided to PORT: %s", host);
1106 return CURLE_FTP_PORT_FAILED;
1112 /* step 2, create a socket for the requested address */
1114 portsock = CURL_SOCKET_BAD;
1116 for(ai = res; ai; ai = ai->ai_next) {
1117 result = Curl_socket(conn, ai, NULL, &portsock);
1125 failf(data, "socket failure: %s", Curl_strerror(conn, error));
1126 return CURLE_FTP_PORT_FAILED;
1129 /* step 3, bind to a suitable local address */
1131 memcpy(sa, ai->ai_addr, ai->ai_addrlen);
1132 sslen = ai->ai_addrlen;
1134 for(port = port_min; port <= port_max;) {
1135 if(sa->sa_family == AF_INET)
1136 sa4->sin_port = htons(port);
1139 sa6->sin6_port = htons(port);
1141 /* Try binding the given address. */
1142 if(bind(portsock, sa, sslen) ) {
1145 if(possibly_non_local && (error == EADDRNOTAVAIL)) {
1146 /* The requested bind address is not local. Use the address used for
1147 * the control connection instead and restart the port loop
1150 infof(data, "bind(port=%hu) on non-local address failed: %s\n", port,
1151 Curl_strerror(conn, error) );
1154 if(getsockname(conn->sock[FIRSTSOCKET], sa, &sslen)) {
1155 failf(data, "getsockname() failed: %s",
1156 Curl_strerror(conn, SOCKERRNO) );
1157 Curl_closesocket(conn, portsock);
1158 return CURLE_FTP_PORT_FAILED;
1161 possibly_non_local = FALSE; /* don't try this again */
1164 if(error != EADDRINUSE && error != EACCES) {
1165 failf(data, "bind(port=%hu) failed: %s", port,
1166 Curl_strerror(conn, error) );
1167 Curl_closesocket(conn, portsock);
1168 return CURLE_FTP_PORT_FAILED;
1177 /* maybe all ports were in use already*/
1178 if(port > port_max) {
1179 failf(data, "bind() failed, we ran out of ports!");
1180 Curl_closesocket(conn, portsock);
1181 return CURLE_FTP_PORT_FAILED;
1184 /* get the name again after the bind() so that we can extract the
1185 port number it uses now */
1187 if(getsockname(portsock, (struct sockaddr *)sa, &sslen)) {
1188 failf(data, "getsockname() failed: %s",
1189 Curl_strerror(conn, SOCKERRNO) );
1190 Curl_closesocket(conn, portsock);
1191 return CURLE_FTP_PORT_FAILED;
1194 /* step 4, listen on the socket */
1196 if(listen(portsock, 1)) {
1197 failf(data, "socket failure: %s", Curl_strerror(conn, SOCKERRNO));
1198 Curl_closesocket(conn, portsock);
1199 return CURLE_FTP_PORT_FAILED;
1202 /* step 5, send the proper FTP command */
1204 /* get a plain printable version of the numerical address to work with
1206 Curl_printable_address(ai, myhost, sizeof(myhost));
1209 if(!conn->bits.ftp_use_eprt && conn->bits.ipv6)
1210 /* EPRT is disabled but we are connected to a IPv6 host, so we ignore the
1211 request and enable EPRT again! */
1212 conn->bits.ftp_use_eprt = TRUE;
1215 for(; fcmd != DONE; fcmd++) {
1217 if(!conn->bits.ftp_use_eprt && (EPRT == fcmd))
1218 /* if disabled, goto next */
1221 if((PORT == fcmd) && sa->sa_family != AF_INET)
1222 /* PORT is IPv4 only */
1225 switch(sa->sa_family) {
1227 port = ntohs(sa4->sin_port);
1231 port = ntohs(sa6->sin6_port);
1235 continue; /* might as well skip this */
1240 * Two fine examples from RFC2428;
1242 * EPRT |1|132.235.1.2|6275|
1244 * EPRT |2|1080::8:800:200C:417A|5282|
1247 result = Curl_pp_sendf(&ftpc->pp, "%s |%d|%s|%hu|", mode[fcmd],
1248 sa->sa_family == AF_INET?1:2,
1251 failf(data, "Failure sending EPRT command: %s",
1252 curl_easy_strerror(result));
1253 Curl_closesocket(conn, portsock);
1254 /* don't retry using PORT */
1255 ftpc->count1 = PORT;
1257 state(conn, FTP_STOP);
1263 char *source = myhost;
1266 /* translate x.x.x.x to x,x,x,x */
1267 while(source && *source) {
1276 snprintf(dest, 20, ",%d,%d", (int)(port>>8), (int)(port&0xff));
1278 result = Curl_pp_sendf(&ftpc->pp, "%s %s", mode[fcmd], tmp);
1280 failf(data, "Failure sending PORT command: %s",
1281 curl_easy_strerror(result));
1282 Curl_closesocket(conn, portsock);
1284 state(conn, FTP_STOP);
1291 /* store which command was sent */
1292 ftpc->count1 = fcmd;
1294 close_secondarysocket(conn);
1296 /* we set the secondary socket variable to this for now, it is only so that
1297 the cleanup function will close it in case we fail before the true
1298 secondary stuff is made */
1299 conn->sock[SECONDARYSOCKET] = portsock;
1301 /* this tcpconnect assignment below is a hackish work-around to make the
1302 multi interface with active FTP work - as it will not wait for a
1303 (passive) connect in Curl_is_connected().
1305 The *proper* fix is to make sure that the active connection from the
1306 server is done in a non-blocking way. Currently, it is still BLOCKING.
1308 conn->bits.tcpconnect[SECONDARYSOCKET] = TRUE;
1310 state(conn, FTP_PORT);
1314 static CURLcode ftp_state_use_pasv(struct connectdata *conn)
1316 struct ftp_conn *ftpc = &conn->proto.ftpc;
1317 CURLcode result = CURLE_OK;
1319 Here's the excecutive summary on what to do:
1321 PASV is RFC959, expect:
1322 227 Entering Passive Mode (a1,a2,a3,a4,p1,p2)
1324 LPSV is RFC1639, expect:
1325 228 Entering Long Passive Mode (4,4,a1,a2,a3,a4,2,p1,p2)
1327 EPSV is RFC2428, expect:
1328 229 Entering Extended Passive Mode (|||port|)
1332 static const char mode[][5] = { "EPSV", "PASV" };
1336 if(!conn->bits.ftp_use_epsv && conn->bits.ipv6)
1337 /* EPSV is disabled but we are connected to a IPv6 host, so we ignore the
1338 request and enable EPSV again! */
1339 conn->bits.ftp_use_epsv = TRUE;
1342 modeoff = conn->bits.ftp_use_epsv?0:1;
1344 PPSENDF(&ftpc->pp, "%s", mode[modeoff]);
1346 ftpc->count1 = modeoff;
1347 state(conn, FTP_PASV);
1348 infof(conn->data, "Connect data stream passively\n");
1354 * ftp_state_prepare_transfer() starts PORT, PASV or PRET etc.
1356 * REST is the last command in the chain of commands when a "head"-like
1357 * request is made. Thus, if an actual transfer is to be made this is where we
1358 * take off for real.
1360 static CURLcode ftp_state_prepare_transfer(struct connectdata *conn)
1362 CURLcode result = CURLE_OK;
1363 struct FTP *ftp = conn->data->req.protop;
1364 struct Curl_easy *data = conn->data;
1366 if(ftp->transfer != FTPTRANSFER_BODY) {
1367 /* doesn't transfer any data */
1369 /* still possibly do PRE QUOTE jobs */
1370 state(conn, FTP_RETR_PREQUOTE);
1371 result = ftp_state_quote(conn, TRUE, FTP_RETR_PREQUOTE);
1373 else if(data->set.ftp_use_port) {
1374 /* We have chosen to use the PORT (or similar) command */
1375 result = ftp_state_use_port(conn, EPRT);
1378 /* We have chosen (this is default) to use the PASV (or similar) command */
1379 if(data->set.ftp_use_pret) {
1380 /* The user has requested that we send a PRET command
1381 to prepare the server for the upcoming PASV */
1382 if(!conn->proto.ftpc.file) {
1383 PPSENDF(&conn->proto.ftpc.pp, "PRET %s",
1384 data->set.str[STRING_CUSTOMREQUEST]?
1385 data->set.str[STRING_CUSTOMREQUEST]:
1386 (data->set.ftp_list_only?"NLST":"LIST"));
1388 else if(data->set.upload) {
1389 PPSENDF(&conn->proto.ftpc.pp, "PRET STOR %s", conn->proto.ftpc.file);
1392 PPSENDF(&conn->proto.ftpc.pp, "PRET RETR %s", conn->proto.ftpc.file);
1394 state(conn, FTP_PRET);
1397 result = ftp_state_use_pasv(conn);
1403 static CURLcode ftp_state_rest(struct connectdata *conn)
1405 CURLcode result = CURLE_OK;
1406 struct FTP *ftp = conn->data->req.protop;
1407 struct ftp_conn *ftpc = &conn->proto.ftpc;
1409 if((ftp->transfer != FTPTRANSFER_BODY) && ftpc->file) {
1410 /* if a "head"-like request is being made (on a file) */
1412 /* Determine if server can respond to REST command and therefore
1413 whether it supports range */
1414 PPSENDF(&conn->proto.ftpc.pp, "REST %d", 0);
1416 state(conn, FTP_REST);
1419 result = ftp_state_prepare_transfer(conn);
1424 static CURLcode ftp_state_size(struct connectdata *conn)
1426 CURLcode result = CURLE_OK;
1427 struct FTP *ftp = conn->data->req.protop;
1428 struct ftp_conn *ftpc = &conn->proto.ftpc;
1430 if((ftp->transfer == FTPTRANSFER_INFO) && ftpc->file) {
1431 /* if a "head"-like request is being made (on a file) */
1433 /* we know ftpc->file is a valid pointer to a file name */
1434 PPSENDF(&ftpc->pp, "SIZE %s", ftpc->file);
1436 state(conn, FTP_SIZE);
1439 result = ftp_state_rest(conn);
1444 static CURLcode ftp_state_list(struct connectdata *conn)
1446 CURLcode result = CURLE_OK;
1447 struct Curl_easy *data = conn->data;
1449 /* If this output is to be machine-parsed, the NLST command might be better
1450 to use, since the LIST command output is not specified or standard in any
1451 way. It has turned out that the NLST list output is not the same on all
1452 servers either... */
1455 if FTPFILE_NOCWD was specified, we are currently in
1456 the user's home directory, so we should add the path
1457 as argument for the LIST / NLST / or custom command.
1458 Whether the server will support this, is uncertain.
1460 The other ftp_filemethods will CWD into dir/dir/ first and
1461 then just do LIST (in that case: nothing to do here)
1463 char *cmd, *lstArg, *slashPos;
1464 const char *inpath = data->state.path;
1467 if((data->set.ftp_filemethod == FTPFILE_NOCWD) &&
1468 inpath && inpath[0] && strchr(inpath, '/')) {
1469 size_t n = strlen(inpath);
1471 /* Check if path does not end with /, as then we cut off the file part */
1472 if(inpath[n - 1] != '/') {
1473 /* chop off the file part if format is dir/dir/file */
1474 slashPos = strrchr(inpath, '/');
1475 n = slashPos - inpath;
1477 result = Curl_urldecode(data, inpath, n, &lstArg, NULL, TRUE);
1482 cmd = aprintf("%s%s%s",
1483 data->set.str[STRING_CUSTOMREQUEST]?
1484 data->set.str[STRING_CUSTOMREQUEST]:
1485 (data->set.ftp_list_only?"NLST":"LIST"),
1487 lstArg? lstArg: "");
1491 return CURLE_OUT_OF_MEMORY;
1494 result = Curl_pp_sendf(&conn->proto.ftpc.pp, "%s", cmd);
1502 state(conn, FTP_LIST);
1507 static CURLcode ftp_state_retr_prequote(struct connectdata *conn)
1509 CURLcode result = CURLE_OK;
1511 /* We've sent the TYPE, now we must send the list of prequote strings */
1513 result = ftp_state_quote(conn, TRUE, FTP_RETR_PREQUOTE);
1518 static CURLcode ftp_state_stor_prequote(struct connectdata *conn)
1520 CURLcode result = CURLE_OK;
1522 /* We've sent the TYPE, now we must send the list of prequote strings */
1524 result = ftp_state_quote(conn, TRUE, FTP_STOR_PREQUOTE);
1529 static CURLcode ftp_state_type(struct connectdata *conn)
1531 CURLcode result = CURLE_OK;
1532 struct FTP *ftp = conn->data->req.protop;
1533 struct Curl_easy *data = conn->data;
1534 struct ftp_conn *ftpc = &conn->proto.ftpc;
1536 /* If we have selected NOBODY and HEADER, it means that we only want file
1537 information. Which in FTP can't be much more than the file size and
1539 if(data->set.opt_no_body && ftpc->file &&
1540 ftp_need_type(conn, data->set.prefer_ascii)) {
1541 /* The SIZE command is _not_ RFC 959 specified, and therefore many servers
1542 may not support it! It is however the only way we have to get a file's
1545 ftp->transfer = FTPTRANSFER_INFO;
1546 /* this means no actual transfer will be made */
1548 /* Some servers return different sizes for different modes, and thus we
1549 must set the proper type before we check the size */
1550 result = ftp_nb_type(conn, data->set.prefer_ascii, FTP_TYPE);
1555 result = ftp_state_size(conn);
1560 /* This is called after the CWD commands have been done in the beginning of
1562 static CURLcode ftp_state_mdtm(struct connectdata *conn)
1564 CURLcode result = CURLE_OK;
1565 struct Curl_easy *data = conn->data;
1566 struct ftp_conn *ftpc = &conn->proto.ftpc;
1568 /* Requested time of file or time-depended transfer? */
1569 if((data->set.get_filetime || data->set.timecondition) && ftpc->file) {
1571 /* we have requested to get the modified-time of the file, this is a white
1572 spot as the MDTM is not mentioned in RFC959 */
1573 PPSENDF(&ftpc->pp, "MDTM %s", ftpc->file);
1575 state(conn, FTP_MDTM);
1578 result = ftp_state_type(conn);
1584 /* This is called after the TYPE and possible quote commands have been sent */
1585 static CURLcode ftp_state_ul_setup(struct connectdata *conn,
1588 CURLcode result = CURLE_OK;
1589 struct FTP *ftp = conn->data->req.protop;
1590 struct Curl_easy *data = conn->data;
1591 struct ftp_conn *ftpc = &conn->proto.ftpc;
1592 int seekerr = CURL_SEEKFUNC_OK;
1594 if((data->state.resume_from && !sizechecked) ||
1595 ((data->state.resume_from > 0) && sizechecked)) {
1596 /* we're about to continue the uploading of a file */
1597 /* 1. get already existing file's size. We use the SIZE command for this
1598 which may not exist in the server! The SIZE command is not in
1601 /* 2. This used to set REST. But since we can do append, we
1602 don't another ftp command. We just skip the source file
1603 offset and then we APPEND the rest on the file instead */
1605 /* 3. pass file-size number of bytes in the source file */
1606 /* 4. lower the infilesize counter */
1607 /* => transfer as usual */
1609 if(data->state.resume_from < 0) {
1610 /* Got no given size to start from, figure it out */
1611 PPSENDF(&ftpc->pp, "SIZE %s", ftpc->file);
1612 state(conn, FTP_STOR_SIZE);
1617 data->set.ftp_append = TRUE;
1619 /* Let's read off the proper amount of bytes from the input. */
1620 if(conn->seek_func) {
1621 Curl_set_in_callback(data, true);
1622 seekerr = conn->seek_func(conn->seek_client, data->state.resume_from,
1624 Curl_set_in_callback(data, true);
1627 if(seekerr != CURL_SEEKFUNC_OK) {
1628 curl_off_t passed = 0;
1629 if(seekerr != CURL_SEEKFUNC_CANTSEEK) {
1630 failf(data, "Could not seek stream");
1631 return CURLE_FTP_COULDNT_USE_REST;
1633 /* seekerr == CURL_SEEKFUNC_CANTSEEK (can't seek to offset) */
1635 size_t readthisamountnow =
1636 (data->state.resume_from - passed > data->set.buffer_size) ?
1637 (size_t)data->set.buffer_size :
1638 curlx_sotouz(data->state.resume_from - passed);
1640 size_t actuallyread =
1641 data->state.fread_func(data->state.buffer, 1, readthisamountnow,
1644 passed += actuallyread;
1645 if((actuallyread == 0) || (actuallyread > readthisamountnow)) {
1646 /* this checks for greater-than only to make sure that the
1647 CURL_READFUNC_ABORT return code still aborts */
1648 failf(data, "Failed to read data");
1649 return CURLE_FTP_COULDNT_USE_REST;
1651 } while(passed < data->state.resume_from);
1653 /* now, decrease the size of the read */
1654 if(data->state.infilesize>0) {
1655 data->state.infilesize -= data->state.resume_from;
1657 if(data->state.infilesize <= 0) {
1658 infof(data, "File already completely uploaded\n");
1660 /* no data to transfer */
1661 Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
1663 /* Set ->transfer so that we won't get any error in
1664 * ftp_done() because we didn't transfer anything! */
1665 ftp->transfer = FTPTRANSFER_NONE;
1667 state(conn, FTP_STOP);
1671 /* we've passed, proceed as normal */
1674 PPSENDF(&ftpc->pp, data->set.ftp_append?"APPE %s":"STOR %s",
1677 state(conn, FTP_STOR);
1682 static CURLcode ftp_state_quote(struct connectdata *conn,
1686 CURLcode result = CURLE_OK;
1687 struct Curl_easy *data = conn->data;
1688 struct FTP *ftp = data->req.protop;
1689 struct ftp_conn *ftpc = &conn->proto.ftpc;
1691 struct curl_slist *item;
1696 item = data->set.quote;
1698 case FTP_RETR_PREQUOTE:
1699 case FTP_STOR_PREQUOTE:
1700 item = data->set.prequote;
1703 item = data->set.postquote;
1709 * 'count1' to iterate over the commands to send
1710 * 'count2' to store whether to allow commands to fail
1721 /* Skip count1 items in the linked list */
1722 while((i< ftpc->count1) && item) {
1727 char *cmd = item->data;
1730 ftpc->count2 = 1; /* the sent command is allowed to fail */
1733 ftpc->count2 = 0; /* failure means cancel operation */
1735 PPSENDF(&ftpc->pp, "%s", cmd);
1736 state(conn, instate);
1742 /* No more quote to send, continue to ... */
1746 result = ftp_state_cwd(conn);
1748 case FTP_RETR_PREQUOTE:
1749 if(ftp->transfer != FTPTRANSFER_BODY)
1750 state(conn, FTP_STOP);
1752 if(ftpc->known_filesize != -1) {
1753 Curl_pgrsSetDownloadSize(data, ftpc->known_filesize);
1754 result = ftp_state_retr(conn, ftpc->known_filesize);
1757 if(data->set.ignorecl) {
1758 /* This code is to support download of growing files. It prevents
1759 the state machine from requesting the file size from the
1760 server. With an unknown file size the download continues until
1761 the server terminates it, otherwise the client stops if the
1762 received byte count exceeds the reported file size. Set option
1763 CURLOPT_IGNORE_CONTENT_LENGTH to 1 to enable this behavior.*/
1764 PPSENDF(&ftpc->pp, "RETR %s", ftpc->file);
1765 state(conn, FTP_RETR);
1768 PPSENDF(&ftpc->pp, "SIZE %s", ftpc->file);
1769 state(conn, FTP_RETR_SIZE);
1774 case FTP_STOR_PREQUOTE:
1775 result = ftp_state_ul_setup(conn, FALSE);
1785 /* called from ftp_state_pasv_resp to switch to PASV in case of EPSV
1787 static CURLcode ftp_epsv_disable(struct connectdata *conn)
1789 CURLcode result = CURLE_OK;
1791 if(conn->bits.ipv6) {
1792 /* We can't disable EPSV when doing IPv6, so this is instead a fail */
1793 failf(conn->data, "Failed EPSV attempt, exiting\n");
1794 return CURLE_WEIRD_SERVER_REPLY;
1797 infof(conn->data, "Failed EPSV attempt. Disabling EPSV\n");
1798 /* disable it for next transfer */
1799 conn->bits.ftp_use_epsv = FALSE;
1800 conn->data->state.errorbuf = FALSE; /* allow error message to get
1802 PPSENDF(&conn->proto.ftpc.pp, "%s", "PASV");
1803 conn->proto.ftpc.count1++;
1804 /* remain in/go to the FTP_PASV state */
1805 state(conn, FTP_PASV);
1810 static char *control_address(struct connectdata *conn)
1812 /* Returns the control connection IP address.
1813 If a proxy tunnel is used, returns the original host name instead, because
1814 the effective control connection address is the proxy address,
1815 not the ftp host. */
1816 if(conn->bits.tunnel_proxy || conn->bits.socksproxy)
1817 return conn->host.name;
1819 return conn->ip_addr_str;
1822 static CURLcode ftp_state_pasv_resp(struct connectdata *conn,
1825 struct ftp_conn *ftpc = &conn->proto.ftpc;
1827 struct Curl_easy *data = conn->data;
1828 struct Curl_dns_entry *addr = NULL;
1830 unsigned short connectport; /* the local port connect() should use! */
1831 char *str = &data->state.buffer[4]; /* start on the first letter */
1833 /* if we come here again, make sure the former name is cleared */
1834 Curl_safefree(ftpc->newhost);
1836 if((ftpc->count1 == 0) &&
1838 /* positive EPSV response */
1839 char *ptr = strchr(str, '(');
1844 if(5 == sscanf(ptr, "%c%c%c%u%c",
1850 const char sep1 = separator[0];
1853 /* The four separators should be identical, or else this is an oddly
1854 formatted reply and we bail out immediately. */
1855 for(i = 1; i<4; i++) {
1856 if(separator[i] != sep1) {
1857 ptr = NULL; /* set to NULL to signal error */
1862 failf(data, "Illegal port number in EPSV reply");
1863 return CURLE_FTP_WEIRD_PASV_REPLY;
1866 ftpc->newport = (unsigned short)(num & 0xffff);
1867 ftpc->newhost = strdup(control_address(conn));
1869 return CURLE_OUT_OF_MEMORY;
1876 failf(data, "Weirdly formatted EPSV reply");
1877 return CURLE_FTP_WEIRD_PASV_REPLY;
1880 else if((ftpc->count1 == 1) &&
1882 /* positive PASV response */
1884 unsigned int port[2];
1887 * Scan for a sequence of six comma-separated numbers and use them as
1888 * IP+port indicators.
1890 * Found reply-strings include:
1891 * "227 Entering Passive Mode (127,0,0,1,4,51)"
1892 * "227 Data transfer will passively listen to 127,0,0,1,4,51"
1893 * "227 Entering passive mode. 127,0,0,1,4,51"
1896 if(6 == sscanf(str, "%u,%u,%u,%u,%u,%u",
1897 &ip[0], &ip[1], &ip[2], &ip[3],
1898 &port[0], &port[1]))
1903 if(!*str || (ip[0] > 255) || (ip[1] > 255) || (ip[2] > 255) ||
1904 (ip[3] > 255) || (port[0] > 255) || (port[1] > 255) ) {
1905 failf(data, "Couldn't interpret the 227-response");
1906 return CURLE_FTP_WEIRD_227_FORMAT;
1909 /* we got OK from server */
1910 if(data->set.ftp_skip_ip) {
1911 /* told to ignore the remotely given IP but instead use the host we used
1912 for the control connection */
1913 infof(data, "Skip %d.%d.%d.%d for data connection, re-use %s instead\n",
1914 ip[0], ip[1], ip[2], ip[3],
1916 ftpc->newhost = strdup(control_address(conn));
1919 ftpc->newhost = aprintf("%d.%d.%d.%d", ip[0], ip[1], ip[2], ip[3]);
1922 return CURLE_OUT_OF_MEMORY;
1924 ftpc->newport = (unsigned short)(((port[0]<<8) + port[1]) & 0xffff);
1926 else if(ftpc->count1 == 0) {
1927 /* EPSV failed, move on to PASV */
1928 return ftp_epsv_disable(conn);
1931 failf(data, "Bad PASV/EPSV response: %03d", ftpcode);
1932 return CURLE_FTP_WEIRD_PASV_REPLY;
1935 if(conn->bits.proxy) {
1937 * This connection uses a proxy and we need to connect to the proxy again
1938 * here. We don't want to rely on a former host lookup that might've
1939 * expired now, instead we remake the lookup here and now!
1941 const char * const host_name = conn->bits.socksproxy ?
1942 conn->socks_proxy.host.name : conn->http_proxy.host.name;
1943 rc = Curl_resolv(conn, host_name, (int)conn->port, &addr);
1944 if(rc == CURLRESOLV_PENDING)
1945 /* BLOCKING, ignores the return code but 'addr' will be NULL in
1947 (void)Curl_resolver_wait_resolv(conn, &addr);
1950 (unsigned short)conn->port; /* we connect to the proxy's port */
1953 failf(data, "Can't resolve proxy host %s:%hu", host_name, connectport);
1954 return CURLE_COULDNT_RESOLVE_PROXY;
1958 /* normal, direct, ftp connection */
1959 rc = Curl_resolv(conn, ftpc->newhost, ftpc->newport, &addr);
1960 if(rc == CURLRESOLV_PENDING)
1962 (void)Curl_resolver_wait_resolv(conn, &addr);
1964 connectport = ftpc->newport; /* we connect to the remote port */
1967 failf(data, "Can't resolve new host %s:%hu", ftpc->newhost, connectport);
1968 return CURLE_FTP_CANT_GET_HOST;
1972 conn->bits.tcpconnect[SECONDARYSOCKET] = FALSE;
1973 result = Curl_connecthost(conn, addr);
1976 Curl_resolv_unlock(data, addr); /* we're done using this address */
1977 if(ftpc->count1 == 0 && ftpcode == 229)
1978 return ftp_epsv_disable(conn);
1985 * When this is used from the multi interface, this might've returned with
1986 * the 'connected' set to FALSE and thus we are now awaiting a non-blocking
1987 * connect to connect.
1990 if(data->set.verbose)
1991 /* this just dumps information about this second connection */
1992 ftp_pasv_verbose(conn, addr->addr, ftpc->newhost, connectport);
1994 Curl_resolv_unlock(data, addr); /* we're done using this address */
1996 Curl_safefree(conn->secondaryhostname);
1997 conn->secondary_port = ftpc->newport;
1998 conn->secondaryhostname = strdup(ftpc->newhost);
1999 if(!conn->secondaryhostname)
2000 return CURLE_OUT_OF_MEMORY;
2002 conn->bits.do_more = TRUE;
2003 state(conn, FTP_STOP); /* this phase is completed */
2008 static CURLcode ftp_state_port_resp(struct connectdata *conn,
2011 struct Curl_easy *data = conn->data;
2012 struct ftp_conn *ftpc = &conn->proto.ftpc;
2013 ftpport fcmd = (ftpport)ftpc->count1;
2014 CURLcode result = CURLE_OK;
2016 /* The FTP spec tells a positive response should have code 200.
2017 Be more permissive here to tolerate deviant servers. */
2018 if(ftpcode / 100 != 2) {
2019 /* the command failed */
2022 infof(data, "disabling EPRT usage\n");
2023 conn->bits.ftp_use_eprt = FALSE;
2028 failf(data, "Failed to do PORT");
2029 result = CURLE_FTP_PORT_FAILED;
2033 result = ftp_state_use_port(conn, fcmd);
2036 infof(data, "Connect data stream actively\n");
2037 state(conn, FTP_STOP); /* end of DO phase */
2038 result = ftp_dophase_done(conn, FALSE);
2044 static CURLcode ftp_state_mdtm_resp(struct connectdata *conn,
2047 CURLcode result = CURLE_OK;
2048 struct Curl_easy *data = conn->data;
2049 struct FTP *ftp = data->req.protop;
2050 struct ftp_conn *ftpc = &conn->proto.ftpc;
2055 /* we got a time. Format should be: "YYYYMMDDHHMMSS[.sss]" where the
2056 last .sss part is optional and means fractions of a second */
2057 int year, month, day, hour, minute, second;
2058 if(6 == sscanf(&data->state.buffer[4], "%04d%02d%02d%02d%02d%02d",
2059 &year, &month, &day, &hour, &minute, &second)) {
2060 /* we have a time, reformat it */
2062 time_t secs = time(NULL);
2064 snprintf(timebuf, sizeof(timebuf),
2065 "%04d%02d%02d %02d:%02d:%02d GMT",
2066 year, month, day, hour, minute, second);
2067 /* now, convert this into a time() value: */
2068 data->info.filetime = curl_getdate(timebuf, &secs);
2071 #ifdef CURL_FTP_HTTPSTYLE_HEAD
2072 /* If we asked for a time of the file and we actually got one as well,
2073 we "emulate" a HTTP-style header in our output. */
2075 if(data->set.opt_no_body &&
2077 data->set.get_filetime &&
2078 (data->info.filetime >= 0) ) {
2079 char headerbuf[128];
2080 time_t filetime = data->info.filetime;
2082 const struct tm *tm = &buffer;
2084 result = Curl_gmtime(filetime, &buffer);
2088 /* format: "Tue, 15 Nov 1994 12:45:26" */
2089 snprintf(headerbuf, sizeof(headerbuf),
2090 "Last-Modified: %s, %02d %s %4d %02d:%02d:%02d GMT\r\n",
2091 Curl_wkday[tm->tm_wday?tm->tm_wday-1:6],
2093 Curl_month[tm->tm_mon],
2098 result = Curl_client_write(conn, CLIENTWRITE_BOTH, headerbuf, 0);
2101 } /* end of a ridiculous amount of conditionals */
2106 infof(data, "unsupported MDTM reply format\n");
2108 case 550: /* "No such file or directory" */
2109 failf(data, "Given file does not exist");
2110 result = CURLE_FTP_COULDNT_RETR_FILE;
2114 if(data->set.timecondition) {
2115 if((data->info.filetime > 0) && (data->set.timevalue > 0)) {
2116 switch(data->set.timecondition) {
2117 case CURL_TIMECOND_IFMODSINCE:
2119 if(data->info.filetime <= data->set.timevalue) {
2120 infof(data, "The requested document is not new enough\n");
2121 ftp->transfer = FTPTRANSFER_NONE; /* mark to not transfer data */
2122 data->info.timecond = TRUE;
2123 state(conn, FTP_STOP);
2127 case CURL_TIMECOND_IFUNMODSINCE:
2128 if(data->info.filetime > data->set.timevalue) {
2129 infof(data, "The requested document is not old enough\n");
2130 ftp->transfer = FTPTRANSFER_NONE; /* mark to not transfer data */
2131 data->info.timecond = TRUE;
2132 state(conn, FTP_STOP);
2139 infof(data, "Skipping time comparison\n");
2144 result = ftp_state_type(conn);
2149 static CURLcode ftp_state_type_resp(struct connectdata *conn,
2153 CURLcode result = CURLE_OK;
2154 struct Curl_easy *data = conn->data;
2156 if(ftpcode/100 != 2) {
2157 /* "sasserftpd" and "(u)r(x)bot ftpd" both responds with 226 after a
2158 successful 'TYPE I'. While that is not as RFC959 says, it is still a
2159 positive response code and we allow that. */
2160 failf(data, "Couldn't set desired mode");
2161 return CURLE_FTP_COULDNT_SET_TYPE;
2164 infof(data, "Got a %03d response code instead of the assumed 200\n",
2167 if(instate == FTP_TYPE)
2168 result = ftp_state_size(conn);
2169 else if(instate == FTP_LIST_TYPE)
2170 result = ftp_state_list(conn);
2171 else if(instate == FTP_RETR_TYPE)
2172 result = ftp_state_retr_prequote(conn);
2173 else if(instate == FTP_STOR_TYPE)
2174 result = ftp_state_stor_prequote(conn);
2179 static CURLcode ftp_state_retr(struct connectdata *conn,
2180 curl_off_t filesize)
2182 CURLcode result = CURLE_OK;
2183 struct Curl_easy *data = conn->data;
2184 struct FTP *ftp = data->req.protop;
2185 struct ftp_conn *ftpc = &conn->proto.ftpc;
2187 if(data->set.max_filesize && (filesize > data->set.max_filesize)) {
2188 failf(data, "Maximum file size exceeded");
2189 return CURLE_FILESIZE_EXCEEDED;
2191 ftp->downloadsize = filesize;
2193 if(data->state.resume_from) {
2194 /* We always (attempt to) get the size of downloads, so it is done before
2195 this even when not doing resumes. */
2196 if(filesize == -1) {
2197 infof(data, "ftp server doesn't support SIZE\n");
2198 /* We couldn't get the size and therefore we can't know if there really
2199 is a part of the file left to get, although the server will just
2200 close the connection when we start the connection so it won't cause
2201 us any harm, just not make us exit as nicely. */
2204 /* We got a file size report, so we check that there actually is a
2205 part of the file left to get, or else we go home. */
2206 if(data->state.resume_from< 0) {
2207 /* We're supposed to download the last abs(from) bytes */
2208 if(filesize < -data->state.resume_from) {
2209 failf(data, "Offset (%" CURL_FORMAT_CURL_OFF_T
2210 ") was beyond file size (%" CURL_FORMAT_CURL_OFF_T ")",
2211 data->state.resume_from, filesize);
2212 return CURLE_BAD_DOWNLOAD_RESUME;
2214 /* convert to size to download */
2215 ftp->downloadsize = -data->state.resume_from;
2216 /* download from where? */
2217 data->state.resume_from = filesize - ftp->downloadsize;
2220 if(filesize < data->state.resume_from) {
2221 failf(data, "Offset (%" CURL_FORMAT_CURL_OFF_T
2222 ") was beyond file size (%" CURL_FORMAT_CURL_OFF_T ")",
2223 data->state.resume_from, filesize);
2224 return CURLE_BAD_DOWNLOAD_RESUME;
2226 /* Now store the number of bytes we are expected to download */
2227 ftp->downloadsize = filesize-data->state.resume_from;
2231 if(ftp->downloadsize == 0) {
2232 /* no data to transfer */
2233 Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
2234 infof(data, "File already completely downloaded\n");
2236 /* Set ->transfer so that we won't get any error in ftp_done()
2237 * because we didn't transfer the any file */
2238 ftp->transfer = FTPTRANSFER_NONE;
2239 state(conn, FTP_STOP);
2243 /* Set resume file transfer offset */
2244 infof(data, "Instructs server to resume from offset %"
2245 CURL_FORMAT_CURL_OFF_T "\n", data->state.resume_from);
2247 PPSENDF(&ftpc->pp, "REST %" CURL_FORMAT_CURL_OFF_T,
2248 data->state.resume_from);
2250 state(conn, FTP_RETR_REST);
2254 PPSENDF(&ftpc->pp, "RETR %s", ftpc->file);
2255 state(conn, FTP_RETR);
2261 static CURLcode ftp_state_size_resp(struct connectdata *conn,
2265 CURLcode result = CURLE_OK;
2266 struct Curl_easy *data = conn->data;
2267 curl_off_t filesize = -1;
2268 char *buf = data->state.buffer;
2270 /* get the size from the ascii string: */
2272 /* ignores parsing errors, which will make the size remain unknown */
2273 (void)curlx_strtoofft(buf + 4, NULL, 0, &filesize);
2275 if(instate == FTP_SIZE) {
2276 #ifdef CURL_FTP_HTTPSTYLE_HEAD
2277 if(-1 != filesize) {
2279 snprintf(clbuf, sizeof(clbuf),
2280 "Content-Length: %" CURL_FORMAT_CURL_OFF_T "\r\n", filesize);
2281 result = Curl_client_write(conn, CLIENTWRITE_BOTH, clbuf, 0);
2286 Curl_pgrsSetDownloadSize(data, filesize);
2287 result = ftp_state_rest(conn);
2289 else if(instate == FTP_RETR_SIZE) {
2290 Curl_pgrsSetDownloadSize(data, filesize);
2291 result = ftp_state_retr(conn, filesize);
2293 else if(instate == FTP_STOR_SIZE) {
2294 data->state.resume_from = filesize;
2295 result = ftp_state_ul_setup(conn, TRUE);
2301 static CURLcode ftp_state_rest_resp(struct connectdata *conn,
2305 CURLcode result = CURLE_OK;
2306 struct ftp_conn *ftpc = &conn->proto.ftpc;
2311 #ifdef CURL_FTP_HTTPSTYLE_HEAD
2312 if(ftpcode == 350) {
2313 char buffer[24]= { "Accept-ranges: bytes\r\n" };
2314 result = Curl_client_write(conn, CLIENTWRITE_BOTH, buffer, 0);
2319 result = ftp_state_prepare_transfer(conn);
2323 if(ftpcode != 350) {
2324 failf(conn->data, "Couldn't use REST");
2325 result = CURLE_FTP_COULDNT_USE_REST;
2328 PPSENDF(&ftpc->pp, "RETR %s", ftpc->file);
2329 state(conn, FTP_RETR);
2337 static CURLcode ftp_state_stor_resp(struct connectdata *conn,
2338 int ftpcode, ftpstate instate)
2340 CURLcode result = CURLE_OK;
2341 struct Curl_easy *data = conn->data;
2343 if(ftpcode >= 400) {
2344 failf(data, "Failed FTP upload: %0d", ftpcode);
2345 state(conn, FTP_STOP);
2346 /* oops, we never close the sockets! */
2347 return CURLE_UPLOAD_FAILED;
2350 conn->proto.ftpc.state_saved = instate;
2352 /* PORT means we are now awaiting the server to connect to us. */
2353 if(data->set.ftp_use_port) {
2356 state(conn, FTP_STOP); /* no longer in STOR state */
2358 result = AllowServerConnect(conn, &connected);
2363 struct ftp_conn *ftpc = &conn->proto.ftpc;
2364 infof(data, "Data conn was not available immediately\n");
2365 ftpc->wait_data_conn = TRUE;
2370 return InitiateTransfer(conn);
2373 /* for LIST and RETR responses */
2374 static CURLcode ftp_state_get_resp(struct connectdata *conn,
2378 CURLcode result = CURLE_OK;
2379 struct Curl_easy *data = conn->data;
2380 struct FTP *ftp = data->req.protop;
2382 if((ftpcode == 150) || (ftpcode == 125)) {
2386 150 Opening BINARY mode data connection for /etc/passwd (2241
2387 bytes). (ok, the file is being transferred)
2390 150 Opening ASCII mode data connection for /bin/ls
2393 150 ASCII data connection for /bin/ls (137.167.104.91,37445) (0 bytes).
2396 150 Opening ASCII mode data connection for [file] (0.0.0.0,0) (545 bytes)
2399 125 Data connection already open; Transfer starting. */
2401 curl_off_t size = -1; /* default unknown size */
2405 * It appears that there are FTP-servers that return size 0 for files when
2406 * SIZE is used on the file while being in BINARY mode. To work around
2407 * that (stupid) behavior, we attempt to parse the RETR response even if
2408 * the SIZE returned size zero.
2410 * Debugging help from Salvatore Sorrentino on February 26, 2003.
2413 if((instate != FTP_LIST) &&
2414 !data->set.prefer_ascii &&
2415 (ftp->downloadsize < 1)) {
2417 * It seems directory listings either don't show the size or very
2418 * often uses size 0 anyway. ASCII transfers may very well turn out
2419 * that the transferred amount of data is not the same as this line
2420 * tells, why using this number in those cases only confuses us.
2422 * Example D above makes this parsing a little tricky */
2424 char *buf = data->state.buffer;
2425 bytes = strstr(buf, " bytes");
2427 long in = (long)(--bytes-buf);
2428 /* this is a hint there is size information in there! ;-) */
2430 /* scan for the left parenthesis and break there */
2433 /* skip only digits */
2434 if(!ISDIGIT(*bytes)) {
2438 /* one more estep backwards */
2441 /* if we have nothing but digits: */
2443 /* get the number! */
2444 (void)curlx_strtoofft(bytes, NULL, 0, &size);
2448 else if(ftp->downloadsize > -1)
2449 size = ftp->downloadsize;
2451 if(size > data->req.maxdownload && data->req.maxdownload > 0)
2452 size = data->req.size = data->req.maxdownload;
2453 else if((instate != FTP_LIST) && (data->set.prefer_ascii))
2454 size = -1; /* kludge for servers that understate ASCII mode file size */
2456 infof(data, "Maxdownload = %" CURL_FORMAT_CURL_OFF_T "\n",
2457 data->req.maxdownload);
2459 if(instate != FTP_LIST)
2460 infof(data, "Getting file with size: %" CURL_FORMAT_CURL_OFF_T "\n",
2464 conn->proto.ftpc.state_saved = instate;
2465 conn->proto.ftpc.retr_size_saved = size;
2467 if(data->set.ftp_use_port) {
2470 result = AllowServerConnect(conn, &connected);
2475 struct ftp_conn *ftpc = &conn->proto.ftpc;
2476 infof(data, "Data conn was not available immediately\n");
2477 state(conn, FTP_STOP);
2478 ftpc->wait_data_conn = TRUE;
2482 return InitiateTransfer(conn);
2485 if((instate == FTP_LIST) && (ftpcode == 450)) {
2486 /* simply no matching files in the dir listing */
2487 ftp->transfer = FTPTRANSFER_NONE; /* don't download anything */
2488 state(conn, FTP_STOP); /* this phase is over */
2491 failf(data, "RETR response: %03d", ftpcode);
2492 return instate == FTP_RETR && ftpcode == 550?
2493 CURLE_REMOTE_FILE_NOT_FOUND:
2494 CURLE_FTP_COULDNT_RETR_FILE;
2501 /* after USER, PASS and ACCT */
2502 static CURLcode ftp_state_loggedin(struct connectdata *conn)
2504 CURLcode result = CURLE_OK;
2506 if(conn->ssl[FIRSTSOCKET].use) {
2507 /* PBSZ = PROTECTION BUFFER SIZE.
2509 The 'draft-murray-auth-ftp-ssl' (draft 12, page 7) says:
2511 Specifically, the PROT command MUST be preceded by a PBSZ
2512 command and a PBSZ command MUST be preceded by a successful
2513 security data exchange (the TLS negotiation in this case)
2515 ... (and on page 8):
2517 Thus the PBSZ command must still be issued, but must have a
2518 parameter of '0' to indicate that no buffering is taking place
2519 and the data connection should not be encapsulated.
2521 PPSENDF(&conn->proto.ftpc.pp, "PBSZ %d", 0);
2522 state(conn, FTP_PBSZ);
2525 result = ftp_state_pwd(conn);
2530 /* for USER and PASS responses */
2531 static CURLcode ftp_state_user_resp(struct connectdata *conn,
2535 CURLcode result = CURLE_OK;
2536 struct Curl_easy *data = conn->data;
2537 struct FTP *ftp = data->req.protop;
2538 struct ftp_conn *ftpc = &conn->proto.ftpc;
2539 (void)instate; /* no use for this yet */
2541 /* some need password anyway, and others just return 2xx ignored */
2542 if((ftpcode == 331) && (ftpc->state == FTP_USER)) {
2543 /* 331 Password required for ...
2544 (the server requires to send the user's password too) */
2545 PPSENDF(&ftpc->pp, "PASS %s", ftp->passwd?ftp->passwd:"");
2546 state(conn, FTP_PASS);
2548 else if(ftpcode/100 == 2) {
2549 /* 230 User ... logged in.
2550 (the user logged in with or without password) */
2551 result = ftp_state_loggedin(conn);
2553 else if(ftpcode == 332) {
2554 if(data->set.str[STRING_FTP_ACCOUNT]) {
2555 PPSENDF(&ftpc->pp, "ACCT %s", data->set.str[STRING_FTP_ACCOUNT]);
2556 state(conn, FTP_ACCT);
2559 failf(data, "ACCT requested but none available");
2560 result = CURLE_LOGIN_DENIED;
2564 /* All other response codes, like:
2566 530 User ... access denied
2567 (the server denies to log the specified user) */
2569 if(conn->data->set.str[STRING_FTP_ALTERNATIVE_TO_USER] &&
2570 !conn->data->state.ftp_trying_alternative) {
2571 /* Ok, USER failed. Let's try the supplied command. */
2572 PPSENDF(&conn->proto.ftpc.pp, "%s",
2573 conn->data->set.str[STRING_FTP_ALTERNATIVE_TO_USER]);
2574 conn->data->state.ftp_trying_alternative = TRUE;
2575 state(conn, FTP_USER);
2579 failf(data, "Access denied: %03d", ftpcode);
2580 result = CURLE_LOGIN_DENIED;
2586 /* for ACCT response */
2587 static CURLcode ftp_state_acct_resp(struct connectdata *conn,
2590 CURLcode result = CURLE_OK;
2591 struct Curl_easy *data = conn->data;
2592 if(ftpcode != 230) {
2593 failf(data, "ACCT rejected by server: %03d", ftpcode);
2594 result = CURLE_FTP_WEIRD_PASS_REPLY; /* FIX */
2597 result = ftp_state_loggedin(conn);
2603 static CURLcode ftp_statemach_act(struct connectdata *conn)
2606 curl_socket_t sock = conn->sock[FIRSTSOCKET];
2607 struct Curl_easy *data = conn->data;
2609 struct ftp_conn *ftpc = &conn->proto.ftpc;
2610 struct pingpong *pp = &ftpc->pp;
2611 static const char ftpauth[][4] = { "SSL", "TLS" };
2615 return Curl_pp_flushsend(pp);
2617 result = ftp_readresp(sock, pp, &ftpcode, &nread);
2622 /* we have now received a full FTP server response */
2623 switch(ftpc->state) {
2626 /* 230 User logged in - already! */
2627 return ftp_state_user_resp(conn, ftpcode, ftpc->state);
2628 else if(ftpcode != 220) {
2629 failf(data, "Got a %03d ftp-server response when 220 was expected",
2631 return CURLE_WEIRD_SERVER_REPLY;
2634 /* We have received a 220 response fine, now we proceed. */
2637 /* If not anonymous login, try a secure login. Note that this
2638 procedure is still BLOCKING. */
2640 Curl_sec_request_prot(conn, "private");
2641 /* We set private first as default, in case the line below fails to
2642 set a valid level */
2643 Curl_sec_request_prot(conn, data->set.str[STRING_KRB_LEVEL]);
2645 if(Curl_sec_login(conn))
2646 infof(data, "Logging in with password in cleartext!\n");
2648 infof(data, "Authentication successful\n");
2652 if(data->set.use_ssl &&
2653 (!conn->ssl[FIRSTSOCKET].use ||
2654 (conn->bits.proxy_ssl_connected[FIRSTSOCKET] &&
2655 !conn->proxy_ssl[FIRSTSOCKET].use))) {
2656 /* We don't have a SSL/TLS connection yet, but FTPS is
2657 requested. Try a FTPS connection now */
2660 switch(data->set.ftpsslauth) {
2661 case CURLFTPAUTH_DEFAULT:
2662 case CURLFTPAUTH_SSL:
2663 ftpc->count2 = 1; /* add one to get next */
2666 case CURLFTPAUTH_TLS:
2667 ftpc->count2 = -1; /* subtract one to get next */
2671 failf(data, "unsupported parameter to CURLOPT_FTPSSLAUTH: %d",
2672 (int)data->set.ftpsslauth);
2673 return CURLE_UNKNOWN_OPTION; /* we don't know what to do */
2675 PPSENDF(&ftpc->pp, "AUTH %s", ftpauth[ftpc->count1]);
2676 state(conn, FTP_AUTH);
2679 result = ftp_state_user(conn);
2687 /* we have gotten the response to a previous AUTH command */
2689 /* RFC2228 (page 5) says:
2691 * If the server is willing to accept the named security mechanism,
2692 * and does not require any security data, it must respond with
2693 * reply code 234/334.
2696 if((ftpcode == 234) || (ftpcode == 334)) {
2697 /* Curl_ssl_connect is BLOCKING */
2698 result = Curl_ssl_connect(conn, FIRSTSOCKET);
2700 conn->bits.ftp_use_data_ssl = FALSE; /* clear-text data */
2701 result = ftp_state_user(conn);
2704 else if(ftpc->count3 < 1) {
2706 ftpc->count1 += ftpc->count2; /* get next attempt */
2707 result = Curl_pp_sendf(&ftpc->pp, "AUTH %s", ftpauth[ftpc->count1]);
2708 /* remain in this same state */
2711 if(data->set.use_ssl > CURLUSESSL_TRY)
2712 /* we failed and CURLUSESSL_CONTROL or CURLUSESSL_ALL is set */
2713 result = CURLE_USE_SSL_FAILED;
2715 /* ignore the failure and continue */
2716 result = ftp_state_user(conn);
2725 result = ftp_state_user_resp(conn, ftpcode, ftpc->state);
2729 result = ftp_state_acct_resp(conn, ftpcode);
2733 PPSENDF(&ftpc->pp, "PROT %c",
2734 data->set.use_ssl == CURLUSESSL_CONTROL ? 'C' : 'P');
2735 state(conn, FTP_PROT);
2740 if(ftpcode/100 == 2)
2741 /* We have enabled SSL for the data connection! */
2742 conn->bits.ftp_use_data_ssl =
2743 (data->set.use_ssl != CURLUSESSL_CONTROL) ? TRUE : FALSE;
2744 /* FTP servers typically responds with 500 if they decide to reject
2746 else if(data->set.use_ssl > CURLUSESSL_CONTROL)
2747 /* we failed and bails out */
2748 return CURLE_USE_SSL_FAILED;
2750 if(data->set.ftp_ccc) {
2751 /* CCC - Clear Command Channel
2753 PPSENDF(&ftpc->pp, "%s", "CCC");
2754 state(conn, FTP_CCC);
2757 result = ftp_state_pwd(conn);
2765 /* First shut down the SSL layer (note: this call will block) */
2766 result = Curl_ssl_shutdown(conn, FIRSTSOCKET);
2769 failf(conn->data, "Failed to clear the command channel (CCC)");
2774 /* Then continue as normal */
2775 result = ftp_state_pwd(conn);
2781 if(ftpcode == 257) {
2782 char *ptr = &data->state.buffer[4]; /* start on the first letter */
2783 const size_t buf_size = data->set.buffer_size;
2786 bool entry_extracted = FALSE;
2788 dir = malloc(nread + 1);
2790 return CURLE_OUT_OF_MEMORY;
2792 /* Reply format is like
2793 257<space>[rubbish]"<directory-name>"<space><commentary> and the
2796 The directory name can contain any character; embedded
2797 double-quotes should be escaped by double-quotes (the
2798 "quote-doubling" convention).
2801 /* scan for the first double-quote for non-standard responses */
2802 while(ptr < &data->state.buffer[buf_size]
2803 && *ptr != '\n' && *ptr != '\0' && *ptr != '"')
2807 /* it started good */
2809 for(store = dir; *ptr;) {
2811 if('\"' == ptr[1]) {
2812 /* "quote-doubling" */
2818 entry_extracted = TRUE;
2819 break; /* get out of this loop */
2827 *store = '\0'; /* zero terminate */
2829 if(entry_extracted) {
2830 /* If the path name does not look like an absolute path (i.e.: it
2831 does not start with a '/'), we probably need some server-dependent
2832 adjustments. For example, this is the case when connecting to
2833 an OS400 FTP server: this server supports two name syntaxes,
2834 the default one being incompatible with standard paths. In
2835 addition, this server switches automatically to the regular path
2836 syntax when one is encountered in a command: this results in
2837 having an entrypath in the wrong syntax when later used in CWD.
2838 The method used here is to check the server OS: we do it only
2839 if the path name looks strange to minimize overhead on other
2842 if(!ftpc->server_os && dir[0] != '/') {
2844 result = Curl_pp_sendf(&ftpc->pp, "%s", "SYST");
2849 Curl_safefree(ftpc->entrypath);
2850 ftpc->entrypath = dir; /* remember this */
2851 infof(data, "Entry path is '%s'\n", ftpc->entrypath);
2852 /* also save it where getinfo can access it: */
2853 data->state.most_recent_ftp_entrypath = ftpc->entrypath;
2854 state(conn, FTP_SYST);
2858 Curl_safefree(ftpc->entrypath);
2859 ftpc->entrypath = dir; /* remember this */
2860 infof(data, "Entry path is '%s'\n", ftpc->entrypath);
2861 /* also save it where getinfo can access it: */
2862 data->state.most_recent_ftp_entrypath = ftpc->entrypath;
2865 /* couldn't get the path */
2867 infof(data, "Failed to figure out path\n");
2870 state(conn, FTP_STOP); /* we are done with the CONNECT phase! */
2871 DEBUGF(infof(data, "protocol connect phase DONE\n"));
2875 if(ftpcode == 215) {
2876 char *ptr = &data->state.buffer[4]; /* start on the first letter */
2880 os = malloc(nread + 1);
2882 return CURLE_OUT_OF_MEMORY;
2884 /* Reply format is like
2885 215<space><OS-name><space><commentary>
2889 for(store = os; *ptr && *ptr != ' ';)
2891 *store = '\0'; /* zero terminate */
2893 /* Check for special servers here. */
2895 if(strcasecompare(os, "OS/400")) {
2896 /* Force OS400 name format 1. */
2897 result = Curl_pp_sendf(&ftpc->pp, "%s", "SITE NAMEFMT 1");
2902 /* remember target server OS */
2903 Curl_safefree(ftpc->server_os);
2904 ftpc->server_os = os;
2905 state(conn, FTP_NAMEFMT);
2908 /* Nothing special for the target server. */
2909 /* remember target server OS */
2910 Curl_safefree(ftpc->server_os);
2911 ftpc->server_os = os;
2914 /* Cannot identify server OS. Continue anyway and cross fingers. */
2917 state(conn, FTP_STOP); /* we are done with the CONNECT phase! */
2918 DEBUGF(infof(data, "protocol connect phase DONE\n"));
2922 if(ftpcode == 250) {
2923 /* Name format change successful: reload initial path. */
2924 ftp_state_pwd(conn);
2928 state(conn, FTP_STOP); /* we are done with the CONNECT phase! */
2929 DEBUGF(infof(data, "protocol connect phase DONE\n"));
2934 case FTP_RETR_PREQUOTE:
2935 case FTP_STOR_PREQUOTE:
2936 if((ftpcode >= 400) && !ftpc->count2) {
2937 /* failure response code, and not allowed to fail */
2938 failf(conn->data, "QUOT command failed with %03d", ftpcode);
2939 return CURLE_QUOTE_ERROR;
2941 result = ftp_state_quote(conn, FALSE, ftpc->state);
2948 if(ftpcode/100 != 2) {
2949 /* failure to CWD there */
2950 if(conn->data->set.ftp_create_missing_dirs &&
2951 ftpc->cwdcount && !ftpc->count2) {
2953 ftpc->count2++; /* counter to prevent CWD-MKD loops */
2954 PPSENDF(&ftpc->pp, "MKD %s", ftpc->dirs[ftpc->cwdcount - 1]);
2955 state(conn, FTP_MKD);
2958 /* return failure */
2959 failf(data, "Server denied you to change to the given directory");
2960 ftpc->cwdfail = TRUE; /* don't remember this path as we failed
2962 return CURLE_REMOTE_ACCESS_DENIED;
2968 if(++ftpc->cwdcount <= ftpc->dirdepth) {
2970 PPSENDF(&ftpc->pp, "CWD %s", ftpc->dirs[ftpc->cwdcount - 1]);
2973 result = ftp_state_mdtm(conn);
2981 if((ftpcode/100 != 2) && !ftpc->count3--) {
2982 /* failure to MKD the dir */
2983 failf(data, "Failed to MKD dir: %03d", ftpcode);
2984 return CURLE_REMOTE_ACCESS_DENIED;
2986 state(conn, FTP_CWD);
2988 PPSENDF(&ftpc->pp, "CWD %s", ftpc->dirs[ftpc->cwdcount - 1]);
2992 result = ftp_state_mdtm_resp(conn, ftpcode);
2999 result = ftp_state_type_resp(conn, ftpcode, ftpc->state);
3005 result = ftp_state_size_resp(conn, ftpcode, ftpc->state);
3010 result = ftp_state_rest_resp(conn, ftpcode, ftpc->state);
3014 if(ftpcode != 200) {
3015 /* there only is this one standard OK return code. */
3016 failf(data, "PRET command not accepted: %03d", ftpcode);
3017 return CURLE_FTP_PRET_FAILED;
3019 result = ftp_state_use_pasv(conn);
3023 result = ftp_state_pasv_resp(conn, ftpcode);
3027 result = ftp_state_port_resp(conn, ftpcode);
3032 result = ftp_state_get_resp(conn, ftpcode, ftpc->state);
3036 result = ftp_state_stor_resp(conn, ftpcode, ftpc->state);
3040 /* fallthrough, just stop! */
3042 /* internal error */
3043 state(conn, FTP_STOP);
3052 /* called repeatedly until done from multi.c */
3053 static CURLcode ftp_multi_statemach(struct connectdata *conn,
3056 struct ftp_conn *ftpc = &conn->proto.ftpc;
3057 CURLcode result = Curl_pp_statemach(&ftpc->pp, FALSE);
3059 /* Check for the state outside of the Curl_socket_check() return code checks
3060 since at times we are in fact already in this state when this function
3062 *done = (ftpc->state == FTP_STOP) ? TRUE : FALSE;
3067 static CURLcode ftp_block_statemach(struct connectdata *conn)
3069 struct ftp_conn *ftpc = &conn->proto.ftpc;
3070 struct pingpong *pp = &ftpc->pp;
3071 CURLcode result = CURLE_OK;
3073 while(ftpc->state != FTP_STOP) {
3074 result = Curl_pp_statemach(pp, TRUE);
3083 * ftp_connect() should do everything that is to be considered a part of
3084 * the connection phase.
3086 * The variable 'done' points to will be TRUE if the protocol-layer connect
3087 * phase is done when this function returns, or FALSE if not.
3090 static CURLcode ftp_connect(struct connectdata *conn,
3091 bool *done) /* see description above */
3094 struct ftp_conn *ftpc = &conn->proto.ftpc;
3095 struct pingpong *pp = &ftpc->pp;
3097 *done = FALSE; /* default to not done yet */
3099 /* We always support persistent connections on ftp */
3100 connkeep(conn, "FTP default");
3102 pp->response_time = RESP_TIMEOUT; /* set default response time-out */
3103 pp->statemach_act = ftp_statemach_act;
3104 pp->endofresp = ftp_endofresp;
3107 if(conn->handler->flags & PROTOPT_SSL) {
3109 result = Curl_ssl_connect(conn, FIRSTSOCKET);
3114 Curl_pp_init(pp); /* init the generic pingpong data */
3116 /* When we connect, we start in the state where we await the 220
3118 state(conn, FTP_WAIT220);
3120 result = ftp_multi_statemach(conn, done);
3125 /***********************************************************************
3129 * The DONE function. This does what needs to be done after a single DO has
3132 * Input argument is already checked for validity.
3134 static CURLcode ftp_done(struct connectdata *conn, CURLcode status,
3137 struct Curl_easy *data = conn->data;
3138 struct FTP *ftp = data->req.protop;
3139 struct ftp_conn *ftpc = &conn->proto.ftpc;
3140 struct pingpong *pp = &ftpc->pp;
3143 CURLcode result = CURLE_OK;
3145 const char *path_to_use = data->state.path;
3151 case CURLE_BAD_DOWNLOAD_RESUME:
3152 case CURLE_FTP_WEIRD_PASV_REPLY:
3153 case CURLE_FTP_PORT_FAILED:
3154 case CURLE_FTP_ACCEPT_FAILED:
3155 case CURLE_FTP_ACCEPT_TIMEOUT:
3156 case CURLE_FTP_COULDNT_SET_TYPE:
3157 case CURLE_FTP_COULDNT_RETR_FILE:
3158 case CURLE_PARTIAL_FILE:
3159 case CURLE_UPLOAD_FAILED:
3160 case CURLE_REMOTE_ACCESS_DENIED:
3161 case CURLE_FILESIZE_EXCEEDED:
3162 case CURLE_REMOTE_FILE_NOT_FOUND:
3163 case CURLE_WRITE_ERROR:
3164 /* the connection stays alive fine even though this happened */
3166 case CURLE_OK: /* doesn't affect the control connection's status */
3170 /* until we cope better with prematurely ended requests, let them
3171 * fallback as if in complete failure */
3173 default: /* by default, an error means the control connection is
3174 wedged and should not be used anymore */
3175 ftpc->ctl_valid = FALSE;
3176 ftpc->cwdfail = TRUE; /* set this TRUE to prevent us to remember the
3177 current path, as this connection is going */
3178 connclose(conn, "FTP ended with bad error code");
3179 result = status; /* use the already set error code */
3183 /* now store a copy of the directory we are in */
3184 free(ftpc->prevpath);
3186 if(data->state.wildcardmatch) {
3187 if(data->set.chunk_end && ftpc->file) {
3188 Curl_set_in_callback(data, true);
3189 data->set.chunk_end(data->wildcard.customptr);
3190 Curl_set_in_callback(data, false);
3192 ftpc->known_filesize = -1;
3196 /* get the "raw" path */
3197 result = Curl_urldecode(data, path_to_use, 0, &path, NULL, TRUE);
3199 /* We can limp along anyway (and should try to since we may already be in
3200 * the error path) */
3201 ftpc->ctl_valid = FALSE; /* mark control connection as bad */
3202 connclose(conn, "FTP: out of memory!"); /* mark for connection closure */
3203 ftpc->prevpath = NULL; /* no path remembering */
3206 size_t flen = ftpc->file?strlen(ftpc->file):0; /* file is "raw" already */
3207 size_t dlen = strlen(path)-flen;
3208 if(!ftpc->cwdfail) {
3209 ftpc->prevmethod = data->set.ftp_filemethod;
3210 if(dlen && (data->set.ftp_filemethod != FTPFILE_NOCWD)) {
3211 ftpc->prevpath = path;
3213 /* if 'path' is not the whole string */
3214 ftpc->prevpath[dlen] = 0; /* terminate */
3217 /* we never changed dir */
3218 ftpc->prevpath = strdup("");
3222 infof(data, "Remembering we are in dir \"%s\"\n", ftpc->prevpath);
3225 ftpc->prevpath = NULL; /* no path */
3229 /* free the dir tree and file parts */
3232 /* shut down the socket to inform the server we're done */
3235 shutdown(conn->sock[SECONDARYSOCKET], 2); /* SD_BOTH */
3238 if(conn->sock[SECONDARYSOCKET] != CURL_SOCKET_BAD) {
3239 if(!result && ftpc->dont_check && data->req.maxdownload > 0) {
3240 /* partial download completed */
3241 result = Curl_pp_sendf(pp, "%s", "ABOR");
3243 failf(data, "Failure sending ABOR command: %s",
3244 curl_easy_strerror(result));
3245 ftpc->ctl_valid = FALSE; /* mark control connection as bad */
3246 connclose(conn, "ABOR command failed"); /* connection closure */
3250 if(conn->ssl[SECONDARYSOCKET].use) {
3251 /* The secondary socket is using SSL so we must close down that part
3252 first before we close the socket for real */
3253 Curl_ssl_close(conn, SECONDARYSOCKET);
3255 /* Note that we keep "use" set to TRUE since that (next) connection is
3256 still requested to use SSL */
3258 close_secondarysocket(conn);
3261 if(!result && (ftp->transfer == FTPTRANSFER_BODY) && ftpc->ctl_valid &&
3262 pp->pending_resp && !premature) {
3264 * Let's see what the server says about the transfer we just performed,
3265 * but lower the timeout as sometimes this connection has died while the
3266 * data has been transferred. This happens when doing through NATs etc that
3267 * abandon old silent connections.
3269 long old_time = pp->response_time;
3271 pp->response_time = 60*1000; /* give it only a minute for now */
3272 pp->response = Curl_now(); /* timeout relative now */
3274 result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
3276 pp->response_time = old_time; /* set this back to previous value */
3278 if(!nread && (CURLE_OPERATION_TIMEDOUT == result)) {
3279 failf(data, "control connection looks dead");
3280 ftpc->ctl_valid = FALSE; /* mark control connection as bad */
3281 connclose(conn, "Timeout or similar in FTP DONE operation"); /* close */
3287 if(ftpc->dont_check && data->req.maxdownload > 0) {
3288 /* we have just sent ABOR and there is no reliable way to check if it was
3289 * successful or not; we have to close the connection now */
3290 infof(data, "partial download completed, closing connection\n");
3291 connclose(conn, "Partial download with no ability to check");
3295 if(!ftpc->dont_check) {
3296 /* 226 Transfer complete, 250 Requested file action okay, completed. */
3297 if((ftpcode != 226) && (ftpcode != 250)) {
3298 failf(data, "server did not report OK, got %d", ftpcode);
3299 result = CURLE_PARTIAL_FILE;
3304 if(result || premature)
3305 /* the response code from the transfer showed an error already so no
3306 use checking further */
3308 else if(data->set.upload) {
3309 if((-1 != data->state.infilesize) &&
3310 (data->state.infilesize != *ftp->bytecountp) &&
3312 (ftp->transfer == FTPTRANSFER_BODY)) {
3313 failf(data, "Uploaded unaligned file size (%" CURL_FORMAT_CURL_OFF_T
3314 " out of %" CURL_FORMAT_CURL_OFF_T " bytes)",
3315 *ftp->bytecountp, data->state.infilesize);
3316 result = CURLE_PARTIAL_FILE;
3320 if((-1 != data->req.size) &&
3321 (data->req.size != *ftp->bytecountp) &&
3322 #ifdef CURL_DO_LINEEND_CONV
3323 /* Most FTP servers don't adjust their file SIZE response for CRLFs, so
3324 * we'll check to see if the discrepancy can be explained by the number
3325 * of CRLFs we've changed to LFs.
3327 ((data->req.size + data->state.crlf_conversions) !=
3328 *ftp->bytecountp) &&
3329 #endif /* CURL_DO_LINEEND_CONV */
3330 (data->req.maxdownload != *ftp->bytecountp)) {
3331 failf(data, "Received only partial file: %" CURL_FORMAT_CURL_OFF_T
3332 " bytes", *ftp->bytecountp);
3333 result = CURLE_PARTIAL_FILE;
3335 else if(!ftpc->dont_check &&
3336 !*ftp->bytecountp &&
3337 (data->req.size>0)) {
3338 failf(data, "No data was received!");
3339 result = CURLE_FTP_COULDNT_RETR_FILE;
3343 /* clear these for next connection */
3344 ftp->transfer = FTPTRANSFER_BODY;
3345 ftpc->dont_check = FALSE;
3347 /* Send any post-transfer QUOTE strings? */
3348 if(!status && !result && !premature && data->set.postquote)
3349 result = ftp_sendquote(conn, data->set.postquote);
3354 /***********************************************************************
3358 * Where a 'quote' means a list of custom commands to send to the server.
3359 * The quote list is passed as an argument.
3365 CURLcode ftp_sendquote(struct connectdata *conn, struct curl_slist *quote)
3367 struct curl_slist *item;
3371 struct ftp_conn *ftpc = &conn->proto.ftpc;
3372 struct pingpong *pp = &ftpc->pp;
3377 char *cmd = item->data;
3378 bool acceptfail = FALSE;
3380 /* if a command starts with an asterisk, which a legal FTP command never
3381 can, the command will be allowed to fail without it causing any
3382 aborts or cancels etc. It will cause libcurl to act as if the command
3383 is successful, whatever the server reponds. */
3390 PPSENDF(&conn->proto.ftpc.pp, "%s", cmd);
3392 pp->response = Curl_now(); /* timeout relative now */
3394 result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
3398 if(!acceptfail && (ftpcode >= 400)) {
3399 failf(conn->data, "QUOT string not accepted: %s", cmd);
3400 return CURLE_QUOTE_ERROR;
3410 /***********************************************************************
3414 * Returns TRUE if we in the current situation should send TYPE
3416 static int ftp_need_type(struct connectdata *conn,
3419 return conn->proto.ftpc.transfertype != (ascii_wanted?'A':'I');
3422 /***********************************************************************
3426 * Set TYPE. We only deal with ASCII or BINARY so this function
3428 * If the transfer type is not sent, simulate on OK response in newstate
3430 static CURLcode ftp_nb_type(struct connectdata *conn,
3431 bool ascii, ftpstate newstate)
3433 struct ftp_conn *ftpc = &conn->proto.ftpc;
3435 char want = (char)(ascii?'A':'I');
3437 if(ftpc->transfertype == want) {
3438 state(conn, newstate);
3439 return ftp_state_type_resp(conn, 200, newstate);
3442 PPSENDF(&ftpc->pp, "TYPE %c", want);
3443 state(conn, newstate);
3445 /* keep track of our current transfer type */
3446 ftpc->transfertype = want;
3450 /***************************************************************************
3452 * ftp_pasv_verbose()
3454 * This function only outputs some informationals about this second connection
3455 * when we've issued a PASV command before and thus we have connected to a
3456 * possibly new IP address.
3459 #ifndef CURL_DISABLE_VERBOSE_STRINGS
3461 ftp_pasv_verbose(struct connectdata *conn,
3463 char *newhost, /* ascii version */
3467 Curl_printable_address(ai, buf, sizeof(buf));
3468 infof(conn->data, "Connecting to %s (%s) port %d\n", newhost, buf, port);
3475 * This function shall be called when the second FTP (data) connection is
3478 * 'complete' can return 0 for incomplete, 1 for done and -1 for go back
3479 * (which basically is only for when PASV is being sent to retry a failed
3483 static CURLcode ftp_do_more(struct connectdata *conn, int *completep)
3485 struct Curl_easy *data = conn->data;
3486 struct ftp_conn *ftpc = &conn->proto.ftpc;
3487 CURLcode result = CURLE_OK;
3488 bool connected = FALSE;
3489 bool complete = FALSE;
3491 /* the ftp struct is inited in ftp_connect() */
3492 struct FTP *ftp = data->req.protop;
3494 /* if the second connection isn't done yet, wait for it */
3495 if(!conn->bits.tcpconnect[SECONDARYSOCKET]) {
3496 if(Curl_connect_ongoing(conn)) {
3497 /* As we're in TUNNEL_CONNECT state now, we know the proxy name and port
3498 aren't used so we blank their arguments. TODO: make this nicer */
3499 result = Curl_proxyCONNECT(conn, SECONDARYSOCKET, NULL, 0);
3504 result = Curl_is_connected(conn, SECONDARYSOCKET, &connected);
3506 /* Ready to do more? */
3508 DEBUGF(infof(data, "DO-MORE connected phase starts\n"));
3511 if(result && (ftpc->count1 == 0)) {
3512 *completep = -1; /* go back to DOING please */
3513 /* this is a EPSV connect failing, try PASV instead */
3514 return ftp_epsv_disable(conn);
3520 result = Curl_proxy_connect(conn, SECONDARYSOCKET);
3524 if(CONNECT_SECONDARYSOCKET_PROXY_SSL())
3527 if(conn->bits.tunnel_proxy && conn->bits.httpproxy &&
3528 Curl_connect_ongoing(conn))
3533 /* already in a state so skip the initial commands.
3534 They are only done to kickstart the do_more state */
3535 result = ftp_multi_statemach(conn, &complete);
3537 *completep = (int)complete;
3539 /* if we got an error or if we don't wait for a data connection return
3541 if(result || (ftpc->wait_data_conn != TRUE))
3544 if(ftpc->wait_data_conn)
3545 /* if we reach the end of the FTP state machine here, *complete will be
3546 TRUE but so is ftpc->wait_data_conn, which says we need to wait for
3547 the data connection and therefore we're not actually complete */
3551 if(ftp->transfer <= FTPTRANSFER_INFO) {
3552 /* a transfer is about to take place, or if not a file name was given
3553 so we'll do a SIZE on it later and then we need the right TYPE first */
3555 if(ftpc->wait_data_conn == TRUE) {
3558 result = ReceivedServerConnect(conn, &serv_conned);
3560 return result; /* Failed to accept data connection */
3563 /* It looks data connection is established */
3564 result = AcceptServerConnect(conn);
3565 ftpc->wait_data_conn = FALSE;
3567 result = InitiateTransfer(conn);
3572 *completep = 1; /* this state is now complete when the server has
3573 connected back to us */
3576 else if(data->set.upload) {
3577 result = ftp_nb_type(conn, data->set.prefer_ascii, FTP_STOR_TYPE);
3581 result = ftp_multi_statemach(conn, &complete);
3582 if(ftpc->wait_data_conn)
3583 /* if we reach the end of the FTP state machine here, *complete will be
3584 TRUE but so is ftpc->wait_data_conn, which says we need to wait for
3585 the data connection and therefore we're not actually complete */
3588 *completep = (int)complete;
3592 ftp->downloadsize = -1; /* unknown as of yet */
3594 result = Curl_range(conn);
3596 if(result == CURLE_OK && data->req.maxdownload >= 0) {
3597 /* Don't check for successful transfer */
3598 ftpc->dont_check = TRUE;
3603 else if(data->set.ftp_list_only || !ftpc->file) {
3604 /* The specified path ends with a slash, and therefore we think this
3605 is a directory that is requested, use LIST. But before that we
3606 need to set ASCII transfer mode. */
3608 /* But only if a body transfer was requested. */
3609 if(ftp->transfer == FTPTRANSFER_BODY) {
3610 result = ftp_nb_type(conn, TRUE, FTP_LIST_TYPE);
3614 /* otherwise just fall through */
3617 result = ftp_nb_type(conn, data->set.prefer_ascii, FTP_RETR_TYPE);
3622 result = ftp_multi_statemach(conn, &complete);
3623 *completep = (int)complete;
3628 if(!result && (ftp->transfer != FTPTRANSFER_BODY))
3629 /* no data to transfer. FIX: it feels like a kludge to have this here
3631 Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
3633 if(!ftpc->wait_data_conn) {
3634 /* no waiting for the data connection so this is now complete */
3636 DEBUGF(infof(data, "DO-MORE phase ends with %d\n", (int)result));
3644 /***********************************************************************
3648 * This is the actual DO function for FTP. Get a file/directory according to
3649 * the options previously setup.
3653 CURLcode ftp_perform(struct connectdata *conn,
3654 bool *connected, /* connect status after PASV / PORT */
3657 /* this is FTP and no proxy */
3658 CURLcode result = CURLE_OK;
3660 DEBUGF(infof(conn->data, "DO phase starts\n"));
3662 if(conn->data->set.opt_no_body) {
3663 /* requested no body means no transfer... */
3664 struct FTP *ftp = conn->data->req.protop;
3665 ftp->transfer = FTPTRANSFER_INFO;
3668 *dophase_done = FALSE; /* not done yet */
3670 /* start the first command in the DO phase */
3671 result = ftp_state_quote(conn, TRUE, FTP_QUOTE);
3675 /* run the state-machine */
3676 result = ftp_multi_statemach(conn, dophase_done);
3678 *connected = conn->bits.tcpconnect[SECONDARYSOCKET];
3680 infof(conn->data, "ftp_perform ends with SECONDARY: %d\n", *connected);
3683 DEBUGF(infof(conn->data, "DO phase is complete1\n"));
3688 static void wc_data_dtor(void *ptr)
3690 struct ftp_wc_tmpdata *tmp = ptr;
3692 Curl_ftp_parselist_data_free(&tmp->parser);
3696 static CURLcode init_wc_data(struct connectdata *conn)
3699 char *path = conn->data->state.path;
3700 struct WildcardData *wildcard = &(conn->data->wildcard);
3701 CURLcode result = CURLE_OK;
3702 struct ftp_wc_tmpdata *ftp_tmp;
3704 last_slash = strrchr(conn->data->state.path, '/');
3707 if(last_slash[0] == '\0') {
3708 wildcard->state = CURLWC_CLEAN;
3709 result = ftp_parse_url_path(conn);
3712 wildcard->pattern = strdup(last_slash);
3713 if(!wildcard->pattern)
3714 return CURLE_OUT_OF_MEMORY;
3715 last_slash[0] = '\0'; /* cut file from path */
3717 else { /* there is only 'wildcard pattern' or nothing */
3719 wildcard->pattern = strdup(path);
3720 if(!wildcard->pattern)
3721 return CURLE_OUT_OF_MEMORY;
3724 else { /* only list */
3725 wildcard->state = CURLWC_CLEAN;
3726 result = ftp_parse_url_path(conn);
3731 /* program continues only if URL is not ending with slash, allocate needed
3732 resources for wildcard transfer */
3734 /* allocate ftp protocol specific temporary wildcard data */
3735 ftp_tmp = calloc(1, sizeof(struct ftp_wc_tmpdata));
3737 Curl_safefree(wildcard->pattern);
3738 return CURLE_OUT_OF_MEMORY;
3741 /* INITIALIZE parselist structure */
3742 ftp_tmp->parser = Curl_ftp_parselist_data_alloc();
3743 if(!ftp_tmp->parser) {
3744 Curl_safefree(wildcard->pattern);
3746 return CURLE_OUT_OF_MEMORY;
3749 wildcard->tmp = ftp_tmp; /* put it to the WildcardData tmp pointer */
3750 wildcard->tmp_dtor = wc_data_dtor;
3752 /* wildcard does not support NOCWD option (assert it?) */
3753 if(conn->data->set.ftp_filemethod == FTPFILE_NOCWD)
3754 conn->data->set.ftp_filemethod = FTPFILE_MULTICWD;
3756 /* try to parse ftp url */
3757 result = ftp_parse_url_path(conn);
3759 Curl_safefree(wildcard->pattern);
3760 wildcard->tmp_dtor(wildcard->tmp);
3761 wildcard->tmp_dtor = ZERO_NULL;
3762 wildcard->tmp = NULL;
3766 wildcard->path = strdup(conn->data->state.path);
3767 if(!wildcard->path) {
3768 Curl_safefree(wildcard->pattern);
3769 wildcard->tmp_dtor(wildcard->tmp);
3770 wildcard->tmp_dtor = ZERO_NULL;
3771 wildcard->tmp = NULL;
3772 return CURLE_OUT_OF_MEMORY;
3775 /* backup old write_function */
3776 ftp_tmp->backup.write_function = conn->data->set.fwrite_func;
3777 /* parsing write function */
3778 conn->data->set.fwrite_func = Curl_ftp_parselist;
3779 /* backup old file descriptor */
3780 ftp_tmp->backup.file_descriptor = conn->data->set.out;
3781 /* let the writefunc callback know what curl pointer is working with */
3782 conn->data->set.out = conn;
3784 infof(conn->data, "Wildcard - Parsing started\n");
3788 /* This is called recursively */
3789 static CURLcode wc_statemach(struct connectdata *conn)
3791 struct WildcardData * const wildcard = &(conn->data->wildcard);
3792 CURLcode result = CURLE_OK;
3794 switch(wildcard->state) {
3796 result = init_wc_data(conn);
3797 if(wildcard->state == CURLWC_CLEAN)
3800 wildcard->state = result ? CURLWC_ERROR : CURLWC_MATCHING;
3803 case CURLWC_MATCHING: {
3804 /* In this state is LIST response successfully parsed, so lets restore
3805 previous WRITEFUNCTION callback and WRITEDATA pointer */
3806 struct ftp_wc_tmpdata *ftp_tmp = wildcard->tmp;
3807 conn->data->set.fwrite_func = ftp_tmp->backup.write_function;
3808 conn->data->set.out = ftp_tmp->backup.file_descriptor;
3809 ftp_tmp->backup.write_function = ZERO_NULL;
3810 ftp_tmp->backup.file_descriptor = NULL;
3811 wildcard->state = CURLWC_DOWNLOADING;
3813 if(Curl_ftp_parselist_geterror(ftp_tmp->parser)) {
3814 /* error found in LIST parsing */
3815 wildcard->state = CURLWC_CLEAN;
3816 return wc_statemach(conn);
3818 if(wildcard->filelist.size == 0) {
3819 /* no corresponding file */
3820 wildcard->state = CURLWC_CLEAN;
3821 return CURLE_REMOTE_FILE_NOT_FOUND;
3823 return wc_statemach(conn);
3826 case CURLWC_DOWNLOADING: {
3827 /* filelist has at least one file, lets get first one */
3828 struct ftp_conn *ftpc = &conn->proto.ftpc;
3829 struct curl_fileinfo *finfo = wildcard->filelist.head->ptr;
3831 char *tmp_path = aprintf("%s%s", wildcard->path, finfo->filename);
3833 return CURLE_OUT_OF_MEMORY;
3835 /* switch default "state.pathbuffer" and tmp_path, good to see
3836 ftp_parse_url_path function to understand this trick */
3837 Curl_safefree(conn->data->state.pathbuffer);
3838 conn->data->state.pathbuffer = tmp_path;
3839 conn->data->state.path = tmp_path;
3841 infof(conn->data, "Wildcard - START of \"%s\"\n", finfo->filename);
3842 if(conn->data->set.chunk_bgn) {
3844 Curl_set_in_callback(conn->data, true);
3845 userresponse = conn->data->set.chunk_bgn(
3846 finfo, wildcard->customptr, (int)wildcard->filelist.size);
3847 Curl_set_in_callback(conn->data, false);
3848 switch(userresponse) {
3849 case CURL_CHUNK_BGN_FUNC_SKIP:
3850 infof(conn->data, "Wildcard - \"%s\" skipped by user\n",
3852 wildcard->state = CURLWC_SKIP;
3853 return wc_statemach(conn);
3854 case CURL_CHUNK_BGN_FUNC_FAIL:
3855 return CURLE_CHUNK_FAILED;
3859 if(finfo->filetype != CURLFILETYPE_FILE) {
3860 wildcard->state = CURLWC_SKIP;
3861 return wc_statemach(conn);
3864 if(finfo->flags & CURLFINFOFLAG_KNOWN_SIZE)
3865 ftpc->known_filesize = finfo->size;
3867 result = ftp_parse_url_path(conn);
3871 /* we don't need the Curl_fileinfo of first file anymore */
3872 Curl_llist_remove(&wildcard->filelist, wildcard->filelist.head, NULL);
3874 if(wildcard->filelist.size == 0) { /* remains only one file to down. */
3875 wildcard->state = CURLWC_CLEAN;
3876 /* after that will be ftp_do called once again and no transfer
3877 will be done because of CURLWC_CLEAN state */
3883 if(conn->data->set.chunk_end) {
3884 Curl_set_in_callback(conn->data, true);
3885 conn->data->set.chunk_end(conn->data->wildcard.customptr);
3886 Curl_set_in_callback(conn->data, false);
3888 Curl_llist_remove(&wildcard->filelist, wildcard->filelist.head, NULL);
3889 wildcard->state = (wildcard->filelist.size == 0) ?
3890 CURLWC_CLEAN : CURLWC_DOWNLOADING;
3891 return wc_statemach(conn);
3894 case CURLWC_CLEAN: {
3895 struct ftp_wc_tmpdata *ftp_tmp = wildcard->tmp;
3898 result = Curl_ftp_parselist_geterror(ftp_tmp->parser);
3900 wildcard->state = result ? CURLWC_ERROR : CURLWC_DONE;
3912 /***********************************************************************
3916 * This function is registered as 'curl_do' function. It decodes the path
3917 * parts etc as a wrapper to the actual DO function (ftp_perform).
3919 * The input argument is already checked for validity.
3921 static CURLcode ftp_do(struct connectdata *conn, bool *done)
3923 CURLcode result = CURLE_OK;
3924 struct ftp_conn *ftpc = &conn->proto.ftpc;
3926 *done = FALSE; /* default to false */
3927 ftpc->wait_data_conn = FALSE; /* default to no such wait */
3929 if(conn->data->state.wildcardmatch) {
3930 result = wc_statemach(conn);
3931 if(conn->data->wildcard.state == CURLWC_SKIP ||
3932 conn->data->wildcard.state == CURLWC_DONE) {
3933 /* do not call ftp_regular_transfer */
3936 if(result) /* error, loop or skipping the file */
3939 else { /* no wildcard FSM needed */
3940 result = ftp_parse_url_path(conn);
3945 result = ftp_regular_transfer(conn, done);
3951 CURLcode Curl_ftpsend(struct connectdata *conn, const char *cmd)
3953 ssize_t bytes_written;
3954 #define SBUF_SIZE 1024
3958 CURLcode result = CURLE_OK;
3960 enum protection_level data_sec = conn->data_prot;
3963 write_len = strlen(cmd);
3964 if(write_len > (sizeof(s) -3))
3965 return CURLE_BAD_FUNCTION_ARGUMENT;
3967 strcpy(&s[write_len], "\r\n"); /* append a trailing CRLF */
3971 result = Curl_convert_to_network(conn->data, s, write_len);
3972 /* Curl_convert_to_network calls failf if unsuccessful */
3978 conn->data_prot = PROT_CMD;
3980 result = Curl_write(conn, conn->sock[FIRSTSOCKET], sptr, write_len,
3983 DEBUGASSERT(data_sec > PROT_NONE && data_sec < PROT_LAST);
3984 conn->data_prot = data_sec;
3990 if(conn->data->set.verbose)
3991 Curl_debug(conn->data, CURLINFO_HEADER_OUT,
3992 sptr, (size_t)bytes_written, conn);
3994 if(bytes_written != (ssize_t)write_len) {
3995 write_len -= bytes_written;
3996 sptr += bytes_written;
4005 /***********************************************************************
4009 * This should be called before calling sclose() on an ftp control connection
4010 * (not data connections). We should then wait for the response from the
4011 * server before returning. The calling code should then try to close the
4015 static CURLcode ftp_quit(struct connectdata *conn)
4017 CURLcode result = CURLE_OK;
4019 if(conn->proto.ftpc.ctl_valid) {
4020 result = Curl_pp_sendf(&conn->proto.ftpc.pp, "%s", "QUIT");
4022 failf(conn->data, "Failure sending QUIT command: %s",
4023 curl_easy_strerror(result));
4024 conn->proto.ftpc.ctl_valid = FALSE; /* mark control connection as bad */
4025 connclose(conn, "QUIT command failed"); /* mark for connection closure */
4026 state(conn, FTP_STOP);
4030 state(conn, FTP_QUIT);
4032 result = ftp_block_statemach(conn);
4038 /***********************************************************************
4042 * Disconnect from an FTP server. Cleanup protocol-specific per-connection
4043 * resources. BLOCKING.
4045 static CURLcode ftp_disconnect(struct connectdata *conn, bool dead_connection)
4047 struct ftp_conn *ftpc = &conn->proto.ftpc;
4048 struct pingpong *pp = &ftpc->pp;
4050 /* We cannot send quit unconditionally. If this connection is stale or
4051 bad in any way, sending quit and waiting around here will make the
4052 disconnect wait in vain and cause more problems than we need to.
4054 ftp_quit() will check the state of ftp->ctl_valid. If it's ok it
4055 will try to send the QUIT command, otherwise it will just return.
4058 ftpc->ctl_valid = FALSE;
4060 /* The FTP session may or may not have been allocated/setup at this point! */
4061 (void)ftp_quit(conn); /* ignore errors on the QUIT */
4063 if(ftpc->entrypath) {
4064 struct Curl_easy *data = conn->data;
4065 if(data->state.most_recent_ftp_entrypath == ftpc->entrypath) {
4066 data->state.most_recent_ftp_entrypath = NULL;
4068 free(ftpc->entrypath);
4069 ftpc->entrypath = NULL;
4073 free(ftpc->prevpath);
4074 ftpc->prevpath = NULL;
4075 free(ftpc->server_os);
4076 ftpc->server_os = NULL;
4078 Curl_pp_disconnect(pp);
4087 /***********************************************************************
4089 * ftp_parse_url_path()
4091 * Parse the URL path into separate path components.
4095 CURLcode ftp_parse_url_path(struct connectdata *conn)
4097 struct Curl_easy *data = conn->data;
4098 /* the ftp struct is already inited in ftp_connect() */
4099 struct FTP *ftp = data->req.protop;
4100 struct ftp_conn *ftpc = &conn->proto.ftpc;
4101 const char *slash_pos; /* position of the first '/' char in curpos */
4102 const char *path_to_use = data->state.path;
4103 const char *cur_pos;
4104 const char *filename = NULL;
4106 cur_pos = path_to_use; /* current position in path. point at the begin of
4107 next path component */
4109 ftpc->ctl_valid = FALSE;
4110 ftpc->cwdfail = FALSE;
4112 switch(data->set.ftp_filemethod) {
4114 /* fastest, but less standard-compliant */
4117 The best time to check whether the path is a file or directory is right
4120 the first condition in the if() right here, is there just in case
4121 someone decides to set path to NULL one day
4123 if(path_to_use[0] &&
4124 (path_to_use[strlen(path_to_use) - 1] != '/') )
4125 filename = path_to_use; /* this is a full file path */
4128 ftpc->file is not used anywhere other than for operations on a file.
4129 In other words, never for directory operations.
4130 So we can safely leave filename as NULL here and use it as a
4131 argument in dir/file decisions.
4136 case FTPFILE_SINGLECWD:
4137 /* get the last slash */
4138 if(!path_to_use[0]) {
4139 /* no dir, no file */
4143 slash_pos = strrchr(cur_pos, '/');
4144 if(slash_pos || !*cur_pos) {
4145 size_t dirlen = slash_pos-cur_pos;
4148 ftpc->dirs = calloc(1, sizeof(ftpc->dirs[0]));
4150 return CURLE_OUT_OF_MEMORY;
4155 result = Curl_urldecode(conn->data, slash_pos ? cur_pos : "/",
4156 slash_pos ? dirlen : 1,
4157 &ftpc->dirs[0], NULL,
4163 ftpc->dirdepth = 1; /* we consider it to be a single dir */
4164 filename = slash_pos ? slash_pos + 1 : cur_pos; /* rest is file name */
4167 filename = cur_pos; /* this is a file name only */
4170 default: /* allow pretty much anything */
4171 case FTPFILE_MULTICWD:
4173 ftpc->diralloc = 5; /* default dir depth to allocate */
4174 ftpc->dirs = calloc(ftpc->diralloc, sizeof(ftpc->dirs[0]));
4176 return CURLE_OUT_OF_MEMORY;
4178 /* we have a special case for listing the root dir only */
4179 if(!strcmp(path_to_use, "/")) {
4180 cur_pos++; /* make it point to the zero byte */
4181 ftpc->dirs[0] = strdup("/");
4185 /* parse the URL path into separate path components */
4186 while((slash_pos = strchr(cur_pos, '/')) != NULL) {
4187 /* 1 or 0 pointer offset to indicate absolute directory */
4188 ssize_t absolute_dir = ((cur_pos - data->state.path > 0) &&
4189 (ftpc->dirdepth == 0))?1:0;
4191 /* seek out the next path component */
4192 if(slash_pos-cur_pos) {
4193 /* we skip empty path components, like "x//y" since the FTP command
4194 CWD requires a parameter and a non-existent parameter a) doesn't
4195 work on many servers and b) has no effect on the others. */
4196 size_t len = slash_pos - cur_pos + absolute_dir;
4198 Curl_urldecode(conn->data, cur_pos - absolute_dir, len,
4199 &ftpc->dirs[ftpc->dirdepth], NULL,
4207 cur_pos = slash_pos + 1; /* jump to the rest of the string */
4208 if(!ftpc->dirdepth) {
4209 /* path starts with a slash, add that as a directory */
4210 ftpc->dirs[ftpc->dirdepth] = strdup("/");
4211 if(!ftpc->dirs[ftpc->dirdepth++]) { /* run out of memory ... */
4212 failf(data, "no memory");
4214 return CURLE_OUT_OF_MEMORY;
4220 cur_pos = slash_pos + 1; /* jump to the rest of the string */
4221 if(++ftpc->dirdepth >= ftpc->diralloc) {
4224 ftpc->diralloc *= 2; /* double the size each time */
4225 bigger = realloc(ftpc->dirs, ftpc->diralloc * sizeof(ftpc->dirs[0]));
4228 return CURLE_OUT_OF_MEMORY;
4230 ftpc->dirs = bigger;
4234 filename = cur_pos; /* the rest is the file name */
4238 if(filename && *filename) {
4240 Curl_urldecode(conn->data, filename, 0, &ftpc->file, NULL, TRUE);
4248 ftpc->file = NULL; /* instead of point to a zero byte, we make it a NULL
4251 if(data->set.upload && !ftpc->file && (ftp->transfer == FTPTRANSFER_BODY)) {
4252 /* We need a file name when uploading. Return error! */
4253 failf(data, "Uploading to a URL without a file name!");
4254 return CURLE_URL_MALFORMAT;
4257 ftpc->cwddone = FALSE; /* default to not done */
4259 if(ftpc->prevpath) {
4260 /* prevpath is "raw" so we convert the input path before we compare the
4265 Curl_urldecode(conn->data, data->state.path, 0, &path, &dlen, TRUE);
4271 dlen -= ftpc->file?strlen(ftpc->file):0;
4272 if((dlen == strlen(ftpc->prevpath)) &&
4273 !strncmp(path, ftpc->prevpath, dlen) &&
4274 (ftpc->prevmethod == data->set.ftp_filemethod)) {
4275 infof(data, "Request has same path as previous transfer\n");
4276 ftpc->cwddone = TRUE;
4284 /* call this when the DO phase has completed */
4285 static CURLcode ftp_dophase_done(struct connectdata *conn,
4288 struct FTP *ftp = conn->data->req.protop;
4289 struct ftp_conn *ftpc = &conn->proto.ftpc;
4293 CURLcode result = ftp_do_more(conn, &completed);
4296 close_secondarysocket(conn);
4301 if(ftp->transfer != FTPTRANSFER_BODY)
4302 /* no data to transfer */
4303 Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
4305 /* since we didn't connect now, we want do_more to get called */
4306 conn->bits.do_more = TRUE;
4308 ftpc->ctl_valid = TRUE; /* seems good */
4313 /* called from multi.c while DOing */
4314 static CURLcode ftp_doing(struct connectdata *conn,
4317 CURLcode result = ftp_multi_statemach(conn, dophase_done);
4320 DEBUGF(infof(conn->data, "DO phase failed\n"));
4321 else if(*dophase_done) {
4322 result = ftp_dophase_done(conn, FALSE /* not connected */);
4324 DEBUGF(infof(conn->data, "DO phase is complete2\n"));
4329 /***********************************************************************
4331 * ftp_regular_transfer()
4333 * The input argument is already checked for validity.
4335 * Performs all commands done before a regular transfer between a local and a
4338 * ftp->ctl_valid starts out as FALSE, and gets set to TRUE if we reach the
4339 * ftp_done() function without finding any major problem.
4342 CURLcode ftp_regular_transfer(struct connectdata *conn,
4345 CURLcode result = CURLE_OK;
4346 bool connected = FALSE;
4347 struct Curl_easy *data = conn->data;
4348 struct ftp_conn *ftpc = &conn->proto.ftpc;
4349 data->req.size = -1; /* make sure this is unknown at this point */
4351 Curl_pgrsSetUploadCounter(data, 0);
4352 Curl_pgrsSetDownloadCounter(data, 0);
4353 Curl_pgrsSetUploadSize(data, -1);
4354 Curl_pgrsSetDownloadSize(data, -1);
4356 ftpc->ctl_valid = TRUE; /* starts good */
4358 result = ftp_perform(conn,
4359 &connected, /* have we connected after PASV/PORT */
4360 dophase_done); /* all commands in the DO-phase done? */
4365 /* the DO phase has not completed yet */
4368 result = ftp_dophase_done(conn, connected);
4379 static CURLcode ftp_setup_connection(struct connectdata *conn)
4381 struct Curl_easy *data = conn->data;
4386 conn->data->req.protop = ftp = malloc(sizeof(struct FTP));
4388 return CURLE_OUT_OF_MEMORY;
4390 data->state.path++; /* don't include the initial slash */
4391 data->state.slash_removed = TRUE; /* we've skipped the slash */
4393 /* FTP URLs support an extension like ";type=<typecode>" that
4394 * we'll try to get now! */
4395 type = strstr(data->state.path, ";type=");
4398 type = strstr(conn->host.rawalloc, ";type=");
4401 *type = 0; /* it was in the middle of the hostname */
4402 command = Curl_raw_toupper(type[6]);
4403 conn->bits.type_set = TRUE;
4406 case 'A': /* ASCII mode */
4407 data->set.prefer_ascii = TRUE;
4410 case 'D': /* directory mode */
4411 data->set.ftp_list_only = TRUE;
4414 case 'I': /* binary mode */
4416 /* switch off ASCII */
4417 data->set.prefer_ascii = FALSE;
4422 /* get some initial data into the ftp struct */
4423 ftp->bytecountp = &conn->data->req.bytecount;
4424 ftp->transfer = FTPTRANSFER_BODY;
4425 ftp->downloadsize = 0;
4427 /* No need to duplicate user+password, the connectdata struct won't change
4428 during a session, but we re-init them here since on subsequent inits
4429 since the conn struct may have changed or been replaced.
4431 ftp->user = conn->user;
4432 ftp->passwd = conn->passwd;
4433 if(isBadFtpString(ftp->user))
4434 return CURLE_URL_MALFORMAT;
4435 if(isBadFtpString(ftp->passwd))
4436 return CURLE_URL_MALFORMAT;
4438 conn->proto.ftpc.known_filesize = -1; /* unknown size for now */
4443 #endif /* CURL_DISABLE_FTP */