Coverage Report

Created: 2025-08-26 07:09

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