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