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