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