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