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