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