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