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