blob: 4e074a111af35755b0e8085e2f433415f50b41a1 [file] [log] [blame]
Kristian Monsen5ab50182010-05-14 18:53:44 +01001/***************************************************************************
2 * _ _ ____ _
3 * Project ___| | | | _ \| |
4 * / __| | | | |_) | |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
7 *
Elliott Hughescac39802018-04-27 16:19:43 -07008 * Copyright (C) 1998 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al.
Kristian Monsen5ab50182010-05-14 18:53:44 +01009 *
10 * This software is licensed as described in the file COPYING, which
11 * you should have received as part of this distribution. The terms
Alex Deymod15eaac2016-06-28 14:49:26 -070012 * are also available at https://curl.haxx.se/docs/copyright.html.
Kristian Monsen5ab50182010-05-14 18:53:44 +010013 *
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 ***************************************************************************/
22
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -070023#include "curl_setup.h"
Kristian Monsen5ab50182010-05-14 18:53:44 +010024
25#ifndef CURL_DISABLE_FTP
Kristian Monsen5ab50182010-05-14 18:53:44 +010026
Kristian Monsen5ab50182010-05-14 18:53:44 +010027#ifdef HAVE_NETINET_IN_H
28#include <netinet/in.h>
29#endif
30#ifdef HAVE_ARPA_INET_H
31#include <arpa/inet.h>
32#endif
33#ifdef HAVE_UTSNAME_H
34#include <sys/utsname.h>
35#endif
36#ifdef HAVE_NETDB_H
37#include <netdb.h>
38#endif
39#ifdef __VMS
40#include <in.h>
41#include <inet.h>
42#endif
43
44#if (defined(NETWARE) && defined(__NOVELL_LIBC__))
45#undef in_addr_t
46#define in_addr_t unsigned long
47#endif
48
49#include <curl/curl.h>
50#include "urldata.h"
51#include "sendf.h"
Kristian Monsen5ab50182010-05-14 18:53:44 +010052#include "if2ip.h"
53#include "hostip.h"
54#include "progress.h"
55#include "transfer.h"
56#include "escape.h"
57#include "http.h" /* for HTTP proxy tunnel stuff */
58#include "socks.h"
59#include "ftp.h"
Lucas Eckels9bd90e62012-08-06 15:07:02 -070060#include "fileinfo.h"
61#include "ftplistparser.h"
Elliott Hughescac39802018-04-27 16:19:43 -070062#include "curl_range.h"
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -070063#include "curl_sec.h"
Kristian Monsen5ab50182010-05-14 18:53:44 +010064#include "strtoofft.h"
Elliott Hughescee03382017-06-23 12:17:18 -070065#include "strcase.h"
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -070066#include "vtls/vtls.h"
Kristian Monsen5ab50182010-05-14 18:53:44 +010067#include "connect.h"
68#include "strerror.h"
69#include "inet_ntop.h"
70#include "inet_pton.h"
71#include "select.h"
72#include "parsedate.h" /* for the week day and month names */
73#include "sockaddr.h" /* required for Curl_sockaddr_storage */
74#include "multiif.h"
75#include "url.h"
Elliott Hughescee03382017-06-23 12:17:18 -070076#include "strcase.h"
Kristian Monsen5ab50182010-05-14 18:53:44 +010077#include "speedcheck.h"
78#include "warnless.h"
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -070079#include "http_proxy.h"
80#include "non-ascii.h"
Alex Deymod15eaac2016-06-28 14:49:26 -070081/* The last 3 #include files should be in this order */
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -070082#include "curl_printf.h"
Kristian Monsen5ab50182010-05-14 18:53:44 +010083#include "curl_memory.h"
Kristian Monsen5ab50182010-05-14 18:53:44 +010084#include "memdebug.h"
85
86#ifndef NI_MAXHOST
87#define NI_MAXHOST 1025
88#endif
89#ifndef INET_ADDRSTRLEN
90#define INET_ADDRSTRLEN 16
91#endif
92
93#ifdef CURL_DISABLE_VERBOSE_STRINGS
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -070094#define ftp_pasv_verbose(a,b,c,d) Curl_nop_stmt
Kristian Monsen5ab50182010-05-14 18:53:44 +010095#endif
96
97/* Local API functions */
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -070098#ifndef DEBUGBUILD
99static void _state(struct connectdata *conn,
100 ftpstate newstate);
101#define state(x,y) _state(x,y)
102#else
103static void _state(struct connectdata *conn,
104 ftpstate newstate,
105 int lineno);
106#define state(x,y) _state(x,y,__LINE__)
107#endif
108
Kristian Monsen5ab50182010-05-14 18:53:44 +0100109static CURLcode ftp_sendquote(struct connectdata *conn,
110 struct curl_slist *quote);
111static CURLcode ftp_quit(struct connectdata *conn);
112static CURLcode ftp_parse_url_path(struct connectdata *conn);
113static CURLcode ftp_regular_transfer(struct connectdata *conn, bool *done);
114#ifndef CURL_DISABLE_VERBOSE_STRINGS
115static void ftp_pasv_verbose(struct connectdata *conn,
116 Curl_addrinfo *ai,
117 char *newhost, /* ascii version */
118 int port);
119#endif
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700120static CURLcode ftp_state_prepare_transfer(struct connectdata *conn);
121static CURLcode ftp_state_mdtm(struct connectdata *conn);
Kristian Monsen5ab50182010-05-14 18:53:44 +0100122static CURLcode ftp_state_quote(struct connectdata *conn,
123 bool init, ftpstate instate);
124static CURLcode ftp_nb_type(struct connectdata *conn,
125 bool ascii, ftpstate newstate);
126static int ftp_need_type(struct connectdata *conn,
127 bool ascii);
128static CURLcode ftp_do(struct connectdata *conn, bool *done);
129static CURLcode ftp_done(struct connectdata *conn,
130 CURLcode, bool premature);
131static CURLcode ftp_connect(struct connectdata *conn, bool *done);
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700132static CURLcode ftp_disconnect(struct connectdata *conn, bool dead_connection);
133static CURLcode ftp_do_more(struct connectdata *conn, int *completed);
Kristian Monsen5ab50182010-05-14 18:53:44 +0100134static CURLcode ftp_multi_statemach(struct connectdata *conn, bool *done);
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700135static int ftp_getsock(struct connectdata *conn, curl_socket_t *socks,
Kristian Monsen5ab50182010-05-14 18:53:44 +0100136 int numsocks);
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700137static int ftp_domore_getsock(struct connectdata *conn, curl_socket_t *socks,
138 int numsocks);
Kristian Monsen5ab50182010-05-14 18:53:44 +0100139static CURLcode ftp_doing(struct connectdata *conn,
140 bool *dophase_done);
141static CURLcode ftp_setup_connection(struct connectdata * conn);
142
Lucas Eckels9bd90e62012-08-06 15:07:02 -0700143static CURLcode init_wc_data(struct connectdata *conn);
144static CURLcode wc_statemach(struct connectdata *conn);
145
146static void wc_data_dtor(void *ptr);
147
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700148static CURLcode ftp_state_retr(struct connectdata *conn, curl_off_t filesize);
149
150static CURLcode ftp_readresp(curl_socket_t sockfd,
151 struct pingpong *pp,
152 int *ftpcode,
153 size_t *size);
154static CURLcode ftp_dophase_done(struct connectdata *conn,
155 bool connected);
Lucas Eckels9bd90e62012-08-06 15:07:02 -0700156
Kristian Monsen5ab50182010-05-14 18:53:44 +0100157/* easy-to-use macro: */
Alex Deymod15eaac2016-06-28 14:49:26 -0700158#define PPSENDF(x,y,z) result = Curl_pp_sendf(x,y,z); \
159 if(result) \
160 return result
Kristian Monsen5ab50182010-05-14 18:53:44 +0100161
162
163/*
164 * FTP protocol handler.
165 */
166
167const struct Curl_handler Curl_handler_ftp = {
168 "FTP", /* scheme */
169 ftp_setup_connection, /* setup_connection */
170 ftp_do, /* do_it */
171 ftp_done, /* done */
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700172 ftp_do_more, /* do_more */
Kristian Monsen5ab50182010-05-14 18:53:44 +0100173 ftp_connect, /* connect_it */
174 ftp_multi_statemach, /* connecting */
175 ftp_doing, /* doing */
176 ftp_getsock, /* proto_getsock */
177 ftp_getsock, /* doing_getsock */
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700178 ftp_domore_getsock, /* domore_getsock */
Kristian Monsen5ab50182010-05-14 18:53:44 +0100179 ZERO_NULL, /* perform_getsock */
180 ftp_disconnect, /* disconnect */
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700181 ZERO_NULL, /* readwrite */
Elliott Hughes82be86d2017-09-20 17:00:17 -0700182 ZERO_NULL, /* connection_check */
Kristian Monsen5ab50182010-05-14 18:53:44 +0100183 PORT_FTP, /* defport */
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700184 CURLPROTO_FTP, /* protocol */
Elliott Hughes82be86d2017-09-20 17:00:17 -0700185 PROTOPT_DUAL | PROTOPT_CLOSEACTION | PROTOPT_NEEDSPWD |
Alex Deymo486467e2017-12-19 19:04:07 +0100186 PROTOPT_NOURLQUERY | PROTOPT_PROXY_AS_HTTP |
187 PROTOPT_WILDCARD /* flags */
Kristian Monsen5ab50182010-05-14 18:53:44 +0100188};
189
190
191#ifdef USE_SSL
192/*
193 * FTPS protocol handler.
194 */
195
196const struct Curl_handler Curl_handler_ftps = {
197 "FTPS", /* scheme */
198 ftp_setup_connection, /* setup_connection */
199 ftp_do, /* do_it */
200 ftp_done, /* done */
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700201 ftp_do_more, /* do_more */
Kristian Monsen5ab50182010-05-14 18:53:44 +0100202 ftp_connect, /* connect_it */
203 ftp_multi_statemach, /* connecting */
204 ftp_doing, /* doing */
205 ftp_getsock, /* proto_getsock */
206 ftp_getsock, /* doing_getsock */
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700207 ftp_domore_getsock, /* domore_getsock */
Kristian Monsen5ab50182010-05-14 18:53:44 +0100208 ZERO_NULL, /* perform_getsock */
209 ftp_disconnect, /* disconnect */
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700210 ZERO_NULL, /* readwrite */
Elliott Hughes82be86d2017-09-20 17:00:17 -0700211 ZERO_NULL, /* connection_check */
Kristian Monsen5ab50182010-05-14 18:53:44 +0100212 PORT_FTPS, /* defport */
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700213 CURLPROTO_FTPS, /* protocol */
214 PROTOPT_SSL | PROTOPT_DUAL | PROTOPT_CLOSEACTION |
Alex Deymo486467e2017-12-19 19:04:07 +0100215 PROTOPT_NEEDSPWD | PROTOPT_NOURLQUERY | PROTOPT_WILDCARD /* flags */
Kristian Monsen5ab50182010-05-14 18:53:44 +0100216};
217#endif
218
Alex Deymod15eaac2016-06-28 14:49:26 -0700219static void close_secondarysocket(struct connectdata *conn)
220{
221 if(CURL_SOCKET_BAD != conn->sock[SECONDARYSOCKET]) {
222 Curl_closesocket(conn, conn->sock[SECONDARYSOCKET]);
223 conn->sock[SECONDARYSOCKET] = CURL_SOCKET_BAD;
224 }
225 conn->bits.tcpconnect[SECONDARYSOCKET] = FALSE;
Alex Deymod15eaac2016-06-28 14:49:26 -0700226}
Kristian Monsen5ab50182010-05-14 18:53:44 +0100227
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
240static void freedirs(struct ftp_conn *ftpc)
241{
242 int i;
243 if(ftpc->dirs) {
Alex Deymo486467e2017-12-19 19:04:07 +0100244 for(i = 0; i < ftpc->dirdepth; i++) {
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700245 free(ftpc->dirs[i]);
Alex Deymo486467e2017-12-19 19:04:07 +0100246 ftpc->dirs[i] = NULL;
Kristian Monsen5ab50182010-05-14 18:53:44 +0100247 }
248 free(ftpc->dirs);
249 ftpc->dirs = NULL;
250 ftpc->dirdepth = 0;
251 }
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700252 Curl_safefree(ftpc->file);
253
254 /* no longer of any use */
255 Curl_safefree(ftpc->newhost);
Kristian Monsen5ab50182010-05-14 18:53:44 +0100256}
257
258/* Returns non-zero if the given string contains CR (\r) or LF (\n),
259 which are not allowed within RFC 959 <string>.
260 Note: The input string is in the client's encoding which might
261 not be ASCII, so escape sequences \r & \n must be used instead
262 of hex values 0x0d & 0x0a.
263*/
264static bool isBadFtpString(const char *string)
265{
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700266 return ((NULL != strchr(string, '\r')) ||
267 (NULL != strchr(string, '\n'))) ? TRUE : FALSE;
Kristian Monsen5ab50182010-05-14 18:53:44 +0100268}
269
270/***********************************************************************
271 *
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700272 * AcceptServerConnect()
Kristian Monsen5ab50182010-05-14 18:53:44 +0100273 *
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700274 * After connection request is received from the server this function is
275 * called to accept the connection and close the listening socket
Kristian Monsen5ab50182010-05-14 18:53:44 +0100276 *
277 */
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700278static CURLcode AcceptServerConnect(struct connectdata *conn)
Kristian Monsen5ab50182010-05-14 18:53:44 +0100279{
Alex Deymoe3149cc2016-10-05 11:18:42 -0700280 struct Curl_easy *data = conn->data;
Kristian Monsen5ab50182010-05-14 18:53:44 +0100281 curl_socket_t sock = conn->sock[SECONDARYSOCKET];
Kristian Monsen5ab50182010-05-14 18:53:44 +0100282 curl_socket_t s = CURL_SOCKET_BAD;
283#ifdef ENABLE_IPV6
284 struct Curl_sockaddr_storage add;
285#else
286 struct sockaddr_in add;
287#endif
288 curl_socklen_t size = (curl_socklen_t) sizeof(add);
289
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700290 if(0 == getsockname(sock, (struct sockaddr *) &add, &size)) {
291 size = sizeof(add);
Kristian Monsen5ab50182010-05-14 18:53:44 +0100292
Alex Deymo486467e2017-12-19 19:04:07 +0100293 s = accept(sock, (struct sockaddr *) &add, &size);
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700294 }
295 Curl_closesocket(conn, sock); /* close the first socket */
296
297 if(CURL_SOCKET_BAD == s) {
298 failf(data, "Error accept()ing server connect");
299 return CURLE_FTP_PORT_FAILED;
300 }
301 infof(data, "Connection accepted from server\n");
Alex Deymod15eaac2016-06-28 14:49:26 -0700302 /* when this happens within the DO state it is important that we mark us as
303 not needing DO_MORE anymore */
304 conn->bits.do_more = FALSE;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700305
306 conn->sock[SECONDARYSOCKET] = s;
307 (void)curlx_nonblock(s, TRUE); /* enable non-blocking */
308 conn->sock_accepted[SECONDARYSOCKET] = TRUE;
309
310 if(data->set.fsockopt) {
311 int error = 0;
312
313 /* activate callback for setting socket options */
Elliott Hughescac39802018-04-27 16:19:43 -0700314 Curl_set_in_callback(data, true);
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700315 error = data->set.fsockopt(data->set.sockopt_client,
316 s,
317 CURLSOCKTYPE_ACCEPT);
Elliott Hughescac39802018-04-27 16:19:43 -0700318 Curl_set_in_callback(data, false);
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700319
320 if(error) {
Alex Deymod15eaac2016-06-28 14:49:26 -0700321 close_secondarysocket(conn);
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700322 return CURLE_ABORTED_BY_CALLBACK;
323 }
324 }
325
326 return CURLE_OK;
327
328}
329
330/*
331 * ftp_timeleft_accept() returns the amount of milliseconds left allowed for
332 * waiting server to connect. If the value is negative, the timeout time has
333 * already elapsed.
334 *
335 * The start time is stored in progress.t_acceptdata - as set with
336 * Curl_pgrsTime(..., TIMER_STARTACCEPT);
337 *
338 */
Alex Deymo486467e2017-12-19 19:04:07 +0100339static timediff_t ftp_timeleft_accept(struct Curl_easy *data)
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700340{
Alex Deymo486467e2017-12-19 19:04:07 +0100341 timediff_t timeout_ms = DEFAULT_ACCEPT_TIMEOUT;
342 timediff_t other;
Elliott Hughes82be86d2017-09-20 17:00:17 -0700343 struct curltime now;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700344
345 if(data->set.accepttimeout > 0)
346 timeout_ms = data->set.accepttimeout;
347
Alex Deymo486467e2017-12-19 19:04:07 +0100348 now = Curl_now();
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700349
350 /* check if the generic timeout possibly is set shorter */
351 other = Curl_timeleft(data, &now, FALSE);
352 if(other && (other < timeout_ms))
353 /* note that this also works fine for when other happens to be negative
354 due to it already having elapsed */
355 timeout_ms = other;
356 else {
357 /* subtract elapsed time */
Alex Deymo486467e2017-12-19 19:04:07 +0100358 timeout_ms -= Curl_timediff(now, data->progress.t_acceptdata);
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700359 if(!timeout_ms)
360 /* avoid returning 0 as that means no timeout! */
361 return -1;
362 }
363
364 return timeout_ms;
365}
366
367
368/***********************************************************************
369 *
370 * ReceivedServerConnect()
371 *
372 * After allowing server to connect to us from data port, this function
373 * checks both data connection for connection establishment and ctrl
374 * connection for a negative response regarding a failure in connecting
375 *
376 */
377static CURLcode ReceivedServerConnect(struct connectdata *conn, bool *received)
378{
Alex Deymoe3149cc2016-10-05 11:18:42 -0700379 struct Curl_easy *data = conn->data;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700380 curl_socket_t ctrl_sock = conn->sock[FIRSTSOCKET];
381 curl_socket_t data_sock = conn->sock[SECONDARYSOCKET];
382 struct ftp_conn *ftpc = &conn->proto.ftpc;
383 struct pingpong *pp = &ftpc->pp;
384 int result;
Elliott Hughescee03382017-06-23 12:17:18 -0700385 time_t timeout_ms;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700386 ssize_t nread;
387 int ftpcode;
388
389 *received = FALSE;
390
391 timeout_ms = ftp_timeleft_accept(data);
392 infof(data, "Checking for server connect\n");
393 if(timeout_ms < 0) {
394 /* if a timeout was already reached, bail out */
395 failf(data, "Accept timeout occurred while waiting server connect");
396 return CURLE_FTP_ACCEPT_TIMEOUT;
397 }
398
399 /* First check whether there is a cached response from server */
400 if(pp->cache_size && pp->cache && pp->cache[0] > '3') {
401 /* Data connection could not be established, let's return */
402 infof(data, "There is negative response in cache while serv connect\n");
403 Curl_GetFTPResponse(&nread, conn, &ftpcode);
404 return CURLE_FTP_ACCEPT_FAILED;
405 }
406
407 result = Curl_socket_check(ctrl_sock, data_sock, CURL_SOCKET_BAD, 0);
408
409 /* see if the connection request is already here */
Elliott Hughes82be86d2017-09-20 17:00:17 -0700410 switch(result) {
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700411 case -1: /* error */
412 /* let's die here */
413 failf(data, "Error while waiting for server connect");
414 return CURLE_FTP_ACCEPT_FAILED;
415 case 0: /* Server connect is not received yet */
416 break; /* loop */
417 default:
418
419 if(result & CURL_CSELECT_IN2) {
420 infof(data, "Ready to accept data connection from server\n");
421 *received = TRUE;
422 }
423 else if(result & CURL_CSELECT_IN) {
424 infof(data, "Ctrl conn has data while waiting for data conn\n");
425 Curl_GetFTPResponse(&nread, conn, &ftpcode);
426
427 if(ftpcode/100 > 3)
428 return CURLE_FTP_ACCEPT_FAILED;
429
Elliott Hughescee03382017-06-23 12:17:18 -0700430 return CURLE_WEIRD_SERVER_REPLY;
Kristian Monsen5ab50182010-05-14 18:53:44 +0100431 }
432
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700433 break;
434 } /* switch() */
Kristian Monsen5ab50182010-05-14 18:53:44 +0100435
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700436 return CURLE_OK;
437}
Kristian Monsen5ab50182010-05-14 18:53:44 +0100438
Kristian Monsen5ab50182010-05-14 18:53:44 +0100439
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700440/***********************************************************************
441 *
442 * InitiateTransfer()
443 *
444 * After connection from server is accepted this function is called to
445 * setup transfer parameters and initiate the data transfer.
446 *
447 */
448static CURLcode InitiateTransfer(struct connectdata *conn)
449{
Alex Deymoe3149cc2016-10-05 11:18:42 -0700450 struct Curl_easy *data = conn->data;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700451 struct FTP *ftp = data->req.protop;
452 CURLcode result = CURLE_OK;
Kristian Monsen5ab50182010-05-14 18:53:44 +0100453
Elliott Hughescee03382017-06-23 12:17:18 -0700454 if(conn->bits.ftp_use_data_ssl) {
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700455 /* since we only have a plaintext TCP connection here, we must now
456 * do the TLS stuff */
457 infof(data, "Doing the SSL/TLS handshake on the data stream\n");
458 result = Curl_ssl_connect(conn, SECONDARYSOCKET);
459 if(result)
460 return result;
Kristian Monsen5ab50182010-05-14 18:53:44 +0100461 }
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700462
463 if(conn->proto.ftpc.state_saved == FTP_STOR) {
Alex Deymo486467e2017-12-19 19:04:07 +0100464 *(ftp->bytecountp) = 0;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700465
466 /* When we know we're uploading a specified file, we can get the file
467 size prior to the actual upload. */
468
469 Curl_pgrsSetUploadSize(data, data->state.infilesize);
470
471 /* set the SO_SNDBUF for the secondary socket for those who need it */
472 Curl_sndbufset(conn->sock[SECONDARYSOCKET]);
473
474 Curl_setup_transfer(conn, -1, -1, FALSE, NULL, /* no download */
475 SECONDARYSOCKET, ftp->bytecountp);
476 }
477 else {
478 /* FTP download: */
479 Curl_setup_transfer(conn, SECONDARYSOCKET,
480 conn->proto.ftpc.retr_size_saved, FALSE,
481 ftp->bytecountp, -1, NULL); /* no upload here */
482 }
483
484 conn->proto.ftpc.pp.pending_resp = TRUE; /* expect server response */
485 state(conn, FTP_STOP);
486
487 return CURLE_OK;
488}
489
490/***********************************************************************
491 *
492 * AllowServerConnect()
493 *
494 * When we've issue the PORT command, we have told the server to connect to
495 * us. This function checks whether data connection is established if so it is
496 * accepted.
497 *
498 */
499static CURLcode AllowServerConnect(struct connectdata *conn, bool *connected)
500{
Alex Deymoe3149cc2016-10-05 11:18:42 -0700501 struct Curl_easy *data = conn->data;
Elliott Hughescee03382017-06-23 12:17:18 -0700502 time_t timeout_ms;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700503 CURLcode result = CURLE_OK;
504
505 *connected = FALSE;
506 infof(data, "Preparing for accepting server on data port\n");
507
508 /* Save the time we start accepting server connect */
509 Curl_pgrsTime(data, TIMER_STARTACCEPT);
510
511 timeout_ms = ftp_timeleft_accept(data);
512 if(timeout_ms < 0) {
513 /* if a timeout was already reached, bail out */
514 failf(data, "Accept timeout occurred while waiting server connect");
515 return CURLE_FTP_ACCEPT_TIMEOUT;
516 }
517
518 /* see if the connection request is already here */
519 result = ReceivedServerConnect(conn, connected);
520 if(result)
521 return result;
522
523 if(*connected) {
524 result = AcceptServerConnect(conn);
525 if(result)
526 return result;
527
528 result = InitiateTransfer(conn);
529 if(result)
530 return result;
531 }
532 else {
533 /* Add timeout to multi handle and break out of the loop */
534 if(!result && *connected == FALSE) {
Elliott Hughes82be86d2017-09-20 17:00:17 -0700535 Curl_expire(data, data->set.accepttimeout > 0 ?
536 data->set.accepttimeout: DEFAULT_ACCEPT_TIMEOUT, 0);
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700537 }
538 }
539
540 return result;
Kristian Monsen5ab50182010-05-14 18:53:44 +0100541}
542
543/* macro to check for a three-digit ftp status code at the start of the
544 given string */
545#define STATUSCODE(line) (ISDIGIT(line[0]) && ISDIGIT(line[1]) && \
546 ISDIGIT(line[2]))
547
548/* macro to check for the last line in an FTP server response */
549#define LASTLINE(line) (STATUSCODE(line) && (' ' == line[3]))
550
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700551static bool ftp_endofresp(struct connectdata *conn, char *line, size_t len,
552 int *code)
Kristian Monsen5ab50182010-05-14 18:53:44 +0100553{
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700554 (void)conn;
Kristian Monsen5ab50182010-05-14 18:53:44 +0100555
556 if((len > 3) && LASTLINE(line)) {
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700557 *code = curlx_sltosi(strtol(line, NULL, 10));
558 return TRUE;
Kristian Monsen5ab50182010-05-14 18:53:44 +0100559 }
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700560
561 return FALSE;
Kristian Monsen5ab50182010-05-14 18:53:44 +0100562}
563
564static CURLcode ftp_readresp(curl_socket_t sockfd,
565 struct pingpong *pp,
566 int *ftpcode, /* return the ftp-code if done */
567 size_t *size) /* size of the response */
568{
569 struct connectdata *conn = pp->conn;
Alex Deymoe3149cc2016-10-05 11:18:42 -0700570 struct Curl_easy *data = conn->data;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700571#ifdef HAVE_GSSAPI
Kristian Monsen5ab50182010-05-14 18:53:44 +0100572 char * const buf = data->state.buffer;
573#endif
574 CURLcode result = CURLE_OK;
575 int code;
576
577 result = Curl_pp_readresp(sockfd, pp, &code, size);
578
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700579#if defined(HAVE_GSSAPI)
Kristian Monsen5ab50182010-05-14 18:53:44 +0100580 /* handle the security-oriented responses 6xx ***/
581 /* FIXME: some errorchecking perhaps... ***/
582 switch(code) {
583 case 631:
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700584 code = Curl_sec_read_msg(conn, buf, PROT_SAFE);
Kristian Monsen5ab50182010-05-14 18:53:44 +0100585 break;
586 case 632:
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700587 code = Curl_sec_read_msg(conn, buf, PROT_PRIVATE);
Kristian Monsen5ab50182010-05-14 18:53:44 +0100588 break;
589 case 633:
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700590 code = Curl_sec_read_msg(conn, buf, PROT_CONFIDENTIAL);
Kristian Monsen5ab50182010-05-14 18:53:44 +0100591 break;
592 default:
593 /* normal ftp stuff we pass through! */
594 break;
595 }
596#endif
597
598 /* store the latest code for later retrieval */
Alex Deymo486467e2017-12-19 19:04:07 +0100599 data->info.httpcode = code;
Kristian Monsen5ab50182010-05-14 18:53:44 +0100600
601 if(ftpcode)
602 *ftpcode = code;
603
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700604 if(421 == code) {
605 /* 421 means "Service not available, closing control connection." and FTP
606 * servers use it to signal that idle session timeout has been exceeded.
607 * If we ignored the response, it could end up hanging in some cases.
608 *
609 * This response code can come at any point so having it treated
610 * generically is a good idea.
611 */
612 infof(data, "We got a 421 - timeout!\n");
613 state(conn, FTP_STOP);
614 return CURLE_OPERATION_TIMEDOUT;
615 }
616
Kristian Monsen5ab50182010-05-14 18:53:44 +0100617 return result;
618}
619
620/* --- parse FTP server responses --- */
621
622/*
623 * Curl_GetFTPResponse() is a BLOCKING function to read the full response
624 * from a server after a command.
625 *
626 */
627
628CURLcode Curl_GetFTPResponse(ssize_t *nreadp, /* return number of bytes read */
629 struct connectdata *conn,
630 int *ftpcode) /* return the ftp-code */
631{
632 /*
633 * We cannot read just one byte per read() and then go back to select() as
634 * the OpenSSL read() doesn't grok that properly.
635 *
636 * Alas, read as much as possible, split up into lines, use the ending
637 * line in a response or continue reading. */
638
639 curl_socket_t sockfd = conn->sock[FIRSTSOCKET];
Elliott Hughescee03382017-06-23 12:17:18 -0700640 time_t timeout; /* timeout in milliseconds */
641 time_t interval_ms;
Alex Deymoe3149cc2016-10-05 11:18:42 -0700642 struct Curl_easy *data = conn->data;
Kristian Monsen5ab50182010-05-14 18:53:44 +0100643 CURLcode result = CURLE_OK;
644 struct ftp_conn *ftpc = &conn->proto.ftpc;
645 struct pingpong *pp = &ftpc->pp;
646 size_t nread;
Alex Deymo486467e2017-12-19 19:04:07 +0100647 int cache_skip = 0;
648 int value_to_be_ignored = 0;
Kristian Monsen5ab50182010-05-14 18:53:44 +0100649
650 if(ftpcode)
651 *ftpcode = 0; /* 0 for errors */
652 else
653 /* make the pointer point to something for the rest of this function */
654 ftpcode = &value_to_be_ignored;
655
Alex Deymo486467e2017-12-19 19:04:07 +0100656 *nreadp = 0;
Kristian Monsen5ab50182010-05-14 18:53:44 +0100657
658 while(!*ftpcode && !result) {
659 /* check and reset timeout value every lap */
660 timeout = Curl_pp_state_timeout(pp);
661
Alex Deymo486467e2017-12-19 19:04:07 +0100662 if(timeout <= 0) {
Kristian Monsen5ab50182010-05-14 18:53:44 +0100663 failf(data, "FTP response timeout");
664 return CURLE_OPERATION_TIMEDOUT; /* already too little time */
665 }
666
667 interval_ms = 1000; /* use 1 second timeout intervals */
668 if(timeout < interval_ms)
669 interval_ms = timeout;
670
671 /*
672 * Since this function is blocking, we need to wait here for input on the
673 * connection and only then we call the response reading function. We do
674 * timeout at least every second to make the timeout check run.
675 *
676 * A caution here is that the ftp_readresp() function has a cache that may
677 * contain pieces of a response from the previous invoke and we need to
678 * make sure we don't just wait for input while there is unhandled data in
679 * that cache. But also, if the cache is there, we call ftp_readresp() and
680 * the cache wasn't good enough to continue we must not just busy-loop
681 * around this function.
682 *
683 */
684
685 if(pp->cache && (cache_skip < 2)) {
686 /*
687 * There's a cache left since before. We then skipping the wait for
688 * socket action, unless this is the same cache like the previous round
689 * as then the cache was deemed not enough to act on and we then need to
690 * wait for more data anyway.
691 */
692 }
Elliott Hughes82be86d2017-09-20 17:00:17 -0700693 else if(!Curl_conn_data_pending(conn, FIRSTSOCKET)) {
694 switch(SOCKET_READABLE(sockfd, interval_ms)) {
Kristian Monsen5ab50182010-05-14 18:53:44 +0100695 case -1: /* select() error, stop reading */
696 failf(data, "FTP response aborted due to select/poll error: %d",
697 SOCKERRNO);
698 return CURLE_RECV_ERROR;
699
700 case 0: /* timeout */
701 if(Curl_pgrsUpdate(conn))
702 return CURLE_ABORTED_BY_CALLBACK;
703 continue; /* just continue in our loop for the timeout duration */
704
705 default: /* for clarity */
706 break;
707 }
708 }
709 result = ftp_readresp(sockfd, pp, ftpcode, &nread);
710 if(result)
711 break;
712
713 if(!nread && pp->cache)
714 /* bump cache skip counter as on repeated skips we must wait for more
715 data */
716 cache_skip++;
717 else
718 /* when we got data or there is no cache left, we reset the cache skip
719 counter */
Alex Deymo486467e2017-12-19 19:04:07 +0100720 cache_skip = 0;
Kristian Monsen5ab50182010-05-14 18:53:44 +0100721
722 *nreadp += nread;
723
724 } /* while there's buffer left and loop is requested */
725
726 pp->pending_resp = FALSE;
727
728 return result;
729}
730
Kristian Monsen5ab50182010-05-14 18:53:44 +0100731#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
732 /* for debug purposes */
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700733static const char * const ftp_state_names[]={
734 "STOP",
735 "WAIT220",
736 "AUTH",
737 "USER",
738 "PASS",
739 "ACCT",
740 "PBSZ",
741 "PROT",
742 "CCC",
743 "PWD",
744 "SYST",
745 "NAMEFMT",
746 "QUOTE",
747 "RETR_PREQUOTE",
748 "STOR_PREQUOTE",
749 "POSTQUOTE",
750 "CWD",
751 "MKD",
752 "MDTM",
753 "TYPE",
754 "LIST_TYPE",
755 "RETR_TYPE",
756 "STOR_TYPE",
757 "SIZE",
758 "RETR_SIZE",
759 "STOR_SIZE",
760 "REST",
761 "RETR_REST",
762 "PORT",
763 "PRET",
764 "PASV",
765 "LIST",
766 "RETR",
767 "STOR",
768 "QUIT"
769};
Kristian Monsen5ab50182010-05-14 18:53:44 +0100770#endif
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700771
772/* This is the ONLY way to change FTP state! */
773static void _state(struct connectdata *conn,
774 ftpstate newstate
775#ifdef DEBUGBUILD
776 , int lineno
777#endif
778 )
779{
Kristian Monsen5ab50182010-05-14 18:53:44 +0100780 struct ftp_conn *ftpc = &conn->proto.ftpc;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700781
782#if defined(DEBUGBUILD)
783
784#if defined(CURL_DISABLE_VERBOSE_STRINGS)
785 (void) lineno;
786#else
Kristian Monsen5ab50182010-05-14 18:53:44 +0100787 if(ftpc->state != newstate)
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700788 infof(conn->data, "FTP %p (line %d) state change from %s to %s\n",
789 (void *)ftpc, lineno, ftp_state_names[ftpc->state],
790 ftp_state_names[newstate]);
Kristian Monsen5ab50182010-05-14 18:53:44 +0100791#endif
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700792#endif
793
Kristian Monsen5ab50182010-05-14 18:53:44 +0100794 ftpc->state = newstate;
795}
796
797static CURLcode ftp_state_user(struct connectdata *conn)
798{
799 CURLcode result;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700800 struct FTP *ftp = conn->data->req.protop;
Kristian Monsen5ab50182010-05-14 18:53:44 +0100801 /* send USER */
802 PPSENDF(&conn->proto.ftpc.pp, "USER %s", ftp->user?ftp->user:"");
803
804 state(conn, FTP_USER);
805 conn->data->state.ftp_trying_alternative = FALSE;
806
807 return CURLE_OK;
808}
809
810static CURLcode ftp_state_pwd(struct connectdata *conn)
811{
812 CURLcode result;
813
814 /* send PWD to discover our entry point */
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700815 PPSENDF(&conn->proto.ftpc.pp, "%s", "PWD");
Kristian Monsen5ab50182010-05-14 18:53:44 +0100816 state(conn, FTP_PWD);
817
818 return CURLE_OK;
819}
820
821/* For the FTP "protocol connect" and "doing" phases only */
822static int ftp_getsock(struct connectdata *conn,
823 curl_socket_t *socks,
824 int numsocks)
825{
826 return Curl_pp_getsock(&conn->proto.ftpc.pp, socks, numsocks);
827}
828
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700829/* For the FTP "DO_MORE" phase only */
830static int ftp_domore_getsock(struct connectdata *conn, curl_socket_t *socks,
831 int numsocks)
832{
833 struct ftp_conn *ftpc = &conn->proto.ftpc;
834
835 if(!numsocks)
836 return GETSOCK_BLANK;
837
838 /* When in DO_MORE state, we could be either waiting for us to connect to a
839 * remote site, or we could wait for that site to connect to us. Or just
840 * handle ordinary commands.
841 */
842
843 if(FTP_STOP == ftpc->state) {
844 int bits = GETSOCK_READSOCK(0);
845
846 /* if stopped and still in this state, then we're also waiting for a
847 connect on the secondary connection */
848 socks[0] = conn->sock[FIRSTSOCKET];
849
850 if(!conn->data->set.ftp_use_port) {
851 int s;
852 int i;
853 /* PORT is used to tell the server to connect to us, and during that we
854 don't do happy eyeballs, but we do if we connect to the server */
Alex Deymo486467e2017-12-19 19:04:07 +0100855 for(s = 1, i = 0; i<2; i++) {
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700856 if(conn->tempsock[i] != CURL_SOCKET_BAD) {
857 socks[s] = conn->tempsock[i];
858 bits |= GETSOCK_WRITESOCK(s++);
859 }
860 }
861 }
862 else {
863 socks[1] = conn->sock[SECONDARYSOCKET];
Elliott Hughescee03382017-06-23 12:17:18 -0700864 bits |= GETSOCK_WRITESOCK(1) | GETSOCK_READSOCK(1);
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700865 }
866
867 return bits;
868 }
Elliott Hughes82be86d2017-09-20 17:00:17 -0700869 return Curl_pp_getsock(&conn->proto.ftpc.pp, socks, numsocks);
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700870}
871
Kristian Monsen5ab50182010-05-14 18:53:44 +0100872/* This is called after the FTP_QUOTE state is passed.
873
874 ftp_state_cwd() sends the range of CWD commands to the server to change to
875 the correct directory. It may also need to send MKD commands to create
876 missing ones, if that option is enabled.
877*/
878static CURLcode ftp_state_cwd(struct connectdata *conn)
879{
880 CURLcode result = CURLE_OK;
881 struct ftp_conn *ftpc = &conn->proto.ftpc;
882
883 if(ftpc->cwddone)
884 /* already done and fine */
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700885 result = ftp_state_mdtm(conn);
Kristian Monsen5ab50182010-05-14 18:53:44 +0100886 else {
887 ftpc->count2 = 0; /* count2 counts failed CWDs */
888
889 /* count3 is set to allow a MKD to fail once. In the case when first CWD
890 fails and then MKD fails (due to another session raced it to create the
891 dir) this then allows for a second try to CWD to it */
Alex Deymo486467e2017-12-19 19:04:07 +0100892 ftpc->count3 = (conn->data->set.ftp_create_missing_dirs == 2)?1:0;
Kristian Monsen5ab50182010-05-14 18:53:44 +0100893
Elliott Hughes82be86d2017-09-20 17:00:17 -0700894 if((conn->data->set.ftp_filemethod == FTPFILE_NOCWD) && !ftpc->cwdcount)
895 /* No CWD necessary */
896 result = ftp_state_mdtm(conn);
897 else if(conn->bits.reuse && ftpc->entrypath) {
Kristian Monsen5ab50182010-05-14 18:53:44 +0100898 /* This is a re-used connection. Since we change directory to where the
899 transfer is taking place, we must first get back to the original dir
900 where we ended up after login: */
Elliott Hughes82be86d2017-09-20 17:00:17 -0700901 ftpc->cwdcount = 0; /* we count this as the first path, then we add one
902 for all upcoming ones in the ftp->dirs[] array */
Kristian Monsen5ab50182010-05-14 18:53:44 +0100903 PPSENDF(&conn->proto.ftpc.pp, "CWD %s", ftpc->entrypath);
904 state(conn, FTP_CWD);
905 }
906 else {
907 if(ftpc->dirdepth) {
Elliott Hughes82be86d2017-09-20 17:00:17 -0700908 ftpc->cwdcount = 1;
Kristian Monsen5ab50182010-05-14 18:53:44 +0100909 /* issue the first CWD, the rest is sent when the CWD responses are
910 received... */
Elliott Hughes82be86d2017-09-20 17:00:17 -0700911 PPSENDF(&conn->proto.ftpc.pp, "CWD %s", ftpc->dirs[ftpc->cwdcount -1]);
Kristian Monsen5ab50182010-05-14 18:53:44 +0100912 state(conn, FTP_CWD);
913 }
914 else {
915 /* No CWD necessary */
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700916 result = ftp_state_mdtm(conn);
Kristian Monsen5ab50182010-05-14 18:53:44 +0100917 }
918 }
919 }
920 return result;
921}
922
923typedef enum {
924 EPRT,
925 PORT,
926 DONE
927} ftpport;
928
929static CURLcode ftp_state_use_port(struct connectdata *conn,
930 ftpport fcmd) /* start with this */
931
932{
933 CURLcode result = CURLE_OK;
934 struct ftp_conn *ftpc = &conn->proto.ftpc;
Alex Deymo486467e2017-12-19 19:04:07 +0100935 struct Curl_easy *data = conn->data;
936 curl_socket_t portsock = CURL_SOCKET_BAD;
Kristian Monsen5ab50182010-05-14 18:53:44 +0100937 char myhost[256] = "";
938
939 struct Curl_sockaddr_storage ss;
940 Curl_addrinfo *res, *ai;
941 curl_socklen_t sslen;
942 char hbuf[NI_MAXHOST];
Alex Deymo486467e2017-12-19 19:04:07 +0100943 struct sockaddr *sa = (struct sockaddr *)&ss;
Kristian Monsen5ab50182010-05-14 18:53:44 +0100944 struct sockaddr_in * const sa4 = (void *)sa;
945#ifdef ENABLE_IPV6
946 struct sockaddr_in6 * const sa6 = (void *)sa;
947#endif
948 char tmp[1024];
949 static const char mode[][5] = { "EPRT", "PORT" };
950 int rc;
951 int error;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700952 char *host = NULL;
Kristian Monsen5ab50182010-05-14 18:53:44 +0100953 char *string_ftpport = data->set.str[STRING_FTPPORT];
Alex Deymo486467e2017-12-19 19:04:07 +0100954 struct Curl_dns_entry *h = NULL;
Kristian Monsen5ab50182010-05-14 18:53:44 +0100955 unsigned short port_min = 0;
956 unsigned short port_max = 0;
957 unsigned short port;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700958 bool possibly_non_local = TRUE;
Kristian Monsen5ab50182010-05-14 18:53:44 +0100959
960 char *addr = NULL;
961
962 /* Step 1, figure out what is requested,
963 * accepted format :
964 * (ipv4|ipv6|domain|interface)?(:port(-range)?)?
965 */
966
967 if(data->set.str[STRING_FTPPORT] &&
968 (strlen(data->set.str[STRING_FTPPORT]) > 1)) {
969
970#ifdef ENABLE_IPV6
971 size_t addrlen = INET6_ADDRSTRLEN > strlen(string_ftpport) ?
972 INET6_ADDRSTRLEN : strlen(string_ftpport);
973#else
974 size_t addrlen = INET_ADDRSTRLEN > strlen(string_ftpport) ?
975 INET_ADDRSTRLEN : strlen(string_ftpport);
976#endif
977 char *ip_start = string_ftpport;
978 char *ip_end = NULL;
979 char *port_start = NULL;
980 char *port_sep = NULL;
981
Alex Deymo486467e2017-12-19 19:04:07 +0100982 addr = calloc(addrlen + 1, 1);
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700983 if(!addr)
Kristian Monsen5ab50182010-05-14 18:53:44 +0100984 return CURLE_OUT_OF_MEMORY;
985
986#ifdef ENABLE_IPV6
987 if(*string_ftpport == '[') {
988 /* [ipv6]:port(-range) */
989 ip_start = string_ftpport + 1;
Elliott Hughes82be86d2017-09-20 17:00:17 -0700990 ip_end = strchr(string_ftpport, ']');
991 if(ip_end)
Kristian Monsen5ab50182010-05-14 18:53:44 +0100992 strncpy(addr, ip_start, ip_end - ip_start);
993 }
994 else
995#endif
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700996 if(*string_ftpport == ':') {
Kristian Monsen5ab50182010-05-14 18:53:44 +0100997 /* :port */
998 ip_end = string_ftpport;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700999 }
Elliott Hughes82be86d2017-09-20 17:00:17 -07001000 else {
1001 ip_end = strchr(string_ftpport, ':');
1002 if(ip_end) {
1003 /* either ipv6 or (ipv4|domain|interface):port(-range) */
1004#ifdef ENABLE_IPV6
1005 if(Curl_inet_pton(AF_INET6, string_ftpport, sa6) == 1) {
1006 /* ipv6 */
1007 port_min = port_max = 0;
1008 strcpy(addr, string_ftpport);
1009 ip_end = NULL; /* this got no port ! */
1010 }
1011 else
Kristian Monsen5ab50182010-05-14 18:53:44 +01001012#endif
Elliott Hughes82be86d2017-09-20 17:00:17 -07001013 /* (ipv4|domain|interface):port(-range) */
1014 strncpy(addr, string_ftpport, ip_end - ip_start);
1015 }
1016 else
1017 /* ipv4|interface */
1018 strcpy(addr, string_ftpport);
1019 }
Kristian Monsen5ab50182010-05-14 18:53:44 +01001020
1021 /* parse the port */
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001022 if(ip_end != NULL) {
Elliott Hughes82be86d2017-09-20 17:00:17 -07001023 port_start = strchr(ip_end, ':');
1024 if(port_start) {
Alex Deymo486467e2017-12-19 19:04:07 +01001025 port_min = curlx_ultous(strtoul(port_start + 1, NULL, 10));
Elliott Hughes82be86d2017-09-20 17:00:17 -07001026 port_sep = strchr(port_start, '-');
1027 if(port_sep) {
Kristian Monsen5ab50182010-05-14 18:53:44 +01001028 port_max = curlx_ultous(strtoul(port_sep + 1, NULL, 10));
1029 }
1030 else
1031 port_max = port_min;
1032 }
1033 }
1034
1035 /* correct errors like:
1036 * :1234-1230
Alex Deymod15eaac2016-06-28 14:49:26 -07001037 * :-4711, in this case port_min is (unsigned)-1,
Kristian Monsen5ab50182010-05-14 18:53:44 +01001038 * therefore port_min > port_max for all cases
1039 * but port_max = (unsigned)-1
1040 */
Alex Deymod15eaac2016-06-28 14:49:26 -07001041 if(port_min > port_max)
Kristian Monsen5ab50182010-05-14 18:53:44 +01001042 port_min = port_max = 0;
1043
1044
1045 if(*addr != '\0') {
1046 /* attempt to get the address of the given interface name */
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001047 switch(Curl_if2ip(conn->ip_addr->ai_family,
1048 Curl_ipv6_scope(conn->ip_addr->ai_addr),
1049 conn->scope_id, addr, hbuf, sizeof(hbuf))) {
1050 case IF2IP_NOT_FOUND:
1051 /* not an interface, use the given string as host name instead */
1052 host = addr;
1053 break;
1054 case IF2IP_AF_NOT_SUPPORTED:
1055 return CURLE_FTP_PORT_FAILED;
1056 case IF2IP_FOUND:
1057 host = hbuf; /* use the hbuf for host name */
1058 }
1059 }
1060 else
Kristian Monsen5ab50182010-05-14 18:53:44 +01001061 /* there was only a port(-range) given, default the host */
1062 host = NULL;
1063 } /* data->set.ftpport */
1064
1065 if(!host) {
1066 /* not an interface and not a host name, get default by extracting
1067 the IP from the control connection */
1068
1069 sslen = sizeof(ss);
1070 if(getsockname(conn->sock[FIRSTSOCKET], sa, &sslen)) {
1071 failf(data, "getsockname() failed: %s",
1072 Curl_strerror(conn, SOCKERRNO) );
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001073 free(addr);
Kristian Monsen5ab50182010-05-14 18:53:44 +01001074 return CURLE_FTP_PORT_FAILED;
1075 }
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001076 switch(sa->sa_family) {
Kristian Monsen5ab50182010-05-14 18:53:44 +01001077#ifdef ENABLE_IPV6
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001078 case AF_INET6:
1079 Curl_inet_ntop(sa->sa_family, &sa6->sin6_addr, hbuf, sizeof(hbuf));
1080 break;
Kristian Monsen5ab50182010-05-14 18:53:44 +01001081#endif
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001082 default:
1083 Curl_inet_ntop(sa->sa_family, &sa4->sin_addr, hbuf, sizeof(hbuf));
1084 break;
Kristian Monsen5ab50182010-05-14 18:53:44 +01001085 }
1086 host = hbuf; /* use this host name */
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001087 possibly_non_local = FALSE; /* we know it is local now */
Kristian Monsen5ab50182010-05-14 18:53:44 +01001088 }
1089
1090 /* resolv ip/host to ip */
1091 rc = Curl_resolv(conn, host, 0, &h);
1092 if(rc == CURLRESOLV_PENDING)
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001093 (void)Curl_resolver_wait_resolv(conn, &h);
Kristian Monsen5ab50182010-05-14 18:53:44 +01001094 if(h) {
1095 res = h->addr;
1096 /* when we return from this function, we can forget about this entry
1097 to we can unlock it now already */
1098 Curl_resolv_unlock(data, h);
1099 } /* (h) */
1100 else
1101 res = NULL; /* failure! */
1102
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001103 if(res == NULL) {
1104 failf(data, "failed to resolve the address provided to PORT: %s", host);
Kristian Monsen5ab50182010-05-14 18:53:44 +01001105 free(addr);
Kristian Monsen5ab50182010-05-14 18:53:44 +01001106 return CURLE_FTP_PORT_FAILED;
1107 }
1108
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001109 free(addr);
1110 host = NULL;
1111
Kristian Monsen5ab50182010-05-14 18:53:44 +01001112 /* step 2, create a socket for the requested address */
1113
1114 portsock = CURL_SOCKET_BAD;
1115 error = 0;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001116 for(ai = res; ai; ai = ai->ai_next) {
1117 result = Curl_socket(conn, ai, NULL, &portsock);
1118 if(result) {
Kristian Monsen5ab50182010-05-14 18:53:44 +01001119 error = SOCKERRNO;
1120 continue;
1121 }
1122 break;
1123 }
1124 if(!ai) {
1125 failf(data, "socket failure: %s", Curl_strerror(conn, error));
1126 return CURLE_FTP_PORT_FAILED;
1127 }
1128
1129 /* step 3, bind to a suitable local address */
1130
1131 memcpy(sa, ai->ai_addr, ai->ai_addrlen);
1132 sslen = ai->ai_addrlen;
1133
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001134 for(port = port_min; port <= port_max;) {
1135 if(sa->sa_family == AF_INET)
Kristian Monsen5ab50182010-05-14 18:53:44 +01001136 sa4->sin_port = htons(port);
1137#ifdef ENABLE_IPV6
1138 else
1139 sa6->sin6_port = htons(port);
1140#endif
1141 /* Try binding the given address. */
1142 if(bind(portsock, sa, sslen) ) {
1143 /* It failed. */
1144 error = SOCKERRNO;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001145 if(possibly_non_local && (error == EADDRNOTAVAIL)) {
Kristian Monsen5ab50182010-05-14 18:53:44 +01001146 /* The requested bind address is not local. Use the address used for
1147 * the control connection instead and restart the port loop
1148 */
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001149
1150 infof(data, "bind(port=%hu) on non-local address failed: %s\n", port,
Kristian Monsen5ab50182010-05-14 18:53:44 +01001151 Curl_strerror(conn, error) );
1152
1153 sslen = sizeof(ss);
1154 if(getsockname(conn->sock[FIRSTSOCKET], sa, &sslen)) {
1155 failf(data, "getsockname() failed: %s",
1156 Curl_strerror(conn, SOCKERRNO) );
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001157 Curl_closesocket(conn, portsock);
Kristian Monsen5ab50182010-05-14 18:53:44 +01001158 return CURLE_FTP_PORT_FAILED;
1159 }
1160 port = port_min;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001161 possibly_non_local = FALSE; /* don't try this again */
Kristian Monsen5ab50182010-05-14 18:53:44 +01001162 continue;
1163 }
Elliott Hughes82be86d2017-09-20 17:00:17 -07001164 if(error != EADDRINUSE && error != EACCES) {
Kristian Monsen5ab50182010-05-14 18:53:44 +01001165 failf(data, "bind(port=%hu) failed: %s", port,
1166 Curl_strerror(conn, error) );
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001167 Curl_closesocket(conn, portsock);
Kristian Monsen5ab50182010-05-14 18:53:44 +01001168 return CURLE_FTP_PORT_FAILED;
1169 }
1170 }
1171 else
1172 break;
1173
1174 port++;
1175 }
1176
1177 /* maybe all ports were in use already*/
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001178 if(port > port_max) {
Kristian Monsen5ab50182010-05-14 18:53:44 +01001179 failf(data, "bind() failed, we ran out of ports!");
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001180 Curl_closesocket(conn, portsock);
Kristian Monsen5ab50182010-05-14 18:53:44 +01001181 return CURLE_FTP_PORT_FAILED;
1182 }
1183
1184 /* get the name again after the bind() so that we can extract the
1185 port number it uses now */
1186 sslen = sizeof(ss);
1187 if(getsockname(portsock, (struct sockaddr *)sa, &sslen)) {
1188 failf(data, "getsockname() failed: %s",
1189 Curl_strerror(conn, SOCKERRNO) );
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001190 Curl_closesocket(conn, portsock);
Kristian Monsen5ab50182010-05-14 18:53:44 +01001191 return CURLE_FTP_PORT_FAILED;
1192 }
1193
1194 /* step 4, listen on the socket */
1195
1196 if(listen(portsock, 1)) {
1197 failf(data, "socket failure: %s", Curl_strerror(conn, SOCKERRNO));
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001198 Curl_closesocket(conn, portsock);
Kristian Monsen5ab50182010-05-14 18:53:44 +01001199 return CURLE_FTP_PORT_FAILED;
1200 }
1201
1202 /* step 5, send the proper FTP command */
1203
1204 /* get a plain printable version of the numerical address to work with
1205 below */
1206 Curl_printable_address(ai, myhost, sizeof(myhost));
1207
1208#ifdef ENABLE_IPV6
1209 if(!conn->bits.ftp_use_eprt && conn->bits.ipv6)
1210 /* EPRT is disabled but we are connected to a IPv6 host, so we ignore the
1211 request and enable EPRT again! */
1212 conn->bits.ftp_use_eprt = TRUE;
1213#endif
1214
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001215 for(; fcmd != DONE; fcmd++) {
Kristian Monsen5ab50182010-05-14 18:53:44 +01001216
1217 if(!conn->bits.ftp_use_eprt && (EPRT == fcmd))
1218 /* if disabled, goto next */
1219 continue;
1220
1221 if((PORT == fcmd) && sa->sa_family != AF_INET)
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001222 /* PORT is IPv4 only */
Kristian Monsen5ab50182010-05-14 18:53:44 +01001223 continue;
1224
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001225 switch(sa->sa_family) {
Kristian Monsen5ab50182010-05-14 18:53:44 +01001226 case AF_INET:
1227 port = ntohs(sa4->sin_port);
1228 break;
1229#ifdef ENABLE_IPV6
1230 case AF_INET6:
1231 port = ntohs(sa6->sin6_port);
1232 break;
1233#endif
1234 default:
1235 continue; /* might as well skip this */
1236 }
1237
1238 if(EPRT == fcmd) {
1239 /*
1240 * Two fine examples from RFC2428;
1241 *
1242 * EPRT |1|132.235.1.2|6275|
1243 *
1244 * EPRT |2|1080::8:800:200C:417A|5282|
1245 */
1246
1247 result = Curl_pp_sendf(&ftpc->pp, "%s |%d|%s|%hu|", mode[fcmd],
1248 sa->sa_family == AF_INET?1:2,
1249 myhost, port);
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001250 if(result) {
1251 failf(data, "Failure sending EPRT command: %s",
1252 curl_easy_strerror(result));
1253 Curl_closesocket(conn, portsock);
1254 /* don't retry using PORT */
1255 ftpc->count1 = PORT;
1256 /* bail out */
1257 state(conn, FTP_STOP);
Kristian Monsen5ab50182010-05-14 18:53:44 +01001258 return result;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001259 }
Kristian Monsen5ab50182010-05-14 18:53:44 +01001260 break;
1261 }
Elliott Hughes82be86d2017-09-20 17:00:17 -07001262 if(PORT == fcmd) {
Kristian Monsen5ab50182010-05-14 18:53:44 +01001263 char *source = myhost;
1264 char *dest = tmp;
1265
1266 /* translate x.x.x.x to x,x,x,x */
1267 while(source && *source) {
1268 if(*source == '.')
Alex Deymo486467e2017-12-19 19:04:07 +01001269 *dest = ',';
Kristian Monsen5ab50182010-05-14 18:53:44 +01001270 else
1271 *dest = *source;
1272 dest++;
1273 source++;
1274 }
1275 *dest = 0;
1276 snprintf(dest, 20, ",%d,%d", (int)(port>>8), (int)(port&0xff));
1277
1278 result = Curl_pp_sendf(&ftpc->pp, "%s %s", mode[fcmd], tmp);
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001279 if(result) {
1280 failf(data, "Failure sending PORT command: %s",
1281 curl_easy_strerror(result));
1282 Curl_closesocket(conn, portsock);
1283 /* bail out */
1284 state(conn, FTP_STOP);
Kristian Monsen5ab50182010-05-14 18:53:44 +01001285 return result;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001286 }
Kristian Monsen5ab50182010-05-14 18:53:44 +01001287 break;
1288 }
1289 }
1290
1291 /* store which command was sent */
1292 ftpc->count1 = fcmd;
1293
Alex Deymod15eaac2016-06-28 14:49:26 -07001294 close_secondarysocket(conn);
1295
Kristian Monsen5ab50182010-05-14 18:53:44 +01001296 /* we set the secondary socket variable to this for now, it is only so that
1297 the cleanup function will close it in case we fail before the true
1298 secondary stuff is made */
Kristian Monsen5ab50182010-05-14 18:53:44 +01001299 conn->sock[SECONDARYSOCKET] = portsock;
1300
1301 /* this tcpconnect assignment below is a hackish work-around to make the
1302 multi interface with active FTP work - as it will not wait for a
1303 (passive) connect in Curl_is_connected().
1304
1305 The *proper* fix is to make sure that the active connection from the
1306 server is done in a non-blocking way. Currently, it is still BLOCKING.
1307 */
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001308 conn->bits.tcpconnect[SECONDARYSOCKET] = TRUE;
Kristian Monsen5ab50182010-05-14 18:53:44 +01001309
1310 state(conn, FTP_PORT);
1311 return result;
1312}
1313
1314static CURLcode ftp_state_use_pasv(struct connectdata *conn)
1315{
1316 struct ftp_conn *ftpc = &conn->proto.ftpc;
1317 CURLcode result = CURLE_OK;
1318 /*
1319 Here's the excecutive summary on what to do:
1320
1321 PASV is RFC959, expect:
1322 227 Entering Passive Mode (a1,a2,a3,a4,p1,p2)
1323
1324 LPSV is RFC1639, expect:
1325 228 Entering Long Passive Mode (4,4,a1,a2,a3,a4,2,p1,p2)
1326
1327 EPSV is RFC2428, expect:
1328 229 Entering Extended Passive Mode (|||port|)
1329
1330 */
1331
1332 static const char mode[][5] = { "EPSV", "PASV" };
1333 int modeoff;
1334
1335#ifdef PF_INET6
1336 if(!conn->bits.ftp_use_epsv && conn->bits.ipv6)
1337 /* EPSV is disabled but we are connected to a IPv6 host, so we ignore the
1338 request and enable EPSV again! */
1339 conn->bits.ftp_use_epsv = TRUE;
1340#endif
1341
1342 modeoff = conn->bits.ftp_use_epsv?0:1;
1343
1344 PPSENDF(&ftpc->pp, "%s", mode[modeoff]);
1345
1346 ftpc->count1 = modeoff;
1347 state(conn, FTP_PASV);
1348 infof(conn->data, "Connect data stream passively\n");
1349
1350 return result;
1351}
1352
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001353/*
1354 * ftp_state_prepare_transfer() starts PORT, PASV or PRET etc.
1355 *
1356 * REST is the last command in the chain of commands when a "head"-like
1357 * request is made. Thus, if an actual transfer is to be made this is where we
1358 * take off for real.
1359 */
1360static CURLcode ftp_state_prepare_transfer(struct connectdata *conn)
Kristian Monsen5ab50182010-05-14 18:53:44 +01001361{
1362 CURLcode result = CURLE_OK;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001363 struct FTP *ftp = conn->data->req.protop;
Alex Deymoe3149cc2016-10-05 11:18:42 -07001364 struct Curl_easy *data = conn->data;
Kristian Monsen5ab50182010-05-14 18:53:44 +01001365
1366 if(ftp->transfer != FTPTRANSFER_BODY) {
1367 /* doesn't transfer any data */
1368
1369 /* still possibly do PRE QUOTE jobs */
1370 state(conn, FTP_RETR_PREQUOTE);
1371 result = ftp_state_quote(conn, TRUE, FTP_RETR_PREQUOTE);
1372 }
1373 else if(data->set.ftp_use_port) {
1374 /* We have chosen to use the PORT (or similar) command */
1375 result = ftp_state_use_port(conn, EPRT);
1376 }
1377 else {
1378 /* We have chosen (this is default) to use the PASV (or similar) command */
1379 if(data->set.ftp_use_pret) {
1380 /* The user has requested that we send a PRET command
1381 to prepare the server for the upcoming PASV */
1382 if(!conn->proto.ftpc.file) {
1383 PPSENDF(&conn->proto.ftpc.pp, "PRET %s",
1384 data->set.str[STRING_CUSTOMREQUEST]?
1385 data->set.str[STRING_CUSTOMREQUEST]:
1386 (data->set.ftp_list_only?"NLST":"LIST"));
1387 }
1388 else if(data->set.upload) {
1389 PPSENDF(&conn->proto.ftpc.pp, "PRET STOR %s", conn->proto.ftpc.file);
1390 }
1391 else {
1392 PPSENDF(&conn->proto.ftpc.pp, "PRET RETR %s", conn->proto.ftpc.file);
1393 }
1394 state(conn, FTP_PRET);
1395 }
1396 else {
1397 result = ftp_state_use_pasv(conn);
1398 }
1399 }
1400 return result;
1401}
1402
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001403static CURLcode ftp_state_rest(struct connectdata *conn)
Kristian Monsen5ab50182010-05-14 18:53:44 +01001404{
1405 CURLcode result = CURLE_OK;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001406 struct FTP *ftp = conn->data->req.protop;
Kristian Monsen5ab50182010-05-14 18:53:44 +01001407 struct ftp_conn *ftpc = &conn->proto.ftpc;
1408
1409 if((ftp->transfer != FTPTRANSFER_BODY) && ftpc->file) {
1410 /* if a "head"-like request is being made (on a file) */
1411
1412 /* Determine if server can respond to REST command and therefore
1413 whether it supports range */
1414 PPSENDF(&conn->proto.ftpc.pp, "REST %d", 0);
1415
1416 state(conn, FTP_REST);
1417 }
1418 else
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001419 result = ftp_state_prepare_transfer(conn);
Kristian Monsen5ab50182010-05-14 18:53:44 +01001420
1421 return result;
1422}
1423
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001424static CURLcode ftp_state_size(struct connectdata *conn)
Kristian Monsen5ab50182010-05-14 18:53:44 +01001425{
1426 CURLcode result = CURLE_OK;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001427 struct FTP *ftp = conn->data->req.protop;
Kristian Monsen5ab50182010-05-14 18:53:44 +01001428 struct ftp_conn *ftpc = &conn->proto.ftpc;
1429
1430 if((ftp->transfer == FTPTRANSFER_INFO) && ftpc->file) {
1431 /* if a "head"-like request is being made (on a file) */
1432
1433 /* we know ftpc->file is a valid pointer to a file name */
1434 PPSENDF(&ftpc->pp, "SIZE %s", ftpc->file);
1435
1436 state(conn, FTP_SIZE);
1437 }
1438 else
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001439 result = ftp_state_rest(conn);
Kristian Monsen5ab50182010-05-14 18:53:44 +01001440
1441 return result;
1442}
1443
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001444static CURLcode ftp_state_list(struct connectdata *conn)
Kristian Monsen5ab50182010-05-14 18:53:44 +01001445{
1446 CURLcode result = CURLE_OK;
Alex Deymoe3149cc2016-10-05 11:18:42 -07001447 struct Curl_easy *data = conn->data;
Kristian Monsen5ab50182010-05-14 18:53:44 +01001448
1449 /* If this output is to be machine-parsed, the NLST command might be better
1450 to use, since the LIST command output is not specified or standard in any
1451 way. It has turned out that the NLST list output is not the same on all
1452 servers either... */
1453
1454 /*
1455 if FTPFILE_NOCWD was specified, we are currently in
1456 the user's home directory, so we should add the path
1457 as argument for the LIST / NLST / or custom command.
1458 Whether the server will support this, is uncertain.
1459
1460 The other ftp_filemethods will CWD into dir/dir/ first and
1461 then just do LIST (in that case: nothing to do here)
1462 */
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001463 char *cmd, *lstArg, *slashPos;
Alex Deymo486467e2017-12-19 19:04:07 +01001464 const char *inpath = data->state.path;
Kristian Monsen5ab50182010-05-14 18:53:44 +01001465
1466 lstArg = NULL;
1467 if((data->set.ftp_filemethod == FTPFILE_NOCWD) &&
Alex Deymo486467e2017-12-19 19:04:07 +01001468 inpath && inpath[0] && strchr(inpath, '/')) {
1469 size_t n = strlen(inpath);
Kristian Monsen5ab50182010-05-14 18:53:44 +01001470
1471 /* Check if path does not end with /, as then we cut off the file part */
Alex Deymo486467e2017-12-19 19:04:07 +01001472 if(inpath[n - 1] != '/') {
Kristian Monsen5ab50182010-05-14 18:53:44 +01001473 /* chop off the file part if format is dir/dir/file */
Alex Deymo486467e2017-12-19 19:04:07 +01001474 slashPos = strrchr(inpath, '/');
1475 n = slashPos - inpath;
Kristian Monsen5ab50182010-05-14 18:53:44 +01001476 }
Elliott Hughescac39802018-04-27 16:19:43 -07001477 result = Curl_urldecode(data, inpath, n, &lstArg, NULL, TRUE);
Alex Deymo486467e2017-12-19 19:04:07 +01001478 if(result)
1479 return result;
Kristian Monsen5ab50182010-05-14 18:53:44 +01001480 }
1481
Alex Deymod15eaac2016-06-28 14:49:26 -07001482 cmd = aprintf("%s%s%s",
1483 data->set.str[STRING_CUSTOMREQUEST]?
1484 data->set.str[STRING_CUSTOMREQUEST]:
1485 (data->set.ftp_list_only?"NLST":"LIST"),
1486 lstArg? " ": "",
1487 lstArg? lstArg: "");
Kristian Monsen5ab50182010-05-14 18:53:44 +01001488
1489 if(!cmd) {
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001490 free(lstArg);
Kristian Monsen5ab50182010-05-14 18:53:44 +01001491 return CURLE_OUT_OF_MEMORY;
1492 }
1493
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001494 result = Curl_pp_sendf(&conn->proto.ftpc.pp, "%s", cmd);
Kristian Monsen5ab50182010-05-14 18:53:44 +01001495
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001496 free(lstArg);
Kristian Monsen5ab50182010-05-14 18:53:44 +01001497 free(cmd);
1498
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001499 if(result)
1500 return result;
1501
Kristian Monsen5ab50182010-05-14 18:53:44 +01001502 state(conn, FTP_LIST);
1503
1504 return result;
1505}
1506
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001507static CURLcode ftp_state_retr_prequote(struct connectdata *conn)
Kristian Monsen5ab50182010-05-14 18:53:44 +01001508{
1509 CURLcode result = CURLE_OK;
1510
1511 /* We've sent the TYPE, now we must send the list of prequote strings */
1512
1513 result = ftp_state_quote(conn, TRUE, FTP_RETR_PREQUOTE);
1514
1515 return result;
1516}
1517
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001518static CURLcode ftp_state_stor_prequote(struct connectdata *conn)
Kristian Monsen5ab50182010-05-14 18:53:44 +01001519{
1520 CURLcode result = CURLE_OK;
1521
1522 /* We've sent the TYPE, now we must send the list of prequote strings */
1523
1524 result = ftp_state_quote(conn, TRUE, FTP_STOR_PREQUOTE);
1525
1526 return result;
1527}
1528
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001529static CURLcode ftp_state_type(struct connectdata *conn)
Kristian Monsen5ab50182010-05-14 18:53:44 +01001530{
1531 CURLcode result = CURLE_OK;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001532 struct FTP *ftp = conn->data->req.protop;
Alex Deymoe3149cc2016-10-05 11:18:42 -07001533 struct Curl_easy *data = conn->data;
Kristian Monsen5ab50182010-05-14 18:53:44 +01001534 struct ftp_conn *ftpc = &conn->proto.ftpc;
1535
1536 /* If we have selected NOBODY and HEADER, it means that we only want file
1537 information. Which in FTP can't be much more than the file size and
1538 date. */
1539 if(data->set.opt_no_body && ftpc->file &&
1540 ftp_need_type(conn, data->set.prefer_ascii)) {
Elliott Hughescac39802018-04-27 16:19:43 -07001541 /* The SIZE command is _not_ RFC 959 specified, and therefore many servers
Kristian Monsen5ab50182010-05-14 18:53:44 +01001542 may not support it! It is however the only way we have to get a file's
1543 size! */
1544
1545 ftp->transfer = FTPTRANSFER_INFO;
1546 /* this means no actual transfer will be made */
1547
1548 /* Some servers return different sizes for different modes, and thus we
1549 must set the proper type before we check the size */
1550 result = ftp_nb_type(conn, data->set.prefer_ascii, FTP_TYPE);
1551 if(result)
1552 return result;
1553 }
1554 else
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001555 result = ftp_state_size(conn);
Kristian Monsen5ab50182010-05-14 18:53:44 +01001556
1557 return result;
1558}
1559
1560/* This is called after the CWD commands have been done in the beginning of
1561 the DO phase */
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001562static CURLcode ftp_state_mdtm(struct connectdata *conn)
Kristian Monsen5ab50182010-05-14 18:53:44 +01001563{
1564 CURLcode result = CURLE_OK;
Alex Deymoe3149cc2016-10-05 11:18:42 -07001565 struct Curl_easy *data = conn->data;
Kristian Monsen5ab50182010-05-14 18:53:44 +01001566 struct ftp_conn *ftpc = &conn->proto.ftpc;
1567
1568 /* Requested time of file or time-depended transfer? */
1569 if((data->set.get_filetime || data->set.timecondition) && ftpc->file) {
1570
1571 /* we have requested to get the modified-time of the file, this is a white
1572 spot as the MDTM is not mentioned in RFC959 */
1573 PPSENDF(&ftpc->pp, "MDTM %s", ftpc->file);
1574
1575 state(conn, FTP_MDTM);
1576 }
1577 else
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001578 result = ftp_state_type(conn);
Kristian Monsen5ab50182010-05-14 18:53:44 +01001579
1580 return result;
1581}
1582
1583
1584/* This is called after the TYPE and possible quote commands have been sent */
1585static CURLcode ftp_state_ul_setup(struct connectdata *conn,
1586 bool sizechecked)
1587{
1588 CURLcode result = CURLE_OK;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001589 struct FTP *ftp = conn->data->req.protop;
Alex Deymoe3149cc2016-10-05 11:18:42 -07001590 struct Curl_easy *data = conn->data;
Kristian Monsen5ab50182010-05-14 18:53:44 +01001591 struct ftp_conn *ftpc = &conn->proto.ftpc;
1592 int seekerr = CURL_SEEKFUNC_OK;
1593
1594 if((data->state.resume_from && !sizechecked) ||
1595 ((data->state.resume_from > 0) && sizechecked)) {
1596 /* we're about to continue the uploading of a file */
1597 /* 1. get already existing file's size. We use the SIZE command for this
1598 which may not exist in the server! The SIZE command is not in
1599 RFC959. */
1600
1601 /* 2. This used to set REST. But since we can do append, we
1602 don't another ftp command. We just skip the source file
1603 offset and then we APPEND the rest on the file instead */
1604
1605 /* 3. pass file-size number of bytes in the source file */
1606 /* 4. lower the infilesize counter */
1607 /* => transfer as usual */
1608
Alex Deymod15eaac2016-06-28 14:49:26 -07001609 if(data->state.resume_from < 0) {
Kristian Monsen5ab50182010-05-14 18:53:44 +01001610 /* Got no given size to start from, figure it out */
1611 PPSENDF(&ftpc->pp, "SIZE %s", ftpc->file);
1612 state(conn, FTP_STOR_SIZE);
1613 return result;
1614 }
1615
1616 /* enable append */
1617 data->set.ftp_append = TRUE;
1618
1619 /* Let's read off the proper amount of bytes from the input. */
1620 if(conn->seek_func) {
Elliott Hughescac39802018-04-27 16:19:43 -07001621 Curl_set_in_callback(data, true);
Kristian Monsen5ab50182010-05-14 18:53:44 +01001622 seekerr = conn->seek_func(conn->seek_client, data->state.resume_from,
1623 SEEK_SET);
Elliott Hughes1ef06ba2018-05-30 15:43:58 -07001624 Curl_set_in_callback(data, false);
Kristian Monsen5ab50182010-05-14 18:53:44 +01001625 }
1626
1627 if(seekerr != CURL_SEEKFUNC_OK) {
Alex Deymo486467e2017-12-19 19:04:07 +01001628 curl_off_t passed = 0;
Kristian Monsen5ab50182010-05-14 18:53:44 +01001629 if(seekerr != CURL_SEEKFUNC_CANTSEEK) {
1630 failf(data, "Could not seek stream");
1631 return CURLE_FTP_COULDNT_USE_REST;
1632 }
1633 /* seekerr == CURL_SEEKFUNC_CANTSEEK (can't seek to offset) */
Elliott Hughes82be86d2017-09-20 17:00:17 -07001634 do {
1635 size_t readthisamountnow =
1636 (data->state.resume_from - passed > data->set.buffer_size) ?
1637 (size_t)data->set.buffer_size :
1638 curlx_sotouz(data->state.resume_from - passed);
Kristian Monsen5ab50182010-05-14 18:53:44 +01001639
Elliott Hughes82be86d2017-09-20 17:00:17 -07001640 size_t actuallyread =
1641 data->state.fread_func(data->state.buffer, 1, readthisamountnow,
1642 data->state.in);
Kristian Monsen5ab50182010-05-14 18:53:44 +01001643
Elliott Hughes82be86d2017-09-20 17:00:17 -07001644 passed += actuallyread;
1645 if((actuallyread == 0) || (actuallyread > readthisamountnow)) {
1646 /* this checks for greater-than only to make sure that the
1647 CURL_READFUNC_ABORT return code still aborts */
1648 failf(data, "Failed to read data");
1649 return CURLE_FTP_COULDNT_USE_REST;
1650 }
1651 } while(passed < data->state.resume_from);
Kristian Monsen5ab50182010-05-14 18:53:44 +01001652 }
1653 /* now, decrease the size of the read */
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001654 if(data->state.infilesize>0) {
1655 data->state.infilesize -= data->state.resume_from;
Kristian Monsen5ab50182010-05-14 18:53:44 +01001656
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001657 if(data->state.infilesize <= 0) {
Kristian Monsen5ab50182010-05-14 18:53:44 +01001658 infof(data, "File already completely uploaded\n");
1659
1660 /* no data to transfer */
Lucas Eckels9bd90e62012-08-06 15:07:02 -07001661 Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
Kristian Monsen5ab50182010-05-14 18:53:44 +01001662
1663 /* Set ->transfer so that we won't get any error in
1664 * ftp_done() because we didn't transfer anything! */
1665 ftp->transfer = FTPTRANSFER_NONE;
1666
1667 state(conn, FTP_STOP);
1668 return CURLE_OK;
1669 }
1670 }
1671 /* we've passed, proceed as normal */
1672 } /* resume_from */
1673
1674 PPSENDF(&ftpc->pp, data->set.ftp_append?"APPE %s":"STOR %s",
1675 ftpc->file);
1676
1677 state(conn, FTP_STOR);
1678
1679 return result;
1680}
1681
1682static CURLcode ftp_state_quote(struct connectdata *conn,
1683 bool init,
1684 ftpstate instate)
1685{
1686 CURLcode result = CURLE_OK;
Alex Deymoe3149cc2016-10-05 11:18:42 -07001687 struct Curl_easy *data = conn->data;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001688 struct FTP *ftp = data->req.protop;
Kristian Monsen5ab50182010-05-14 18:53:44 +01001689 struct ftp_conn *ftpc = &conn->proto.ftpc;
Alex Deymo486467e2017-12-19 19:04:07 +01001690 bool quote = FALSE;
Kristian Monsen5ab50182010-05-14 18:53:44 +01001691 struct curl_slist *item;
1692
1693 switch(instate) {
1694 case FTP_QUOTE:
1695 default:
1696 item = data->set.quote;
1697 break;
1698 case FTP_RETR_PREQUOTE:
1699 case FTP_STOR_PREQUOTE:
1700 item = data->set.prequote;
1701 break;
1702 case FTP_POSTQUOTE:
1703 item = data->set.postquote;
1704 break;
1705 }
1706
1707 /*
1708 * This state uses:
1709 * 'count1' to iterate over the commands to send
Elliott Hughes82be86d2017-09-20 17:00:17 -07001710 * 'count2' to store whether to allow commands to fail
Kristian Monsen5ab50182010-05-14 18:53:44 +01001711 */
1712
1713 if(init)
1714 ftpc->count1 = 0;
1715 else
1716 ftpc->count1++;
1717
1718 if(item) {
1719 int i = 0;
1720
1721 /* Skip count1 items in the linked list */
1722 while((i< ftpc->count1) && item) {
1723 item = item->next;
1724 i++;
1725 }
1726 if(item) {
1727 char *cmd = item->data;
1728 if(cmd[0] == '*') {
1729 cmd++;
1730 ftpc->count2 = 1; /* the sent command is allowed to fail */
1731 }
1732 else
1733 ftpc->count2 = 0; /* failure means cancel operation */
1734
1735 PPSENDF(&ftpc->pp, "%s", cmd);
1736 state(conn, instate);
1737 quote = TRUE;
1738 }
1739 }
1740
1741 if(!quote) {
1742 /* No more quote to send, continue to ... */
1743 switch(instate) {
1744 case FTP_QUOTE:
1745 default:
1746 result = ftp_state_cwd(conn);
1747 break;
1748 case FTP_RETR_PREQUOTE:
1749 if(ftp->transfer != FTPTRANSFER_BODY)
1750 state(conn, FTP_STOP);
1751 else {
Lucas Eckels9bd90e62012-08-06 15:07:02 -07001752 if(ftpc->known_filesize != -1) {
1753 Curl_pgrsSetDownloadSize(data, ftpc->known_filesize);
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001754 result = ftp_state_retr(conn, ftpc->known_filesize);
Lucas Eckels9bd90e62012-08-06 15:07:02 -07001755 }
1756 else {
Alex Deymod15eaac2016-06-28 14:49:26 -07001757 if(data->set.ignorecl) {
1758 /* This code is to support download of growing files. It prevents
1759 the state machine from requesting the file size from the
1760 server. With an unknown file size the download continues until
1761 the server terminates it, otherwise the client stops if the
1762 received byte count exceeds the reported file size. Set option
1763 CURLOPT_IGNORE_CONTENT_LENGTH to 1 to enable this behavior.*/
1764 PPSENDF(&ftpc->pp, "RETR %s", ftpc->file);
1765 state(conn, FTP_RETR);
1766 }
1767 else {
1768 PPSENDF(&ftpc->pp, "SIZE %s", ftpc->file);
1769 state(conn, FTP_RETR_SIZE);
1770 }
Lucas Eckels9bd90e62012-08-06 15:07:02 -07001771 }
Kristian Monsen5ab50182010-05-14 18:53:44 +01001772 }
1773 break;
1774 case FTP_STOR_PREQUOTE:
1775 result = ftp_state_ul_setup(conn, FALSE);
1776 break;
1777 case FTP_POSTQUOTE:
1778 break;
1779 }
1780 }
1781
1782 return result;
1783}
1784
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001785/* called from ftp_state_pasv_resp to switch to PASV in case of EPSV
1786 problems */
1787static CURLcode ftp_epsv_disable(struct connectdata *conn)
1788{
1789 CURLcode result = CURLE_OK;
1790
Elliott Hughes1ef06ba2018-05-30 15:43:58 -07001791 if(conn->bits.ipv6 && !(conn->bits.tunnel_proxy || conn->bits.socksproxy)) {
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001792 /* We can't disable EPSV when doing IPv6, so this is instead a fail */
1793 failf(conn->data, "Failed EPSV attempt, exiting\n");
Elliott Hughescee03382017-06-23 12:17:18 -07001794 return CURLE_WEIRD_SERVER_REPLY;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001795 }
1796
1797 infof(conn->data, "Failed EPSV attempt. Disabling EPSV\n");
1798 /* disable it for next transfer */
1799 conn->bits.ftp_use_epsv = FALSE;
1800 conn->data->state.errorbuf = FALSE; /* allow error message to get
1801 rewritten */
1802 PPSENDF(&conn->proto.ftpc.pp, "%s", "PASV");
1803 conn->proto.ftpc.count1++;
1804 /* remain in/go to the FTP_PASV state */
1805 state(conn, FTP_PASV);
1806 return result;
1807}
1808
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001809
1810static char *control_address(struct connectdata *conn)
1811{
1812 /* Returns the control connection IP address.
1813 If a proxy tunnel is used, returns the original host name instead, because
1814 the effective control connection address is the proxy address,
1815 not the ftp host. */
Elliott Hughescee03382017-06-23 12:17:18 -07001816 if(conn->bits.tunnel_proxy || conn->bits.socksproxy)
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001817 return conn->host.name;
1818
1819 return conn->ip_addr_str;
1820}
1821
Kristian Monsen5ab50182010-05-14 18:53:44 +01001822static CURLcode ftp_state_pasv_resp(struct connectdata *conn,
1823 int ftpcode)
1824{
1825 struct ftp_conn *ftpc = &conn->proto.ftpc;
1826 CURLcode result;
Alex Deymo486467e2017-12-19 19:04:07 +01001827 struct Curl_easy *data = conn->data;
1828 struct Curl_dns_entry *addr = NULL;
Kristian Monsen5ab50182010-05-14 18:53:44 +01001829 int rc;
1830 unsigned short connectport; /* the local port connect() should use! */
Alex Deymo486467e2017-12-19 19:04:07 +01001831 char *str = &data->state.buffer[4]; /* start on the first letter */
Kristian Monsen5ab50182010-05-14 18:53:44 +01001832
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001833 /* if we come here again, make sure the former name is cleared */
1834 Curl_safefree(ftpc->newhost);
1835
Kristian Monsen5ab50182010-05-14 18:53:44 +01001836 if((ftpc->count1 == 0) &&
1837 (ftpcode == 229)) {
1838 /* positive EPSV response */
1839 char *ptr = strchr(str, '(');
1840 if(ptr) {
1841 unsigned int num;
1842 char separator[4];
1843 ptr++;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001844 if(5 == sscanf(ptr, "%c%c%c%u%c",
1845 &separator[0],
1846 &separator[1],
1847 &separator[2],
1848 &num,
1849 &separator[3])) {
Kristian Monsen5ab50182010-05-14 18:53:44 +01001850 const char sep1 = separator[0];
1851 int i;
1852
1853 /* The four separators should be identical, or else this is an oddly
1854 formatted reply and we bail out immediately. */
Alex Deymo486467e2017-12-19 19:04:07 +01001855 for(i = 1; i<4; i++) {
Kristian Monsen5ab50182010-05-14 18:53:44 +01001856 if(separator[i] != sep1) {
Alex Deymo486467e2017-12-19 19:04:07 +01001857 ptr = NULL; /* set to NULL to signal error */
Kristian Monsen5ab50182010-05-14 18:53:44 +01001858 break;
1859 }
1860 }
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001861 if(num > 0xffff) {
1862 failf(data, "Illegal port number in EPSV reply");
1863 return CURLE_FTP_WEIRD_PASV_REPLY;
1864 }
Kristian Monsen5ab50182010-05-14 18:53:44 +01001865 if(ptr) {
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001866 ftpc->newport = (unsigned short)(num & 0xffff);
1867 ftpc->newhost = strdup(control_address(conn));
1868 if(!ftpc->newhost)
1869 return CURLE_OUT_OF_MEMORY;
Kristian Monsen5ab50182010-05-14 18:53:44 +01001870 }
1871 }
1872 else
Alex Deymo486467e2017-12-19 19:04:07 +01001873 ptr = NULL;
Kristian Monsen5ab50182010-05-14 18:53:44 +01001874 }
1875 if(!ptr) {
1876 failf(data, "Weirdly formatted EPSV reply");
1877 return CURLE_FTP_WEIRD_PASV_REPLY;
1878 }
1879 }
1880 else if((ftpc->count1 == 1) &&
1881 (ftpcode == 227)) {
1882 /* positive PASV response */
Alex Deymo486467e2017-12-19 19:04:07 +01001883 unsigned int ip[4];
1884 unsigned int port[2];
Kristian Monsen5ab50182010-05-14 18:53:44 +01001885
1886 /*
1887 * Scan for a sequence of six comma-separated numbers and use them as
1888 * IP+port indicators.
1889 *
1890 * Found reply-strings include:
1891 * "227 Entering Passive Mode (127,0,0,1,4,51)"
1892 * "227 Data transfer will passively listen to 127,0,0,1,4,51"
1893 * "227 Entering passive mode. 127,0,0,1,4,51"
1894 */
1895 while(*str) {
Alex Deymo486467e2017-12-19 19:04:07 +01001896 if(6 == sscanf(str, "%u,%u,%u,%u,%u,%u",
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001897 &ip[0], &ip[1], &ip[2], &ip[3],
1898 &port[0], &port[1]))
Kristian Monsen5ab50182010-05-14 18:53:44 +01001899 break;
1900 str++;
1901 }
1902
Alex Deymo486467e2017-12-19 19:04:07 +01001903 if(!*str || (ip[0] > 255) || (ip[1] > 255) || (ip[2] > 255) ||
1904 (ip[3] > 255) || (port[0] > 255) || (port[1] > 255) ) {
Kristian Monsen5ab50182010-05-14 18:53:44 +01001905 failf(data, "Couldn't interpret the 227-response");
1906 return CURLE_FTP_WEIRD_227_FORMAT;
1907 }
1908
1909 /* we got OK from server */
1910 if(data->set.ftp_skip_ip) {
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001911 /* told to ignore the remotely given IP but instead use the host we used
Kristian Monsen5ab50182010-05-14 18:53:44 +01001912 for the control connection */
Elliott Hughes1ef06ba2018-05-30 15:43:58 -07001913 infof(data, "Skip %u.%u.%u.%u for data connection, re-use %s instead\n",
Kristian Monsen5ab50182010-05-14 18:53:44 +01001914 ip[0], ip[1], ip[2], ip[3],
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001915 conn->host.name);
1916 ftpc->newhost = strdup(control_address(conn));
Kristian Monsen5ab50182010-05-14 18:53:44 +01001917 }
1918 else
Elliott Hughes1ef06ba2018-05-30 15:43:58 -07001919 ftpc->newhost = aprintf("%u.%u.%u.%u", ip[0], ip[1], ip[2], ip[3]);
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001920
1921 if(!ftpc->newhost)
1922 return CURLE_OUT_OF_MEMORY;
1923
1924 ftpc->newport = (unsigned short)(((port[0]<<8) + port[1]) & 0xffff);
Kristian Monsen5ab50182010-05-14 18:53:44 +01001925 }
1926 else if(ftpc->count1 == 0) {
1927 /* EPSV failed, move on to PASV */
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001928 return ftp_epsv_disable(conn);
Kristian Monsen5ab50182010-05-14 18:53:44 +01001929 }
1930 else {
1931 failf(data, "Bad PASV/EPSV response: %03d", ftpcode);
1932 return CURLE_FTP_WEIRD_PASV_REPLY;
1933 }
1934
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001935 if(conn->bits.proxy) {
Kristian Monsen5ab50182010-05-14 18:53:44 +01001936 /*
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001937 * This connection uses a proxy and we need to connect to the proxy again
1938 * here. We don't want to rely on a former host lookup that might've
1939 * expired now, instead we remake the lookup here and now!
Kristian Monsen5ab50182010-05-14 18:53:44 +01001940 */
Elliott Hughescee03382017-06-23 12:17:18 -07001941 const char * const host_name = conn->bits.socksproxy ?
1942 conn->socks_proxy.host.name : conn->http_proxy.host.name;
1943 rc = Curl_resolv(conn, host_name, (int)conn->port, &addr);
Kristian Monsen5ab50182010-05-14 18:53:44 +01001944 if(rc == CURLRESOLV_PENDING)
Lucas Eckels9bd90e62012-08-06 15:07:02 -07001945 /* BLOCKING, ignores the return code but 'addr' will be NULL in
1946 case of failure */
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001947 (void)Curl_resolver_wait_resolv(conn, &addr);
Kristian Monsen5ab50182010-05-14 18:53:44 +01001948
1949 connectport =
1950 (unsigned short)conn->port; /* we connect to the proxy's port */
1951
1952 if(!addr) {
Elliott Hughescee03382017-06-23 12:17:18 -07001953 failf(data, "Can't resolve proxy host %s:%hu", host_name, connectport);
Elliott Hughes82be86d2017-09-20 17:00:17 -07001954 return CURLE_COULDNT_RESOLVE_PROXY;
Kristian Monsen5ab50182010-05-14 18:53:44 +01001955 }
1956 }
1957 else {
1958 /* normal, direct, ftp connection */
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001959 rc = Curl_resolv(conn, ftpc->newhost, ftpc->newport, &addr);
Kristian Monsen5ab50182010-05-14 18:53:44 +01001960 if(rc == CURLRESOLV_PENDING)
1961 /* BLOCKING */
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001962 (void)Curl_resolver_wait_resolv(conn, &addr);
Kristian Monsen5ab50182010-05-14 18:53:44 +01001963
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001964 connectport = ftpc->newport; /* we connect to the remote port */
Kristian Monsen5ab50182010-05-14 18:53:44 +01001965
1966 if(!addr) {
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001967 failf(data, "Can't resolve new host %s:%hu", ftpc->newhost, connectport);
Kristian Monsen5ab50182010-05-14 18:53:44 +01001968 return CURLE_FTP_CANT_GET_HOST;
1969 }
1970 }
1971
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001972 conn->bits.tcpconnect[SECONDARYSOCKET] = FALSE;
1973 result = Curl_connecthost(conn, addr);
Kristian Monsen5ab50182010-05-14 18:53:44 +01001974
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001975 if(result) {
1976 Curl_resolv_unlock(data, addr); /* we're done using this address */
1977 if(ftpc->count1 == 0 && ftpcode == 229)
1978 return ftp_epsv_disable(conn);
Kristian Monsen5ab50182010-05-14 18:53:44 +01001979
Kristian Monsen5ab50182010-05-14 18:53:44 +01001980 return result;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001981 }
Kristian Monsen5ab50182010-05-14 18:53:44 +01001982
Kristian Monsen5ab50182010-05-14 18:53:44 +01001983
1984 /*
1985 * When this is used from the multi interface, this might've returned with
1986 * the 'connected' set to FALSE and thus we are now awaiting a non-blocking
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001987 * connect to connect.
Kristian Monsen5ab50182010-05-14 18:53:44 +01001988 */
1989
1990 if(data->set.verbose)
1991 /* this just dumps information about this second connection */
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001992 ftp_pasv_verbose(conn, addr->addr, ftpc->newhost, connectport);
Kristian Monsen5ab50182010-05-14 18:53:44 +01001993
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001994 Curl_resolv_unlock(data, addr); /* we're done using this address */
Elliott Hughes82be86d2017-09-20 17:00:17 -07001995
1996 Curl_safefree(conn->secondaryhostname);
1997 conn->secondary_port = ftpc->newport;
1998 conn->secondaryhostname = strdup(ftpc->newhost);
1999 if(!conn->secondaryhostname)
2000 return CURLE_OUT_OF_MEMORY;
2001
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07002002 conn->bits.do_more = TRUE;
Kristian Monsen5ab50182010-05-14 18:53:44 +01002003 state(conn, FTP_STOP); /* this phase is completed */
2004
2005 return result;
2006}
2007
2008static CURLcode ftp_state_port_resp(struct connectdata *conn,
2009 int ftpcode)
2010{
Alex Deymoe3149cc2016-10-05 11:18:42 -07002011 struct Curl_easy *data = conn->data;
Kristian Monsen5ab50182010-05-14 18:53:44 +01002012 struct ftp_conn *ftpc = &conn->proto.ftpc;
2013 ftpport fcmd = (ftpport)ftpc->count1;
2014 CURLcode result = CURLE_OK;
2015
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07002016 /* The FTP spec tells a positive response should have code 200.
2017 Be more permissive here to tolerate deviant servers. */
2018 if(ftpcode / 100 != 2) {
Kristian Monsen5ab50182010-05-14 18:53:44 +01002019 /* the command failed */
2020
2021 if(EPRT == fcmd) {
2022 infof(data, "disabling EPRT usage\n");
2023 conn->bits.ftp_use_eprt = FALSE;
2024 }
2025 fcmd++;
2026
2027 if(fcmd == DONE) {
2028 failf(data, "Failed to do PORT");
2029 result = CURLE_FTP_PORT_FAILED;
2030 }
2031 else
2032 /* try next */
2033 result = ftp_state_use_port(conn, fcmd);
2034 }
2035 else {
2036 infof(data, "Connect data stream actively\n");
2037 state(conn, FTP_STOP); /* end of DO phase */
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07002038 result = ftp_dophase_done(conn, FALSE);
Kristian Monsen5ab50182010-05-14 18:53:44 +01002039 }
2040
2041 return result;
2042}
2043
2044static CURLcode ftp_state_mdtm_resp(struct connectdata *conn,
2045 int ftpcode)
2046{
2047 CURLcode result = CURLE_OK;
Alex Deymo486467e2017-12-19 19:04:07 +01002048 struct Curl_easy *data = conn->data;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07002049 struct FTP *ftp = data->req.protop;
Kristian Monsen5ab50182010-05-14 18:53:44 +01002050 struct ftp_conn *ftpc = &conn->proto.ftpc;
2051
2052 switch(ftpcode) {
2053 case 213:
2054 {
2055 /* we got a time. Format should be: "YYYYMMDDHHMMSS[.sss]" where the
2056 last .sss part is optional and means fractions of a second */
2057 int year, month, day, hour, minute, second;
Elliott Hughes82be86d2017-09-20 17:00:17 -07002058 if(6 == sscanf(&data->state.buffer[4], "%04d%02d%02d%02d%02d%02d",
Kristian Monsen5ab50182010-05-14 18:53:44 +01002059 &year, &month, &day, &hour, &minute, &second)) {
2060 /* we have a time, reformat it */
Elliott Hughes82be86d2017-09-20 17:00:17 -07002061 char timebuf[24];
Alex Deymo486467e2017-12-19 19:04:07 +01002062 time_t secs = time(NULL);
Elliott Hughes82be86d2017-09-20 17:00:17 -07002063
2064 snprintf(timebuf, sizeof(timebuf),
Kristian Monsen5ab50182010-05-14 18:53:44 +01002065 "%04d%02d%02d %02d:%02d:%02d GMT",
2066 year, month, day, hour, minute, second);
2067 /* now, convert this into a time() value: */
Elliott Hughescac39802018-04-27 16:19:43 -07002068 data->info.filetime = curl_getdate(timebuf, &secs);
Kristian Monsen5ab50182010-05-14 18:53:44 +01002069 }
2070
2071#ifdef CURL_FTP_HTTPSTYLE_HEAD
2072 /* If we asked for a time of the file and we actually got one as well,
2073 we "emulate" a HTTP-style header in our output. */
2074
2075 if(data->set.opt_no_body &&
2076 ftpc->file &&
2077 data->set.get_filetime &&
Alex Deymo486467e2017-12-19 19:04:07 +01002078 (data->info.filetime >= 0) ) {
Elliott Hughes82be86d2017-09-20 17:00:17 -07002079 char headerbuf[128];
Elliott Hughescac39802018-04-27 16:19:43 -07002080 time_t filetime = data->info.filetime;
Kristian Monsen5ab50182010-05-14 18:53:44 +01002081 struct tm buffer;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07002082 const struct tm *tm = &buffer;
2083
2084 result = Curl_gmtime(filetime, &buffer);
2085 if(result)
2086 return result;
2087
Kristian Monsen5ab50182010-05-14 18:53:44 +01002088 /* format: "Tue, 15 Nov 1994 12:45:26" */
Elliott Hughes82be86d2017-09-20 17:00:17 -07002089 snprintf(headerbuf, sizeof(headerbuf),
Kristian Monsen5ab50182010-05-14 18:53:44 +01002090 "Last-Modified: %s, %02d %s %4d %02d:%02d:%02d GMT\r\n",
2091 Curl_wkday[tm->tm_wday?tm->tm_wday-1:6],
2092 tm->tm_mday,
2093 Curl_month[tm->tm_mon],
2094 tm->tm_year + 1900,
2095 tm->tm_hour,
2096 tm->tm_min,
2097 tm->tm_sec);
Elliott Hughes82be86d2017-09-20 17:00:17 -07002098 result = Curl_client_write(conn, CLIENTWRITE_BOTH, headerbuf, 0);
Kristian Monsen5ab50182010-05-14 18:53:44 +01002099 if(result)
2100 return result;
2101 } /* end of a ridiculous amount of conditionals */
2102#endif
2103 }
2104 break;
2105 default:
2106 infof(data, "unsupported MDTM reply format\n");
2107 break;
2108 case 550: /* "No such file or directory" */
2109 failf(data, "Given file does not exist");
2110 result = CURLE_FTP_COULDNT_RETR_FILE;
2111 break;
2112 }
2113
2114 if(data->set.timecondition) {
2115 if((data->info.filetime > 0) && (data->set.timevalue > 0)) {
2116 switch(data->set.timecondition) {
2117 case CURL_TIMECOND_IFMODSINCE:
2118 default:
2119 if(data->info.filetime <= data->set.timevalue) {
2120 infof(data, "The requested document is not new enough\n");
2121 ftp->transfer = FTPTRANSFER_NONE; /* mark to not transfer data */
2122 data->info.timecond = TRUE;
2123 state(conn, FTP_STOP);
2124 return CURLE_OK;
2125 }
2126 break;
2127 case CURL_TIMECOND_IFUNMODSINCE:
2128 if(data->info.filetime > data->set.timevalue) {
2129 infof(data, "The requested document is not old enough\n");
2130 ftp->transfer = FTPTRANSFER_NONE; /* mark to not transfer data */
2131 data->info.timecond = TRUE;
2132 state(conn, FTP_STOP);
2133 return CURLE_OK;
2134 }
2135 break;
2136 } /* switch */
2137 }
2138 else {
2139 infof(data, "Skipping time comparison\n");
2140 }
2141 }
2142
2143 if(!result)
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07002144 result = ftp_state_type(conn);
Kristian Monsen5ab50182010-05-14 18:53:44 +01002145
2146 return result;
2147}
2148
2149static CURLcode ftp_state_type_resp(struct connectdata *conn,
2150 int ftpcode,
2151 ftpstate instate)
2152{
2153 CURLcode result = CURLE_OK;
Alex Deymo486467e2017-12-19 19:04:07 +01002154 struct Curl_easy *data = conn->data;
Kristian Monsen5ab50182010-05-14 18:53:44 +01002155
2156 if(ftpcode/100 != 2) {
2157 /* "sasserftpd" and "(u)r(x)bot ftpd" both responds with 226 after a
2158 successful 'TYPE I'. While that is not as RFC959 says, it is still a
2159 positive response code and we allow that. */
2160 failf(data, "Couldn't set desired mode");
2161 return CURLE_FTP_COULDNT_SET_TYPE;
2162 }
2163 if(ftpcode != 200)
2164 infof(data, "Got a %03d response code instead of the assumed 200\n",
2165 ftpcode);
2166
2167 if(instate == FTP_TYPE)
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07002168 result = ftp_state_size(conn);
Kristian Monsen5ab50182010-05-14 18:53:44 +01002169 else if(instate == FTP_LIST_TYPE)
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07002170 result = ftp_state_list(conn);
Kristian Monsen5ab50182010-05-14 18:53:44 +01002171 else if(instate == FTP_RETR_TYPE)
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07002172 result = ftp_state_retr_prequote(conn);
Kristian Monsen5ab50182010-05-14 18:53:44 +01002173 else if(instate == FTP_STOR_TYPE)
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07002174 result = ftp_state_stor_prequote(conn);
Kristian Monsen5ab50182010-05-14 18:53:44 +01002175
2176 return result;
2177}
2178
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07002179static CURLcode ftp_state_retr(struct connectdata *conn,
Kristian Monsen5ab50182010-05-14 18:53:44 +01002180 curl_off_t filesize)
2181{
2182 CURLcode result = CURLE_OK;
Alex Deymo486467e2017-12-19 19:04:07 +01002183 struct Curl_easy *data = conn->data;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07002184 struct FTP *ftp = data->req.protop;
Kristian Monsen5ab50182010-05-14 18:53:44 +01002185 struct ftp_conn *ftpc = &conn->proto.ftpc;
2186
2187 if(data->set.max_filesize && (filesize > data->set.max_filesize)) {
2188 failf(data, "Maximum file size exceeded");
2189 return CURLE_FILESIZE_EXCEEDED;
2190 }
2191 ftp->downloadsize = filesize;
2192
2193 if(data->state.resume_from) {
2194 /* We always (attempt to) get the size of downloads, so it is done before
2195 this even when not doing resumes. */
2196 if(filesize == -1) {
2197 infof(data, "ftp server doesn't support SIZE\n");
2198 /* We couldn't get the size and therefore we can't know if there really
2199 is a part of the file left to get, although the server will just
2200 close the connection when we start the connection so it won't cause
2201 us any harm, just not make us exit as nicely. */
2202 }
2203 else {
2204 /* We got a file size report, so we check that there actually is a
2205 part of the file left to get, or else we go home. */
2206 if(data->state.resume_from< 0) {
2207 /* We're supposed to download the last abs(from) bytes */
2208 if(filesize < -data->state.resume_from) {
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07002209 failf(data, "Offset (%" CURL_FORMAT_CURL_OFF_T
2210 ") was beyond file size (%" CURL_FORMAT_CURL_OFF_T ")",
Kristian Monsen5ab50182010-05-14 18:53:44 +01002211 data->state.resume_from, filesize);
2212 return CURLE_BAD_DOWNLOAD_RESUME;
2213 }
2214 /* convert to size to download */
2215 ftp->downloadsize = -data->state.resume_from;
2216 /* download from where? */
2217 data->state.resume_from = filesize - ftp->downloadsize;
2218 }
2219 else {
2220 if(filesize < data->state.resume_from) {
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07002221 failf(data, "Offset (%" CURL_FORMAT_CURL_OFF_T
2222 ") was beyond file size (%" CURL_FORMAT_CURL_OFF_T ")",
Kristian Monsen5ab50182010-05-14 18:53:44 +01002223 data->state.resume_from, filesize);
2224 return CURLE_BAD_DOWNLOAD_RESUME;
2225 }
2226 /* Now store the number of bytes we are expected to download */
2227 ftp->downloadsize = filesize-data->state.resume_from;
2228 }
2229 }
2230
2231 if(ftp->downloadsize == 0) {
2232 /* no data to transfer */
Lucas Eckels9bd90e62012-08-06 15:07:02 -07002233 Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
Kristian Monsen5ab50182010-05-14 18:53:44 +01002234 infof(data, "File already completely downloaded\n");
2235
2236 /* Set ->transfer so that we won't get any error in ftp_done()
2237 * because we didn't transfer the any file */
2238 ftp->transfer = FTPTRANSFER_NONE;
2239 state(conn, FTP_STOP);
2240 return CURLE_OK;
2241 }
2242
2243 /* Set resume file transfer offset */
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07002244 infof(data, "Instructs server to resume from offset %"
2245 CURL_FORMAT_CURL_OFF_T "\n", data->state.resume_from);
Kristian Monsen5ab50182010-05-14 18:53:44 +01002246
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07002247 PPSENDF(&ftpc->pp, "REST %" CURL_FORMAT_CURL_OFF_T,
2248 data->state.resume_from);
Kristian Monsen5ab50182010-05-14 18:53:44 +01002249
2250 state(conn, FTP_RETR_REST);
Kristian Monsen5ab50182010-05-14 18:53:44 +01002251 }
2252 else {
2253 /* no resume */
2254 PPSENDF(&ftpc->pp, "RETR %s", ftpc->file);
2255 state(conn, FTP_RETR);
2256 }
2257
2258 return result;
2259}
2260
2261static CURLcode ftp_state_size_resp(struct connectdata *conn,
2262 int ftpcode,
2263 ftpstate instate)
2264{
2265 CURLcode result = CURLE_OK;
Alex Deymo486467e2017-12-19 19:04:07 +01002266 struct Curl_easy *data = conn->data;
2267 curl_off_t filesize = -1;
Kristian Monsen5ab50182010-05-14 18:53:44 +01002268 char *buf = data->state.buffer;
2269
2270 /* get the size from the ascii string: */
Alex Deymo486467e2017-12-19 19:04:07 +01002271 if(ftpcode == 213)
2272 /* ignores parsing errors, which will make the size remain unknown */
2273 (void)curlx_strtoofft(buf + 4, NULL, 0, &filesize);
Kristian Monsen5ab50182010-05-14 18:53:44 +01002274
2275 if(instate == FTP_SIZE) {
2276#ifdef CURL_FTP_HTTPSTYLE_HEAD
2277 if(-1 != filesize) {
Elliott Hughes82be86d2017-09-20 17:00:17 -07002278 char clbuf[128];
2279 snprintf(clbuf, sizeof(clbuf),
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07002280 "Content-Length: %" CURL_FORMAT_CURL_OFF_T "\r\n", filesize);
Elliott Hughes82be86d2017-09-20 17:00:17 -07002281 result = Curl_client_write(conn, CLIENTWRITE_BOTH, clbuf, 0);
Kristian Monsen5ab50182010-05-14 18:53:44 +01002282 if(result)
2283 return result;
2284 }
2285#endif
2286 Curl_pgrsSetDownloadSize(data, filesize);
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07002287 result = ftp_state_rest(conn);
Kristian Monsen5ab50182010-05-14 18:53:44 +01002288 }
2289 else if(instate == FTP_RETR_SIZE) {
2290 Curl_pgrsSetDownloadSize(data, filesize);
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07002291 result = ftp_state_retr(conn, filesize);
Kristian Monsen5ab50182010-05-14 18:53:44 +01002292 }
2293 else if(instate == FTP_STOR_SIZE) {
2294 data->state.resume_from = filesize;
2295 result = ftp_state_ul_setup(conn, TRUE);
2296 }
2297
2298 return result;
2299}
2300
2301static CURLcode ftp_state_rest_resp(struct connectdata *conn,
2302 int ftpcode,
2303 ftpstate instate)
2304{
2305 CURLcode result = CURLE_OK;
2306 struct ftp_conn *ftpc = &conn->proto.ftpc;
2307
2308 switch(instate) {
2309 case FTP_REST:
2310 default:
2311#ifdef CURL_FTP_HTTPSTYLE_HEAD
2312 if(ftpcode == 350) {
2313 char buffer[24]= { "Accept-ranges: bytes\r\n" };
2314 result = Curl_client_write(conn, CLIENTWRITE_BOTH, buffer, 0);
2315 if(result)
2316 return result;
2317 }
2318#endif
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07002319 result = ftp_state_prepare_transfer(conn);
Kristian Monsen5ab50182010-05-14 18:53:44 +01002320 break;
2321
2322 case FTP_RETR_REST:
2323 if(ftpcode != 350) {
2324 failf(conn->data, "Couldn't use REST");
2325 result = CURLE_FTP_COULDNT_USE_REST;
2326 }
2327 else {
2328 PPSENDF(&ftpc->pp, "RETR %s", ftpc->file);
2329 state(conn, FTP_RETR);
2330 }
2331 break;
2332 }
2333
2334 return result;
2335}
2336
2337static CURLcode ftp_state_stor_resp(struct connectdata *conn,
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07002338 int ftpcode, ftpstate instate)
Kristian Monsen5ab50182010-05-14 18:53:44 +01002339{
2340 CURLcode result = CURLE_OK;
Alex Deymoe3149cc2016-10-05 11:18:42 -07002341 struct Curl_easy *data = conn->data;
Kristian Monsen5ab50182010-05-14 18:53:44 +01002342
Alex Deymo486467e2017-12-19 19:04:07 +01002343 if(ftpcode >= 400) {
Kristian Monsen5ab50182010-05-14 18:53:44 +01002344 failf(data, "Failed FTP upload: %0d", ftpcode);
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07002345 state(conn, FTP_STOP);
Kristian Monsen5ab50182010-05-14 18:53:44 +01002346 /* oops, we never close the sockets! */
2347 return CURLE_UPLOAD_FAILED;
2348 }
2349
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07002350 conn->proto.ftpc.state_saved = instate;
Kristian Monsen5ab50182010-05-14 18:53:44 +01002351
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07002352 /* PORT means we are now awaiting the server to connect to us. */
2353 if(data->set.ftp_use_port) {
2354 bool connected;
2355
2356 state(conn, FTP_STOP); /* no longer in STOR state */
2357
2358 result = AllowServerConnect(conn, &connected);
Kristian Monsen5ab50182010-05-14 18:53:44 +01002359 if(result)
2360 return result;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07002361
2362 if(!connected) {
2363 struct ftp_conn *ftpc = &conn->proto.ftpc;
2364 infof(data, "Data conn was not available immediately\n");
2365 ftpc->wait_data_conn = TRUE;
2366 }
2367
2368 return CURLE_OK;
Kristian Monsen5ab50182010-05-14 18:53:44 +01002369 }
Elliott Hughes82be86d2017-09-20 17:00:17 -07002370 return InitiateTransfer(conn);
Kristian Monsen5ab50182010-05-14 18:53:44 +01002371}
2372
2373/* for LIST and RETR responses */
2374static CURLcode ftp_state_get_resp(struct connectdata *conn,
2375 int ftpcode,
2376 ftpstate instate)
2377{
2378 CURLcode result = CURLE_OK;
Alex Deymoe3149cc2016-10-05 11:18:42 -07002379 struct Curl_easy *data = conn->data;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07002380 struct FTP *ftp = data->req.protop;
Kristian Monsen5ab50182010-05-14 18:53:44 +01002381
2382 if((ftpcode == 150) || (ftpcode == 125)) {
2383
2384 /*
2385 A;
2386 150 Opening BINARY mode data connection for /etc/passwd (2241
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07002387 bytes). (ok, the file is being transferred)
Kristian Monsen5ab50182010-05-14 18:53:44 +01002388
2389 B:
2390 150 Opening ASCII mode data connection for /bin/ls
2391
2392 C:
2393 150 ASCII data connection for /bin/ls (137.167.104.91,37445) (0 bytes).
2394
2395 D:
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07002396 150 Opening ASCII mode data connection for [file] (0.0.0.0,0) (545 bytes)
Kristian Monsen5ab50182010-05-14 18:53:44 +01002397
2398 E:
2399 125 Data connection already open; Transfer starting. */
2400
Alex Deymo486467e2017-12-19 19:04:07 +01002401 curl_off_t size = -1; /* default unknown size */
Kristian Monsen5ab50182010-05-14 18:53:44 +01002402
2403
2404 /*
2405 * It appears that there are FTP-servers that return size 0 for files when
2406 * SIZE is used on the file while being in BINARY mode. To work around
2407 * that (stupid) behavior, we attempt to parse the RETR response even if
2408 * the SIZE returned size zero.
2409 *
2410 * Debugging help from Salvatore Sorrentino on February 26, 2003.
2411 */
2412
2413 if((instate != FTP_LIST) &&
2414 !data->set.prefer_ascii &&
2415 (ftp->downloadsize < 1)) {
2416 /*
2417 * It seems directory listings either don't show the size or very
2418 * often uses size 0 anyway. ASCII transfers may very well turn out
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07002419 * that the transferred amount of data is not the same as this line
Kristian Monsen5ab50182010-05-14 18:53:44 +01002420 * tells, why using this number in those cases only confuses us.
2421 *
2422 * Example D above makes this parsing a little tricky */
2423 char *bytes;
Elliott Hughes82be86d2017-09-20 17:00:17 -07002424 char *buf = data->state.buffer;
Alex Deymo486467e2017-12-19 19:04:07 +01002425 bytes = strstr(buf, " bytes");
2426 if(bytes) {
2427 long in = (long)(--bytes-buf);
Kristian Monsen5ab50182010-05-14 18:53:44 +01002428 /* this is a hint there is size information in there! ;-) */
2429 while(--in) {
2430 /* scan for the left parenthesis and break there */
2431 if('(' == *bytes)
2432 break;
2433 /* skip only digits */
2434 if(!ISDIGIT(*bytes)) {
Alex Deymo486467e2017-12-19 19:04:07 +01002435 bytes = NULL;
Kristian Monsen5ab50182010-05-14 18:53:44 +01002436 break;
2437 }
2438 /* one more estep backwards */
2439 bytes--;
2440 }
2441 /* if we have nothing but digits: */
2442 if(bytes++) {
2443 /* get the number! */
Alex Deymo486467e2017-12-19 19:04:07 +01002444 (void)curlx_strtoofft(bytes, NULL, 0, &size);
Kristian Monsen5ab50182010-05-14 18:53:44 +01002445 }
2446 }
2447 }
2448 else if(ftp->downloadsize > -1)
2449 size = ftp->downloadsize;
2450
Kristian Monsen5ab50182010-05-14 18:53:44 +01002451 if(size > data->req.maxdownload && data->req.maxdownload > 0)
2452 size = data->req.size = data->req.maxdownload;
2453 else if((instate != FTP_LIST) && (data->set.prefer_ascii))
2454 size = -1; /* kludge for servers that understate ASCII mode file size */
2455
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07002456 infof(data, "Maxdownload = %" CURL_FORMAT_CURL_OFF_T "\n",
2457 data->req.maxdownload);
Kristian Monsen5ab50182010-05-14 18:53:44 +01002458
2459 if(instate != FTP_LIST)
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07002460 infof(data, "Getting file with size: %" CURL_FORMAT_CURL_OFF_T "\n",
2461 size);
Kristian Monsen5ab50182010-05-14 18:53:44 +01002462
2463 /* FTP download: */
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07002464 conn->proto.ftpc.state_saved = instate;
2465 conn->proto.ftpc.retr_size_saved = size;
Kristian Monsen5ab50182010-05-14 18:53:44 +01002466
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07002467 if(data->set.ftp_use_port) {
2468 bool connected;
2469
2470 result = AllowServerConnect(conn, &connected);
2471 if(result)
2472 return result;
2473
2474 if(!connected) {
2475 struct ftp_conn *ftpc = &conn->proto.ftpc;
2476 infof(data, "Data conn was not available immediately\n");
2477 state(conn, FTP_STOP);
2478 ftpc->wait_data_conn = TRUE;
2479 }
2480 }
2481 else
2482 return InitiateTransfer(conn);
Kristian Monsen5ab50182010-05-14 18:53:44 +01002483 }
2484 else {
2485 if((instate == FTP_LIST) && (ftpcode == 450)) {
2486 /* simply no matching files in the dir listing */
2487 ftp->transfer = FTPTRANSFER_NONE; /* don't download anything */
2488 state(conn, FTP_STOP); /* this phase is over */
2489 }
2490 else {
2491 failf(data, "RETR response: %03d", ftpcode);
2492 return instate == FTP_RETR && ftpcode == 550?
2493 CURLE_REMOTE_FILE_NOT_FOUND:
2494 CURLE_FTP_COULDNT_RETR_FILE;
2495 }
2496 }
2497
2498 return result;
2499}
2500
2501/* after USER, PASS and ACCT */
2502static CURLcode ftp_state_loggedin(struct connectdata *conn)
2503{
2504 CURLcode result = CURLE_OK;
2505
Kristian Monsen5ab50182010-05-14 18:53:44 +01002506 if(conn->ssl[FIRSTSOCKET].use) {
2507 /* PBSZ = PROTECTION BUFFER SIZE.
2508
2509 The 'draft-murray-auth-ftp-ssl' (draft 12, page 7) says:
2510
2511 Specifically, the PROT command MUST be preceded by a PBSZ
2512 command and a PBSZ command MUST be preceded by a successful
2513 security data exchange (the TLS negotiation in this case)
2514
2515 ... (and on page 8):
2516
2517 Thus the PBSZ command must still be issued, but must have a
2518 parameter of '0' to indicate that no buffering is taking place
2519 and the data connection should not be encapsulated.
2520 */
2521 PPSENDF(&conn->proto.ftpc.pp, "PBSZ %d", 0);
2522 state(conn, FTP_PBSZ);
2523 }
2524 else {
2525 result = ftp_state_pwd(conn);
2526 }
2527 return result;
2528}
2529
2530/* for USER and PASS responses */
2531static CURLcode ftp_state_user_resp(struct connectdata *conn,
2532 int ftpcode,
2533 ftpstate instate)
2534{
2535 CURLcode result = CURLE_OK;
Alex Deymoe3149cc2016-10-05 11:18:42 -07002536 struct Curl_easy *data = conn->data;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07002537 struct FTP *ftp = data->req.protop;
Kristian Monsen5ab50182010-05-14 18:53:44 +01002538 struct ftp_conn *ftpc = &conn->proto.ftpc;
2539 (void)instate; /* no use for this yet */
2540
2541 /* some need password anyway, and others just return 2xx ignored */
2542 if((ftpcode == 331) && (ftpc->state == FTP_USER)) {
2543 /* 331 Password required for ...
2544 (the server requires to send the user's password too) */
2545 PPSENDF(&ftpc->pp, "PASS %s", ftp->passwd?ftp->passwd:"");
2546 state(conn, FTP_PASS);
2547 }
2548 else if(ftpcode/100 == 2) {
2549 /* 230 User ... logged in.
2550 (the user logged in with or without password) */
2551 result = ftp_state_loggedin(conn);
2552 }
2553 else if(ftpcode == 332) {
2554 if(data->set.str[STRING_FTP_ACCOUNT]) {
2555 PPSENDF(&ftpc->pp, "ACCT %s", data->set.str[STRING_FTP_ACCOUNT]);
2556 state(conn, FTP_ACCT);
2557 }
2558 else {
2559 failf(data, "ACCT requested but none available");
2560 result = CURLE_LOGIN_DENIED;
2561 }
2562 }
2563 else {
2564 /* All other response codes, like:
2565
2566 530 User ... access denied
2567 (the server denies to log the specified user) */
2568
2569 if(conn->data->set.str[STRING_FTP_ALTERNATIVE_TO_USER] &&
2570 !conn->data->state.ftp_trying_alternative) {
2571 /* Ok, USER failed. Let's try the supplied command. */
2572 PPSENDF(&conn->proto.ftpc.pp, "%s",
2573 conn->data->set.str[STRING_FTP_ALTERNATIVE_TO_USER]);
2574 conn->data->state.ftp_trying_alternative = TRUE;
2575 state(conn, FTP_USER);
2576 result = CURLE_OK;
2577 }
2578 else {
2579 failf(data, "Access denied: %03d", ftpcode);
2580 result = CURLE_LOGIN_DENIED;
2581 }
2582 }
2583 return result;
2584}
2585
2586/* for ACCT response */
2587static CURLcode ftp_state_acct_resp(struct connectdata *conn,
2588 int ftpcode)
2589{
2590 CURLcode result = CURLE_OK;
Alex Deymoe3149cc2016-10-05 11:18:42 -07002591 struct Curl_easy *data = conn->data;
Kristian Monsen5ab50182010-05-14 18:53:44 +01002592 if(ftpcode != 230) {
2593 failf(data, "ACCT rejected by server: %03d", ftpcode);
2594 result = CURLE_FTP_WEIRD_PASS_REPLY; /* FIX */
2595 }
2596 else
2597 result = ftp_state_loggedin(conn);
2598
2599 return result;
2600}
2601
2602
2603static CURLcode ftp_statemach_act(struct connectdata *conn)
2604{
2605 CURLcode result;
2606 curl_socket_t sock = conn->sock[FIRSTSOCKET];
Alex Deymo486467e2017-12-19 19:04:07 +01002607 struct Curl_easy *data = conn->data;
Kristian Monsen5ab50182010-05-14 18:53:44 +01002608 int ftpcode;
2609 struct ftp_conn *ftpc = &conn->proto.ftpc;
2610 struct pingpong *pp = &ftpc->pp;
2611 static const char ftpauth[][4] = { "SSL", "TLS" };
2612 size_t nread = 0;
2613
2614 if(pp->sendleft)
2615 return Curl_pp_flushsend(pp);
2616
Kristian Monsen5ab50182010-05-14 18:53:44 +01002617 result = ftp_readresp(sock, pp, &ftpcode, &nread);
2618 if(result)
2619 return result;
2620
2621 if(ftpcode) {
2622 /* we have now received a full FTP server response */
2623 switch(ftpc->state) {
2624 case FTP_WAIT220:
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07002625 if(ftpcode == 230)
2626 /* 230 User logged in - already! */
2627 return ftp_state_user_resp(conn, ftpcode, ftpc->state);
2628 else if(ftpcode != 220) {
Kristian Monsen5ab50182010-05-14 18:53:44 +01002629 failf(data, "Got a %03d ftp-server response when 220 was expected",
2630 ftpcode);
Elliott Hughescee03382017-06-23 12:17:18 -07002631 return CURLE_WEIRD_SERVER_REPLY;
Kristian Monsen5ab50182010-05-14 18:53:44 +01002632 }
2633
2634 /* We have received a 220 response fine, now we proceed. */
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07002635#ifdef HAVE_GSSAPI
Kristian Monsen5ab50182010-05-14 18:53:44 +01002636 if(data->set.krb) {
2637 /* If not anonymous login, try a secure login. Note that this
2638 procedure is still BLOCKING. */
2639
2640 Curl_sec_request_prot(conn, "private");
2641 /* We set private first as default, in case the line below fails to
2642 set a valid level */
2643 Curl_sec_request_prot(conn, data->set.str[STRING_KRB_LEVEL]);
2644
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07002645 if(Curl_sec_login(conn))
Kristian Monsen5ab50182010-05-14 18:53:44 +01002646 infof(data, "Logging in with password in cleartext!\n");
2647 else
2648 infof(data, "Authentication successful\n");
2649 }
2650#endif
2651
Elliott Hughescee03382017-06-23 12:17:18 -07002652 if(data->set.use_ssl &&
2653 (!conn->ssl[FIRSTSOCKET].use ||
2654 (conn->bits.proxy_ssl_connected[FIRSTSOCKET] &&
2655 !conn->proxy_ssl[FIRSTSOCKET].use))) {
Kristian Monsen5ab50182010-05-14 18:53:44 +01002656 /* We don't have a SSL/TLS connection yet, but FTPS is
2657 requested. Try a FTPS connection now */
2658
Alex Deymo486467e2017-12-19 19:04:07 +01002659 ftpc->count3 = 0;
Kristian Monsen5ab50182010-05-14 18:53:44 +01002660 switch(data->set.ftpsslauth) {
2661 case CURLFTPAUTH_DEFAULT:
2662 case CURLFTPAUTH_SSL:
2663 ftpc->count2 = 1; /* add one to get next */
2664 ftpc->count1 = 0;
2665 break;
2666 case CURLFTPAUTH_TLS:
2667 ftpc->count2 = -1; /* subtract one to get next */
2668 ftpc->count1 = 1;
2669 break;
2670 default:
2671 failf(data, "unsupported parameter to CURLOPT_FTPSSLAUTH: %d",
2672 (int)data->set.ftpsslauth);
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07002673 return CURLE_UNKNOWN_OPTION; /* we don't know what to do */
Kristian Monsen5ab50182010-05-14 18:53:44 +01002674 }
2675 PPSENDF(&ftpc->pp, "AUTH %s", ftpauth[ftpc->count1]);
2676 state(conn, FTP_AUTH);
2677 }
2678 else {
2679 result = ftp_state_user(conn);
2680 if(result)
2681 return result;
2682 }
2683
2684 break;
2685
2686 case FTP_AUTH:
2687 /* we have gotten the response to a previous AUTH command */
2688
2689 /* RFC2228 (page 5) says:
2690 *
2691 * If the server is willing to accept the named security mechanism,
2692 * and does not require any security data, it must respond with
2693 * reply code 234/334.
2694 */
2695
2696 if((ftpcode == 234) || (ftpcode == 334)) {
2697 /* Curl_ssl_connect is BLOCKING */
2698 result = Curl_ssl_connect(conn, FIRSTSOCKET);
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07002699 if(!result) {
Elliott Hughescee03382017-06-23 12:17:18 -07002700 conn->bits.ftp_use_data_ssl = FALSE; /* clear-text data */
Kristian Monsen5ab50182010-05-14 18:53:44 +01002701 result = ftp_state_user(conn);
2702 }
2703 }
2704 else if(ftpc->count3 < 1) {
2705 ftpc->count3++;
2706 ftpc->count1 += ftpc->count2; /* get next attempt */
2707 result = Curl_pp_sendf(&ftpc->pp, "AUTH %s", ftpauth[ftpc->count1]);
2708 /* remain in this same state */
2709 }
2710 else {
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07002711 if(data->set.use_ssl > CURLUSESSL_TRY)
Kristian Monsen5ab50182010-05-14 18:53:44 +01002712 /* we failed and CURLUSESSL_CONTROL or CURLUSESSL_ALL is set */
2713 result = CURLE_USE_SSL_FAILED;
2714 else
2715 /* ignore the failure and continue */
2716 result = ftp_state_user(conn);
2717 }
2718
2719 if(result)
2720 return result;
2721 break;
2722
2723 case FTP_USER:
2724 case FTP_PASS:
2725 result = ftp_state_user_resp(conn, ftpcode, ftpc->state);
2726 break;
2727
2728 case FTP_ACCT:
2729 result = ftp_state_acct_resp(conn, ftpcode);
2730 break;
2731
2732 case FTP_PBSZ:
2733 PPSENDF(&ftpc->pp, "PROT %c",
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07002734 data->set.use_ssl == CURLUSESSL_CONTROL ? 'C' : 'P');
Kristian Monsen5ab50182010-05-14 18:53:44 +01002735 state(conn, FTP_PROT);
2736
2737 break;
2738
2739 case FTP_PROT:
2740 if(ftpcode/100 == 2)
2741 /* We have enabled SSL for the data connection! */
Elliott Hughescee03382017-06-23 12:17:18 -07002742 conn->bits.ftp_use_data_ssl =
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07002743 (data->set.use_ssl != CURLUSESSL_CONTROL) ? TRUE : FALSE;
Kristian Monsen5ab50182010-05-14 18:53:44 +01002744 /* FTP servers typically responds with 500 if they decide to reject
2745 our 'P' request */
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07002746 else if(data->set.use_ssl > CURLUSESSL_CONTROL)
Kristian Monsen5ab50182010-05-14 18:53:44 +01002747 /* we failed and bails out */
2748 return CURLE_USE_SSL_FAILED;
2749
2750 if(data->set.ftp_ccc) {
2751 /* CCC - Clear Command Channel
2752 */
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07002753 PPSENDF(&ftpc->pp, "%s", "CCC");
Kristian Monsen5ab50182010-05-14 18:53:44 +01002754 state(conn, FTP_CCC);
2755 }
2756 else {
2757 result = ftp_state_pwd(conn);
2758 if(result)
2759 return result;
2760 }
2761 break;
2762
2763 case FTP_CCC:
2764 if(ftpcode < 500) {
2765 /* First shut down the SSL layer (note: this call will block) */
2766 result = Curl_ssl_shutdown(conn, FIRSTSOCKET);
2767
2768 if(result) {
2769 failf(conn->data, "Failed to clear the command channel (CCC)");
2770 return result;
2771 }
2772 }
2773
2774 /* Then continue as normal */
2775 result = ftp_state_pwd(conn);
2776 if(result)
2777 return result;
2778 break;
2779
2780 case FTP_PWD:
2781 if(ftpcode == 257) {
Alex Deymo486467e2017-12-19 19:04:07 +01002782 char *ptr = &data->state.buffer[4]; /* start on the first letter */
Elliott Hughes82be86d2017-09-20 17:00:17 -07002783 const size_t buf_size = data->set.buffer_size;
Kristian Monsen5ab50182010-05-14 18:53:44 +01002784 char *dir;
2785 char *store;
Alex Deymo486467e2017-12-19 19:04:07 +01002786 bool entry_extracted = FALSE;
Kristian Monsen5ab50182010-05-14 18:53:44 +01002787
2788 dir = malloc(nread + 1);
2789 if(!dir)
2790 return CURLE_OUT_OF_MEMORY;
2791
2792 /* Reply format is like
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07002793 257<space>[rubbish]"<directory-name>"<space><commentary> and the
2794 RFC959 says
Kristian Monsen5ab50182010-05-14 18:53:44 +01002795
2796 The directory name can contain any character; embedded
2797 double-quotes should be escaped by double-quotes (the
2798 "quote-doubling" convention).
2799 */
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07002800
2801 /* scan for the first double-quote for non-standard responses */
Elliott Hughes82be86d2017-09-20 17:00:17 -07002802 while(ptr < &data->state.buffer[buf_size]
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07002803 && *ptr != '\n' && *ptr != '\0' && *ptr != '"')
2804 ptr++;
2805
Kristian Monsen5ab50182010-05-14 18:53:44 +01002806 if('\"' == *ptr) {
2807 /* it started good */
2808 ptr++;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07002809 for(store = dir; *ptr;) {
Kristian Monsen5ab50182010-05-14 18:53:44 +01002810 if('\"' == *ptr) {
2811 if('\"' == ptr[1]) {
2812 /* "quote-doubling" */
2813 *store = ptr[1];
2814 ptr++;
2815 }
2816 else {
2817 /* end of path */
Alex Deymo486467e2017-12-19 19:04:07 +01002818 entry_extracted = TRUE;
Kristian Monsen5ab50182010-05-14 18:53:44 +01002819 break; /* get out of this loop */
2820 }
2821 }
2822 else
2823 *store = *ptr;
2824 store++;
2825 ptr++;
2826 }
Alex Deymo486467e2017-12-19 19:04:07 +01002827 *store = '\0'; /* zero terminate */
2828 }
2829 if(entry_extracted) {
Kristian Monsen5ab50182010-05-14 18:53:44 +01002830 /* If the path name does not look like an absolute path (i.e.: it
2831 does not start with a '/'), we probably need some server-dependent
2832 adjustments. For example, this is the case when connecting to
2833 an OS400 FTP server: this server supports two name syntaxes,
Elliott Hughes82be86d2017-09-20 17:00:17 -07002834 the default one being incompatible with standard paths. In
Kristian Monsen5ab50182010-05-14 18:53:44 +01002835 addition, this server switches automatically to the regular path
2836 syntax when one is encountered in a command: this results in
2837 having an entrypath in the wrong syntax when later used in CWD.
2838 The method used here is to check the server OS: we do it only
2839 if the path name looks strange to minimize overhead on other
2840 systems. */
2841
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07002842 if(!ftpc->server_os && dir[0] != '/') {
2843
2844 result = Curl_pp_sendf(&ftpc->pp, "%s", "SYST");
2845 if(result) {
2846 free(dir);
2847 return result;
2848 }
2849 Curl_safefree(ftpc->entrypath);
2850 ftpc->entrypath = dir; /* remember this */
2851 infof(data, "Entry path is '%s'\n", ftpc->entrypath);
2852 /* also save it where getinfo can access it: */
2853 data->state.most_recent_ftp_entrypath = ftpc->entrypath;
Kristian Monsen5ab50182010-05-14 18:53:44 +01002854 state(conn, FTP_SYST);
2855 break;
2856 }
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07002857
2858 Curl_safefree(ftpc->entrypath);
2859 ftpc->entrypath = dir; /* remember this */
2860 infof(data, "Entry path is '%s'\n", ftpc->entrypath);
2861 /* also save it where getinfo can access it: */
2862 data->state.most_recent_ftp_entrypath = ftpc->entrypath;
Kristian Monsen5ab50182010-05-14 18:53:44 +01002863 }
2864 else {
2865 /* couldn't get the path */
2866 free(dir);
2867 infof(data, "Failed to figure out path\n");
2868 }
2869 }
2870 state(conn, FTP_STOP); /* we are done with the CONNECT phase! */
2871 DEBUGF(infof(data, "protocol connect phase DONE\n"));
2872 break;
2873
2874 case FTP_SYST:
2875 if(ftpcode == 215) {
Alex Deymo486467e2017-12-19 19:04:07 +01002876 char *ptr = &data->state.buffer[4]; /* start on the first letter */
Kristian Monsen5ab50182010-05-14 18:53:44 +01002877 char *os;
2878 char *store;
2879
2880 os = malloc(nread + 1);
2881 if(!os)
2882 return CURLE_OUT_OF_MEMORY;
2883
2884 /* Reply format is like
2885 215<space><OS-name><space><commentary>
2886 */
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07002887 while(*ptr == ' ')
Kristian Monsen5ab50182010-05-14 18:53:44 +01002888 ptr++;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07002889 for(store = os; *ptr && *ptr != ' ';)
Kristian Monsen5ab50182010-05-14 18:53:44 +01002890 *store++ = *ptr++;
2891 *store = '\0'; /* zero terminate */
Kristian Monsen5ab50182010-05-14 18:53:44 +01002892
2893 /* Check for special servers here. */
2894
Elliott Hughescee03382017-06-23 12:17:18 -07002895 if(strcasecompare(os, "OS/400")) {
Kristian Monsen5ab50182010-05-14 18:53:44 +01002896 /* Force OS400 name format 1. */
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07002897 result = Curl_pp_sendf(&ftpc->pp, "%s", "SITE NAMEFMT 1");
2898 if(result) {
2899 free(os);
2900 return result;
2901 }
2902 /* remember target server OS */
2903 Curl_safefree(ftpc->server_os);
2904 ftpc->server_os = os;
Kristian Monsen5ab50182010-05-14 18:53:44 +01002905 state(conn, FTP_NAMEFMT);
2906 break;
2907 }
Elliott Hughes82be86d2017-09-20 17:00:17 -07002908 /* Nothing special for the target server. */
2909 /* remember target server OS */
2910 Curl_safefree(ftpc->server_os);
2911 ftpc->server_os = os;
Kristian Monsen5ab50182010-05-14 18:53:44 +01002912 }
2913 else {
2914 /* Cannot identify server OS. Continue anyway and cross fingers. */
2915 }
2916
2917 state(conn, FTP_STOP); /* we are done with the CONNECT phase! */
2918 DEBUGF(infof(data, "protocol connect phase DONE\n"));
2919 break;
2920
2921 case FTP_NAMEFMT:
2922 if(ftpcode == 250) {
2923 /* Name format change successful: reload initial path. */
2924 ftp_state_pwd(conn);
2925 break;
2926 }
2927
2928 state(conn, FTP_STOP); /* we are done with the CONNECT phase! */
2929 DEBUGF(infof(data, "protocol connect phase DONE\n"));
2930 break;
2931
2932 case FTP_QUOTE:
2933 case FTP_POSTQUOTE:
2934 case FTP_RETR_PREQUOTE:
2935 case FTP_STOR_PREQUOTE:
2936 if((ftpcode >= 400) && !ftpc->count2) {
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07002937 /* failure response code, and not allowed to fail */
Kristian Monsen5ab50182010-05-14 18:53:44 +01002938 failf(conn->data, "QUOT command failed with %03d", ftpcode);
2939 return CURLE_QUOTE_ERROR;
2940 }
2941 result = ftp_state_quote(conn, FALSE, ftpc->state);
2942 if(result)
2943 return result;
2944
2945 break;
2946
2947 case FTP_CWD:
2948 if(ftpcode/100 != 2) {
2949 /* failure to CWD there */
2950 if(conn->data->set.ftp_create_missing_dirs &&
Elliott Hughes82be86d2017-09-20 17:00:17 -07002951 ftpc->cwdcount && !ftpc->count2) {
Kristian Monsen5ab50182010-05-14 18:53:44 +01002952 /* try making it */
2953 ftpc->count2++; /* counter to prevent CWD-MKD loops */
Elliott Hughes82be86d2017-09-20 17:00:17 -07002954 PPSENDF(&ftpc->pp, "MKD %s", ftpc->dirs[ftpc->cwdcount - 1]);
Kristian Monsen5ab50182010-05-14 18:53:44 +01002955 state(conn, FTP_MKD);
2956 }
2957 else {
2958 /* return failure */
2959 failf(data, "Server denied you to change to the given directory");
2960 ftpc->cwdfail = TRUE; /* don't remember this path as we failed
2961 to enter it */
2962 return CURLE_REMOTE_ACCESS_DENIED;
2963 }
2964 }
2965 else {
2966 /* success */
Alex Deymo486467e2017-12-19 19:04:07 +01002967 ftpc->count2 = 0;
Elliott Hughes82be86d2017-09-20 17:00:17 -07002968 if(++ftpc->cwdcount <= ftpc->dirdepth) {
Kristian Monsen5ab50182010-05-14 18:53:44 +01002969 /* send next CWD */
Elliott Hughes82be86d2017-09-20 17:00:17 -07002970 PPSENDF(&ftpc->pp, "CWD %s", ftpc->dirs[ftpc->cwdcount - 1]);
Kristian Monsen5ab50182010-05-14 18:53:44 +01002971 }
2972 else {
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07002973 result = ftp_state_mdtm(conn);
Kristian Monsen5ab50182010-05-14 18:53:44 +01002974 if(result)
2975 return result;
2976 }
2977 }
2978 break;
2979
2980 case FTP_MKD:
2981 if((ftpcode/100 != 2) && !ftpc->count3--) {
2982 /* failure to MKD the dir */
2983 failf(data, "Failed to MKD dir: %03d", ftpcode);
2984 return CURLE_REMOTE_ACCESS_DENIED;
2985 }
2986 state(conn, FTP_CWD);
2987 /* send CWD */
Elliott Hughes82be86d2017-09-20 17:00:17 -07002988 PPSENDF(&ftpc->pp, "CWD %s", ftpc->dirs[ftpc->cwdcount - 1]);
Kristian Monsen5ab50182010-05-14 18:53:44 +01002989 break;
2990
2991 case FTP_MDTM:
2992 result = ftp_state_mdtm_resp(conn, ftpcode);
2993 break;
2994
2995 case FTP_TYPE:
2996 case FTP_LIST_TYPE:
2997 case FTP_RETR_TYPE:
2998 case FTP_STOR_TYPE:
2999 result = ftp_state_type_resp(conn, ftpcode, ftpc->state);
3000 break;
3001
3002 case FTP_SIZE:
3003 case FTP_RETR_SIZE:
3004 case FTP_STOR_SIZE:
3005 result = ftp_state_size_resp(conn, ftpcode, ftpc->state);
3006 break;
3007
3008 case FTP_REST:
3009 case FTP_RETR_REST:
3010 result = ftp_state_rest_resp(conn, ftpcode, ftpc->state);
3011 break;
3012
3013 case FTP_PRET:
3014 if(ftpcode != 200) {
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07003015 /* there only is this one standard OK return code. */
Kristian Monsen5ab50182010-05-14 18:53:44 +01003016 failf(data, "PRET command not accepted: %03d", ftpcode);
3017 return CURLE_FTP_PRET_FAILED;
3018 }
3019 result = ftp_state_use_pasv(conn);
3020 break;
3021
3022 case FTP_PASV:
3023 result = ftp_state_pasv_resp(conn, ftpcode);
3024 break;
3025
3026 case FTP_PORT:
3027 result = ftp_state_port_resp(conn, ftpcode);
3028 break;
3029
3030 case FTP_LIST:
3031 case FTP_RETR:
3032 result = ftp_state_get_resp(conn, ftpcode, ftpc->state);
3033 break;
3034
3035 case FTP_STOR:
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07003036 result = ftp_state_stor_resp(conn, ftpcode, ftpc->state);
Kristian Monsen5ab50182010-05-14 18:53:44 +01003037 break;
3038
3039 case FTP_QUIT:
3040 /* fallthrough, just stop! */
3041 default:
3042 /* internal error */
3043 state(conn, FTP_STOP);
3044 break;
3045 }
3046 } /* if(ftpcode) */
3047
3048 return result;
3049}
3050
3051
3052/* called repeatedly until done from multi.c */
3053static CURLcode ftp_multi_statemach(struct connectdata *conn,
3054 bool *done)
3055{
3056 struct ftp_conn *ftpc = &conn->proto.ftpc;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07003057 CURLcode result = Curl_pp_statemach(&ftpc->pp, FALSE);
Kristian Monsen5ab50182010-05-14 18:53:44 +01003058
Elliott Hughescee03382017-06-23 12:17:18 -07003059 /* Check for the state outside of the Curl_socket_check() return code checks
Kristian Monsen5ab50182010-05-14 18:53:44 +01003060 since at times we are in fact already in this state when this function
3061 gets called. */
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07003062 *done = (ftpc->state == FTP_STOP) ? TRUE : FALSE;
Kristian Monsen5ab50182010-05-14 18:53:44 +01003063
3064 return result;
3065}
3066
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07003067static CURLcode ftp_block_statemach(struct connectdata *conn)
Kristian Monsen5ab50182010-05-14 18:53:44 +01003068{
3069 struct ftp_conn *ftpc = &conn->proto.ftpc;
3070 struct pingpong *pp = &ftpc->pp;
3071 CURLcode result = CURLE_OK;
3072
3073 while(ftpc->state != FTP_STOP) {
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07003074 result = Curl_pp_statemach(pp, TRUE);
Kristian Monsen5ab50182010-05-14 18:53:44 +01003075 if(result)
3076 break;
3077 }
3078
3079 return result;
3080}
3081
3082/*
Kristian Monsen5ab50182010-05-14 18:53:44 +01003083 * ftp_connect() should do everything that is to be considered a part of
3084 * the connection phase.
3085 *
3086 * The variable 'done' points to will be TRUE if the protocol-layer connect
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07003087 * phase is done when this function returns, or FALSE if not.
3088 *
Kristian Monsen5ab50182010-05-14 18:53:44 +01003089 */
3090static CURLcode ftp_connect(struct connectdata *conn,
3091 bool *done) /* see description above */
3092{
3093 CURLcode result;
3094 struct ftp_conn *ftpc = &conn->proto.ftpc;
Kristian Monsen5ab50182010-05-14 18:53:44 +01003095 struct pingpong *pp = &ftpc->pp;
3096
3097 *done = FALSE; /* default to not done yet */
3098
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07003099 /* We always support persistent connections on ftp */
3100 connkeep(conn, "FTP default");
Kristian Monsen5ab50182010-05-14 18:53:44 +01003101
3102 pp->response_time = RESP_TIMEOUT; /* set default response time-out */
3103 pp->statemach_act = ftp_statemach_act;
3104 pp->endofresp = ftp_endofresp;
3105 pp->conn = conn;
3106
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07003107 if(conn->handler->flags & PROTOPT_SSL) {
Kristian Monsen5ab50182010-05-14 18:53:44 +01003108 /* BLOCKING */
Kristian Monsen5ab50182010-05-14 18:53:44 +01003109 result = Curl_ssl_connect(conn, FIRSTSOCKET);
3110 if(result)
3111 return result;
3112 }
3113
3114 Curl_pp_init(pp); /* init the generic pingpong data */
3115
3116 /* When we connect, we start in the state where we await the 220
3117 response */
3118 state(conn, FTP_WAIT220);
3119
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07003120 result = ftp_multi_statemach(conn, done);
Kristian Monsen5ab50182010-05-14 18:53:44 +01003121
3122 return result;
3123}
3124
3125/***********************************************************************
3126 *
3127 * ftp_done()
3128 *
3129 * The DONE function. This does what needs to be done after a single DO has
3130 * performed.
3131 *
3132 * Input argument is already checked for validity.
3133 */
3134static CURLcode ftp_done(struct connectdata *conn, CURLcode status,
Alex Deymod15eaac2016-06-28 14:49:26 -07003135 bool premature)
Kristian Monsen5ab50182010-05-14 18:53:44 +01003136{
Alex Deymoe3149cc2016-10-05 11:18:42 -07003137 struct Curl_easy *data = conn->data;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07003138 struct FTP *ftp = data->req.protop;
Kristian Monsen5ab50182010-05-14 18:53:44 +01003139 struct ftp_conn *ftpc = &conn->proto.ftpc;
3140 struct pingpong *pp = &ftpc->pp;
3141 ssize_t nread;
3142 int ftpcode;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07003143 CURLcode result = CURLE_OK;
Elliott Hughescee03382017-06-23 12:17:18 -07003144 char *path = NULL;
Kristian Monsen5ab50182010-05-14 18:53:44 +01003145 const char *path_to_use = data->state.path;
3146
3147 if(!ftp)
Kristian Monsen5ab50182010-05-14 18:53:44 +01003148 return CURLE_OK;
3149
3150 switch(status) {
3151 case CURLE_BAD_DOWNLOAD_RESUME:
3152 case CURLE_FTP_WEIRD_PASV_REPLY:
3153 case CURLE_FTP_PORT_FAILED:
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07003154 case CURLE_FTP_ACCEPT_FAILED:
3155 case CURLE_FTP_ACCEPT_TIMEOUT:
Kristian Monsen5ab50182010-05-14 18:53:44 +01003156 case CURLE_FTP_COULDNT_SET_TYPE:
3157 case CURLE_FTP_COULDNT_RETR_FILE:
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07003158 case CURLE_PARTIAL_FILE:
Kristian Monsen5ab50182010-05-14 18:53:44 +01003159 case CURLE_UPLOAD_FAILED:
3160 case CURLE_REMOTE_ACCESS_DENIED:
3161 case CURLE_FILESIZE_EXCEEDED:
3162 case CURLE_REMOTE_FILE_NOT_FOUND:
3163 case CURLE_WRITE_ERROR:
3164 /* the connection stays alive fine even though this happened */
3165 /* fall-through */
3166 case CURLE_OK: /* doesn't affect the control connection's status */
Elliott Hughescee03382017-06-23 12:17:18 -07003167 if(!premature)
Kristian Monsen5ab50182010-05-14 18:53:44 +01003168 break;
Elliott Hughescee03382017-06-23 12:17:18 -07003169
Kristian Monsen5ab50182010-05-14 18:53:44 +01003170 /* until we cope better with prematurely ended requests, let them
3171 * fallback as if in complete failure */
Elliott Hughes82be86d2017-09-20 17:00:17 -07003172 /* FALLTHROUGH */
Kristian Monsen5ab50182010-05-14 18:53:44 +01003173 default: /* by default, an error means the control connection is
3174 wedged and should not be used anymore */
3175 ftpc->ctl_valid = FALSE;
3176 ftpc->cwdfail = TRUE; /* set this TRUE to prevent us to remember the
3177 current path, as this connection is going */
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07003178 connclose(conn, "FTP ended with bad error code");
Kristian Monsen5ab50182010-05-14 18:53:44 +01003179 result = status; /* use the already set error code */
3180 break;
3181 }
3182
3183 /* now store a copy of the directory we are in */
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07003184 free(ftpc->prevpath);
Kristian Monsen5ab50182010-05-14 18:53:44 +01003185
Alex Deymo486467e2017-12-19 19:04:07 +01003186 if(data->state.wildcardmatch) {
Lucas Eckels9bd90e62012-08-06 15:07:02 -07003187 if(data->set.chunk_end && ftpc->file) {
Elliott Hughescac39802018-04-27 16:19:43 -07003188 Curl_set_in_callback(data, true);
Lucas Eckels9bd90e62012-08-06 15:07:02 -07003189 data->set.chunk_end(data->wildcard.customptr);
Elliott Hughescac39802018-04-27 16:19:43 -07003190 Curl_set_in_callback(data, false);
Lucas Eckels9bd90e62012-08-06 15:07:02 -07003191 }
3192 ftpc->known_filesize = -1;
3193 }
3194
Elliott Hughescee03382017-06-23 12:17:18 -07003195 if(!result)
3196 /* get the "raw" path */
Elliott Hughescac39802018-04-27 16:19:43 -07003197 result = Curl_urldecode(data, path_to_use, 0, &path, NULL, TRUE);
Elliott Hughescee03382017-06-23 12:17:18 -07003198 if(result) {
3199 /* We can limp along anyway (and should try to since we may already be in
3200 * the error path) */
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07003201 ftpc->ctl_valid = FALSE; /* mark control connection as bad */
3202 connclose(conn, "FTP: out of memory!"); /* mark for connection closure */
3203 ftpc->prevpath = NULL; /* no path remembering */
Kristian Monsen5ab50182010-05-14 18:53:44 +01003204 }
3205 else {
3206 size_t flen = ftpc->file?strlen(ftpc->file):0; /* file is "raw" already */
3207 size_t dlen = strlen(path)-flen;
3208 if(!ftpc->cwdfail) {
Alex Deymo486467e2017-12-19 19:04:07 +01003209 ftpc->prevmethod = data->set.ftp_filemethod;
Kristian Monsen5ab50182010-05-14 18:53:44 +01003210 if(dlen && (data->set.ftp_filemethod != FTPFILE_NOCWD)) {
3211 ftpc->prevpath = path;
3212 if(flen)
3213 /* if 'path' is not the whole string */
Alex Deymo486467e2017-12-19 19:04:07 +01003214 ftpc->prevpath[dlen] = 0; /* terminate */
Kristian Monsen5ab50182010-05-14 18:53:44 +01003215 }
3216 else {
3217 /* we never changed dir */
Alex Deymo486467e2017-12-19 19:04:07 +01003218 ftpc->prevpath = strdup("");
Kristian Monsen5ab50182010-05-14 18:53:44 +01003219 free(path);
3220 }
3221 if(ftpc->prevpath)
3222 infof(data, "Remembering we are in dir \"%s\"\n", ftpc->prevpath);
3223 }
3224 else {
3225 ftpc->prevpath = NULL; /* no path */
3226 free(path);
3227 }
3228 }
3229 /* free the dir tree and file parts */
3230 freedirs(ftpc);
3231
Kristian Monsen5ab50182010-05-14 18:53:44 +01003232 /* shut down the socket to inform the server we're done */
3233
3234#ifdef _WIN32_WCE
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07003235 shutdown(conn->sock[SECONDARYSOCKET], 2); /* SD_BOTH */
Kristian Monsen5ab50182010-05-14 18:53:44 +01003236#endif
3237
3238 if(conn->sock[SECONDARYSOCKET] != CURL_SOCKET_BAD) {
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07003239 if(!result && ftpc->dont_check && data->req.maxdownload > 0) {
3240 /* partial download completed */
3241 result = Curl_pp_sendf(pp, "%s", "ABOR");
3242 if(result) {
3243 failf(data, "Failure sending ABOR command: %s",
3244 curl_easy_strerror(result));
3245 ftpc->ctl_valid = FALSE; /* mark control connection as bad */
3246 connclose(conn, "ABOR command failed"); /* connection closure */
3247 }
3248 }
3249
Kristian Monsen5ab50182010-05-14 18:53:44 +01003250 if(conn->ssl[SECONDARYSOCKET].use) {
3251 /* The secondary socket is using SSL so we must close down that part
3252 first before we close the socket for real */
3253 Curl_ssl_close(conn, SECONDARYSOCKET);
3254
3255 /* Note that we keep "use" set to TRUE since that (next) connection is
3256 still requested to use SSL */
3257 }
Alex Deymod15eaac2016-06-28 14:49:26 -07003258 close_secondarysocket(conn);
Kristian Monsen5ab50182010-05-14 18:53:44 +01003259 }
3260
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07003261 if(!result && (ftp->transfer == FTPTRANSFER_BODY) && ftpc->ctl_valid &&
Kristian Monsen5ab50182010-05-14 18:53:44 +01003262 pp->pending_resp && !premature) {
3263 /*
3264 * Let's see what the server says about the transfer we just performed,
3265 * but lower the timeout as sometimes this connection has died while the
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07003266 * data has been transferred. This happens when doing through NATs etc that
Kristian Monsen5ab50182010-05-14 18:53:44 +01003267 * abandon old silent connections.
3268 */
3269 long old_time = pp->response_time;
3270
3271 pp->response_time = 60*1000; /* give it only a minute for now */
Alex Deymo486467e2017-12-19 19:04:07 +01003272 pp->response = Curl_now(); /* timeout relative now */
Kristian Monsen5ab50182010-05-14 18:53:44 +01003273
3274 result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
3275
3276 pp->response_time = old_time; /* set this back to previous value */
3277
3278 if(!nread && (CURLE_OPERATION_TIMEDOUT == result)) {
3279 failf(data, "control connection looks dead");
3280 ftpc->ctl_valid = FALSE; /* mark control connection as bad */
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07003281 connclose(conn, "Timeout or similar in FTP DONE operation"); /* close */
Kristian Monsen5ab50182010-05-14 18:53:44 +01003282 }
3283
3284 if(result)
3285 return result;
3286
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07003287 if(ftpc->dont_check && data->req.maxdownload > 0) {
3288 /* we have just sent ABOR and there is no reliable way to check if it was
3289 * successful or not; we have to close the connection now */
3290 infof(data, "partial download completed, closing connection\n");
3291 connclose(conn, "Partial download with no ability to check");
3292 return result;
3293 }
3294
Kristian Monsen5ab50182010-05-14 18:53:44 +01003295 if(!ftpc->dont_check) {
3296 /* 226 Transfer complete, 250 Requested file action okay, completed. */
3297 if((ftpcode != 226) && (ftpcode != 250)) {
3298 failf(data, "server did not report OK, got %d", ftpcode);
3299 result = CURLE_PARTIAL_FILE;
3300 }
3301 }
3302 }
3303
3304 if(result || premature)
3305 /* the response code from the transfer showed an error already so no
3306 use checking further */
3307 ;
3308 else if(data->set.upload) {
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07003309 if((-1 != data->state.infilesize) &&
3310 (data->state.infilesize != *ftp->bytecountp) &&
Kristian Monsen5ab50182010-05-14 18:53:44 +01003311 !data->set.crlf &&
3312 (ftp->transfer == FTPTRANSFER_BODY)) {
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07003313 failf(data, "Uploaded unaligned file size (%" CURL_FORMAT_CURL_OFF_T
3314 " out of %" CURL_FORMAT_CURL_OFF_T " bytes)",
3315 *ftp->bytecountp, data->state.infilesize);
Kristian Monsen5ab50182010-05-14 18:53:44 +01003316 result = CURLE_PARTIAL_FILE;
3317 }
3318 }
3319 else {
3320 if((-1 != data->req.size) &&
3321 (data->req.size != *ftp->bytecountp) &&
3322#ifdef CURL_DO_LINEEND_CONV
3323 /* Most FTP servers don't adjust their file SIZE response for CRLFs, so
3324 * we'll check to see if the discrepancy can be explained by the number
3325 * of CRLFs we've changed to LFs.
3326 */
3327 ((data->req.size + data->state.crlf_conversions) !=
3328 *ftp->bytecountp) &&
3329#endif /* CURL_DO_LINEEND_CONV */
3330 (data->req.maxdownload != *ftp->bytecountp)) {
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07003331 failf(data, "Received only partial file: %" CURL_FORMAT_CURL_OFF_T
3332 " bytes", *ftp->bytecountp);
Kristian Monsen5ab50182010-05-14 18:53:44 +01003333 result = CURLE_PARTIAL_FILE;
3334 }
3335 else if(!ftpc->dont_check &&
3336 !*ftp->bytecountp &&
3337 (data->req.size>0)) {
3338 failf(data, "No data was received!");
3339 result = CURLE_FTP_COULDNT_RETR_FILE;
3340 }
3341 }
3342
3343 /* clear these for next connection */
3344 ftp->transfer = FTPTRANSFER_BODY;
3345 ftpc->dont_check = FALSE;
3346
3347 /* Send any post-transfer QUOTE strings? */
3348 if(!status && !result && !premature && data->set.postquote)
3349 result = ftp_sendquote(conn, data->set.postquote);
3350
3351 return result;
3352}
3353
3354/***********************************************************************
3355 *
3356 * ftp_sendquote()
3357 *
3358 * Where a 'quote' means a list of custom commands to send to the server.
3359 * The quote list is passed as an argument.
3360 *
3361 * BLOCKING
3362 */
3363
3364static
3365CURLcode ftp_sendquote(struct connectdata *conn, struct curl_slist *quote)
3366{
3367 struct curl_slist *item;
3368 ssize_t nread;
3369 int ftpcode;
3370 CURLcode result;
Lucas Eckels9bd90e62012-08-06 15:07:02 -07003371 struct ftp_conn *ftpc = &conn->proto.ftpc;
3372 struct pingpong *pp = &ftpc->pp;
Kristian Monsen5ab50182010-05-14 18:53:44 +01003373
3374 item = quote;
3375 while(item) {
3376 if(item->data) {
3377 char *cmd = item->data;
3378 bool acceptfail = FALSE;
3379
3380 /* if a command starts with an asterisk, which a legal FTP command never
3381 can, the command will be allowed to fail without it causing any
3382 aborts or cancels etc. It will cause libcurl to act as if the command
3383 is successful, whatever the server reponds. */
3384
3385 if(cmd[0] == '*') {
3386 cmd++;
3387 acceptfail = TRUE;
3388 }
3389
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07003390 PPSENDF(&conn->proto.ftpc.pp, "%s", cmd);
Kristian Monsen5ab50182010-05-14 18:53:44 +01003391
Alex Deymo486467e2017-12-19 19:04:07 +01003392 pp->response = Curl_now(); /* timeout relative now */
Lucas Eckels9bd90e62012-08-06 15:07:02 -07003393
Kristian Monsen5ab50182010-05-14 18:53:44 +01003394 result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
3395 if(result)
3396 return result;
3397
3398 if(!acceptfail && (ftpcode >= 400)) {
3399 failf(conn->data, "QUOT string not accepted: %s", cmd);
3400 return CURLE_QUOTE_ERROR;
3401 }
3402 }
3403
3404 item = item->next;
3405 }
3406
3407 return CURLE_OK;
3408}
3409
3410/***********************************************************************
3411 *
3412 * ftp_need_type()
3413 *
3414 * Returns TRUE if we in the current situation should send TYPE
3415 */
3416static int ftp_need_type(struct connectdata *conn,
3417 bool ascii_wanted)
3418{
3419 return conn->proto.ftpc.transfertype != (ascii_wanted?'A':'I');
3420}
3421
3422/***********************************************************************
3423 *
3424 * ftp_nb_type()
3425 *
3426 * Set TYPE. We only deal with ASCII or BINARY so this function
3427 * sets one of them.
3428 * If the transfer type is not sent, simulate on OK response in newstate
3429 */
3430static CURLcode ftp_nb_type(struct connectdata *conn,
3431 bool ascii, ftpstate newstate)
3432{
3433 struct ftp_conn *ftpc = &conn->proto.ftpc;
3434 CURLcode result;
3435 char want = (char)(ascii?'A':'I');
3436
3437 if(ftpc->transfertype == want) {
3438 state(conn, newstate);
3439 return ftp_state_type_resp(conn, 200, newstate);
3440 }
3441
3442 PPSENDF(&ftpc->pp, "TYPE %c", want);
3443 state(conn, newstate);
3444
3445 /* keep track of our current transfer type */
3446 ftpc->transfertype = want;
3447 return CURLE_OK;
3448}
3449
3450/***************************************************************************
3451 *
3452 * ftp_pasv_verbose()
3453 *
3454 * This function only outputs some informationals about this second connection
3455 * when we've issued a PASV command before and thus we have connected to a
3456 * possibly new IP address.
3457 *
3458 */
3459#ifndef CURL_DISABLE_VERBOSE_STRINGS
3460static void
3461ftp_pasv_verbose(struct connectdata *conn,
3462 Curl_addrinfo *ai,
3463 char *newhost, /* ascii version */
3464 int port)
3465{
3466 char buf[256];
3467 Curl_printable_address(ai, buf, sizeof(buf));
3468 infof(conn->data, "Connecting to %s (%s) port %d\n", newhost, buf, port);
3469}
3470#endif
3471
3472/*
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07003473 * ftp_do_more()
Kristian Monsen5ab50182010-05-14 18:53:44 +01003474 *
3475 * This function shall be called when the second FTP (data) connection is
3476 * connected.
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07003477 *
3478 * 'complete' can return 0 for incomplete, 1 for done and -1 for go back
3479 * (which basically is only for when PASV is being sent to retry a failed
3480 * EPSV).
Kristian Monsen5ab50182010-05-14 18:53:44 +01003481 */
3482
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07003483static CURLcode ftp_do_more(struct connectdata *conn, int *completep)
Kristian Monsen5ab50182010-05-14 18:53:44 +01003484{
Alex Deymo486467e2017-12-19 19:04:07 +01003485 struct Curl_easy *data = conn->data;
Kristian Monsen5ab50182010-05-14 18:53:44 +01003486 struct ftp_conn *ftpc = &conn->proto.ftpc;
3487 CURLcode result = CURLE_OK;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07003488 bool connected = FALSE;
3489 bool complete = FALSE;
Kristian Monsen5ab50182010-05-14 18:53:44 +01003490
3491 /* the ftp struct is inited in ftp_connect() */
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07003492 struct FTP *ftp = data->req.protop;
Kristian Monsen5ab50182010-05-14 18:53:44 +01003493
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07003494 /* if the second connection isn't done yet, wait for it */
3495 if(!conn->bits.tcpconnect[SECONDARYSOCKET]) {
Elliott Hughes82be86d2017-09-20 17:00:17 -07003496 if(Curl_connect_ongoing(conn)) {
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07003497 /* As we're in TUNNEL_CONNECT state now, we know the proxy name and port
3498 aren't used so we blank their arguments. TODO: make this nicer */
Elliott Hughes82be86d2017-09-20 17:00:17 -07003499 result = Curl_proxyCONNECT(conn, SECONDARYSOCKET, NULL, 0);
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07003500
3501 return result;
3502 }
3503
3504 result = Curl_is_connected(conn, SECONDARYSOCKET, &connected);
3505
3506 /* Ready to do more? */
3507 if(connected) {
3508 DEBUGF(infof(data, "DO-MORE connected phase starts\n"));
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07003509 }
3510 else {
3511 if(result && (ftpc->count1 == 0)) {
3512 *completep = -1; /* go back to DOING please */
3513 /* this is a EPSV connect failing, try PASV instead */
3514 return ftp_epsv_disable(conn);
3515 }
3516 return result;
3517 }
3518 }
3519
Elliott Hughescee03382017-06-23 12:17:18 -07003520 result = Curl_proxy_connect(conn, SECONDARYSOCKET);
3521 if(result)
3522 return result;
3523
3524 if(CONNECT_SECONDARYSOCKET_PROXY_SSL())
3525 return result;
3526
3527 if(conn->bits.tunnel_proxy && conn->bits.httpproxy &&
Elliott Hughes82be86d2017-09-20 17:00:17 -07003528 Curl_connect_ongoing(conn))
Elliott Hughescee03382017-06-23 12:17:18 -07003529 return result;
3530
3531
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07003532 if(ftpc->state) {
Elliott Hughes82be86d2017-09-20 17:00:17 -07003533 /* already in a state so skip the initial commands.
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07003534 They are only done to kickstart the do_more state */
3535 result = ftp_multi_statemach(conn, &complete);
3536
3537 *completep = (int)complete;
3538
3539 /* if we got an error or if we don't wait for a data connection return
3540 immediately */
3541 if(result || (ftpc->wait_data_conn != TRUE))
3542 return result;
3543
3544 if(ftpc->wait_data_conn)
3545 /* if we reach the end of the FTP state machine here, *complete will be
3546 TRUE but so is ftpc->wait_data_conn, which says we need to wait for
3547 the data connection and therefore we're not actually complete */
3548 *completep = 0;
3549 }
Kristian Monsen5ab50182010-05-14 18:53:44 +01003550
3551 if(ftp->transfer <= FTPTRANSFER_INFO) {
3552 /* a transfer is about to take place, or if not a file name was given
3553 so we'll do a SIZE on it later and then we need the right TYPE first */
3554
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07003555 if(ftpc->wait_data_conn == TRUE) {
3556 bool serv_conned;
3557
3558 result = ReceivedServerConnect(conn, &serv_conned);
3559 if(result)
3560 return result; /* Failed to accept data connection */
3561
3562 if(serv_conned) {
3563 /* It looks data connection is established */
3564 result = AcceptServerConnect(conn);
3565 ftpc->wait_data_conn = FALSE;
3566 if(!result)
3567 result = InitiateTransfer(conn);
3568
3569 if(result)
3570 return result;
3571
3572 *completep = 1; /* this state is now complete when the server has
3573 connected back to us */
3574 }
3575 }
3576 else if(data->set.upload) {
Kristian Monsen5ab50182010-05-14 18:53:44 +01003577 result = ftp_nb_type(conn, data->set.prefer_ascii, FTP_STOR_TYPE);
3578 if(result)
3579 return result;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07003580
3581 result = ftp_multi_statemach(conn, &complete);
Alex Deymod15eaac2016-06-28 14:49:26 -07003582 if(ftpc->wait_data_conn)
3583 /* if we reach the end of the FTP state machine here, *complete will be
3584 TRUE but so is ftpc->wait_data_conn, which says we need to wait for
3585 the data connection and therefore we're not actually complete */
3586 *completep = 0;
3587 else
3588 *completep = (int)complete;
Kristian Monsen5ab50182010-05-14 18:53:44 +01003589 }
3590 else {
3591 /* download */
3592 ftp->downloadsize = -1; /* unknown as of yet */
3593
Elliott Hughescac39802018-04-27 16:19:43 -07003594 result = Curl_range(conn);
3595
3596 if(result == CURLE_OK && data->req.maxdownload >= 0) {
3597 /* Don't check for successful transfer */
3598 ftpc->dont_check = TRUE;
3599 }
3600
Kristian Monsen5ab50182010-05-14 18:53:44 +01003601 if(result)
3602 ;
3603 else if(data->set.ftp_list_only || !ftpc->file) {
3604 /* The specified path ends with a slash, and therefore we think this
3605 is a directory that is requested, use LIST. But before that we
3606 need to set ASCII transfer mode. */
3607
3608 /* But only if a body transfer was requested. */
3609 if(ftp->transfer == FTPTRANSFER_BODY) {
3610 result = ftp_nb_type(conn, TRUE, FTP_LIST_TYPE);
3611 if(result)
3612 return result;
3613 }
3614 /* otherwise just fall through */
3615 }
3616 else {
3617 result = ftp_nb_type(conn, data->set.prefer_ascii, FTP_RETR_TYPE);
3618 if(result)
3619 return result;
3620 }
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07003621
3622 result = ftp_multi_statemach(conn, &complete);
3623 *completep = (int)complete;
Kristian Monsen5ab50182010-05-14 18:53:44 +01003624 }
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07003625 return result;
Kristian Monsen5ab50182010-05-14 18:53:44 +01003626 }
3627
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07003628 if(!result && (ftp->transfer != FTPTRANSFER_BODY))
Kristian Monsen5ab50182010-05-14 18:53:44 +01003629 /* no data to transfer. FIX: it feels like a kludge to have this here
3630 too! */
Lucas Eckels9bd90e62012-08-06 15:07:02 -07003631 Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
Kristian Monsen5ab50182010-05-14 18:53:44 +01003632
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07003633 if(!ftpc->wait_data_conn) {
3634 /* no waiting for the data connection so this is now complete */
3635 *completep = 1;
3636 DEBUGF(infof(data, "DO-MORE phase ends with %d\n", (int)result));
3637 }
Kristian Monsen5ab50182010-05-14 18:53:44 +01003638
3639 return result;
3640}
3641
3642
3643
3644/***********************************************************************
3645 *
3646 * ftp_perform()
3647 *
3648 * This is the actual DO function for FTP. Get a file/directory according to
3649 * the options previously setup.
3650 */
3651
3652static
3653CURLcode ftp_perform(struct connectdata *conn,
3654 bool *connected, /* connect status after PASV / PORT */
3655 bool *dophase_done)
3656{
3657 /* this is FTP and no proxy */
Alex Deymo486467e2017-12-19 19:04:07 +01003658 CURLcode result = CURLE_OK;
Kristian Monsen5ab50182010-05-14 18:53:44 +01003659
3660 DEBUGF(infof(conn->data, "DO phase starts\n"));
3661
3662 if(conn->data->set.opt_no_body) {
3663 /* requested no body means no transfer... */
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07003664 struct FTP *ftp = conn->data->req.protop;
Kristian Monsen5ab50182010-05-14 18:53:44 +01003665 ftp->transfer = FTPTRANSFER_INFO;
3666 }
3667
Kristian Monsen5ab50182010-05-14 18:53:44 +01003668 *dophase_done = FALSE; /* not done yet */
3669
3670 /* start the first command in the DO phase */
3671 result = ftp_state_quote(conn, TRUE, FTP_QUOTE);
3672 if(result)
3673 return result;
3674
3675 /* run the state-machine */
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07003676 result = ftp_multi_statemach(conn, dophase_done);
3677
3678 *connected = conn->bits.tcpconnect[SECONDARYSOCKET];
3679
3680 infof(conn->data, "ftp_perform ends with SECONDARY: %d\n", *connected);
Kristian Monsen5ab50182010-05-14 18:53:44 +01003681
3682 if(*dophase_done)
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07003683 DEBUGF(infof(conn->data, "DO phase is complete1\n"));
Kristian Monsen5ab50182010-05-14 18:53:44 +01003684
3685 return result;
3686}
3687
Lucas Eckels9bd90e62012-08-06 15:07:02 -07003688static void wc_data_dtor(void *ptr)
3689{
Elliott Hughes1ef06ba2018-05-30 15:43:58 -07003690 struct ftp_wc *ftpwc = ptr;
3691 if(ftpwc && ftpwc->parser)
3692 Curl_ftp_parselist_data_free(&ftpwc->parser);
3693 free(ftpwc);
Lucas Eckels9bd90e62012-08-06 15:07:02 -07003694}
3695
3696static CURLcode init_wc_data(struct connectdata *conn)
3697{
3698 char *last_slash;
3699 char *path = conn->data->state.path;
3700 struct WildcardData *wildcard = &(conn->data->wildcard);
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07003701 CURLcode result = CURLE_OK;
Elliott Hughes1ef06ba2018-05-30 15:43:58 -07003702 struct ftp_wc *ftpwc = NULL;
Lucas Eckels9bd90e62012-08-06 15:07:02 -07003703
3704 last_slash = strrchr(conn->data->state.path, '/');
3705 if(last_slash) {
3706 last_slash++;
3707 if(last_slash[0] == '\0') {
3708 wildcard->state = CURLWC_CLEAN;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07003709 result = ftp_parse_url_path(conn);
3710 return result;
Lucas Eckels9bd90e62012-08-06 15:07:02 -07003711 }
Elliott Hughes82be86d2017-09-20 17:00:17 -07003712 wildcard->pattern = strdup(last_slash);
3713 if(!wildcard->pattern)
3714 return CURLE_OUT_OF_MEMORY;
3715 last_slash[0] = '\0'; /* cut file from path */
Lucas Eckels9bd90e62012-08-06 15:07:02 -07003716 }
3717 else { /* there is only 'wildcard pattern' or nothing */
3718 if(path[0]) {
3719 wildcard->pattern = strdup(path);
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07003720 if(!wildcard->pattern)
Lucas Eckels9bd90e62012-08-06 15:07:02 -07003721 return CURLE_OUT_OF_MEMORY;
3722 path[0] = '\0';
3723 }
3724 else { /* only list */
3725 wildcard->state = CURLWC_CLEAN;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07003726 result = ftp_parse_url_path(conn);
3727 return result;
Lucas Eckels9bd90e62012-08-06 15:07:02 -07003728 }
3729 }
3730
3731 /* program continues only if URL is not ending with slash, allocate needed
3732 resources for wildcard transfer */
3733
Elliott Hughes1ef06ba2018-05-30 15:43:58 -07003734 /* allocate ftp protocol specific wildcard data */
3735 ftpwc = calloc(1, sizeof(struct ftp_wc));
3736 if(!ftpwc) {
3737 result = CURLE_OUT_OF_MEMORY;
3738 goto fail;
Lucas Eckels9bd90e62012-08-06 15:07:02 -07003739 }
3740
3741 /* INITIALIZE parselist structure */
Elliott Hughes1ef06ba2018-05-30 15:43:58 -07003742 ftpwc->parser = Curl_ftp_parselist_data_alloc();
3743 if(!ftpwc->parser) {
3744 result = CURLE_OUT_OF_MEMORY;
3745 goto fail;
Lucas Eckels9bd90e62012-08-06 15:07:02 -07003746 }
3747
Elliott Hughes1ef06ba2018-05-30 15:43:58 -07003748 wildcard->protdata = ftpwc; /* put it to the WildcardData tmp pointer */
3749 wildcard->dtor = wc_data_dtor;
Lucas Eckels9bd90e62012-08-06 15:07:02 -07003750
3751 /* wildcard does not support NOCWD option (assert it?) */
3752 if(conn->data->set.ftp_filemethod == FTPFILE_NOCWD)
3753 conn->data->set.ftp_filemethod = FTPFILE_MULTICWD;
3754
3755 /* try to parse ftp url */
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07003756 result = ftp_parse_url_path(conn);
3757 if(result) {
Elliott Hughes1ef06ba2018-05-30 15:43:58 -07003758 goto fail;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07003759 }
3760
3761 wildcard->path = strdup(conn->data->state.path);
3762 if(!wildcard->path) {
Elliott Hughes1ef06ba2018-05-30 15:43:58 -07003763 result = CURLE_OUT_OF_MEMORY;
3764 goto fail;
Lucas Eckels9bd90e62012-08-06 15:07:02 -07003765 }
3766
3767 /* backup old write_function */
Elliott Hughes1ef06ba2018-05-30 15:43:58 -07003768 ftpwc->backup.write_function = conn->data->set.fwrite_func;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07003769 /* parsing write function */
Lucas Eckels9bd90e62012-08-06 15:07:02 -07003770 conn->data->set.fwrite_func = Curl_ftp_parselist;
3771 /* backup old file descriptor */
Elliott Hughes1ef06ba2018-05-30 15:43:58 -07003772 ftpwc->backup.file_descriptor = conn->data->set.out;
Lucas Eckels9bd90e62012-08-06 15:07:02 -07003773 /* let the writefunc callback know what curl pointer is working with */
3774 conn->data->set.out = conn;
3775
Lucas Eckels9bd90e62012-08-06 15:07:02 -07003776 infof(conn->data, "Wildcard - Parsing started\n");
3777 return CURLE_OK;
Elliott Hughes1ef06ba2018-05-30 15:43:58 -07003778
3779 fail:
3780 if(ftpwc) {
3781 Curl_ftp_parselist_data_free(&ftpwc->parser);
3782 free(ftpwc);
3783 }
3784 Curl_safefree(wildcard->pattern);
3785 wildcard->dtor = ZERO_NULL;
3786 wildcard->protdata = NULL;
3787 return result;
Lucas Eckels9bd90e62012-08-06 15:07:02 -07003788}
3789
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07003790/* This is called recursively */
Lucas Eckels9bd90e62012-08-06 15:07:02 -07003791static CURLcode wc_statemach(struct connectdata *conn)
3792{
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07003793 struct WildcardData * const wildcard = &(conn->data->wildcard);
3794 CURLcode result = CURLE_OK;
3795
Elliott Hughes82be86d2017-09-20 17:00:17 -07003796 switch(wildcard->state) {
Lucas Eckels9bd90e62012-08-06 15:07:02 -07003797 case CURLWC_INIT:
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07003798 result = init_wc_data(conn);
Lucas Eckels9bd90e62012-08-06 15:07:02 -07003799 if(wildcard->state == CURLWC_CLEAN)
3800 /* only listing! */
3801 break;
Elliott Hughes82be86d2017-09-20 17:00:17 -07003802 wildcard->state = result ? CURLWC_ERROR : CURLWC_MATCHING;
Lucas Eckels9bd90e62012-08-06 15:07:02 -07003803 break;
3804
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07003805 case CURLWC_MATCHING: {
Lucas Eckels9bd90e62012-08-06 15:07:02 -07003806 /* In this state is LIST response successfully parsed, so lets restore
3807 previous WRITEFUNCTION callback and WRITEDATA pointer */
Elliott Hughes1ef06ba2018-05-30 15:43:58 -07003808 struct ftp_wc *ftpwc = wildcard->protdata;
3809 conn->data->set.fwrite_func = ftpwc->backup.write_function;
3810 conn->data->set.out = ftpwc->backup.file_descriptor;
3811 ftpwc->backup.write_function = ZERO_NULL;
3812 ftpwc->backup.file_descriptor = NULL;
Lucas Eckels9bd90e62012-08-06 15:07:02 -07003813 wildcard->state = CURLWC_DOWNLOADING;
3814
Elliott Hughes1ef06ba2018-05-30 15:43:58 -07003815 if(Curl_ftp_parselist_geterror(ftpwc->parser)) {
Lucas Eckels9bd90e62012-08-06 15:07:02 -07003816 /* error found in LIST parsing */
3817 wildcard->state = CURLWC_CLEAN;
3818 return wc_statemach(conn);
3819 }
Elliott Hughes82be86d2017-09-20 17:00:17 -07003820 if(wildcard->filelist.size == 0) {
Lucas Eckels9bd90e62012-08-06 15:07:02 -07003821 /* no corresponding file */
3822 wildcard->state = CURLWC_CLEAN;
3823 return CURLE_REMOTE_FILE_NOT_FOUND;
3824 }
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07003825 return wc_statemach(conn);
3826 }
Lucas Eckels9bd90e62012-08-06 15:07:02 -07003827
3828 case CURLWC_DOWNLOADING: {
3829 /* filelist has at least one file, lets get first one */
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07003830 struct ftp_conn *ftpc = &conn->proto.ftpc;
Elliott Hughes82be86d2017-09-20 17:00:17 -07003831 struct curl_fileinfo *finfo = wildcard->filelist.head->ptr;
Lucas Eckels9bd90e62012-08-06 15:07:02 -07003832
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07003833 char *tmp_path = aprintf("%s%s", wildcard->path, finfo->filename);
3834 if(!tmp_path)
3835 return CURLE_OUT_OF_MEMORY;
3836
Lucas Eckels9bd90e62012-08-06 15:07:02 -07003837 /* switch default "state.pathbuffer" and tmp_path, good to see
3838 ftp_parse_url_path function to understand this trick */
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07003839 Curl_safefree(conn->data->state.pathbuffer);
Lucas Eckels9bd90e62012-08-06 15:07:02 -07003840 conn->data->state.pathbuffer = tmp_path;
3841 conn->data->state.path = tmp_path;
3842
3843 infof(conn->data, "Wildcard - START of \"%s\"\n", finfo->filename);
3844 if(conn->data->set.chunk_bgn) {
Elliott Hughescac39802018-04-27 16:19:43 -07003845 long userresponse;
3846 Curl_set_in_callback(conn->data, true);
3847 userresponse = conn->data->set.chunk_bgn(
Elliott Hughes82be86d2017-09-20 17:00:17 -07003848 finfo, wildcard->customptr, (int)wildcard->filelist.size);
Elliott Hughescac39802018-04-27 16:19:43 -07003849 Curl_set_in_callback(conn->data, false);
Lucas Eckels9bd90e62012-08-06 15:07:02 -07003850 switch(userresponse) {
3851 case CURL_CHUNK_BGN_FUNC_SKIP:
3852 infof(conn->data, "Wildcard - \"%s\" skipped by user\n",
3853 finfo->filename);
3854 wildcard->state = CURLWC_SKIP;
3855 return wc_statemach(conn);
3856 case CURL_CHUNK_BGN_FUNC_FAIL:
3857 return CURLE_CHUNK_FAILED;
3858 }
3859 }
3860
3861 if(finfo->filetype != CURLFILETYPE_FILE) {
3862 wildcard->state = CURLWC_SKIP;
3863 return wc_statemach(conn);
3864 }
3865
3866 if(finfo->flags & CURLFINFOFLAG_KNOWN_SIZE)
3867 ftpc->known_filesize = finfo->size;
3868
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07003869 result = ftp_parse_url_path(conn);
3870 if(result)
3871 return result;
Lucas Eckels9bd90e62012-08-06 15:07:02 -07003872
3873 /* we don't need the Curl_fileinfo of first file anymore */
Elliott Hughes82be86d2017-09-20 17:00:17 -07003874 Curl_llist_remove(&wildcard->filelist, wildcard->filelist.head, NULL);
Lucas Eckels9bd90e62012-08-06 15:07:02 -07003875
Elliott Hughes82be86d2017-09-20 17:00:17 -07003876 if(wildcard->filelist.size == 0) { /* remains only one file to down. */
Lucas Eckels9bd90e62012-08-06 15:07:02 -07003877 wildcard->state = CURLWC_CLEAN;
3878 /* after that will be ftp_do called once again and no transfer
3879 will be done because of CURLWC_CLEAN state */
3880 return CURLE_OK;
3881 }
3882 } break;
3883
3884 case CURLWC_SKIP: {
Elliott Hughescac39802018-04-27 16:19:43 -07003885 if(conn->data->set.chunk_end) {
3886 Curl_set_in_callback(conn->data, true);
Lucas Eckels9bd90e62012-08-06 15:07:02 -07003887 conn->data->set.chunk_end(conn->data->wildcard.customptr);
Elliott Hughescac39802018-04-27 16:19:43 -07003888 Curl_set_in_callback(conn->data, false);
3889 }
Elliott Hughes82be86d2017-09-20 17:00:17 -07003890 Curl_llist_remove(&wildcard->filelist, wildcard->filelist.head, NULL);
3891 wildcard->state = (wildcard->filelist.size == 0) ?
Lucas Eckels9bd90e62012-08-06 15:07:02 -07003892 CURLWC_CLEAN : CURLWC_DOWNLOADING;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07003893 return wc_statemach(conn);
3894 }
Lucas Eckels9bd90e62012-08-06 15:07:02 -07003895
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07003896 case CURLWC_CLEAN: {
Elliott Hughes1ef06ba2018-05-30 15:43:58 -07003897 struct ftp_wc *ftpwc = wildcard->protdata;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07003898 result = CURLE_OK;
Elliott Hughes1ef06ba2018-05-30 15:43:58 -07003899 if(ftpwc)
3900 result = Curl_ftp_parselist_geterror(ftpwc->parser);
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07003901
3902 wildcard->state = result ? CURLWC_ERROR : CURLWC_DONE;
3903 } break;
Lucas Eckels9bd90e62012-08-06 15:07:02 -07003904
3905 case CURLWC_DONE:
3906 case CURLWC_ERROR:
Elliott Hughes82be86d2017-09-20 17:00:17 -07003907 case CURLWC_CLEAR:
Elliott Hughes1ef06ba2018-05-30 15:43:58 -07003908 if(wildcard->dtor)
3909 wildcard->dtor(wildcard->protdata);
Lucas Eckels9bd90e62012-08-06 15:07:02 -07003910 break;
3911 }
3912
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07003913 return result;
Lucas Eckels9bd90e62012-08-06 15:07:02 -07003914}
3915
Kristian Monsen5ab50182010-05-14 18:53:44 +01003916/***********************************************************************
3917 *
3918 * ftp_do()
3919 *
3920 * This function is registered as 'curl_do' function. It decodes the path
3921 * parts etc as a wrapper to the actual DO function (ftp_perform).
3922 *
3923 * The input argument is already checked for validity.
3924 */
3925static CURLcode ftp_do(struct connectdata *conn, bool *done)
3926{
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07003927 CURLcode result = CURLE_OK;
3928 struct ftp_conn *ftpc = &conn->proto.ftpc;
Kristian Monsen5ab50182010-05-14 18:53:44 +01003929
3930 *done = FALSE; /* default to false */
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07003931 ftpc->wait_data_conn = FALSE; /* default to no such wait */
Kristian Monsen5ab50182010-05-14 18:53:44 +01003932
Alex Deymo486467e2017-12-19 19:04:07 +01003933 if(conn->data->state.wildcardmatch) {
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07003934 result = wc_statemach(conn);
Lucas Eckels9bd90e62012-08-06 15:07:02 -07003935 if(conn->data->wildcard.state == CURLWC_SKIP ||
3936 conn->data->wildcard.state == CURLWC_DONE) {
3937 /* do not call ftp_regular_transfer */
3938 return CURLE_OK;
3939 }
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07003940 if(result) /* error, loop or skipping the file */
3941 return result;
Lucas Eckels9bd90e62012-08-06 15:07:02 -07003942 }
3943 else { /* no wildcard FSM needed */
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07003944 result = ftp_parse_url_path(conn);
3945 if(result)
3946 return result;
Lucas Eckels9bd90e62012-08-06 15:07:02 -07003947 }
Kristian Monsen5ab50182010-05-14 18:53:44 +01003948
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07003949 result = ftp_regular_transfer(conn, done);
Kristian Monsen5ab50182010-05-14 18:53:44 +01003950
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07003951 return result;
Kristian Monsen5ab50182010-05-14 18:53:44 +01003952}
3953
3954
Elliott Hughescee03382017-06-23 12:17:18 -07003955CURLcode Curl_ftpsend(struct connectdata *conn, const char *cmd)
Kristian Monsen5ab50182010-05-14 18:53:44 +01003956{
3957 ssize_t bytes_written;
3958#define SBUF_SIZE 1024
3959 char s[SBUF_SIZE];
3960 size_t write_len;
Alex Deymo486467e2017-12-19 19:04:07 +01003961 char *sptr = s;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07003962 CURLcode result = CURLE_OK;
3963#ifdef HAVE_GSSAPI
Kristian Monsen5ab50182010-05-14 18:53:44 +01003964 enum protection_level data_sec = conn->data_prot;
3965#endif
3966
Elliott Hughescee03382017-06-23 12:17:18 -07003967 write_len = strlen(cmd);
3968 if(write_len > (sizeof(s) -3))
3969 return CURLE_BAD_FUNCTION_ARGUMENT;
Kristian Monsen5ab50182010-05-14 18:53:44 +01003970
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07003971 strcpy(&s[write_len], "\r\n"); /* append a trailing CRLF */
Alex Deymo486467e2017-12-19 19:04:07 +01003972 write_len += 2;
3973 bytes_written = 0;
Kristian Monsen5ab50182010-05-14 18:53:44 +01003974
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07003975 result = Curl_convert_to_network(conn->data, s, write_len);
Kristian Monsen5ab50182010-05-14 18:53:44 +01003976 /* Curl_convert_to_network calls failf if unsuccessful */
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07003977 if(result)
3978 return result;
Kristian Monsen5ab50182010-05-14 18:53:44 +01003979
3980 for(;;) {
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07003981#ifdef HAVE_GSSAPI
3982 conn->data_prot = PROT_CMD;
Kristian Monsen5ab50182010-05-14 18:53:44 +01003983#endif
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07003984 result = Curl_write(conn, conn->sock[FIRSTSOCKET], sptr, write_len,
3985 &bytes_written);
3986#ifdef HAVE_GSSAPI
3987 DEBUGASSERT(data_sec > PROT_NONE && data_sec < PROT_LAST);
Kristian Monsen5ab50182010-05-14 18:53:44 +01003988 conn->data_prot = data_sec;
3989#endif
3990
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07003991 if(result)
Kristian Monsen5ab50182010-05-14 18:53:44 +01003992 break;
3993
3994 if(conn->data->set.verbose)
3995 Curl_debug(conn->data, CURLINFO_HEADER_OUT,
3996 sptr, (size_t)bytes_written, conn);
3997
3998 if(bytes_written != (ssize_t)write_len) {
3999 write_len -= bytes_written;
4000 sptr += bytes_written;
4001 }
4002 else
4003 break;
4004 }
4005
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07004006 return result;
Kristian Monsen5ab50182010-05-14 18:53:44 +01004007}
4008
4009/***********************************************************************
4010 *
4011 * ftp_quit()
4012 *
4013 * This should be called before calling sclose() on an ftp control connection
4014 * (not data connections). We should then wait for the response from the
4015 * server before returning. The calling code should then try to close the
4016 * connection.
4017 *
4018 */
4019static CURLcode ftp_quit(struct connectdata *conn)
4020{
4021 CURLcode result = CURLE_OK;
4022
4023 if(conn->proto.ftpc.ctl_valid) {
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07004024 result = Curl_pp_sendf(&conn->proto.ftpc.pp, "%s", "QUIT");
4025 if(result) {
4026 failf(conn->data, "Failure sending QUIT command: %s",
4027 curl_easy_strerror(result));
4028 conn->proto.ftpc.ctl_valid = FALSE; /* mark control connection as bad */
4029 connclose(conn, "QUIT command failed"); /* mark for connection closure */
4030 state(conn, FTP_STOP);
4031 return result;
4032 }
4033
Kristian Monsen5ab50182010-05-14 18:53:44 +01004034 state(conn, FTP_QUIT);
4035
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07004036 result = ftp_block_statemach(conn);
Kristian Monsen5ab50182010-05-14 18:53:44 +01004037 }
4038
4039 return result;
4040}
4041
4042/***********************************************************************
4043 *
4044 * ftp_disconnect()
4045 *
4046 * Disconnect from an FTP server. Cleanup protocol-specific per-connection
4047 * resources. BLOCKING.
4048 */
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07004049static CURLcode ftp_disconnect(struct connectdata *conn, bool dead_connection)
Kristian Monsen5ab50182010-05-14 18:53:44 +01004050{
Alex Deymo486467e2017-12-19 19:04:07 +01004051 struct ftp_conn *ftpc = &conn->proto.ftpc;
Kristian Monsen5ab50182010-05-14 18:53:44 +01004052 struct pingpong *pp = &ftpc->pp;
4053
4054 /* We cannot send quit unconditionally. If this connection is stale or
4055 bad in any way, sending quit and waiting around here will make the
4056 disconnect wait in vain and cause more problems than we need to.
4057
4058 ftp_quit() will check the state of ftp->ctl_valid. If it's ok it
4059 will try to send the QUIT command, otherwise it will just return.
4060 */
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07004061 if(dead_connection)
4062 ftpc->ctl_valid = FALSE;
Kristian Monsen5ab50182010-05-14 18:53:44 +01004063
4064 /* The FTP session may or may not have been allocated/setup at this point! */
4065 (void)ftp_quit(conn); /* ignore errors on the QUIT */
4066
4067 if(ftpc->entrypath) {
Alex Deymoe3149cc2016-10-05 11:18:42 -07004068 struct Curl_easy *data = conn->data;
Kristian Monsen5ab50182010-05-14 18:53:44 +01004069 if(data->state.most_recent_ftp_entrypath == ftpc->entrypath) {
4070 data->state.most_recent_ftp_entrypath = NULL;
4071 }
4072 free(ftpc->entrypath);
4073 ftpc->entrypath = NULL;
4074 }
4075
4076 freedirs(ftpc);
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07004077 free(ftpc->prevpath);
4078 ftpc->prevpath = NULL;
4079 free(ftpc->server_os);
4080 ftpc->server_os = NULL;
Kristian Monsen5ab50182010-05-14 18:53:44 +01004081
4082 Curl_pp_disconnect(pp);
4083
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07004084#ifdef HAVE_GSSAPI
Lucas Eckels9bd90e62012-08-06 15:07:02 -07004085 Curl_sec_end(conn);
4086#endif
4087
Kristian Monsen5ab50182010-05-14 18:53:44 +01004088 return CURLE_OK;
4089}
4090
4091/***********************************************************************
4092 *
4093 * ftp_parse_url_path()
4094 *
4095 * Parse the URL path into separate path components.
4096 *
4097 */
4098static
4099CURLcode ftp_parse_url_path(struct connectdata *conn)
4100{
Alex Deymoe3149cc2016-10-05 11:18:42 -07004101 struct Curl_easy *data = conn->data;
Kristian Monsen5ab50182010-05-14 18:53:44 +01004102 /* the ftp struct is already inited in ftp_connect() */
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07004103 struct FTP *ftp = data->req.protop;
Kristian Monsen5ab50182010-05-14 18:53:44 +01004104 struct ftp_conn *ftpc = &conn->proto.ftpc;
4105 const char *slash_pos; /* position of the first '/' char in curpos */
4106 const char *path_to_use = data->state.path;
4107 const char *cur_pos;
4108 const char *filename = NULL;
4109
Elliott Hughescee03382017-06-23 12:17:18 -07004110 cur_pos = path_to_use; /* current position in path. point at the begin of
4111 next path component */
Kristian Monsen5ab50182010-05-14 18:53:44 +01004112
4113 ftpc->ctl_valid = FALSE;
4114 ftpc->cwdfail = FALSE;
4115
4116 switch(data->set.ftp_filemethod) {
4117 case FTPFILE_NOCWD:
4118 /* fastest, but less standard-compliant */
4119
4120 /*
4121 The best time to check whether the path is a file or directory is right
4122 here. so:
4123
4124 the first condition in the if() right here, is there just in case
4125 someone decides to set path to NULL one day
4126 */
Alex Deymod15eaac2016-06-28 14:49:26 -07004127 if(path_to_use[0] &&
4128 (path_to_use[strlen(path_to_use) - 1] != '/') )
4129 filename = path_to_use; /* this is a full file path */
4130 /*
4131 else {
Kristian Monsen5ab50182010-05-14 18:53:44 +01004132 ftpc->file is not used anywhere other than for operations on a file.
4133 In other words, never for directory operations.
4134 So we can safely leave filename as NULL here and use it as a
4135 argument in dir/file decisions.
Alex Deymod15eaac2016-06-28 14:49:26 -07004136 }
4137 */
Kristian Monsen5ab50182010-05-14 18:53:44 +01004138 break;
4139
4140 case FTPFILE_SINGLECWD:
4141 /* get the last slash */
4142 if(!path_to_use[0]) {
4143 /* no dir, no file */
4144 ftpc->dirdepth = 0;
4145 break;
4146 }
Alex Deymo486467e2017-12-19 19:04:07 +01004147 slash_pos = strrchr(cur_pos, '/');
Kristian Monsen5ab50182010-05-14 18:53:44 +01004148 if(slash_pos || !*cur_pos) {
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07004149 size_t dirlen = slash_pos-cur_pos;
Elliott Hughescee03382017-06-23 12:17:18 -07004150 CURLcode result;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07004151
Kristian Monsen5ab50182010-05-14 18:53:44 +01004152 ftpc->dirs = calloc(1, sizeof(ftpc->dirs[0]));
4153 if(!ftpc->dirs)
4154 return CURLE_OUT_OF_MEMORY;
4155
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07004156 if(!dirlen)
4157 dirlen++;
4158
Elliott Hughescee03382017-06-23 12:17:18 -07004159 result = Curl_urldecode(conn->data, slash_pos ? cur_pos : "/",
4160 slash_pos ? dirlen : 1,
4161 &ftpc->dirs[0], NULL,
Elliott Hughescac39802018-04-27 16:19:43 -07004162 TRUE);
Elliott Hughescee03382017-06-23 12:17:18 -07004163 if(result) {
Kristian Monsen5ab50182010-05-14 18:53:44 +01004164 freedirs(ftpc);
Elliott Hughescee03382017-06-23 12:17:18 -07004165 return result;
Kristian Monsen5ab50182010-05-14 18:53:44 +01004166 }
4167 ftpc->dirdepth = 1; /* we consider it to be a single dir */
Alex Deymo486467e2017-12-19 19:04:07 +01004168 filename = slash_pos ? slash_pos + 1 : cur_pos; /* rest is file name */
Kristian Monsen5ab50182010-05-14 18:53:44 +01004169 }
4170 else
4171 filename = cur_pos; /* this is a file name only */
4172 break;
4173
4174 default: /* allow pretty much anything */
4175 case FTPFILE_MULTICWD:
4176 ftpc->dirdepth = 0;
4177 ftpc->diralloc = 5; /* default dir depth to allocate */
4178 ftpc->dirs = calloc(ftpc->diralloc, sizeof(ftpc->dirs[0]));
4179 if(!ftpc->dirs)
4180 return CURLE_OUT_OF_MEMORY;
4181
4182 /* we have a special case for listing the root dir only */
Elliott Hughescee03382017-06-23 12:17:18 -07004183 if(!strcmp(path_to_use, "/")) {
Kristian Monsen5ab50182010-05-14 18:53:44 +01004184 cur_pos++; /* make it point to the zero byte */
4185 ftpc->dirs[0] = strdup("/");
4186 ftpc->dirdepth++;
4187 }
4188 else {
4189 /* parse the URL path into separate path components */
4190 while((slash_pos = strchr(cur_pos, '/')) != NULL) {
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07004191 /* 1 or 0 pointer offset to indicate absolute directory */
4192 ssize_t absolute_dir = ((cur_pos - data->state.path > 0) &&
4193 (ftpc->dirdepth == 0))?1:0;
Kristian Monsen5ab50182010-05-14 18:53:44 +01004194
4195 /* seek out the next path component */
4196 if(slash_pos-cur_pos) {
4197 /* we skip empty path components, like "x//y" since the FTP command
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07004198 CWD requires a parameter and a non-existent parameter a) doesn't
Kristian Monsen5ab50182010-05-14 18:53:44 +01004199 work on many servers and b) has no effect on the others. */
Elliott Hughescee03382017-06-23 12:17:18 -07004200 size_t len = slash_pos - cur_pos + absolute_dir;
4201 CURLcode result =
4202 Curl_urldecode(conn->data, cur_pos - absolute_dir, len,
4203 &ftpc->dirs[ftpc->dirdepth], NULL,
4204 TRUE);
4205 if(result) {
Kristian Monsen5ab50182010-05-14 18:53:44 +01004206 freedirs(ftpc);
Elliott Hughescee03382017-06-23 12:17:18 -07004207 return result;
Kristian Monsen5ab50182010-05-14 18:53:44 +01004208 }
4209 }
4210 else {
4211 cur_pos = slash_pos + 1; /* jump to the rest of the string */
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07004212 if(!ftpc->dirdepth) {
4213 /* path starts with a slash, add that as a directory */
4214 ftpc->dirs[ftpc->dirdepth] = strdup("/");
4215 if(!ftpc->dirs[ftpc->dirdepth++]) { /* run out of memory ... */
4216 failf(data, "no memory");
4217 freedirs(ftpc);
4218 return CURLE_OUT_OF_MEMORY;
4219 }
4220 }
Kristian Monsen5ab50182010-05-14 18:53:44 +01004221 continue;
4222 }
4223
4224 cur_pos = slash_pos + 1; /* jump to the rest of the string */
4225 if(++ftpc->dirdepth >= ftpc->diralloc) {
4226 /* enlarge array */
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07004227 char **bigger;
Kristian Monsen5ab50182010-05-14 18:53:44 +01004228 ftpc->diralloc *= 2; /* double the size each time */
4229 bigger = realloc(ftpc->dirs, ftpc->diralloc * sizeof(ftpc->dirs[0]));
4230 if(!bigger) {
4231 freedirs(ftpc);
4232 return CURLE_OUT_OF_MEMORY;
4233 }
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07004234 ftpc->dirs = bigger;
Kristian Monsen5ab50182010-05-14 18:53:44 +01004235 }
4236 }
4237 }
4238 filename = cur_pos; /* the rest is the file name */
4239 break;
4240 } /* switch */
4241
4242 if(filename && *filename) {
Elliott Hughescee03382017-06-23 12:17:18 -07004243 CURLcode result =
4244 Curl_urldecode(conn->data, filename, 0, &ftpc->file, NULL, TRUE);
4245
4246 if(result) {
Kristian Monsen5ab50182010-05-14 18:53:44 +01004247 freedirs(ftpc);
Elliott Hughescee03382017-06-23 12:17:18 -07004248 return result;
Kristian Monsen5ab50182010-05-14 18:53:44 +01004249 }
4250 }
4251 else
Alex Deymo486467e2017-12-19 19:04:07 +01004252 ftpc->file = NULL; /* instead of point to a zero byte, we make it a NULL
4253 pointer */
Kristian Monsen5ab50182010-05-14 18:53:44 +01004254
4255 if(data->set.upload && !ftpc->file && (ftp->transfer == FTPTRANSFER_BODY)) {
4256 /* We need a file name when uploading. Return error! */
4257 failf(data, "Uploading to a URL without a file name!");
4258 return CURLE_URL_MALFORMAT;
4259 }
4260
4261 ftpc->cwddone = FALSE; /* default to not done */
4262
4263 if(ftpc->prevpath) {
4264 /* prevpath is "raw" so we convert the input path before we compare the
4265 strings */
Elliott Hughescee03382017-06-23 12:17:18 -07004266 size_t dlen;
4267 char *path;
4268 CURLcode result =
Elliott Hughescac39802018-04-27 16:19:43 -07004269 Curl_urldecode(conn->data, data->state.path, 0, &path, &dlen, TRUE);
Elliott Hughescee03382017-06-23 12:17:18 -07004270 if(result) {
Kristian Monsen5ab50182010-05-14 18:53:44 +01004271 freedirs(ftpc);
Elliott Hughescee03382017-06-23 12:17:18 -07004272 return result;
Kristian Monsen5ab50182010-05-14 18:53:44 +01004273 }
4274
Elliott Hughescee03382017-06-23 12:17:18 -07004275 dlen -= ftpc->file?strlen(ftpc->file):0;
4276 if((dlen == strlen(ftpc->prevpath)) &&
Alex Deymo486467e2017-12-19 19:04:07 +01004277 !strncmp(path, ftpc->prevpath, dlen) &&
4278 (ftpc->prevmethod == data->set.ftp_filemethod)) {
Kristian Monsen5ab50182010-05-14 18:53:44 +01004279 infof(data, "Request has same path as previous transfer\n");
4280 ftpc->cwddone = TRUE;
4281 }
4282 free(path);
4283 }
4284
4285 return CURLE_OK;
4286}
4287
4288/* call this when the DO phase has completed */
4289static CURLcode ftp_dophase_done(struct connectdata *conn,
4290 bool connected)
4291{
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07004292 struct FTP *ftp = conn->data->req.protop;
Kristian Monsen5ab50182010-05-14 18:53:44 +01004293 struct ftp_conn *ftpc = &conn->proto.ftpc;
4294
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07004295 if(connected) {
4296 int completed;
4297 CURLcode result = ftp_do_more(conn, &completed);
Kristian Monsen5ab50182010-05-14 18:53:44 +01004298
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07004299 if(result) {
Alex Deymod15eaac2016-06-28 14:49:26 -07004300 close_secondarysocket(conn);
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07004301 return result;
4302 }
Kristian Monsen5ab50182010-05-14 18:53:44 +01004303 }
4304
4305 if(ftp->transfer != FTPTRANSFER_BODY)
4306 /* no data to transfer */
Lucas Eckels9bd90e62012-08-06 15:07:02 -07004307 Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
Kristian Monsen5ab50182010-05-14 18:53:44 +01004308 else if(!connected)
4309 /* since we didn't connect now, we want do_more to get called */
4310 conn->bits.do_more = TRUE;
4311
4312 ftpc->ctl_valid = TRUE; /* seems good */
4313
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07004314 return CURLE_OK;
Kristian Monsen5ab50182010-05-14 18:53:44 +01004315}
4316
4317/* called from multi.c while DOing */
4318static CURLcode ftp_doing(struct connectdata *conn,
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07004319 bool *dophase_done)
Kristian Monsen5ab50182010-05-14 18:53:44 +01004320{
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07004321 CURLcode result = ftp_multi_statemach(conn, dophase_done);
Kristian Monsen5ab50182010-05-14 18:53:44 +01004322
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07004323 if(result)
4324 DEBUGF(infof(conn->data, "DO phase failed\n"));
4325 else if(*dophase_done) {
Kristian Monsen5ab50182010-05-14 18:53:44 +01004326 result = ftp_dophase_done(conn, FALSE /* not connected */);
4327
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07004328 DEBUGF(infof(conn->data, "DO phase is complete2\n"));
Kristian Monsen5ab50182010-05-14 18:53:44 +01004329 }
4330 return result;
4331}
4332
4333/***********************************************************************
4334 *
4335 * ftp_regular_transfer()
4336 *
4337 * The input argument is already checked for validity.
4338 *
4339 * Performs all commands done before a regular transfer between a local and a
4340 * remote host.
4341 *
4342 * ftp->ctl_valid starts out as FALSE, and gets set to TRUE if we reach the
4343 * ftp_done() function without finding any major problem.
4344 */
4345static
4346CURLcode ftp_regular_transfer(struct connectdata *conn,
4347 bool *dophase_done)
4348{
Alex Deymo486467e2017-12-19 19:04:07 +01004349 CURLcode result = CURLE_OK;
4350 bool connected = FALSE;
Alex Deymoe3149cc2016-10-05 11:18:42 -07004351 struct Curl_easy *data = conn->data;
Kristian Monsen5ab50182010-05-14 18:53:44 +01004352 struct ftp_conn *ftpc = &conn->proto.ftpc;
4353 data->req.size = -1; /* make sure this is unknown at this point */
4354
4355 Curl_pgrsSetUploadCounter(data, 0);
4356 Curl_pgrsSetDownloadCounter(data, 0);
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07004357 Curl_pgrsSetUploadSize(data, -1);
4358 Curl_pgrsSetDownloadSize(data, -1);
Kristian Monsen5ab50182010-05-14 18:53:44 +01004359
4360 ftpc->ctl_valid = TRUE; /* starts good */
4361
4362 result = ftp_perform(conn,
4363 &connected, /* have we connected after PASV/PORT */
4364 dophase_done); /* all commands in the DO-phase done? */
4365
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07004366 if(!result) {
Kristian Monsen5ab50182010-05-14 18:53:44 +01004367
4368 if(!*dophase_done)
4369 /* the DO phase has not completed yet */
4370 return CURLE_OK;
4371
4372 result = ftp_dophase_done(conn, connected);
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07004373
Kristian Monsen5ab50182010-05-14 18:53:44 +01004374 if(result)
4375 return result;
4376 }
4377 else
4378 freedirs(ftpc);
4379
4380 return result;
4381}
4382
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07004383static CURLcode ftp_setup_connection(struct connectdata *conn)
Kristian Monsen5ab50182010-05-14 18:53:44 +01004384{
Alex Deymoe3149cc2016-10-05 11:18:42 -07004385 struct Curl_easy *data = conn->data;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07004386 char *type;
Kristian Monsen5ab50182010-05-14 18:53:44 +01004387 char command;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07004388 struct FTP *ftp;
Kristian Monsen5ab50182010-05-14 18:53:44 +01004389
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07004390 conn->data->req.protop = ftp = malloc(sizeof(struct FTP));
4391 if(NULL == ftp)
4392 return CURLE_OUT_OF_MEMORY;
4393
Kristian Monsen5ab50182010-05-14 18:53:44 +01004394 data->state.path++; /* don't include the initial slash */
Lucas Eckels9bd90e62012-08-06 15:07:02 -07004395 data->state.slash_removed = TRUE; /* we've skipped the slash */
Kristian Monsen5ab50182010-05-14 18:53:44 +01004396
4397 /* FTP URLs support an extension like ";type=<typecode>" that
4398 * we'll try to get now! */
4399 type = strstr(data->state.path, ";type=");
4400
4401 if(!type)
4402 type = strstr(conn->host.rawalloc, ";type=");
4403
4404 if(type) {
4405 *type = 0; /* it was in the middle of the hostname */
4406 command = Curl_raw_toupper(type[6]);
Lucas Eckels9bd90e62012-08-06 15:07:02 -07004407 conn->bits.type_set = TRUE;
Kristian Monsen5ab50182010-05-14 18:53:44 +01004408
Elliott Hughes82be86d2017-09-20 17:00:17 -07004409 switch(command) {
Kristian Monsen5ab50182010-05-14 18:53:44 +01004410 case 'A': /* ASCII mode */
4411 data->set.prefer_ascii = TRUE;
4412 break;
4413
4414 case 'D': /* directory mode */
4415 data->set.ftp_list_only = TRUE;
4416 break;
4417
4418 case 'I': /* binary mode */
4419 default:
4420 /* switch off ASCII */
4421 data->set.prefer_ascii = FALSE;
4422 break;
4423 }
4424 }
4425
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07004426 /* get some initial data into the ftp struct */
4427 ftp->bytecountp = &conn->data->req.bytecount;
4428 ftp->transfer = FTPTRANSFER_BODY;
4429 ftp->downloadsize = 0;
4430
4431 /* No need to duplicate user+password, the connectdata struct won't change
4432 during a session, but we re-init them here since on subsequent inits
4433 since the conn struct may have changed or been replaced.
4434 */
4435 ftp->user = conn->user;
4436 ftp->passwd = conn->passwd;
4437 if(isBadFtpString(ftp->user))
4438 return CURLE_URL_MALFORMAT;
4439 if(isBadFtpString(ftp->passwd))
4440 return CURLE_URL_MALFORMAT;
4441
4442 conn->proto.ftpc.known_filesize = -1; /* unknown size for now */
4443
Kristian Monsen5ab50182010-05-14 18:53:44 +01004444 return CURLE_OK;
4445}
4446
4447#endif /* CURL_DISABLE_FTP */