quickjs-tart

quickjs-based runtime for wallet-core logic
Log | Files | Refs | README | LICENSE

ftp.c (143189B)


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