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