1 /***************************************************************************
3 * Project ___| | | | _ \| |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
8 * Copyright (C) 1998 - 2007, Daniel Stenberg, <daniel@haxx.se>, et al.
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 http://curl.haxx.se/docs/copyright.html.
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.
18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19 * KIND, either express or implied.
21 * $Id: ftp.c,v 1.3 2007/11/05 19:34:36 king Exp $
22 ***************************************************************************/
26 #ifndef CURL_DISABLE_FTP
39 #else /* probably some kind of unix */
40 #ifdef HAVE_SYS_SOCKET_H
41 #include <sys/socket.h>
43 #include <sys/types.h>
44 #ifdef HAVE_NETINET_IN_H
45 #include <netinet/in.h>
47 #ifdef HAVE_ARPA_INET_H
48 #include <arpa/inet.h>
51 #include <sys/utsname.h>
62 #if (defined(NETWARE) && defined(__NOVELL_LIBC__))
64 #define in_addr_t unsigned long
67 #include <curl/curl.h>
70 #include "easyif.h" /* for Curl_convert_... prototypes */
77 #include "http.h" /* for HTTP proxy tunnel stuff */
84 #include "strtoofft.h"
90 #include "inet_ntop.h"
92 #include "parsedate.h" /* for the week day and month names */
93 #include "sockaddr.h" /* required for Curl_sockaddr_storage */
96 #if defined(HAVE_INET_NTOA_R) && !defined(HAVE_INET_NTOA_R_DECL)
97 #include "inet_ntoa_r.h"
100 #define _MPRINTF_REPLACE /* use our functions only */
101 #include <curl/mprintf.h>
103 /* The last #include file should be: */
105 #include "memdebug.h"
108 #ifdef HAVE_NI_WITHSCOPEID
109 #define NIFLAGS NI_NUMERICHOST | NI_NUMERICSERV | NI_WITHSCOPEID
111 #define NIFLAGS NI_NUMERICHOST | NI_NUMERICSERV
114 /* Local API functions */
115 static CURLcode
ftp_sendquote(struct connectdata
*conn
,
116 struct curl_slist
*quote
);
117 static CURLcode
ftp_quit(struct connectdata
*conn
);
118 static CURLcode
ftp_parse_url_path(struct connectdata
*conn
);
119 static CURLcode
ftp_regular_transfer(struct connectdata
*conn
, bool *done
);
120 static void ftp_pasv_verbose(struct connectdata
*conn
,
122 char *newhost
, /* ascii version */
124 static CURLcode
ftp_state_post_rest(struct connectdata
*conn
);
125 static CURLcode
ftp_state_post_cwd(struct connectdata
*conn
);
126 static CURLcode
ftp_state_quote(struct connectdata
*conn
,
127 bool init
, ftpstate instate
);
128 static CURLcode
ftp_nb_type(struct connectdata
*conn
,
129 bool ascii
, ftpstate state
);
130 static int ftp_need_type(struct connectdata
*conn
,
133 /* easy-to-use macro: */
134 #define FTPSENDF(x,y,z) if ((result = Curl_ftpsendf(x,y,z)) != CURLE_OK) \
136 #define NBFTPSENDF(x,y,z) if ((result = Curl_nbftpsendf(x,y,z)) != CURLE_OK) \
139 static void freedirs(struct connectdata
*conn
)
141 struct ftp_conn
*ftpc
= &conn
->proto
.ftpc
;
142 struct FTP
*ftp
= conn
->data
->reqdata
.proto
.ftp
;
146 for (i
=0; i
< ftpc
->dirdepth
; i
++){
161 /* Returns non-zero if the given string contains CR (\r) or LF (\n),
162 which are not allowed within RFC 959 <string>.
163 Note: The input string is in the client's encoding which might
164 not be ASCII, so escape sequences \r & \n must be used instead
165 of hex values 0x0d & 0x0a.
167 static bool isBadFtpString(const char *string
)
169 return (bool)((NULL
!= strchr(string
, '\r')) || (NULL
!= strchr(string
, '\n')));
172 /***********************************************************************
174 * AllowServerConnect()
176 * When we've issue the PORT command, we have told the server to connect
177 * to us. This function will sit and wait here until the server has
181 static CURLcode
AllowServerConnect(struct connectdata
*conn
)
184 struct SessionHandle
*data
= conn
->data
;
185 curl_socket_t sock
= conn
->sock
[SECONDARYSOCKET
];
186 struct timeval now
= Curl_tvnow();
187 long timespent
= Curl_tvdiff(Curl_tvnow(), now
)/1000;
188 long timeout
= data
->set
.connecttimeout
?data
->set
.connecttimeout
:
189 (data
->set
.timeout
?data
->set
.timeout
: 0);
192 timeout
-= timespent
;
194 failf(data
, "Timed out before server could connect to us");
195 return CURLE_OPERATION_TIMEDOUT
;
199 /* We allow the server 60 seconds to connect to us, or a custom timeout.
200 Note the typecast here. */
201 timeout_ms
= (timeout
?(int)timeout
:60) * 1000;
203 switch (Curl_select(sock
, CURL_SOCKET_BAD
, timeout_ms
)) {
206 failf(data
, "Error while waiting for server connect");
207 return CURLE_FTP_PORT_FAILED
;
208 case 0: /* timeout */
210 failf(data
, "Timeout while waiting for server connect");
211 return CURLE_FTP_PORT_FAILED
;
213 /* we have received data here */
215 curl_socket_t s
= CURL_SOCKET_BAD
;
217 struct Curl_sockaddr_storage add
;
219 struct sockaddr_in add
;
221 socklen_t size
= (socklen_t
) sizeof(add
);
223 if(0 == getsockname(sock
, (struct sockaddr
*) &add
, &size
)) {
226 s
=accept(sock
, (struct sockaddr
*) &add
, &size
);
228 sclose(sock
); /* close the first socket */
230 if (CURL_SOCKET_BAD
== s
) {
232 failf(data
, "Error accept()ing server connect");
233 return CURLE_FTP_PORT_FAILED
;
235 infof(data
, "Connection accepted from server\n");
237 conn
->sock
[SECONDARYSOCKET
] = s
;
238 Curl_nonblock(s
, TRUE
); /* enable non-blocking */
246 /* initialize stuff to prepare for reading a fresh new response */
247 static void ftp_respinit(struct connectdata
*conn
)
249 struct ftp_conn
*ftpc
= &conn
->proto
.ftpc
;
250 ftpc
->nread_resp
= 0;
251 ftpc
->linestart_resp
= conn
->data
->state
.buffer
;
254 /* macro to check for the last line in an FTP server response */
255 #define lastline(line) (ISDIGIT(line[0]) && ISDIGIT(line[1]) && \
256 ISDIGIT(line[2]) && (' ' == line[3]))
258 static CURLcode
ftp_readresp(curl_socket_t sockfd
,
259 struct connectdata
*conn
,
260 int *ftpcode
, /* return the ftp-code if done */
261 size_t *size
) /* size of the response */
263 int perline
; /* count bytes per line */
267 struct SessionHandle
*data
= conn
->data
;
268 char *buf
= data
->state
.buffer
;
269 CURLcode result
= CURLE_OK
;
270 struct ftp_conn
*ftpc
= &conn
->proto
.ftpc
;
274 *ftpcode
= 0; /* 0 for errors or not done */
276 ptr
=buf
+ ftpc
->nread_resp
;
278 perline
= (int)(ptr
-ftpc
->linestart_resp
); /* number of bytes in the current
282 while((ftpc
->nread_resp
<BUFSIZE
) && (keepon
&& !result
)) {
285 /* we had data in the "cache", copy that instead of doing an actual
288 * ftp->cache_size is cast to int here. This should be safe,
289 * because it would have been populated with something of size
290 * int to begin with, even though its datatype may be larger
293 memcpy(ptr
, ftpc
->cache
, (int)ftpc
->cache_size
);
294 gotbytes
= (int)ftpc
->cache_size
;
295 free(ftpc
->cache
); /* free the cache */
296 ftpc
->cache
= NULL
; /* clear the pointer */
297 ftpc
->cache_size
= 0; /* zero the size just in case */
300 int res
= Curl_read(conn
, sockfd
, ptr
, BUFSIZE
-ftpc
->nread_resp
,
304 return CURLE_OK
; /* return */
306 #ifdef CURL_DOES_CONVERSIONS
307 if((res
== CURLE_OK
) && (gotbytes
> 0)) {
308 /* convert from the network encoding */
309 result
= res
= Curl_convert_from_network(data
, ptr
, gotbytes
);
310 /* Curl_convert_from_network calls failf if unsuccessful */
312 #endif /* CURL_DOES_CONVERSIONS */
320 else if(gotbytes
<= 0) {
322 result
= CURLE_RECV_ERROR
;
323 failf(data
, "FTP response reading failed");
326 /* we got a whole chunk of data, which can be anything from one
327 * byte to a set of lines and possible just a piece of the last
331 conn
->headerbytecount
+= gotbytes
;
333 ftpc
->nread_resp
+= gotbytes
;
334 for(i
= 0; i
< gotbytes
; ptr
++, i
++) {
337 /* a newline is CRLF in ftp-talk, so the CR is ignored as
338 the line isn't really terminated until the LF comes */
340 /* output debug output if that is requested */
341 if(data
->set
.verbose
)
342 Curl_debug(data
, CURLINFO_HEADER_IN
,
343 ftpc
->linestart_resp
, (size_t)perline
, conn
);
346 * We pass all response-lines to the callback function registered
347 * for "headers". The response lines can be seen as a kind of
350 result
= Curl_client_write(conn
, CLIENTWRITE_HEADER
,
351 ftpc
->linestart_resp
, perline
);
355 if(perline
>3 && lastline(ftpc
->linestart_resp
)) {
356 /* This is the end of the last line, copy the last line to the
357 start of the buffer and zero terminate, for old times sake (and
361 for(meow
=ftpc
->linestart_resp
, n
=0; meow
<ptr
; meow
++, n
++)
363 *meow
=0; /* zero terminate */
365 ftpc
->linestart_resp
= ptr
+1; /* advance pointer */
366 i
++; /* skip this before getting out */
368 *size
= ftpc
->nread_resp
; /* size of the response */
369 ftpc
->nread_resp
= 0; /* restart */
372 perline
=0; /* line starts over here */
373 ftpc
->linestart_resp
= ptr
+1;
376 if(!keepon
&& (i
!= gotbytes
)) {
377 /* We found the end of the response lines, but we didn't parse the
378 full chunk of data we have read from the server. We therefore need
379 to store the rest of the data to be checked on the next invoke as
380 it may actually contain another end of response already! */
381 ftpc
->cache_size
= gotbytes
- i
;
382 ftpc
->cache
= (char *)malloc((int)ftpc
->cache_size
);
384 memcpy(ftpc
->cache
, ftpc
->linestart_resp
, (int)ftpc
->cache_size
);
386 return CURLE_OUT_OF_MEMORY
; /**BANG**/
388 } /* there was data */
390 } /* while there's buffer left and loop is requested */
396 /* handle the security-oriented responses 6xx ***/
397 /* FIXME: some errorchecking perhaps... ***/
400 Curl_sec_read_msg(conn
, buf
, prot_safe
);
403 Curl_sec_read_msg(conn
, buf
, prot_private
);
406 Curl_sec_read_msg(conn
, buf
, prot_confidential
);
409 /* normal ftp stuff we pass through! */
414 *ftpcode
=code
; /* return the initial number like this */
417 /* store the latest code for later retrieval */
418 conn
->data
->info
.httpcode
=code
;
423 /* --- parse FTP server responses --- */
426 * Curl_GetFTPResponse() is supposed to be invoked after each command sent to
427 * a remote FTP server. This function will wait and read all lines of the
428 * response and extract the relevant return code for the invoking function.
431 CURLcode
Curl_GetFTPResponse(ssize_t
*nreadp
, /* return number of bytes read */
432 struct connectdata
*conn
,
433 int *ftpcode
) /* return the ftp-code */
436 * We cannot read just one byte per read() and then go back to select() as
437 * the OpenSSL read() doesn't grok that properly.
439 * Alas, read as much as possible, split up into lines, use the ending
440 * line in a response or continue reading. */
442 curl_socket_t sockfd
= conn
->sock
[FIRSTSOCKET
];
443 int perline
; /* count bytes per line */
447 long timeout
; /* timeout in seconds */
449 struct SessionHandle
*data
= conn
->data
;
451 int code
=0; /* default ftp "error code" to return */
452 char *buf
= data
->state
.buffer
;
453 CURLcode result
= CURLE_OK
;
454 struct ftp_conn
*ftpc
= &conn
->proto
.ftpc
;
455 struct timeval now
= Curl_tvnow();
458 *ftpcode
= 0; /* 0 for errors */
467 while((*nreadp
<BUFSIZE
) && (keepon
&& !result
)) {
468 /* check and reset timeout value every lap */
469 if(data
->set
.ftp_response_timeout
)
470 /* if CURLOPT_FTP_RESPONSE_TIMEOUT is set, use that to determine
471 remaining time. Also, use "now" as opposed to "conn->now"
472 because ftp_response_timeout is only supposed to govern
473 the response for any given ftp response, not for the time
474 from connect to the given ftp response. */
475 timeout
= data
->set
.ftp_response_timeout
- /* timeout time */
476 Curl_tvdiff(Curl_tvnow(), now
)/1000; /* spent time */
477 else if(data
->set
.timeout
)
478 /* if timeout is requested, find out how much remaining time we have */
479 timeout
= data
->set
.timeout
- /* timeout time */
480 Curl_tvdiff(Curl_tvnow(), conn
->now
)/1000; /* spent time */
482 /* Even without a requested timeout, we only wait response_time
483 seconds for the full response to arrive before we bail out */
484 timeout
= ftpc
->response_time
-
485 Curl_tvdiff(Curl_tvnow(), now
)/1000; /* spent time */
488 failf(data
, "FTP response timeout");
489 return CURLE_OPERATION_TIMEDOUT
; /* already too little time */
493 interval_ms
= 1 * 1000; /* use 1 second timeout intervals */
495 switch (Curl_select(sockfd
, CURL_SOCKET_BAD
, interval_ms
)) {
496 case -1: /* select() error, stop reading */
497 result
= CURLE_RECV_ERROR
;
498 failf(data
, "FTP response aborted due to select() error: %d",
501 case 0: /* timeout */
502 if(Curl_pgrsUpdate(conn
))
503 return CURLE_ABORTED_BY_CALLBACK
;
504 continue; /* just continue in our loop for the timeout duration */
510 if(CURLE_OK
== result
) {
512 * This code previously didn't use the kerberos sec_read() code
513 * to read, but when we use Curl_read() it may do so. Do confirm
514 * that this is still ok and then remove this comment!
517 /* we had data in the "cache", copy that instead of doing an actual
520 * Dave Meyer, December 2003:
521 * ftp->cache_size is cast to int here. This should be safe,
522 * because it would have been populated with something of size
523 * int to begin with, even though its datatype may be larger
526 memcpy(ptr
, ftpc
->cache
, (int)ftpc
->cache_size
);
527 gotbytes
= (int)ftpc
->cache_size
;
528 free(ftpc
->cache
); /* free the cache */
529 ftpc
->cache
= NULL
; /* clear the pointer */
530 ftpc
->cache_size
= 0; /* zero the size just in case */
533 int res
= Curl_read(conn
, sockfd
, ptr
, BUFSIZE
-*nreadp
, &gotbytes
);
536 continue; /* go looping again */
538 #ifdef CURL_DOES_CONVERSIONS
539 if((res
== CURLE_OK
) && (gotbytes
> 0)) {
540 /* convert from the network encoding */
541 result
= res
= Curl_convert_from_network(data
, ptr
, gotbytes
);
542 /* Curl_convert_from_network calls failf if unsuccessful */
544 #endif /* CURL_DOES_CONVERSIONS */
552 else if(gotbytes
<= 0) {
554 result
= CURLE_RECV_ERROR
;
555 failf(data
, "FTP response reading failed");
558 /* we got a whole chunk of data, which can be anything from one
559 * byte to a set of lines and possible just a piece of the last
563 conn
->headerbytecount
+= gotbytes
;
566 for(i
= 0; i
< gotbytes
; ptr
++, i
++) {
569 /* a newline is CRLF in ftp-talk, so the CR is ignored as
570 the line isn't really terminated until the LF comes */
572 /* output debug output if that is requested */
573 if(data
->set
.verbose
)
574 Curl_debug(data
, CURLINFO_HEADER_IN
,
575 line_start
, (size_t)perline
, conn
);
578 * We pass all response-lines to the callback function registered
579 * for "headers". The response lines can be seen as a kind of
582 result
= Curl_client_write(conn
, CLIENTWRITE_HEADER
,
583 line_start
, perline
);
587 if(perline
>3 && lastline(line_start
)) {
588 /* This is the end of the last line, copy the last
589 * line to the start of the buffer and zero terminate,
590 * for old times sake (and krb4)! */
593 for(meow
=line_start
, n
=0; meow
<ptr
; meow
++, n
++)
595 *meow
=0; /* zero terminate */
597 line_start
= ptr
+1; /* advance pointer */
598 i
++; /* skip this before getting out */
601 perline
=0; /* line starts over here */
605 if(!keepon
&& (i
!= gotbytes
)) {
606 /* We found the end of the response lines, but we didn't parse the
607 full chunk of data we have read from the server. We therefore
608 need to store the rest of the data to be checked on the next
609 invoke as it may actually contain another end of response
610 already! Cleverly figured out by Eric Lavigne in December
612 ftpc
->cache_size
= gotbytes
- i
;
613 ftpc
->cache
= (char *)malloc((int)ftpc
->cache_size
);
615 memcpy(ftpc
->cache
, line_start
, (int)ftpc
->cache_size
);
617 return CURLE_OUT_OF_MEMORY
; /**BANG**/
619 } /* there was data */
621 } /* while there's buffer left and loop is requested */
627 /* handle the security-oriented responses 6xx ***/
628 /* FIXME: some errorchecking perhaps... ***/
631 Curl_sec_read_msg(conn
, buf
, prot_safe
);
634 Curl_sec_read_msg(conn
, buf
, prot_private
);
637 Curl_sec_read_msg(conn
, buf
, prot_confidential
);
640 /* normal ftp stuff we pass through! */
646 *ftpcode
=code
; /* return the initial number like this */
648 /* store the latest code for later retrieval */
649 conn
->data
->info
.httpcode
=code
;
654 /* This is the ONLY way to change FTP state! */
655 static void state(struct connectdata
*conn
,
659 /* for debug purposes */
660 const char *names
[]={
695 struct ftp_conn
*ftpc
= &conn
->proto
.ftpc
;
697 if(ftpc
->state
!= state
)
698 infof(conn
->data
, "FTP %p state change from %s to %s\n",
699 ftpc
, names
[ftpc
->state
], names
[state
]);
704 static CURLcode
ftp_state_user(struct connectdata
*conn
)
707 struct FTP
*ftp
= conn
->data
->reqdata
.proto
.ftp
;
709 NBFTPSENDF(conn
, "USER %s", ftp
->user
?ftp
->user
:"");
711 state(conn
, FTP_USER
);
712 conn
->data
->state
.ftp_trying_alternative
= FALSE
;
717 static CURLcode
ftp_state_pwd(struct connectdata
*conn
)
721 /* send PWD to discover our entry point */
722 NBFTPSENDF(conn
, "PWD", NULL
);
723 state(conn
, FTP_PWD
);
728 /* For the FTP "protocol connect" and "doing" phases only */
729 int Curl_ftp_getsock(struct connectdata
*conn
,
730 curl_socket_t
*socks
,
733 struct ftp_conn
*ftpc
= &conn
->proto
.ftpc
;
736 return GETSOCK_BLANK
;
738 socks
[0] = conn
->sock
[FIRSTSOCKET
];
742 return GETSOCK_WRITESOCK(0);
746 return GETSOCK_READSOCK(0);
749 /* This is called after the FTP_QUOTE state is passed.
751 ftp_state_cwd() sends the range of PWD commands to the server to change to
752 the correct directory. It may also need to send MKD commands to create
753 missing ones, if that option is enabled.
755 static CURLcode
ftp_state_cwd(struct connectdata
*conn
)
757 CURLcode result
= CURLE_OK
;
758 struct ftp_conn
*ftpc
= &conn
->proto
.ftpc
;
761 /* already done and fine */
762 result
= ftp_state_post_cwd(conn
);
765 if (conn
->bits
.reuse
&& ftpc
->entrypath
) {
766 /* This is a re-used connection. Since we change directory to where the
767 transfer is taking place, we must first get back to the original dir
768 where we ended up after login: */
769 ftpc
->count1
= 0; /* we count this as the first path, then we add one
770 for all upcoming ones in the ftp->dirs[] array */
771 NBFTPSENDF(conn
, "CWD %s", ftpc
->entrypath
);
772 state(conn
, FTP_CWD
);
777 /* issue the first CWD, the rest is sent when the CWD responses are
779 NBFTPSENDF(conn
, "CWD %s", ftpc
->dirs
[ftpc
->count1
-1]);
780 state(conn
, FTP_CWD
);
783 /* No CWD necessary */
784 result
= ftp_state_post_cwd(conn
);
797 static CURLcode
ftp_state_use_port(struct connectdata
*conn
,
798 ftpport fcmd
) /* start with this */
801 CURLcode result
= CURLE_OK
;
802 struct ftp_conn
*ftpc
= &conn
->proto
.ftpc
;
803 struct SessionHandle
*data
=conn
->data
;
804 curl_socket_t portsock
= CURL_SOCKET_BAD
;
805 char myhost
[256] = "";
808 /******************************************************************
809 * IPv6-specific section
811 struct Curl_sockaddr_storage ss
;
812 struct addrinfo
*res
, *ai
;
814 char hbuf
[NI_MAXHOST
];
815 struct sockaddr
*sa
=(struct sockaddr
*)&ss
;
817 const char *mode
[] = { "EPRT", "PORT", NULL
};
821 struct Curl_dns_entry
*h
=NULL
;
822 unsigned short port
= 0;
824 /* Step 1, figure out what address that is requested */
826 if(data
->set
.ftpport
&& (strlen(data
->set
.ftpport
) > 1)) {
827 /* attempt to get the address of the given interface name */
828 if(!Curl_if2ip(data
->set
.ftpport
, hbuf
, sizeof(hbuf
)))
829 /* not an interface, use the given string as host name instead */
830 host
= data
->set
.ftpport
;
832 host
= hbuf
; /* use the hbuf for host name */
833 } /* data->set.ftpport */
836 /* not an interface and not a host name, get default by extracting
837 the IP from the control connection */
840 if (getsockname(conn
->sock
[FIRSTSOCKET
], (struct sockaddr
*)&ss
, &sslen
)) {
841 failf(data
, "getsockname() failed: %s",
842 Curl_strerror(conn
, Curl_sockerrno()) );
843 return CURLE_FTP_PORT_FAILED
;
846 if (sslen
> (socklen_t
)sizeof(ss
))
848 rc
= getnameinfo((struct sockaddr
*)&ss
, sslen
, hbuf
, sizeof(hbuf
), NULL
,
851 failf(data
, "getnameinfo() returned %d \n", rc
);
852 return CURLE_FTP_PORT_FAILED
;
854 host
= hbuf
; /* use this host name */
857 rc
= Curl_resolv(conn
, host
, 0, &h
);
858 if(rc
== CURLRESOLV_PENDING
)
859 rc
= Curl_wait_for_resolv(conn
, &h
);
862 /* when we return from this function, we can forget about this entry
863 to we can unlock it now already */
864 Curl_resolv_unlock(data
, h
);
867 res
= NULL
; /* failure! */
870 /* step 2, create a socket for the requested address */
872 portsock
= CURL_SOCKET_BAD
;
874 for (ai
= res
; ai
; ai
= ai
->ai_next
) {
876 * Workaround for AIX5 getaddrinfo() problem (it doesn't set ai_socktype):
878 if (ai
->ai_socktype
== 0)
879 ai
->ai_socktype
= conn
->socktype
;
881 portsock
= socket(ai
->ai_family
, ai
->ai_socktype
, ai
->ai_protocol
);
882 if (portsock
== CURL_SOCKET_BAD
) {
883 error
= Curl_sockerrno();
889 failf(data
, "socket failure: %s", Curl_strerror(conn
, error
));
890 return CURLE_FTP_PORT_FAILED
;
893 /* step 3, bind to a suitable local address */
895 /* Try binding the given address. */
896 if (bind(portsock
, ai
->ai_addr
, ai
->ai_addrlen
)) {
898 /* It failed. Bind the address used for the control connection instead */
900 if (getsockname(conn
->sock
[FIRSTSOCKET
],
901 (struct sockaddr
*)sa
, &sslen
)) {
902 failf(data
, "getsockname() failed: %s",
903 Curl_strerror(conn
, Curl_sockerrno()) );
905 return CURLE_FTP_PORT_FAILED
;
908 /* set port number to zero to make bind() pick "any" */
909 if(((struct sockaddr
*)sa
)->sa_family
== AF_INET
)
910 ((struct sockaddr_in
*)sa
)->sin_port
=0;
912 ((struct sockaddr_in6
*)sa
)->sin6_port
=0;
914 if (sslen
> (socklen_t
)sizeof(ss
))
917 if(bind(portsock
, (struct sockaddr
*)sa
, sslen
)) {
918 failf(data
, "bind failed: %s", Curl_strerror(conn
, Curl_sockerrno()));
920 return CURLE_FTP_PORT_FAILED
;
924 /* get the name again after the bind() so that we can extract the
925 port number it uses now */
927 if(getsockname(portsock
, (struct sockaddr
*)sa
, &sslen
)) {
928 failf(data
, "getsockname() failed: %s",
929 Curl_strerror(conn
, Curl_sockerrno()) );
931 return CURLE_FTP_PORT_FAILED
;
934 /* step 4, listen on the socket */
936 if (listen(portsock
, 1)) {
937 failf(data
, "socket failure: %s", Curl_strerror(conn
, Curl_sockerrno()));
939 return CURLE_FTP_PORT_FAILED
;
942 /* step 5, send the proper FTP command */
944 /* get a plain printable version of the numerical address to work with
946 Curl_printable_address(ai
, myhost
, sizeof(myhost
));
949 if(!conn
->bits
.ftp_use_eprt
&& conn
->bits
.ipv6
)
950 /* EPRT is disabled but we are connected to a IPv6 host, so we ignore the
951 request and enable EPRT again! */
952 conn
->bits
.ftp_use_eprt
= TRUE
;
955 for (; fcmd
!= DONE
; fcmd
++) {
957 if(!conn
->bits
.ftp_use_eprt
&& (EPRT
== fcmd
))
958 /* if disabled, goto next */
961 switch (sa
->sa_family
) {
963 port
= ntohs(((struct sockaddr_in
*)sa
)->sin_port
);
966 port
= ntohs(((struct sockaddr_in6
*)sa
)->sin6_port
);
974 * Two fine examples from RFC2428;
976 * EPRT |1|132.235.1.2|6275|
978 * EPRT |2|1080::8:800:200C:417A|5282|
981 result
= Curl_nbftpsendf(conn
, "%s |%d|%s|%d|", mode
[fcmd
],
982 ai
->ai_family
== AF_INET
?1:2,
988 else if (PORT
== fcmd
) {
989 char *source
= myhost
;
992 if ((PORT
== fcmd
) && ai
->ai_family
!= AF_INET
)
995 /* translate x.x.x.x to x,x,x,x */
996 while(source
&& *source
) {
1005 snprintf(dest
, 20, ",%d,%d", port
>>8, port
&0xff);
1007 result
= Curl_nbftpsendf(conn
, "%s %s", mode
[fcmd
], tmp
);
1014 /* store which command was sent */
1015 ftpc
->count1
= fcmd
;
1017 /* we set the secondary socket variable to this for now, it is only so that
1018 the cleanup function will close it in case we fail before the true
1019 secondary stuff is made */
1020 if(CURL_SOCKET_BAD
!= conn
->sock
[SECONDARYSOCKET
])
1021 sclose(conn
->sock
[SECONDARYSOCKET
]);
1022 conn
->sock
[SECONDARYSOCKET
] = portsock
;
1025 /******************************************************************
1026 * IPv4-specific section
1028 struct sockaddr_in sa
;
1029 unsigned short porttouse
;
1030 bool sa_filled_in
= FALSE
;
1031 Curl_addrinfo
*addr
= NULL
;
1032 unsigned short ip
[4];
1033 bool freeaddr
= TRUE
;
1034 socklen_t sslen
= sizeof(sa
);
1036 (void)fcmd
; /* not used in the IPv4 code */
1037 if(data
->set
.ftpport
) {
1040 /* First check if the given name is an IP address */
1041 in
=inet_addr(data
->set
.ftpport
);
1043 if(in
!= CURL_INADDR_NONE
)
1044 /* this is an IPv4 address */
1045 addr
= Curl_ip2addr(in
, data
->set
.ftpport
, 0);
1047 if(Curl_if2ip(data
->set
.ftpport
, myhost
, sizeof(myhost
))) {
1048 /* The interface to IP conversion provided a dotted address */
1049 in
=inet_addr(myhost
);
1050 addr
= Curl_ip2addr(in
, myhost
, 0);
1052 else if(strlen(data
->set
.ftpport
)> 1) {
1053 /* might be a host name! */
1054 struct Curl_dns_entry
*h
=NULL
;
1055 int rc
= Curl_resolv(conn
, data
->set
.ftpport
, 0, &h
);
1056 if(rc
== CURLRESOLV_PENDING
)
1058 rc
= Curl_wait_for_resolv(conn
, &h
);
1061 /* when we return from this function, we can forget about this entry
1062 so we can unlock it now already */
1063 Curl_resolv_unlock(data
, h
);
1065 freeaddr
= FALSE
; /* make sure we don't free 'addr' in this function
1066 since it points to a DNS cache entry! */
1069 infof(data
, "Failed to resolve host name %s\n", data
->set
.ftpport
);
1072 } /* CURL_INADDR_NONE */
1073 } /* data->set.ftpport */
1076 /* pick a suitable default here */
1078 if (getsockname(conn
->sock
[FIRSTSOCKET
],
1079 (struct sockaddr
*)&sa
, &sslen
)) {
1080 failf(data
, "getsockname() failed: %s",
1081 Curl_strerror(conn
, Curl_sockerrno()) );
1082 return CURLE_FTP_PORT_FAILED
;
1084 if (sslen
> (socklen_t
)sizeof(sa
))
1087 sa_filled_in
= TRUE
; /* the sa struct is filled in */
1090 if (addr
|| sa_filled_in
) {
1091 portsock
= socket(AF_INET
, SOCK_STREAM
, 0);
1092 if(CURL_SOCKET_BAD
!= portsock
) {
1094 /* we set the secondary socket variable to this for now, it
1095 is only so that the cleanup function will close it in case
1096 we fail before the true secondary stuff is made */
1097 if(CURL_SOCKET_BAD
!= conn
->sock
[SECONDARYSOCKET
])
1098 sclose(conn
->sock
[SECONDARYSOCKET
]);
1099 conn
->sock
[SECONDARYSOCKET
] = portsock
;
1102 memcpy(&sa
, addr
->ai_addr
, sslen
);
1103 sa
.sin_addr
.s_addr
= INADDR_ANY
;
1109 if(bind(portsock
, (struct sockaddr
*)&sa
, sslen
) == 0) {
1110 /* we succeeded to bind */
1111 struct sockaddr_in add
;
1112 socklen_t socksize
= sizeof(add
);
1114 if(getsockname(portsock
, (struct sockaddr
*) &add
,
1116 failf(data
, "getsockname() failed: %s",
1117 Curl_strerror(conn
, Curl_sockerrno()) );
1118 return CURLE_FTP_PORT_FAILED
;
1120 porttouse
= ntohs(add
.sin_port
);
1122 if ( listen(portsock
, 1) < 0 ) {
1123 failf(data
, "listen(2) failed on socket");
1124 return CURLE_FTP_PORT_FAILED
;
1128 failf(data
, "bind(2) failed on socket");
1129 return CURLE_FTP_PORT_FAILED
;
1133 failf(data
, "socket(2) failed (%s)");
1134 return CURLE_FTP_PORT_FAILED
;
1138 failf(data
, "couldn't find IP address to use");
1139 return CURLE_FTP_PORT_FAILED
;
1143 Curl_inet_ntop(AF_INET
, &((struct sockaddr_in
*)&sa
)->sin_addr
,
1144 myhost
, sizeof(myhost
));
1146 Curl_printable_address(addr
, myhost
, sizeof(myhost
));
1148 if(4 == sscanf(myhost
, "%hu.%hu.%hu.%hu",
1149 &ip
[0], &ip
[1], &ip
[2], &ip
[3])) {
1151 infof(data
, "Telling server to connect to %d.%d.%d.%d:%d\n",
1152 ip
[0], ip
[1], ip
[2], ip
[3], porttouse
);
1154 result
=Curl_nbftpsendf(conn
, "PORT %d,%d,%d,%d,%d,%d",
1155 ip
[0], ip
[1], ip
[2], ip
[3],
1156 porttouse
>> 8, porttouse
& 255);
1161 return CURLE_FTP_PORT_FAILED
;
1164 Curl_freeaddrinfo(addr
);
1166 ftpc
->count1
= PORT
;
1168 #endif /* end of ipv4-specific code */
1170 /* this tcpconnect assignment below is a hackish work-around to make the
1171 multi interface with active FTP work - as it will not wait for a
1172 (passive) connect in Curl_is_connected().
1174 The *proper* fix is to make sure that the active connection from the
1175 server is done in a non-blocking way. Currently, it is still BLOCKING.
1177 conn
->bits
.tcpconnect
= TRUE
;
1179 state(conn
, FTP_PORT
);
1183 static CURLcode
ftp_state_use_pasv(struct connectdata
*conn
)
1185 struct ftp_conn
*ftpc
= &conn
->proto
.ftpc
;
1186 CURLcode result
= CURLE_OK
;
1188 Here's the excecutive summary on what to do:
1190 PASV is RFC959, expect:
1191 227 Entering Passive Mode (a1,a2,a3,a4,p1,p2)
1193 LPSV is RFC1639, expect:
1194 228 Entering Long Passive Mode (4,4,a1,a2,a3,a4,2,p1,p2)
1196 EPSV is RFC2428, expect:
1197 229 Entering Extended Passive Mode (|||port|)
1201 const char *mode
[] = { "EPSV", "PASV", NULL
};
1205 if(!conn
->bits
.ftp_use_epsv
&& conn
->bits
.ipv6
)
1206 /* EPSV is disabled but we are connected to a IPv6 host, so we ignore the
1207 request and enable EPSV again! */
1208 conn
->bits
.ftp_use_epsv
= TRUE
;
1211 modeoff
= conn
->bits
.ftp_use_epsv
?0:1;
1213 result
= Curl_nbftpsendf(conn
, "%s", mode
[modeoff
]);
1217 ftpc
->count1
= modeoff
;
1218 state(conn
, FTP_PASV
);
1219 infof(conn
->data
, "Connect data stream passively\n");
1224 /* REST is the last command in the chain of commands when a "head"-like
1225 request is made. Thus, if an actual transfer is to be made this is where
1226 we take off for real. */
1227 static CURLcode
ftp_state_post_rest(struct connectdata
*conn
)
1229 CURLcode result
= CURLE_OK
;
1230 struct FTP
*ftp
= conn
->data
->reqdata
.proto
.ftp
;
1231 struct SessionHandle
*data
= conn
->data
;
1233 if(ftp
->no_transfer
|| conn
->bits
.no_body
) {
1234 /* doesn't transfer any data */
1235 ftp
->no_transfer
= TRUE
;
1237 /* still possibly do PRE QUOTE jobs */
1238 state(conn
, FTP_RETR_PREQUOTE
);
1239 result
= ftp_state_quote(conn
, TRUE
, FTP_RETR_PREQUOTE
);
1241 else if(data
->set
.ftp_use_port
) {
1242 /* We have chosen to use the PORT (or similar) command */
1243 result
= ftp_state_use_port(conn
, EPRT
);
1246 /* We have chosen (this is default) to use the PASV (or similar) command */
1247 result
= ftp_state_use_pasv(conn
);
1252 static CURLcode
ftp_state_post_size(struct connectdata
*conn
)
1254 CURLcode result
= CURLE_OK
;
1255 struct FTP
*ftp
= conn
->data
->reqdata
.proto
.ftp
;
1257 if(ftp
->no_transfer
) {
1258 /* if a "head"-like request is being made */
1260 /* Determine if server can respond to REST command and therefore
1261 whether it supports range */
1262 NBFTPSENDF(conn
, "REST %d", 0);
1264 state(conn
, FTP_REST
);
1267 result
= ftp_state_post_rest(conn
);
1272 static CURLcode
ftp_state_post_type(struct connectdata
*conn
)
1274 CURLcode result
= CURLE_OK
;
1275 struct FTP
*ftp
= conn
->data
->reqdata
.proto
.ftp
;
1277 if(ftp
->no_transfer
) {
1278 /* if a "head"-like request is being made */
1280 /* we know ftp->file is a valid pointer to a file name */
1281 NBFTPSENDF(conn
, "SIZE %s", ftp
->file
);
1283 state(conn
, FTP_SIZE
);
1286 result
= ftp_state_post_size(conn
);
1291 static CURLcode
ftp_state_post_listtype(struct connectdata
*conn
)
1293 CURLcode result
= CURLE_OK
;
1294 struct SessionHandle
*data
= conn
->data
;
1296 /* If this output is to be machine-parsed, the NLST command might be better
1297 to use, since the LIST command output is not specified or standard in any
1298 way. It has turned out that the NLST list output is not the same on all
1299 servers either... */
1301 NBFTPSENDF(conn
, "%s",
1302 data
->set
.customrequest
?data
->set
.customrequest
:
1303 (data
->set
.ftp_list_only
?"NLST":"LIST"));
1305 state(conn
, FTP_LIST
);
1310 static CURLcode
ftp_state_post_retrtype(struct connectdata
*conn
)
1312 CURLcode result
= CURLE_OK
;
1314 /* We've sent the TYPE, now we must send the list of prequote strings */
1316 result
= ftp_state_quote(conn
, TRUE
, FTP_RETR_PREQUOTE
);
1321 static CURLcode
ftp_state_post_stortype(struct connectdata
*conn
)
1323 CURLcode result
= CURLE_OK
;
1325 /* We've sent the TYPE, now we must send the list of prequote strings */
1327 result
= ftp_state_quote(conn
, TRUE
, FTP_STOR_PREQUOTE
);
1332 static CURLcode
ftp_state_post_mdtm(struct connectdata
*conn
)
1334 CURLcode result
= CURLE_OK
;
1335 struct FTP
*ftp
= conn
->data
->reqdata
.proto
.ftp
;
1336 struct SessionHandle
*data
= conn
->data
;
1338 /* If we have selected NOBODY and HEADER, it means that we only want file
1339 information. Which in FTP can't be much more than the file size and
1341 if(conn
->bits
.no_body
&& data
->set
.include_header
&& ftp
->file
&&
1342 ftp_need_type(conn
, data
->set
.prefer_ascii
)) {
1343 /* The SIZE command is _not_ RFC 959 specified, and therefor many servers
1344 may not support it! It is however the only way we have to get a file's
1347 ftp
->no_transfer
= TRUE
; /* this means no actual transfer will be made */
1349 /* Some servers return different sizes for different modes, and thus we
1350 must set the proper type before we check the size */
1351 result
= ftp_nb_type(conn
, data
->set
.prefer_ascii
, FTP_TYPE
);
1356 result
= ftp_state_post_type(conn
);
1361 /* This is called after the CWD commands have been done in the beginning of
1363 static CURLcode
ftp_state_post_cwd(struct connectdata
*conn
)
1365 CURLcode result
= CURLE_OK
;
1366 struct FTP
*ftp
= conn
->data
->reqdata
.proto
.ftp
;
1367 struct SessionHandle
*data
= conn
->data
;
1369 /* Requested time of file or time-depended transfer? */
1370 if((data
->set
.get_filetime
|| data
->set
.timecondition
) && ftp
->file
) {
1372 /* we have requested to get the modified-time of the file, this is a white
1373 spot as the MDTM is not mentioned in RFC959 */
1374 NBFTPSENDF(conn
, "MDTM %s", ftp
->file
);
1376 state(conn
, FTP_MDTM
);
1379 result
= ftp_state_post_mdtm(conn
);
1385 /* This is called after the TYPE and possible quote commands have been sent */
1386 static CURLcode
ftp_state_ul_setup(struct connectdata
*conn
,
1389 CURLcode result
= CURLE_OK
;
1390 struct FTP
*ftp
= conn
->data
->reqdata
.proto
.ftp
;
1391 struct SessionHandle
*data
= conn
->data
;
1392 curl_off_t passed
=0;
1394 if((data
->reqdata
.resume_from
&& !sizechecked
) ||
1395 ((data
->reqdata
.resume_from
> 0) && sizechecked
)) {
1396 /* we're about to continue the uploading of a file */
1397 /* 1. get already existing file's size. We use the SIZE command for this
1398 which may not exist in the server! The SIZE command is not in
1401 /* 2. This used to set REST. But since we can do append, we
1402 don't another ftp command. We just skip the source file
1403 offset and then we APPEND the rest on the file instead */
1405 /* 3. pass file-size number of bytes in the source file */
1406 /* 4. lower the infilesize counter */
1407 /* => transfer as usual */
1409 if(data
->reqdata
.resume_from
< 0 ) {
1410 /* Got no given size to start from, figure it out */
1411 NBFTPSENDF(conn
, "SIZE %s", ftp
->file
);
1412 state(conn
, FTP_STOR_SIZE
);
1417 data
->set
.ftp_append
= TRUE
;
1419 /* Let's read off the proper amount of bytes from the input. If we knew it
1420 was a proper file we could've just fseek()ed but we only have a stream
1423 /* TODO: allow the ioctlfunction to provide a fast forward function that
1424 can be used here and use this method only as a fallback! */
1426 curl_off_t readthisamountnow
= (data
->reqdata
.resume_from
- passed
);
1427 curl_off_t actuallyread
;
1429 if(readthisamountnow
> BUFSIZE
)
1430 readthisamountnow
= BUFSIZE
;
1432 actuallyread
= (curl_off_t
)
1433 conn
->fread(data
->state
.buffer
, 1, (size_t)readthisamountnow
,
1436 passed
+= actuallyread
;
1437 if(actuallyread
!= readthisamountnow
) {
1438 failf(data
, "Could only read %" FORMAT_OFF_T
1439 " bytes from the input", passed
);
1440 return CURLE_FTP_COULDNT_USE_REST
;
1442 } while(passed
!= data
->reqdata
.resume_from
);
1444 /* now, decrease the size of the read */
1445 if(data
->set
.infilesize
>0) {
1446 data
->set
.infilesize
-= data
->reqdata
.resume_from
;
1448 if(data
->set
.infilesize
<= 0) {
1449 infof(data
, "File already completely uploaded\n");
1451 /* no data to transfer */
1452 result
=Curl_setup_transfer(conn
, -1, -1, FALSE
, NULL
, -1, NULL
);
1454 /* Set no_transfer so that we won't get any error in
1455 * Curl_ftp_done() because we didn't transfer anything! */
1456 ftp
->no_transfer
= TRUE
;
1458 state(conn
, FTP_STOP
);
1462 /* we've passed, proceed as normal */
1465 NBFTPSENDF(conn
, data
->set
.ftp_append
?"APPE %s":"STOR %s",
1468 state(conn
, FTP_STOR
);
1473 static CURLcode
ftp_state_quote(struct connectdata
*conn
,
1477 CURLcode result
= CURLE_OK
;
1478 struct SessionHandle
*data
= conn
->data
;
1479 struct FTP
*ftp
= data
->reqdata
.proto
.ftp
;
1480 struct ftp_conn
*ftpc
= &conn
->proto
.ftpc
;
1482 struct curl_slist
*item
;
1487 item
= data
->set
.quote
;
1489 case FTP_RETR_PREQUOTE
:
1490 case FTP_STOR_PREQUOTE
:
1491 item
= data
->set
.prequote
;
1494 item
= data
->set
.postquote
;
1506 /* Skip count1 items in the linked list */
1507 while((i
< ftpc
->count1
) && item
) {
1512 NBFTPSENDF(conn
, "%s", item
->data
);
1513 state(conn
, instate
);
1519 /* No more quote to send, continue to ... */
1523 result
= ftp_state_cwd(conn
);
1525 case FTP_RETR_PREQUOTE
:
1526 if (ftp
->no_transfer
)
1527 state(conn
, FTP_STOP
);
1529 NBFTPSENDF(conn
, "SIZE %s", ftp
->file
);
1530 state(conn
, FTP_RETR_SIZE
);
1533 case FTP_STOR_PREQUOTE
:
1534 result
= ftp_state_ul_setup(conn
, FALSE
);
1544 static CURLcode
ftp_state_pasv_resp(struct connectdata
*conn
,
1547 struct ftp_conn
*ftpc
= &conn
->proto
.ftpc
;
1549 struct SessionHandle
*data
=conn
->data
;
1550 Curl_addrinfo
*conninfo
;
1551 struct Curl_dns_entry
*addr
=NULL
;
1553 unsigned short connectport
; /* the local port connect() should use! */
1554 unsigned short newport
=0; /* remote port */
1557 /* newhost must be able to hold a full IP-style address in ASCII, which
1558 in the IPv6 case means 5*8-1 = 39 letters */
1559 #define NEWHOST_BUFSIZE 48
1560 char newhost
[NEWHOST_BUFSIZE
];
1561 char *str
=&data
->state
.buffer
[4]; /* start on the first letter */
1563 if((ftpc
->count1
== 0) &&
1565 /* positive EPSV response */
1566 char *ptr
= strchr(str
, '(');
1571 if(5 == sscanf(ptr
, "%c%c%c%u%c",
1577 const char sep1
= separator
[0];
1580 /* The four separators should be identical, or else this is an oddly
1581 formatted reply and we bail out immediately. */
1582 for(i
=1; i
<4; i
++) {
1583 if(separator
[i
] != sep1
) {
1584 ptr
=NULL
; /* set to NULL to signal error */
1591 if (conn
->bits
.tunnel_proxy
)
1592 /* proxy tunnel -> use other host info because ip_addr_str is the
1593 proxy address not the ftp host */
1594 snprintf(newhost
, sizeof(newhost
), "%s", conn
->host
.name
);
1596 /* use the same IP we are already connected to */
1597 snprintf(newhost
, NEWHOST_BUFSIZE
, "%s", conn
->ip_addr_str
);
1604 failf(data
, "Weirdly formatted EPSV reply");
1605 return CURLE_FTP_WEIRD_PASV_REPLY
;
1608 else if((ftpc
->count1
== 1) &&
1610 /* positive PASV response */
1615 * Scan for a sequence of six comma-separated numbers and use them as
1616 * IP+port indicators.
1618 * Found reply-strings include:
1619 * "227 Entering Passive Mode (127,0,0,1,4,51)"
1620 * "227 Data transfer will passively listen to 127,0,0,1,4,51"
1621 * "227 Entering passive mode. 127,0,0,1,4,51"
1624 if (6 == sscanf(str
, "%d,%d,%d,%d,%d,%d",
1625 &ip
[0], &ip
[1], &ip
[2], &ip
[3],
1626 &port
[0], &port
[1]))
1632 failf(data
, "Couldn't interpret the 227-response");
1633 return CURLE_FTP_WEIRD_227_FORMAT
;
1636 /* we got OK from server */
1637 if(data
->set
.ftp_skip_ip
) {
1638 /* told to ignore the remotely given IP but instead use the one we used
1639 for the control connection */
1640 infof(data
, "Skips %d.%d.%d.%d for data connection, uses %s instead\n",
1641 ip
[0], ip
[1], ip
[2], ip
[3],
1643 if (conn
->bits
.tunnel_proxy
)
1644 /* proxy tunnel -> use other host info because ip_addr_str is the
1645 proxy address not the ftp host */
1646 snprintf(newhost
, sizeof(newhost
), "%s", conn
->host
.name
);
1648 snprintf(newhost
, sizeof(newhost
), "%s", conn
->ip_addr_str
);
1651 snprintf(newhost
, sizeof(newhost
),
1652 "%d.%d.%d.%d", ip
[0], ip
[1], ip
[2], ip
[3]);
1653 newport
= (port
[0]<<8) + port
[1];
1655 else if(ftpc
->count1
== 0) {
1656 /* EPSV failed, move on to PASV */
1658 /* disable it for next transfer */
1659 conn
->bits
.ftp_use_epsv
= FALSE
;
1660 infof(data
, "disabling EPSV usage\n");
1662 NBFTPSENDF(conn
, "PASV", NULL
);
1664 /* remain in the FTP_PASV state */
1668 failf(data
, "Bad PASV/EPSV response: %03d", ftpcode
);
1669 return CURLE_FTP_WEIRD_PASV_REPLY
;
1672 if(data
->set
.proxy
&& *data
->set
.proxy
) {
1674 * This is a tunnel through a http proxy and we need to connect to the
1677 * We don't want to rely on a former host lookup that might've expired
1678 * now, instead we remake the lookup here and now!
1680 rc
= Curl_resolv(conn
, conn
->proxy
.name
, (int)conn
->port
, &addr
);
1681 if(rc
== CURLRESOLV_PENDING
)
1683 rc
= Curl_wait_for_resolv(conn
, &addr
);
1686 (unsigned short)conn
->port
; /* we connect to the proxy's port */
1690 /* normal, direct, ftp connection */
1691 rc
= Curl_resolv(conn
, newhost
, newport
, &addr
);
1692 if(rc
== CURLRESOLV_PENDING
)
1694 rc
= Curl_wait_for_resolv(conn
, &addr
);
1697 failf(data
, "Can't resolve new host %s:%d", newhost
, newport
);
1698 return CURLE_FTP_CANT_GET_HOST
;
1700 connectport
= newport
; /* we connect to the remote port */
1703 result
= Curl_connecthost(conn
,
1705 &conn
->sock
[SECONDARYSOCKET
],
1709 Curl_resolv_unlock(data
, addr
); /* we're done using this address */
1711 if (result
&& ftpc
->count1
== 0 && ftpcode
== 229) {
1712 infof(data
, "got positive EPSV response, but can't connect. "
1713 "Disabling EPSV\n");
1714 /* disable it for next transfer */
1715 conn
->bits
.ftp_use_epsv
= FALSE
;
1716 data
->state
.errorbuf
= FALSE
; /* allow error message to get rewritten */
1717 NBFTPSENDF(conn
, "PASV", NULL
);
1719 /* remain in the FTP_PASV state */
1726 conn
->bits
.tcpconnect
= connected
; /* simply TRUE or FALSE */
1729 * When this is used from the multi interface, this might've returned with
1730 * the 'connected' set to FALSE and thus we are now awaiting a non-blocking
1731 * connect to connect and we should not be "hanging" here waiting.
1734 if(data
->set
.verbose
)
1735 /* this just dumps information about this second connection */
1736 ftp_pasv_verbose(conn
, conninfo
, newhost
, connectport
);
1738 #ifndef CURL_DISABLE_HTTP
1739 if(conn
->bits
.tunnel_proxy
&& conn
->bits
.httpproxy
) {
1740 /* FIX: this MUST wait for a proper connect first if 'connected' is
1744 /* We want "seamless" FTP operations through HTTP proxy tunnel */
1746 /* Curl_proxyCONNECT is based on a pointer to a struct HTTP at the member
1747 * conn->proto.http; we want FTP through HTTP and we have to change the
1748 * member temporarily for connecting to the HTTP proxy. After
1749 * Curl_proxyCONNECT we have to set back the member to the original struct
1752 struct HTTP http_proxy
;
1753 struct FTP
*ftp_save
= data
->reqdata
.proto
.ftp
;
1754 memset(&http_proxy
, 0, sizeof(http_proxy
));
1755 data
->reqdata
.proto
.http
= &http_proxy
;
1757 result
= Curl_proxyCONNECT(conn
, SECONDARYSOCKET
, newhost
, newport
);
1759 data
->reqdata
.proto
.ftp
= ftp_save
;
1761 if(CURLE_OK
!= result
)
1764 #endif /* CURL_DISABLE_HTTP */
1766 state(conn
, FTP_STOP
); /* this phase is completed */
1771 static CURLcode
ftp_state_port_resp(struct connectdata
*conn
,
1774 struct SessionHandle
*data
= conn
->data
;
1775 struct ftp_conn
*ftpc
= &conn
->proto
.ftpc
;
1776 ftpport fcmd
= (ftpport
)ftpc
->count1
;
1777 CURLcode result
= CURLE_OK
;
1779 if(ftpcode
!= 200) {
1780 /* the command failed */
1783 infof(data
, "disabling EPRT usage\n");
1784 conn
->bits
.ftp_use_eprt
= FALSE
;
1789 failf(data
, "Failed to do PORT");
1790 result
= CURLE_FTP_PORT_FAILED
;
1794 result
= ftp_state_use_port(conn
, fcmd
);
1797 infof(data
, "Connect data stream actively\n");
1798 state(conn
, FTP_STOP
); /* end of DO phase */
1804 static CURLcode
ftp_state_mdtm_resp(struct connectdata
*conn
,
1807 CURLcode result
= CURLE_OK
;
1808 struct SessionHandle
*data
=conn
->data
;
1809 struct FTP
*ftp
= data
->reqdata
.proto
.ftp
;
1814 /* we got a time. Format should be: "YYYYMMDDHHMMSS[.sss]" where the
1815 last .sss part is optional and means fractions of a second */
1816 int year
, month
, day
, hour
, minute
, second
;
1817 char *buf
= data
->state
.buffer
;
1818 if(6 == sscanf(buf
+4, "%04d%02d%02d%02d%02d%02d",
1819 &year
, &month
, &day
, &hour
, &minute
, &second
)) {
1820 /* we have a time, reformat it */
1821 time_t secs
=time(NULL
);
1822 /* using the good old yacc/bison yuck */
1823 snprintf(buf
, sizeof(conn
->data
->state
.buffer
),
1824 "%04d%02d%02d %02d:%02d:%02d GMT",
1825 year
, month
, day
, hour
, minute
, second
);
1826 /* now, convert this into a time() value: */
1827 data
->info
.filetime
= (long)curl_getdate(buf
, &secs
);
1830 /* If we asked for a time of the file and we actually got one as well,
1831 we "emulate" a HTTP-style header in our output. */
1833 if(conn
->bits
.no_body
&&
1834 data
->set
.include_header
&&
1836 data
->set
.get_filetime
&&
1837 (data
->info
.filetime
>=0) ) {
1839 time_t clock
= (time_t)data
->info
.filetime
;
1840 #ifdef HAVE_GMTIME_R
1842 tm
= (struct tm
*)gmtime_r(&clock
, &buffer
);
1844 tm
= gmtime(&clock
);
1846 /* format: "Tue, 15 Nov 1994 12:45:26" */
1847 snprintf(buf
, BUFSIZE
-1,
1848 "Last-Modified: %s, %02d %s %4d %02d:%02d:%02d GMT\r\n",
1849 Curl_wkday
[tm
->tm_wday
?tm
->tm_wday
-1:6],
1851 Curl_month
[tm
->tm_mon
],
1856 result
= Curl_client_write(conn
, CLIENTWRITE_BOTH
, buf
, 0);
1859 } /* end of a ridiculous amount of conditionals */
1863 infof(data
, "unsupported MDTM reply format\n");
1865 case 550: /* "No such file or directory" */
1866 failf(data
, "Given file does not exist");
1867 result
= CURLE_FTP_COULDNT_RETR_FILE
;
1871 if(data
->set
.timecondition
) {
1872 if((data
->info
.filetime
> 0) && (data
->set
.timevalue
> 0)) {
1873 switch(data
->set
.timecondition
) {
1874 case CURL_TIMECOND_IFMODSINCE
:
1876 if(data
->info
.filetime
<= data
->set
.timevalue
) {
1877 infof(data
, "The requested document is not new enough\n");
1878 ftp
->no_transfer
= TRUE
; /* mark this to not transfer data */
1879 state(conn
, FTP_STOP
);
1883 case CURL_TIMECOND_IFUNMODSINCE
:
1884 if(data
->info
.filetime
> data
->set
.timevalue
) {
1885 infof(data
, "The requested document is not old enough\n");
1886 ftp
->no_transfer
= TRUE
; /* mark this to not transfer data */
1887 state(conn
, FTP_STOP
);
1894 infof(data
, "Skipping time comparison\n");
1899 result
= ftp_state_post_mdtm(conn
);
1904 static CURLcode
ftp_state_type_resp(struct connectdata
*conn
,
1908 CURLcode result
= CURLE_OK
;
1909 struct SessionHandle
*data
=conn
->data
;
1911 if(ftpcode
/100 != 2) {
1912 /* "sasserftpd" and "(u)r(x)bot ftpd" both responds with 226 after a
1913 successful 'TYPE I'. While that is not as RFC959 says, it is still a
1914 positive response code and we allow that. */
1915 failf(data
, "Couldn't set desired mode");
1916 return CURLE_FTP_COULDNT_SET_BINARY
; /* FIX */
1919 infof(data
, "Got a %03d response code instead of the assumed 200\n",
1922 if(instate
== FTP_TYPE
)
1923 result
= ftp_state_post_type(conn
);
1924 else if(instate
== FTP_LIST_TYPE
)
1925 result
= ftp_state_post_listtype(conn
);
1926 else if(instate
== FTP_RETR_TYPE
)
1927 result
= ftp_state_post_retrtype(conn
);
1928 else if(instate
== FTP_STOR_TYPE
)
1929 result
= ftp_state_post_stortype(conn
);
1934 static CURLcode
ftp_state_post_retr_size(struct connectdata
*conn
,
1935 curl_off_t filesize
)
1937 CURLcode result
= CURLE_OK
;
1938 struct SessionHandle
*data
=conn
->data
;
1939 struct FTP
*ftp
= data
->reqdata
.proto
.ftp
;
1941 if (data
->set
.max_filesize
&& (filesize
> data
->set
.max_filesize
)) {
1942 failf(data
, "Maximum file size exceeded");
1943 return CURLE_FILESIZE_EXCEEDED
;
1945 ftp
->downloadsize
= filesize
;
1947 if(data
->reqdata
.resume_from
) {
1948 /* We always (attempt to) get the size of downloads, so it is done before
1949 this even when not doing resumes. */
1950 if(filesize
== -1) {
1951 infof(data
, "ftp server doesn't support SIZE\n");
1952 /* We couldn't get the size and therefore we can't know if there really
1953 is a part of the file left to get, although the server will just
1954 close the connection when we start the connection so it won't cause
1955 us any harm, just not make us exit as nicely. */
1958 /* We got a file size report, so we check that there actually is a
1959 part of the file left to get, or else we go home. */
1960 if(data
->reqdata
.resume_from
< 0) {
1961 /* We're supposed to download the last abs(from) bytes */
1962 if(filesize
< -data
->reqdata
.resume_from
) {
1963 failf(data
, "Offset (%" FORMAT_OFF_T
1964 ") was beyond file size (%" FORMAT_OFF_T
")",
1965 data
->reqdata
.resume_from
, filesize
);
1966 return CURLE_BAD_DOWNLOAD_RESUME
;
1968 /* convert to size to download */
1969 ftp
->downloadsize
= -data
->reqdata
.resume_from
;
1970 /* download from where? */
1971 data
->reqdata
.resume_from
= filesize
- ftp
->downloadsize
;
1974 if(filesize
< data
->reqdata
.resume_from
) {
1975 failf(data
, "Offset (%" FORMAT_OFF_T
1976 ") was beyond file size (%" FORMAT_OFF_T
")",
1977 data
->reqdata
.resume_from
, filesize
);
1978 return CURLE_BAD_DOWNLOAD_RESUME
;
1980 /* Now store the number of bytes we are expected to download */
1981 ftp
->downloadsize
= filesize
-data
->reqdata
.resume_from
;
1985 if(ftp
->downloadsize
== 0) {
1986 /* no data to transfer */
1987 result
= Curl_setup_transfer(conn
, -1, -1, FALSE
, NULL
, -1, NULL
);
1988 infof(data
, "File already completely downloaded\n");
1990 /* Set no_transfer so that we won't get any error in Curl_ftp_done()
1991 * because we didn't transfer the any file */
1992 ftp
->no_transfer
= TRUE
;
1993 state(conn
, FTP_STOP
);
1997 /* Set resume file transfer offset */
1998 infof(data
, "Instructs server to resume from offset %" FORMAT_OFF_T
1999 "\n", data
->reqdata
.resume_from
);
2001 NBFTPSENDF(conn
, "REST %" FORMAT_OFF_T
, data
->reqdata
.resume_from
);
2003 state(conn
, FTP_RETR_REST
);
2008 NBFTPSENDF(conn
, "RETR %s", ftp
->file
);
2009 state(conn
, FTP_RETR
);
2015 static CURLcode
ftp_state_size_resp(struct connectdata
*conn
,
2019 CURLcode result
= CURLE_OK
;
2020 struct SessionHandle
*data
=conn
->data
;
2021 curl_off_t filesize
;
2022 char *buf
= data
->state
.buffer
;
2024 /* get the size from the ascii string: */
2025 filesize
= (ftpcode
== 213)?curlx_strtoofft(buf
+4, NULL
, 0):-1;
2027 if(instate
== FTP_SIZE
) {
2028 if(-1 != filesize
) {
2029 snprintf(buf
, sizeof(data
->state
.buffer
),
2030 "Content-Length: %" FORMAT_OFF_T
"\r\n", filesize
);
2031 result
= Curl_client_write(conn
, CLIENTWRITE_BOTH
, buf
, 0);
2035 result
= ftp_state_post_size(conn
);
2037 else if(instate
== FTP_RETR_SIZE
)
2038 result
= ftp_state_post_retr_size(conn
, filesize
);
2039 else if(instate
== FTP_STOR_SIZE
) {
2040 data
->reqdata
.resume_from
= filesize
;
2041 result
= ftp_state_ul_setup(conn
, TRUE
);
2047 static CURLcode
ftp_state_rest_resp(struct connectdata
*conn
,
2051 CURLcode result
= CURLE_OK
;
2052 struct FTP
*ftp
= conn
->data
->reqdata
.proto
.ftp
;
2057 if (ftpcode
== 350) {
2058 result
= Curl_client_write(conn
, CLIENTWRITE_BOTH
,
2059 (char *)"Accept-ranges: bytes\r\n", 0);
2064 result
= ftp_state_post_rest(conn
);
2068 if (ftpcode
!= 350) {
2069 failf(conn
->data
, "Couldn't use REST");
2070 result
= CURLE_FTP_COULDNT_USE_REST
;
2073 NBFTPSENDF(conn
, "RETR %s", ftp
->file
);
2074 state(conn
, FTP_RETR
);
2082 static CURLcode
ftp_state_stor_resp(struct connectdata
*conn
,
2085 CURLcode result
= CURLE_OK
;
2086 struct SessionHandle
*data
= conn
->data
;
2087 struct FTP
*ftp
= data
->reqdata
.proto
.ftp
;
2090 failf(data
, "Failed FTP upload: %0d", ftpcode
);
2091 /* oops, we never close the sockets! */
2092 return CURLE_FTP_COULDNT_STOR_FILE
;
2095 if(data
->set
.ftp_use_port
) {
2097 /* PORT means we are now awaiting the server to connect to us. */
2098 result
= AllowServerConnect(conn
);
2103 if(conn
->ssl
[SECONDARYSOCKET
].use
) {
2104 /* since we only have a plaintext TCP connection here, we must now
2106 infof(data
, "Doing the SSL/TLS handshake on the data stream\n");
2108 result
= Curl_ssl_connect(conn
, SECONDARYSOCKET
);
2113 *(ftp
->bytecountp
)=0;
2115 /* When we know we're uploading a specified file, we can get the file
2116 size prior to the actual upload. */
2118 Curl_pgrsSetUploadSize(data
, data
->set
.infilesize
);
2120 result
= Curl_setup_transfer(conn
, -1, -1, FALSE
, NULL
, /* no download */
2121 SECONDARYSOCKET
, ftp
->bytecountp
);
2122 state(conn
, FTP_STOP
);
2127 /* for LIST and RETR responses */
2128 static CURLcode
ftp_state_get_resp(struct connectdata
*conn
,
2132 CURLcode result
= CURLE_OK
;
2133 struct SessionHandle
*data
= conn
->data
;
2134 struct FTP
*ftp
= data
->reqdata
.proto
.ftp
;
2135 char *buf
= data
->state
.buffer
;
2137 if((ftpcode
== 150) || (ftpcode
== 125)) {
2141 150 Opening BINARY mode data connection for /etc/passwd (2241
2142 bytes). (ok, the file is being transfered)
2145 150 Opening ASCII mode data connection for /bin/ls
2148 150 ASCII data connection for /bin/ls (137.167.104.91,37445) (0 bytes).
2151 150 Opening ASCII mode data connection for /linux/fisk/kpanelrc (0.0.0.0,0) (545 bytes).
2154 125 Data connection already open; Transfer starting. */
2156 curl_off_t size
=-1; /* default unknown size */
2160 * It appears that there are FTP-servers that return size 0 for files when
2161 * SIZE is used on the file while being in BINARY mode. To work around
2162 * that (stupid) behavior, we attempt to parse the RETR response even if
2163 * the SIZE returned size zero.
2165 * Debugging help from Salvatore Sorrentino on February 26, 2003.
2168 if((instate
!= FTP_LIST
) &&
2169 !data
->set
.prefer_ascii
&&
2170 (ftp
->downloadsize
< 1)) {
2172 * It seems directory listings either don't show the size or very
2173 * often uses size 0 anyway. ASCII transfers may very well turn out
2174 * that the transfered amount of data is not the same as this line
2175 * tells, why using this number in those cases only confuses us.
2177 * Example D above makes this parsing a little tricky */
2179 bytes
=strstr(buf
, " bytes");
2181 long in
=(long)(bytes
-buf
);
2182 /* this is a hint there is size information in there! ;-) */
2184 /* scan for the left parenthesis and break there */
2187 /* skip only digits */
2188 if(!ISDIGIT(*bytes
)) {
2192 /* one more estep backwards */
2195 /* if we have nothing but digits: */
2197 /* get the number! */
2198 size
= curlx_strtoofft(bytes
, NULL
, 0);
2202 else if(ftp
->downloadsize
> -1)
2203 size
= ftp
->downloadsize
;
2205 if(data
->set
.ftp_use_port
) {
2207 result
= AllowServerConnect(conn
);
2212 if(conn
->ssl
[SECONDARYSOCKET
].use
) {
2213 /* since we only have a plaintext TCP connection here, we must now
2215 infof(data
, "Doing the SSL/TLS handshake on the data stream\n");
2216 result
= Curl_ssl_connect(conn
, SECONDARYSOCKET
);
2221 if(size
> data
->reqdata
.maxdownload
&& data
->reqdata
.maxdownload
> 0)
2222 size
= data
->reqdata
.size
= data
->reqdata
.maxdownload
;
2224 infof(data
, "Maxdownload = %" FORMAT_OFF_T
"\n", data
->reqdata
.maxdownload
);
2226 if(instate
!= FTP_LIST
)
2227 infof(data
, "Getting file with size: %" FORMAT_OFF_T
"\n", size
);
2230 result
=Curl_setup_transfer(conn
, SECONDARYSOCKET
, size
, FALSE
,
2232 -1, NULL
); /* no upload here */
2236 state(conn
, FTP_STOP
);
2239 if((instate
== FTP_LIST
) && (ftpcode
== 450)) {
2240 /* simply no matching files in the dir listing */
2241 ftp
->no_transfer
= TRUE
; /* don't download anything */
2242 state(conn
, FTP_STOP
); /* this phase is over */
2245 failf(data
, "RETR response: %03d", ftpcode
);
2246 return CURLE_FTP_COULDNT_RETR_FILE
;
2253 /* after USER, PASS and ACCT */
2254 static CURLcode
ftp_state_loggedin(struct connectdata
*conn
)
2256 CURLcode result
= CURLE_OK
;
2259 if(conn
->data
->set
.krb4
) {
2260 /* We are logged in, asked to use Kerberos. Set the requested
2263 if(conn
->sec_complete
)
2265 Curl_sec_set_protection_level(conn
);
2267 /* We may need to issue a KAUTH here to have access to the files
2268 * do it if user supplied a password
2270 if(conn
->passwd
&& *conn
->passwd
) {
2272 result
= Curl_krb_kauth(conn
);
2278 if(conn
->ssl
[FIRSTSOCKET
].use
) {
2279 /* PBSZ = PROTECTION BUFFER SIZE.
2281 The 'draft-murray-auth-ftp-ssl' (draft 12, page 7) says:
2283 Specifically, the PROT command MUST be preceded by a PBSZ
2284 command and a PBSZ command MUST be preceded by a successful
2285 security data exchange (the TLS negotiation in this case)
2287 ... (and on page 8):
2289 Thus the PBSZ command must still be issued, but must have a
2290 parameter of '0' to indicate that no buffering is taking place
2291 and the data connection should not be encapsulated.
2293 NBFTPSENDF(conn
, "PBSZ %d", 0);
2294 state(conn
, FTP_PBSZ
);
2297 result
= ftp_state_pwd(conn
);
2302 /* for USER and PASS responses */
2303 static CURLcode
ftp_state_user_resp(struct connectdata
*conn
,
2307 CURLcode result
= CURLE_OK
;
2308 struct SessionHandle
*data
= conn
->data
;
2309 struct FTP
*ftp
= data
->reqdata
.proto
.ftp
;
2310 struct ftp_conn
*ftpc
= &conn
->proto
.ftpc
;
2311 (void)instate
; /* no use for this yet */
2313 if((ftpcode
== 331) && (ftpc
->state
== FTP_USER
)) {
2314 /* 331 Password required for ...
2315 (the server requires to send the user's password too) */
2316 NBFTPSENDF(conn
, "PASS %s", ftp
->passwd
?ftp
->passwd
:"");
2317 state(conn
, FTP_PASS
);
2319 else if(ftpcode
/100 == 2) {
2320 /* 230 User ... logged in.
2321 (the user logged in with or without password) */
2322 result
= ftp_state_loggedin(conn
);
2324 else if(ftpcode
== 332) {
2325 if(data
->set
.ftp_account
) {
2326 NBFTPSENDF(conn
, "ACCT %s", data
->set
.ftp_account
);
2327 state(conn
, FTP_ACCT
);
2330 failf(data
, "ACCT requested but none available");
2331 result
= CURLE_LOGIN_DENIED
;
2335 /* All other response codes, like:
2337 530 User ... access denied
2338 (the server denies to log the specified user) */
2340 if (conn
->data
->set
.ftp_alternative_to_user
&&
2341 !conn
->data
->state
.ftp_trying_alternative
) {
2342 /* Ok, USER failed. Let's try the supplied command. */
2343 NBFTPSENDF(conn
, "%s", conn
->data
->set
.ftp_alternative_to_user
);
2344 conn
->data
->state
.ftp_trying_alternative
= TRUE
;
2345 state(conn
, FTP_USER
);
2349 failf(data
, "Access denied: %03d", ftpcode
);
2350 result
= CURLE_LOGIN_DENIED
;
2356 /* for ACCT response */
2357 static CURLcode
ftp_state_acct_resp(struct connectdata
*conn
,
2360 CURLcode result
= CURLE_OK
;
2361 struct SessionHandle
*data
= conn
->data
;
2362 if(ftpcode
!= 230) {
2363 failf(data
, "ACCT rejected by server: %03d", ftpcode
);
2364 result
= CURLE_FTP_WEIRD_PASS_REPLY
; /* FIX */
2367 result
= ftp_state_loggedin(conn
);
2373 static CURLcode
ftp_statemach_act(struct connectdata
*conn
)
2376 curl_socket_t sock
= conn
->sock
[FIRSTSOCKET
];
2377 struct SessionHandle
*data
=conn
->data
;
2379 struct ftp_conn
*ftpc
= &conn
->proto
.ftpc
;
2380 static const char * const ftpauth
[] = {
2385 if(ftpc
->sendleft
) {
2386 /* we have a piece of a command still left to send */
2388 result
= Curl_write(conn
, sock
, ftpc
->sendthis
+ ftpc
->sendsize
-
2389 ftpc
->sendleft
, ftpc
->sendleft
, &written
);
2393 if(written
!= (ssize_t
)ftpc
->sendleft
) {
2394 /* only a fraction was sent */
2395 ftpc
->sendleft
-= written
;
2398 free(ftpc
->sendthis
);
2399 ftpc
->sendthis
=NULL
;
2400 ftpc
->sendleft
= ftpc
->sendsize
= 0;
2401 ftpc
->response
= Curl_tvnow();
2406 /* we read a piece of response */
2407 result
= ftp_readresp(sock
, conn
, &ftpcode
, &nread
);
2412 /* we have now received a full FTP server response */
2413 switch(ftpc
->state
) {
2415 if(ftpcode
!= 220) {
2416 failf(data
, "This doesn't seem like a nice ftp-server response");
2417 return CURLE_FTP_WEIRD_SERVER_REPLY
;
2420 /* We have received a 220 response fine, now we proceed. */
2422 if(data
->set
.krb4
) {
2423 /* If not anonymous login, try a secure login. Note that this
2424 procedure is still BLOCKING. */
2426 Curl_sec_request_prot(conn
, "private");
2427 /* We set private first as default, in case the line below fails to
2428 set a valid level */
2429 Curl_sec_request_prot(conn
, data
->set
.krb4_level
);
2431 if(Curl_sec_login(conn
) != 0)
2432 infof(data
, "Logging in with password in cleartext!\n");
2434 infof(data
, "Authentication successful\n");
2438 if(data
->set
.ftp_ssl
&& !conn
->ssl
[FIRSTSOCKET
].use
) {
2439 /* We don't have a SSL/TLS connection yet, but FTPS is
2440 requested. Try a FTPS connection now */
2443 switch(data
->set
.ftpsslauth
) {
2444 case CURLFTPAUTH_DEFAULT
:
2445 case CURLFTPAUTH_SSL
:
2446 ftpc
->count2
= 1; /* add one to get next */
2449 case CURLFTPAUTH_TLS
:
2450 ftpc
->count2
= -1; /* subtract one to get next */
2454 failf(data
, "unsupported parameter to CURLOPT_FTPSSLAUTH: %d\n",
2455 data
->set
.ftpsslauth
);
2456 return CURLE_FAILED_INIT
; /* we don't know what to do */
2458 NBFTPSENDF(conn
, "AUTH %s", ftpauth
[ftpc
->count1
]);
2459 state(conn
, FTP_AUTH
);
2462 result
= ftp_state_user(conn
);
2470 /* we have gotten the response to a previous AUTH command */
2472 /* RFC2228 (page 5) says:
2474 * If the server is willing to accept the named security mechanism,
2475 * and does not require any security data, it must respond with
2476 * reply code 234/334.
2479 if((ftpcode
== 234) || (ftpcode
== 334)) {
2480 /* Curl_ssl_connect is BLOCKING */
2481 result
= Curl_ssl_connect(conn
, FIRSTSOCKET
);
2482 if(CURLE_OK
== result
) {
2483 conn
->protocol
|= PROT_FTPS
;
2484 conn
->ssl
[SECONDARYSOCKET
].use
= FALSE
; /* clear-text data */
2485 result
= ftp_state_user(conn
);
2488 else if(ftpc
->count3
< 1) {
2490 ftpc
->count1
+= ftpc
->count2
; /* get next attempt */
2491 result
= Curl_nbftpsendf(conn
, "AUTH %s", ftpauth
[ftpc
->count1
]);
2492 /* remain in this same state */
2495 if(data
->set
.ftp_ssl
> CURLFTPSSL_TRY
)
2496 /* we failed and CURLFTPSSL_CONTROL or CURLFTPSSL_ALL is set */
2497 result
= CURLE_FTP_SSL_FAILED
;
2499 /* ignore the failure and continue */
2500 result
= ftp_state_user(conn
);
2509 result
= ftp_state_user_resp(conn
, ftpcode
, ftpc
->state
);
2513 result
= ftp_state_acct_resp(conn
, ftpcode
);
2517 /* FIX: check response code */
2519 /* For TLS, the data connection can have one of two security levels.
2521 1) Clear (requested by 'PROT C')
2523 2)Private (requested by 'PROT P')
2525 if(!conn
->ssl
[SECONDARYSOCKET
].use
) {
2526 NBFTPSENDF(conn
, "PROT %c",
2527 data
->set
.ftp_ssl
== CURLFTPSSL_CONTROL
? 'C' : 'P');
2528 state(conn
, FTP_PROT
);
2531 result
= ftp_state_pwd(conn
);
2539 if(ftpcode
/100 == 2)
2540 /* We have enabled SSL for the data connection! */
2541 conn
->ssl
[SECONDARYSOCKET
].use
=
2542 (bool)(data
->set
.ftp_ssl
!= CURLFTPSSL_CONTROL
);
2543 /* FTP servers typically responds with 500 if they decide to reject
2545 else if(data
->set
.ftp_ssl
> CURLFTPSSL_CONTROL
)
2546 /* we failed and bails out */
2547 return CURLE_FTP_SSL_FAILED
;
2549 if(data
->set
.ftp_use_ccc
) {
2550 /* CCC - Clear Command Channel
2552 NBFTPSENDF(conn
, "CCC", NULL
);
2553 state(conn
, FTP_CCC
);
2556 result
= ftp_state_pwd(conn
);
2563 if (ftpcode
< 500) {
2564 /* First shut down the SSL layer (note: this call will block) */
2565 result
= Curl_ssl_shutdown(conn
, FIRSTSOCKET
);
2568 failf(conn
->data
, "Failed to clear the command channel (CCC)");
2573 /* Then continue as normal */
2574 result
= ftp_state_pwd(conn
);
2580 if(ftpcode
== 257) {
2581 char *dir
= (char *)malloc(nread
+1);
2583 char *ptr
=&data
->state
.buffer
[4]; /* start on the first letter */
2586 return CURLE_OUT_OF_MEMORY
;
2588 /* Reply format is like
2589 257<space>"<directory-name>"<space><commentary> and the RFC959
2592 The directory name can contain any character; embedded
2593 double-quotes should be escaped by double-quotes (the
2594 "quote-doubling" convention).
2597 /* it started good */
2599 while(ptr
&& *ptr
) {
2601 if('\"' == ptr
[1]) {
2602 /* "quote-doubling" */
2608 *store
= '\0'; /* zero terminate */
2609 break; /* get out of this loop */
2617 ftpc
->entrypath
=dir
; /* remember this */
2618 infof(data
, "Entry path is '%s'\n", ftpc
->entrypath
);
2619 /* also save it where getinfo can access it: */
2620 data
->state
.most_recent_ftp_entrypath
= ftpc
->entrypath
;
2623 /* couldn't get the path */
2625 infof(data
, "Failed to figure out path\n");
2628 state(conn
, FTP_STOP
); /* we are done with the CONNECT phase! */
2629 DEBUGF(infof(data
, "protocol connect phase DONE\n"));
2634 case FTP_RETR_PREQUOTE
:
2635 case FTP_STOR_PREQUOTE
:
2636 if(ftpcode
>= 400) {
2637 failf(conn
->data
, "QUOT command failed with %03d", ftpcode
);
2638 return CURLE_FTP_QUOTE_ERROR
;
2640 result
= ftp_state_quote(conn
, FALSE
, ftpc
->state
);
2647 if(ftpcode
/100 != 2) {
2648 /* failure to CWD there */
2649 if(conn
->data
->set
.ftp_create_missing_dirs
&&
2650 ftpc
->count1
&& !ftpc
->count2
) {
2652 ftpc
->count2
++; /* counter to prevent CWD-MKD loops */
2653 NBFTPSENDF(conn
, "MKD %s", ftpc
->dirs
[ftpc
->count1
- 1]);
2654 state(conn
, FTP_MKD
);
2657 /* return failure */
2658 failf(data
, "Server denied you to change to the given directory");
2659 ftpc
->cwdfail
= TRUE
; /* don't remember this path as we failed
2661 return CURLE_FTP_ACCESS_DENIED
;
2667 if(++ftpc
->count1
<= ftpc
->dirdepth
) {
2669 NBFTPSENDF(conn
, "CWD %s", ftpc
->dirs
[ftpc
->count1
- 1]);
2672 result
= ftp_state_post_cwd(conn
);
2680 if(ftpcode
/100 != 2) {
2681 /* failure to MKD the dir */
2682 failf(data
, "Failed to MKD dir: %03d", ftpcode
);
2683 return CURLE_FTP_ACCESS_DENIED
;
2685 state(conn
, FTP_CWD
);
2687 NBFTPSENDF(conn
, "CWD %s", ftpc
->dirs
[ftpc
->count1
- 1]);
2691 result
= ftp_state_mdtm_resp(conn
, ftpcode
);
2698 result
= ftp_state_type_resp(conn
, ftpcode
, ftpc
->state
);
2704 result
= ftp_state_size_resp(conn
, ftpcode
, ftpc
->state
);
2709 result
= ftp_state_rest_resp(conn
, ftpcode
, ftpc
->state
);
2713 result
= ftp_state_pasv_resp(conn
, ftpcode
);
2717 result
= ftp_state_port_resp(conn
, ftpcode
);
2722 result
= ftp_state_get_resp(conn
, ftpcode
, ftpc
->state
);
2726 result
= ftp_state_stor_resp(conn
, ftpcode
);
2730 /* fallthrough, just stop! */
2732 /* internal error */
2733 state(conn
, FTP_STOP
);
2741 /* Returns timeout in ms. 0 or negative number means the timeout has already
2743 static long ftp_state_timeout(struct connectdata
*conn
)
2745 struct SessionHandle
*data
=conn
->data
;
2746 struct ftp_conn
*ftpc
= &conn
->proto
.ftpc
;
2747 long timeout_ms
=360000; /* in milliseconds */
2749 if(data
->set
.ftp_response_timeout
)
2750 /* if CURLOPT_FTP_RESPONSE_TIMEOUT is set, use that to determine remaining
2751 time. Also, use ftp->response because FTP_RESPONSE_TIMEOUT is supposed
2752 to govern the response for any given ftp response, not for the time
2753 from connect to the given ftp response. */
2754 timeout_ms
= data
->set
.ftp_response_timeout
*1000 - /* timeout time */
2755 Curl_tvdiff(Curl_tvnow(), ftpc
->response
); /* spent time */
2756 else if(data
->set
.timeout
)
2757 /* if timeout is requested, find out how much remaining time we have */
2758 timeout_ms
= data
->set
.timeout
*1000 - /* timeout time */
2759 Curl_tvdiff(Curl_tvnow(), conn
->now
); /* spent time */
2761 /* Without a requested timeout, we only wait 'response_time' seconds for
2762 the full response to arrive before we bail out */
2763 timeout_ms
= ftpc
->response_time
*1000 -
2764 Curl_tvdiff(Curl_tvnow(), ftpc
->response
); /* spent time */
2770 /* called repeatedly until done from multi.c */
2771 CURLcode
Curl_ftp_multi_statemach(struct connectdata
*conn
,
2774 curl_socket_t sock
= conn
->sock
[FIRSTSOCKET
];
2776 struct SessionHandle
*data
=conn
->data
;
2777 struct ftp_conn
*ftpc
= &conn
->proto
.ftpc
;
2778 CURLcode result
= CURLE_OK
;
2779 long timeout_ms
= ftp_state_timeout(conn
);
2781 *done
= FALSE
; /* default to not done yet */
2783 if(timeout_ms
<= 0) {
2784 failf(data
, "FTP response timeout");
2785 return CURLE_OPERATION_TIMEDOUT
;
2788 rc
= Curl_select(ftpc
->sendleft
?CURL_SOCKET_BAD
:sock
, /* reading */
2789 ftpc
->sendleft
?sock
:CURL_SOCKET_BAD
, /* writing */
2793 failf(data
, "select error");
2794 return CURLE_OUT_OF_MEMORY
;
2797 result
= ftp_statemach_act(conn
);
2798 *done
= (bool)(ftpc
->state
== FTP_STOP
);
2800 /* if rc == 0, then select() timed out */
2805 static CURLcode
ftp_easy_statemach(struct connectdata
*conn
)
2807 curl_socket_t sock
= conn
->sock
[FIRSTSOCKET
];
2809 struct SessionHandle
*data
=conn
->data
;
2810 struct ftp_conn
*ftpc
= &conn
->proto
.ftpc
;
2811 CURLcode result
= CURLE_OK
;
2813 while(ftpc
->state
!= FTP_STOP
) {
2814 long timeout_ms
= ftp_state_timeout(conn
);
2816 if(timeout_ms
<=0 ) {
2817 failf(data
, "FTP response timeout");
2818 return CURLE_OPERATION_TIMEDOUT
; /* already too little time */
2821 rc
= Curl_select(ftpc
->sendleft
?CURL_SOCKET_BAD
:sock
, /* reading */
2822 ftpc
->sendleft
?sock
:CURL_SOCKET_BAD
, /* writing */
2826 failf(data
, "select error");
2827 return CURLE_OUT_OF_MEMORY
;
2830 result
= CURLE_OPERATION_TIMEDOUT
;
2834 result
= ftp_statemach_act(conn
);
2844 * Allocate and initialize the struct FTP for the current SessionHandle. If
2847 static CURLcode
ftp_init(struct connectdata
*conn
)
2849 struct SessionHandle
*data
= conn
->data
;
2851 if(data
->reqdata
.proto
.ftp
)
2854 ftp
= (struct FTP
*)calloc(sizeof(struct FTP
), 1);
2856 return CURLE_OUT_OF_MEMORY
;
2858 data
->reqdata
.proto
.ftp
= ftp
;
2860 /* get some initial data into the ftp struct */
2861 ftp
->bytecountp
= &data
->reqdata
.keep
.bytecount
;
2863 /* no need to duplicate them, this connectdata struct won't change */
2864 ftp
->user
= conn
->user
;
2865 ftp
->passwd
= conn
->passwd
;
2866 if (isBadFtpString(ftp
->user
) || isBadFtpString(ftp
->passwd
))
2867 return CURLE_URL_MALFORMAT
;
2873 * Curl_ftp_connect() should do everything that is to be considered a part of
2874 * the connection phase.
2876 * The variable 'done' points to will be TRUE if the protocol-layer connect
2877 * phase is done when this function returns, or FALSE is not. When called as
2878 * a part of the easy interface, it will always be TRUE.
2880 CURLcode
Curl_ftp_connect(struct connectdata
*conn
,
2881 bool *done
) /* see description above */
2884 #ifndef CURL_DISABLE_HTTP
2885 /* for FTP over HTTP proxy */
2886 struct HTTP http_proxy
;
2887 struct FTP
*ftp_save
;
2888 #endif /* CURL_DISABLE_HTTP */
2889 struct ftp_conn
*ftpc
= &conn
->proto
.ftpc
;
2890 struct SessionHandle
*data
=conn
->data
;
2892 *done
= FALSE
; /* default to not done yet */
2894 if (data
->reqdata
.proto
.ftp
) {
2895 Curl_ftp_disconnect(conn
);
2896 free(data
->reqdata
.proto
.ftp
);
2897 data
->reqdata
.proto
.ftp
= NULL
;
2900 result
= ftp_init(conn
);
2904 /* We always support persistant connections on ftp */
2905 conn
->bits
.close
= FALSE
;
2907 ftpc
->response_time
= 3600; /* set default response time-out */
2909 #ifndef CURL_DISABLE_HTTP
2910 if (conn
->bits
.tunnel_proxy
&& conn
->bits
.httpproxy
) {
2912 /* We want "seamless" FTP operations through HTTP proxy tunnel */
2914 /* Curl_proxyCONNECT is based on a pointer to a struct HTTP at the member
2915 * conn->proto.http; we want FTP through HTTP and we have to change the
2916 * member temporarily for connecting to the HTTP proxy. After
2917 * Curl_proxyCONNECT we have to set back the member to the original struct
2920 ftp_save
= data
->reqdata
.proto
.ftp
;
2921 memset(&http_proxy
, 0, sizeof(http_proxy
));
2922 data
->reqdata
.proto
.http
= &http_proxy
;
2924 result
= Curl_proxyCONNECT(conn
, FIRSTSOCKET
,
2925 conn
->host
.name
, conn
->remote_port
);
2927 data
->reqdata
.proto
.ftp
= ftp_save
;
2929 if(CURLE_OK
!= result
)
2932 #endif /* CURL_DISABLE_HTTP */
2934 if(conn
->protocol
& PROT_FTPS
) {
2936 /* FTPS is simply ftp with SSL for the control channel */
2937 /* now, perform the SSL initialization for this socket */
2938 result
= Curl_ssl_connect(conn
, FIRSTSOCKET
);
2943 /* When we connect, we start in the state where we await the 220
2945 ftp_respinit(conn
); /* init the response reader stuff */
2946 state(conn
, FTP_WAIT220
);
2947 ftpc
->response
= Curl_tvnow(); /* start response time-out now! */
2949 if(data
->state
.used_interface
== Curl_if_multi
)
2950 result
= Curl_ftp_multi_statemach(conn
, done
);
2952 result
= ftp_easy_statemach(conn
);
2960 /***********************************************************************
2964 * The DONE function. This does what needs to be done after a single DO has
2967 * Input argument is already checked for validity.
2969 CURLcode
Curl_ftp_done(struct connectdata
*conn
, CURLcode status
, bool premature
)
2971 struct SessionHandle
*data
= conn
->data
;
2972 struct FTP
*ftp
= data
->reqdata
.proto
.ftp
;
2973 struct ftp_conn
*ftpc
= &conn
->proto
.ftpc
;
2976 CURLcode result
=CURLE_OK
;
2977 bool was_ctl_valid
= ftpc
->ctl_valid
;
2981 char *path_to_use
= data
->reqdata
.path
;
2982 struct Curl_transfer_keeper
*k
= &data
->reqdata
.keep
;
2985 /* When the easy handle is removed from the multi while libcurl is still
2986 * trying to resolve the host name, it seems that the ftp struct is not
2987 * yet initialized, but the removal action calls Curl_done() which calls
2988 * this function. So we simply return success if no ftp pointer is set.
2993 case CURLE_BAD_DOWNLOAD_RESUME
:
2994 case CURLE_FTP_WEIRD_PASV_REPLY
:
2995 case CURLE_FTP_PORT_FAILED
:
2996 case CURLE_FTP_COULDNT_SET_BINARY
:
2997 case CURLE_FTP_COULDNT_RETR_FILE
:
2998 case CURLE_FTP_COULDNT_STOR_FILE
:
2999 case CURLE_FTP_ACCESS_DENIED
:
3000 /* the connection stays alive fine even though this happened */
3002 case CURLE_OK
: /* doesn't affect the control connection's status */
3004 ftpc
->ctl_valid
= was_ctl_valid
;
3007 /* until we cope better with prematurely ended requests, let them
3008 * fallback as if in complete failure */
3009 default: /* by default, an error means the control connection is
3010 wedged and should not be used anymore */
3011 ftpc
->ctl_valid
= FALSE
;
3012 ftpc
->cwdfail
= TRUE
; /* set this TRUE to prevent us to remember the
3013 current path, as this connection is going */
3014 conn
->bits
.close
= TRUE
; /* marked for closure */
3018 /* now store a copy of the directory we are in */
3020 free(ftpc
->prevpath
);
3022 /* get the "raw" path */
3023 path
= curl_easy_unescape(data
, path_to_use
, 0, NULL
);
3025 return CURLE_OUT_OF_MEMORY
;
3027 flen
= ftp
->file
?strlen(ftp
->file
):0; /* file is "raw" already */
3028 dlen
= strlen(path
)-flen
;
3029 if(dlen
&& !ftpc
->cwdfail
) {
3030 ftpc
->prevpath
= path
;
3032 /* if 'path' is not the whole string */
3033 ftpc
->prevpath
[dlen
]=0; /* terminate */
3034 infof(data
, "Remembering we are in dir %s\n", ftpc
->prevpath
);
3037 ftpc
->prevpath
= NULL
; /* no path */
3040 /* free the dir tree and file parts */
3044 Curl_sec_fflush_fd(conn
, conn
->sock
[SECONDARYSOCKET
]);
3047 /* shut down the socket to inform the server we're done */
3050 shutdown(conn
->sock
[SECONDARYSOCKET
],2); /* SD_BOTH */
3053 sclose(conn
->sock
[SECONDARYSOCKET
]);
3055 conn
->sock
[SECONDARYSOCKET
] = CURL_SOCKET_BAD
;
3057 if(!ftp
->no_transfer
&& !status
&& !premature
) {
3059 * Let's see what the server says about the transfer we just performed,
3060 * but lower the timeout as sometimes this connection has died while the
3061 * data has been transfered. This happens when doing through NATs etc that
3062 * abandon old silent connections.
3064 long old_time
= ftpc
->response_time
;
3066 ftpc
->response_time
= 60; /* give it only a minute for now */
3068 result
= Curl_GetFTPResponse(&nread
, conn
, &ftpcode
);
3070 ftpc
->response_time
= old_time
; /* set this back to previous value */
3072 if(!nread
&& (CURLE_OPERATION_TIMEDOUT
== result
)) {
3073 failf(data
, "control connection looks dead");
3074 ftpc
->ctl_valid
= FALSE
; /* mark control connection as bad */
3081 if(!ftpc
->dont_check
) {
3082 /* 226 Transfer complete, 250 Requested file action okay, completed. */
3083 if((ftpcode
!= 226) && (ftpcode
!= 250)) {
3084 failf(data
, "server did not report OK, got %d", ftpcode
);
3085 result
= CURLE_PARTIAL_FILE
;
3090 if(result
|| premature
)
3091 /* the response code from the transfer showed an error already so no
3092 use checking further */
3094 else if(data
->set
.upload
) {
3095 if((-1 != data
->set
.infilesize
) &&
3096 (data
->set
.infilesize
!= *ftp
->bytecountp
) &&
3098 !ftp
->no_transfer
) {
3099 failf(data
, "Uploaded unaligned file size (%" FORMAT_OFF_T
3100 " out of %" FORMAT_OFF_T
" bytes)",
3101 *ftp
->bytecountp
, data
->set
.infilesize
);
3102 result
= CURLE_PARTIAL_FILE
;
3106 if((-1 != k
->size
) && (k
->size
!= *ftp
->bytecountp
) &&
3107 #ifdef CURL_DO_LINEEND_CONV
3108 /* Most FTP servers don't adjust their file SIZE response for CRLFs, so
3109 * we'll check to see if the discrepancy can be explained by the number
3110 * of CRLFs we've changed to LFs.
3112 ((k
->size
+ data
->state
.crlf_conversions
) != *ftp
->bytecountp
) &&
3113 #endif /* CURL_DO_LINEEND_CONV */
3114 (k
->maxdownload
!= *ftp
->bytecountp
)) {
3115 failf(data
, "Received only partial file: %" FORMAT_OFF_T
" bytes",
3117 result
= CURLE_PARTIAL_FILE
;
3119 else if(!ftpc
->dont_check
&&
3120 !*ftp
->bytecountp
&&
3122 failf(data
, "No data was received!");
3123 result
= CURLE_FTP_COULDNT_RETR_FILE
;
3127 /* clear these for next connection */
3128 ftp
->no_transfer
= FALSE
;
3129 ftpc
->dont_check
= FALSE
;
3131 /* Send any post-transfer QUOTE strings? */
3132 if(!status
&& !result
&& !premature
&& data
->set
.postquote
)
3133 result
= ftp_sendquote(conn
, data
->set
.postquote
);
3138 /***********************************************************************
3142 * Where a 'quote' means a list of custom commands to send to the server.
3143 * The quote list is passed as an argument.
3147 CURLcode
ftp_sendquote(struct connectdata
*conn
, struct curl_slist
*quote
)
3149 struct curl_slist
*item
;
3157 FTPSENDF(conn
, "%s", item
->data
);
3159 result
= Curl_GetFTPResponse(&nread
, conn
, &ftpcode
);
3163 if (ftpcode
>= 400) {
3164 failf(conn
->data
, "QUOT string not accepted: %s", item
->data
);
3165 return CURLE_FTP_QUOTE_ERROR
;
3175 /***********************************************************************
3179 * Returns TRUE if we in the current situation should send TYPE
3181 static int ftp_need_type(struct connectdata
*conn
,
3184 return conn
->proto
.ftpc
.transfertype
!= (ascii_wanted
?'A':'I');
3187 /***********************************************************************
3191 * Set TYPE. We only deal with ASCII or BINARY so this function
3193 * If the transfer type is not sent, simulate on OK response in newstate
3195 static CURLcode
ftp_nb_type(struct connectdata
*conn
,
3196 bool ascii
, ftpstate newstate
)
3198 struct ftp_conn
*ftpc
= &conn
->proto
.ftpc
;
3200 int want
= ascii
?'A':'I';
3202 if (ftpc
->transfertype
== want
) {
3203 state(conn
, newstate
);
3204 return ftp_state_type_resp(conn
, 200, newstate
);
3207 NBFTPSENDF(conn
, "TYPE %c", want
);
3208 state(conn
, newstate
);
3210 /* keep track of our current transfer type */
3211 ftpc
->transfertype
= want
;
3215 /***************************************************************************
3217 * ftp_pasv_verbose()
3219 * This function only outputs some informationals about this second connection
3220 * when we've issued a PASV command before and thus we have connected to a
3221 * possibly new IP address.
3225 ftp_pasv_verbose(struct connectdata
*conn
,
3227 char *newhost
, /* ascii version */
3231 Curl_printable_address(ai
, buf
, sizeof(buf
));
3232 infof(conn
->data
, "Connecting to %s (%s) port %d\n", newhost
, buf
, port
);
3236 Check if this is a range download, and if so, set the internal variables
3240 static CURLcode
ftp_range(struct connectdata
*conn
)
3242 curl_off_t from
, to
;
3243 curl_off_t totalsize
=-1;
3246 struct SessionHandle
*data
= conn
->data
;
3247 struct ftp_conn
*ftpc
= &conn
->proto
.ftpc
;
3249 if(data
->reqdata
.use_range
&& data
->reqdata
.range
) {
3250 from
=curlx_strtoofft(data
->reqdata
.range
, &ptr
, 0);
3251 while(ptr
&& *ptr
&& (ISSPACE(*ptr
) || (*ptr
=='-')))
3253 to
=curlx_strtoofft(ptr
, &ptr2
, 0);
3255 /* we didn't get any digit */
3258 if((-1 == to
) && (from
>=0)) {
3260 data
->reqdata
.resume_from
= from
;
3261 DEBUGF(infof(conn
->data
, "FTP RANGE %" FORMAT_OFF_T
" to end of file\n",
3267 data
->reqdata
.maxdownload
= -from
;
3268 data
->reqdata
.resume_from
= from
;
3269 DEBUGF(infof(conn
->data
, "FTP RANGE the last %" FORMAT_OFF_T
" bytes\n",
3274 totalsize
= to
-from
;
3275 data
->reqdata
.maxdownload
= totalsize
+1; /* include last byte */
3276 data
->reqdata
.resume_from
= from
;
3277 DEBUGF(infof(conn
->data
, "FTP RANGE from %" FORMAT_OFF_T
3278 " getting %" FORMAT_OFF_T
" bytes\n",
3279 from
, data
->reqdata
.maxdownload
));
3281 DEBUGF(infof(conn
->data
, "range-download from %" FORMAT_OFF_T
3282 " to %" FORMAT_OFF_T
", totally %" FORMAT_OFF_T
" bytes\n",
3283 from
, to
, data
->reqdata
.maxdownload
));
3284 ftpc
->dont_check
= TRUE
; /* dont check for successful transfer */
3291 * Curl_ftp_nextconnect()
3293 * This function shall be called when the second FTP (data) connection is
3297 CURLcode
Curl_ftp_nextconnect(struct connectdata
*conn
)
3299 struct SessionHandle
*data
=conn
->data
;
3300 CURLcode result
= CURLE_OK
;
3302 /* the ftp struct is inited in Curl_ftp_connect() */
3303 struct FTP
*ftp
= data
->reqdata
.proto
.ftp
;
3305 DEBUGF(infof(data
, "DO-MORE phase starts\n"));
3307 if(!ftp
->no_transfer
&& !conn
->bits
.no_body
) {
3308 /* a transfer is about to take place */
3310 if(data
->set
.upload
) {
3311 result
= ftp_nb_type(conn
, data
->set
.prefer_ascii
,
3318 ftp
->downloadsize
= -1; /* unknown as of yet */
3320 result
= ftp_range(conn
);
3323 else if((data
->set
.ftp_list_only
) || !ftp
->file
) {
3324 /* The specified path ends with a slash, and therefore we think this
3325 is a directory that is requested, use LIST. But before that we
3326 need to set ASCII transfer mode. */
3327 result
= ftp_nb_type(conn
, 1, FTP_LIST_TYPE
);
3332 result
= ftp_nb_type(conn
, data
->set
.prefer_ascii
, FTP_RETR_TYPE
);
3337 result
= ftp_easy_statemach(conn
);
3340 if(ftp
->no_transfer
)
3341 /* no data to transfer. FIX: it feels like a kludge to have this here
3343 result
=Curl_setup_transfer(conn
, -1, -1, FALSE
, NULL
, -1, NULL
);
3345 /* end of transfer */
3346 DEBUGF(infof(data
, "DO-MORE phase ends with %d\n", result
));
3353 /***********************************************************************
3357 * This is the actual DO function for FTP. Get a file/directory according to
3358 * the options previously setup.
3362 CURLcode
ftp_perform(struct connectdata
*conn
,
3363 bool *connected
, /* connect status after PASV / PORT */
3366 /* this is FTP and no proxy */
3367 CURLcode result
=CURLE_OK
;
3369 DEBUGF(infof(conn
->data
, "DO phase starts\n"));
3371 *dophase_done
= FALSE
; /* not done yet */
3373 /* start the first command in the DO phase */
3374 result
= ftp_state_quote(conn
, TRUE
, FTP_QUOTE
);
3378 /* run the state-machine */
3379 if(conn
->data
->state
.used_interface
== Curl_if_multi
)
3380 result
= Curl_ftp_multi_statemach(conn
, dophase_done
);
3382 result
= ftp_easy_statemach(conn
);
3383 *dophase_done
= TRUE
; /* with the easy interface we are done here */
3385 *connected
= conn
->bits
.tcpconnect
;
3388 DEBUGF(infof(conn
->data
, "DO phase is complete\n"));
3394 /***********************************************************************
3398 * This function is registered as 'curl_do' function. It decodes the path
3399 * parts etc as a wrapper to the actual DO function (ftp_perform).
3401 * The input argument is already checked for validity.
3403 CURLcode
Curl_ftp(struct connectdata
*conn
, bool *done
)
3405 CURLcode retcode
= CURLE_OK
;
3407 *done
= FALSE
; /* default to false */
3410 Since connections can be re-used between SessionHandles, this might be a
3411 connection already existing but on a fresh SessionHandle struct so we must
3412 make sure we have a good 'struct FTP' to play with. For new connections,
3413 the struct FTP is allocated and setup in the Curl_ftp_connect() function.
3415 retcode
= ftp_init(conn
);
3419 retcode
= ftp_parse_url_path(conn
);
3423 retcode
= ftp_regular_transfer(conn
, done
);
3428 /***********************************************************************
3430 * Curl_(nb)ftpsendf()
3432 * Sends the formated string as a ftp command to a ftp server
3434 * NOTE: we build the command in a fixed-length buffer, which sets length
3435 * restrictions on the command!
3437 * The "nb" version is made to Never Block.
3439 CURLcode
Curl_nbftpsendf(struct connectdata
*conn
,
3440 const char *fmt
, ...)
3442 ssize_t bytes_written
;
3446 CURLcode res
= CURLE_OK
;
3447 struct SessionHandle
*data
= conn
->data
;
3448 struct ftp_conn
*ftpc
= &conn
->proto
.ftpc
;
3452 vsnprintf(s
, 250, fmt
, ap
);
3455 strcat(s
, "\r\n"); /* append a trailing CRLF */
3458 write_len
= strlen(s
);
3462 #ifdef CURL_DOES_CONVERSIONS
3463 res
= Curl_convert_to_network(data
, s
, write_len
);
3464 /* Curl_convert_to_network calls failf if unsuccessful */
3465 if(res
!= CURLE_OK
) {
3468 #endif /* CURL_DOES_CONVERSIONS */
3470 res
= Curl_write(conn
, conn
->sock
[FIRSTSOCKET
], sptr
, write_len
,
3476 if(conn
->data
->set
.verbose
)
3477 Curl_debug(conn
->data
, CURLINFO_HEADER_OUT
,
3478 sptr
, (size_t)bytes_written
, conn
);
3480 if(bytes_written
!= (ssize_t
)write_len
) {
3481 /* the whole chunk was not sent, store the rest of the data */
3482 write_len
-= bytes_written
;
3483 sptr
+= bytes_written
;
3484 ftpc
->sendthis
= malloc(write_len
);
3485 if(ftpc
->sendthis
) {
3486 memcpy(ftpc
->sendthis
, sptr
, write_len
);
3487 ftpc
->sendsize
= ftpc
->sendleft
= write_len
;
3490 failf(data
, "out of memory");
3491 res
= CURLE_OUT_OF_MEMORY
;
3495 ftpc
->response
= Curl_tvnow();
3500 CURLcode
Curl_ftpsendf(struct connectdata
*conn
,
3501 const char *fmt
, ...)
3503 ssize_t bytes_written
;
3507 CURLcode res
= CURLE_OK
;
3511 vsnprintf(s
, 250, fmt
, ap
);
3514 strcat(s
, "\r\n"); /* append a trailing CRLF */
3517 write_len
= strlen(s
);
3519 #ifdef CURL_DOES_CONVERSIONS
3520 res
= Curl_convert_to_network(conn
->data
, s
, write_len
);
3521 /* Curl_convert_to_network calls failf if unsuccessful */
3522 if(res
!= CURLE_OK
) {
3525 #endif /* CURL_DOES_CONVERSIONS */
3528 res
= Curl_write(conn
, conn
->sock
[FIRSTSOCKET
], sptr
, write_len
,
3534 if(conn
->data
->set
.verbose
)
3535 Curl_debug(conn
->data
, CURLINFO_HEADER_OUT
,
3536 sptr
, (size_t)bytes_written
, conn
);
3538 if(bytes_written
!= (ssize_t
)write_len
) {
3539 write_len
-= bytes_written
;
3540 sptr
+= bytes_written
;
3549 /***********************************************************************
3553 * This should be called before calling sclose() on an ftp control connection
3554 * (not data connections). We should then wait for the response from the
3555 * server before returning. The calling code should then try to close the
3559 static CURLcode
ftp_quit(struct connectdata
*conn
)
3561 CURLcode result
= CURLE_OK
;
3563 if(conn
->proto
.ftpc
.ctl_valid
) {
3564 NBFTPSENDF(conn
, "QUIT", NULL
);
3565 state(conn
, FTP_QUIT
);
3567 result
= ftp_easy_statemach(conn
);
3573 /***********************************************************************
3575 * Curl_ftp_disconnect()
3577 * Disconnect from an FTP server. Cleanup protocol-specific per-connection
3578 * resources. BLOCKING.
3580 CURLcode
Curl_ftp_disconnect(struct connectdata
*conn
)
3582 struct ftp_conn
*ftpc
= &conn
->proto
.ftpc
;
3584 /* We cannot send quit unconditionally. If this connection is stale or
3585 bad in any way, sending quit and waiting around here will make the
3586 disconnect wait in vain and cause more problems than we need to.
3588 ftp_quit() will check the state of ftp->ctl_valid. If it's ok it
3589 will try to send the QUIT command, otherwise it will just return.
3592 /* The FTP session may or may not have been allocated/setup at this point! */
3593 if(conn
->data
->reqdata
.proto
.ftp
) {
3594 (void)ftp_quit(conn
); /* ignore errors on the QUIT */
3596 if(ftpc
->entrypath
) {
3597 struct SessionHandle
*data
= conn
->data
;
3598 data
->state
.most_recent_ftp_entrypath
= NULL
;
3599 free(ftpc
->entrypath
);
3600 ftpc
->entrypath
= NULL
;
3607 if(ftpc
->prevpath
) {
3608 free(ftpc
->prevpath
);
3609 ftpc
->prevpath
= NULL
;
3615 /***********************************************************************
3617 * ftp_parse_url_path()
3619 * Parse the URL path into separate path components.
3623 CURLcode
ftp_parse_url_path(struct connectdata
*conn
)
3625 CURLcode retcode
= CURLE_OK
;
3626 struct SessionHandle
*data
= conn
->data
;
3627 /* the ftp struct is already inited in ftp_connect() */
3628 struct FTP
*ftp
= data
->reqdata
.proto
.ftp
;
3629 struct ftp_conn
*ftpc
= &conn
->proto
.ftpc
;
3631 char *slash_pos
; /* position of the first '/' char in curpos */
3632 char *path_to_use
= data
->reqdata
.path
;
3635 cur_pos
= path_to_use
; /* current position in path. point at the begin
3636 of next path component */
3638 ftpc
->ctl_valid
= FALSE
;
3639 ftpc
->cwdfail
= FALSE
;
3641 switch(data
->set
.ftp_filemethod
) {
3643 /* fastest, but less standard-compliant */
3644 ftp
->file
= data
->reqdata
.path
; /* this is a full file path */
3647 case FTPFILE_SINGLECWD
:
3648 /* get the last slash */
3649 slash_pos
=strrchr(cur_pos
, '/');
3650 if(slash_pos
|| !cur_pos
|| !*cur_pos
) {
3651 ftpc
->dirdepth
= 1; /* we consider it to be a single dir */
3652 ftpc
->dirs
= (char **)calloc(1, sizeof(ftpc
->dirs
[0]));
3654 return CURLE_OUT_OF_MEMORY
;
3656 ftpc
->dirs
[0] = curl_easy_unescape(conn
->data
, slash_pos
? cur_pos
: "/",
3657 slash_pos
?(int)(slash_pos
-cur_pos
):1,
3659 if(!ftpc
->dirs
[0]) {
3661 return CURLE_OUT_OF_MEMORY
;
3663 ftp
->file
= slash_pos
? slash_pos
+1 : cur_pos
; /* rest is file name */
3666 ftp
->file
= cur_pos
; /* this is a file name only */
3669 default: /* allow pretty much anything */
3670 case FTPFILE_MULTICWD
:
3672 ftpc
->diralloc
= 5; /* default dir depth to allocate */
3673 ftpc
->dirs
= (char **)calloc(ftpc
->diralloc
, sizeof(ftpc
->dirs
[0]));
3675 return CURLE_OUT_OF_MEMORY
;
3677 /* parse the URL path into separate path components */
3678 while ((slash_pos
= strchr(cur_pos
, '/')) != NULL
) {
3679 /* 1 or 0 to indicate absolute directory */
3680 bool absolute_dir
= (bool)((cur_pos
- data
->reqdata
.path
> 0) &&
3681 (ftpc
->dirdepth
== 0));
3683 /* seek out the next path component */
3684 if (slash_pos
-cur_pos
) {
3685 /* we skip empty path components, like "x//y" since the FTP command
3686 CWD requires a parameter and a non-existant parameter a) doesn't
3687 work on many servers and b) has no effect on the others. */
3688 int len
= (int)(slash_pos
- cur_pos
+ absolute_dir
);
3689 ftpc
->dirs
[ftpc
->dirdepth
] = curl_easy_unescape(conn
->data
,
3690 cur_pos
- absolute_dir
,
3692 if (!ftpc
->dirs
[ftpc
->dirdepth
]) { /* run out of memory ... */
3693 failf(data
, "no memory");
3695 return CURLE_OUT_OF_MEMORY
;
3697 if (isBadFtpString(ftpc
->dirs
[ftpc
->dirdepth
])) {
3699 return CURLE_URL_MALFORMAT
;
3703 cur_pos
= slash_pos
+ 1; /* jump to the rest of the string */
3708 cur_pos
= slash_pos
+ 1; /* jump to the rest of the string */
3709 if(++ftpc
->dirdepth
>= ftpc
->diralloc
) {
3712 ftpc
->diralloc
*= 2; /* double the size each time */
3713 bigger
= realloc(ftpc
->dirs
, ftpc
->diralloc
* sizeof(ftpc
->dirs
[0]));
3717 return CURLE_OUT_OF_MEMORY
;
3719 ftpc
->dirs
= (char **)bigger
;
3724 ftp
->file
= cur_pos
; /* the rest is the file name */
3728 ftp
->file
= curl_easy_unescape(conn
->data
, ftp
->file
, 0, NULL
);
3729 if(NULL
== ftp
->file
) {
3731 failf(data
, "no memory");
3732 return CURLE_OUT_OF_MEMORY
;
3734 if (isBadFtpString(ftp
->file
)) {
3736 return CURLE_URL_MALFORMAT
;
3740 ftp
->file
=NULL
; /* instead of point to a zero byte, we make it a NULL
3743 if(data
->set
.upload
&& !ftp
->file
&&
3744 (!ftp
->no_transfer
|| conn
->bits
.no_body
)) {
3745 /* We need a file name when uploading. Return error! */
3746 failf(data
, "Uploading to a URL without a file name!");
3747 return CURLE_URL_MALFORMAT
;
3750 ftpc
->cwddone
= FALSE
; /* default to not done */
3752 if(ftpc
->prevpath
) {
3753 /* prevpath is "raw" so we convert the input path before we compare the
3755 char *path
= curl_easy_unescape(conn
->data
, data
->reqdata
.path
, 0, NULL
);
3757 return CURLE_OUT_OF_MEMORY
;
3759 dlen
= strlen(path
) - (ftp
->file
?strlen(ftp
->file
):0);
3760 if((dlen
== strlen(ftpc
->prevpath
)) &&
3761 curl_strnequal(path
, ftpc
->prevpath
, dlen
)) {
3762 infof(data
, "Request has same path as previous transfer\n");
3763 ftpc
->cwddone
= TRUE
;
3771 /* call this when the DO phase has completed */
3772 static CURLcode
ftp_dophase_done(struct connectdata
*conn
,
3775 CURLcode result
= CURLE_OK
;
3776 struct FTP
*ftp
= conn
->data
->reqdata
.proto
.ftp
;
3777 struct ftp_conn
*ftpc
= &conn
->proto
.ftpc
;
3780 result
= Curl_ftp_nextconnect(conn
);
3782 if(result
&& (conn
->sock
[SECONDARYSOCKET
] != CURL_SOCKET_BAD
)) {
3783 /* Failure detected, close the second socket if it was created already */
3784 sclose(conn
->sock
[SECONDARYSOCKET
]);
3785 conn
->sock
[SECONDARYSOCKET
] = CURL_SOCKET_BAD
;
3789 if(ftp
->no_transfer
)
3790 /* no data to transfer */
3791 result
=Curl_setup_transfer(conn
, -1, -1, FALSE
, NULL
, -1, NULL
);
3793 /* since we didn't connect now, we want do_more to get called */
3794 conn
->bits
.do_more
= TRUE
;
3796 ftpc
->ctl_valid
= TRUE
; /* seems good */
3801 /* called from multi.c while DOing */
3802 CURLcode
Curl_ftp_doing(struct connectdata
*conn
,
3806 result
= Curl_ftp_multi_statemach(conn
, dophase_done
);
3809 result
= ftp_dophase_done(conn
, FALSE
/* not connected */);
3811 DEBUGF(infof(conn
->data
, "DO phase is complete\n"));
3816 /***********************************************************************
3818 * ftp_regular_transfer()
3820 * The input argument is already checked for validity.
3822 * Performs all commands done before a regular transfer between a local and a
3825 * ftp->ctl_valid starts out as FALSE, and gets set to TRUE if we reach the
3826 * Curl_ftp_done() function without finding any major problem.
3829 CURLcode
ftp_regular_transfer(struct connectdata
*conn
,
3832 CURLcode result
=CURLE_OK
;
3834 struct SessionHandle
*data
= conn
->data
;
3835 struct ftp_conn
*ftpc
= &conn
->proto
.ftpc
;
3836 data
->reqdata
.size
= -1; /* make sure this is unknown at this point */
3838 Curl_pgrsSetUploadCounter(data
, 0);
3839 Curl_pgrsSetDownloadCounter(data
, 0);
3840 Curl_pgrsSetUploadSize(data
, 0);
3841 Curl_pgrsSetDownloadSize(data
, 0);
3843 ftpc
->ctl_valid
= TRUE
; /* starts good */
3845 result
= ftp_perform(conn
,
3846 &connected
, /* have we connected after PASV/PORT */
3847 dophase_done
); /* all commands in the DO-phase done? */
3849 if(CURLE_OK
== result
) {
3852 /* the DO phase has not completed yet */
3855 result
= ftp_dophase_done(conn
, connected
);
3865 #endif /* CURL_DISABLE_FTP */