Coverage Report

Created: 2026-03-12 06:35

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