Coverage Report

Created: 2024-02-25 06:14

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