1 /***************************************************************************
3 * Project ___| | | | _ \| |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
8 * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al.
10 * This software is licensed as described in the file COPYING, which
11 * you should have received as part of this distribution. The terms
12 * are also available at http://curl.haxx.se/docs/copyright.html.
14 * You may opt to use, copy, modify, merge, publish, distribute and/or sell
15 * copies of the Software, and permit persons to whom the Software is
16 * furnished to do so, under the terms of the COPYING file.
18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19 * KIND, either express or implied.
21 ***************************************************************************/
23 #include "curl_setup.h"
25 #ifndef CURL_DISABLE_FTP
27 #ifdef HAVE_NETINET_IN_H
28 #include <netinet/in.h>
30 #ifdef HAVE_ARPA_INET_H
31 #include <arpa/inet.h>
34 #include <sys/utsname.h>
44 #if (defined(NETWARE) && defined(__NOVELL_LIBC__))
46 #define in_addr_t unsigned long
49 #include <curl/curl.h>
57 #include "http.h" /* for HTTP proxy tunnel stuff */
61 #include "ftplistparser.h"
63 #include "strtoofft.h"
65 #include "vtls/vtls.h"
68 #include "inet_ntop.h"
69 #include "inet_pton.h"
71 #include "parsedate.h" /* for the week day and month names */
72 #include "sockaddr.h" /* required for Curl_sockaddr_storage */
76 #include "speedcheck.h"
78 #include "http_proxy.h"
79 #include "non-ascii.h"
81 #define _MPRINTF_REPLACE /* use our functions only */
82 #include <curl/mprintf.h>
84 #include "curl_memory.h"
85 /* The last #include file should be: */
89 #define NI_MAXHOST 1025
91 #ifndef INET_ADDRSTRLEN
92 #define INET_ADDRSTRLEN 16
95 #ifdef CURL_DISABLE_VERBOSE_STRINGS
96 #define ftp_pasv_verbose(a,b,c,d) Curl_nop_stmt
99 /* Local API functions */
101 static void _state(struct connectdata *conn,
103 #define state(x,y) _state(x,y)
105 static void _state(struct connectdata *conn,
108 #define state(x,y) _state(x,y,__LINE__)
111 static CURLcode ftp_sendquote(struct connectdata *conn,
112 struct curl_slist *quote);
113 static CURLcode ftp_quit(struct connectdata *conn);
114 static CURLcode ftp_parse_url_path(struct connectdata *conn);
115 static CURLcode ftp_regular_transfer(struct connectdata *conn, bool *done);
116 #ifndef CURL_DISABLE_VERBOSE_STRINGS
117 static void ftp_pasv_verbose(struct connectdata *conn,
119 char *newhost, /* ascii version */
122 static CURLcode ftp_state_prepare_transfer(struct connectdata *conn);
123 static CURLcode ftp_state_mdtm(struct connectdata *conn);
124 static CURLcode ftp_state_quote(struct connectdata *conn,
125 bool init, ftpstate instate);
126 static CURLcode ftp_nb_type(struct connectdata *conn,
127 bool ascii, ftpstate newstate);
128 static int ftp_need_type(struct connectdata *conn,
130 static CURLcode ftp_do(struct connectdata *conn, bool *done);
131 static CURLcode ftp_done(struct connectdata *conn,
132 CURLcode, bool premature);
133 static CURLcode ftp_connect(struct connectdata *conn, bool *done);
134 static CURLcode ftp_disconnect(struct connectdata *conn, bool dead_connection);
135 static CURLcode ftp_do_more(struct connectdata *conn, int *completed);
136 static CURLcode ftp_multi_statemach(struct connectdata *conn, bool *done);
137 static int ftp_getsock(struct connectdata *conn, curl_socket_t *socks,
139 static int ftp_domore_getsock(struct connectdata *conn, curl_socket_t *socks,
141 static CURLcode ftp_doing(struct connectdata *conn,
143 static CURLcode ftp_setup_connection(struct connectdata * conn);
145 static CURLcode init_wc_data(struct connectdata *conn);
146 static CURLcode wc_statemach(struct connectdata *conn);
148 static void wc_data_dtor(void *ptr);
150 static CURLcode ftp_state_retr(struct connectdata *conn, curl_off_t filesize);
152 static CURLcode ftp_readresp(curl_socket_t sockfd,
156 static CURLcode ftp_dophase_done(struct connectdata *conn,
159 /* easy-to-use macro: */
160 #define PPSENDF(x,y,z) if((result = Curl_pp_sendf(x,y,z))) \
165 * FTP protocol handler.
168 const struct Curl_handler Curl_handler_ftp = {
170 ftp_setup_connection, /* setup_connection */
173 ftp_do_more, /* do_more */
174 ftp_connect, /* connect_it */
175 ftp_multi_statemach, /* connecting */
176 ftp_doing, /* doing */
177 ftp_getsock, /* proto_getsock */
178 ftp_getsock, /* doing_getsock */
179 ftp_domore_getsock, /* domore_getsock */
180 ZERO_NULL, /* perform_getsock */
181 ftp_disconnect, /* disconnect */
182 ZERO_NULL, /* readwrite */
183 PORT_FTP, /* defport */
184 CURLPROTO_FTP, /* protocol */
185 PROTOPT_DUAL | PROTOPT_CLOSEACTION | PROTOPT_NEEDSPWD
186 | PROTOPT_NOURLQUERY /* flags */
192 * FTPS protocol handler.
195 const struct Curl_handler Curl_handler_ftps = {
197 ftp_setup_connection, /* setup_connection */
200 ftp_do_more, /* do_more */
201 ftp_connect, /* connect_it */
202 ftp_multi_statemach, /* connecting */
203 ftp_doing, /* doing */
204 ftp_getsock, /* proto_getsock */
205 ftp_getsock, /* doing_getsock */
206 ftp_domore_getsock, /* domore_getsock */
207 ZERO_NULL, /* perform_getsock */
208 ftp_disconnect, /* disconnect */
209 ZERO_NULL, /* readwrite */
210 PORT_FTPS, /* defport */
211 CURLPROTO_FTPS, /* protocol */
212 PROTOPT_SSL | PROTOPT_DUAL | PROTOPT_CLOSEACTION |
213 PROTOPT_NEEDSPWD | PROTOPT_NOURLQUERY /* flags */
217 #ifndef CURL_DISABLE_HTTP
219 * HTTP-proxyed FTP protocol handler.
222 static const struct Curl_handler Curl_handler_ftp_proxy = {
224 Curl_http_setup_conn, /* setup_connection */
225 Curl_http, /* do_it */
226 Curl_http_done, /* done */
227 ZERO_NULL, /* do_more */
228 ZERO_NULL, /* connect_it */
229 ZERO_NULL, /* connecting */
230 ZERO_NULL, /* doing */
231 ZERO_NULL, /* proto_getsock */
232 ZERO_NULL, /* doing_getsock */
233 ZERO_NULL, /* domore_getsock */
234 ZERO_NULL, /* perform_getsock */
235 ZERO_NULL, /* disconnect */
236 ZERO_NULL, /* readwrite */
237 PORT_FTP, /* defport */
238 CURLPROTO_HTTP, /* protocol */
239 PROTOPT_NONE /* flags */
245 * HTTP-proxyed FTPS protocol handler.
248 static const struct Curl_handler Curl_handler_ftps_proxy = {
250 Curl_http_setup_conn, /* setup_connection */
251 Curl_http, /* do_it */
252 Curl_http_done, /* done */
253 ZERO_NULL, /* do_more */
254 ZERO_NULL, /* connect_it */
255 ZERO_NULL, /* connecting */
256 ZERO_NULL, /* doing */
257 ZERO_NULL, /* proto_getsock */
258 ZERO_NULL, /* doing_getsock */
259 ZERO_NULL, /* domore_getsock */
260 ZERO_NULL, /* perform_getsock */
261 ZERO_NULL, /* disconnect */
262 ZERO_NULL, /* readwrite */
263 PORT_FTPS, /* defport */
264 CURLPROTO_HTTP, /* protocol */
265 PROTOPT_NONE /* flags */
272 * NOTE: back in the old days, we added code in the FTP code that made NOBODY
273 * requests on files respond with headers passed to the client/stdout that
274 * looked like HTTP ones.
276 * This approach is not very elegant, it causes confusion and is error-prone.
277 * It is subject for removal at the next (or at least a future) soname bump.
278 * Until then you can test the effects of the removal by undefining the
279 * following define named CURL_FTP_HTTPSTYLE_HEAD.
281 #define CURL_FTP_HTTPSTYLE_HEAD 1
283 static void freedirs(struct ftp_conn *ftpc)
287 for(i=0; i < ftpc->dirdepth; i++) {
297 Curl_safefree(ftpc->file);
299 /* no longer of any use */
300 Curl_safefree(ftpc->newhost);
303 /* Returns non-zero if the given string contains CR (\r) or LF (\n),
304 which are not allowed within RFC 959 <string>.
305 Note: The input string is in the client's encoding which might
306 not be ASCII, so escape sequences \r & \n must be used instead
307 of hex values 0x0d & 0x0a.
309 static bool isBadFtpString(const char *string)
311 return ((NULL != strchr(string, '\r')) ||
312 (NULL != strchr(string, '\n'))) ? TRUE : FALSE;
315 /***********************************************************************
317 * AcceptServerConnect()
319 * After connection request is received from the server this function is
320 * called to accept the connection and close the listening socket
323 static CURLcode AcceptServerConnect(struct connectdata *conn)
325 struct SessionHandle *data = conn->data;
326 curl_socket_t sock = conn->sock[SECONDARYSOCKET];
327 curl_socket_t s = CURL_SOCKET_BAD;
329 struct Curl_sockaddr_storage add;
331 struct sockaddr_in add;
333 curl_socklen_t size = (curl_socklen_t) sizeof(add);
335 if(0 == getsockname(sock, (struct sockaddr *) &add, &size)) {
338 s=accept(sock, (struct sockaddr *) &add, &size);
340 Curl_closesocket(conn, sock); /* close the first socket */
342 if(CURL_SOCKET_BAD == s) {
343 failf(data, "Error accept()ing server connect");
344 return CURLE_FTP_PORT_FAILED;
346 infof(data, "Connection accepted from server\n");
348 conn->sock[SECONDARYSOCKET] = s;
349 (void)curlx_nonblock(s, TRUE); /* enable non-blocking */
350 conn->sock_accepted[SECONDARYSOCKET] = TRUE;
352 if(data->set.fsockopt) {
355 /* activate callback for setting socket options */
356 error = data->set.fsockopt(data->set.sockopt_client,
358 CURLSOCKTYPE_ACCEPT);
361 Curl_closesocket(conn, s); /* close the socket and bail out */
362 conn->sock[SECONDARYSOCKET] = CURL_SOCKET_BAD;
363 return CURLE_ABORTED_BY_CALLBACK;
372 * ftp_timeleft_accept() returns the amount of milliseconds left allowed for
373 * waiting server to connect. If the value is negative, the timeout time has
376 * The start time is stored in progress.t_acceptdata - as set with
377 * Curl_pgrsTime(..., TIMER_STARTACCEPT);
380 static long ftp_timeleft_accept(struct SessionHandle *data)
382 long timeout_ms = DEFAULT_ACCEPT_TIMEOUT;
386 if(data->set.accepttimeout > 0)
387 timeout_ms = data->set.accepttimeout;
391 /* check if the generic timeout possibly is set shorter */
392 other = Curl_timeleft(data, &now, FALSE);
393 if(other && (other < timeout_ms))
394 /* note that this also works fine for when other happens to be negative
395 due to it already having elapsed */
398 /* subtract elapsed time */
399 timeout_ms -= Curl_tvdiff(now, data->progress.t_acceptdata);
401 /* avoid returning 0 as that means no timeout! */
409 /***********************************************************************
411 * ReceivedServerConnect()
413 * After allowing server to connect to us from data port, this function
414 * checks both data connection for connection establishment and ctrl
415 * connection for a negative response regarding a failure in connecting
418 static CURLcode ReceivedServerConnect(struct connectdata *conn, bool *received)
420 struct SessionHandle *data = conn->data;
421 curl_socket_t ctrl_sock = conn->sock[FIRSTSOCKET];
422 curl_socket_t data_sock = conn->sock[SECONDARYSOCKET];
423 struct ftp_conn *ftpc = &conn->proto.ftpc;
424 struct pingpong *pp = &ftpc->pp;
432 timeout_ms = ftp_timeleft_accept(data);
433 infof(data, "Checking for server connect\n");
435 /* if a timeout was already reached, bail out */
436 failf(data, "Accept timeout occurred while waiting server connect");
437 return CURLE_FTP_ACCEPT_TIMEOUT;
440 /* First check whether there is a cached response from server */
441 if(pp->cache_size && pp->cache && pp->cache[0] > '3') {
442 /* Data connection could not be established, let's return */
443 infof(data, "There is negative response in cache while serv connect\n");
444 Curl_GetFTPResponse(&nread, conn, &ftpcode);
445 return CURLE_FTP_ACCEPT_FAILED;
448 result = Curl_socket_check(ctrl_sock, data_sock, CURL_SOCKET_BAD, 0);
450 /* see if the connection request is already here */
454 failf(data, "Error while waiting for server connect");
455 return CURLE_FTP_ACCEPT_FAILED;
456 case 0: /* Server connect is not received yet */
460 if(result & CURL_CSELECT_IN2) {
461 infof(data, "Ready to accept data connection from server\n");
464 else if(result & CURL_CSELECT_IN) {
465 infof(data, "Ctrl conn has data while waiting for data conn\n");
466 Curl_GetFTPResponse(&nread, conn, &ftpcode);
469 return CURLE_FTP_ACCEPT_FAILED;
471 return CURLE_FTP_WEIRD_SERVER_REPLY;
481 /***********************************************************************
485 * After connection from server is accepted this function is called to
486 * setup transfer parameters and initiate the data transfer.
489 static CURLcode InitiateTransfer(struct connectdata *conn)
491 struct SessionHandle *data = conn->data;
492 struct FTP *ftp = data->req.protop;
493 CURLcode result = CURLE_OK;
495 if(conn->ssl[SECONDARYSOCKET].use) {
496 /* since we only have a plaintext TCP connection here, we must now
497 * do the TLS stuff */
498 infof(data, "Doing the SSL/TLS handshake on the data stream\n");
499 result = Curl_ssl_connect(conn, SECONDARYSOCKET);
504 if(conn->proto.ftpc.state_saved == FTP_STOR) {
505 *(ftp->bytecountp)=0;
507 /* When we know we're uploading a specified file, we can get the file
508 size prior to the actual upload. */
510 Curl_pgrsSetUploadSize(data, data->state.infilesize);
512 /* set the SO_SNDBUF for the secondary socket for those who need it */
513 Curl_sndbufset(conn->sock[SECONDARYSOCKET]);
515 Curl_setup_transfer(conn, -1, -1, FALSE, NULL, /* no download */
516 SECONDARYSOCKET, ftp->bytecountp);
520 Curl_setup_transfer(conn, SECONDARYSOCKET,
521 conn->proto.ftpc.retr_size_saved, FALSE,
522 ftp->bytecountp, -1, NULL); /* no upload here */
525 conn->proto.ftpc.pp.pending_resp = TRUE; /* expect server response */
526 state(conn, FTP_STOP);
531 /***********************************************************************
533 * AllowServerConnect()
535 * When we've issue the PORT command, we have told the server to connect to
536 * us. This function checks whether data connection is established if so it is
540 static CURLcode AllowServerConnect(struct connectdata *conn, bool *connected)
542 struct SessionHandle *data = conn->data;
544 CURLcode result = CURLE_OK;
547 infof(data, "Preparing for accepting server on data port\n");
549 /* Save the time we start accepting server connect */
550 Curl_pgrsTime(data, TIMER_STARTACCEPT);
552 timeout_ms = ftp_timeleft_accept(data);
554 /* if a timeout was already reached, bail out */
555 failf(data, "Accept timeout occurred while waiting server connect");
556 return CURLE_FTP_ACCEPT_TIMEOUT;
559 /* see if the connection request is already here */
560 result = ReceivedServerConnect(conn, connected);
565 result = AcceptServerConnect(conn);
569 result = InitiateTransfer(conn);
574 /* Add timeout to multi handle and break out of the loop */
575 if(!result && *connected == FALSE) {
576 if(data->set.accepttimeout > 0)
577 Curl_expire(data, data->set.accepttimeout);
579 Curl_expire(data, DEFAULT_ACCEPT_TIMEOUT);
586 /* macro to check for a three-digit ftp status code at the start of the
588 #define STATUSCODE(line) (ISDIGIT(line[0]) && ISDIGIT(line[1]) && \
591 /* macro to check for the last line in an FTP server response */
592 #define LASTLINE(line) (STATUSCODE(line) && (' ' == line[3]))
594 static bool ftp_endofresp(struct connectdata *conn, char *line, size_t len,
599 if((len > 3) && LASTLINE(line)) {
600 *code = curlx_sltosi(strtol(line, NULL, 10));
607 static CURLcode ftp_readresp(curl_socket_t sockfd,
609 int *ftpcode, /* return the ftp-code if done */
610 size_t *size) /* size of the response */
612 struct connectdata *conn = pp->conn;
613 struct SessionHandle *data = conn->data;
615 char * const buf = data->state.buffer;
617 CURLcode result = CURLE_OK;
620 result = Curl_pp_readresp(sockfd, pp, &code, size);
622 #if defined(HAVE_GSSAPI)
623 /* handle the security-oriented responses 6xx ***/
624 /* FIXME: some errorchecking perhaps... ***/
627 code = Curl_sec_read_msg(conn, buf, PROT_SAFE);
630 code = Curl_sec_read_msg(conn, buf, PROT_PRIVATE);
633 code = Curl_sec_read_msg(conn, buf, PROT_CONFIDENTIAL);
636 /* normal ftp stuff we pass through! */
641 /* store the latest code for later retrieval */
642 data->info.httpcode=code;
648 /* 421 means "Service not available, closing control connection." and FTP
649 * servers use it to signal that idle session timeout has been exceeded.
650 * If we ignored the response, it could end up hanging in some cases.
652 * This response code can come at any point so having it treated
653 * generically is a good idea.
655 infof(data, "We got a 421 - timeout!\n");
656 state(conn, FTP_STOP);
657 return CURLE_OPERATION_TIMEDOUT;
663 /* --- parse FTP server responses --- */
666 * Curl_GetFTPResponse() is a BLOCKING function to read the full response
667 * from a server after a command.
671 CURLcode Curl_GetFTPResponse(ssize_t *nreadp, /* return number of bytes read */
672 struct connectdata *conn,
673 int *ftpcode) /* return the ftp-code */
676 * We cannot read just one byte per read() and then go back to select() as
677 * the OpenSSL read() doesn't grok that properly.
679 * Alas, read as much as possible, split up into lines, use the ending
680 * line in a response or continue reading. */
682 curl_socket_t sockfd = conn->sock[FIRSTSOCKET];
683 long timeout; /* timeout in milliseconds */
685 struct SessionHandle *data = conn->data;
686 CURLcode result = CURLE_OK;
687 struct ftp_conn *ftpc = &conn->proto.ftpc;
688 struct pingpong *pp = &ftpc->pp;
691 int value_to_be_ignored=0;
694 *ftpcode = 0; /* 0 for errors */
696 /* make the pointer point to something for the rest of this function */
697 ftpcode = &value_to_be_ignored;
701 while(!*ftpcode && !result) {
702 /* check and reset timeout value every lap */
703 timeout = Curl_pp_state_timeout(pp);
706 failf(data, "FTP response timeout");
707 return CURLE_OPERATION_TIMEDOUT; /* already too little time */
710 interval_ms = 1000; /* use 1 second timeout intervals */
711 if(timeout < interval_ms)
712 interval_ms = timeout;
715 * Since this function is blocking, we need to wait here for input on the
716 * connection and only then we call the response reading function. We do
717 * timeout at least every second to make the timeout check run.
719 * A caution here is that the ftp_readresp() function has a cache that may
720 * contain pieces of a response from the previous invoke and we need to
721 * make sure we don't just wait for input while there is unhandled data in
722 * that cache. But also, if the cache is there, we call ftp_readresp() and
723 * the cache wasn't good enough to continue we must not just busy-loop
724 * around this function.
728 if(pp->cache && (cache_skip < 2)) {
730 * There's a cache left since before. We then skipping the wait for
731 * socket action, unless this is the same cache like the previous round
732 * as then the cache was deemed not enough to act on and we then need to
733 * wait for more data anyway.
737 switch (Curl_socket_ready(sockfd, CURL_SOCKET_BAD, interval_ms)) {
738 case -1: /* select() error, stop reading */
739 failf(data, "FTP response aborted due to select/poll error: %d",
741 return CURLE_RECV_ERROR;
743 case 0: /* timeout */
744 if(Curl_pgrsUpdate(conn))
745 return CURLE_ABORTED_BY_CALLBACK;
746 continue; /* just continue in our loop for the timeout duration */
748 default: /* for clarity */
752 result = ftp_readresp(sockfd, pp, ftpcode, &nread);
756 if(!nread && pp->cache)
757 /* bump cache skip counter as on repeated skips we must wait for more
761 /* when we got data or there is no cache left, we reset the cache skip
767 } /* while there's buffer left and loop is requested */
769 pp->pending_resp = FALSE;
774 #if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
775 /* for debug purposes */
776 static const char * const ftp_state_names[]={
815 /* This is the ONLY way to change FTP state! */
816 static void _state(struct connectdata *conn,
823 struct ftp_conn *ftpc = &conn->proto.ftpc;
825 #if defined(DEBUGBUILD)
827 #if defined(CURL_DISABLE_VERBOSE_STRINGS)
830 if(ftpc->state != newstate)
831 infof(conn->data, "FTP %p (line %d) state change from %s to %s\n",
832 (void *)ftpc, lineno, ftp_state_names[ftpc->state],
833 ftp_state_names[newstate]);
837 ftpc->state = newstate;
840 static CURLcode ftp_state_user(struct connectdata *conn)
843 struct FTP *ftp = conn->data->req.protop;
845 PPSENDF(&conn->proto.ftpc.pp, "USER %s", ftp->user?ftp->user:"");
847 state(conn, FTP_USER);
848 conn->data->state.ftp_trying_alternative = FALSE;
853 static CURLcode ftp_state_pwd(struct connectdata *conn)
857 /* send PWD to discover our entry point */
858 PPSENDF(&conn->proto.ftpc.pp, "%s", "PWD");
859 state(conn, FTP_PWD);
864 /* For the FTP "protocol connect" and "doing" phases only */
865 static int ftp_getsock(struct connectdata *conn,
866 curl_socket_t *socks,
869 return Curl_pp_getsock(&conn->proto.ftpc.pp, socks, numsocks);
872 /* For the FTP "DO_MORE" phase only */
873 static int ftp_domore_getsock(struct connectdata *conn, curl_socket_t *socks,
876 struct ftp_conn *ftpc = &conn->proto.ftpc;
879 return GETSOCK_BLANK;
881 /* When in DO_MORE state, we could be either waiting for us to connect to a
882 * remote site, or we could wait for that site to connect to us. Or just
883 * handle ordinary commands.
886 if(FTP_STOP == ftpc->state) {
887 int bits = GETSOCK_READSOCK(0);
889 /* if stopped and still in this state, then we're also waiting for a
890 connect on the secondary connection */
891 socks[0] = conn->sock[FIRSTSOCKET];
893 if(!conn->data->set.ftp_use_port) {
896 /* PORT is used to tell the server to connect to us, and during that we
897 don't do happy eyeballs, but we do if we connect to the server */
898 for(s=1, i=0; i<2; i++) {
899 if(conn->tempsock[i] != CURL_SOCKET_BAD) {
900 socks[s] = conn->tempsock[i];
901 bits |= GETSOCK_WRITESOCK(s++);
906 socks[1] = conn->sock[SECONDARYSOCKET];
907 bits |= GETSOCK_WRITESOCK(1);
913 return Curl_pp_getsock(&conn->proto.ftpc.pp, socks, numsocks);
916 /* This is called after the FTP_QUOTE state is passed.
918 ftp_state_cwd() sends the range of CWD commands to the server to change to
919 the correct directory. It may also need to send MKD commands to create
920 missing ones, if that option is enabled.
922 static CURLcode ftp_state_cwd(struct connectdata *conn)
924 CURLcode result = CURLE_OK;
925 struct ftp_conn *ftpc = &conn->proto.ftpc;
928 /* already done and fine */
929 result = ftp_state_mdtm(conn);
931 ftpc->count2 = 0; /* count2 counts failed CWDs */
933 /* count3 is set to allow a MKD to fail once. In the case when first CWD
934 fails and then MKD fails (due to another session raced it to create the
935 dir) this then allows for a second try to CWD to it */
936 ftpc->count3 = (conn->data->set.ftp_create_missing_dirs==2)?1:0;
938 if(conn->bits.reuse && ftpc->entrypath) {
939 /* This is a re-used connection. Since we change directory to where the
940 transfer is taking place, we must first get back to the original dir
941 where we ended up after login: */
942 ftpc->count1 = 0; /* we count this as the first path, then we add one
943 for all upcoming ones in the ftp->dirs[] array */
944 PPSENDF(&conn->proto.ftpc.pp, "CWD %s", ftpc->entrypath);
945 state(conn, FTP_CWD);
950 /* issue the first CWD, the rest is sent when the CWD responses are
952 PPSENDF(&conn->proto.ftpc.pp, "CWD %s", ftpc->dirs[ftpc->count1 -1]);
953 state(conn, FTP_CWD);
956 /* No CWD necessary */
957 result = ftp_state_mdtm(conn);
970 static CURLcode ftp_state_use_port(struct connectdata *conn,
971 ftpport fcmd) /* start with this */
974 CURLcode result = CURLE_OK;
975 struct ftp_conn *ftpc = &conn->proto.ftpc;
976 struct SessionHandle *data=conn->data;
977 curl_socket_t portsock= CURL_SOCKET_BAD;
978 char myhost[256] = "";
980 struct Curl_sockaddr_storage ss;
981 Curl_addrinfo *res, *ai;
982 curl_socklen_t sslen;
983 char hbuf[NI_MAXHOST];
984 struct sockaddr *sa=(struct sockaddr *)&ss;
985 struct sockaddr_in * const sa4 = (void *)sa;
987 struct sockaddr_in6 * const sa6 = (void *)sa;
990 static const char mode[][5] = { "EPRT", "PORT" };
994 char *string_ftpport = data->set.str[STRING_FTPPORT];
995 struct Curl_dns_entry *h=NULL;
996 unsigned short port_min = 0;
997 unsigned short port_max = 0;
999 bool possibly_non_local = TRUE;
1003 /* Step 1, figure out what is requested,
1005 * (ipv4|ipv6|domain|interface)?(:port(-range)?)?
1008 if(data->set.str[STRING_FTPPORT] &&
1009 (strlen(data->set.str[STRING_FTPPORT]) > 1)) {
1012 size_t addrlen = INET6_ADDRSTRLEN > strlen(string_ftpport) ?
1013 INET6_ADDRSTRLEN : strlen(string_ftpport);
1015 size_t addrlen = INET_ADDRSTRLEN > strlen(string_ftpport) ?
1016 INET_ADDRSTRLEN : strlen(string_ftpport);
1018 char *ip_start = string_ftpport;
1019 char *ip_end = NULL;
1020 char *port_start = NULL;
1021 char *port_sep = NULL;
1023 addr = calloc(addrlen+1, 1);
1025 return CURLE_OUT_OF_MEMORY;
1028 if(*string_ftpport == '[') {
1029 /* [ipv6]:port(-range) */
1030 ip_start = string_ftpport + 1;
1031 if((ip_end = strchr(string_ftpport, ']')) != NULL )
1032 strncpy(addr, ip_start, ip_end - ip_start);
1036 if(*string_ftpport == ':') {
1038 ip_end = string_ftpport;
1040 else if((ip_end = strchr(string_ftpport, ':')) != NULL) {
1041 /* either ipv6 or (ipv4|domain|interface):port(-range) */
1043 if(Curl_inet_pton(AF_INET6, string_ftpport, sa6) == 1) {
1045 port_min = port_max = 0;
1046 strcpy(addr, string_ftpport);
1047 ip_end = NULL; /* this got no port ! */
1051 /* (ipv4|domain|interface):port(-range) */
1052 strncpy(addr, string_ftpport, ip_end - ip_start );
1055 /* ipv4|interface */
1056 strcpy(addr, string_ftpport);
1058 /* parse the port */
1059 if(ip_end != NULL) {
1060 if((port_start = strchr(ip_end, ':')) != NULL) {
1061 port_min = curlx_ultous(strtoul(port_start+1, NULL, 10));
1062 if((port_sep = strchr(port_start, '-')) != NULL) {
1063 port_max = curlx_ultous(strtoul(port_sep + 1, NULL, 10));
1066 port_max = port_min;
1070 /* correct errors like:
1072 * :-4711 , in this case port_min is (unsigned)-1,
1073 * therefore port_min > port_max for all cases
1074 * but port_max = (unsigned)-1
1076 if(port_min > port_max )
1077 port_min = port_max = 0;
1081 /* attempt to get the address of the given interface name */
1082 switch(Curl_if2ip(conn->ip_addr->ai_family,
1083 Curl_ipv6_scope(conn->ip_addr->ai_addr),
1084 conn->scope_id, addr, hbuf, sizeof(hbuf))) {
1085 case IF2IP_NOT_FOUND:
1086 /* not an interface, use the given string as host name instead */
1089 case IF2IP_AF_NOT_SUPPORTED:
1090 return CURLE_FTP_PORT_FAILED;
1092 host = hbuf; /* use the hbuf for host name */
1096 /* there was only a port(-range) given, default the host */
1098 } /* data->set.ftpport */
1101 /* not an interface and not a host name, get default by extracting
1102 the IP from the control connection */
1105 if(getsockname(conn->sock[FIRSTSOCKET], sa, &sslen)) {
1106 failf(data, "getsockname() failed: %s",
1107 Curl_strerror(conn, SOCKERRNO) );
1108 Curl_safefree(addr);
1109 return CURLE_FTP_PORT_FAILED;
1111 switch(sa->sa_family) {
1114 Curl_inet_ntop(sa->sa_family, &sa6->sin6_addr, hbuf, sizeof(hbuf));
1118 Curl_inet_ntop(sa->sa_family, &sa4->sin_addr, hbuf, sizeof(hbuf));
1121 host = hbuf; /* use this host name */
1122 possibly_non_local = FALSE; /* we know it is local now */
1125 /* resolv ip/host to ip */
1126 rc = Curl_resolv(conn, host, 0, &h);
1127 if(rc == CURLRESOLV_PENDING)
1128 (void)Curl_resolver_wait_resolv(conn, &h);
1131 /* when we return from this function, we can forget about this entry
1132 to we can unlock it now already */
1133 Curl_resolv_unlock(data, h);
1136 res = NULL; /* failure! */
1139 failf(data, "failed to resolve the address provided to PORT: %s", host);
1140 Curl_safefree(addr);
1141 return CURLE_FTP_PORT_FAILED;
1144 Curl_safefree(addr);
1147 /* step 2, create a socket for the requested address */
1149 portsock = CURL_SOCKET_BAD;
1151 for(ai = res; ai; ai = ai->ai_next) {
1152 result = Curl_socket(conn, ai, NULL, &portsock);
1160 failf(data, "socket failure: %s", Curl_strerror(conn, error));
1161 return CURLE_FTP_PORT_FAILED;
1164 /* step 3, bind to a suitable local address */
1166 memcpy(sa, ai->ai_addr, ai->ai_addrlen);
1167 sslen = ai->ai_addrlen;
1169 for(port = port_min; port <= port_max;) {
1170 if(sa->sa_family == AF_INET)
1171 sa4->sin_port = htons(port);
1174 sa6->sin6_port = htons(port);
1176 /* Try binding the given address. */
1177 if(bind(portsock, sa, sslen) ) {
1180 if(possibly_non_local && (error == EADDRNOTAVAIL)) {
1181 /* The requested bind address is not local. Use the address used for
1182 * the control connection instead and restart the port loop
1185 infof(data, "bind(port=%hu) on non-local address failed: %s\n", port,
1186 Curl_strerror(conn, error) );
1189 if(getsockname(conn->sock[FIRSTSOCKET], sa, &sslen)) {
1190 failf(data, "getsockname() failed: %s",
1191 Curl_strerror(conn, SOCKERRNO) );
1192 Curl_closesocket(conn, portsock);
1193 return CURLE_FTP_PORT_FAILED;
1196 possibly_non_local = FALSE; /* don't try this again */
1199 else if(error != EADDRINUSE && error != EACCES) {
1200 failf(data, "bind(port=%hu) failed: %s", port,
1201 Curl_strerror(conn, error) );
1202 Curl_closesocket(conn, portsock);
1203 return CURLE_FTP_PORT_FAILED;
1212 /* maybe all ports were in use already*/
1213 if(port > port_max) {
1214 failf(data, "bind() failed, we ran out of ports!");
1215 Curl_closesocket(conn, portsock);
1216 return CURLE_FTP_PORT_FAILED;
1219 /* get the name again after the bind() so that we can extract the
1220 port number it uses now */
1222 if(getsockname(portsock, (struct sockaddr *)sa, &sslen)) {
1223 failf(data, "getsockname() failed: %s",
1224 Curl_strerror(conn, SOCKERRNO) );
1225 Curl_closesocket(conn, portsock);
1226 return CURLE_FTP_PORT_FAILED;
1229 /* step 4, listen on the socket */
1231 if(listen(portsock, 1)) {
1232 failf(data, "socket failure: %s", Curl_strerror(conn, SOCKERRNO));
1233 Curl_closesocket(conn, portsock);
1234 return CURLE_FTP_PORT_FAILED;
1237 /* step 5, send the proper FTP command */
1239 /* get a plain printable version of the numerical address to work with
1241 Curl_printable_address(ai, myhost, sizeof(myhost));
1244 if(!conn->bits.ftp_use_eprt && conn->bits.ipv6)
1245 /* EPRT is disabled but we are connected to a IPv6 host, so we ignore the
1246 request and enable EPRT again! */
1247 conn->bits.ftp_use_eprt = TRUE;
1250 for(; fcmd != DONE; fcmd++) {
1252 if(!conn->bits.ftp_use_eprt && (EPRT == fcmd))
1253 /* if disabled, goto next */
1256 if((PORT == fcmd) && sa->sa_family != AF_INET)
1257 /* PORT is IPv4 only */
1260 switch(sa->sa_family) {
1262 port = ntohs(sa4->sin_port);
1266 port = ntohs(sa6->sin6_port);
1270 continue; /* might as well skip this */
1275 * Two fine examples from RFC2428;
1277 * EPRT |1|132.235.1.2|6275|
1279 * EPRT |2|1080::8:800:200C:417A|5282|
1282 result = Curl_pp_sendf(&ftpc->pp, "%s |%d|%s|%hu|", mode[fcmd],
1283 sa->sa_family == AF_INET?1:2,
1286 failf(data, "Failure sending EPRT command: %s",
1287 curl_easy_strerror(result));
1288 Curl_closesocket(conn, portsock);
1289 /* don't retry using PORT */
1290 ftpc->count1 = PORT;
1292 state(conn, FTP_STOP);
1297 else if(PORT == fcmd) {
1298 char *source = myhost;
1301 /* translate x.x.x.x to x,x,x,x */
1302 while(source && *source) {
1311 snprintf(dest, 20, ",%d,%d", (int)(port>>8), (int)(port&0xff));
1313 result = Curl_pp_sendf(&ftpc->pp, "%s %s", mode[fcmd], tmp);
1315 failf(data, "Failure sending PORT command: %s",
1316 curl_easy_strerror(result));
1317 Curl_closesocket(conn, portsock);
1319 state(conn, FTP_STOP);
1326 /* store which command was sent */
1327 ftpc->count1 = fcmd;
1329 /* we set the secondary socket variable to this for now, it is only so that
1330 the cleanup function will close it in case we fail before the true
1331 secondary stuff is made */
1332 if(CURL_SOCKET_BAD != conn->sock[SECONDARYSOCKET])
1333 Curl_closesocket(conn, conn->sock[SECONDARYSOCKET]);
1334 conn->sock[SECONDARYSOCKET] = portsock;
1336 /* this tcpconnect assignment below is a hackish work-around to make the
1337 multi interface with active FTP work - as it will not wait for a
1338 (passive) connect in Curl_is_connected().
1340 The *proper* fix is to make sure that the active connection from the
1341 server is done in a non-blocking way. Currently, it is still BLOCKING.
1343 conn->bits.tcpconnect[SECONDARYSOCKET] = TRUE;
1345 state(conn, FTP_PORT);
1349 static CURLcode ftp_state_use_pasv(struct connectdata *conn)
1351 struct ftp_conn *ftpc = &conn->proto.ftpc;
1352 CURLcode result = CURLE_OK;
1354 Here's the excecutive summary on what to do:
1356 PASV is RFC959, expect:
1357 227 Entering Passive Mode (a1,a2,a3,a4,p1,p2)
1359 LPSV is RFC1639, expect:
1360 228 Entering Long Passive Mode (4,4,a1,a2,a3,a4,2,p1,p2)
1362 EPSV is RFC2428, expect:
1363 229 Entering Extended Passive Mode (|||port|)
1367 static const char mode[][5] = { "EPSV", "PASV" };
1371 if(!conn->bits.ftp_use_epsv && conn->bits.ipv6)
1372 /* EPSV is disabled but we are connected to a IPv6 host, so we ignore the
1373 request and enable EPSV again! */
1374 conn->bits.ftp_use_epsv = TRUE;
1377 modeoff = conn->bits.ftp_use_epsv?0:1;
1379 PPSENDF(&ftpc->pp, "%s", mode[modeoff]);
1381 ftpc->count1 = modeoff;
1382 state(conn, FTP_PASV);
1383 infof(conn->data, "Connect data stream passively\n");
1389 * ftp_state_prepare_transfer() starts PORT, PASV or PRET etc.
1391 * REST is the last command in the chain of commands when a "head"-like
1392 * request is made. Thus, if an actual transfer is to be made this is where we
1393 * take off for real.
1395 static CURLcode ftp_state_prepare_transfer(struct connectdata *conn)
1397 CURLcode result = CURLE_OK;
1398 struct FTP *ftp = conn->data->req.protop;
1399 struct SessionHandle *data = conn->data;
1401 if(ftp->transfer != FTPTRANSFER_BODY) {
1402 /* doesn't transfer any data */
1404 /* still possibly do PRE QUOTE jobs */
1405 state(conn, FTP_RETR_PREQUOTE);
1406 result = ftp_state_quote(conn, TRUE, FTP_RETR_PREQUOTE);
1408 else if(data->set.ftp_use_port) {
1409 /* We have chosen to use the PORT (or similar) command */
1410 result = ftp_state_use_port(conn, EPRT);
1413 /* We have chosen (this is default) to use the PASV (or similar) command */
1414 if(data->set.ftp_use_pret) {
1415 /* The user has requested that we send a PRET command
1416 to prepare the server for the upcoming PASV */
1417 if(!conn->proto.ftpc.file) {
1418 PPSENDF(&conn->proto.ftpc.pp, "PRET %s",
1419 data->set.str[STRING_CUSTOMREQUEST]?
1420 data->set.str[STRING_CUSTOMREQUEST]:
1421 (data->set.ftp_list_only?"NLST":"LIST"));
1423 else if(data->set.upload) {
1424 PPSENDF(&conn->proto.ftpc.pp, "PRET STOR %s", conn->proto.ftpc.file);
1427 PPSENDF(&conn->proto.ftpc.pp, "PRET RETR %s", conn->proto.ftpc.file);
1429 state(conn, FTP_PRET);
1432 result = ftp_state_use_pasv(conn);
1438 static CURLcode ftp_state_rest(struct connectdata *conn)
1440 CURLcode result = CURLE_OK;
1441 struct FTP *ftp = conn->data->req.protop;
1442 struct ftp_conn *ftpc = &conn->proto.ftpc;
1444 if((ftp->transfer != FTPTRANSFER_BODY) && ftpc->file) {
1445 /* if a "head"-like request is being made (on a file) */
1447 /* Determine if server can respond to REST command and therefore
1448 whether it supports range */
1449 PPSENDF(&conn->proto.ftpc.pp, "REST %d", 0);
1451 state(conn, FTP_REST);
1454 result = ftp_state_prepare_transfer(conn);
1459 static CURLcode ftp_state_size(struct connectdata *conn)
1461 CURLcode result = CURLE_OK;
1462 struct FTP *ftp = conn->data->req.protop;
1463 struct ftp_conn *ftpc = &conn->proto.ftpc;
1465 if((ftp->transfer == FTPTRANSFER_INFO) && ftpc->file) {
1466 /* if a "head"-like request is being made (on a file) */
1468 /* we know ftpc->file is a valid pointer to a file name */
1469 PPSENDF(&ftpc->pp, "SIZE %s", ftpc->file);
1471 state(conn, FTP_SIZE);
1474 result = ftp_state_rest(conn);
1479 static CURLcode ftp_state_list(struct connectdata *conn)
1481 CURLcode result = CURLE_OK;
1482 struct SessionHandle *data = conn->data;
1484 /* If this output is to be machine-parsed, the NLST command might be better
1485 to use, since the LIST command output is not specified or standard in any
1486 way. It has turned out that the NLST list output is not the same on all
1487 servers either... */
1490 if FTPFILE_NOCWD was specified, we are currently in
1491 the user's home directory, so we should add the path
1492 as argument for the LIST / NLST / or custom command.
1493 Whether the server will support this, is uncertain.
1495 The other ftp_filemethods will CWD into dir/dir/ first and
1496 then just do LIST (in that case: nothing to do here)
1498 char *cmd,*lstArg,*slashPos;
1501 if((data->set.ftp_filemethod == FTPFILE_NOCWD) &&
1503 data->state.path[0] &&
1504 strchr(data->state.path,'/')) {
1506 lstArg = strdup(data->state.path);
1508 return CURLE_OUT_OF_MEMORY;
1510 /* Check if path does not end with /, as then we cut off the file part */
1511 if(lstArg[strlen(lstArg) - 1] != '/') {
1513 /* chop off the file part if format is dir/dir/file */
1514 slashPos = strrchr(lstArg,'/');
1516 *(slashPos+1) = '\0';
1520 cmd = aprintf( "%s%s%s",
1521 data->set.str[STRING_CUSTOMREQUEST]?
1522 data->set.str[STRING_CUSTOMREQUEST]:
1523 (data->set.ftp_list_only?"NLST":"LIST"),
1525 lstArg? lstArg: "" );
1530 return CURLE_OUT_OF_MEMORY;
1533 result = Curl_pp_sendf(&conn->proto.ftpc.pp, "%s", cmd);
1543 state(conn, FTP_LIST);
1548 static CURLcode ftp_state_retr_prequote(struct connectdata *conn)
1550 CURLcode result = CURLE_OK;
1552 /* We've sent the TYPE, now we must send the list of prequote strings */
1554 result = ftp_state_quote(conn, TRUE, FTP_RETR_PREQUOTE);
1559 static CURLcode ftp_state_stor_prequote(struct connectdata *conn)
1561 CURLcode result = CURLE_OK;
1563 /* We've sent the TYPE, now we must send the list of prequote strings */
1565 result = ftp_state_quote(conn, TRUE, FTP_STOR_PREQUOTE);
1570 static CURLcode ftp_state_type(struct connectdata *conn)
1572 CURLcode result = CURLE_OK;
1573 struct FTP *ftp = conn->data->req.protop;
1574 struct SessionHandle *data = conn->data;
1575 struct ftp_conn *ftpc = &conn->proto.ftpc;
1577 /* If we have selected NOBODY and HEADER, it means that we only want file
1578 information. Which in FTP can't be much more than the file size and
1580 if(data->set.opt_no_body && ftpc->file &&
1581 ftp_need_type(conn, data->set.prefer_ascii)) {
1582 /* The SIZE command is _not_ RFC 959 specified, and therefor many servers
1583 may not support it! It is however the only way we have to get a file's
1586 ftp->transfer = FTPTRANSFER_INFO;
1587 /* this means no actual transfer will be made */
1589 /* Some servers return different sizes for different modes, and thus we
1590 must set the proper type before we check the size */
1591 result = ftp_nb_type(conn, data->set.prefer_ascii, FTP_TYPE);
1596 result = ftp_state_size(conn);
1601 /* This is called after the CWD commands have been done in the beginning of
1603 static CURLcode ftp_state_mdtm(struct connectdata *conn)
1605 CURLcode result = CURLE_OK;
1606 struct SessionHandle *data = conn->data;
1607 struct ftp_conn *ftpc = &conn->proto.ftpc;
1609 /* Requested time of file or time-depended transfer? */
1610 if((data->set.get_filetime || data->set.timecondition) && ftpc->file) {
1612 /* we have requested to get the modified-time of the file, this is a white
1613 spot as the MDTM is not mentioned in RFC959 */
1614 PPSENDF(&ftpc->pp, "MDTM %s", ftpc->file);
1616 state(conn, FTP_MDTM);
1619 result = ftp_state_type(conn);
1625 /* This is called after the TYPE and possible quote commands have been sent */
1626 static CURLcode ftp_state_ul_setup(struct connectdata *conn,
1629 CURLcode result = CURLE_OK;
1630 struct FTP *ftp = conn->data->req.protop;
1631 struct SessionHandle *data = conn->data;
1632 struct ftp_conn *ftpc = &conn->proto.ftpc;
1633 int seekerr = CURL_SEEKFUNC_OK;
1635 if((data->state.resume_from && !sizechecked) ||
1636 ((data->state.resume_from > 0) && sizechecked)) {
1637 /* we're about to continue the uploading of a file */
1638 /* 1. get already existing file's size. We use the SIZE command for this
1639 which may not exist in the server! The SIZE command is not in
1642 /* 2. This used to set REST. But since we can do append, we
1643 don't another ftp command. We just skip the source file
1644 offset and then we APPEND the rest on the file instead */
1646 /* 3. pass file-size number of bytes in the source file */
1647 /* 4. lower the infilesize counter */
1648 /* => transfer as usual */
1650 if(data->state.resume_from < 0 ) {
1651 /* Got no given size to start from, figure it out */
1652 PPSENDF(&ftpc->pp, "SIZE %s", ftpc->file);
1653 state(conn, FTP_STOR_SIZE);
1658 data->set.ftp_append = TRUE;
1660 /* Let's read off the proper amount of bytes from the input. */
1661 if(conn->seek_func) {
1662 seekerr = conn->seek_func(conn->seek_client, data->state.resume_from,
1666 if(seekerr != CURL_SEEKFUNC_OK) {
1667 if(seekerr != CURL_SEEKFUNC_CANTSEEK) {
1668 failf(data, "Could not seek stream");
1669 return CURLE_FTP_COULDNT_USE_REST;
1671 /* seekerr == CURL_SEEKFUNC_CANTSEEK (can't seek to offset) */
1673 curl_off_t passed=0;
1675 size_t readthisamountnow =
1676 (data->state.resume_from - passed > CURL_OFF_T_C(BUFSIZE)) ?
1677 BUFSIZE : curlx_sotouz(data->state.resume_from - passed);
1679 size_t actuallyread =
1680 conn->fread_func(data->state.buffer, 1, readthisamountnow,
1683 passed += actuallyread;
1684 if((actuallyread == 0) || (actuallyread > readthisamountnow)) {
1685 /* this checks for greater-than only to make sure that the
1686 CURL_READFUNC_ABORT return code still aborts */
1687 failf(data, "Failed to read data");
1688 return CURLE_FTP_COULDNT_USE_REST;
1690 } while(passed < data->state.resume_from);
1693 /* now, decrease the size of the read */
1694 if(data->state.infilesize>0) {
1695 data->state.infilesize -= data->state.resume_from;
1697 if(data->state.infilesize <= 0) {
1698 infof(data, "File already completely uploaded\n");
1700 /* no data to transfer */
1701 Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
1703 /* Set ->transfer so that we won't get any error in
1704 * ftp_done() because we didn't transfer anything! */
1705 ftp->transfer = FTPTRANSFER_NONE;
1707 state(conn, FTP_STOP);
1711 /* we've passed, proceed as normal */
1714 PPSENDF(&ftpc->pp, data->set.ftp_append?"APPE %s":"STOR %s",
1717 state(conn, FTP_STOR);
1722 static CURLcode ftp_state_quote(struct connectdata *conn,
1726 CURLcode result = CURLE_OK;
1727 struct SessionHandle *data = conn->data;
1728 struct FTP *ftp = data->req.protop;
1729 struct ftp_conn *ftpc = &conn->proto.ftpc;
1731 struct curl_slist *item;
1736 item = data->set.quote;
1738 case FTP_RETR_PREQUOTE:
1739 case FTP_STOR_PREQUOTE:
1740 item = data->set.prequote;
1743 item = data->set.postquote;
1749 * 'count1' to iterate over the commands to send
1750 * 'count2' to store wether to allow commands to fail
1761 /* Skip count1 items in the linked list */
1762 while((i< ftpc->count1) && item) {
1767 char *cmd = item->data;
1770 ftpc->count2 = 1; /* the sent command is allowed to fail */
1773 ftpc->count2 = 0; /* failure means cancel operation */
1775 PPSENDF(&ftpc->pp, "%s", cmd);
1776 state(conn, instate);
1782 /* No more quote to send, continue to ... */
1786 result = ftp_state_cwd(conn);
1788 case FTP_RETR_PREQUOTE:
1789 if(ftp->transfer != FTPTRANSFER_BODY)
1790 state(conn, FTP_STOP);
1792 if(ftpc->known_filesize != -1) {
1793 Curl_pgrsSetDownloadSize(data, ftpc->known_filesize);
1794 result = ftp_state_retr(conn, ftpc->known_filesize);
1797 PPSENDF(&ftpc->pp, "SIZE %s", ftpc->file);
1798 state(conn, FTP_RETR_SIZE);
1802 case FTP_STOR_PREQUOTE:
1803 result = ftp_state_ul_setup(conn, FALSE);
1813 /* called from ftp_state_pasv_resp to switch to PASV in case of EPSV
1815 static CURLcode ftp_epsv_disable(struct connectdata *conn)
1817 CURLcode result = CURLE_OK;
1819 if(conn->bits.ipv6) {
1820 /* We can't disable EPSV when doing IPv6, so this is instead a fail */
1821 failf(conn->data, "Failed EPSV attempt, exiting\n");
1822 return CURLE_FTP_WEIRD_SERVER_REPLY;
1825 infof(conn->data, "Failed EPSV attempt. Disabling EPSV\n");
1826 /* disable it for next transfer */
1827 conn->bits.ftp_use_epsv = FALSE;
1828 conn->data->state.errorbuf = FALSE; /* allow error message to get
1830 PPSENDF(&conn->proto.ftpc.pp, "%s", "PASV");
1831 conn->proto.ftpc.count1++;
1832 /* remain in/go to the FTP_PASV state */
1833 state(conn, FTP_PASV);
1838 * Perform the necessary magic that needs to be done once the TCP connection
1839 * to the proxy has completed.
1841 static CURLcode proxy_magic(struct connectdata *conn,
1842 char *newhost, unsigned short newport,
1845 CURLcode result = CURLE_OK;
1846 struct SessionHandle *data = conn->data;
1848 #if defined(CURL_DISABLE_PROXY)
1855 switch(conn->proxytype) {
1856 case CURLPROXY_SOCKS5:
1857 case CURLPROXY_SOCKS5_HOSTNAME:
1858 result = Curl_SOCKS5(conn->proxyuser, conn->proxypasswd, newhost,
1859 newport, SECONDARYSOCKET, conn);
1862 case CURLPROXY_SOCKS4:
1863 result = Curl_SOCKS4(conn->proxyuser, newhost, newport,
1864 SECONDARYSOCKET, conn, FALSE);
1867 case CURLPROXY_SOCKS4A:
1868 result = Curl_SOCKS4(conn->proxyuser, newhost, newport,
1869 SECONDARYSOCKET, conn, TRUE);
1872 case CURLPROXY_HTTP:
1873 case CURLPROXY_HTTP_1_0:
1874 /* do nothing here. handled later. */
1877 failf(data, "unknown proxytype option given");
1878 result = CURLE_COULDNT_CONNECT;
1882 if(conn->bits.tunnel_proxy && conn->bits.httpproxy) {
1884 /* We want "seamless" FTP operations through HTTP proxy tunnel */
1886 /* Curl_proxyCONNECT is based on a pointer to a struct HTTP at the
1887 * member conn->proto.http; we want FTP through HTTP and we have to
1888 * change the member temporarily for connecting to the HTTP proxy. After
1889 * Curl_proxyCONNECT we have to set back the member to the original
1890 * struct FTP pointer
1892 struct HTTP http_proxy;
1893 struct FTP *ftp_save = data->req.protop;
1894 memset(&http_proxy, 0, sizeof(http_proxy));
1895 data->req.protop = &http_proxy;
1897 result = Curl_proxyCONNECT(conn, SECONDARYSOCKET, newhost, newport);
1899 data->req.protop = ftp_save;
1904 if(conn->tunnel_state[SECONDARYSOCKET] != TUNNEL_COMPLETE) {
1905 /* the CONNECT procedure is not complete, the tunnel is not yet up */
1906 state(conn, FTP_STOP); /* this phase is completed */
1916 static CURLcode ftp_state_pasv_resp(struct connectdata *conn,
1919 struct ftp_conn *ftpc = &conn->proto.ftpc;
1921 struct SessionHandle *data=conn->data;
1922 struct Curl_dns_entry *addr=NULL;
1924 unsigned short connectport; /* the local port connect() should use! */
1925 char *str=&data->state.buffer[4]; /* start on the first letter */
1927 /* if we come here again, make sure the former name is cleared */
1928 Curl_safefree(ftpc->newhost);
1930 if((ftpc->count1 == 0) &&
1932 /* positive EPSV response */
1933 char *ptr = strchr(str, '(');
1938 if(5 == sscanf(ptr, "%c%c%c%u%c",
1944 const char sep1 = separator[0];
1947 /* The four separators should be identical, or else this is an oddly
1948 formatted reply and we bail out immediately. */
1949 for(i=1; i<4; i++) {
1950 if(separator[i] != sep1) {
1951 ptr=NULL; /* set to NULL to signal error */
1956 failf(data, "Illegal port number in EPSV reply");
1957 return CURLE_FTP_WEIRD_PASV_REPLY;
1960 ftpc->newport = (unsigned short)(num & 0xffff);
1962 /* use the original host name again */
1963 ftpc->newhost = strdup(conn->host.name);
1965 return CURLE_OUT_OF_MEMORY;
1972 failf(data, "Weirdly formatted EPSV reply");
1973 return CURLE_FTP_WEIRD_PASV_REPLY;
1976 else if((ftpc->count1 == 1) &&
1978 /* positive PASV response */
1983 * Scan for a sequence of six comma-separated numbers and use them as
1984 * IP+port indicators.
1986 * Found reply-strings include:
1987 * "227 Entering Passive Mode (127,0,0,1,4,51)"
1988 * "227 Data transfer will passively listen to 127,0,0,1,4,51"
1989 * "227 Entering passive mode. 127,0,0,1,4,51"
1992 if(6 == sscanf(str, "%d,%d,%d,%d,%d,%d",
1993 &ip[0], &ip[1], &ip[2], &ip[3],
1994 &port[0], &port[1]))
2000 failf(data, "Couldn't interpret the 227-response");
2001 return CURLE_FTP_WEIRD_227_FORMAT;
2004 /* we got OK from server */
2005 if(data->set.ftp_skip_ip) {
2006 /* told to ignore the remotely given IP but instead use the host we used
2007 for the control connection */
2008 infof(data, "Skip %d.%d.%d.%d for data connection, re-use %s instead\n",
2009 ip[0], ip[1], ip[2], ip[3],
2012 /* use the original host name again */
2013 ftpc->newhost = strdup(conn->host.name);
2016 ftpc->newhost = aprintf("%d.%d.%d.%d", ip[0], ip[1], ip[2], ip[3]);
2019 return CURLE_OUT_OF_MEMORY;
2021 ftpc->newport = (unsigned short)(((port[0]<<8) + port[1]) & 0xffff);
2023 else if(ftpc->count1 == 0) {
2024 /* EPSV failed, move on to PASV */
2025 return ftp_epsv_disable(conn);
2028 failf(data, "Bad PASV/EPSV response: %03d", ftpcode);
2029 return CURLE_FTP_WEIRD_PASV_REPLY;
2032 if(conn->bits.proxy) {
2034 * This connection uses a proxy and we need to connect to the proxy again
2035 * here. We don't want to rely on a former host lookup that might've
2036 * expired now, instead we remake the lookup here and now!
2038 rc = Curl_resolv(conn, conn->proxy.name, (int)conn->port, &addr);
2039 if(rc == CURLRESOLV_PENDING)
2040 /* BLOCKING, ignores the return code but 'addr' will be NULL in
2042 (void)Curl_resolver_wait_resolv(conn, &addr);
2045 (unsigned short)conn->port; /* we connect to the proxy's port */
2048 failf(data, "Can't resolve proxy host %s:%hu",
2049 conn->proxy.name, connectport);
2050 return CURLE_FTP_CANT_GET_HOST;
2054 /* normal, direct, ftp connection */
2055 rc = Curl_resolv(conn, ftpc->newhost, ftpc->newport, &addr);
2056 if(rc == CURLRESOLV_PENDING)
2058 (void)Curl_resolver_wait_resolv(conn, &addr);
2060 connectport = ftpc->newport; /* we connect to the remote port */
2063 failf(data, "Can't resolve new host %s:%hu", ftpc->newhost, connectport);
2064 return CURLE_FTP_CANT_GET_HOST;
2068 conn->bits.tcpconnect[SECONDARYSOCKET] = FALSE;
2069 result = Curl_connecthost(conn, addr);
2071 Curl_resolv_unlock(data, addr); /* we're done using this address */
2074 if(ftpc->count1 == 0 && ftpcode == 229)
2075 return ftp_epsv_disable(conn);
2082 * When this is used from the multi interface, this might've returned with
2083 * the 'connected' set to FALSE and thus we are now awaiting a non-blocking
2084 * connect to connect.
2087 if(data->set.verbose)
2088 /* this just dumps information about this second connection */
2089 ftp_pasv_verbose(conn, conn->ip_addr, ftpc->newhost, connectport);
2091 conn->bits.do_more = TRUE;
2092 state(conn, FTP_STOP); /* this phase is completed */
2097 static CURLcode ftp_state_port_resp(struct connectdata *conn,
2100 struct SessionHandle *data = conn->data;
2101 struct ftp_conn *ftpc = &conn->proto.ftpc;
2102 ftpport fcmd = (ftpport)ftpc->count1;
2103 CURLcode result = CURLE_OK;
2105 if(ftpcode != 200) {
2106 /* the command failed */
2109 infof(data, "disabling EPRT usage\n");
2110 conn->bits.ftp_use_eprt = FALSE;
2115 failf(data, "Failed to do PORT");
2116 result = CURLE_FTP_PORT_FAILED;
2120 result = ftp_state_use_port(conn, fcmd);
2123 infof(data, "Connect data stream actively\n");
2124 state(conn, FTP_STOP); /* end of DO phase */
2125 result = ftp_dophase_done(conn, FALSE);
2131 static CURLcode ftp_state_mdtm_resp(struct connectdata *conn,
2134 CURLcode result = CURLE_OK;
2135 struct SessionHandle *data=conn->data;
2136 struct FTP *ftp = data->req.protop;
2137 struct ftp_conn *ftpc = &conn->proto.ftpc;
2142 /* we got a time. Format should be: "YYYYMMDDHHMMSS[.sss]" where the
2143 last .sss part is optional and means fractions of a second */
2144 int year, month, day, hour, minute, second;
2145 char *buf = data->state.buffer;
2146 if(6 == sscanf(buf+4, "%04d%02d%02d%02d%02d%02d",
2147 &year, &month, &day, &hour, &minute, &second)) {
2148 /* we have a time, reformat it */
2149 time_t secs=time(NULL);
2150 /* using the good old yacc/bison yuck */
2151 snprintf(buf, sizeof(conn->data->state.buffer),
2152 "%04d%02d%02d %02d:%02d:%02d GMT",
2153 year, month, day, hour, minute, second);
2154 /* now, convert this into a time() value: */
2155 data->info.filetime = (long)curl_getdate(buf, &secs);
2158 #ifdef CURL_FTP_HTTPSTYLE_HEAD
2159 /* If we asked for a time of the file and we actually got one as well,
2160 we "emulate" a HTTP-style header in our output. */
2162 if(data->set.opt_no_body &&
2164 data->set.get_filetime &&
2165 (data->info.filetime>=0) ) {
2166 time_t filetime = (time_t)data->info.filetime;
2168 const struct tm *tm = &buffer;
2170 result = Curl_gmtime(filetime, &buffer);
2174 /* format: "Tue, 15 Nov 1994 12:45:26" */
2175 snprintf(buf, BUFSIZE-1,
2176 "Last-Modified: %s, %02d %s %4d %02d:%02d:%02d GMT\r\n",
2177 Curl_wkday[tm->tm_wday?tm->tm_wday-1:6],
2179 Curl_month[tm->tm_mon],
2184 result = Curl_client_write(conn, CLIENTWRITE_BOTH, buf, 0);
2187 } /* end of a ridiculous amount of conditionals */
2192 infof(data, "unsupported MDTM reply format\n");
2194 case 550: /* "No such file or directory" */
2195 failf(data, "Given file does not exist");
2196 result = CURLE_FTP_COULDNT_RETR_FILE;
2200 if(data->set.timecondition) {
2201 if((data->info.filetime > 0) && (data->set.timevalue > 0)) {
2202 switch(data->set.timecondition) {
2203 case CURL_TIMECOND_IFMODSINCE:
2205 if(data->info.filetime <= data->set.timevalue) {
2206 infof(data, "The requested document is not new enough\n");
2207 ftp->transfer = FTPTRANSFER_NONE; /* mark to not transfer data */
2208 data->info.timecond = TRUE;
2209 state(conn, FTP_STOP);
2213 case CURL_TIMECOND_IFUNMODSINCE:
2214 if(data->info.filetime > data->set.timevalue) {
2215 infof(data, "The requested document is not old enough\n");
2216 ftp->transfer = FTPTRANSFER_NONE; /* mark to not transfer data */
2217 data->info.timecond = TRUE;
2218 state(conn, FTP_STOP);
2225 infof(data, "Skipping time comparison\n");
2230 result = ftp_state_type(conn);
2235 static CURLcode ftp_state_type_resp(struct connectdata *conn,
2239 CURLcode result = CURLE_OK;
2240 struct SessionHandle *data=conn->data;
2242 if(ftpcode/100 != 2) {
2243 /* "sasserftpd" and "(u)r(x)bot ftpd" both responds with 226 after a
2244 successful 'TYPE I'. While that is not as RFC959 says, it is still a
2245 positive response code and we allow that. */
2246 failf(data, "Couldn't set desired mode");
2247 return CURLE_FTP_COULDNT_SET_TYPE;
2250 infof(data, "Got a %03d response code instead of the assumed 200\n",
2253 if(instate == FTP_TYPE)
2254 result = ftp_state_size(conn);
2255 else if(instate == FTP_LIST_TYPE)
2256 result = ftp_state_list(conn);
2257 else if(instate == FTP_RETR_TYPE)
2258 result = ftp_state_retr_prequote(conn);
2259 else if(instate == FTP_STOR_TYPE)
2260 result = ftp_state_stor_prequote(conn);
2265 static CURLcode ftp_state_retr(struct connectdata *conn,
2266 curl_off_t filesize)
2268 CURLcode result = CURLE_OK;
2269 struct SessionHandle *data=conn->data;
2270 struct FTP *ftp = data->req.protop;
2271 struct ftp_conn *ftpc = &conn->proto.ftpc;
2273 if(data->set.max_filesize && (filesize > data->set.max_filesize)) {
2274 failf(data, "Maximum file size exceeded");
2275 return CURLE_FILESIZE_EXCEEDED;
2277 ftp->downloadsize = filesize;
2279 if(data->state.resume_from) {
2280 /* We always (attempt to) get the size of downloads, so it is done before
2281 this even when not doing resumes. */
2282 if(filesize == -1) {
2283 infof(data, "ftp server doesn't support SIZE\n");
2284 /* We couldn't get the size and therefore we can't know if there really
2285 is a part of the file left to get, although the server will just
2286 close the connection when we start the connection so it won't cause
2287 us any harm, just not make us exit as nicely. */
2290 /* We got a file size report, so we check that there actually is a
2291 part of the file left to get, or else we go home. */
2292 if(data->state.resume_from< 0) {
2293 /* We're supposed to download the last abs(from) bytes */
2294 if(filesize < -data->state.resume_from) {
2295 failf(data, "Offset (%" CURL_FORMAT_CURL_OFF_T
2296 ") was beyond file size (%" CURL_FORMAT_CURL_OFF_T ")",
2297 data->state.resume_from, filesize);
2298 return CURLE_BAD_DOWNLOAD_RESUME;
2300 /* convert to size to download */
2301 ftp->downloadsize = -data->state.resume_from;
2302 /* download from where? */
2303 data->state.resume_from = filesize - ftp->downloadsize;
2306 if(filesize < data->state.resume_from) {
2307 failf(data, "Offset (%" CURL_FORMAT_CURL_OFF_T
2308 ") was beyond file size (%" CURL_FORMAT_CURL_OFF_T ")",
2309 data->state.resume_from, filesize);
2310 return CURLE_BAD_DOWNLOAD_RESUME;
2312 /* Now store the number of bytes we are expected to download */
2313 ftp->downloadsize = filesize-data->state.resume_from;
2317 if(ftp->downloadsize == 0) {
2318 /* no data to transfer */
2319 Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
2320 infof(data, "File already completely downloaded\n");
2322 /* Set ->transfer so that we won't get any error in ftp_done()
2323 * because we didn't transfer the any file */
2324 ftp->transfer = FTPTRANSFER_NONE;
2325 state(conn, FTP_STOP);
2329 /* Set resume file transfer offset */
2330 infof(data, "Instructs server to resume from offset %"
2331 CURL_FORMAT_CURL_OFF_T "\n", data->state.resume_from);
2333 PPSENDF(&ftpc->pp, "REST %" CURL_FORMAT_CURL_OFF_T,
2334 data->state.resume_from);
2336 state(conn, FTP_RETR_REST);
2340 PPSENDF(&ftpc->pp, "RETR %s", ftpc->file);
2341 state(conn, FTP_RETR);
2347 static CURLcode ftp_state_size_resp(struct connectdata *conn,
2351 CURLcode result = CURLE_OK;
2352 struct SessionHandle *data=conn->data;
2353 curl_off_t filesize;
2354 char *buf = data->state.buffer;
2356 /* get the size from the ascii string: */
2357 filesize = (ftpcode == 213)?curlx_strtoofft(buf+4, NULL, 0):-1;
2359 if(instate == FTP_SIZE) {
2360 #ifdef CURL_FTP_HTTPSTYLE_HEAD
2361 if(-1 != filesize) {
2362 snprintf(buf, sizeof(data->state.buffer),
2363 "Content-Length: %" CURL_FORMAT_CURL_OFF_T "\r\n", filesize);
2364 result = Curl_client_write(conn, CLIENTWRITE_BOTH, buf, 0);
2369 Curl_pgrsSetDownloadSize(data, filesize);
2370 result = ftp_state_rest(conn);
2372 else if(instate == FTP_RETR_SIZE) {
2373 Curl_pgrsSetDownloadSize(data, filesize);
2374 result = ftp_state_retr(conn, filesize);
2376 else if(instate == FTP_STOR_SIZE) {
2377 data->state.resume_from = filesize;
2378 result = ftp_state_ul_setup(conn, TRUE);
2384 static CURLcode ftp_state_rest_resp(struct connectdata *conn,
2388 CURLcode result = CURLE_OK;
2389 struct ftp_conn *ftpc = &conn->proto.ftpc;
2394 #ifdef CURL_FTP_HTTPSTYLE_HEAD
2395 if(ftpcode == 350) {
2396 char buffer[24]= { "Accept-ranges: bytes\r\n" };
2397 result = Curl_client_write(conn, CLIENTWRITE_BOTH, buffer, 0);
2402 result = ftp_state_prepare_transfer(conn);
2406 if(ftpcode != 350) {
2407 failf(conn->data, "Couldn't use REST");
2408 result = CURLE_FTP_COULDNT_USE_REST;
2411 PPSENDF(&ftpc->pp, "RETR %s", ftpc->file);
2412 state(conn, FTP_RETR);
2420 static CURLcode ftp_state_stor_resp(struct connectdata *conn,
2421 int ftpcode, ftpstate instate)
2423 CURLcode result = CURLE_OK;
2424 struct SessionHandle *data = conn->data;
2427 failf(data, "Failed FTP upload: %0d", ftpcode);
2428 state(conn, FTP_STOP);
2429 /* oops, we never close the sockets! */
2430 return CURLE_UPLOAD_FAILED;
2433 conn->proto.ftpc.state_saved = instate;
2435 /* PORT means we are now awaiting the server to connect to us. */
2436 if(data->set.ftp_use_port) {
2439 state(conn, FTP_STOP); /* no longer in STOR state */
2441 result = AllowServerConnect(conn, &connected);
2446 struct ftp_conn *ftpc = &conn->proto.ftpc;
2447 infof(data, "Data conn was not available immediately\n");
2448 ftpc->wait_data_conn = TRUE;
2454 return InitiateTransfer(conn);
2457 /* for LIST and RETR responses */
2458 static CURLcode ftp_state_get_resp(struct connectdata *conn,
2462 CURLcode result = CURLE_OK;
2463 struct SessionHandle *data = conn->data;
2464 struct FTP *ftp = data->req.protop;
2465 char *buf = data->state.buffer;
2467 if((ftpcode == 150) || (ftpcode == 125)) {
2471 150 Opening BINARY mode data connection for /etc/passwd (2241
2472 bytes). (ok, the file is being transferred)
2475 150 Opening ASCII mode data connection for /bin/ls
2478 150 ASCII data connection for /bin/ls (137.167.104.91,37445) (0 bytes).
2481 150 Opening ASCII mode data connection for [file] (0.0.0.0,0) (545 bytes)
2484 125 Data connection already open; Transfer starting. */
2486 curl_off_t size=-1; /* default unknown size */
2490 * It appears that there are FTP-servers that return size 0 for files when
2491 * SIZE is used on the file while being in BINARY mode. To work around
2492 * that (stupid) behavior, we attempt to parse the RETR response even if
2493 * the SIZE returned size zero.
2495 * Debugging help from Salvatore Sorrentino on February 26, 2003.
2498 if((instate != FTP_LIST) &&
2499 !data->set.prefer_ascii &&
2500 (ftp->downloadsize < 1)) {
2502 * It seems directory listings either don't show the size or very
2503 * often uses size 0 anyway. ASCII transfers may very well turn out
2504 * that the transferred amount of data is not the same as this line
2505 * tells, why using this number in those cases only confuses us.
2507 * Example D above makes this parsing a little tricky */
2509 bytes=strstr(buf, " bytes");
2511 long in=(long)(bytes-buf);
2512 /* this is a hint there is size information in there! ;-) */
2514 /* scan for the left parenthesis and break there */
2517 /* skip only digits */
2518 if(!ISDIGIT(*bytes)) {
2522 /* one more estep backwards */
2525 /* if we have nothing but digits: */
2527 /* get the number! */
2528 size = curlx_strtoofft(bytes, NULL, 0);
2532 else if(ftp->downloadsize > -1)
2533 size = ftp->downloadsize;
2535 if(size > data->req.maxdownload && data->req.maxdownload > 0)
2536 size = data->req.size = data->req.maxdownload;
2537 else if((instate != FTP_LIST) && (data->set.prefer_ascii))
2538 size = -1; /* kludge for servers that understate ASCII mode file size */
2540 infof(data, "Maxdownload = %" CURL_FORMAT_CURL_OFF_T "\n",
2541 data->req.maxdownload);
2543 if(instate != FTP_LIST)
2544 infof(data, "Getting file with size: %" CURL_FORMAT_CURL_OFF_T "\n",
2548 conn->proto.ftpc.state_saved = instate;
2549 conn->proto.ftpc.retr_size_saved = size;
2551 if(data->set.ftp_use_port) {
2554 result = AllowServerConnect(conn, &connected);
2559 struct ftp_conn *ftpc = &conn->proto.ftpc;
2560 infof(data, "Data conn was not available immediately\n");
2561 state(conn, FTP_STOP);
2562 ftpc->wait_data_conn = TRUE;
2566 return InitiateTransfer(conn);
2569 if((instate == FTP_LIST) && (ftpcode == 450)) {
2570 /* simply no matching files in the dir listing */
2571 ftp->transfer = FTPTRANSFER_NONE; /* don't download anything */
2572 state(conn, FTP_STOP); /* this phase is over */
2575 failf(data, "RETR response: %03d", ftpcode);
2576 return instate == FTP_RETR && ftpcode == 550?
2577 CURLE_REMOTE_FILE_NOT_FOUND:
2578 CURLE_FTP_COULDNT_RETR_FILE;
2585 /* after USER, PASS and ACCT */
2586 static CURLcode ftp_state_loggedin(struct connectdata *conn)
2588 CURLcode result = CURLE_OK;
2590 if(conn->ssl[FIRSTSOCKET].use) {
2591 /* PBSZ = PROTECTION BUFFER SIZE.
2593 The 'draft-murray-auth-ftp-ssl' (draft 12, page 7) says:
2595 Specifically, the PROT command MUST be preceded by a PBSZ
2596 command and a PBSZ command MUST be preceded by a successful
2597 security data exchange (the TLS negotiation in this case)
2599 ... (and on page 8):
2601 Thus the PBSZ command must still be issued, but must have a
2602 parameter of '0' to indicate that no buffering is taking place
2603 and the data connection should not be encapsulated.
2605 PPSENDF(&conn->proto.ftpc.pp, "PBSZ %d", 0);
2606 state(conn, FTP_PBSZ);
2609 result = ftp_state_pwd(conn);
2614 /* for USER and PASS responses */
2615 static CURLcode ftp_state_user_resp(struct connectdata *conn,
2619 CURLcode result = CURLE_OK;
2620 struct SessionHandle *data = conn->data;
2621 struct FTP *ftp = data->req.protop;
2622 struct ftp_conn *ftpc = &conn->proto.ftpc;
2623 (void)instate; /* no use for this yet */
2625 /* some need password anyway, and others just return 2xx ignored */
2626 if((ftpcode == 331) && (ftpc->state == FTP_USER)) {
2627 /* 331 Password required for ...
2628 (the server requires to send the user's password too) */
2629 PPSENDF(&ftpc->pp, "PASS %s", ftp->passwd?ftp->passwd:"");
2630 state(conn, FTP_PASS);
2632 else if(ftpcode/100 == 2) {
2633 /* 230 User ... logged in.
2634 (the user logged in with or without password) */
2635 result = ftp_state_loggedin(conn);
2637 else if(ftpcode == 332) {
2638 if(data->set.str[STRING_FTP_ACCOUNT]) {
2639 PPSENDF(&ftpc->pp, "ACCT %s", data->set.str[STRING_FTP_ACCOUNT]);
2640 state(conn, FTP_ACCT);
2643 failf(data, "ACCT requested but none available");
2644 result = CURLE_LOGIN_DENIED;
2648 /* All other response codes, like:
2650 530 User ... access denied
2651 (the server denies to log the specified user) */
2653 if(conn->data->set.str[STRING_FTP_ALTERNATIVE_TO_USER] &&
2654 !conn->data->state.ftp_trying_alternative) {
2655 /* Ok, USER failed. Let's try the supplied command. */
2656 PPSENDF(&conn->proto.ftpc.pp, "%s",
2657 conn->data->set.str[STRING_FTP_ALTERNATIVE_TO_USER]);
2658 conn->data->state.ftp_trying_alternative = TRUE;
2659 state(conn, FTP_USER);
2663 failf(data, "Access denied: %03d", ftpcode);
2664 result = CURLE_LOGIN_DENIED;
2670 /* for ACCT response */
2671 static CURLcode ftp_state_acct_resp(struct connectdata *conn,
2674 CURLcode result = CURLE_OK;
2675 struct SessionHandle *data = conn->data;
2676 if(ftpcode != 230) {
2677 failf(data, "ACCT rejected by server: %03d", ftpcode);
2678 result = CURLE_FTP_WEIRD_PASS_REPLY; /* FIX */
2681 result = ftp_state_loggedin(conn);
2687 static CURLcode ftp_statemach_act(struct connectdata *conn)
2690 curl_socket_t sock = conn->sock[FIRSTSOCKET];
2691 struct SessionHandle *data=conn->data;
2693 struct ftp_conn *ftpc = &conn->proto.ftpc;
2694 struct pingpong *pp = &ftpc->pp;
2695 static const char ftpauth[][4] = { "SSL", "TLS" };
2699 return Curl_pp_flushsend(pp);
2701 result = ftp_readresp(sock, pp, &ftpcode, &nread);
2706 /* we have now received a full FTP server response */
2707 switch(ftpc->state) {
2710 /* 230 User logged in - already! */
2711 return ftp_state_user_resp(conn, ftpcode, ftpc->state);
2712 else if(ftpcode != 220) {
2713 failf(data, "Got a %03d ftp-server response when 220 was expected",
2715 return CURLE_FTP_WEIRD_SERVER_REPLY;
2718 /* We have received a 220 response fine, now we proceed. */
2721 /* If not anonymous login, try a secure login. Note that this
2722 procedure is still BLOCKING. */
2724 Curl_sec_request_prot(conn, "private");
2725 /* We set private first as default, in case the line below fails to
2726 set a valid level */
2727 Curl_sec_request_prot(conn, data->set.str[STRING_KRB_LEVEL]);
2729 if(Curl_sec_login(conn))
2730 infof(data, "Logging in with password in cleartext!\n");
2732 infof(data, "Authentication successful\n");
2736 if(data->set.use_ssl && !conn->ssl[FIRSTSOCKET].use) {
2737 /* We don't have a SSL/TLS connection yet, but FTPS is
2738 requested. Try a FTPS connection now */
2741 switch(data->set.ftpsslauth) {
2742 case CURLFTPAUTH_DEFAULT:
2743 case CURLFTPAUTH_SSL:
2744 ftpc->count2 = 1; /* add one to get next */
2747 case CURLFTPAUTH_TLS:
2748 ftpc->count2 = -1; /* subtract one to get next */
2752 failf(data, "unsupported parameter to CURLOPT_FTPSSLAUTH: %d",
2753 (int)data->set.ftpsslauth);
2754 return CURLE_UNKNOWN_OPTION; /* we don't know what to do */
2756 PPSENDF(&ftpc->pp, "AUTH %s", ftpauth[ftpc->count1]);
2757 state(conn, FTP_AUTH);
2760 result = ftp_state_user(conn);
2768 /* we have gotten the response to a previous AUTH command */
2770 /* RFC2228 (page 5) says:
2772 * If the server is willing to accept the named security mechanism,
2773 * and does not require any security data, it must respond with
2774 * reply code 234/334.
2777 if((ftpcode == 234) || (ftpcode == 334)) {
2778 /* Curl_ssl_connect is BLOCKING */
2779 result = Curl_ssl_connect(conn, FIRSTSOCKET);
2781 conn->ssl[SECONDARYSOCKET].use = FALSE; /* clear-text data */
2782 result = ftp_state_user(conn);
2785 else if(ftpc->count3 < 1) {
2787 ftpc->count1 += ftpc->count2; /* get next attempt */
2788 result = Curl_pp_sendf(&ftpc->pp, "AUTH %s", ftpauth[ftpc->count1]);
2789 /* remain in this same state */
2792 if(data->set.use_ssl > CURLUSESSL_TRY)
2793 /* we failed and CURLUSESSL_CONTROL or CURLUSESSL_ALL is set */
2794 result = CURLE_USE_SSL_FAILED;
2796 /* ignore the failure and continue */
2797 result = ftp_state_user(conn);
2806 result = ftp_state_user_resp(conn, ftpcode, ftpc->state);
2810 result = ftp_state_acct_resp(conn, ftpcode);
2814 PPSENDF(&ftpc->pp, "PROT %c",
2815 data->set.use_ssl == CURLUSESSL_CONTROL ? 'C' : 'P');
2816 state(conn, FTP_PROT);
2821 if(ftpcode/100 == 2)
2822 /* We have enabled SSL for the data connection! */
2823 conn->ssl[SECONDARYSOCKET].use =
2824 (data->set.use_ssl != CURLUSESSL_CONTROL) ? TRUE : FALSE;
2825 /* FTP servers typically responds with 500 if they decide to reject
2827 else if(data->set.use_ssl > CURLUSESSL_CONTROL)
2828 /* we failed and bails out */
2829 return CURLE_USE_SSL_FAILED;
2831 if(data->set.ftp_ccc) {
2832 /* CCC - Clear Command Channel
2834 PPSENDF(&ftpc->pp, "%s", "CCC");
2835 state(conn, FTP_CCC);
2838 result = ftp_state_pwd(conn);
2846 /* First shut down the SSL layer (note: this call will block) */
2847 result = Curl_ssl_shutdown(conn, FIRSTSOCKET);
2850 failf(conn->data, "Failed to clear the command channel (CCC)");
2855 /* Then continue as normal */
2856 result = ftp_state_pwd(conn);
2862 if(ftpcode == 257) {
2863 char *ptr=&data->state.buffer[4]; /* start on the first letter */
2867 dir = malloc(nread + 1);
2869 return CURLE_OUT_OF_MEMORY;
2871 /* Reply format is like
2872 257<space>[rubbish]"<directory-name>"<space><commentary> and the
2875 The directory name can contain any character; embedded
2876 double-quotes should be escaped by double-quotes (the
2877 "quote-doubling" convention).
2880 /* scan for the first double-quote for non-standard responses */
2881 while(ptr < &data->state.buffer[sizeof(data->state.buffer)]
2882 && *ptr != '\n' && *ptr != '\0' && *ptr != '"')
2886 /* it started good */
2888 for(store = dir; *ptr;) {
2890 if('\"' == ptr[1]) {
2891 /* "quote-doubling" */
2897 *store = '\0'; /* zero terminate */
2898 break; /* get out of this loop */
2907 /* If the path name does not look like an absolute path (i.e.: it
2908 does not start with a '/'), we probably need some server-dependent
2909 adjustments. For example, this is the case when connecting to
2910 an OS400 FTP server: this server supports two name syntaxes,
2911 the default one being incompatible with standard pathes. In
2912 addition, this server switches automatically to the regular path
2913 syntax when one is encountered in a command: this results in
2914 having an entrypath in the wrong syntax when later used in CWD.
2915 The method used here is to check the server OS: we do it only
2916 if the path name looks strange to minimize overhead on other
2919 if(!ftpc->server_os && dir[0] != '/') {
2921 result = Curl_pp_sendf(&ftpc->pp, "%s", "SYST");
2926 Curl_safefree(ftpc->entrypath);
2927 ftpc->entrypath = dir; /* remember this */
2928 infof(data, "Entry path is '%s'\n", ftpc->entrypath);
2929 /* also save it where getinfo can access it: */
2930 data->state.most_recent_ftp_entrypath = ftpc->entrypath;
2931 state(conn, FTP_SYST);
2935 Curl_safefree(ftpc->entrypath);
2936 ftpc->entrypath = dir; /* remember this */
2937 infof(data, "Entry path is '%s'\n", ftpc->entrypath);
2938 /* also save it where getinfo can access it: */
2939 data->state.most_recent_ftp_entrypath = ftpc->entrypath;
2942 /* couldn't get the path */
2944 infof(data, "Failed to figure out path\n");
2947 state(conn, FTP_STOP); /* we are done with the CONNECT phase! */
2948 DEBUGF(infof(data, "protocol connect phase DONE\n"));
2952 if(ftpcode == 215) {
2953 char *ptr=&data->state.buffer[4]; /* start on the first letter */
2957 os = malloc(nread + 1);
2959 return CURLE_OUT_OF_MEMORY;
2961 /* Reply format is like
2962 215<space><OS-name><space><commentary>
2966 for(store = os; *ptr && *ptr != ' ';)
2968 *store = '\0'; /* zero terminate */
2970 /* Check for special servers here. */
2972 if(strequal(os, "OS/400")) {
2973 /* Force OS400 name format 1. */
2974 result = Curl_pp_sendf(&ftpc->pp, "%s", "SITE NAMEFMT 1");
2979 /* remember target server OS */
2980 Curl_safefree(ftpc->server_os);
2981 ftpc->server_os = os;
2982 state(conn, FTP_NAMEFMT);
2986 /* Nothing special for the target server. */
2987 /* remember target server OS */
2988 Curl_safefree(ftpc->server_os);
2989 ftpc->server_os = os;
2993 /* Cannot identify server OS. Continue anyway and cross fingers. */
2996 state(conn, FTP_STOP); /* we are done with the CONNECT phase! */
2997 DEBUGF(infof(data, "protocol connect phase DONE\n"));
3001 if(ftpcode == 250) {
3002 /* Name format change successful: reload initial path. */
3003 ftp_state_pwd(conn);
3007 state(conn, FTP_STOP); /* we are done with the CONNECT phase! */
3008 DEBUGF(infof(data, "protocol connect phase DONE\n"));
3013 case FTP_RETR_PREQUOTE:
3014 case FTP_STOR_PREQUOTE:
3015 if((ftpcode >= 400) && !ftpc->count2) {
3016 /* failure response code, and not allowed to fail */
3017 failf(conn->data, "QUOT command failed with %03d", ftpcode);
3018 return CURLE_QUOTE_ERROR;
3020 result = ftp_state_quote(conn, FALSE, ftpc->state);
3027 if(ftpcode/100 != 2) {
3028 /* failure to CWD there */
3029 if(conn->data->set.ftp_create_missing_dirs &&
3030 ftpc->count1 && !ftpc->count2) {
3032 ftpc->count2++; /* counter to prevent CWD-MKD loops */
3033 PPSENDF(&ftpc->pp, "MKD %s", ftpc->dirs[ftpc->count1 - 1]);
3034 state(conn, FTP_MKD);
3037 /* return failure */
3038 failf(data, "Server denied you to change to the given directory");
3039 ftpc->cwdfail = TRUE; /* don't remember this path as we failed
3041 return CURLE_REMOTE_ACCESS_DENIED;
3047 if(++ftpc->count1 <= ftpc->dirdepth) {
3049 PPSENDF(&ftpc->pp, "CWD %s", ftpc->dirs[ftpc->count1 - 1]);
3052 result = ftp_state_mdtm(conn);
3060 if((ftpcode/100 != 2) && !ftpc->count3--) {
3061 /* failure to MKD the dir */
3062 failf(data, "Failed to MKD dir: %03d", ftpcode);
3063 return CURLE_REMOTE_ACCESS_DENIED;
3065 state(conn, FTP_CWD);
3067 PPSENDF(&ftpc->pp, "CWD %s", ftpc->dirs[ftpc->count1 - 1]);
3071 result = ftp_state_mdtm_resp(conn, ftpcode);
3078 result = ftp_state_type_resp(conn, ftpcode, ftpc->state);
3084 result = ftp_state_size_resp(conn, ftpcode, ftpc->state);
3089 result = ftp_state_rest_resp(conn, ftpcode, ftpc->state);
3093 if(ftpcode != 200) {
3094 /* there only is this one standard OK return code. */
3095 failf(data, "PRET command not accepted: %03d", ftpcode);
3096 return CURLE_FTP_PRET_FAILED;
3098 result = ftp_state_use_pasv(conn);
3102 result = ftp_state_pasv_resp(conn, ftpcode);
3106 result = ftp_state_port_resp(conn, ftpcode);
3111 result = ftp_state_get_resp(conn, ftpcode, ftpc->state);
3115 result = ftp_state_stor_resp(conn, ftpcode, ftpc->state);
3119 /* fallthrough, just stop! */
3121 /* internal error */
3122 state(conn, FTP_STOP);
3131 /* called repeatedly until done from multi.c */
3132 static CURLcode ftp_multi_statemach(struct connectdata *conn,
3135 struct ftp_conn *ftpc = &conn->proto.ftpc;
3136 CURLcode result = Curl_pp_statemach(&ftpc->pp, FALSE);
3138 /* Check for the state outside of the Curl_socket_ready() return code checks
3139 since at times we are in fact already in this state when this function
3141 *done = (ftpc->state == FTP_STOP) ? TRUE : FALSE;
3146 static CURLcode ftp_block_statemach(struct connectdata *conn)
3148 struct ftp_conn *ftpc = &conn->proto.ftpc;
3149 struct pingpong *pp = &ftpc->pp;
3150 CURLcode result = CURLE_OK;
3152 while(ftpc->state != FTP_STOP) {
3153 result = Curl_pp_statemach(pp, TRUE);
3162 * ftp_connect() should do everything that is to be considered a part of
3163 * the connection phase.
3165 * The variable 'done' points to will be TRUE if the protocol-layer connect
3166 * phase is done when this function returns, or FALSE if not.
3169 static CURLcode ftp_connect(struct connectdata *conn,
3170 bool *done) /* see description above */
3173 struct ftp_conn *ftpc = &conn->proto.ftpc;
3174 struct pingpong *pp = &ftpc->pp;
3176 *done = FALSE; /* default to not done yet */
3178 /* We always support persistent connections on ftp */
3179 connkeep(conn, "FTP default");
3181 pp->response_time = RESP_TIMEOUT; /* set default response time-out */
3182 pp->statemach_act = ftp_statemach_act;
3183 pp->endofresp = ftp_endofresp;
3186 if(conn->handler->flags & PROTOPT_SSL) {
3188 result = Curl_ssl_connect(conn, FIRSTSOCKET);
3193 Curl_pp_init(pp); /* init the generic pingpong data */
3195 /* When we connect, we start in the state where we await the 220
3197 state(conn, FTP_WAIT220);
3199 result = ftp_multi_statemach(conn, done);
3204 /***********************************************************************
3208 * The DONE function. This does what needs to be done after a single DO has
3211 * Input argument is already checked for validity.
3213 static CURLcode ftp_done(struct connectdata *conn, CURLcode status,
3216 struct SessionHandle *data = conn->data;
3217 struct FTP *ftp = data->req.protop;
3218 struct ftp_conn *ftpc = &conn->proto.ftpc;
3219 struct pingpong *pp = &ftpc->pp;
3222 CURLcode result = CURLE_OK;
3223 bool was_ctl_valid = ftpc->ctl_valid;
3225 const char *path_to_use = data->state.path;
3228 /* When the easy handle is removed from the multi while libcurl is still
3229 * trying to resolve the host name, it seems that the ftp struct is not
3230 * yet initialized, but the removal action calls Curl_done() which calls
3231 * this function. So we simply return success if no ftp pointer is set.
3236 case CURLE_BAD_DOWNLOAD_RESUME:
3237 case CURLE_FTP_WEIRD_PASV_REPLY:
3238 case CURLE_FTP_PORT_FAILED:
3239 case CURLE_FTP_ACCEPT_FAILED:
3240 case CURLE_FTP_ACCEPT_TIMEOUT:
3241 case CURLE_FTP_COULDNT_SET_TYPE:
3242 case CURLE_FTP_COULDNT_RETR_FILE:
3243 case CURLE_PARTIAL_FILE:
3244 case CURLE_UPLOAD_FAILED:
3245 case CURLE_REMOTE_ACCESS_DENIED:
3246 case CURLE_FILESIZE_EXCEEDED:
3247 case CURLE_REMOTE_FILE_NOT_FOUND:
3248 case CURLE_WRITE_ERROR:
3249 /* the connection stays alive fine even though this happened */
3251 case CURLE_OK: /* doesn't affect the control connection's status */
3253 ftpc->ctl_valid = was_ctl_valid;
3256 /* until we cope better with prematurely ended requests, let them
3257 * fallback as if in complete failure */
3258 default: /* by default, an error means the control connection is
3259 wedged and should not be used anymore */
3260 ftpc->ctl_valid = FALSE;
3261 ftpc->cwdfail = TRUE; /* set this TRUE to prevent us to remember the
3262 current path, as this connection is going */
3263 connclose(conn, "FTP ended with bad error code");
3264 result = status; /* use the already set error code */
3268 /* now store a copy of the directory we are in */
3270 free(ftpc->prevpath);
3272 if(data->set.wildcardmatch) {
3273 if(data->set.chunk_end && ftpc->file) {
3274 data->set.chunk_end(data->wildcard.customptr);
3276 ftpc->known_filesize = -1;
3279 /* get the "raw" path */
3280 path = curl_easy_unescape(data, path_to_use, 0, NULL);
3282 /* out of memory, but we can limp along anyway (and should try to
3283 * since we may already be in the out of memory cleanup path) */
3285 result = CURLE_OUT_OF_MEMORY;
3286 ftpc->ctl_valid = FALSE; /* mark control connection as bad */
3287 connclose(conn, "FTP: out of memory!"); /* mark for connection closure */
3288 ftpc->prevpath = NULL; /* no path remembering */
3291 size_t flen = ftpc->file?strlen(ftpc->file):0; /* file is "raw" already */
3292 size_t dlen = strlen(path)-flen;
3293 if(!ftpc->cwdfail) {
3294 if(dlen && (data->set.ftp_filemethod != FTPFILE_NOCWD)) {
3295 ftpc->prevpath = path;
3297 /* if 'path' is not the whole string */
3298 ftpc->prevpath[dlen]=0; /* terminate */
3301 /* we never changed dir */
3302 ftpc->prevpath=strdup("");
3306 infof(data, "Remembering we are in dir \"%s\"\n", ftpc->prevpath);
3309 ftpc->prevpath = NULL; /* no path */
3313 /* free the dir tree and file parts */
3316 /* shut down the socket to inform the server we're done */
3319 shutdown(conn->sock[SECONDARYSOCKET],2); /* SD_BOTH */
3322 if(conn->sock[SECONDARYSOCKET] != CURL_SOCKET_BAD) {
3323 if(!result && ftpc->dont_check && data->req.maxdownload > 0) {
3324 /* partial download completed */
3325 result = Curl_pp_sendf(pp, "%s", "ABOR");
3327 failf(data, "Failure sending ABOR command: %s",
3328 curl_easy_strerror(result));
3329 ftpc->ctl_valid = FALSE; /* mark control connection as bad */
3330 connclose(conn, "ABOR command failed"); /* connection closure */
3334 if(conn->ssl[SECONDARYSOCKET].use) {
3335 /* The secondary socket is using SSL so we must close down that part
3336 first before we close the socket for real */
3337 Curl_ssl_close(conn, SECONDARYSOCKET);
3339 /* Note that we keep "use" set to TRUE since that (next) connection is
3340 still requested to use SSL */
3342 if(CURL_SOCKET_BAD != conn->sock[SECONDARYSOCKET]) {
3343 Curl_closesocket(conn, conn->sock[SECONDARYSOCKET]);
3344 conn->sock[SECONDARYSOCKET] = CURL_SOCKET_BAD;
3345 conn->bits.tcpconnect[SECONDARYSOCKET] = FALSE;
3349 if(!result && (ftp->transfer == FTPTRANSFER_BODY) && ftpc->ctl_valid &&
3350 pp->pending_resp && !premature) {
3352 * Let's see what the server says about the transfer we just performed,
3353 * but lower the timeout as sometimes this connection has died while the
3354 * data has been transferred. This happens when doing through NATs etc that
3355 * abandon old silent connections.
3357 long old_time = pp->response_time;
3359 pp->response_time = 60*1000; /* give it only a minute for now */
3360 pp->response = Curl_tvnow(); /* timeout relative now */
3362 result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
3364 pp->response_time = old_time; /* set this back to previous value */
3366 if(!nread && (CURLE_OPERATION_TIMEDOUT == result)) {
3367 failf(data, "control connection looks dead");
3368 ftpc->ctl_valid = FALSE; /* mark control connection as bad */
3369 connclose(conn, "Timeout or similar in FTP DONE operation"); /* close */
3375 if(ftpc->dont_check && data->req.maxdownload > 0) {
3376 /* we have just sent ABOR and there is no reliable way to check if it was
3377 * successful or not; we have to close the connection now */
3378 infof(data, "partial download completed, closing connection\n");
3379 connclose(conn, "Partial download with no ability to check");
3383 if(!ftpc->dont_check) {
3384 /* 226 Transfer complete, 250 Requested file action okay, completed. */
3385 if((ftpcode != 226) && (ftpcode != 250)) {
3386 failf(data, "server did not report OK, got %d", ftpcode);
3387 result = CURLE_PARTIAL_FILE;
3392 if(result || premature)
3393 /* the response code from the transfer showed an error already so no
3394 use checking further */
3396 else if(data->set.upload) {
3397 if((-1 != data->state.infilesize) &&
3398 (data->state.infilesize != *ftp->bytecountp) &&
3400 (ftp->transfer == FTPTRANSFER_BODY)) {
3401 failf(data, "Uploaded unaligned file size (%" CURL_FORMAT_CURL_OFF_T
3402 " out of %" CURL_FORMAT_CURL_OFF_T " bytes)",
3403 *ftp->bytecountp, data->state.infilesize);
3404 result = CURLE_PARTIAL_FILE;
3408 if((-1 != data->req.size) &&
3409 (data->req.size != *ftp->bytecountp) &&
3410 #ifdef CURL_DO_LINEEND_CONV
3411 /* Most FTP servers don't adjust their file SIZE response for CRLFs, so
3412 * we'll check to see if the discrepancy can be explained by the number
3413 * of CRLFs we've changed to LFs.
3415 ((data->req.size + data->state.crlf_conversions) !=
3416 *ftp->bytecountp) &&
3417 #endif /* CURL_DO_LINEEND_CONV */
3418 (data->req.maxdownload != *ftp->bytecountp)) {
3419 failf(data, "Received only partial file: %" CURL_FORMAT_CURL_OFF_T
3420 " bytes", *ftp->bytecountp);
3421 result = CURLE_PARTIAL_FILE;
3423 else if(!ftpc->dont_check &&
3424 !*ftp->bytecountp &&
3425 (data->req.size>0)) {
3426 failf(data, "No data was received!");
3427 result = CURLE_FTP_COULDNT_RETR_FILE;
3431 /* clear these for next connection */
3432 ftp->transfer = FTPTRANSFER_BODY;
3433 ftpc->dont_check = FALSE;
3435 /* Send any post-transfer QUOTE strings? */
3436 if(!status && !result && !premature && data->set.postquote)
3437 result = ftp_sendquote(conn, data->set.postquote);
3442 /***********************************************************************
3446 * Where a 'quote' means a list of custom commands to send to the server.
3447 * The quote list is passed as an argument.
3453 CURLcode ftp_sendquote(struct connectdata *conn, struct curl_slist *quote)
3455 struct curl_slist *item;
3459 struct ftp_conn *ftpc = &conn->proto.ftpc;
3460 struct pingpong *pp = &ftpc->pp;
3465 char *cmd = item->data;
3466 bool acceptfail = FALSE;
3468 /* if a command starts with an asterisk, which a legal FTP command never
3469 can, the command will be allowed to fail without it causing any
3470 aborts or cancels etc. It will cause libcurl to act as if the command
3471 is successful, whatever the server reponds. */
3478 PPSENDF(&conn->proto.ftpc.pp, "%s", cmd);
3480 pp->response = Curl_tvnow(); /* timeout relative now */
3482 result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
3486 if(!acceptfail && (ftpcode >= 400)) {
3487 failf(conn->data, "QUOT string not accepted: %s", cmd);
3488 return CURLE_QUOTE_ERROR;
3498 /***********************************************************************
3502 * Returns TRUE if we in the current situation should send TYPE
3504 static int ftp_need_type(struct connectdata *conn,
3507 return conn->proto.ftpc.transfertype != (ascii_wanted?'A':'I');
3510 /***********************************************************************
3514 * Set TYPE. We only deal with ASCII or BINARY so this function
3516 * If the transfer type is not sent, simulate on OK response in newstate
3518 static CURLcode ftp_nb_type(struct connectdata *conn,
3519 bool ascii, ftpstate newstate)
3521 struct ftp_conn *ftpc = &conn->proto.ftpc;
3523 char want = (char)(ascii?'A':'I');
3525 if(ftpc->transfertype == want) {
3526 state(conn, newstate);
3527 return ftp_state_type_resp(conn, 200, newstate);
3530 PPSENDF(&ftpc->pp, "TYPE %c", want);
3531 state(conn, newstate);
3533 /* keep track of our current transfer type */
3534 ftpc->transfertype = want;
3538 /***************************************************************************
3540 * ftp_pasv_verbose()
3542 * This function only outputs some informationals about this second connection
3543 * when we've issued a PASV command before and thus we have connected to a
3544 * possibly new IP address.
3547 #ifndef CURL_DISABLE_VERBOSE_STRINGS
3549 ftp_pasv_verbose(struct connectdata *conn,
3551 char *newhost, /* ascii version */
3555 Curl_printable_address(ai, buf, sizeof(buf));
3556 infof(conn->data, "Connecting to %s (%s) port %d\n", newhost, buf, port);
3561 Check if this is a range download, and if so, set the internal variables
3565 static CURLcode ftp_range(struct connectdata *conn)
3567 curl_off_t from, to;
3570 struct SessionHandle *data = conn->data;
3571 struct ftp_conn *ftpc = &conn->proto.ftpc;
3573 if(data->state.use_range && data->state.range) {
3574 from=curlx_strtoofft(data->state.range, &ptr, 0);
3575 while(*ptr && (ISSPACE(*ptr) || (*ptr=='-')))
3577 to=curlx_strtoofft(ptr, &ptr2, 0);
3579 /* we didn't get any digit */
3582 if((-1 == to) && (from>=0)) {
3584 data->state.resume_from = from;
3585 DEBUGF(infof(conn->data, "FTP RANGE %" CURL_FORMAT_CURL_OFF_T
3586 " to end of file\n", from));
3590 data->req.maxdownload = -from;
3591 data->state.resume_from = from;
3592 DEBUGF(infof(conn->data, "FTP RANGE the last %" CURL_FORMAT_CURL_OFF_T
3593 " bytes\n", -from));
3597 data->req.maxdownload = (to-from)+1; /* include last byte */
3598 data->state.resume_from = from;
3599 DEBUGF(infof(conn->data, "FTP RANGE from %" CURL_FORMAT_CURL_OFF_T
3600 " getting %" CURL_FORMAT_CURL_OFF_T " bytes\n",
3601 from, data->req.maxdownload));
3603 DEBUGF(infof(conn->data, "range-download from %" CURL_FORMAT_CURL_OFF_T
3604 " to %" CURL_FORMAT_CURL_OFF_T ", totally %"
3605 CURL_FORMAT_CURL_OFF_T " bytes\n",
3606 from, to, data->req.maxdownload));
3607 ftpc->dont_check = TRUE; /* dont check for successful transfer */
3610 data->req.maxdownload = -1;
3618 * This function shall be called when the second FTP (data) connection is
3621 * 'complete' can return 0 for incomplete, 1 for done and -1 for go back
3622 * (which basically is only for when PASV is being sent to retry a failed
3626 static CURLcode ftp_do_more(struct connectdata *conn, int *completep)
3628 struct SessionHandle *data=conn->data;
3629 struct ftp_conn *ftpc = &conn->proto.ftpc;
3630 CURLcode result = CURLE_OK;
3631 bool connected = FALSE;
3632 bool complete = FALSE;
3634 /* the ftp struct is inited in ftp_connect() */
3635 struct FTP *ftp = data->req.protop;
3637 /* if the second connection isn't done yet, wait for it */
3638 if(!conn->bits.tcpconnect[SECONDARYSOCKET]) {
3639 if(conn->tunnel_state[SECONDARYSOCKET] == TUNNEL_CONNECT) {
3640 /* As we're in TUNNEL_CONNECT state now, we know the proxy name and port
3641 aren't used so we blank their arguments. TODO: make this nicer */
3642 result = Curl_proxyCONNECT(conn, SECONDARYSOCKET, NULL, 0);
3647 result = Curl_is_connected(conn, SECONDARYSOCKET, &connected);
3649 /* Ready to do more? */
3651 DEBUGF(infof(data, "DO-MORE connected phase starts\n"));
3652 if(conn->bits.proxy) {
3653 infof(data, "Connection to proxy confirmed\n");
3654 result = proxy_magic(conn, ftpc->newhost, ftpc->newport, &connected);
3658 if(result && (ftpc->count1 == 0)) {
3659 *completep = -1; /* go back to DOING please */
3660 /* this is a EPSV connect failing, try PASV instead */
3661 return ftp_epsv_disable(conn);
3668 /* already in a state so skip the intial commands.
3669 They are only done to kickstart the do_more state */
3670 result = ftp_multi_statemach(conn, &complete);
3672 *completep = (int)complete;
3674 /* if we got an error or if we don't wait for a data connection return
3676 if(result || (ftpc->wait_data_conn != TRUE))
3679 if(ftpc->wait_data_conn)
3680 /* if we reach the end of the FTP state machine here, *complete will be
3681 TRUE but so is ftpc->wait_data_conn, which says we need to wait for
3682 the data connection and therefore we're not actually complete */
3686 if(ftp->transfer <= FTPTRANSFER_INFO) {
3687 /* a transfer is about to take place, or if not a file name was given
3688 so we'll do a SIZE on it later and then we need the right TYPE first */
3690 if(ftpc->wait_data_conn == TRUE) {
3693 result = ReceivedServerConnect(conn, &serv_conned);
3695 return result; /* Failed to accept data connection */
3698 /* It looks data connection is established */
3699 result = AcceptServerConnect(conn);
3700 ftpc->wait_data_conn = FALSE;
3702 result = InitiateTransfer(conn);
3707 *completep = 1; /* this state is now complete when the server has
3708 connected back to us */
3711 else if(data->set.upload) {
3712 result = ftp_nb_type(conn, data->set.prefer_ascii, FTP_STOR_TYPE);
3716 result = ftp_multi_statemach(conn, &complete);
3717 *completep = (int)complete;
3721 ftp->downloadsize = -1; /* unknown as of yet */
3723 result = ftp_range(conn);
3726 else if(data->set.ftp_list_only || !ftpc->file) {
3727 /* The specified path ends with a slash, and therefore we think this
3728 is a directory that is requested, use LIST. But before that we
3729 need to set ASCII transfer mode. */
3731 /* But only if a body transfer was requested. */
3732 if(ftp->transfer == FTPTRANSFER_BODY) {
3733 result = ftp_nb_type(conn, TRUE, FTP_LIST_TYPE);
3737 /* otherwise just fall through */
3740 result = ftp_nb_type(conn, data->set.prefer_ascii, FTP_RETR_TYPE);
3745 result = ftp_multi_statemach(conn, &complete);
3746 *completep = (int)complete;
3751 if(!result && (ftp->transfer != FTPTRANSFER_BODY))
3752 /* no data to transfer. FIX: it feels like a kludge to have this here
3754 Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
3756 if(!ftpc->wait_data_conn) {
3757 /* no waiting for the data connection so this is now complete */
3759 DEBUGF(infof(data, "DO-MORE phase ends with %d\n", (int)result));
3767 /***********************************************************************
3771 * This is the actual DO function for FTP. Get a file/directory according to
3772 * the options previously setup.
3776 CURLcode ftp_perform(struct connectdata *conn,
3777 bool *connected, /* connect status after PASV / PORT */
3780 /* this is FTP and no proxy */
3781 CURLcode result=CURLE_OK;
3783 DEBUGF(infof(conn->data, "DO phase starts\n"));
3785 if(conn->data->set.opt_no_body) {
3786 /* requested no body means no transfer... */
3787 struct FTP *ftp = conn->data->req.protop;
3788 ftp->transfer = FTPTRANSFER_INFO;
3791 *dophase_done = FALSE; /* not done yet */
3793 /* start the first command in the DO phase */
3794 result = ftp_state_quote(conn, TRUE, FTP_QUOTE);
3798 /* run the state-machine */
3799 result = ftp_multi_statemach(conn, dophase_done);
3801 *connected = conn->bits.tcpconnect[SECONDARYSOCKET];
3803 infof(conn->data, "ftp_perform ends with SECONDARY: %d\n", *connected);
3806 DEBUGF(infof(conn->data, "DO phase is complete1\n"));
3811 static void wc_data_dtor(void *ptr)
3813 struct ftp_wc_tmpdata *tmp = ptr;
3815 Curl_ftp_parselist_data_free(&tmp->parser);
3819 static CURLcode init_wc_data(struct connectdata *conn)
3822 char *path = conn->data->state.path;
3823 struct WildcardData *wildcard = &(conn->data->wildcard);
3824 CURLcode result = CURLE_OK;
3825 struct ftp_wc_tmpdata *ftp_tmp;
3827 last_slash = strrchr(conn->data->state.path, '/');
3830 if(last_slash[0] == '\0') {
3831 wildcard->state = CURLWC_CLEAN;
3832 result = ftp_parse_url_path(conn);
3836 wildcard->pattern = strdup(last_slash);
3837 if(!wildcard->pattern)
3838 return CURLE_OUT_OF_MEMORY;
3839 last_slash[0] = '\0'; /* cut file from path */
3842 else { /* there is only 'wildcard pattern' or nothing */
3844 wildcard->pattern = strdup(path);
3845 if(!wildcard->pattern)
3846 return CURLE_OUT_OF_MEMORY;
3849 else { /* only list */
3850 wildcard->state = CURLWC_CLEAN;
3851 result = ftp_parse_url_path(conn);
3856 /* program continues only if URL is not ending with slash, allocate needed
3857 resources for wildcard transfer */
3859 /* allocate ftp protocol specific temporary wildcard data */
3860 ftp_tmp = calloc(1, sizeof(struct ftp_wc_tmpdata));
3862 Curl_safefree(wildcard->pattern);
3863 return CURLE_OUT_OF_MEMORY;
3866 /* INITIALIZE parselist structure */
3867 ftp_tmp->parser = Curl_ftp_parselist_data_alloc();
3868 if(!ftp_tmp->parser) {
3869 Curl_safefree(wildcard->pattern);
3870 Curl_safefree(ftp_tmp);
3871 return CURLE_OUT_OF_MEMORY;
3874 wildcard->tmp = ftp_tmp; /* put it to the WildcardData tmp pointer */
3875 wildcard->tmp_dtor = wc_data_dtor;
3877 /* wildcard does not support NOCWD option (assert it?) */
3878 if(conn->data->set.ftp_filemethod == FTPFILE_NOCWD)
3879 conn->data->set.ftp_filemethod = FTPFILE_MULTICWD;
3881 /* try to parse ftp url */
3882 result = ftp_parse_url_path(conn);
3884 Curl_safefree(wildcard->pattern);
3885 wildcard->tmp_dtor(wildcard->tmp);
3886 wildcard->tmp_dtor = ZERO_NULL;
3887 wildcard->tmp = NULL;
3891 wildcard->path = strdup(conn->data->state.path);
3892 if(!wildcard->path) {
3893 Curl_safefree(wildcard->pattern);
3894 wildcard->tmp_dtor(wildcard->tmp);
3895 wildcard->tmp_dtor = ZERO_NULL;
3896 wildcard->tmp = NULL;
3897 return CURLE_OUT_OF_MEMORY;
3900 /* backup old write_function */
3901 ftp_tmp->backup.write_function = conn->data->set.fwrite_func;
3902 /* parsing write function */
3903 conn->data->set.fwrite_func = Curl_ftp_parselist;
3904 /* backup old file descriptor */
3905 ftp_tmp->backup.file_descriptor = conn->data->set.out;
3906 /* let the writefunc callback know what curl pointer is working with */
3907 conn->data->set.out = conn;
3909 infof(conn->data, "Wildcard - Parsing started\n");
3913 /* This is called recursively */
3914 static CURLcode wc_statemach(struct connectdata *conn)
3916 struct WildcardData * const wildcard = &(conn->data->wildcard);
3917 CURLcode result = CURLE_OK;
3919 switch (wildcard->state) {
3921 result = init_wc_data(conn);
3922 if(wildcard->state == CURLWC_CLEAN)
3926 wildcard->state = result ? CURLWC_ERROR : CURLWC_MATCHING;
3929 case CURLWC_MATCHING: {
3930 /* In this state is LIST response successfully parsed, so lets restore
3931 previous WRITEFUNCTION callback and WRITEDATA pointer */
3932 struct ftp_wc_tmpdata *ftp_tmp = wildcard->tmp;
3933 conn->data->set.fwrite_func = ftp_tmp->backup.write_function;
3934 conn->data->set.out = ftp_tmp->backup.file_descriptor;
3935 ftp_tmp->backup.write_function = ZERO_NULL;
3936 ftp_tmp->backup.file_descriptor = NULL;
3937 wildcard->state = CURLWC_DOWNLOADING;
3939 if(Curl_ftp_parselist_geterror(ftp_tmp->parser)) {
3940 /* error found in LIST parsing */
3941 wildcard->state = CURLWC_CLEAN;
3942 return wc_statemach(conn);
3944 else if(wildcard->filelist->size == 0) {
3945 /* no corresponding file */
3946 wildcard->state = CURLWC_CLEAN;
3947 return CURLE_REMOTE_FILE_NOT_FOUND;
3949 return wc_statemach(conn);
3952 case CURLWC_DOWNLOADING: {
3953 /* filelist has at least one file, lets get first one */
3954 struct ftp_conn *ftpc = &conn->proto.ftpc;
3955 struct curl_fileinfo *finfo = wildcard->filelist->head->ptr;
3957 char *tmp_path = aprintf("%s%s", wildcard->path, finfo->filename);
3959 return CURLE_OUT_OF_MEMORY;
3961 /* switch default "state.pathbuffer" and tmp_path, good to see
3962 ftp_parse_url_path function to understand this trick */
3963 Curl_safefree(conn->data->state.pathbuffer);
3964 conn->data->state.pathbuffer = tmp_path;
3965 conn->data->state.path = tmp_path;
3967 infof(conn->data, "Wildcard - START of \"%s\"\n", finfo->filename);
3968 if(conn->data->set.chunk_bgn) {
3969 long userresponse = conn->data->set.chunk_bgn(
3970 finfo, wildcard->customptr, (int)wildcard->filelist->size);
3971 switch(userresponse) {
3972 case CURL_CHUNK_BGN_FUNC_SKIP:
3973 infof(conn->data, "Wildcard - \"%s\" skipped by user\n",
3975 wildcard->state = CURLWC_SKIP;
3976 return wc_statemach(conn);
3977 case CURL_CHUNK_BGN_FUNC_FAIL:
3978 return CURLE_CHUNK_FAILED;
3982 if(finfo->filetype != CURLFILETYPE_FILE) {
3983 wildcard->state = CURLWC_SKIP;
3984 return wc_statemach(conn);
3987 if(finfo->flags & CURLFINFOFLAG_KNOWN_SIZE)
3988 ftpc->known_filesize = finfo->size;
3990 result = ftp_parse_url_path(conn);
3994 /* we don't need the Curl_fileinfo of first file anymore */
3995 Curl_llist_remove(wildcard->filelist, wildcard->filelist->head, NULL);
3997 if(wildcard->filelist->size == 0) { /* remains only one file to down. */
3998 wildcard->state = CURLWC_CLEAN;
3999 /* after that will be ftp_do called once again and no transfer
4000 will be done because of CURLWC_CLEAN state */
4006 if(conn->data->set.chunk_end)
4007 conn->data->set.chunk_end(conn->data->wildcard.customptr);
4008 Curl_llist_remove(wildcard->filelist, wildcard->filelist->head, NULL);
4009 wildcard->state = (wildcard->filelist->size == 0) ?
4010 CURLWC_CLEAN : CURLWC_DOWNLOADING;
4011 return wc_statemach(conn);
4014 case CURLWC_CLEAN: {
4015 struct ftp_wc_tmpdata *ftp_tmp = wildcard->tmp;
4018 result = Curl_ftp_parselist_geterror(ftp_tmp->parser);
4020 wildcard->state = result ? CURLWC_ERROR : CURLWC_DONE;
4031 /***********************************************************************
4035 * This function is registered as 'curl_do' function. It decodes the path
4036 * parts etc as a wrapper to the actual DO function (ftp_perform).
4038 * The input argument is already checked for validity.
4040 static CURLcode ftp_do(struct connectdata *conn, bool *done)
4042 CURLcode result = CURLE_OK;
4043 struct ftp_conn *ftpc = &conn->proto.ftpc;
4045 *done = FALSE; /* default to false */
4046 ftpc->wait_data_conn = FALSE; /* default to no such wait */
4048 if(conn->data->set.wildcardmatch) {
4049 result = wc_statemach(conn);
4050 if(conn->data->wildcard.state == CURLWC_SKIP ||
4051 conn->data->wildcard.state == CURLWC_DONE) {
4052 /* do not call ftp_regular_transfer */
4055 if(result) /* error, loop or skipping the file */
4058 else { /* no wildcard FSM needed */
4059 result = ftp_parse_url_path(conn);
4064 result = ftp_regular_transfer(conn, done);
4070 CURLcode Curl_ftpsendf(struct connectdata *conn,
4071 const char *fmt, ...)
4073 ssize_t bytes_written;
4074 #define SBUF_SIZE 1024
4078 CURLcode result = CURLE_OK;
4080 enum protection_level data_sec = conn->data_prot;
4085 write_len = vsnprintf(s, SBUF_SIZE-3, fmt, ap);
4088 strcpy(&s[write_len], "\r\n"); /* append a trailing CRLF */
4093 result = Curl_convert_to_network(conn->data, s, write_len);
4094 /* Curl_convert_to_network calls failf if unsuccessful */
4100 conn->data_prot = PROT_CMD;
4102 result = Curl_write(conn, conn->sock[FIRSTSOCKET], sptr, write_len,
4105 DEBUGASSERT(data_sec > PROT_NONE && data_sec < PROT_LAST);
4106 conn->data_prot = data_sec;
4112 if(conn->data->set.verbose)
4113 Curl_debug(conn->data, CURLINFO_HEADER_OUT,
4114 sptr, (size_t)bytes_written, conn);
4116 if(bytes_written != (ssize_t)write_len) {
4117 write_len -= bytes_written;
4118 sptr += bytes_written;
4127 /***********************************************************************
4131 * This should be called before calling sclose() on an ftp control connection
4132 * (not data connections). We should then wait for the response from the
4133 * server before returning. The calling code should then try to close the
4137 static CURLcode ftp_quit(struct connectdata *conn)
4139 CURLcode result = CURLE_OK;
4141 if(conn->proto.ftpc.ctl_valid) {
4142 result = Curl_pp_sendf(&conn->proto.ftpc.pp, "%s", "QUIT");
4144 failf(conn->data, "Failure sending QUIT command: %s",
4145 curl_easy_strerror(result));
4146 conn->proto.ftpc.ctl_valid = FALSE; /* mark control connection as bad */
4147 connclose(conn, "QUIT command failed"); /* mark for connection closure */
4148 state(conn, FTP_STOP);
4152 state(conn, FTP_QUIT);
4154 result = ftp_block_statemach(conn);
4160 /***********************************************************************
4164 * Disconnect from an FTP server. Cleanup protocol-specific per-connection
4165 * resources. BLOCKING.
4167 static CURLcode ftp_disconnect(struct connectdata *conn, bool dead_connection)
4169 struct ftp_conn *ftpc= &conn->proto.ftpc;
4170 struct pingpong *pp = &ftpc->pp;
4172 /* We cannot send quit unconditionally. If this connection is stale or
4173 bad in any way, sending quit and waiting around here will make the
4174 disconnect wait in vain and cause more problems than we need to.
4176 ftp_quit() will check the state of ftp->ctl_valid. If it's ok it
4177 will try to send the QUIT command, otherwise it will just return.
4180 ftpc->ctl_valid = FALSE;
4182 /* The FTP session may or may not have been allocated/setup at this point! */
4183 (void)ftp_quit(conn); /* ignore errors on the QUIT */
4185 if(ftpc->entrypath) {
4186 struct SessionHandle *data = conn->data;
4187 if(data->state.most_recent_ftp_entrypath == ftpc->entrypath) {
4188 data->state.most_recent_ftp_entrypath = NULL;
4190 free(ftpc->entrypath);
4191 ftpc->entrypath = NULL;
4195 if(ftpc->prevpath) {
4196 free(ftpc->prevpath);
4197 ftpc->prevpath = NULL;
4199 if(ftpc->server_os) {
4200 free(ftpc->server_os);
4201 ftpc->server_os = NULL;
4204 Curl_pp_disconnect(pp);
4213 /***********************************************************************
4215 * ftp_parse_url_path()
4217 * Parse the URL path into separate path components.
4221 CURLcode ftp_parse_url_path(struct connectdata *conn)
4223 struct SessionHandle *data = conn->data;
4224 /* the ftp struct is already inited in ftp_connect() */
4225 struct FTP *ftp = data->req.protop;
4226 struct ftp_conn *ftpc = &conn->proto.ftpc;
4227 const char *slash_pos; /* position of the first '/' char in curpos */
4228 const char *path_to_use = data->state.path;
4229 const char *cur_pos;
4230 const char *filename = NULL;
4232 cur_pos = path_to_use; /* current position in path. point at the begin
4233 of next path component */
4235 ftpc->ctl_valid = FALSE;
4236 ftpc->cwdfail = FALSE;
4238 switch(data->set.ftp_filemethod) {
4240 /* fastest, but less standard-compliant */
4243 The best time to check whether the path is a file or directory is right
4246 the first condition in the if() right here, is there just in case
4247 someone decides to set path to NULL one day
4249 if(data->state.path &&
4250 data->state.path[0] &&
4251 (data->state.path[strlen(data->state.path) - 1] != '/') )
4252 filename = data->state.path; /* this is a full file path */
4254 ftpc->file is not used anywhere other than for operations on a file.
4255 In other words, never for directory operations.
4256 So we can safely leave filename as NULL here and use it as a
4257 argument in dir/file decisions.
4261 case FTPFILE_SINGLECWD:
4262 /* get the last slash */
4263 if(!path_to_use[0]) {
4264 /* no dir, no file */
4268 slash_pos=strrchr(cur_pos, '/');
4269 if(slash_pos || !*cur_pos) {
4270 size_t dirlen = slash_pos-cur_pos;
4272 ftpc->dirs = calloc(1, sizeof(ftpc->dirs[0]));
4274 return CURLE_OUT_OF_MEMORY;
4279 ftpc->dirs[0] = curl_easy_unescape(conn->data, slash_pos ? cur_pos : "/",
4280 slash_pos ? curlx_uztosi(dirlen) : 1,
4282 if(!ftpc->dirs[0]) {
4284 return CURLE_OUT_OF_MEMORY;
4286 ftpc->dirdepth = 1; /* we consider it to be a single dir */
4287 filename = slash_pos ? slash_pos+1 : cur_pos; /* rest is file name */
4290 filename = cur_pos; /* this is a file name only */
4293 default: /* allow pretty much anything */
4294 case FTPFILE_MULTICWD:
4296 ftpc->diralloc = 5; /* default dir depth to allocate */
4297 ftpc->dirs = calloc(ftpc->diralloc, sizeof(ftpc->dirs[0]));
4299 return CURLE_OUT_OF_MEMORY;
4301 /* we have a special case for listing the root dir only */
4302 if(strequal(path_to_use, "/")) {
4303 cur_pos++; /* make it point to the zero byte */
4304 ftpc->dirs[0] = strdup("/");
4308 /* parse the URL path into separate path components */
4309 while((slash_pos = strchr(cur_pos, '/')) != NULL) {
4310 /* 1 or 0 pointer offset to indicate absolute directory */
4311 ssize_t absolute_dir = ((cur_pos - data->state.path > 0) &&
4312 (ftpc->dirdepth == 0))?1:0;
4314 /* seek out the next path component */
4315 if(slash_pos-cur_pos) {
4316 /* we skip empty path components, like "x//y" since the FTP command
4317 CWD requires a parameter and a non-existent parameter a) doesn't
4318 work on many servers and b) has no effect on the others. */
4319 int len = curlx_sztosi(slash_pos - cur_pos + absolute_dir);
4320 ftpc->dirs[ftpc->dirdepth] =
4321 curl_easy_unescape(conn->data, cur_pos - absolute_dir, len, NULL);
4322 if(!ftpc->dirs[ftpc->dirdepth]) { /* run out of memory ... */
4323 failf(data, "no memory");
4325 return CURLE_OUT_OF_MEMORY;
4327 if(isBadFtpString(ftpc->dirs[ftpc->dirdepth])) {
4328 free(ftpc->dirs[ftpc->dirdepth]);
4330 return CURLE_URL_MALFORMAT;
4334 cur_pos = slash_pos + 1; /* jump to the rest of the string */
4335 if(!ftpc->dirdepth) {
4336 /* path starts with a slash, add that as a directory */
4337 ftpc->dirs[ftpc->dirdepth] = strdup("/");
4338 if(!ftpc->dirs[ftpc->dirdepth++]) { /* run out of memory ... */
4339 failf(data, "no memory");
4341 return CURLE_OUT_OF_MEMORY;
4347 cur_pos = slash_pos + 1; /* jump to the rest of the string */
4348 if(++ftpc->dirdepth >= ftpc->diralloc) {
4351 ftpc->diralloc *= 2; /* double the size each time */
4352 bigger = realloc(ftpc->dirs, ftpc->diralloc * sizeof(ftpc->dirs[0]));
4355 return CURLE_OUT_OF_MEMORY;
4357 ftpc->dirs = bigger;
4361 filename = cur_pos; /* the rest is the file name */
4365 if(filename && *filename) {
4366 ftpc->file = curl_easy_unescape(conn->data, filename, 0, NULL);
4367 if(NULL == ftpc->file) {
4369 failf(data, "no memory");
4370 return CURLE_OUT_OF_MEMORY;
4372 if(isBadFtpString(ftpc->file)) {
4374 return CURLE_URL_MALFORMAT;
4378 ftpc->file=NULL; /* instead of point to a zero byte, we make it a NULL
4381 if(data->set.upload && !ftpc->file && (ftp->transfer == FTPTRANSFER_BODY)) {
4382 /* We need a file name when uploading. Return error! */
4383 failf(data, "Uploading to a URL without a file name!");
4384 return CURLE_URL_MALFORMAT;
4387 ftpc->cwddone = FALSE; /* default to not done */
4389 if(ftpc->prevpath) {
4390 /* prevpath is "raw" so we convert the input path before we compare the
4393 char *path = curl_easy_unescape(conn->data, data->state.path, 0, &dlen);
4396 return CURLE_OUT_OF_MEMORY;
4399 dlen -= ftpc->file?curlx_uztosi(strlen(ftpc->file)):0;
4400 if((dlen == curlx_uztosi(strlen(ftpc->prevpath))) &&
4401 strnequal(path, ftpc->prevpath, dlen)) {
4402 infof(data, "Request has same path as previous transfer\n");
4403 ftpc->cwddone = TRUE;
4411 /* call this when the DO phase has completed */
4412 static CURLcode ftp_dophase_done(struct connectdata *conn,
4415 struct FTP *ftp = conn->data->req.protop;
4416 struct ftp_conn *ftpc = &conn->proto.ftpc;
4420 CURLcode result = ftp_do_more(conn, &completed);
4423 if(conn->sock[SECONDARYSOCKET] != CURL_SOCKET_BAD) {
4424 /* close the second socket if it was created already */
4425 Curl_closesocket(conn, conn->sock[SECONDARYSOCKET]);
4426 conn->sock[SECONDARYSOCKET] = CURL_SOCKET_BAD;
4432 if(ftp->transfer != FTPTRANSFER_BODY)
4433 /* no data to transfer */
4434 Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
4436 /* since we didn't connect now, we want do_more to get called */
4437 conn->bits.do_more = TRUE;
4439 ftpc->ctl_valid = TRUE; /* seems good */
4444 /* called from multi.c while DOing */
4445 static CURLcode ftp_doing(struct connectdata *conn,
4448 CURLcode result = ftp_multi_statemach(conn, dophase_done);
4451 DEBUGF(infof(conn->data, "DO phase failed\n"));
4452 else if(*dophase_done) {
4453 result = ftp_dophase_done(conn, FALSE /* not connected */);
4455 DEBUGF(infof(conn->data, "DO phase is complete2\n"));
4460 /***********************************************************************
4462 * ftp_regular_transfer()
4464 * The input argument is already checked for validity.
4466 * Performs all commands done before a regular transfer between a local and a
4469 * ftp->ctl_valid starts out as FALSE, and gets set to TRUE if we reach the
4470 * ftp_done() function without finding any major problem.
4473 CURLcode ftp_regular_transfer(struct connectdata *conn,
4476 CURLcode result=CURLE_OK;
4477 bool connected=FALSE;
4478 struct SessionHandle *data = conn->data;
4479 struct ftp_conn *ftpc = &conn->proto.ftpc;
4480 data->req.size = -1; /* make sure this is unknown at this point */
4482 Curl_pgrsSetUploadCounter(data, 0);
4483 Curl_pgrsSetDownloadCounter(data, 0);
4484 Curl_pgrsSetUploadSize(data, -1);
4485 Curl_pgrsSetDownloadSize(data, -1);
4487 ftpc->ctl_valid = TRUE; /* starts good */
4489 result = ftp_perform(conn,
4490 &connected, /* have we connected after PASV/PORT */
4491 dophase_done); /* all commands in the DO-phase done? */
4496 /* the DO phase has not completed yet */
4499 result = ftp_dophase_done(conn, connected);
4510 static CURLcode ftp_setup_connection(struct connectdata *conn)
4512 struct SessionHandle *data = conn->data;
4517 if(conn->bits.httpproxy && !data->set.tunnel_thru_httpproxy) {
4518 /* Unless we have asked to tunnel ftp operations through the proxy, we
4519 switch and use HTTP operations only */
4520 #ifndef CURL_DISABLE_HTTP
4521 if(conn->handler == &Curl_handler_ftp)
4522 conn->handler = &Curl_handler_ftp_proxy;
4525 conn->handler = &Curl_handler_ftps_proxy;
4527 failf(data, "FTPS not supported!");
4528 return CURLE_UNSUPPORTED_PROTOCOL;
4531 /* set it up as a HTTP connection instead */
4532 return conn->handler->setup_connection(conn);
4534 failf(data, "FTP over http proxy requires HTTP support built-in!");
4535 return CURLE_UNSUPPORTED_PROTOCOL;
4539 conn->data->req.protop = ftp = malloc(sizeof(struct FTP));
4541 return CURLE_OUT_OF_MEMORY;
4543 data->state.path++; /* don't include the initial slash */
4544 data->state.slash_removed = TRUE; /* we've skipped the slash */
4546 /* FTP URLs support an extension like ";type=<typecode>" that
4547 * we'll try to get now! */
4548 type = strstr(data->state.path, ";type=");
4551 type = strstr(conn->host.rawalloc, ";type=");
4554 *type = 0; /* it was in the middle of the hostname */
4555 command = Curl_raw_toupper(type[6]);
4556 conn->bits.type_set = TRUE;
4559 case 'A': /* ASCII mode */
4560 data->set.prefer_ascii = TRUE;
4563 case 'D': /* directory mode */
4564 data->set.ftp_list_only = TRUE;
4567 case 'I': /* binary mode */
4569 /* switch off ASCII */
4570 data->set.prefer_ascii = FALSE;
4575 /* get some initial data into the ftp struct */
4576 ftp->bytecountp = &conn->data->req.bytecount;
4577 ftp->transfer = FTPTRANSFER_BODY;
4578 ftp->downloadsize = 0;
4580 /* No need to duplicate user+password, the connectdata struct won't change
4581 during a session, but we re-init them here since on subsequent inits
4582 since the conn struct may have changed or been replaced.
4584 ftp->user = conn->user;
4585 ftp->passwd = conn->passwd;
4586 if(isBadFtpString(ftp->user))
4587 return CURLE_URL_MALFORMAT;
4588 if(isBadFtpString(ftp->passwd))
4589 return CURLE_URL_MALFORMAT;
4591 conn->proto.ftpc.known_filesize = -1; /* unknown size for now */
4596 #endif /* CURL_DISABLE_FTP */