Coverage Report

Created: 2025-06-09 07:42

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