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