Coverage Report

Created: 2025-10-13 06:43

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