Imported Upstream version 3.24.0
[platform/upstream/cmake.git] / Utilities / cmcurl / lib / ftp.c
1 /***************************************************************************
2  *                                  _   _ ____  _
3  *  Project                     ___| | | |  _ \| |
4  *                             / __| | | | |_) | |
5  *                            | (__| |_| |  _ <| |___
6  *                             \___|\___/|_| \_\_____|
7  *
8  * Copyright (C) 1998 - 2022, Daniel Stenberg, <daniel@haxx.se>, et al.
9  *
10  * This software is licensed as described in the file COPYING, which
11  * you should have received as part of this distribution. The terms
12  * are also available at https://curl.se/docs/copyright.html.
13  *
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.
17  *
18  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19  * KIND, either express or implied.
20  *
21  ***************************************************************************/
22
23 #include "curl_setup.h"
24
25 #ifndef CURL_DISABLE_FTP
26
27 #ifdef HAVE_NETINET_IN_H
28 #include <netinet/in.h>
29 #endif
30 #ifdef HAVE_ARPA_INET_H
31 #include <arpa/inet.h>
32 #endif
33 #ifdef HAVE_UTSNAME_H
34 #include <sys/utsname.h>
35 #endif
36 #ifdef HAVE_NETDB_H
37 #include <netdb.h>
38 #endif
39 #ifdef __VMS
40 #include <in.h>
41 #include <inet.h>
42 #endif
43
44 #if (defined(NETWARE) && defined(__NOVELL_LIBC__))
45 #undef in_addr_t
46 #define in_addr_t unsigned long
47 #endif
48
49 #include <curl/curl.h>
50 #include "urldata.h"
51 #include "sendf.h"
52 #include "if2ip.h"
53 #include "hostip.h"
54 #include "progress.h"
55 #include "transfer.h"
56 #include "escape.h"
57 #include "http.h" /* for HTTP proxy tunnel stuff */
58 #include "ftp.h"
59 #include "fileinfo.h"
60 #include "ftplistparser.h"
61 #include "curl_range.h"
62 #include "curl_krb5.h"
63 #include "strtoofft.h"
64 #include "strcase.h"
65 #include "vtls/vtls.h"
66 #include "connect.h"
67 #include "strerror.h"
68 #include "inet_ntop.h"
69 #include "inet_pton.h"
70 #include "select.h"
71 #include "parsedate.h" /* for the week day and month names */
72 #include "sockaddr.h" /* required for Curl_sockaddr_storage */
73 #include "multiif.h"
74 #include "url.h"
75 #include "strcase.h"
76 #include "speedcheck.h"
77 #include "warnless.h"
78 #include "http_proxy.h"
79 #include "socks.h"
80 /* The last 3 #include files should be in this order */
81 #include "curl_printf.h"
82 #include "curl_memory.h"
83 #include "memdebug.h"
84
85 #ifndef NI_MAXHOST
86 #define NI_MAXHOST 1025
87 #endif
88 #ifndef INET_ADDRSTRLEN
89 #define INET_ADDRSTRLEN 16
90 #endif
91
92 #ifdef CURL_DISABLE_VERBOSE_STRINGS
93 #define ftp_pasv_verbose(a,b,c,d)  Curl_nop_stmt
94 #endif
95
96 /* Local API functions */
97 #ifndef DEBUGBUILD
98 static void _state(struct Curl_easy *data,
99                    ftpstate newstate);
100 #define state(x,y) _state(x,y)
101 #else
102 static void _state(struct Curl_easy *data,
103                    ftpstate newstate,
104                    int lineno);
105 #define state(x,y) _state(x,y,__LINE__)
106 #endif
107
108 static CURLcode ftp_sendquote(struct Curl_easy *data,
109                               struct connectdata *conn,
110                               struct curl_slist *quote);
111 static CURLcode ftp_quit(struct Curl_easy *data, struct connectdata *conn);
112 static CURLcode ftp_parse_url_path(struct Curl_easy *data);
113 static CURLcode ftp_regular_transfer(struct Curl_easy *data, bool *done);
114 #ifndef CURL_DISABLE_VERBOSE_STRINGS
115 static void ftp_pasv_verbose(struct Curl_easy *data,
116                              struct Curl_addrinfo *ai,
117                              char *newhost, /* ascii version */
118                              int port);
119 #endif
120 static CURLcode ftp_state_prepare_transfer(struct Curl_easy *data);
121 static CURLcode ftp_state_mdtm(struct Curl_easy *data);
122 static CURLcode ftp_state_quote(struct Curl_easy *data,
123                                 bool init, ftpstate instate);
124 static CURLcode ftp_nb_type(struct Curl_easy *data,
125                             struct connectdata *conn,
126                             bool ascii, ftpstate newstate);
127 static int ftp_need_type(struct connectdata *conn,
128                          bool ascii);
129 static CURLcode ftp_do(struct Curl_easy *data, bool *done);
130 static CURLcode ftp_done(struct Curl_easy *data,
131                          CURLcode, bool premature);
132 static CURLcode ftp_connect(struct Curl_easy *data, bool *done);
133 static CURLcode ftp_disconnect(struct Curl_easy *data,
134                                struct connectdata *conn, bool dead_connection);
135 static CURLcode ftp_do_more(struct Curl_easy *data, int *completed);
136 static CURLcode ftp_multi_statemach(struct Curl_easy *data, bool *done);
137 static int ftp_getsock(struct Curl_easy *data, struct connectdata *conn,
138                        curl_socket_t *socks);
139 static int ftp_domore_getsock(struct Curl_easy *data,
140                               struct connectdata *conn, curl_socket_t *socks);
141 static CURLcode ftp_doing(struct Curl_easy *data,
142                           bool *dophase_done);
143 static CURLcode ftp_setup_connection(struct Curl_easy *data,
144                                      struct connectdata *conn);
145 static CURLcode init_wc_data(struct Curl_easy *data);
146 static CURLcode wc_statemach(struct Curl_easy *data);
147 static void wc_data_dtor(void *ptr);
148 static CURLcode ftp_state_retr(struct Curl_easy *data, curl_off_t filesize);
149 static CURLcode ftp_readresp(struct Curl_easy *data,
150                              curl_socket_t sockfd,
151                              struct pingpong *pp,
152                              int *ftpcode,
153                              size_t *size);
154 static CURLcode ftp_dophase_done(struct Curl_easy *data,
155                                  bool connected);
156
157 /*
158  * FTP protocol handler.
159  */
160
161 const struct Curl_handler Curl_handler_ftp = {
162   "FTP",                           /* scheme */
163   ftp_setup_connection,            /* setup_connection */
164   ftp_do,                          /* do_it */
165   ftp_done,                        /* done */
166   ftp_do_more,                     /* do_more */
167   ftp_connect,                     /* connect_it */
168   ftp_multi_statemach,             /* connecting */
169   ftp_doing,                       /* doing */
170   ftp_getsock,                     /* proto_getsock */
171   ftp_getsock,                     /* doing_getsock */
172   ftp_domore_getsock,              /* domore_getsock */
173   ZERO_NULL,                       /* perform_getsock */
174   ftp_disconnect,                  /* disconnect */
175   ZERO_NULL,                       /* readwrite */
176   ZERO_NULL,                       /* connection_check */
177   ZERO_NULL,                       /* attach connection */
178   PORT_FTP,                        /* defport */
179   CURLPROTO_FTP,                   /* protocol */
180   CURLPROTO_FTP,                   /* family */
181   PROTOPT_DUAL | PROTOPT_CLOSEACTION | PROTOPT_NEEDSPWD |
182   PROTOPT_NOURLQUERY | PROTOPT_PROXY_AS_HTTP |
183   PROTOPT_WILDCARD /* flags */
184 };
185
186
187 #ifdef USE_SSL
188 /*
189  * FTPS protocol handler.
190  */
191
192 const struct Curl_handler Curl_handler_ftps = {
193   "FTPS",                          /* scheme */
194   ftp_setup_connection,            /* setup_connection */
195   ftp_do,                          /* do_it */
196   ftp_done,                        /* done */
197   ftp_do_more,                     /* do_more */
198   ftp_connect,                     /* connect_it */
199   ftp_multi_statemach,             /* connecting */
200   ftp_doing,                       /* doing */
201   ftp_getsock,                     /* proto_getsock */
202   ftp_getsock,                     /* doing_getsock */
203   ftp_domore_getsock,              /* domore_getsock */
204   ZERO_NULL,                       /* perform_getsock */
205   ftp_disconnect,                  /* disconnect */
206   ZERO_NULL,                       /* readwrite */
207   ZERO_NULL,                       /* connection_check */
208   ZERO_NULL,                       /* attach connection */
209   PORT_FTPS,                       /* defport */
210   CURLPROTO_FTPS,                  /* protocol */
211   CURLPROTO_FTP,                   /* family */
212   PROTOPT_SSL | PROTOPT_DUAL | PROTOPT_CLOSEACTION |
213   PROTOPT_NEEDSPWD | PROTOPT_NOURLQUERY | PROTOPT_WILDCARD /* flags */
214 };
215 #endif
216
217 static void close_secondarysocket(struct Curl_easy *data,
218                                   struct connectdata *conn)
219 {
220   if(CURL_SOCKET_BAD != conn->sock[SECONDARYSOCKET]) {
221     Curl_closesocket(data, conn, conn->sock[SECONDARYSOCKET]);
222     conn->sock[SECONDARYSOCKET] = CURL_SOCKET_BAD;
223   }
224   conn->bits.tcpconnect[SECONDARYSOCKET] = FALSE;
225 #ifndef CURL_DISABLE_PROXY
226   conn->bits.proxy_ssl_connected[SECONDARYSOCKET] = FALSE;
227 #endif
228 }
229
230 /*
231  * NOTE: back in the old days, we added code in the FTP code that made NOBODY
232  * requests on files respond with headers passed to the client/stdout that
233  * looked like HTTP ones.
234  *
235  * This approach is not very elegant, it causes confusion and is error-prone.
236  * It is subject for removal at the next (or at least a future) soname bump.
237  * Until then you can test the effects of the removal by undefining the
238  * following define named CURL_FTP_HTTPSTYLE_HEAD.
239  */
240 #define CURL_FTP_HTTPSTYLE_HEAD 1
241
242 static void freedirs(struct ftp_conn *ftpc)
243 {
244   if(ftpc->dirs) {
245     int i;
246     for(i = 0; i < ftpc->dirdepth; i++) {
247       free(ftpc->dirs[i]);
248       ftpc->dirs[i] = NULL;
249     }
250     free(ftpc->dirs);
251     ftpc->dirs = NULL;
252     ftpc->dirdepth = 0;
253   }
254   Curl_safefree(ftpc->file);
255
256   /* no longer of any use */
257   Curl_safefree(ftpc->newhost);
258 }
259
260 /***********************************************************************
261  *
262  * AcceptServerConnect()
263  *
264  * After connection request is received from the server this function is
265  * called to accept the connection and close the listening socket
266  *
267  */
268 static CURLcode AcceptServerConnect(struct Curl_easy *data)
269 {
270   struct connectdata *conn = data->conn;
271   curl_socket_t sock = conn->sock[SECONDARYSOCKET];
272   curl_socket_t s = CURL_SOCKET_BAD;
273 #ifdef ENABLE_IPV6
274   struct Curl_sockaddr_storage add;
275 #else
276   struct sockaddr_in add;
277 #endif
278   curl_socklen_t size = (curl_socklen_t) sizeof(add);
279
280   if(0 == getsockname(sock, (struct sockaddr *) &add, &size)) {
281     size = sizeof(add);
282
283     s = accept(sock, (struct sockaddr *) &add, &size);
284   }
285   Curl_closesocket(data, conn, sock); /* close the first socket */
286
287   if(CURL_SOCKET_BAD == s) {
288     failf(data, "Error accept()ing server connect");
289     return CURLE_FTP_PORT_FAILED;
290   }
291   infof(data, "Connection accepted from server");
292   /* when this happens within the DO state it is important that we mark us as
293      not needing DO_MORE anymore */
294   conn->bits.do_more = FALSE;
295
296   conn->sock[SECONDARYSOCKET] = s;
297   (void)curlx_nonblock(s, TRUE); /* enable non-blocking */
298   conn->bits.sock_accepted = TRUE;
299
300   if(data->set.fsockopt) {
301     int error = 0;
302
303     /* activate callback for setting socket options */
304     Curl_set_in_callback(data, true);
305     error = data->set.fsockopt(data->set.sockopt_client,
306                                s,
307                                CURLSOCKTYPE_ACCEPT);
308     Curl_set_in_callback(data, false);
309
310     if(error) {
311       close_secondarysocket(data, conn);
312       return CURLE_ABORTED_BY_CALLBACK;
313     }
314   }
315
316   return CURLE_OK;
317
318 }
319
320 /*
321  * ftp_timeleft_accept() returns the amount of milliseconds left allowed for
322  * waiting server to connect. If the value is negative, the timeout time has
323  * already elapsed.
324  *
325  * The start time is stored in progress.t_acceptdata - as set with
326  * Curl_pgrsTime(..., TIMER_STARTACCEPT);
327  *
328  */
329 static timediff_t ftp_timeleft_accept(struct Curl_easy *data)
330 {
331   timediff_t timeout_ms = DEFAULT_ACCEPT_TIMEOUT;
332   timediff_t other;
333   struct curltime now;
334
335   if(data->set.accepttimeout > 0)
336     timeout_ms = data->set.accepttimeout;
337
338   now = Curl_now();
339
340   /* check if the generic timeout possibly is set shorter */
341   other = Curl_timeleft(data, &now, FALSE);
342   if(other && (other < timeout_ms))
343     /* note that this also works fine for when other happens to be negative
344        due to it already having elapsed */
345     timeout_ms = other;
346   else {
347     /* subtract elapsed time */
348     timeout_ms -= Curl_timediff(now, data->progress.t_acceptdata);
349     if(!timeout_ms)
350       /* avoid returning 0 as that means no timeout! */
351       return -1;
352   }
353
354   return timeout_ms;
355 }
356
357
358 /***********************************************************************
359  *
360  * ReceivedServerConnect()
361  *
362  * After allowing server to connect to us from data port, this function
363  * checks both data connection for connection establishment and ctrl
364  * connection for a negative response regarding a failure in connecting
365  *
366  */
367 static CURLcode ReceivedServerConnect(struct Curl_easy *data, bool *received)
368 {
369   struct connectdata *conn = data->conn;
370   curl_socket_t ctrl_sock = conn->sock[FIRSTSOCKET];
371   curl_socket_t data_sock = conn->sock[SECONDARYSOCKET];
372   struct ftp_conn *ftpc = &conn->proto.ftpc;
373   struct pingpong *pp = &ftpc->pp;
374   int result;
375   timediff_t timeout_ms;
376   ssize_t nread;
377   int ftpcode;
378
379   *received = FALSE;
380
381   timeout_ms = ftp_timeleft_accept(data);
382   infof(data, "Checking for server connect");
383   if(timeout_ms < 0) {
384     /* if a timeout was already reached, bail out */
385     failf(data, "Accept timeout occurred while waiting server connect");
386     return CURLE_FTP_ACCEPT_TIMEOUT;
387   }
388
389   /* First check whether there is a cached response from server */
390   if(pp->cache_size && pp->cache && pp->cache[0] > '3') {
391     /* Data connection could not be established, let's return */
392     infof(data, "There is negative response in cache while serv connect");
393     (void)Curl_GetFTPResponse(data, &nread, &ftpcode);
394     return CURLE_FTP_ACCEPT_FAILED;
395   }
396
397   result = Curl_socket_check(ctrl_sock, data_sock, CURL_SOCKET_BAD, 0);
398
399   /* see if the connection request is already here */
400   switch(result) {
401   case -1: /* error */
402     /* let's die here */
403     failf(data, "Error while waiting for server connect");
404     return CURLE_FTP_ACCEPT_FAILED;
405   case 0:  /* Server connect is not received yet */
406     break; /* loop */
407   default:
408
409     if(result & CURL_CSELECT_IN2) {
410       infof(data, "Ready to accept data connection from server");
411       *received = TRUE;
412     }
413     else if(result & CURL_CSELECT_IN) {
414       infof(data, "Ctrl conn has data while waiting for data conn");
415       (void)Curl_GetFTPResponse(data, &nread, &ftpcode);
416
417       if(ftpcode/100 > 3)
418         return CURLE_FTP_ACCEPT_FAILED;
419
420       return CURLE_WEIRD_SERVER_REPLY;
421     }
422
423     break;
424   } /* switch() */
425
426   return CURLE_OK;
427 }
428
429
430 /***********************************************************************
431  *
432  * InitiateTransfer()
433  *
434  * After connection from server is accepted this function is called to
435  * setup transfer parameters and initiate the data transfer.
436  *
437  */
438 static CURLcode InitiateTransfer(struct Curl_easy *data)
439 {
440   CURLcode result = CURLE_OK;
441   struct connectdata *conn = data->conn;
442
443   if(conn->bits.ftp_use_data_ssl) {
444     /* since we only have a plaintext TCP connection here, we must now
445      * do the TLS stuff */
446     infof(data, "Doing the SSL/TLS handshake on the data stream");
447     result = Curl_ssl_connect(data, conn, SECONDARYSOCKET);
448     if(result)
449       return result;
450   }
451
452   if(conn->proto.ftpc.state_saved == FTP_STOR) {
453     /* When we know we're uploading a specified file, we can get the file
454        size prior to the actual upload. */
455     Curl_pgrsSetUploadSize(data, data->state.infilesize);
456
457     /* set the SO_SNDBUF for the secondary socket for those who need it */
458     Curl_sndbufset(conn->sock[SECONDARYSOCKET]);
459
460     Curl_setup_transfer(data, -1, -1, FALSE, SECONDARYSOCKET);
461   }
462   else {
463     /* FTP download: */
464     Curl_setup_transfer(data, SECONDARYSOCKET,
465                         conn->proto.ftpc.retr_size_saved, FALSE, -1);
466   }
467
468   conn->proto.ftpc.pp.pending_resp = TRUE; /* expect server response */
469   state(data, FTP_STOP);
470
471   return CURLE_OK;
472 }
473
474 /***********************************************************************
475  *
476  * AllowServerConnect()
477  *
478  * When we've issue the PORT command, we have told the server to connect to
479  * us. This function checks whether data connection is established if so it is
480  * accepted.
481  *
482  */
483 static CURLcode AllowServerConnect(struct Curl_easy *data, bool *connected)
484 {
485   timediff_t timeout_ms;
486   CURLcode result = CURLE_OK;
487
488   *connected = FALSE;
489   infof(data, "Preparing for accepting server on data port");
490
491   /* Save the time we start accepting server connect */
492   Curl_pgrsTime(data, TIMER_STARTACCEPT);
493
494   timeout_ms = ftp_timeleft_accept(data);
495   if(timeout_ms < 0) {
496     /* if a timeout was already reached, bail out */
497     failf(data, "Accept timeout occurred while waiting server connect");
498     return CURLE_FTP_ACCEPT_TIMEOUT;
499   }
500
501   /* see if the connection request is already here */
502   result = ReceivedServerConnect(data, connected);
503   if(result)
504     return result;
505
506   if(*connected) {
507     result = AcceptServerConnect(data);
508     if(result)
509       return result;
510
511     result = InitiateTransfer(data);
512     if(result)
513       return result;
514   }
515   else {
516     /* Add timeout to multi handle and break out of the loop */
517     if(*connected == FALSE) {
518       Curl_expire(data, data->set.accepttimeout > 0 ?
519                   data->set.accepttimeout: DEFAULT_ACCEPT_TIMEOUT, 0);
520     }
521   }
522
523   return result;
524 }
525
526 /* macro to check for a three-digit ftp status code at the start of the
527    given string */
528 #define STATUSCODE(line) (ISDIGIT(line[0]) && ISDIGIT(line[1]) &&       \
529                           ISDIGIT(line[2]))
530
531 /* macro to check for the last line in an FTP server response */
532 #define LASTLINE(line) (STATUSCODE(line) && (' ' == line[3]))
533
534 static bool ftp_endofresp(struct Curl_easy *data, struct connectdata *conn,
535                           char *line, size_t len, int *code)
536 {
537   (void)data;
538   (void)conn;
539
540   if((len > 3) && LASTLINE(line)) {
541     *code = curlx_sltosi(strtol(line, NULL, 10));
542     return TRUE;
543   }
544
545   return FALSE;
546 }
547
548 static CURLcode ftp_readresp(struct Curl_easy *data,
549                              curl_socket_t sockfd,
550                              struct pingpong *pp,
551                              int *ftpcode, /* return the ftp-code if done */
552                              size_t *size) /* size of the response */
553 {
554   int code;
555   CURLcode result = Curl_pp_readresp(data, sockfd, pp, &code, size);
556
557 #ifdef HAVE_GSSAPI
558   {
559     struct connectdata *conn = data->conn;
560     char * const buf = data->state.buffer;
561
562     /* handle the security-oriented responses 6xx ***/
563     switch(code) {
564     case 631:
565       code = Curl_sec_read_msg(data, conn, buf, PROT_SAFE);
566       break;
567     case 632:
568       code = Curl_sec_read_msg(data, conn, buf, PROT_PRIVATE);
569       break;
570     case 633:
571       code = Curl_sec_read_msg(data, conn, buf, PROT_CONFIDENTIAL);
572       break;
573     default:
574       /* normal ftp stuff we pass through! */
575       break;
576     }
577   }
578 #endif
579
580   /* store the latest code for later retrieval */
581   data->info.httpcode = code;
582
583   if(ftpcode)
584     *ftpcode = code;
585
586   if(421 == code) {
587     /* 421 means "Service not available, closing control connection." and FTP
588      * servers use it to signal that idle session timeout has been exceeded.
589      * If we ignored the response, it could end up hanging in some cases.
590      *
591      * This response code can come at any point so having it treated
592      * generically is a good idea.
593      */
594     infof(data, "We got a 421 - timeout");
595     state(data, FTP_STOP);
596     return CURLE_OPERATION_TIMEDOUT;
597   }
598
599   return result;
600 }
601
602 /* --- parse FTP server responses --- */
603
604 /*
605  * Curl_GetFTPResponse() is a BLOCKING function to read the full response
606  * from a server after a command.
607  *
608  */
609
610 CURLcode Curl_GetFTPResponse(struct Curl_easy *data,
611                              ssize_t *nreadp, /* return number of bytes read */
612                              int *ftpcode) /* return the ftp-code */
613 {
614   /*
615    * We cannot read just one byte per read() and then go back to select() as
616    * the OpenSSL read() doesn't grok that properly.
617    *
618    * Alas, read as much as possible, split up into lines, use the ending
619    * line in a response or continue reading.  */
620
621   struct connectdata *conn = data->conn;
622   curl_socket_t sockfd = conn->sock[FIRSTSOCKET];
623   CURLcode result = CURLE_OK;
624   struct ftp_conn *ftpc = &conn->proto.ftpc;
625   struct pingpong *pp = &ftpc->pp;
626   size_t nread;
627   int cache_skip = 0;
628   int value_to_be_ignored = 0;
629
630   if(ftpcode)
631     *ftpcode = 0; /* 0 for errors */
632   else
633     /* make the pointer point to something for the rest of this function */
634     ftpcode = &value_to_be_ignored;
635
636   *nreadp = 0;
637
638   while(!*ftpcode && !result) {
639     /* check and reset timeout value every lap */
640     timediff_t timeout = Curl_pp_state_timeout(data, pp, FALSE);
641     timediff_t interval_ms;
642
643     if(timeout <= 0) {
644       failf(data, "FTP response timeout");
645       return CURLE_OPERATION_TIMEDOUT; /* already too little time */
646     }
647
648     interval_ms = 1000;  /* use 1 second timeout intervals */
649     if(timeout < interval_ms)
650       interval_ms = timeout;
651
652     /*
653      * Since this function is blocking, we need to wait here for input on the
654      * connection and only then we call the response reading function. We do
655      * timeout at least every second to make the timeout check run.
656      *
657      * A caution here is that the ftp_readresp() function has a cache that may
658      * contain pieces of a response from the previous invoke and we need to
659      * make sure we don't just wait for input while there is unhandled data in
660      * that cache. But also, if the cache is there, we call ftp_readresp() and
661      * the cache wasn't good enough to continue we must not just busy-loop
662      * around this function.
663      *
664      */
665
666     if(pp->cache && (cache_skip < 2)) {
667       /*
668        * There's a cache left since before. We then skipping the wait for
669        * socket action, unless this is the same cache like the previous round
670        * as then the cache was deemed not enough to act on and we then need to
671        * wait for more data anyway.
672        */
673     }
674     else if(!Curl_conn_data_pending(conn, FIRSTSOCKET)) {
675       switch(SOCKET_READABLE(sockfd, interval_ms)) {
676       case -1: /* select() error, stop reading */
677         failf(data, "FTP response aborted due to select/poll error: %d",
678               SOCKERRNO);
679         return CURLE_RECV_ERROR;
680
681       case 0: /* timeout */
682         if(Curl_pgrsUpdate(data))
683           return CURLE_ABORTED_BY_CALLBACK;
684         continue; /* just continue in our loop for the timeout duration */
685
686       default: /* for clarity */
687         break;
688       }
689     }
690     result = ftp_readresp(data, sockfd, pp, ftpcode, &nread);
691     if(result)
692       break;
693
694     if(!nread && pp->cache)
695       /* bump cache skip counter as on repeated skips we must wait for more
696          data */
697       cache_skip++;
698     else
699       /* when we got data or there is no cache left, we reset the cache skip
700          counter */
701       cache_skip = 0;
702
703     *nreadp += nread;
704
705   } /* while there's buffer left and loop is requested */
706
707   pp->pending_resp = FALSE;
708
709   return result;
710 }
711
712 #if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
713   /* for debug purposes */
714 static const char * const ftp_state_names[]={
715   "STOP",
716   "WAIT220",
717   "AUTH",
718   "USER",
719   "PASS",
720   "ACCT",
721   "PBSZ",
722   "PROT",
723   "CCC",
724   "PWD",
725   "SYST",
726   "NAMEFMT",
727   "QUOTE",
728   "RETR_PREQUOTE",
729   "STOR_PREQUOTE",
730   "POSTQUOTE",
731   "CWD",
732   "MKD",
733   "MDTM",
734   "TYPE",
735   "LIST_TYPE",
736   "RETR_TYPE",
737   "STOR_TYPE",
738   "SIZE",
739   "RETR_SIZE",
740   "STOR_SIZE",
741   "REST",
742   "RETR_REST",
743   "PORT",
744   "PRET",
745   "PASV",
746   "LIST",
747   "RETR",
748   "STOR",
749   "QUIT"
750 };
751 #endif
752
753 /* This is the ONLY way to change FTP state! */
754 static void _state(struct Curl_easy *data,
755                    ftpstate newstate
756 #ifdef DEBUGBUILD
757                    , int lineno
758 #endif
759   )
760 {
761   struct connectdata *conn = data->conn;
762   struct ftp_conn *ftpc = &conn->proto.ftpc;
763
764 #if defined(DEBUGBUILD)
765
766 #if defined(CURL_DISABLE_VERBOSE_STRINGS)
767   (void) lineno;
768 #else
769   if(ftpc->state != newstate)
770     infof(data, "FTP %p (line %d) state change from %s to %s",
771           (void *)ftpc, lineno, ftp_state_names[ftpc->state],
772           ftp_state_names[newstate]);
773 #endif
774 #endif
775
776   ftpc->state = newstate;
777 }
778
779 static CURLcode ftp_state_user(struct Curl_easy *data,
780                                struct connectdata *conn)
781 {
782   CURLcode result = Curl_pp_sendf(data,
783                                   &conn->proto.ftpc.pp, "USER %s",
784                                   conn->user?conn->user:"");
785   if(!result) {
786     state(data, FTP_USER);
787     data->state.ftp_trying_alternative = FALSE;
788   }
789   return result;
790 }
791
792 static CURLcode ftp_state_pwd(struct Curl_easy *data,
793                               struct connectdata *conn)
794 {
795   CURLcode result = Curl_pp_sendf(data, &conn->proto.ftpc.pp, "%s", "PWD");
796   if(!result)
797     state(data, FTP_PWD);
798
799   return result;
800 }
801
802 /* For the FTP "protocol connect" and "doing" phases only */
803 static int ftp_getsock(struct Curl_easy *data,
804                        struct connectdata *conn,
805                        curl_socket_t *socks)
806 {
807   return Curl_pp_getsock(data, &conn->proto.ftpc.pp, socks);
808 }
809
810 /* For the FTP "DO_MORE" phase only */
811 static int ftp_domore_getsock(struct Curl_easy *data,
812                               struct connectdata *conn, curl_socket_t *socks)
813 {
814   struct ftp_conn *ftpc = &conn->proto.ftpc;
815   (void)data;
816
817   /* When in DO_MORE state, we could be either waiting for us to connect to a
818    * remote site, or we could wait for that site to connect to us. Or just
819    * handle ordinary commands.
820    */
821
822   if(SOCKS_STATE(conn->cnnct.state))
823     return Curl_SOCKS_getsock(conn, socks, SECONDARYSOCKET);
824
825   if(FTP_STOP == ftpc->state) {
826     int bits = GETSOCK_READSOCK(0);
827     bool any = FALSE;
828
829     /* if stopped and still in this state, then we're also waiting for a
830        connect on the secondary connection */
831     socks[0] = conn->sock[FIRSTSOCKET];
832
833     if(!data->set.ftp_use_port) {
834       int s;
835       int i;
836       /* PORT is used to tell the server to connect to us, and during that we
837          don't do happy eyeballs, but we do if we connect to the server */
838       for(s = 1, i = 0; i<2; i++) {
839         if(conn->tempsock[i] != CURL_SOCKET_BAD) {
840           socks[s] = conn->tempsock[i];
841           bits |= GETSOCK_WRITESOCK(s++);
842           any = TRUE;
843         }
844       }
845     }
846     if(!any) {
847       socks[1] = conn->sock[SECONDARYSOCKET];
848       bits |= GETSOCK_WRITESOCK(1) | GETSOCK_READSOCK(1);
849     }
850
851     return bits;
852   }
853   return Curl_pp_getsock(data, &conn->proto.ftpc.pp, socks);
854 }
855
856 /* This is called after the FTP_QUOTE state is passed.
857
858    ftp_state_cwd() sends the range of CWD commands to the server to change to
859    the correct directory. It may also need to send MKD commands to create
860    missing ones, if that option is enabled.
861 */
862 static CURLcode ftp_state_cwd(struct Curl_easy *data,
863                               struct connectdata *conn)
864 {
865   CURLcode result = CURLE_OK;
866   struct ftp_conn *ftpc = &conn->proto.ftpc;
867
868   if(ftpc->cwddone)
869     /* already done and fine */
870     result = ftp_state_mdtm(data);
871   else {
872     /* FTPFILE_NOCWD with full path: expect ftpc->cwddone! */
873     DEBUGASSERT((data->set.ftp_filemethod != FTPFILE_NOCWD) ||
874                 !(ftpc->dirdepth && ftpc->dirs[0][0] == '/'));
875
876     ftpc->count2 = 0; /* count2 counts failed CWDs */
877
878     if(conn->bits.reuse && ftpc->entrypath &&
879        /* no need to go to entrypath when we have an absolute path */
880        !(ftpc->dirdepth && ftpc->dirs[0][0] == '/')) {
881       /* This is a re-used connection. Since we change directory to where the
882          transfer is taking place, we must first get back to the original dir
883          where we ended up after login: */
884       ftpc->cwdcount = 0; /* we count this as the first path, then we add one
885                              for all upcoming ones in the ftp->dirs[] array */
886       result = Curl_pp_sendf(data, &ftpc->pp, "CWD %s", ftpc->entrypath);
887       if(!result)
888         state(data, FTP_CWD);
889     }
890     else {
891       if(ftpc->dirdepth) {
892         ftpc->cwdcount = 1;
893         /* issue the first CWD, the rest is sent when the CWD responses are
894            received... */
895         result = Curl_pp_sendf(data, &ftpc->pp, "CWD %s",
896                                ftpc->dirs[ftpc->cwdcount -1]);
897         if(!result)
898           state(data, FTP_CWD);
899       }
900       else {
901         /* No CWD necessary */
902         result = ftp_state_mdtm(data);
903       }
904     }
905   }
906   return result;
907 }
908
909 typedef enum {
910   EPRT,
911   PORT,
912   DONE
913 } ftpport;
914
915 static CURLcode ftp_state_use_port(struct Curl_easy *data,
916                                    ftpport fcmd) /* start with this */
917 {
918   CURLcode result = CURLE_OK;
919   struct connectdata *conn = data->conn;
920   struct ftp_conn *ftpc = &conn->proto.ftpc;
921   curl_socket_t portsock = CURL_SOCKET_BAD;
922   char myhost[MAX_IPADR_LEN + 1] = "";
923
924   struct Curl_sockaddr_storage ss;
925   struct Curl_addrinfo *res, *ai;
926   curl_socklen_t sslen;
927   char hbuf[NI_MAXHOST];
928   struct sockaddr *sa = (struct sockaddr *)&ss;
929   struct sockaddr_in * const sa4 = (void *)sa;
930 #ifdef ENABLE_IPV6
931   struct sockaddr_in6 * const sa6 = (void *)sa;
932 #endif
933   static const char mode[][5] = { "EPRT", "PORT" };
934   enum resolve_t rc;
935   int error;
936   char *host = NULL;
937   char *string_ftpport = data->set.str[STRING_FTPPORT];
938   struct Curl_dns_entry *h = NULL;
939   unsigned short port_min = 0;
940   unsigned short port_max = 0;
941   unsigned short port;
942   bool possibly_non_local = TRUE;
943   char buffer[STRERROR_LEN];
944   char *addr = NULL;
945
946   /* Step 1, figure out what is requested,
947    * accepted format :
948    * (ipv4|ipv6|domain|interface)?(:port(-range)?)?
949    */
950
951   if(data->set.str[STRING_FTPPORT] &&
952      (strlen(data->set.str[STRING_FTPPORT]) > 1)) {
953
954 #ifdef ENABLE_IPV6
955     size_t addrlen = INET6_ADDRSTRLEN > strlen(string_ftpport) ?
956       INET6_ADDRSTRLEN : strlen(string_ftpport);
957 #else
958     size_t addrlen = INET_ADDRSTRLEN > strlen(string_ftpport) ?
959       INET_ADDRSTRLEN : strlen(string_ftpport);
960 #endif
961     char *ip_start = string_ftpport;
962     char *ip_end = NULL;
963     char *port_start = NULL;
964     char *port_sep = NULL;
965
966     addr = calloc(addrlen + 1, 1);
967     if(!addr)
968       return CURLE_OUT_OF_MEMORY;
969
970 #ifdef ENABLE_IPV6
971     if(*string_ftpport == '[') {
972       /* [ipv6]:port(-range) */
973       ip_start = string_ftpport + 1;
974       ip_end = strchr(string_ftpport, ']');
975       if(ip_end)
976         strncpy(addr, ip_start, ip_end - ip_start);
977     }
978     else
979 #endif
980       if(*string_ftpport == ':') {
981         /* :port */
982         ip_end = string_ftpport;
983       }
984       else {
985         ip_end = strchr(string_ftpport, ':');
986         if(ip_end) {
987           /* either ipv6 or (ipv4|domain|interface):port(-range) */
988 #ifdef ENABLE_IPV6
989           if(Curl_inet_pton(AF_INET6, string_ftpport, sa6) == 1) {
990             /* ipv6 */
991             port_min = port_max = 0;
992             strcpy(addr, string_ftpport);
993             ip_end = NULL; /* this got no port ! */
994           }
995           else
996 #endif
997             /* (ipv4|domain|interface):port(-range) */
998             strncpy(addr, string_ftpport, ip_end - ip_start);
999         }
1000         else
1001           /* ipv4|interface */
1002           strcpy(addr, string_ftpport);
1003       }
1004
1005     /* parse the port */
1006     if(ip_end) {
1007       port_start = strchr(ip_end, ':');
1008       if(port_start) {
1009         port_min = curlx_ultous(strtoul(port_start + 1, NULL, 10));
1010         port_sep = strchr(port_start, '-');
1011         if(port_sep) {
1012           port_max = curlx_ultous(strtoul(port_sep + 1, NULL, 10));
1013         }
1014         else
1015           port_max = port_min;
1016       }
1017     }
1018
1019     /* correct errors like:
1020      *  :1234-1230
1021      *  :-4711,  in this case port_min is (unsigned)-1,
1022      *           therefore port_min > port_max for all cases
1023      *           but port_max = (unsigned)-1
1024      */
1025     if(port_min > port_max)
1026       port_min = port_max = 0;
1027
1028
1029     if(*addr != '\0') {
1030       /* attempt to get the address of the given interface name */
1031       switch(Curl_if2ip(conn->ip_addr->ai_family,
1032 #ifdef ENABLE_IPV6
1033                         Curl_ipv6_scope(conn->ip_addr->ai_addr),
1034                         conn->scope_id,
1035 #endif
1036                         addr, hbuf, sizeof(hbuf))) {
1037         case IF2IP_NOT_FOUND:
1038           /* not an interface, use the given string as host name instead */
1039           host = addr;
1040           break;
1041         case IF2IP_AF_NOT_SUPPORTED:
1042           return CURLE_FTP_PORT_FAILED;
1043         case IF2IP_FOUND:
1044           host = hbuf; /* use the hbuf for host name */
1045       }
1046     }
1047     else
1048       /* there was only a port(-range) given, default the host */
1049       host = NULL;
1050   } /* data->set.ftpport */
1051
1052   if(!host) {
1053     const char *r;
1054     /* not an interface and not a host name, get default by extracting
1055        the IP from the control connection */
1056     sslen = sizeof(ss);
1057     if(getsockname(conn->sock[FIRSTSOCKET], sa, &sslen)) {
1058       failf(data, "getsockname() failed: %s",
1059             Curl_strerror(SOCKERRNO, buffer, sizeof(buffer)));
1060       free(addr);
1061       return CURLE_FTP_PORT_FAILED;
1062     }
1063     switch(sa->sa_family) {
1064 #ifdef ENABLE_IPV6
1065     case AF_INET6:
1066       r = Curl_inet_ntop(sa->sa_family, &sa6->sin6_addr, hbuf, sizeof(hbuf));
1067       break;
1068 #endif
1069     default:
1070       r = Curl_inet_ntop(sa->sa_family, &sa4->sin_addr, hbuf, sizeof(hbuf));
1071       break;
1072     }
1073     if(!r)
1074       return CURLE_FTP_PORT_FAILED;
1075     host = hbuf; /* use this host name */
1076     possibly_non_local = FALSE; /* we know it is local now */
1077   }
1078
1079   /* resolv ip/host to ip */
1080   rc = Curl_resolv(data, host, 0, FALSE, &h);
1081   if(rc == CURLRESOLV_PENDING)
1082     (void)Curl_resolver_wait_resolv(data, &h);
1083   if(h) {
1084     res = h->addr;
1085     /* when we return from this function, we can forget about this entry
1086        to we can unlock it now already */
1087     Curl_resolv_unlock(data, h);
1088   } /* (h) */
1089   else
1090     res = NULL; /* failure! */
1091
1092   if(!res) {
1093     failf(data, "failed to resolve the address provided to PORT: %s", host);
1094     free(addr);
1095     return CURLE_FTP_PORT_FAILED;
1096   }
1097
1098   free(addr);
1099   host = NULL;
1100
1101   /* step 2, create a socket for the requested address */
1102
1103   portsock = CURL_SOCKET_BAD;
1104   error = 0;
1105   for(ai = res; ai; ai = ai->ai_next) {
1106     result = Curl_socket(data, ai, NULL, &portsock);
1107     if(result) {
1108       error = SOCKERRNO;
1109       continue;
1110     }
1111     break;
1112   }
1113   if(!ai) {
1114     failf(data, "socket failure: %s",
1115           Curl_strerror(error, buffer, sizeof(buffer)));
1116     return CURLE_FTP_PORT_FAILED;
1117   }
1118
1119   /* step 3, bind to a suitable local address */
1120
1121   memcpy(sa, ai->ai_addr, ai->ai_addrlen);
1122   sslen = ai->ai_addrlen;
1123
1124   for(port = port_min; port <= port_max;) {
1125     if(sa->sa_family == AF_INET)
1126       sa4->sin_port = htons(port);
1127 #ifdef ENABLE_IPV6
1128     else
1129       sa6->sin6_port = htons(port);
1130 #endif
1131     /* Try binding the given address. */
1132     if(bind(portsock, sa, sslen) ) {
1133       /* It failed. */
1134       error = SOCKERRNO;
1135       if(possibly_non_local && (error == EADDRNOTAVAIL)) {
1136         /* The requested bind address is not local.  Use the address used for
1137          * the control connection instead and restart the port loop
1138          */
1139         infof(data, "bind(port=%hu) on non-local address failed: %s", port,
1140               Curl_strerror(error, buffer, sizeof(buffer)));
1141
1142         sslen = sizeof(ss);
1143         if(getsockname(conn->sock[FIRSTSOCKET], sa, &sslen)) {
1144           failf(data, "getsockname() failed: %s",
1145                 Curl_strerror(SOCKERRNO, buffer, sizeof(buffer)));
1146           Curl_closesocket(data, conn, portsock);
1147           return CURLE_FTP_PORT_FAILED;
1148         }
1149         port = port_min;
1150         possibly_non_local = FALSE; /* don't try this again */
1151         continue;
1152       }
1153       if(error != EADDRINUSE && error != EACCES) {
1154         failf(data, "bind(port=%hu) failed: %s", port,
1155               Curl_strerror(error, buffer, sizeof(buffer)));
1156         Curl_closesocket(data, conn, portsock);
1157         return CURLE_FTP_PORT_FAILED;
1158       }
1159     }
1160     else
1161       break;
1162
1163     port++;
1164   }
1165
1166   /* maybe all ports were in use already*/
1167   if(port > port_max) {
1168     failf(data, "bind() failed, we ran out of ports");
1169     Curl_closesocket(data, conn, portsock);
1170     return CURLE_FTP_PORT_FAILED;
1171   }
1172
1173   /* get the name again after the bind() so that we can extract the
1174      port number it uses now */
1175   sslen = sizeof(ss);
1176   if(getsockname(portsock, (struct sockaddr *)sa, &sslen)) {
1177     failf(data, "getsockname() failed: %s",
1178           Curl_strerror(SOCKERRNO, buffer, sizeof(buffer)));
1179     Curl_closesocket(data, conn, portsock);
1180     return CURLE_FTP_PORT_FAILED;
1181   }
1182
1183   /* step 4, listen on the socket */
1184
1185   if(listen(portsock, 1)) {
1186     failf(data, "socket failure: %s",
1187           Curl_strerror(SOCKERRNO, buffer, sizeof(buffer)));
1188     Curl_closesocket(data, conn, portsock);
1189     return CURLE_FTP_PORT_FAILED;
1190   }
1191
1192   /* step 5, send the proper FTP command */
1193
1194   /* get a plain printable version of the numerical address to work with
1195      below */
1196   Curl_printable_address(ai, myhost, sizeof(myhost));
1197
1198 #ifdef ENABLE_IPV6
1199   if(!conn->bits.ftp_use_eprt && conn->bits.ipv6)
1200     /* EPRT is disabled but we are connected to a IPv6 host, so we ignore the
1201        request and enable EPRT again! */
1202     conn->bits.ftp_use_eprt = TRUE;
1203 #endif
1204
1205   for(; fcmd != DONE; fcmd++) {
1206
1207     if(!conn->bits.ftp_use_eprt && (EPRT == fcmd))
1208       /* if disabled, goto next */
1209       continue;
1210
1211     if((PORT == fcmd) && sa->sa_family != AF_INET)
1212       /* PORT is IPv4 only */
1213       continue;
1214
1215     switch(sa->sa_family) {
1216     case AF_INET:
1217       port = ntohs(sa4->sin_port);
1218       break;
1219 #ifdef ENABLE_IPV6
1220     case AF_INET6:
1221       port = ntohs(sa6->sin6_port);
1222       break;
1223 #endif
1224     default:
1225       continue; /* might as well skip this */
1226     }
1227
1228     if(EPRT == fcmd) {
1229       /*
1230        * Two fine examples from RFC2428;
1231        *
1232        * EPRT |1|132.235.1.2|6275|
1233        *
1234        * EPRT |2|1080::8:800:200C:417A|5282|
1235        */
1236
1237       result = Curl_pp_sendf(data, &ftpc->pp, "%s |%d|%s|%hu|", mode[fcmd],
1238                              sa->sa_family == AF_INET?1:2,
1239                              myhost, port);
1240       if(result) {
1241         failf(data, "Failure sending EPRT command: %s",
1242               curl_easy_strerror(result));
1243         Curl_closesocket(data, conn, portsock);
1244         /* don't retry using PORT */
1245         ftpc->count1 = PORT;
1246         /* bail out */
1247         state(data, FTP_STOP);
1248         return result;
1249       }
1250       break;
1251     }
1252     if(PORT == fcmd) {
1253       /* large enough for [IP address],[num],[num] */
1254       char target[sizeof(myhost) + 20];
1255       char *source = myhost;
1256       char *dest = target;
1257
1258       /* translate x.x.x.x to x,x,x,x */
1259       while(source && *source) {
1260         if(*source == '.')
1261           *dest = ',';
1262         else
1263           *dest = *source;
1264         dest++;
1265         source++;
1266       }
1267       *dest = 0;
1268       msnprintf(dest, 20, ",%d,%d", (int)(port>>8), (int)(port&0xff));
1269
1270       result = Curl_pp_sendf(data, &ftpc->pp, "%s %s", mode[fcmd], target);
1271       if(result) {
1272         failf(data, "Failure sending PORT command: %s",
1273               curl_easy_strerror(result));
1274         Curl_closesocket(data, conn, portsock);
1275         /* bail out */
1276         state(data, FTP_STOP);
1277         return result;
1278       }
1279       break;
1280     }
1281   }
1282
1283   /* store which command was sent */
1284   ftpc->count1 = fcmd;
1285
1286   close_secondarysocket(data, conn);
1287
1288   /* we set the secondary socket variable to this for now, it is only so that
1289      the cleanup function will close it in case we fail before the true
1290      secondary stuff is made */
1291   conn->sock[SECONDARYSOCKET] = portsock;
1292
1293   /* this tcpconnect assignment below is a hackish work-around to make the
1294      multi interface with active FTP work - as it will not wait for a
1295      (passive) connect in Curl_is_connected().
1296
1297      The *proper* fix is to make sure that the active connection from the
1298      server is done in a non-blocking way. Currently, it is still BLOCKING.
1299   */
1300   conn->bits.tcpconnect[SECONDARYSOCKET] = TRUE;
1301
1302   state(data, FTP_PORT);
1303   return result;
1304 }
1305
1306 static CURLcode ftp_state_use_pasv(struct Curl_easy *data,
1307                                    struct connectdata *conn)
1308 {
1309   struct ftp_conn *ftpc = &conn->proto.ftpc;
1310   CURLcode result = CURLE_OK;
1311   /*
1312     Here's the executive summary on what to do:
1313
1314     PASV is RFC959, expect:
1315     227 Entering Passive Mode (a1,a2,a3,a4,p1,p2)
1316
1317     LPSV is RFC1639, expect:
1318     228 Entering Long Passive Mode (4,4,a1,a2,a3,a4,2,p1,p2)
1319
1320     EPSV is RFC2428, expect:
1321     229 Entering Extended Passive Mode (|||port|)
1322
1323   */
1324
1325   static const char mode[][5] = { "EPSV", "PASV" };
1326   int modeoff;
1327
1328 #ifdef PF_INET6
1329   if(!conn->bits.ftp_use_epsv && conn->bits.ipv6)
1330     /* EPSV is disabled but we are connected to a IPv6 host, so we ignore the
1331        request and enable EPSV again! */
1332     conn->bits.ftp_use_epsv = TRUE;
1333 #endif
1334
1335   modeoff = conn->bits.ftp_use_epsv?0:1;
1336
1337   result = Curl_pp_sendf(data, &ftpc->pp, "%s", mode[modeoff]);
1338   if(!result) {
1339     ftpc->count1 = modeoff;
1340     state(data, FTP_PASV);
1341     infof(data, "Connect data stream passively");
1342   }
1343   return result;
1344 }
1345
1346 /*
1347  * ftp_state_prepare_transfer() starts PORT, PASV or PRET etc.
1348  *
1349  * REST is the last command in the chain of commands when a "head"-like
1350  * request is made. Thus, if an actual transfer is to be made this is where we
1351  * take off for real.
1352  */
1353 static CURLcode ftp_state_prepare_transfer(struct Curl_easy *data)
1354 {
1355   CURLcode result = CURLE_OK;
1356   struct FTP *ftp = data->req.p.ftp;
1357   struct connectdata *conn = data->conn;
1358
1359   if(ftp->transfer != PPTRANSFER_BODY) {
1360     /* doesn't transfer any data */
1361
1362     /* still possibly do PRE QUOTE jobs */
1363     state(data, FTP_RETR_PREQUOTE);
1364     result = ftp_state_quote(data, TRUE, FTP_RETR_PREQUOTE);
1365   }
1366   else if(data->set.ftp_use_port) {
1367     /* We have chosen to use the PORT (or similar) command */
1368     result = ftp_state_use_port(data, EPRT);
1369   }
1370   else {
1371     /* We have chosen (this is default) to use the PASV (or similar) command */
1372     if(data->set.ftp_use_pret) {
1373       /* The user has requested that we send a PRET command
1374          to prepare the server for the upcoming PASV */
1375       struct ftp_conn *ftpc = &conn->proto.ftpc;
1376       if(!conn->proto.ftpc.file)
1377         result = Curl_pp_sendf(data, &ftpc->pp, "PRET %s",
1378                                data->set.str[STRING_CUSTOMREQUEST]?
1379                                data->set.str[STRING_CUSTOMREQUEST]:
1380                                (data->state.list_only?"NLST":"LIST"));
1381       else if(data->set.upload)
1382         result = Curl_pp_sendf(data, &ftpc->pp, "PRET STOR %s",
1383                                conn->proto.ftpc.file);
1384       else
1385         result = Curl_pp_sendf(data, &ftpc->pp, "PRET RETR %s",
1386                                conn->proto.ftpc.file);
1387       if(!result)
1388         state(data, FTP_PRET);
1389     }
1390     else
1391       result = ftp_state_use_pasv(data, conn);
1392   }
1393   return result;
1394 }
1395
1396 static CURLcode ftp_state_rest(struct Curl_easy *data,
1397                                struct connectdata *conn)
1398 {
1399   CURLcode result = CURLE_OK;
1400   struct FTP *ftp = data->req.p.ftp;
1401   struct ftp_conn *ftpc = &conn->proto.ftpc;
1402
1403   if((ftp->transfer != PPTRANSFER_BODY) && ftpc->file) {
1404     /* if a "head"-like request is being made (on a file) */
1405
1406     /* Determine if server can respond to REST command and therefore
1407        whether it supports range */
1408     result = Curl_pp_sendf(data, &ftpc->pp, "REST %d", 0);
1409     if(!result)
1410       state(data, FTP_REST);
1411   }
1412   else
1413     result = ftp_state_prepare_transfer(data);
1414
1415   return result;
1416 }
1417
1418 static CURLcode ftp_state_size(struct Curl_easy *data,
1419                                struct connectdata *conn)
1420 {
1421   CURLcode result = CURLE_OK;
1422   struct FTP *ftp = data->req.p.ftp;
1423   struct ftp_conn *ftpc = &conn->proto.ftpc;
1424
1425   if((ftp->transfer == PPTRANSFER_INFO) && ftpc->file) {
1426     /* if a "head"-like request is being made (on a file) */
1427
1428     /* we know ftpc->file is a valid pointer to a file name */
1429     result = Curl_pp_sendf(data, &ftpc->pp, "SIZE %s", ftpc->file);
1430     if(!result)
1431       state(data, FTP_SIZE);
1432   }
1433   else
1434     result = ftp_state_rest(data, conn);
1435
1436   return result;
1437 }
1438
1439 static CURLcode ftp_state_list(struct Curl_easy *data)
1440 {
1441   CURLcode result = CURLE_OK;
1442   struct FTP *ftp = data->req.p.ftp;
1443   struct connectdata *conn = data->conn;
1444
1445   /* If this output is to be machine-parsed, the NLST command might be better
1446      to use, since the LIST command output is not specified or standard in any
1447      way. It has turned out that the NLST list output is not the same on all
1448      servers either... */
1449
1450   /*
1451      if FTPFILE_NOCWD was specified, we should add the path
1452      as argument for the LIST / NLST / or custom command.
1453      Whether the server will support this, is uncertain.
1454
1455      The other ftp_filemethods will CWD into dir/dir/ first and
1456      then just do LIST (in that case: nothing to do here)
1457   */
1458   char *lstArg = NULL;
1459   char *cmd;
1460
1461   if((data->set.ftp_filemethod == FTPFILE_NOCWD) && ftp->path) {
1462     /* url-decode before evaluation: e.g. paths starting/ending with %2f */
1463     const char *slashPos = NULL;
1464     char *rawPath = NULL;
1465     result = Curl_urldecode(ftp->path, 0, &rawPath, NULL, REJECT_CTRL);
1466     if(result)
1467       return result;
1468
1469     slashPos = strrchr(rawPath, '/');
1470     if(slashPos) {
1471       /* chop off the file part if format is dir/file otherwise remove
1472          the trailing slash for dir/dir/ except for absolute path / */
1473       size_t n = slashPos - rawPath;
1474       if(n == 0)
1475         ++n;
1476
1477       lstArg = rawPath;
1478       lstArg[n] = '\0';
1479     }
1480     else
1481       free(rawPath);
1482   }
1483
1484   cmd = aprintf("%s%s%s",
1485                 data->set.str[STRING_CUSTOMREQUEST]?
1486                 data->set.str[STRING_CUSTOMREQUEST]:
1487                 (data->state.list_only?"NLST":"LIST"),
1488                 lstArg? " ": "",
1489                 lstArg? lstArg: "");
1490   free(lstArg);
1491
1492   if(!cmd)
1493     return CURLE_OUT_OF_MEMORY;
1494
1495   result = Curl_pp_sendf(data, &conn->proto.ftpc.pp, "%s", cmd);
1496   free(cmd);
1497
1498   if(!result)
1499     state(data, FTP_LIST);
1500
1501   return result;
1502 }
1503
1504 static CURLcode ftp_state_retr_prequote(struct Curl_easy *data)
1505 {
1506   /* We've sent the TYPE, now we must send the list of prequote strings */
1507   return ftp_state_quote(data, TRUE, FTP_RETR_PREQUOTE);
1508 }
1509
1510 static CURLcode ftp_state_stor_prequote(struct Curl_easy *data)
1511 {
1512   /* We've sent the TYPE, now we must send the list of prequote strings */
1513   return ftp_state_quote(data, TRUE, FTP_STOR_PREQUOTE);
1514 }
1515
1516 static CURLcode ftp_state_type(struct Curl_easy *data)
1517 {
1518   CURLcode result = CURLE_OK;
1519   struct FTP *ftp = data->req.p.ftp;
1520   struct connectdata *conn = data->conn;
1521   struct ftp_conn *ftpc = &conn->proto.ftpc;
1522
1523   /* If we have selected NOBODY and HEADER, it means that we only want file
1524      information. Which in FTP can't be much more than the file size and
1525      date. */
1526   if(data->set.opt_no_body && ftpc->file &&
1527      ftp_need_type(conn, data->state.prefer_ascii)) {
1528     /* The SIZE command is _not_ RFC 959 specified, and therefore many servers
1529        may not support it! It is however the only way we have to get a file's
1530        size! */
1531
1532     ftp->transfer = PPTRANSFER_INFO;
1533     /* this means no actual transfer will be made */
1534
1535     /* Some servers return different sizes for different modes, and thus we
1536        must set the proper type before we check the size */
1537     result = ftp_nb_type(data, conn, data->state.prefer_ascii, FTP_TYPE);
1538     if(result)
1539       return result;
1540   }
1541   else
1542     result = ftp_state_size(data, conn);
1543
1544   return result;
1545 }
1546
1547 /* This is called after the CWD commands have been done in the beginning of
1548    the DO phase */
1549 static CURLcode ftp_state_mdtm(struct Curl_easy *data)
1550 {
1551   CURLcode result = CURLE_OK;
1552   struct connectdata *conn = data->conn;
1553   struct ftp_conn *ftpc = &conn->proto.ftpc;
1554
1555   /* Requested time of file or time-depended transfer? */
1556   if((data->set.get_filetime || data->set.timecondition) && ftpc->file) {
1557
1558     /* we have requested to get the modified-time of the file, this is a white
1559        spot as the MDTM is not mentioned in RFC959 */
1560     result = Curl_pp_sendf(data, &ftpc->pp, "MDTM %s", ftpc->file);
1561
1562     if(!result)
1563       state(data, FTP_MDTM);
1564   }
1565   else
1566     result = ftp_state_type(data);
1567
1568   return result;
1569 }
1570
1571
1572 /* This is called after the TYPE and possible quote commands have been sent */
1573 static CURLcode ftp_state_ul_setup(struct Curl_easy *data,
1574                                    bool sizechecked)
1575 {
1576   CURLcode result = CURLE_OK;
1577   struct connectdata *conn = data->conn;
1578   struct FTP *ftp = data->req.p.ftp;
1579   struct ftp_conn *ftpc = &conn->proto.ftpc;
1580   bool append = data->set.remote_append;
1581
1582   if((data->state.resume_from && !sizechecked) ||
1583      ((data->state.resume_from > 0) && sizechecked)) {
1584     /* we're about to continue the uploading of a file */
1585     /* 1. get already existing file's size. We use the SIZE command for this
1586        which may not exist in the server!  The SIZE command is not in
1587        RFC959. */
1588
1589     /* 2. This used to set REST. But since we can do append, we
1590        don't another ftp command. We just skip the source file
1591        offset and then we APPEND the rest on the file instead */
1592
1593     /* 3. pass file-size number of bytes in the source file */
1594     /* 4. lower the infilesize counter */
1595     /* => transfer as usual */
1596     int seekerr = CURL_SEEKFUNC_OK;
1597
1598     if(data->state.resume_from < 0) {
1599       /* Got no given size to start from, figure it out */
1600       result = Curl_pp_sendf(data, &ftpc->pp, "SIZE %s", ftpc->file);
1601       if(!result)
1602         state(data, FTP_STOR_SIZE);
1603       return result;
1604     }
1605
1606     /* enable append */
1607     append = TRUE;
1608
1609     /* Let's read off the proper amount of bytes from the input. */
1610     if(conn->seek_func) {
1611       Curl_set_in_callback(data, true);
1612       seekerr = conn->seek_func(conn->seek_client, data->state.resume_from,
1613                                 SEEK_SET);
1614       Curl_set_in_callback(data, false);
1615     }
1616
1617     if(seekerr != CURL_SEEKFUNC_OK) {
1618       curl_off_t passed = 0;
1619       if(seekerr != CURL_SEEKFUNC_CANTSEEK) {
1620         failf(data, "Could not seek stream");
1621         return CURLE_FTP_COULDNT_USE_REST;
1622       }
1623       /* seekerr == CURL_SEEKFUNC_CANTSEEK (can't seek to offset) */
1624       do {
1625         size_t readthisamountnow =
1626           (data->state.resume_from - passed > data->set.buffer_size) ?
1627           (size_t)data->set.buffer_size :
1628           curlx_sotouz(data->state.resume_from - passed);
1629
1630         size_t actuallyread =
1631           data->state.fread_func(data->state.buffer, 1, readthisamountnow,
1632                                  data->state.in);
1633
1634         passed += actuallyread;
1635         if((actuallyread == 0) || (actuallyread > readthisamountnow)) {
1636           /* this checks for greater-than only to make sure that the
1637              CURL_READFUNC_ABORT return code still aborts */
1638           failf(data, "Failed to read data");
1639           return CURLE_FTP_COULDNT_USE_REST;
1640         }
1641       } while(passed < data->state.resume_from);
1642     }
1643     /* now, decrease the size of the read */
1644     if(data->state.infilesize>0) {
1645       data->state.infilesize -= data->state.resume_from;
1646
1647       if(data->state.infilesize <= 0) {
1648         infof(data, "File already completely uploaded");
1649
1650         /* no data to transfer */
1651         Curl_setup_transfer(data, -1, -1, FALSE, -1);
1652
1653         /* Set ->transfer so that we won't get any error in
1654          * ftp_done() because we didn't transfer anything! */
1655         ftp->transfer = PPTRANSFER_NONE;
1656
1657         state(data, FTP_STOP);
1658         return CURLE_OK;
1659       }
1660     }
1661     /* we've passed, proceed as normal */
1662   } /* resume_from */
1663
1664   result = Curl_pp_sendf(data, &ftpc->pp, append?"APPE %s":"STOR %s",
1665                          ftpc->file);
1666   if(!result)
1667     state(data, FTP_STOR);
1668
1669   return result;
1670 }
1671
1672 static CURLcode ftp_state_quote(struct Curl_easy *data,
1673                                 bool init,
1674                                 ftpstate instate)
1675 {
1676   CURLcode result = CURLE_OK;
1677   struct FTP *ftp = data->req.p.ftp;
1678   struct connectdata *conn = data->conn;
1679   struct ftp_conn *ftpc = &conn->proto.ftpc;
1680   bool quote = FALSE;
1681   struct curl_slist *item;
1682
1683   switch(instate) {
1684   case FTP_QUOTE:
1685   default:
1686     item = data->set.quote;
1687     break;
1688   case FTP_RETR_PREQUOTE:
1689   case FTP_STOR_PREQUOTE:
1690     item = data->set.prequote;
1691     break;
1692   case FTP_POSTQUOTE:
1693     item = data->set.postquote;
1694     break;
1695   }
1696
1697   /*
1698    * This state uses:
1699    * 'count1' to iterate over the commands to send
1700    * 'count2' to store whether to allow commands to fail
1701    */
1702
1703   if(init)
1704     ftpc->count1 = 0;
1705   else
1706     ftpc->count1++;
1707
1708   if(item) {
1709     int i = 0;
1710
1711     /* Skip count1 items in the linked list */
1712     while((i< ftpc->count1) && item) {
1713       item = item->next;
1714       i++;
1715     }
1716     if(item) {
1717       char *cmd = item->data;
1718       if(cmd[0] == '*') {
1719         cmd++;
1720         ftpc->count2 = 1; /* the sent command is allowed to fail */
1721       }
1722       else
1723         ftpc->count2 = 0; /* failure means cancel operation */
1724
1725       result = Curl_pp_sendf(data, &ftpc->pp, "%s", cmd);
1726       if(result)
1727         return result;
1728       state(data, instate);
1729       quote = TRUE;
1730     }
1731   }
1732
1733   if(!quote) {
1734     /* No more quote to send, continue to ... */
1735     switch(instate) {
1736     case FTP_QUOTE:
1737     default:
1738       result = ftp_state_cwd(data, conn);
1739       break;
1740     case FTP_RETR_PREQUOTE:
1741       if(ftp->transfer != PPTRANSFER_BODY)
1742         state(data, FTP_STOP);
1743       else {
1744         if(ftpc->known_filesize != -1) {
1745           Curl_pgrsSetDownloadSize(data, ftpc->known_filesize);
1746           result = ftp_state_retr(data, ftpc->known_filesize);
1747         }
1748         else {
1749           if(data->set.ignorecl || data->state.prefer_ascii) {
1750             /* 'ignorecl' is used to support download of growing files.  It
1751                prevents the state machine from requesting the file size from
1752                the server.  With an unknown file size the download continues
1753                until the server terminates it, otherwise the client stops if
1754                the received byte count exceeds the reported file size.  Set
1755                option CURLOPT_IGNORE_CONTENT_LENGTH to 1 to enable this
1756                behavior.
1757
1758                In addition: asking for the size for 'TYPE A' transfers is not
1759                constructive since servers don't report the converted size. So
1760                skip it.
1761             */
1762             result = Curl_pp_sendf(data, &ftpc->pp, "RETR %s", ftpc->file);
1763             if(!result)
1764               state(data, FTP_RETR);
1765           }
1766           else {
1767             result = Curl_pp_sendf(data, &ftpc->pp, "SIZE %s", ftpc->file);
1768             if(!result)
1769               state(data, FTP_RETR_SIZE);
1770           }
1771         }
1772       }
1773       break;
1774     case FTP_STOR_PREQUOTE:
1775       result = ftp_state_ul_setup(data, FALSE);
1776       break;
1777     case FTP_POSTQUOTE:
1778       break;
1779     }
1780   }
1781
1782   return result;
1783 }
1784
1785 /* called from ftp_state_pasv_resp to switch to PASV in case of EPSV
1786    problems */
1787 static CURLcode ftp_epsv_disable(struct Curl_easy *data,
1788                                  struct connectdata *conn)
1789 {
1790   CURLcode result = CURLE_OK;
1791
1792   if(conn->bits.ipv6
1793 #ifndef CURL_DISABLE_PROXY
1794      && !(conn->bits.tunnel_proxy || conn->bits.socksproxy)
1795 #endif
1796     ) {
1797     /* We can't disable EPSV when doing IPv6, so this is instead a fail */
1798     failf(data, "Failed EPSV attempt, exiting");
1799     return CURLE_WEIRD_SERVER_REPLY;
1800   }
1801
1802   infof(data, "Failed EPSV attempt. Disabling EPSV");
1803   /* disable it for next transfer */
1804   conn->bits.ftp_use_epsv = FALSE;
1805   data->state.errorbuf = FALSE; /* allow error message to get
1806                                          rewritten */
1807   result = Curl_pp_sendf(data, &conn->proto.ftpc.pp, "%s", "PASV");
1808   if(!result) {
1809     conn->proto.ftpc.count1++;
1810     /* remain in/go to the FTP_PASV state */
1811     state(data, FTP_PASV);
1812   }
1813   return result;
1814 }
1815
1816
1817 static char *control_address(struct connectdata *conn)
1818 {
1819   /* Returns the control connection IP address.
1820      If a proxy tunnel is used, returns the original host name instead, because
1821      the effective control connection address is the proxy address,
1822      not the ftp host. */
1823 #ifndef CURL_DISABLE_PROXY
1824   if(conn->bits.tunnel_proxy || conn->bits.socksproxy)
1825     return conn->host.name;
1826 #endif
1827   return conn->primary_ip;
1828 }
1829
1830 static CURLcode ftp_state_pasv_resp(struct Curl_easy *data,
1831                                     int ftpcode)
1832 {
1833   struct connectdata *conn = data->conn;
1834   struct ftp_conn *ftpc = &conn->proto.ftpc;
1835   CURLcode result;
1836   struct Curl_dns_entry *addr = NULL;
1837   enum resolve_t rc;
1838   unsigned short connectport; /* the local port connect() should use! */
1839   char *str = &data->state.buffer[4];  /* start on the first letter */
1840
1841   /* if we come here again, make sure the former name is cleared */
1842   Curl_safefree(ftpc->newhost);
1843
1844   if((ftpc->count1 == 0) &&
1845      (ftpcode == 229)) {
1846     /* positive EPSV response */
1847     char *ptr = strchr(str, '(');
1848     if(ptr) {
1849       unsigned int num;
1850       char separator[4];
1851       ptr++;
1852       if(5 == sscanf(ptr, "%c%c%c%u%c",
1853                      &separator[0],
1854                      &separator[1],
1855                      &separator[2],
1856                      &num,
1857                      &separator[3])) {
1858         const char sep1 = separator[0];
1859         int i;
1860
1861         /* The four separators should be identical, or else this is an oddly
1862            formatted reply and we bail out immediately. */
1863         for(i = 1; i<4; i++) {
1864           if(separator[i] != sep1) {
1865             ptr = NULL; /* set to NULL to signal error */
1866             break;
1867           }
1868         }
1869         if(num > 0xffff) {
1870           failf(data, "Illegal port number in EPSV reply");
1871           return CURLE_FTP_WEIRD_PASV_REPLY;
1872         }
1873         if(ptr) {
1874           ftpc->newport = (unsigned short)(num & 0xffff);
1875           ftpc->newhost = strdup(control_address(conn));
1876           if(!ftpc->newhost)
1877             return CURLE_OUT_OF_MEMORY;
1878         }
1879       }
1880       else
1881         ptr = NULL;
1882     }
1883     if(!ptr) {
1884       failf(data, "Weirdly formatted EPSV reply");
1885       return CURLE_FTP_WEIRD_PASV_REPLY;
1886     }
1887   }
1888   else if((ftpc->count1 == 1) &&
1889           (ftpcode == 227)) {
1890     /* positive PASV response */
1891     unsigned int ip[4] = {0, 0, 0, 0};
1892     unsigned int port[2] = {0, 0};
1893
1894     /*
1895      * Scan for a sequence of six comma-separated numbers and use them as
1896      * IP+port indicators.
1897      *
1898      * Found reply-strings include:
1899      * "227 Entering Passive Mode (127,0,0,1,4,51)"
1900      * "227 Data transfer will passively listen to 127,0,0,1,4,51"
1901      * "227 Entering passive mode. 127,0,0,1,4,51"
1902      */
1903     while(*str) {
1904       if(6 == sscanf(str, "%u,%u,%u,%u,%u,%u",
1905                      &ip[0], &ip[1], &ip[2], &ip[3],
1906                      &port[0], &port[1]))
1907         break;
1908       str++;
1909     }
1910
1911     if(!*str || (ip[0] > 255) || (ip[1] > 255)  || (ip[2] > 255)  ||
1912        (ip[3] > 255) || (port[0] > 255)  || (port[1] > 255) ) {
1913       failf(data, "Couldn't interpret the 227-response");
1914       return CURLE_FTP_WEIRD_227_FORMAT;
1915     }
1916
1917     /* we got OK from server */
1918     if(data->set.ftp_skip_ip) {
1919       /* told to ignore the remotely given IP but instead use the host we used
1920          for the control connection */
1921       infof(data, "Skip %u.%u.%u.%u for data connection, re-use %s instead",
1922             ip[0], ip[1], ip[2], ip[3],
1923             conn->host.name);
1924       ftpc->newhost = strdup(control_address(conn));
1925     }
1926     else
1927       ftpc->newhost = aprintf("%u.%u.%u.%u", ip[0], ip[1], ip[2], ip[3]);
1928
1929     if(!ftpc->newhost)
1930       return CURLE_OUT_OF_MEMORY;
1931
1932     ftpc->newport = (unsigned short)(((port[0]<<8) + port[1]) & 0xffff);
1933   }
1934   else if(ftpc->count1 == 0) {
1935     /* EPSV failed, move on to PASV */
1936     return ftp_epsv_disable(data, conn);
1937   }
1938   else {
1939     failf(data, "Bad PASV/EPSV response: %03d", ftpcode);
1940     return CURLE_FTP_WEIRD_PASV_REPLY;
1941   }
1942
1943 #ifndef CURL_DISABLE_PROXY
1944   if(conn->bits.proxy) {
1945     /*
1946      * This connection uses a proxy and we need to connect to the proxy again
1947      * here. We don't want to rely on a former host lookup that might've
1948      * expired now, instead we remake the lookup here and now!
1949      */
1950     const char * const host_name = conn->bits.socksproxy ?
1951       conn->socks_proxy.host.name : conn->http_proxy.host.name;
1952     rc = Curl_resolv(data, host_name, (int)conn->port, FALSE, &addr);
1953     if(rc == CURLRESOLV_PENDING)
1954       /* BLOCKING, ignores the return code but 'addr' will be NULL in
1955          case of failure */
1956       (void)Curl_resolver_wait_resolv(data, &addr);
1957
1958     connectport =
1959       (unsigned short)conn->port; /* we connect to the proxy's port */
1960
1961     if(!addr) {
1962       failf(data, "Can't resolve proxy host %s:%hu", host_name, connectport);
1963       return CURLE_COULDNT_RESOLVE_PROXY;
1964     }
1965   }
1966   else
1967 #endif
1968   {
1969     /* normal, direct, ftp connection */
1970     DEBUGASSERT(ftpc->newhost);
1971
1972     /* postponed address resolution in case of tcp fastopen */
1973     if(conn->bits.tcp_fastopen && !conn->bits.reuse && !ftpc->newhost[0]) {
1974       Curl_conninfo_remote(data, conn, conn->sock[FIRSTSOCKET]);
1975       Curl_safefree(ftpc->newhost);
1976       ftpc->newhost = strdup(control_address(conn));
1977       if(!ftpc->newhost)
1978         return CURLE_OUT_OF_MEMORY;
1979     }
1980
1981     rc = Curl_resolv(data, ftpc->newhost, ftpc->newport, FALSE, &addr);
1982     if(rc == CURLRESOLV_PENDING)
1983       /* BLOCKING */
1984       (void)Curl_resolver_wait_resolv(data, &addr);
1985
1986     connectport = ftpc->newport; /* we connect to the remote port */
1987
1988     if(!addr) {
1989       failf(data, "Can't resolve new host %s:%hu", ftpc->newhost, connectport);
1990       return CURLE_FTP_CANT_GET_HOST;
1991     }
1992   }
1993
1994   conn->bits.tcpconnect[SECONDARYSOCKET] = FALSE;
1995   result = Curl_connecthost(data, conn, addr);
1996
1997   if(result) {
1998     Curl_resolv_unlock(data, addr); /* we're done using this address */
1999     if(ftpc->count1 == 0 && ftpcode == 229)
2000       return ftp_epsv_disable(data, conn);
2001
2002     return result;
2003   }
2004
2005
2006   /*
2007    * When this is used from the multi interface, this might've returned with
2008    * the 'connected' set to FALSE and thus we are now awaiting a non-blocking
2009    * connect to connect.
2010    */
2011
2012   if(data->set.verbose)
2013     /* this just dumps information about this second connection */
2014     ftp_pasv_verbose(data, addr->addr, ftpc->newhost, connectport);
2015
2016   Curl_resolv_unlock(data, addr); /* we're done using this address */
2017
2018   Curl_safefree(conn->secondaryhostname);
2019   conn->secondary_port = ftpc->newport;
2020   conn->secondaryhostname = strdup(ftpc->newhost);
2021   if(!conn->secondaryhostname)
2022     return CURLE_OUT_OF_MEMORY;
2023
2024   conn->bits.do_more = TRUE;
2025   state(data, FTP_STOP); /* this phase is completed */
2026
2027   return result;
2028 }
2029
2030 static CURLcode ftp_state_port_resp(struct Curl_easy *data,
2031                                     int ftpcode)
2032 {
2033   struct connectdata *conn = data->conn;
2034   struct ftp_conn *ftpc = &conn->proto.ftpc;
2035   ftpport fcmd = (ftpport)ftpc->count1;
2036   CURLcode result = CURLE_OK;
2037
2038   /* The FTP spec tells a positive response should have code 200.
2039      Be more permissive here to tolerate deviant servers. */
2040   if(ftpcode / 100 != 2) {
2041     /* the command failed */
2042
2043     if(EPRT == fcmd) {
2044       infof(data, "disabling EPRT usage");
2045       conn->bits.ftp_use_eprt = FALSE;
2046     }
2047     fcmd++;
2048
2049     if(fcmd == DONE) {
2050       failf(data, "Failed to do PORT");
2051       result = CURLE_FTP_PORT_FAILED;
2052     }
2053     else
2054       /* try next */
2055       result = ftp_state_use_port(data, fcmd);
2056   }
2057   else {
2058     infof(data, "Connect data stream actively");
2059     state(data, FTP_STOP); /* end of DO phase */
2060     result = ftp_dophase_done(data, FALSE);
2061   }
2062
2063   return result;
2064 }
2065
2066 static CURLcode ftp_state_mdtm_resp(struct Curl_easy *data,
2067                                     int ftpcode)
2068 {
2069   CURLcode result = CURLE_OK;
2070   struct FTP *ftp = data->req.p.ftp;
2071   struct connectdata *conn = data->conn;
2072   struct ftp_conn *ftpc = &conn->proto.ftpc;
2073
2074   switch(ftpcode) {
2075   case 213:
2076     {
2077       /* we got a time. Format should be: "YYYYMMDDHHMMSS[.sss]" where the
2078          last .sss part is optional and means fractions of a second */
2079       int year, month, day, hour, minute, second;
2080       if(6 == sscanf(&data->state.buffer[4], "%04d%02d%02d%02d%02d%02d",
2081                      &year, &month, &day, &hour, &minute, &second)) {
2082         /* we have a time, reformat it */
2083         char timebuf[24];
2084         msnprintf(timebuf, sizeof(timebuf),
2085                   "%04d%02d%02d %02d:%02d:%02d GMT",
2086                   year, month, day, hour, minute, second);
2087         /* now, convert this into a time() value: */
2088         data->info.filetime = Curl_getdate_capped(timebuf);
2089       }
2090
2091 #ifdef CURL_FTP_HTTPSTYLE_HEAD
2092       /* If we asked for a time of the file and we actually got one as well,
2093          we "emulate" a HTTP-style header in our output. */
2094
2095       if(data->set.opt_no_body &&
2096          ftpc->file &&
2097          data->set.get_filetime &&
2098          (data->info.filetime >= 0) ) {
2099         char headerbuf[128];
2100         int headerbuflen;
2101         time_t filetime = data->info.filetime;
2102         struct tm buffer;
2103         const struct tm *tm = &buffer;
2104
2105         result = Curl_gmtime(filetime, &buffer);
2106         if(result)
2107           return result;
2108
2109         /* format: "Tue, 15 Nov 1994 12:45:26" */
2110         headerbuflen = msnprintf(headerbuf, sizeof(headerbuf),
2111                   "Last-Modified: %s, %02d %s %4d %02d:%02d:%02d GMT\r\n",
2112                   Curl_wkday[tm->tm_wday?tm->tm_wday-1:6],
2113                   tm->tm_mday,
2114                   Curl_month[tm->tm_mon],
2115                   tm->tm_year + 1900,
2116                   tm->tm_hour,
2117                   tm->tm_min,
2118                   tm->tm_sec);
2119         result = Curl_client_write(data, CLIENTWRITE_BOTH, headerbuf,
2120                                    headerbuflen);
2121         if(result)
2122           return result;
2123       } /* end of a ridiculous amount of conditionals */
2124 #endif
2125     }
2126     break;
2127   default:
2128     infof(data, "unsupported MDTM reply format");
2129     break;
2130   case 550: /* "No such file or directory" */
2131     failf(data, "Given file does not exist");
2132     result = CURLE_REMOTE_FILE_NOT_FOUND;
2133     break;
2134   }
2135
2136   if(data->set.timecondition) {
2137     if((data->info.filetime > 0) && (data->set.timevalue > 0)) {
2138       switch(data->set.timecondition) {
2139       case CURL_TIMECOND_IFMODSINCE:
2140       default:
2141         if(data->info.filetime <= data->set.timevalue) {
2142           infof(data, "The requested document is not new enough");
2143           ftp->transfer = PPTRANSFER_NONE; /* mark to not transfer data */
2144           data->info.timecond = TRUE;
2145           state(data, FTP_STOP);
2146           return CURLE_OK;
2147         }
2148         break;
2149       case CURL_TIMECOND_IFUNMODSINCE:
2150         if(data->info.filetime > data->set.timevalue) {
2151           infof(data, "The requested document is not old enough");
2152           ftp->transfer = PPTRANSFER_NONE; /* mark to not transfer data */
2153           data->info.timecond = TRUE;
2154           state(data, FTP_STOP);
2155           return CURLE_OK;
2156         }
2157         break;
2158       } /* switch */
2159     }
2160     else {
2161       infof(data, "Skipping time comparison");
2162     }
2163   }
2164
2165   if(!result)
2166     result = ftp_state_type(data);
2167
2168   return result;
2169 }
2170
2171 static CURLcode ftp_state_type_resp(struct Curl_easy *data,
2172                                     int ftpcode,
2173                                     ftpstate instate)
2174 {
2175   CURLcode result = CURLE_OK;
2176   struct connectdata *conn = data->conn;
2177
2178   if(ftpcode/100 != 2) {
2179     /* "sasserftpd" and "(u)r(x)bot ftpd" both responds with 226 after a
2180        successful 'TYPE I'. While that is not as RFC959 says, it is still a
2181        positive response code and we allow that. */
2182     failf(data, "Couldn't set desired mode");
2183     return CURLE_FTP_COULDNT_SET_TYPE;
2184   }
2185   if(ftpcode != 200)
2186     infof(data, "Got a %03d response code instead of the assumed 200",
2187           ftpcode);
2188
2189   if(instate == FTP_TYPE)
2190     result = ftp_state_size(data, conn);
2191   else if(instate == FTP_LIST_TYPE)
2192     result = ftp_state_list(data);
2193   else if(instate == FTP_RETR_TYPE)
2194     result = ftp_state_retr_prequote(data);
2195   else if(instate == FTP_STOR_TYPE)
2196     result = ftp_state_stor_prequote(data);
2197
2198   return result;
2199 }
2200
2201 static CURLcode ftp_state_retr(struct Curl_easy *data,
2202                                curl_off_t filesize)
2203 {
2204   CURLcode result = CURLE_OK;
2205   struct FTP *ftp = data->req.p.ftp;
2206   struct connectdata *conn = data->conn;
2207   struct ftp_conn *ftpc = &conn->proto.ftpc;
2208
2209   if(data->set.max_filesize && (filesize > data->set.max_filesize)) {
2210     failf(data, "Maximum file size exceeded");
2211     return CURLE_FILESIZE_EXCEEDED;
2212   }
2213   ftp->downloadsize = filesize;
2214
2215   if(data->state.resume_from) {
2216     /* We always (attempt to) get the size of downloads, so it is done before
2217        this even when not doing resumes. */
2218     if(filesize == -1) {
2219       infof(data, "ftp server doesn't support SIZE");
2220       /* We couldn't get the size and therefore we can't know if there really
2221          is a part of the file left to get, although the server will just
2222          close the connection when we start the connection so it won't cause
2223          us any harm, just not make us exit as nicely. */
2224     }
2225     else {
2226       /* We got a file size report, so we check that there actually is a
2227          part of the file left to get, or else we go home.  */
2228       if(data->state.resume_from< 0) {
2229         /* We're supposed to download the last abs(from) bytes */
2230         if(filesize < -data->state.resume_from) {
2231           failf(data, "Offset (%" CURL_FORMAT_CURL_OFF_T
2232                 ") was beyond file size (%" CURL_FORMAT_CURL_OFF_T ")",
2233                 data->state.resume_from, filesize);
2234           return CURLE_BAD_DOWNLOAD_RESUME;
2235         }
2236         /* convert to size to download */
2237         ftp->downloadsize = -data->state.resume_from;
2238         /* download from where? */
2239         data->state.resume_from = filesize - ftp->downloadsize;
2240       }
2241       else {
2242         if(filesize < data->state.resume_from) {
2243           failf(data, "Offset (%" CURL_FORMAT_CURL_OFF_T
2244                 ") was beyond file size (%" CURL_FORMAT_CURL_OFF_T ")",
2245                 data->state.resume_from, filesize);
2246           return CURLE_BAD_DOWNLOAD_RESUME;
2247         }
2248         /* Now store the number of bytes we are expected to download */
2249         ftp->downloadsize = filesize-data->state.resume_from;
2250       }
2251     }
2252
2253     if(ftp->downloadsize == 0) {
2254       /* no data to transfer */
2255       Curl_setup_transfer(data, -1, -1, FALSE, -1);
2256       infof(data, "File already completely downloaded");
2257
2258       /* Set ->transfer so that we won't get any error in ftp_done()
2259        * because we didn't transfer the any file */
2260       ftp->transfer = PPTRANSFER_NONE;
2261       state(data, FTP_STOP);
2262       return CURLE_OK;
2263     }
2264
2265     /* Set resume file transfer offset */
2266     infof(data, "Instructs server to resume from offset %"
2267           CURL_FORMAT_CURL_OFF_T, data->state.resume_from);
2268
2269     result = Curl_pp_sendf(data, &ftpc->pp, "REST %" CURL_FORMAT_CURL_OFF_T,
2270                            data->state.resume_from);
2271     if(!result)
2272       state(data, FTP_RETR_REST);
2273   }
2274   else {
2275     /* no resume */
2276     result = Curl_pp_sendf(data, &ftpc->pp, "RETR %s", ftpc->file);
2277     if(!result)
2278       state(data, FTP_RETR);
2279   }
2280
2281   return result;
2282 }
2283
2284 static CURLcode ftp_state_size_resp(struct Curl_easy *data,
2285                                     int ftpcode,
2286                                     ftpstate instate)
2287 {
2288   CURLcode result = CURLE_OK;
2289   curl_off_t filesize = -1;
2290   char *buf = data->state.buffer;
2291
2292   /* get the size from the ascii string: */
2293   if(ftpcode == 213) {
2294     /* To allow servers to prepend "rubbish" in the response string, we scan
2295        for all the digits at the end of the response and parse only those as a
2296        number. */
2297     char *start = &buf[4];
2298     char *fdigit = strchr(start, '\r');
2299     if(fdigit) {
2300       do
2301         fdigit--;
2302       while(ISDIGIT(*fdigit) && (fdigit > start));
2303       if(!ISDIGIT(*fdigit))
2304         fdigit++;
2305     }
2306     else
2307       fdigit = start;
2308     /* ignores parsing errors, which will make the size remain unknown */
2309     (void)curlx_strtoofft(fdigit, NULL, 0, &filesize);
2310
2311   }
2312   else if(ftpcode == 550) { /* "No such file or directory" */
2313     /* allow a SIZE failure for (resumed) uploads, when probing what command
2314        to use */
2315     if(instate != FTP_STOR_SIZE) {
2316       failf(data, "The file does not exist");
2317       return CURLE_REMOTE_FILE_NOT_FOUND;
2318     }
2319   }
2320
2321   if(instate == FTP_SIZE) {
2322 #ifdef CURL_FTP_HTTPSTYLE_HEAD
2323     if(-1 != filesize) {
2324       char clbuf[128];
2325       int clbuflen = msnprintf(clbuf, sizeof(clbuf),
2326                 "Content-Length: %" CURL_FORMAT_CURL_OFF_T "\r\n", filesize);
2327       result = Curl_client_write(data, CLIENTWRITE_BOTH, clbuf, clbuflen);
2328       if(result)
2329         return result;
2330     }
2331 #endif
2332     Curl_pgrsSetDownloadSize(data, filesize);
2333     result = ftp_state_rest(data, data->conn);
2334   }
2335   else if(instate == FTP_RETR_SIZE) {
2336     Curl_pgrsSetDownloadSize(data, filesize);
2337     result = ftp_state_retr(data, filesize);
2338   }
2339   else if(instate == FTP_STOR_SIZE) {
2340     data->state.resume_from = filesize;
2341     result = ftp_state_ul_setup(data, TRUE);
2342   }
2343
2344   return result;
2345 }
2346
2347 static CURLcode ftp_state_rest_resp(struct Curl_easy *data,
2348                                     struct connectdata *conn,
2349                                     int ftpcode,
2350                                     ftpstate instate)
2351 {
2352   CURLcode result = CURLE_OK;
2353   struct ftp_conn *ftpc = &conn->proto.ftpc;
2354
2355   switch(instate) {
2356   case FTP_REST:
2357   default:
2358 #ifdef CURL_FTP_HTTPSTYLE_HEAD
2359     if(ftpcode == 350) {
2360       char buffer[24]= { "Accept-ranges: bytes\r\n" };
2361       result = Curl_client_write(data, CLIENTWRITE_BOTH, buffer,
2362                                  strlen(buffer));
2363       if(result)
2364         return result;
2365     }
2366 #endif
2367     result = ftp_state_prepare_transfer(data);
2368     break;
2369
2370   case FTP_RETR_REST:
2371     if(ftpcode != 350) {
2372       failf(data, "Couldn't use REST");
2373       result = CURLE_FTP_COULDNT_USE_REST;
2374     }
2375     else {
2376       result = Curl_pp_sendf(data, &ftpc->pp, "RETR %s", ftpc->file);
2377       if(!result)
2378         state(data, FTP_RETR);
2379     }
2380     break;
2381   }
2382
2383   return result;
2384 }
2385
2386 static CURLcode ftp_state_stor_resp(struct Curl_easy *data,
2387                                     int ftpcode, ftpstate instate)
2388 {
2389   CURLcode result = CURLE_OK;
2390   struct connectdata *conn = data->conn;
2391
2392   if(ftpcode >= 400) {
2393     failf(data, "Failed FTP upload: %0d", ftpcode);
2394     state(data, FTP_STOP);
2395     /* oops, we never close the sockets! */
2396     return CURLE_UPLOAD_FAILED;
2397   }
2398
2399   conn->proto.ftpc.state_saved = instate;
2400
2401   /* PORT means we are now awaiting the server to connect to us. */
2402   if(data->set.ftp_use_port) {
2403     bool connected;
2404
2405     state(data, FTP_STOP); /* no longer in STOR state */
2406
2407     result = AllowServerConnect(data, &connected);
2408     if(result)
2409       return result;
2410
2411     if(!connected) {
2412       struct ftp_conn *ftpc = &conn->proto.ftpc;
2413       infof(data, "Data conn was not available immediately");
2414       ftpc->wait_data_conn = TRUE;
2415     }
2416
2417     return CURLE_OK;
2418   }
2419   return InitiateTransfer(data);
2420 }
2421
2422 /* for LIST and RETR responses */
2423 static CURLcode ftp_state_get_resp(struct Curl_easy *data,
2424                                    int ftpcode,
2425                                    ftpstate instate)
2426 {
2427   CURLcode result = CURLE_OK;
2428   struct FTP *ftp = data->req.p.ftp;
2429   struct connectdata *conn = data->conn;
2430
2431   if((ftpcode == 150) || (ftpcode == 125)) {
2432
2433     /*
2434       A;
2435       150 Opening BINARY mode data connection for /etc/passwd (2241
2436       bytes).  (ok, the file is being transferred)
2437
2438       B:
2439       150 Opening ASCII mode data connection for /bin/ls
2440
2441       C:
2442       150 ASCII data connection for /bin/ls (137.167.104.91,37445) (0 bytes).
2443
2444       D:
2445       150 Opening ASCII mode data connection for [file] (0.0.0.0,0) (545 bytes)
2446
2447       E:
2448       125 Data connection already open; Transfer starting. */
2449
2450     curl_off_t size = -1; /* default unknown size */
2451
2452
2453     /*
2454      * It appears that there are FTP-servers that return size 0 for files when
2455      * SIZE is used on the file while being in BINARY mode. To work around
2456      * that (stupid) behavior, we attempt to parse the RETR response even if
2457      * the SIZE returned size zero.
2458      *
2459      * Debugging help from Salvatore Sorrentino on February 26, 2003.
2460      */
2461
2462     if((instate != FTP_LIST) &&
2463        !data->state.prefer_ascii &&
2464        (ftp->downloadsize < 1)) {
2465       /*
2466        * It seems directory listings either don't show the size or very
2467        * often uses size 0 anyway. ASCII transfers may very well turn out
2468        * that the transferred amount of data is not the same as this line
2469        * tells, why using this number in those cases only confuses us.
2470        *
2471        * Example D above makes this parsing a little tricky */
2472       char *bytes;
2473       char *buf = data->state.buffer;
2474       bytes = strstr(buf, " bytes");
2475       if(bytes) {
2476         long in = (long)(--bytes-buf);
2477         /* this is a hint there is size information in there! ;-) */
2478         while(--in) {
2479           /* scan for the left parenthesis and break there */
2480           if('(' == *bytes)
2481             break;
2482           /* skip only digits */
2483           if(!ISDIGIT(*bytes)) {
2484             bytes = NULL;
2485             break;
2486           }
2487           /* one more estep backwards */
2488           bytes--;
2489         }
2490         /* if we have nothing but digits: */
2491         if(bytes) {
2492           ++bytes;
2493           /* get the number! */
2494           (void)curlx_strtoofft(bytes, NULL, 0, &size);
2495         }
2496       }
2497     }
2498     else if(ftp->downloadsize > -1)
2499       size = ftp->downloadsize;
2500
2501     if(size > data->req.maxdownload && data->req.maxdownload > 0)
2502       size = data->req.size = data->req.maxdownload;
2503     else if((instate != FTP_LIST) && (data->state.prefer_ascii))
2504       size = -1; /* kludge for servers that understate ASCII mode file size */
2505
2506     infof(data, "Maxdownload = %" CURL_FORMAT_CURL_OFF_T,
2507           data->req.maxdownload);
2508
2509     if(instate != FTP_LIST)
2510       infof(data, "Getting file with size: %" CURL_FORMAT_CURL_OFF_T,
2511             size);
2512
2513     /* FTP download: */
2514     conn->proto.ftpc.state_saved = instate;
2515     conn->proto.ftpc.retr_size_saved = size;
2516
2517     if(data->set.ftp_use_port) {
2518       bool connected;
2519
2520       result = AllowServerConnect(data, &connected);
2521       if(result)
2522         return result;
2523
2524       if(!connected) {
2525         struct ftp_conn *ftpc = &conn->proto.ftpc;
2526         infof(data, "Data conn was not available immediately");
2527         state(data, FTP_STOP);
2528         ftpc->wait_data_conn = TRUE;
2529       }
2530     }
2531     else
2532       return InitiateTransfer(data);
2533   }
2534   else {
2535     if((instate == FTP_LIST) && (ftpcode == 450)) {
2536       /* simply no matching files in the dir listing */
2537       ftp->transfer = PPTRANSFER_NONE; /* don't download anything */
2538       state(data, FTP_STOP); /* this phase is over */
2539     }
2540     else {
2541       failf(data, "RETR response: %03d", ftpcode);
2542       return instate == FTP_RETR && ftpcode == 550?
2543         CURLE_REMOTE_FILE_NOT_FOUND:
2544         CURLE_FTP_COULDNT_RETR_FILE;
2545     }
2546   }
2547
2548   return result;
2549 }
2550
2551 /* after USER, PASS and ACCT */
2552 static CURLcode ftp_state_loggedin(struct Curl_easy *data)
2553 {
2554   CURLcode result = CURLE_OK;
2555   struct connectdata *conn = data->conn;
2556
2557   if(conn->bits.ftp_use_control_ssl) {
2558     /* PBSZ = PROTECTION BUFFER SIZE.
2559
2560     The 'draft-murray-auth-ftp-ssl' (draft 12, page 7) says:
2561
2562     Specifically, the PROT command MUST be preceded by a PBSZ
2563     command and a PBSZ command MUST be preceded by a successful
2564     security data exchange (the TLS negotiation in this case)
2565
2566     ... (and on page 8):
2567
2568     Thus the PBSZ command must still be issued, but must have a
2569     parameter of '0' to indicate that no buffering is taking place
2570     and the data connection should not be encapsulated.
2571     */
2572     result = Curl_pp_sendf(data, &conn->proto.ftpc.pp, "PBSZ %d", 0);
2573     if(!result)
2574       state(data, FTP_PBSZ);
2575   }
2576   else {
2577     result = ftp_state_pwd(data, conn);
2578   }
2579   return result;
2580 }
2581
2582 /* for USER and PASS responses */
2583 static CURLcode ftp_state_user_resp(struct Curl_easy *data,
2584                                     int ftpcode,
2585                                     ftpstate instate)
2586 {
2587   CURLcode result = CURLE_OK;
2588   struct connectdata *conn = data->conn;
2589   struct ftp_conn *ftpc = &conn->proto.ftpc;
2590   (void)instate; /* no use for this yet */
2591
2592   /* some need password anyway, and others just return 2xx ignored */
2593   if((ftpcode == 331) && (ftpc->state == FTP_USER)) {
2594     /* 331 Password required for ...
2595        (the server requires to send the user's password too) */
2596     result = Curl_pp_sendf(data, &ftpc->pp, "PASS %s",
2597                            conn->passwd?conn->passwd:"");
2598     if(!result)
2599       state(data, FTP_PASS);
2600   }
2601   else if(ftpcode/100 == 2) {
2602     /* 230 User ... logged in.
2603        (the user logged in with or without password) */
2604     result = ftp_state_loggedin(data);
2605   }
2606   else if(ftpcode == 332) {
2607     if(data->set.str[STRING_FTP_ACCOUNT]) {
2608       result = Curl_pp_sendf(data, &ftpc->pp, "ACCT %s",
2609                              data->set.str[STRING_FTP_ACCOUNT]);
2610       if(!result)
2611         state(data, FTP_ACCT);
2612     }
2613     else {
2614       failf(data, "ACCT requested but none available");
2615       result = CURLE_LOGIN_DENIED;
2616     }
2617   }
2618   else {
2619     /* All other response codes, like:
2620
2621     530 User ... access denied
2622     (the server denies to log the specified user) */
2623
2624     if(data->set.str[STRING_FTP_ALTERNATIVE_TO_USER] &&
2625         !data->state.ftp_trying_alternative) {
2626       /* Ok, USER failed.  Let's try the supplied command. */
2627       result =
2628         Curl_pp_sendf(data, &ftpc->pp, "%s",
2629                       data->set.str[STRING_FTP_ALTERNATIVE_TO_USER]);
2630       if(!result) {
2631         data->state.ftp_trying_alternative = TRUE;
2632         state(data, FTP_USER);
2633       }
2634     }
2635     else {
2636       failf(data, "Access denied: %03d", ftpcode);
2637       result = CURLE_LOGIN_DENIED;
2638     }
2639   }
2640   return result;
2641 }
2642
2643 /* for ACCT response */
2644 static CURLcode ftp_state_acct_resp(struct Curl_easy *data,
2645                                     int ftpcode)
2646 {
2647   CURLcode result = CURLE_OK;
2648   if(ftpcode != 230) {
2649     failf(data, "ACCT rejected by server: %03d", ftpcode);
2650     result = CURLE_FTP_WEIRD_PASS_REPLY; /* FIX */
2651   }
2652   else
2653     result = ftp_state_loggedin(data);
2654
2655   return result;
2656 }
2657
2658
2659 static CURLcode ftp_statemachine(struct Curl_easy *data,
2660                                  struct connectdata *conn)
2661 {
2662   CURLcode result;
2663   curl_socket_t sock = conn->sock[FIRSTSOCKET];
2664   int ftpcode;
2665   struct ftp_conn *ftpc = &conn->proto.ftpc;
2666   struct pingpong *pp = &ftpc->pp;
2667   static const char ftpauth[][4]  = { "SSL", "TLS" };
2668   size_t nread = 0;
2669
2670   if(pp->sendleft)
2671     return Curl_pp_flushsend(data, pp);
2672
2673   result = ftp_readresp(data, sock, pp, &ftpcode, &nread);
2674   if(result)
2675     return result;
2676
2677   if(ftpcode) {
2678     /* we have now received a full FTP server response */
2679     switch(ftpc->state) {
2680     case FTP_WAIT220:
2681       if(ftpcode == 230) {
2682         /* 230 User logged in - already! Take as 220 if TLS required. */
2683         if(data->set.use_ssl <= CURLUSESSL_TRY ||
2684            conn->bits.ftp_use_control_ssl)
2685           return ftp_state_user_resp(data, ftpcode, ftpc->state);
2686       }
2687       else if(ftpcode != 220) {
2688         failf(data, "Got a %03d ftp-server response when 220 was expected",
2689               ftpcode);
2690         return CURLE_WEIRD_SERVER_REPLY;
2691       }
2692
2693       /* We have received a 220 response fine, now we proceed. */
2694 #ifdef HAVE_GSSAPI
2695       if(data->set.krb) {
2696         /* If not anonymous login, try a secure login. Note that this
2697            procedure is still BLOCKING. */
2698
2699         Curl_sec_request_prot(conn, "private");
2700         /* We set private first as default, in case the line below fails to
2701            set a valid level */
2702         Curl_sec_request_prot(conn, data->set.str[STRING_KRB_LEVEL]);
2703
2704         if(Curl_sec_login(data, conn))
2705           infof(data, "Logging in with password in cleartext");
2706         else
2707           infof(data, "Authentication successful");
2708       }
2709 #endif
2710
2711       if(data->set.use_ssl && !conn->bits.ftp_use_control_ssl) {
2712         /* We don't have a SSL/TLS control connection yet, but FTPS is
2713            requested. Try a FTPS connection now */
2714
2715         ftpc->count3 = 0;
2716         switch(data->set.ftpsslauth) {
2717         case CURLFTPAUTH_DEFAULT:
2718         case CURLFTPAUTH_SSL:
2719           ftpc->count2 = 1; /* add one to get next */
2720           ftpc->count1 = 0;
2721           break;
2722         case CURLFTPAUTH_TLS:
2723           ftpc->count2 = -1; /* subtract one to get next */
2724           ftpc->count1 = 1;
2725           break;
2726         default:
2727           failf(data, "unsupported parameter to CURLOPT_FTPSSLAUTH: %d",
2728                 (int)data->set.ftpsslauth);
2729           return CURLE_UNKNOWN_OPTION; /* we don't know what to do */
2730         }
2731         result = Curl_pp_sendf(data, &ftpc->pp, "AUTH %s",
2732                                ftpauth[ftpc->count1]);
2733         if(!result)
2734           state(data, FTP_AUTH);
2735       }
2736       else
2737         result = ftp_state_user(data, conn);
2738       break;
2739
2740     case FTP_AUTH:
2741       /* we have gotten the response to a previous AUTH command */
2742
2743       if(pp->cache_size)
2744         return CURLE_WEIRD_SERVER_REPLY; /* Forbid pipelining in response. */
2745
2746       /* RFC2228 (page 5) says:
2747        *
2748        * If the server is willing to accept the named security mechanism,
2749        * and does not require any security data, it must respond with
2750        * reply code 234/334.
2751        */
2752
2753       if((ftpcode == 234) || (ftpcode == 334)) {
2754         /* Curl_ssl_connect is BLOCKING */
2755         result = Curl_ssl_connect(data, conn, FIRSTSOCKET);
2756         if(!result) {
2757           conn->bits.ftp_use_data_ssl = FALSE; /* clear-text data */
2758           conn->bits.ftp_use_control_ssl = TRUE; /* SSL on control */
2759           result = ftp_state_user(data, conn);
2760         }
2761       }
2762       else if(ftpc->count3 < 1) {
2763         ftpc->count3++;
2764         ftpc->count1 += ftpc->count2; /* get next attempt */
2765         result = Curl_pp_sendf(data, &ftpc->pp, "AUTH %s",
2766                                ftpauth[ftpc->count1]);
2767         /* remain in this same state */
2768       }
2769       else {
2770         if(data->set.use_ssl > CURLUSESSL_TRY)
2771           /* we failed and CURLUSESSL_CONTROL or CURLUSESSL_ALL is set */
2772           result = CURLE_USE_SSL_FAILED;
2773         else
2774           /* ignore the failure and continue */
2775           result = ftp_state_user(data, conn);
2776       }
2777       break;
2778
2779     case FTP_USER:
2780     case FTP_PASS:
2781       result = ftp_state_user_resp(data, ftpcode, ftpc->state);
2782       break;
2783
2784     case FTP_ACCT:
2785       result = ftp_state_acct_resp(data, ftpcode);
2786       break;
2787
2788     case FTP_PBSZ:
2789       result =
2790         Curl_pp_sendf(data, &ftpc->pp, "PROT %c",
2791                       data->set.use_ssl == CURLUSESSL_CONTROL ? 'C' : 'P');
2792       if(!result)
2793         state(data, FTP_PROT);
2794       break;
2795
2796     case FTP_PROT:
2797       if(ftpcode/100 == 2)
2798         /* We have enabled SSL for the data connection! */
2799         conn->bits.ftp_use_data_ssl =
2800           (data->set.use_ssl != CURLUSESSL_CONTROL) ? TRUE : FALSE;
2801       /* FTP servers typically responds with 500 if they decide to reject
2802          our 'P' request */
2803       else if(data->set.use_ssl > CURLUSESSL_CONTROL)
2804         /* we failed and bails out */
2805         return CURLE_USE_SSL_FAILED;
2806
2807       if(data->set.ftp_ccc) {
2808         /* CCC - Clear Command Channel
2809          */
2810         result = Curl_pp_sendf(data, &ftpc->pp, "%s", "CCC");
2811         if(!result)
2812           state(data, FTP_CCC);
2813       }
2814       else
2815         result = ftp_state_pwd(data, conn);
2816       break;
2817
2818     case FTP_CCC:
2819       if(ftpcode < 500) {
2820         /* First shut down the SSL layer (note: this call will block) */
2821         result = Curl_ssl_shutdown(data, conn, FIRSTSOCKET);
2822
2823         if(result)
2824           failf(data, "Failed to clear the command channel (CCC)");
2825       }
2826       if(!result)
2827         /* Then continue as normal */
2828         result = ftp_state_pwd(data, conn);
2829       break;
2830
2831     case FTP_PWD:
2832       if(ftpcode == 257) {
2833         char *ptr = &data->state.buffer[4];  /* start on the first letter */
2834         const size_t buf_size = data->set.buffer_size;
2835         char *dir;
2836         bool entry_extracted = FALSE;
2837
2838         dir = malloc(nread + 1);
2839         if(!dir)
2840           return CURLE_OUT_OF_MEMORY;
2841
2842         /* Reply format is like
2843            257<space>[rubbish]"<directory-name>"<space><commentary> and the
2844            RFC959 says
2845
2846            The directory name can contain any character; embedded
2847            double-quotes should be escaped by double-quotes (the
2848            "quote-doubling" convention).
2849         */
2850
2851         /* scan for the first double-quote for non-standard responses */
2852         while(ptr < &data->state.buffer[buf_size]
2853               && *ptr != '\n' && *ptr != '\0' && *ptr != '"')
2854           ptr++;
2855
2856         if('\"' == *ptr) {
2857           /* it started good */
2858           char *store;
2859           ptr++;
2860           for(store = dir; *ptr;) {
2861             if('\"' == *ptr) {
2862               if('\"' == ptr[1]) {
2863                 /* "quote-doubling" */
2864                 *store = ptr[1];
2865                 ptr++;
2866               }
2867               else {
2868                 /* end of path */
2869                 entry_extracted = TRUE;
2870                 break; /* get out of this loop */
2871               }
2872             }
2873             else
2874               *store = *ptr;
2875             store++;
2876             ptr++;
2877           }
2878           *store = '\0'; /* null-terminate */
2879         }
2880         if(entry_extracted) {
2881           /* If the path name does not look like an absolute path (i.e.: it
2882              does not start with a '/'), we probably need some server-dependent
2883              adjustments. For example, this is the case when connecting to
2884              an OS400 FTP server: this server supports two name syntaxes,
2885              the default one being incompatible with standard paths. In
2886              addition, this server switches automatically to the regular path
2887              syntax when one is encountered in a command: this results in
2888              having an entrypath in the wrong syntax when later used in CWD.
2889                The method used here is to check the server OS: we do it only
2890              if the path name looks strange to minimize overhead on other
2891              systems. */
2892
2893           if(!ftpc->server_os && dir[0] != '/') {
2894             result = Curl_pp_sendf(data, &ftpc->pp, "%s", "SYST");
2895             if(result) {
2896               free(dir);
2897               return result;
2898             }
2899             Curl_safefree(ftpc->entrypath);
2900             ftpc->entrypath = dir; /* remember this */
2901             infof(data, "Entry path is '%s'", ftpc->entrypath);
2902             /* also save it where getinfo can access it: */
2903             data->state.most_recent_ftp_entrypath = ftpc->entrypath;
2904             state(data, FTP_SYST);
2905             break;
2906           }
2907
2908           Curl_safefree(ftpc->entrypath);
2909           ftpc->entrypath = dir; /* remember this */
2910           infof(data, "Entry path is '%s'", ftpc->entrypath);
2911           /* also save it where getinfo can access it: */
2912           data->state.most_recent_ftp_entrypath = ftpc->entrypath;
2913         }
2914         else {
2915           /* couldn't get the path */
2916           free(dir);
2917           infof(data, "Failed to figure out path");
2918         }
2919       }
2920       state(data, FTP_STOP); /* we are done with the CONNECT phase! */
2921       DEBUGF(infof(data, "protocol connect phase DONE"));
2922       break;
2923
2924     case FTP_SYST:
2925       if(ftpcode == 215) {
2926         char *ptr = &data->state.buffer[4];  /* start on the first letter */
2927         char *os;
2928         char *store;
2929
2930         os = malloc(nread + 1);
2931         if(!os)
2932           return CURLE_OUT_OF_MEMORY;
2933
2934         /* Reply format is like
2935            215<space><OS-name><space><commentary>
2936         */
2937         while(*ptr == ' ')
2938           ptr++;
2939         for(store = os; *ptr && *ptr != ' ';)
2940           *store++ = *ptr++;
2941         *store = '\0'; /* null-terminate */
2942
2943         /* Check for special servers here. */
2944
2945         if(strcasecompare(os, "OS/400")) {
2946           /* Force OS400 name format 1. */
2947           result = Curl_pp_sendf(data, &ftpc->pp, "%s", "SITE NAMEFMT 1");
2948           if(result) {
2949             free(os);
2950             return result;
2951           }
2952           /* remember target server OS */
2953           Curl_safefree(ftpc->server_os);
2954           ftpc->server_os = os;
2955           state(data, FTP_NAMEFMT);
2956           break;
2957         }
2958         /* Nothing special for the target server. */
2959         /* remember target server OS */
2960         Curl_safefree(ftpc->server_os);
2961         ftpc->server_os = os;
2962       }
2963       else {
2964         /* Cannot identify server OS. Continue anyway and cross fingers. */
2965       }
2966
2967       state(data, FTP_STOP); /* we are done with the CONNECT phase! */
2968       DEBUGF(infof(data, "protocol connect phase DONE"));
2969       break;
2970
2971     case FTP_NAMEFMT:
2972       if(ftpcode == 250) {
2973         /* Name format change successful: reload initial path. */
2974         ftp_state_pwd(data, conn);
2975         break;
2976       }
2977
2978       state(data, FTP_STOP); /* we are done with the CONNECT phase! */
2979       DEBUGF(infof(data, "protocol connect phase DONE"));
2980       break;
2981
2982     case FTP_QUOTE:
2983     case FTP_POSTQUOTE:
2984     case FTP_RETR_PREQUOTE:
2985     case FTP_STOR_PREQUOTE:
2986       if((ftpcode >= 400) && !ftpc->count2) {
2987         /* failure response code, and not allowed to fail */
2988         failf(data, "QUOT command failed with %03d", ftpcode);
2989         result = CURLE_QUOTE_ERROR;
2990       }
2991       else
2992         result = ftp_state_quote(data, FALSE, ftpc->state);
2993       break;
2994
2995     case FTP_CWD:
2996       if(ftpcode/100 != 2) {
2997         /* failure to CWD there */
2998         if(data->set.ftp_create_missing_dirs &&
2999            ftpc->cwdcount && !ftpc->count2) {
3000           /* try making it */
3001           ftpc->count2++; /* counter to prevent CWD-MKD loops */
3002
3003           /* count3 is set to allow MKD to fail once per dir. In the case when
3004           CWD fails and then MKD fails (due to another session raced it to
3005           create the dir) this then allows for a second try to CWD to it. */
3006           ftpc->count3 = (data->set.ftp_create_missing_dirs == 2) ? 1 : 0;
3007
3008           result = Curl_pp_sendf(data, &ftpc->pp, "MKD %s",
3009                                  ftpc->dirs[ftpc->cwdcount - 1]);
3010           if(!result)
3011             state(data, FTP_MKD);
3012         }
3013         else {
3014           /* return failure */
3015           failf(data, "Server denied you to change to the given directory");
3016           ftpc->cwdfail = TRUE; /* don't remember this path as we failed
3017                                    to enter it */
3018           result = CURLE_REMOTE_ACCESS_DENIED;
3019         }
3020       }
3021       else {
3022         /* success */
3023         ftpc->count2 = 0;
3024         if(++ftpc->cwdcount <= ftpc->dirdepth)
3025           /* send next CWD */
3026           result = Curl_pp_sendf(data, &ftpc->pp, "CWD %s",
3027                                  ftpc->dirs[ftpc->cwdcount - 1]);
3028         else
3029           result = ftp_state_mdtm(data);
3030       }
3031       break;
3032
3033     case FTP_MKD:
3034       if((ftpcode/100 != 2) && !ftpc->count3--) {
3035         /* failure to MKD the dir */
3036         failf(data, "Failed to MKD dir: %03d", ftpcode);
3037         result = CURLE_REMOTE_ACCESS_DENIED;
3038       }
3039       else {
3040         state(data, FTP_CWD);
3041         /* send CWD */
3042         result = Curl_pp_sendf(data, &ftpc->pp, "CWD %s",
3043                                ftpc->dirs[ftpc->cwdcount - 1]);
3044       }
3045       break;
3046
3047     case FTP_MDTM:
3048       result = ftp_state_mdtm_resp(data, ftpcode);
3049       break;
3050
3051     case FTP_TYPE:
3052     case FTP_LIST_TYPE:
3053     case FTP_RETR_TYPE:
3054     case FTP_STOR_TYPE:
3055       result = ftp_state_type_resp(data, ftpcode, ftpc->state);
3056       break;
3057
3058     case FTP_SIZE:
3059     case FTP_RETR_SIZE:
3060     case FTP_STOR_SIZE:
3061       result = ftp_state_size_resp(data, ftpcode, ftpc->state);
3062       break;
3063
3064     case FTP_REST:
3065     case FTP_RETR_REST:
3066       result = ftp_state_rest_resp(data, conn, ftpcode, ftpc->state);
3067       break;
3068
3069     case FTP_PRET:
3070       if(ftpcode != 200) {
3071         /* there only is this one standard OK return code. */
3072         failf(data, "PRET command not accepted: %03d", ftpcode);
3073         return CURLE_FTP_PRET_FAILED;
3074       }
3075       result = ftp_state_use_pasv(data, conn);
3076       break;
3077
3078     case FTP_PASV:
3079       result = ftp_state_pasv_resp(data, ftpcode);
3080       break;
3081
3082     case FTP_PORT:
3083       result = ftp_state_port_resp(data, ftpcode);
3084       break;
3085
3086     case FTP_LIST:
3087     case FTP_RETR:
3088       result = ftp_state_get_resp(data, ftpcode, ftpc->state);
3089       break;
3090
3091     case FTP_STOR:
3092       result = ftp_state_stor_resp(data, ftpcode, ftpc->state);
3093       break;
3094
3095     case FTP_QUIT:
3096       /* fallthrough, just stop! */
3097     default:
3098       /* internal error */
3099       state(data, FTP_STOP);
3100       break;
3101     }
3102   } /* if(ftpcode) */
3103
3104   return result;
3105 }
3106
3107
3108 /* called repeatedly until done from multi.c */
3109 static CURLcode ftp_multi_statemach(struct Curl_easy *data,
3110                                     bool *done)
3111 {
3112   struct connectdata *conn = data->conn;
3113   struct ftp_conn *ftpc = &conn->proto.ftpc;
3114   CURLcode result = Curl_pp_statemach(data, &ftpc->pp, FALSE, FALSE);
3115
3116   /* Check for the state outside of the Curl_socket_check() return code checks
3117      since at times we are in fact already in this state when this function
3118      gets called. */
3119   *done = (ftpc->state == FTP_STOP) ? TRUE : FALSE;
3120
3121   return result;
3122 }
3123
3124 static CURLcode ftp_block_statemach(struct Curl_easy *data,
3125                                     struct connectdata *conn)
3126 {
3127   struct ftp_conn *ftpc = &conn->proto.ftpc;
3128   struct pingpong *pp = &ftpc->pp;
3129   CURLcode result = CURLE_OK;
3130
3131   while(ftpc->state != FTP_STOP) {
3132     result = Curl_pp_statemach(data, pp, TRUE, TRUE /* disconnecting */);
3133     if(result)
3134       break;
3135   }
3136
3137   return result;
3138 }
3139
3140 /*
3141  * ftp_connect() should do everything that is to be considered a part of
3142  * the connection phase.
3143  *
3144  * The variable 'done' points to will be TRUE if the protocol-layer connect
3145  * phase is done when this function returns, or FALSE if not.
3146  *
3147  */
3148 static CURLcode ftp_connect(struct Curl_easy *data,
3149                             bool *done) /* see description above */
3150 {
3151   CURLcode result;
3152   struct connectdata *conn = data->conn;
3153   struct ftp_conn *ftpc = &conn->proto.ftpc;
3154   struct pingpong *pp = &ftpc->pp;
3155
3156   *done = FALSE; /* default to not done yet */
3157
3158   /* We always support persistent connections on ftp */
3159   connkeep(conn, "FTP default");
3160
3161   PINGPONG_SETUP(pp, ftp_statemachine, ftp_endofresp);
3162
3163   if(conn->handler->flags & PROTOPT_SSL) {
3164     /* BLOCKING */
3165     result = Curl_ssl_connect(data, conn, FIRSTSOCKET);
3166     if(result)
3167       return result;
3168     conn->bits.ftp_use_control_ssl = TRUE;
3169   }
3170
3171   Curl_pp_setup(pp); /* once per transfer */
3172   Curl_pp_init(data, pp); /* init the generic pingpong data */
3173
3174   /* When we connect, we start in the state where we await the 220
3175      response */
3176   state(data, FTP_WAIT220);
3177
3178   result = ftp_multi_statemach(data, done);
3179
3180   return result;
3181 }
3182
3183 /***********************************************************************
3184  *
3185  * ftp_done()
3186  *
3187  * The DONE function. This does what needs to be done after a single DO has
3188  * performed.
3189  *
3190  * Input argument is already checked for validity.
3191  */
3192 static CURLcode ftp_done(struct Curl_easy *data, CURLcode status,
3193                          bool premature)
3194 {
3195   struct connectdata *conn = data->conn;
3196   struct FTP *ftp = data->req.p.ftp;
3197   struct ftp_conn *ftpc = &conn->proto.ftpc;
3198   struct pingpong *pp = &ftpc->pp;
3199   ssize_t nread;
3200   int ftpcode;
3201   CURLcode result = CURLE_OK;
3202   char *rawPath = NULL;
3203   size_t pathLen = 0;
3204
3205   if(!ftp)
3206     return CURLE_OK;
3207
3208   switch(status) {
3209   case CURLE_BAD_DOWNLOAD_RESUME:
3210   case CURLE_FTP_WEIRD_PASV_REPLY:
3211   case CURLE_FTP_PORT_FAILED:
3212   case CURLE_FTP_ACCEPT_FAILED:
3213   case CURLE_FTP_ACCEPT_TIMEOUT:
3214   case CURLE_FTP_COULDNT_SET_TYPE:
3215   case CURLE_FTP_COULDNT_RETR_FILE:
3216   case CURLE_PARTIAL_FILE:
3217   case CURLE_UPLOAD_FAILED:
3218   case CURLE_REMOTE_ACCESS_DENIED:
3219   case CURLE_FILESIZE_EXCEEDED:
3220   case CURLE_REMOTE_FILE_NOT_FOUND:
3221   case CURLE_WRITE_ERROR:
3222     /* the connection stays alive fine even though this happened */
3223     /* fall-through */
3224   case CURLE_OK: /* doesn't affect the control connection's status */
3225     if(!premature)
3226       break;
3227
3228     /* until we cope better with prematurely ended requests, let them
3229      * fallback as if in complete failure */
3230     /* FALLTHROUGH */
3231   default:       /* by default, an error means the control connection is
3232                     wedged and should not be used anymore */
3233     ftpc->ctl_valid = FALSE;
3234     ftpc->cwdfail = TRUE; /* set this TRUE to prevent us to remember the
3235                              current path, as this connection is going */
3236     connclose(conn, "FTP ended with bad error code");
3237     result = status;      /* use the already set error code */
3238     break;
3239   }
3240
3241   if(data->state.wildcardmatch) {
3242     if(data->set.chunk_end && ftpc->file) {
3243       Curl_set_in_callback(data, true);
3244       data->set.chunk_end(data->wildcard.customptr);
3245       Curl_set_in_callback(data, false);
3246     }
3247     ftpc->known_filesize = -1;
3248   }
3249
3250   if(!result)
3251     /* get the url-decoded "raw" path */
3252     result = Curl_urldecode(ftp->path, 0, &rawPath, &pathLen,
3253                             REJECT_CTRL);
3254   if(result) {
3255     /* We can limp along anyway (and should try to since we may already be in
3256      * the error path) */
3257     ftpc->ctl_valid = FALSE; /* mark control connection as bad */
3258     connclose(conn, "FTP: out of memory!"); /* mark for connection closure */
3259     free(ftpc->prevpath);
3260     ftpc->prevpath = NULL; /* no path remembering */
3261   }
3262   else { /* remember working directory for connection reuse */
3263     if((data->set.ftp_filemethod == FTPFILE_NOCWD) && (rawPath[0] == '/'))
3264       free(rawPath); /* full path => no CWDs happened => keep ftpc->prevpath */
3265     else {
3266       free(ftpc->prevpath);
3267
3268       if(!ftpc->cwdfail) {
3269         if(data->set.ftp_filemethod == FTPFILE_NOCWD)
3270           pathLen = 0; /* relative path => working directory is FTP home */
3271         else
3272           pathLen -= ftpc->file?strlen(ftpc->file):0; /* file is url-decoded */
3273
3274         rawPath[pathLen] = '\0';
3275         ftpc->prevpath = rawPath;
3276       }
3277       else {
3278         free(rawPath);
3279         ftpc->prevpath = NULL; /* no path */
3280       }
3281     }
3282
3283     if(ftpc->prevpath)
3284       infof(data, "Remembering we are in dir \"%s\"", ftpc->prevpath);
3285   }
3286
3287   /* free the dir tree and file parts */
3288   freedirs(ftpc);
3289
3290   /* shut down the socket to inform the server we're done */
3291
3292 #ifdef _WIN32_WCE
3293   shutdown(conn->sock[SECONDARYSOCKET], 2);  /* SD_BOTH */
3294 #endif
3295
3296   if(conn->sock[SECONDARYSOCKET] != CURL_SOCKET_BAD) {
3297     if(!result && ftpc->dont_check && data->req.maxdownload > 0) {
3298       /* partial download completed */
3299       result = Curl_pp_sendf(data, pp, "%s", "ABOR");
3300       if(result) {
3301         failf(data, "Failure sending ABOR command: %s",
3302               curl_easy_strerror(result));
3303         ftpc->ctl_valid = FALSE; /* mark control connection as bad */
3304         connclose(conn, "ABOR command failed"); /* connection closure */
3305       }
3306     }
3307
3308     if(conn->ssl[SECONDARYSOCKET].use) {
3309       /* The secondary socket is using SSL so we must close down that part
3310          first before we close the socket for real */
3311       Curl_ssl_close(data, conn, SECONDARYSOCKET);
3312
3313       /* Note that we keep "use" set to TRUE since that (next) connection is
3314          still requested to use SSL */
3315     }
3316     close_secondarysocket(data, conn);
3317   }
3318
3319   if(!result && (ftp->transfer == PPTRANSFER_BODY) && ftpc->ctl_valid &&
3320      pp->pending_resp && !premature) {
3321     /*
3322      * Let's see what the server says about the transfer we just performed,
3323      * but lower the timeout as sometimes this connection has died while the
3324      * data has been transferred. This happens when doing through NATs etc that
3325      * abandon old silent connections.
3326      */
3327     timediff_t old_time = pp->response_time;
3328
3329     pp->response_time = 60*1000; /* give it only a minute for now */
3330     pp->response = Curl_now(); /* timeout relative now */
3331
3332     result = Curl_GetFTPResponse(data, &nread, &ftpcode);
3333
3334     pp->response_time = old_time; /* set this back to previous value */
3335
3336     if(!nread && (CURLE_OPERATION_TIMEDOUT == result)) {
3337       failf(data, "control connection looks dead");
3338       ftpc->ctl_valid = FALSE; /* mark control connection as bad */
3339       connclose(conn, "Timeout or similar in FTP DONE operation"); /* close */
3340     }
3341
3342     if(result) {
3343       Curl_safefree(ftp->pathalloc);
3344       return result;
3345     }
3346
3347     if(ftpc->dont_check && data->req.maxdownload > 0) {
3348       /* we have just sent ABOR and there is no reliable way to check if it was
3349        * successful or not; we have to close the connection now */
3350       infof(data, "partial download completed, closing connection");
3351       connclose(conn, "Partial download with no ability to check");
3352       return result;
3353     }
3354
3355     if(!ftpc->dont_check) {
3356       /* 226 Transfer complete, 250 Requested file action okay, completed. */
3357       switch(ftpcode) {
3358       case 226:
3359       case 250:
3360         break;
3361       case 552:
3362         failf(data, "Exceeded storage allocation");
3363         result = CURLE_REMOTE_DISK_FULL;
3364         break;
3365       default:
3366         failf(data, "server did not report OK, got %d", ftpcode);
3367         result = CURLE_PARTIAL_FILE;
3368         break;
3369       }
3370     }
3371   }
3372
3373   if(result || premature)
3374     /* the response code from the transfer showed an error already so no
3375        use checking further */
3376     ;
3377   else if(data->set.upload) {
3378     if((-1 != data->state.infilesize) &&
3379        (data->state.infilesize != data->req.writebytecount) &&
3380        !data->set.crlf &&
3381        (ftp->transfer == PPTRANSFER_BODY)) {
3382       failf(data, "Uploaded unaligned file size (%" CURL_FORMAT_CURL_OFF_T
3383             " out of %" CURL_FORMAT_CURL_OFF_T " bytes)",
3384             data->req.writebytecount, data->state.infilesize);
3385       result = CURLE_PARTIAL_FILE;
3386     }
3387   }
3388   else {
3389     if((-1 != data->req.size) &&
3390        (data->req.size != data->req.bytecount) &&
3391 #ifdef CURL_DO_LINEEND_CONV
3392        /* Most FTP servers don't adjust their file SIZE response for CRLFs, so
3393         * we'll check to see if the discrepancy can be explained by the number
3394         * of CRLFs we've changed to LFs.
3395         */
3396        ((data->req.size + data->state.crlf_conversions) !=
3397         data->req.bytecount) &&
3398 #endif /* CURL_DO_LINEEND_CONV */
3399        (data->req.maxdownload != data->req.bytecount)) {
3400       failf(data, "Received only partial file: %" CURL_FORMAT_CURL_OFF_T
3401             " bytes", data->req.bytecount);
3402       result = CURLE_PARTIAL_FILE;
3403     }
3404     else if(!ftpc->dont_check &&
3405             !data->req.bytecount &&
3406             (data->req.size>0)) {
3407       failf(data, "No data was received");
3408       result = CURLE_FTP_COULDNT_RETR_FILE;
3409     }
3410   }
3411
3412   /* clear these for next connection */
3413   ftp->transfer = PPTRANSFER_BODY;
3414   ftpc->dont_check = FALSE;
3415
3416   /* Send any post-transfer QUOTE strings? */
3417   if(!status && !result && !premature && data->set.postquote)
3418     result = ftp_sendquote(data, conn, data->set.postquote);
3419   Curl_safefree(ftp->pathalloc);
3420   return result;
3421 }
3422
3423 /***********************************************************************
3424  *
3425  * ftp_sendquote()
3426  *
3427  * Where a 'quote' means a list of custom commands to send to the server.
3428  * The quote list is passed as an argument.
3429  *
3430  * BLOCKING
3431  */
3432
3433 static
3434 CURLcode ftp_sendquote(struct Curl_easy *data,
3435                        struct connectdata *conn, struct curl_slist *quote)
3436 {
3437   struct curl_slist *item;
3438   struct ftp_conn *ftpc = &conn->proto.ftpc;
3439   struct pingpong *pp = &ftpc->pp;
3440
3441   item = quote;
3442   while(item) {
3443     if(item->data) {
3444       ssize_t nread;
3445       char *cmd = item->data;
3446       bool acceptfail = FALSE;
3447       CURLcode result;
3448       int ftpcode = 0;
3449
3450       /* if a command starts with an asterisk, which a legal FTP command never
3451          can, the command will be allowed to fail without it causing any
3452          aborts or cancels etc. It will cause libcurl to act as if the command
3453          is successful, whatever the server reponds. */
3454
3455       if(cmd[0] == '*') {
3456         cmd++;
3457         acceptfail = TRUE;
3458       }
3459
3460       result = Curl_pp_sendf(data, &ftpc->pp, "%s", cmd);
3461       if(!result) {
3462         pp->response = Curl_now(); /* timeout relative now */
3463         result = Curl_GetFTPResponse(data, &nread, &ftpcode);
3464       }
3465       if(result)
3466         return result;
3467
3468       if(!acceptfail && (ftpcode >= 400)) {
3469         failf(data, "QUOT string not accepted: %s", cmd);
3470         return CURLE_QUOTE_ERROR;
3471       }
3472     }
3473
3474     item = item->next;
3475   }
3476
3477   return CURLE_OK;
3478 }
3479
3480 /***********************************************************************
3481  *
3482  * ftp_need_type()
3483  *
3484  * Returns TRUE if we in the current situation should send TYPE
3485  */
3486 static int ftp_need_type(struct connectdata *conn,
3487                          bool ascii_wanted)
3488 {
3489   return conn->proto.ftpc.transfertype != (ascii_wanted?'A':'I');
3490 }
3491
3492 /***********************************************************************
3493  *
3494  * ftp_nb_type()
3495  *
3496  * Set TYPE. We only deal with ASCII or BINARY so this function
3497  * sets one of them.
3498  * If the transfer type is not sent, simulate on OK response in newstate
3499  */
3500 static CURLcode ftp_nb_type(struct Curl_easy *data,
3501                             struct connectdata *conn,
3502                             bool ascii, ftpstate newstate)
3503 {
3504   struct ftp_conn *ftpc = &conn->proto.ftpc;
3505   CURLcode result;
3506   char want = (char)(ascii?'A':'I');
3507
3508   if(ftpc->transfertype == want) {
3509     state(data, newstate);
3510     return ftp_state_type_resp(data, 200, newstate);
3511   }
3512
3513   result = Curl_pp_sendf(data, &ftpc->pp, "TYPE %c", want);
3514   if(!result) {
3515     state(data, newstate);
3516
3517     /* keep track of our current transfer type */
3518     ftpc->transfertype = want;
3519   }
3520   return result;
3521 }
3522
3523 /***************************************************************************
3524  *
3525  * ftp_pasv_verbose()
3526  *
3527  * This function only outputs some informationals about this second connection
3528  * when we've issued a PASV command before and thus we have connected to a
3529  * possibly new IP address.
3530  *
3531  */
3532 #ifndef CURL_DISABLE_VERBOSE_STRINGS
3533 static void
3534 ftp_pasv_verbose(struct Curl_easy *data,
3535                  struct Curl_addrinfo *ai,
3536                  char *newhost, /* ascii version */
3537                  int port)
3538 {
3539   char buf[256];
3540   Curl_printable_address(ai, buf, sizeof(buf));
3541   infof(data, "Connecting to %s (%s) port %d", newhost, buf, port);
3542 }
3543 #endif
3544
3545 /*
3546  * ftp_do_more()
3547  *
3548  * This function shall be called when the second FTP (data) connection is
3549  * connected.
3550  *
3551  * 'complete' can return 0 for incomplete, 1 for done and -1 for go back
3552  * (which basically is only for when PASV is being sent to retry a failed
3553  * EPSV).
3554  */
3555
3556 static CURLcode ftp_do_more(struct Curl_easy *data, int *completep)
3557 {
3558   struct connectdata *conn = data->conn;
3559   struct ftp_conn *ftpc = &conn->proto.ftpc;
3560   CURLcode result = CURLE_OK;
3561   bool connected = FALSE;
3562   bool complete = FALSE;
3563
3564   /* the ftp struct is inited in ftp_connect() */
3565   struct FTP *ftp = data->req.p.ftp;
3566
3567   /* if the second connection isn't done yet, wait for it */
3568   if(!conn->bits.tcpconnect[SECONDARYSOCKET]) {
3569     if(Curl_connect_ongoing(conn)) {
3570       /* As we're in TUNNEL_CONNECT state now, we know the proxy name and port
3571          aren't used so we blank their arguments. */
3572       result = Curl_proxyCONNECT(data, SECONDARYSOCKET, NULL, 0);
3573
3574       return result;
3575     }
3576
3577     result = Curl_is_connected(data, conn, SECONDARYSOCKET, &connected);
3578
3579     /* Ready to do more? */
3580     if(connected) {
3581       DEBUGF(infof(data, "DO-MORE connected phase starts"));
3582     }
3583     else {
3584       if(result && (ftpc->count1 == 0)) {
3585         *completep = -1; /* go back to DOING please */
3586         /* this is a EPSV connect failing, try PASV instead */
3587         return ftp_epsv_disable(data, conn);
3588       }
3589       return result;
3590     }
3591   }
3592
3593 #ifndef CURL_DISABLE_PROXY
3594   result = Curl_proxy_connect(data, SECONDARYSOCKET);
3595   if(result)
3596     return result;
3597
3598   if(CONNECT_SECONDARYSOCKET_PROXY_SSL())
3599     return result;
3600
3601   if(conn->bits.tunnel_proxy && conn->bits.httpproxy &&
3602      Curl_connect_ongoing(conn))
3603     return result;
3604 #endif
3605
3606   if(ftpc->state) {
3607     /* already in a state so skip the initial commands.
3608        They are only done to kickstart the do_more state */
3609     result = ftp_multi_statemach(data, &complete);
3610
3611     *completep = (int)complete;
3612
3613     /* if we got an error or if we don't wait for a data connection return
3614        immediately */
3615     if(result || !ftpc->wait_data_conn)
3616       return result;
3617
3618     /* if we reach the end of the FTP state machine here, *complete will be
3619        TRUE but so is ftpc->wait_data_conn, which says we need to wait for the
3620        data connection and therefore we're not actually complete */
3621     *completep = 0;
3622   }
3623
3624   if(ftp->transfer <= PPTRANSFER_INFO) {
3625     /* a transfer is about to take place, or if not a file name was given
3626        so we'll do a SIZE on it later and then we need the right TYPE first */
3627
3628     if(ftpc->wait_data_conn == TRUE) {
3629       bool serv_conned;
3630
3631       result = ReceivedServerConnect(data, &serv_conned);
3632       if(result)
3633         return result; /* Failed to accept data connection */
3634
3635       if(serv_conned) {
3636         /* It looks data connection is established */
3637         result = AcceptServerConnect(data);
3638         ftpc->wait_data_conn = FALSE;
3639         if(!result)
3640           result = InitiateTransfer(data);
3641
3642         if(result)
3643           return result;
3644
3645         *completep = 1; /* this state is now complete when the server has
3646                            connected back to us */
3647       }
3648     }
3649     else if(data->set.upload) {
3650       result = ftp_nb_type(data, conn, data->state.prefer_ascii,
3651                            FTP_STOR_TYPE);
3652       if(result)
3653         return result;
3654
3655       result = ftp_multi_statemach(data, &complete);
3656       if(ftpc->wait_data_conn)
3657         /* if we reach the end of the FTP state machine here, *complete will be
3658            TRUE but so is ftpc->wait_data_conn, which says we need to wait for
3659            the data connection and therefore we're not actually complete */
3660         *completep = 0;
3661       else
3662         *completep = (int)complete;
3663     }
3664     else {
3665       /* download */
3666       ftp->downloadsize = -1; /* unknown as of yet */
3667
3668       result = Curl_range(data);
3669
3670       if(result == CURLE_OK && data->req.maxdownload >= 0) {
3671         /* Don't check for successful transfer */
3672         ftpc->dont_check = TRUE;
3673       }
3674
3675       if(result)
3676         ;
3677       else if(data->state.list_only || !ftpc->file) {
3678         /* The specified path ends with a slash, and therefore we think this
3679            is a directory that is requested, use LIST. But before that we
3680            need to set ASCII transfer mode. */
3681
3682         /* But only if a body transfer was requested. */
3683         if(ftp->transfer == PPTRANSFER_BODY) {
3684           result = ftp_nb_type(data, conn, TRUE, FTP_LIST_TYPE);
3685           if(result)
3686             return result;
3687         }
3688         /* otherwise just fall through */
3689       }
3690       else {
3691         result = ftp_nb_type(data, conn, data->state.prefer_ascii,
3692                              FTP_RETR_TYPE);
3693         if(result)
3694           return result;
3695       }
3696
3697       result = ftp_multi_statemach(data, &complete);
3698       *completep = (int)complete;
3699     }
3700     return result;
3701   }
3702
3703   /* no data to transfer */
3704   Curl_setup_transfer(data, -1, -1, FALSE, -1);
3705
3706   if(!ftpc->wait_data_conn) {
3707     /* no waiting for the data connection so this is now complete */
3708     *completep = 1;
3709     DEBUGF(infof(data, "DO-MORE phase ends with %d", (int)result));
3710   }
3711
3712   return result;
3713 }
3714
3715
3716
3717 /***********************************************************************
3718  *
3719  * ftp_perform()
3720  *
3721  * This is the actual DO function for FTP. Get a file/directory according to
3722  * the options previously setup.
3723  */
3724
3725 static
3726 CURLcode ftp_perform(struct Curl_easy *data,
3727                      bool *connected,  /* connect status after PASV / PORT */
3728                      bool *dophase_done)
3729 {
3730   /* this is FTP and no proxy */
3731   CURLcode result = CURLE_OK;
3732   struct connectdata *conn = data->conn;
3733
3734   DEBUGF(infof(data, "DO phase starts"));
3735
3736   if(data->set.opt_no_body) {
3737     /* requested no body means no transfer... */
3738     struct FTP *ftp = data->req.p.ftp;
3739     ftp->transfer = PPTRANSFER_INFO;
3740   }
3741
3742   *dophase_done = FALSE; /* not done yet */
3743
3744   /* start the first command in the DO phase */
3745   result = ftp_state_quote(data, TRUE, FTP_QUOTE);
3746   if(result)
3747     return result;
3748
3749   /* run the state-machine */
3750   result = ftp_multi_statemach(data, dophase_done);
3751
3752   *connected = conn->bits.tcpconnect[SECONDARYSOCKET];
3753
3754   infof(data, "ftp_perform ends with SECONDARY: %d", *connected);
3755
3756   if(*dophase_done) {
3757     DEBUGF(infof(data, "DO phase is complete1"));
3758   }
3759
3760   return result;
3761 }
3762
3763 static void wc_data_dtor(void *ptr)
3764 {
3765   struct ftp_wc *ftpwc = ptr;
3766   if(ftpwc && ftpwc->parser)
3767     Curl_ftp_parselist_data_free(&ftpwc->parser);
3768   free(ftpwc);
3769 }
3770
3771 static CURLcode init_wc_data(struct Curl_easy *data)
3772 {
3773   char *last_slash;
3774   struct FTP *ftp = data->req.p.ftp;
3775   char *path = ftp->path;
3776   struct WildcardData *wildcard = &(data->wildcard);
3777   CURLcode result = CURLE_OK;
3778   struct ftp_wc *ftpwc = NULL;
3779
3780   last_slash = strrchr(ftp->path, '/');
3781   if(last_slash) {
3782     last_slash++;
3783     if(last_slash[0] == '\0') {
3784       wildcard->state = CURLWC_CLEAN;
3785       result = ftp_parse_url_path(data);
3786       return result;
3787     }
3788     wildcard->pattern = strdup(last_slash);
3789     if(!wildcard->pattern)
3790       return CURLE_OUT_OF_MEMORY;
3791     last_slash[0] = '\0'; /* cut file from path */
3792   }
3793   else { /* there is only 'wildcard pattern' or nothing */
3794     if(path[0]) {
3795       wildcard->pattern = strdup(path);
3796       if(!wildcard->pattern)
3797         return CURLE_OUT_OF_MEMORY;
3798       path[0] = '\0';
3799     }
3800     else { /* only list */
3801       wildcard->state = CURLWC_CLEAN;
3802       result = ftp_parse_url_path(data);
3803       return result;
3804     }
3805   }
3806
3807   /* program continues only if URL is not ending with slash, allocate needed
3808      resources for wildcard transfer */
3809
3810   /* allocate ftp protocol specific wildcard data */
3811   ftpwc = calloc(1, sizeof(struct ftp_wc));
3812   if(!ftpwc) {
3813     result = CURLE_OUT_OF_MEMORY;
3814     goto fail;
3815   }
3816
3817   /* INITIALIZE parselist structure */
3818   ftpwc->parser = Curl_ftp_parselist_data_alloc();
3819   if(!ftpwc->parser) {
3820     result = CURLE_OUT_OF_MEMORY;
3821     goto fail;
3822   }
3823
3824   wildcard->protdata = ftpwc; /* put it to the WildcardData tmp pointer */
3825   wildcard->dtor = wc_data_dtor;
3826
3827   /* wildcard does not support NOCWD option (assert it?) */
3828   if(data->set.ftp_filemethod == FTPFILE_NOCWD)
3829     data->set.ftp_filemethod = FTPFILE_MULTICWD;
3830
3831   /* try to parse ftp url */
3832   result = ftp_parse_url_path(data);
3833   if(result) {
3834     goto fail;
3835   }
3836
3837   wildcard->path = strdup(ftp->path);
3838   if(!wildcard->path) {
3839     result = CURLE_OUT_OF_MEMORY;
3840     goto fail;
3841   }
3842
3843   /* backup old write_function */
3844   ftpwc->backup.write_function = data->set.fwrite_func;
3845   /* parsing write function */
3846   data->set.fwrite_func = Curl_ftp_parselist;
3847   /* backup old file descriptor */
3848   ftpwc->backup.file_descriptor = data->set.out;
3849   /* let the writefunc callback know the transfer */
3850   data->set.out = data;
3851
3852   infof(data, "Wildcard - Parsing started");
3853   return CURLE_OK;
3854
3855   fail:
3856   if(ftpwc) {
3857     Curl_ftp_parselist_data_free(&ftpwc->parser);
3858     free(ftpwc);
3859   }
3860   Curl_safefree(wildcard->pattern);
3861   wildcard->dtor = ZERO_NULL;
3862   wildcard->protdata = NULL;
3863   return result;
3864 }
3865
3866 static CURLcode wc_statemach(struct Curl_easy *data)
3867 {
3868   struct WildcardData * const wildcard = &(data->wildcard);
3869   struct connectdata *conn = data->conn;
3870   CURLcode result = CURLE_OK;
3871
3872   for(;;) {
3873     switch(wildcard->state) {
3874     case CURLWC_INIT:
3875       result = init_wc_data(data);
3876       if(wildcard->state == CURLWC_CLEAN)
3877         /* only listing! */
3878         return result;
3879       wildcard->state = result ? CURLWC_ERROR : CURLWC_MATCHING;
3880       return result;
3881
3882     case CURLWC_MATCHING: {
3883       /* In this state is LIST response successfully parsed, so lets restore
3884          previous WRITEFUNCTION callback and WRITEDATA pointer */
3885       struct ftp_wc *ftpwc = wildcard->protdata;
3886       data->set.fwrite_func = ftpwc->backup.write_function;
3887       data->set.out = ftpwc->backup.file_descriptor;
3888       ftpwc->backup.write_function = ZERO_NULL;
3889       ftpwc->backup.file_descriptor = NULL;
3890       wildcard->state = CURLWC_DOWNLOADING;
3891
3892       if(Curl_ftp_parselist_geterror(ftpwc->parser)) {
3893         /* error found in LIST parsing */
3894         wildcard->state = CURLWC_CLEAN;
3895         continue;
3896       }
3897       if(wildcard->filelist.size == 0) {
3898         /* no corresponding file */
3899         wildcard->state = CURLWC_CLEAN;
3900         return CURLE_REMOTE_FILE_NOT_FOUND;
3901       }
3902       continue;
3903     }
3904
3905     case CURLWC_DOWNLOADING: {
3906       /* filelist has at least one file, lets get first one */
3907       struct ftp_conn *ftpc = &conn->proto.ftpc;
3908       struct curl_fileinfo *finfo = wildcard->filelist.head->ptr;
3909       struct FTP *ftp = data->req.p.ftp;
3910
3911       char *tmp_path = aprintf("%s%s", wildcard->path, finfo->filename);
3912       if(!tmp_path)
3913         return CURLE_OUT_OF_MEMORY;
3914
3915       /* switch default ftp->path and tmp_path */
3916       free(ftp->pathalloc);
3917       ftp->pathalloc = ftp->path = tmp_path;
3918
3919       infof(data, "Wildcard - START of \"%s\"", finfo->filename);
3920       if(data->set.chunk_bgn) {
3921         long userresponse;
3922         Curl_set_in_callback(data, true);
3923         userresponse = data->set.chunk_bgn(
3924           finfo, wildcard->customptr, (int)wildcard->filelist.size);
3925         Curl_set_in_callback(data, false);
3926         switch(userresponse) {
3927         case CURL_CHUNK_BGN_FUNC_SKIP:
3928           infof(data, "Wildcard - \"%s\" skipped by user",
3929                 finfo->filename);
3930           wildcard->state = CURLWC_SKIP;
3931           continue;
3932         case CURL_CHUNK_BGN_FUNC_FAIL:
3933           return CURLE_CHUNK_FAILED;
3934         }
3935       }
3936
3937       if(finfo->filetype != CURLFILETYPE_FILE) {
3938         wildcard->state = CURLWC_SKIP;
3939         continue;
3940       }
3941
3942       if(finfo->flags & CURLFINFOFLAG_KNOWN_SIZE)
3943         ftpc->known_filesize = finfo->size;
3944
3945       result = ftp_parse_url_path(data);
3946       if(result)
3947         return result;
3948
3949       /* we don't need the Curl_fileinfo of first file anymore */
3950       Curl_llist_remove(&wildcard->filelist, wildcard->filelist.head, NULL);
3951
3952       if(wildcard->filelist.size == 0) { /* remains only one file to down. */
3953         wildcard->state = CURLWC_CLEAN;
3954         /* after that will be ftp_do called once again and no transfer
3955            will be done because of CURLWC_CLEAN state */
3956         return CURLE_OK;
3957       }
3958       return result;
3959     }
3960
3961     case CURLWC_SKIP: {
3962       if(data->set.chunk_end) {
3963         Curl_set_in_callback(data, true);
3964         data->set.chunk_end(data->wildcard.customptr);
3965         Curl_set_in_callback(data, false);
3966       }
3967       Curl_llist_remove(&wildcard->filelist, wildcard->filelist.head, NULL);
3968       wildcard->state = (wildcard->filelist.size == 0) ?
3969         CURLWC_CLEAN : CURLWC_DOWNLOADING;
3970       continue;
3971     }
3972
3973     case CURLWC_CLEAN: {
3974       struct ftp_wc *ftpwc = wildcard->protdata;
3975       result = CURLE_OK;
3976       if(ftpwc)
3977         result = Curl_ftp_parselist_geterror(ftpwc->parser);
3978
3979       wildcard->state = result ? CURLWC_ERROR : CURLWC_DONE;
3980       return result;
3981     }
3982
3983     case CURLWC_DONE:
3984     case CURLWC_ERROR:
3985     case CURLWC_CLEAR:
3986       if(wildcard->dtor)
3987         wildcard->dtor(wildcard->protdata);
3988       return result;
3989     }
3990   }
3991   /* UNREACHABLE */
3992 }
3993
3994 /***********************************************************************
3995  *
3996  * ftp_do()
3997  *
3998  * This function is registered as 'curl_do' function. It decodes the path
3999  * parts etc as a wrapper to the actual DO function (ftp_perform).
4000  *
4001  * The input argument is already checked for validity.
4002  */
4003 static CURLcode ftp_do(struct Curl_easy *data, bool *done)
4004 {
4005   CURLcode result = CURLE_OK;
4006   struct connectdata *conn = data->conn;
4007   struct ftp_conn *ftpc = &conn->proto.ftpc;
4008
4009   *done = FALSE; /* default to false */
4010   ftpc->wait_data_conn = FALSE; /* default to no such wait */
4011
4012   if(data->state.wildcardmatch) {
4013     result = wc_statemach(data);
4014     if(data->wildcard.state == CURLWC_SKIP ||
4015       data->wildcard.state == CURLWC_DONE) {
4016       /* do not call ftp_regular_transfer */
4017       return CURLE_OK;
4018     }
4019     if(result) /* error, loop or skipping the file */
4020       return result;
4021   }
4022   else { /* no wildcard FSM needed */
4023     result = ftp_parse_url_path(data);
4024     if(result)
4025       return result;
4026   }
4027
4028   result = ftp_regular_transfer(data, done);
4029
4030   return result;
4031 }
4032
4033 /***********************************************************************
4034  *
4035  * ftp_quit()
4036  *
4037  * This should be called before calling sclose() on an ftp control connection
4038  * (not data connections). We should then wait for the response from the
4039  * server before returning. The calling code should then try to close the
4040  * connection.
4041  *
4042  */
4043 static CURLcode ftp_quit(struct Curl_easy *data, struct connectdata *conn)
4044 {
4045   CURLcode result = CURLE_OK;
4046
4047   if(conn->proto.ftpc.ctl_valid) {
4048     result = Curl_pp_sendf(data, &conn->proto.ftpc.pp, "%s", "QUIT");
4049     if(result) {
4050       failf(data, "Failure sending QUIT command: %s",
4051             curl_easy_strerror(result));
4052       conn->proto.ftpc.ctl_valid = FALSE; /* mark control connection as bad */
4053       connclose(conn, "QUIT command failed"); /* mark for connection closure */
4054       state(data, FTP_STOP);
4055       return result;
4056     }
4057
4058     state(data, FTP_QUIT);
4059
4060     result = ftp_block_statemach(data, conn);
4061   }
4062
4063   return result;
4064 }
4065
4066 /***********************************************************************
4067  *
4068  * ftp_disconnect()
4069  *
4070  * Disconnect from an FTP server. Cleanup protocol-specific per-connection
4071  * resources. BLOCKING.
4072  */
4073 static CURLcode ftp_disconnect(struct Curl_easy *data,
4074                                struct connectdata *conn,
4075                                bool dead_connection)
4076 {
4077   struct ftp_conn *ftpc = &conn->proto.ftpc;
4078   struct pingpong *pp = &ftpc->pp;
4079
4080   /* We cannot send quit unconditionally. If this connection is stale or
4081      bad in any way, sending quit and waiting around here will make the
4082      disconnect wait in vain and cause more problems than we need to.
4083
4084      ftp_quit() will check the state of ftp->ctl_valid. If it's ok it
4085      will try to send the QUIT command, otherwise it will just return.
4086   */
4087   if(dead_connection)
4088     ftpc->ctl_valid = FALSE;
4089
4090   /* The FTP session may or may not have been allocated/setup at this point! */
4091   (void)ftp_quit(data, conn); /* ignore errors on the QUIT */
4092
4093   if(ftpc->entrypath) {
4094     if(data->state.most_recent_ftp_entrypath == ftpc->entrypath) {
4095       data->state.most_recent_ftp_entrypath = NULL;
4096     }
4097     Curl_safefree(ftpc->entrypath);
4098   }
4099
4100   freedirs(ftpc);
4101   Curl_safefree(ftpc->prevpath);
4102   Curl_safefree(ftpc->server_os);
4103   Curl_pp_disconnect(pp);
4104   Curl_sec_end(conn);
4105   return CURLE_OK;
4106 }
4107
4108 #ifdef _MSC_VER
4109 /* warning C4706: assignment within conditional expression */
4110 #pragma warning(disable:4706)
4111 #endif
4112
4113 /***********************************************************************
4114  *
4115  * ftp_parse_url_path()
4116  *
4117  * Parse the URL path into separate path components.
4118  *
4119  */
4120 static
4121 CURLcode ftp_parse_url_path(struct Curl_easy *data)
4122 {
4123   /* the ftp struct is already inited in ftp_connect() */
4124   struct FTP *ftp = data->req.p.ftp;
4125   struct connectdata *conn = data->conn;
4126   struct ftp_conn *ftpc = &conn->proto.ftpc;
4127   const char *slashPos = NULL;
4128   const char *fileName = NULL;
4129   CURLcode result = CURLE_OK;
4130   char *rawPath = NULL; /* url-decoded "raw" path */
4131   size_t pathLen = 0;
4132
4133   ftpc->ctl_valid = FALSE;
4134   ftpc->cwdfail = FALSE;
4135
4136   /* url-decode ftp path before further evaluation */
4137   result = Curl_urldecode(ftp->path, 0, &rawPath, &pathLen, REJECT_CTRL);
4138   if(result) {
4139     failf(data, "path contains control characters");
4140     return result;
4141   }
4142
4143   switch(data->set.ftp_filemethod) {
4144     case FTPFILE_NOCWD: /* fastest, but less standard-compliant */
4145
4146       if((pathLen > 0) && (rawPath[pathLen - 1] != '/'))
4147           fileName = rawPath;  /* this is a full file path */
4148       /*
4149         else: ftpc->file is not used anywhere other than for operations on
4150               a file. In other words, never for directory operations.
4151               So we can safely leave filename as NULL here and use it as a
4152               argument in dir/file decisions.
4153       */
4154       break;
4155
4156     case FTPFILE_SINGLECWD:
4157       slashPos = strrchr(rawPath, '/');
4158       if(slashPos) {
4159         /* get path before last slash, except for / */
4160         size_t dirlen = slashPos - rawPath;
4161         if(dirlen == 0)
4162             dirlen++;
4163
4164         ftpc->dirs = calloc(1, sizeof(ftpc->dirs[0]));
4165         if(!ftpc->dirs) {
4166           free(rawPath);
4167           return CURLE_OUT_OF_MEMORY;
4168         }
4169
4170         ftpc->dirs[0] = calloc(1, dirlen + 1);
4171         if(!ftpc->dirs[0]) {
4172           free(rawPath);
4173           return CURLE_OUT_OF_MEMORY;
4174         }
4175
4176         strncpy(ftpc->dirs[0], rawPath, dirlen);
4177         ftpc->dirdepth = 1; /* we consider it to be a single dir */
4178         fileName = slashPos + 1; /* rest is file name */
4179       }
4180       else
4181         fileName = rawPath; /* file name only (or empty) */
4182       break;
4183
4184     default: /* allow pretty much anything */
4185     case FTPFILE_MULTICWD: {
4186       /* current position: begin of next path component */
4187       const char *curPos = rawPath;
4188
4189       int dirAlloc = 0; /* number of entries allocated for the 'dirs' array */
4190       const char *str = rawPath;
4191       for(; *str != 0; ++str)
4192         if (*str == '/')
4193           ++dirAlloc;
4194
4195       if(dirAlloc > 0) {
4196         ftpc->dirs = calloc(dirAlloc, sizeof(ftpc->dirs[0]));
4197         if(!ftpc->dirs) {
4198           free(rawPath);
4199           return CURLE_OUT_OF_MEMORY;
4200         }
4201
4202         /* parse the URL path into separate path components */
4203         while((slashPos = strchr(curPos, '/'))) {
4204           size_t compLen = slashPos - curPos;
4205
4206           /* path starts with a slash: add that as a directory */
4207           if((compLen == 0) && (ftpc->dirdepth == 0))
4208             ++compLen;
4209
4210           /* we skip empty path components, like "x//y" since the FTP command
4211              CWD requires a parameter and a non-existent parameter a) doesn't
4212              work on many servers and b) has no effect on the others. */
4213           if(compLen > 0) {
4214             char *comp = calloc(1, compLen + 1);
4215             if(!comp) {
4216               free(rawPath);
4217               return CURLE_OUT_OF_MEMORY;
4218             }
4219             strncpy(comp, curPos, compLen);
4220             ftpc->dirs[ftpc->dirdepth++] = comp;
4221           }
4222           curPos = slashPos + 1;
4223         }
4224       }
4225       DEBUGASSERT(ftpc->dirdepth <= dirAlloc);
4226       fileName = curPos; /* the rest is the file name (or empty) */
4227     }
4228     break;
4229   } /* switch */
4230
4231   if(fileName && *fileName)
4232     ftpc->file = strdup(fileName);
4233   else
4234     ftpc->file = NULL; /* instead of point to a zero byte,
4235                             we make it a NULL pointer */
4236
4237   if(data->set.upload && !ftpc->file && (ftp->transfer == PPTRANSFER_BODY)) {
4238     /* We need a file name when uploading. Return error! */
4239     failf(data, "Uploading to a URL without a file name");
4240     free(rawPath);
4241     return CURLE_URL_MALFORMAT;
4242   }
4243
4244   ftpc->cwddone = FALSE; /* default to not done */
4245
4246   if((data->set.ftp_filemethod == FTPFILE_NOCWD) && (rawPath[0] == '/'))
4247     ftpc->cwddone = TRUE; /* skip CWD for absolute paths */
4248   else { /* newly created FTP connections are already in entry path */
4249     const char *oldPath = conn->bits.reuse ? ftpc->prevpath : "";
4250     if(oldPath) {
4251       size_t n = pathLen;
4252       if(data->set.ftp_filemethod == FTPFILE_NOCWD)
4253         n = 0; /* CWD to entry for relative paths */
4254       else
4255         n -= ftpc->file?strlen(ftpc->file):0;
4256
4257       if((strlen(oldPath) == n) && !strncmp(rawPath, oldPath, n)) {
4258         infof(data, "Request has same path as previous transfer");
4259         ftpc->cwddone = TRUE;
4260       }
4261     }
4262   }
4263
4264   free(rawPath);
4265   return CURLE_OK;
4266 }
4267
4268 /* call this when the DO phase has completed */
4269 static CURLcode ftp_dophase_done(struct Curl_easy *data, bool connected)
4270 {
4271   struct connectdata *conn = data->conn;
4272   struct FTP *ftp = data->req.p.ftp;
4273   struct ftp_conn *ftpc = &conn->proto.ftpc;
4274
4275   if(connected) {
4276     int completed;
4277     CURLcode result = ftp_do_more(data, &completed);
4278
4279     if(result) {
4280       close_secondarysocket(data, conn);
4281       return result;
4282     }
4283   }
4284
4285   if(ftp->transfer != PPTRANSFER_BODY)
4286     /* no data to transfer */
4287     Curl_setup_transfer(data, -1, -1, FALSE, -1);
4288   else if(!connected)
4289     /* since we didn't connect now, we want do_more to get called */
4290     conn->bits.do_more = TRUE;
4291
4292   ftpc->ctl_valid = TRUE; /* seems good */
4293
4294   return CURLE_OK;
4295 }
4296
4297 /* called from multi.c while DOing */
4298 static CURLcode ftp_doing(struct Curl_easy *data,
4299                           bool *dophase_done)
4300 {
4301   CURLcode result = ftp_multi_statemach(data, dophase_done);
4302
4303   if(result)
4304     DEBUGF(infof(data, "DO phase failed"));
4305   else if(*dophase_done) {
4306     result = ftp_dophase_done(data, FALSE /* not connected */);
4307
4308     DEBUGF(infof(data, "DO phase is complete2"));
4309   }
4310   return result;
4311 }
4312
4313 /***********************************************************************
4314  *
4315  * ftp_regular_transfer()
4316  *
4317  * The input argument is already checked for validity.
4318  *
4319  * Performs all commands done before a regular transfer between a local and a
4320  * remote host.
4321  *
4322  * ftp->ctl_valid starts out as FALSE, and gets set to TRUE if we reach the
4323  * ftp_done() function without finding any major problem.
4324  */
4325 static
4326 CURLcode ftp_regular_transfer(struct Curl_easy *data,
4327                               bool *dophase_done)
4328 {
4329   CURLcode result = CURLE_OK;
4330   bool connected = FALSE;
4331   struct connectdata *conn = data->conn;
4332   struct ftp_conn *ftpc = &conn->proto.ftpc;
4333   data->req.size = -1; /* make sure this is unknown at this point */
4334
4335   Curl_pgrsSetUploadCounter(data, 0);
4336   Curl_pgrsSetDownloadCounter(data, 0);
4337   Curl_pgrsSetUploadSize(data, -1);
4338   Curl_pgrsSetDownloadSize(data, -1);
4339
4340   ftpc->ctl_valid = TRUE; /* starts good */
4341
4342   result = ftp_perform(data,
4343                        &connected, /* have we connected after PASV/PORT */
4344                        dophase_done); /* all commands in the DO-phase done? */
4345
4346   if(!result) {
4347
4348     if(!*dophase_done)
4349       /* the DO phase has not completed yet */
4350       return CURLE_OK;
4351
4352     result = ftp_dophase_done(data, connected);
4353
4354     if(result)
4355       return result;
4356   }
4357   else
4358     freedirs(ftpc);
4359
4360   return result;
4361 }
4362
4363 static CURLcode ftp_setup_connection(struct Curl_easy *data,
4364                                      struct connectdata *conn)
4365 {
4366   char *type;
4367   struct FTP *ftp;
4368
4369   data->req.p.ftp = ftp = calloc(sizeof(struct FTP), 1);
4370   if(!ftp)
4371     return CURLE_OUT_OF_MEMORY;
4372
4373   ftp->path = &data->state.up.path[1]; /* don't include the initial slash */
4374
4375   /* FTP URLs support an extension like ";type=<typecode>" that
4376    * we'll try to get now! */
4377   type = strstr(ftp->path, ";type=");
4378
4379   if(!type)
4380     type = strstr(conn->host.rawalloc, ";type=");
4381
4382   if(type) {
4383     char command;
4384     *type = 0;                     /* it was in the middle of the hostname */
4385     command = Curl_raw_toupper(type[6]);
4386
4387     switch(command) {
4388     case 'A': /* ASCII mode */
4389       data->state.prefer_ascii = TRUE;
4390       break;
4391
4392     case 'D': /* directory mode */
4393       data->state.list_only = TRUE;
4394       break;
4395
4396     case 'I': /* binary mode */
4397     default:
4398       /* switch off ASCII */
4399       data->state.prefer_ascii = FALSE;
4400       break;
4401     }
4402   }
4403
4404   /* get some initial data into the ftp struct */
4405   ftp->transfer = PPTRANSFER_BODY;
4406   ftp->downloadsize = 0;
4407   conn->proto.ftpc.known_filesize = -1; /* unknown size for now */
4408
4409   return CURLE_OK;
4410 }
4411
4412 #endif /* CURL_DISABLE_FTP */