1 /***************************************************************************
3 * Project ___| | | | _ \| |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
8 * Copyright (C) 1998 - 2004, 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.
22 ***************************************************************************/
26 #ifndef CURL_DISABLE_FTP
37 #ifdef HAVE_SYS_SELECT_H
38 #include <sys/select.h>
41 #if defined(WIN32) && !defined(__GNUC__) || defined(__MINGW32__)
43 #else /* some kind of unix */
44 #ifdef HAVE_SYS_SOCKET_H
45 #include <sys/socket.h>
47 #include <sys/types.h>
48 #ifdef HAVE_NETINET_IN_H
49 #include <netinet/in.h>
51 #ifdef HAVE_ARPA_INET_H
52 #include <arpa/inet.h>
54 #include <sys/utsname.h>
64 #if defined(WIN32) && defined(__GNUC__) || defined(__MINGW32__)
68 #include <curl/curl.h>
77 #include "http.h" /* for HTTP proxy tunnel stuff */
85 #include "strtoofft.h"
90 #if defined(HAVE_INET_NTOA_R) && !defined(HAVE_INET_NTOA_R_DECL)
91 #include "inet_ntoa_r.h"
94 #define _MPRINTF_REPLACE /* use our functions only */
95 #include <curl/mprintf.h>
97 /* The last #include file should be: */
102 /* Local API functions */
103 static CURLcode ftp_sendquote(struct connectdata *conn,
104 struct curl_slist *quote);
105 static CURLcode ftp_cwd(struct connectdata *conn, char *path);
106 static CURLcode ftp_mkd(struct connectdata *conn, char *path);
107 static CURLcode ftp_cwd_and_mkd(struct connectdata *conn, char *path);
109 /* easy-to-use macro: */
110 #define FTPSENDF(x,y,z) if((result = Curl_ftpsendf(x,y,z))) return result
112 static void freedirs(struct FTP *ftp)
115 for (i=0; ftp->dirs[i]; i++){
121 /***********************************************************************
123 * AllowServerConnect()
125 * When we've issue the PORT command, we have told the server to connect
126 * to us. This function will sit and wait here until the server has
130 static CURLcode AllowServerConnect(struct connectdata *conn)
134 struct SessionHandle *data = conn->data;
135 int sock = conn->sock[SECONDARYSOCKET];
136 struct timeval now = Curl_tvnow();
137 long timespent = Curl_tvdiff(Curl_tvnow(), now)/1000;
138 long timeout = data->set.connecttimeout?data->set.connecttimeout:
139 (data->set.timeout?data->set.timeout: 0);
143 FD_SET(sock, &rdset);
146 timeout -= timespent;
148 failf(data, "Timed out before server could connect to us");
149 return CURLE_OPERATION_TIMEDOUT;
153 /* we give the server 60 seconds to connect to us, or a custom timeout */
154 dt.tv_sec = (int)(timeout?timeout:60);
157 switch (select(sock+1, &rdset, NULL, NULL, &dt)) {
160 failf(data, "Error while waiting for server connect");
161 return CURLE_FTP_PORT_FAILED;
162 case 0: /* timeout */
164 failf(data, "Timeout while waiting for server connect");
165 return CURLE_FTP_PORT_FAILED;
167 /* we have received data here */
170 size_t size = sizeof(struct sockaddr_in);
171 struct sockaddr_in add;
173 getsockname(sock, (struct sockaddr *) &add, (socklen_t *)&size);
174 s=accept(sock, (struct sockaddr *) &add, (socklen_t *)&size);
176 sclose(sock); /* close the first socket */
180 failf(data, "Error accept()ing server connect");
181 return CURLE_FTP_PORT_FAILED;
183 infof(data, "Connection accepted from server\n");
185 conn->sock[SECONDARYSOCKET] = s;
186 Curl_nonblock(s, TRUE); /* enable non-blocking */
195 /* --- parse FTP server responses --- */
198 * Curl_GetFTPResponse() is supposed to be invoked after each command sent to
199 * a remote FTP server. This function will wait and read all lines of the
200 * response and extract the relevant return code for the invoking function.
203 CURLcode Curl_GetFTPResponse(ssize_t *nreadp, /* return number of bytes read */
204 struct connectdata *conn,
205 int *ftpcode) /* return the ftp-code */
207 /* Brand new implementation.
208 * We cannot read just one byte per read() and then go back to select()
209 * as it seems that the OpenSSL read() stuff doesn't grok that properly.
211 * Alas, read as much as possible, split up into lines, use the ending
212 * line in a response or continue reading. */
214 int sockfd = conn->sock[FIRSTSOCKET];
215 int perline; /* count bytes per line */
219 long timeout; /* timeout in seconds */
220 struct timeval interval;
223 struct SessionHandle *data = conn->data;
225 int code=0; /* default ftp "error code" to return */
226 char *buf = data->state.buffer;
227 CURLcode result = CURLE_OK;
228 struct FTP *ftp = conn->proto.ftp;
229 struct timeval now = Curl_tvnow();
232 *ftpcode = 0; /* 0 for errors */
234 FD_ZERO (&readfd); /* clear it */
235 FD_SET (sockfd, &readfd); /* read socket */
237 /* get this in a backup variable to be able to restore it on each lap in the
248 while((*nreadp<BUFSIZE) && (keepon && !result)) {
249 /* check and reset timeout value every lap */
250 if(data->set.ftp_response_timeout )
251 /* if CURLOPT_FTP_RESPONSE_TIMEOUT is set, use that to determine
252 remaining time. Also, use "now" as opposed to "conn->now"
253 because ftp_response_timeout is only supposed to govern
254 the response for any given ftp response, not for the time
255 from connect to the given ftp response. */
256 timeout = data->set.ftp_response_timeout - /* timeout time */
257 Curl_tvdiff(Curl_tvnow(), now)/1000; /* spent time */
258 else if(data->set.timeout)
259 /* if timeout is requested, find out how much remaining time we have */
260 timeout = data->set.timeout - /* timeout time */
261 Curl_tvdiff(Curl_tvnow(), conn->now)/1000; /* spent time */
263 /* Even without a requested timeout, we only wait response_time
264 seconds for the full response to arrive before we bail out */
265 timeout = ftp->response_time -
266 Curl_tvdiff(Curl_tvnow(), now)/1000; /* spent time */
269 failf(data, "FTP response timeout");
270 return CURLE_OPERATION_TIMEDOUT; /* already too little time */
274 readfd = rkeepfd; /* set every lap */
275 interval.tv_sec = 1; /* use 1 second timeout intervals */
276 interval.tv_usec = 0;
278 switch (select (sockfd+1, &readfd, NULL, NULL, &interval)) {
279 case -1: /* select() error, stop reading */
280 result = CURLE_RECV_ERROR;
281 failf(data, "FTP response aborted due to select() error: %d", errno);
283 case 0: /* timeout */
284 if(Curl_pgrsUpdate(conn))
285 return CURLE_ABORTED_BY_CALLBACK;
286 continue; /* just continue in our loop for the timeout duration */
292 if(CURLE_OK == result) {
294 * This code previously didn't use the kerberos sec_read() code
295 * to read, but when we use Curl_read() it may do so. Do confirm
296 * that this is still ok and then remove this comment!
299 /* we had data in the "cache", copy that instead of doing an actual
302 * Dave Meyer, December 2003:
303 * ftp->cache_size is cast to int here. This should be safe,
304 * because it would have been populated with something of size
305 * int to begin with, even though its datatype may be larger
308 memcpy(ptr, ftp->cache, (int)ftp->cache_size);
309 gotbytes = (int)ftp->cache_size;
310 free(ftp->cache); /* free the cache */
311 ftp->cache = NULL; /* clear the pointer */
312 ftp->cache_size = 0; /* zero the size just in case */
315 int res = Curl_read(conn, sockfd, ptr, BUFSIZE-*nreadp, &gotbytes);
318 continue; /* go looping again */
326 else if(gotbytes <= 0) {
328 result = CURLE_RECV_ERROR;
329 failf(data, "FTP response reading failed");
332 /* we got a whole chunk of data, which can be anything from one
333 * byte to a set of lines and possible just a piece of the last
338 for(i = 0; i < gotbytes; ptr++, i++) {
341 /* a newline is CRLF in ftp-talk, so the CR is ignored as
342 the line isn't really terminated until the LF comes */
344 /* output debug output if that is requested */
345 if(data->set.verbose)
346 Curl_debug(data, CURLINFO_HEADER_IN, line_start, perline);
349 * We pass all response-lines to the callback function registered
350 * for "headers". The response lines can be seen as a kind of
353 result = Curl_client_write(data, CLIENTWRITE_HEADER,
354 line_start, perline);
358 #define lastline(line) (isdigit((int)line[0]) && isdigit((int)line[1]) && \
359 isdigit((int)line[2]) && (' ' == line[3]))
361 if(perline>3 && lastline(line_start)) {
362 /* This is the end of the last line, copy the last
363 * line to the start of the buffer and zero terminate,
364 * for old times sake (and krb4)! */
367 for(meow=line_start, n=0; meow<ptr; meow++, n++)
369 *meow=0; /* zero terminate */
371 line_start = ptr+1; /* advance pointer */
372 i++; /* skip this before getting out */
375 perline=0; /* line starts over here */
379 if(!keepon && (i != gotbytes)) {
380 /* We found the end of the response lines, but we didn't parse the
381 full chunk of data we have read from the server. We therefore
382 need to store the rest of the data to be checked on the next
383 invoke as it may actually contain another end of response
384 already! Cleverly figured out by Eric Lavigne in December
386 ftp->cache_size = gotbytes - i;
387 ftp->cache = (char *)malloc((int)ftp->cache_size);
389 memcpy(ftp->cache, line_start, (int)ftp->cache_size);
391 return CURLE_OUT_OF_MEMORY; /**BANG**/
393 } /* there was data */
395 } /* while there's buffer left and loop is requested */
401 /* handle the security-oriented responses 6xx ***/
402 /* FIXME: some errorchecking perhaps... ***/
405 Curl_sec_read_msg(conn, buf, prot_safe);
408 Curl_sec_read_msg(conn, buf, prot_private);
411 Curl_sec_read_msg(conn, buf, prot_confidential);
414 /* normal ftp stuff we pass through! */
420 *ftpcode=code; /* return the initial number like this */
422 /* store the latest code for later retrieval */
423 conn->data->info.httpcode=code;
428 static const char *ftpauth[]= {
433 * Curl_ftp_connect() should do everything that is to be considered a part of
434 * the connection phase.
436 CURLcode Curl_ftp_connect(struct connectdata *conn)
438 /* this is FTP and no proxy */
440 struct SessionHandle *data=conn->data;
441 char *buf = data->state.buffer; /* this is our buffer */
446 ftp = (struct FTP *)malloc(sizeof(struct FTP));
448 return CURLE_OUT_OF_MEMORY;
450 memset(ftp, 0, sizeof(struct FTP));
451 conn->proto.ftp = ftp;
453 /* We always support persistant connections on ftp */
454 conn->bits.close = FALSE;
456 /* get some initial data into the ftp struct */
457 ftp->bytecountp = &conn->bytecount;
459 /* no need to duplicate them, this connectdata struct won't change */
460 ftp->user = conn->user;
461 ftp->passwd = conn->passwd;
462 ftp->response_time = 3600; /* set default response time-out */
464 if (data->set.tunnel_thru_httpproxy) {
465 /* We want "seamless" FTP operations through HTTP proxy tunnel */
466 result = Curl_ConnectHTTPProxyTunnel(conn, FIRSTSOCKET,
467 conn->hostname, conn->remote_port);
468 if(CURLE_OK != result)
472 if(conn->protocol & PROT_FTPS) {
473 /* FTPS is simply ftp with SSL for the control channel */
474 /* now, perform the SSL initialization for this socket */
475 result = Curl_SSLConnect(conn, FIRSTSOCKET);
480 /* The first thing we do is wait for the "220*" line: */
481 result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
486 failf(data, "This doesn't seem like a nice ftp-server response");
487 return CURLE_FTP_WEIRD_SERVER_REPLY;
491 /* if not anonymous login, try a secure login */
494 /* request data protection level (default is 'clear') */
495 Curl_sec_request_prot(conn, "private");
497 /* We set private first as default, in case the line below fails to
499 Curl_sec_request_prot(conn, data->set.krb4_level);
501 if(Curl_sec_login(conn) != 0)
502 infof(data, "Logging in with password in cleartext!\n");
504 infof(data, "Authentication successful\n");
508 if(data->set.ftp_ssl && !conn->ssl[FIRSTSOCKET].use) {
509 /* we don't have a SSL/TLS connection, try a FTPS connection now */
511 for (try = 0; ftpauth[try]; try++) {
513 FTPSENDF(conn, "AUTH %s", ftpauth[try]);
515 result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
520 /* RFC2228 (page 5) says:
522 * If the server is willing to accept the named security mechanism, and
523 * does not require any security data, it must respond with reply code
527 if((ftpcode == 234) || (ftpcode == 334)) {
528 result = Curl_SSLConnect(conn, FIRSTSOCKET);
531 conn->protocol |= PROT_FTPS;
532 conn->ssl[SECONDARYSOCKET].use = FALSE; /* clear-text data */
539 FTPSENDF(conn, "USER %s", ftp->user?ftp->user:"");
541 /* wait for feedback */
542 result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
547 /* 530 User ... access denied
548 (the server denies to log the specified user) */
549 failf(data, "Access denied: %s", &buf[4]);
550 return CURLE_FTP_ACCESS_DENIED;
552 else if(ftpcode == 331) {
553 /* 331 Password required for ...
554 (the server requires to send the user's password too) */
555 FTPSENDF(conn, "PASS %s", ftp->passwd?ftp->passwd:"");
556 result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
561 /* 530 Login incorrect.
562 (the username and/or the password are incorrect) */
563 failf(data, "the username and/or the password are incorrect");
564 return CURLE_FTP_USER_PASSWORD_INCORRECT;
566 else if(ftpcode == 230) {
567 /* 230 User ... logged in.
568 (user successfully logged in) */
570 infof(data, "We have successfully logged in\n");
573 failf(data, "Odd return code after PASS");
574 return CURLE_FTP_WEIRD_PASS_REPLY;
577 else if(buf[0] == '2') {
578 /* 230 User ... logged in.
579 (the user logged in without password) */
580 infof(data, "We have successfully logged in\n");
581 if (conn->ssl[FIRSTSOCKET].use) {
583 /* we are logged in (with Kerberos)
584 * now set the requested protection level
586 if(conn->sec_complete)
587 Curl_sec_set_protection_level(conn);
589 /* we may need to issue a KAUTH here to have access to the files
590 * do it if user supplied a password
592 if(conn->passwd && *conn->passwd) {
593 result = Curl_krb_kauth(conn);
601 failf(data, "Odd return code after USER");
602 return CURLE_FTP_WEIRD_USER_REPLY;
605 if(conn->ssl[FIRSTSOCKET].use) {
606 /* PBSZ = PROTECTION BUFFER SIZE.
608 The 'draft-murray-auth-ftp-ssl' (draft 12, page 7) says:
610 Specifically, the PROT command MUST be preceded by a PBSZ command
611 and a PBSZ command MUST be preceded by a successful security data
612 exchange (the TLS negotiation in this case)
616 Thus the PBSZ command must still be issued, but must have a parameter
617 of '0' to indicate that no buffering is taking place and the data
618 connection should not be encapsulated.
620 FTPSENDF(conn, "PBSZ %d", 0);
621 result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
625 /* For TLS, the data connection can have one of two security levels.
627 1)Clear (requested by 'PROT C')
629 2)Private (requested by 'PROT P')
631 if(!conn->ssl[SECONDARYSOCKET].use) {
632 FTPSENDF(conn, "PROT %c", 'P');
633 result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
638 /* We have enabled SSL for the data connection! */
639 conn->ssl[SECONDARYSOCKET].use = TRUE;
641 /* FTP servers typically responds with 500 if they decide to reject
646 /* send PWD to discover our entry point */
647 FTPSENDF(conn, "PWD", NULL);
649 /* wait for feedback */
650 result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
655 char *dir = (char *)malloc(nread+1);
657 char *ptr=&buf[4]; /* start on the first letter */
660 return CURLE_OUT_OF_MEMORY;
662 /* Reply format is like
663 257<space>"<directory-name>"<space><commentary> and the RFC959 says
665 The directory name can contain any character; embedded double-quotes
666 should be escaped by double-quotes (the "quote-doubling" convention).
669 /* it started good */
674 /* "quote-doubling" */
680 *store = '\0'; /* zero terminate */
681 break; /* get out of this loop */
689 ftp->entrypath =dir; /* remember this */
690 infof(data, "Entry path is '%s'\n", ftp->entrypath);
693 /* couldn't get the path */
695 infof(data, "Failed to figure out path\n");
700 /* We couldn't read the PWD response! */
706 /***********************************************************************
710 * The DONE function. This does what needs to be done after a single DO has
713 * Input argument is already checked for validity.
715 CURLcode Curl_ftp_done(struct connectdata *conn)
717 struct SessionHandle *data = conn->data;
718 struct FTP *ftp = conn->proto.ftp;
721 CURLcode result=CURLE_OK;
723 /* free the dir tree parts */
731 if(data->set.upload) {
732 if((-1 != data->set.infilesize) &&
733 (data->set.infilesize != *ftp->bytecountp) &&
735 failf(data, "Uploaded unaligned file size (%" FORMAT_OFF_T
736 " out of %" FORMAT_OFF_T " bytes)",
737 *ftp->bytecountp, data->set.infilesize);
738 conn->bits.close = TRUE; /* close this connection since we don't
739 know what state this error leaves us in */
740 return CURLE_PARTIAL_FILE;
744 if((-1 != conn->size) && (conn->size != *ftp->bytecountp) &&
745 (conn->maxdownload != *ftp->bytecountp)) {
746 failf(data, "Received only partial file: %" FORMAT_OFF_T " bytes",
748 conn->bits.close = TRUE; /* close this connection since we don't
749 know what state this error leaves us in */
750 return CURLE_PARTIAL_FILE;
752 else if(!ftp->dont_check &&
755 /* We consider this an error, but there's no true FTP error received
756 why we need to continue to "read out" the server response too.
757 We don't want to leave a "waiting" server reply if we'll get told
758 to make a second request on this same connection! */
759 failf(data, "No data was received!");
760 result = CURLE_FTP_COULDNT_RETR_FILE;
765 Curl_sec_fflush_fd(conn, conn->sock[SECONDARYSOCKET]);
767 /* shut down the socket to inform the server we're done */
768 sclose(conn->sock[SECONDARYSOCKET]);
769 conn->sock[SECONDARYSOCKET] = -1;
771 if(!ftp->no_transfer) {
772 /* Let's see what the server says about the transfer we just performed,
773 but lower the timeout as sometimes this connection has died while
774 the data has been transfered. This happens when doing through NATs
775 etc that abandon old silent connections.
777 ftp->response_time = 60; /* give it only a minute for now */
779 result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
781 ftp->response_time = 3600; /* set this back to one hour waits */
783 if(!nread && (CURLE_OPERATION_TIMEDOUT == result)) {
784 failf(data, "control connection looks dead");
791 if(!ftp->dont_check) {
792 /* 226 Transfer complete, 250 Requested file action okay, completed. */
793 if((ftpcode != 226) && (ftpcode != 250)) {
794 failf(data, "server did not report OK, got %d", ftpcode);
795 return CURLE_FTP_WRITE_ERROR;
800 /* clear these for next connection */
801 ftp->no_transfer = FALSE;
802 ftp->dont_check = FALSE;
804 /* Send any post-transfer QUOTE strings? */
805 if(!result && data->set.postquote)
806 result = ftp_sendquote(conn, data->set.postquote);
811 /***********************************************************************
815 * Where a 'quote' means a list of custom commands to send to the server.
816 * The quote list is passed as an argument.
820 CURLcode ftp_sendquote(struct connectdata *conn, struct curl_slist *quote)
822 struct curl_slist *item;
830 FTPSENDF(conn, "%s", item->data);
832 result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
836 if (ftpcode >= 400) {
837 failf(conn->data, "QUOT string not accepted: %s", item->data);
838 return CURLE_FTP_QUOTE_ERROR;
848 /***********************************************************************
852 * Get the timestamp of the given file.
855 CURLcode ftp_getfiletime(struct connectdata *conn, char *file)
857 CURLcode result=CURLE_OK;
858 int ftpcode; /* for ftp status */
860 char *buf = conn->data->state.buffer;
862 /* we have requested to get the modified-time of the file, this is yet
863 again a grey area as the MDTM is not kosher RFC959 */
864 FTPSENDF(conn, "MDTM %s", file);
866 result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
873 /* we got a time. Format should be: "YYYYMMDDHHMMSS[.sss]" where the
874 last .sss part is optional and means fractions of a second */
875 int year, month, day, hour, minute, second;
876 if(6 == sscanf(buf+4, "%04d%02d%02d%02d%02d%02d",
877 &year, &month, &day, &hour, &minute, &second)) {
878 /* we have a time, reformat it */
879 time_t secs=time(NULL);
880 sprintf(buf, "%04d%02d%02d %02d:%02d:%02d GMT",
881 year, month, day, hour, minute, second);
882 /* now, convert this into a time() value: */
883 conn->data->info.filetime = curl_getdate(buf, &secs);
888 infof(conn->data, "unsupported MDTM reply format\n");
890 case 550: /* "No such file or directory" */
891 failf(conn->data, "Given file does not exist");
892 result = CURLE_FTP_COULDNT_RETR_FILE;
898 /***********************************************************************
902 * Set transfer type. We only deal with ASCII or BINARY so this function
905 static CURLcode ftp_transfertype(struct connectdata *conn,
908 struct SessionHandle *data = conn->data;
913 FTPSENDF(conn, "TYPE %s", ascii?"A":"I");
915 result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
920 failf(data, "Couldn't set %s mode",
921 ascii?"ASCII":"binary");
922 return ascii? CURLE_FTP_COULDNT_SET_ASCII:CURLE_FTP_COULDNT_SET_BINARY;
928 /***********************************************************************
932 * Returns the file size (in bytes) of the given remote file.
936 CURLcode ftp_getsize(struct connectdata *conn, char *file,
939 struct SessionHandle *data = conn->data;
942 char *buf=data->state.buffer;
945 FTPSENDF(conn, "SIZE %s", file);
946 result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
951 /* get the size from the ascii string: */
952 *size = strtoofft(buf+4, NULL, 0);
955 return CURLE_FTP_COULDNT_GET_SIZE;
960 /***************************************************************************
964 * This function only outputs some informationals about this second connection
965 * when we've issued a PASV command before and thus we have connected to a
966 * possibly new IP address.
970 ftp_pasv_verbose(struct connectdata *conn,
971 Curl_ipconnect *addr,
972 char *newhost, /* ascii version */
976 /*****************************************************************
978 * IPv4-only code section
982 struct hostent * answer;
984 #ifdef HAVE_INET_NTOA_R
987 /* The array size trick below is to make this a large chunk of memory
988 suitably 8-byte aligned on 64-bit platforms. This was thoughtfully
989 suggested by Philip Gladstone. */
990 long bigbuf[9000 / sizeof(long)];
992 #if defined(HAVE_INET_ADDR)
994 # if defined(HAVE_GETHOSTBYADDR_R)
997 char *hostent_buf = (char *)bigbuf; /* get a char * to the buffer */
999 address = inet_addr(newhost);
1000 # ifdef HAVE_GETHOSTBYADDR_R
1002 # ifdef HAVE_GETHOSTBYADDR_R_5
1003 /* AIX, Digital Unix (OSF1, Tru64) style:
1004 extern int gethostbyaddr_r(char *addr, size_t len, int type,
1005 struct hostent *htent, struct hostent_data *ht_data); */
1007 /* Fred Noz helped me try this out, now it at least compiles! */
1009 /* Bjorn Reese (November 28 2001):
1010 The Tru64 man page on gethostbyaddr_r() says that
1011 the hostent struct must be filled with zeroes before the call to
1014 ... as must be struct hostent_data Craig Markwardt 19 Sep 2002. */
1016 memset(hostent_buf, 0, sizeof(struct hostent)+sizeof(struct hostent_data));
1018 if(gethostbyaddr_r((char *) &address,
1019 sizeof(address), AF_INET,
1020 (struct hostent *)hostent_buf,
1021 (struct hostent_data *)(hostent_buf + sizeof(*answer))))
1024 answer=(struct hostent *)hostent_buf;
1027 # ifdef HAVE_GETHOSTBYADDR_R_7
1028 /* Solaris and IRIX */
1029 answer = gethostbyaddr_r((char *) &address, sizeof(address), AF_INET,
1030 (struct hostent *)bigbuf,
1031 hostent_buf + sizeof(*answer),
1032 sizeof(bigbuf) - sizeof(*answer),
1035 # ifdef HAVE_GETHOSTBYADDR_R_8
1037 if(gethostbyaddr_r((char *) &address, sizeof(address), AF_INET,
1038 (struct hostent *)hostent_buf,
1039 hostent_buf + sizeof(*answer),
1040 sizeof(bigbuf) - sizeof(*answer),
1043 answer=NULL; /* error */
1047 (void)hostent_buf; /* avoid compiler warning */
1048 answer = gethostbyaddr((char *) &address, sizeof(address), AF_INET);
1053 (void) memcpy(&in.s_addr, addr, sizeof (Curl_ipconnect));
1054 infof(conn->data, "Connecting to %s (%s) port %u\n",
1055 answer?answer->h_name:newhost,
1056 #if defined(HAVE_INET_NTOA_R)
1057 inet_ntoa_r(in, ntoa_buf, sizeof(ntoa_buf)),
1064 /*****************************************************************
1066 * IPv6-only code section
1068 char hbuf[NI_MAXHOST]; /* ~1KB */
1069 char nbuf[NI_MAXHOST]; /* ~1KB */
1070 char sbuf[NI_MAXSERV]; /* around 32 */
1071 #ifdef NI_WITHSCOPEID
1072 const int niflags = NI_NUMERICHOST | NI_NUMERICSERV | NI_WITHSCOPEID;
1074 const int niflags = NI_NUMERICHOST | NI_NUMERICSERV;
1076 (void)port; /* prevent compiler warning */
1077 if (getnameinfo(addr->ai_addr, addr->ai_addrlen,
1078 nbuf, sizeof(nbuf), sbuf, sizeof(sbuf), niflags)) {
1079 snprintf(nbuf, sizeof(nbuf), "?");
1080 snprintf(sbuf, sizeof(sbuf), "?");
1083 if (getnameinfo(addr->ai_addr, addr->ai_addrlen,
1084 hbuf, sizeof(hbuf), NULL, 0, 0)) {
1085 infof(conn->data, "Connecting to %s (%s) port %s\n", nbuf, newhost, sbuf);
1088 infof(conn->data, "Connecting to %s (%s) port %s\n", hbuf, nbuf, sbuf);
1093 /***********************************************************************
1097 * Send the proper PORT command. PORT is the ftp client's way of telling the
1098 * server that *WE* open a port that we listen on an awaits the server to
1099 * connect to. This is the opposite of PASV.
1103 CURLcode ftp_use_port(struct connectdata *conn)
1105 struct SessionHandle *data=conn->data;
1108 int ftpcode; /* receive FTP response codes in this */
1112 /******************************************************************
1114 * Here's a piece of IPv6-specific code coming up
1118 struct addrinfo hints, *res, *ai;
1119 struct sockaddr_storage ss;
1121 char hbuf[NI_MAXHOST];
1123 struct sockaddr *sa=(struct sockaddr *)&ss;
1124 #ifdef NI_WITHSCOPEID
1125 const int niflags = NI_NUMERICHOST | NI_NUMERICSERV | NI_WITHSCOPEID;
1127 const int niflags = NI_NUMERICHOST | NI_NUMERICSERV;
1131 char portmsgbuf[4096], tmp[4096];
1133 const char *mode[] = { "EPRT", "LPRT", "PORT", NULL };
1138 * we should use Curl_if2ip? given pickiness of recent ftpd,
1139 * I believe we should use the same address as the control connection.
1142 rc = getsockname(conn->sock[FIRSTSOCKET], (struct sockaddr *)&ss, &sslen);
1144 failf(data, "getsockname() returned %d\n", rc);
1145 return CURLE_FTP_PORT_FAILED;
1148 rc = getnameinfo((struct sockaddr *)&ss, sslen, hbuf, sizeof(hbuf), NULL, 0,
1151 failf(data, "getnameinfo() returned %d\n", rc);
1152 return CURLE_FTP_PORT_FAILED;
1155 memset(&hints, 0, sizeof(hints));
1156 hints.ai_family = sa->sa_family;
1157 /*hints.ai_family = ss.ss_family;
1158 this way can be used if sockaddr_storage is properly defined, as glibc
1160 hints.ai_socktype = SOCK_STREAM;
1161 hints.ai_flags = AI_PASSIVE;
1163 rc = getaddrinfo(hbuf, NULL, &hints, &res);
1165 failf(data, "getaddrinfo() returned %d\n", rc);
1166 return CURLE_FTP_PORT_FAILED;
1170 for (ai = res; ai; ai = ai->ai_next) {
1172 * Workaround for AIX5 getaddrinfo() problem (it doesn't set ai_socktype):
1174 if (ai->ai_socktype == 0)
1175 ai->ai_socktype = hints.ai_socktype;
1177 portsock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
1181 if (bind(portsock, ai->ai_addr, ai->ai_addrlen) < 0) {
1187 if (listen(portsock, 1) < 0) {
1197 failf(data, "%s", strerror(errno));
1198 return CURLE_FTP_PORT_FAILED;
1202 if (getsockname(portsock, sa, &sslen) < 0) {
1203 failf(data, "%s", strerror(errno));
1204 return CURLE_FTP_PORT_FAILED;
1207 for (modep = (char **)(data->set.ftp_use_eprt?&mode[0]:&mode[2]);
1208 modep && *modep; modep++) {
1212 switch (sa->sa_family) {
1214 ap = (unsigned char *)&((struct sockaddr_in *)&ss)->sin_addr;
1215 alen = sizeof(((struct sockaddr_in *)&ss)->sin_addr);
1216 pp = (unsigned char *)&((struct sockaddr_in *)&ss)->sin_port;
1217 plen = sizeof(((struct sockaddr_in *)&ss)->sin_port);
1222 ap = (unsigned char *)&((struct sockaddr_in6 *)&ss)->sin6_addr;
1223 alen = sizeof(((struct sockaddr_in6 *)&ss)->sin6_addr);
1224 pp = (unsigned char *)&((struct sockaddr_in6 *)&ss)->sin6_port;
1225 plen = sizeof(((struct sockaddr_in6 *)&ss)->sin6_port);
1231 lprtaf = eprtaf = -1;
1235 if (strcmp(*modep, "EPRT") == 0) {
1238 if (getnameinfo((struct sockaddr *)&ss, sslen,
1239 portmsgbuf, sizeof(portmsgbuf), tmp, sizeof(tmp), niflags))
1242 /* do not transmit IPv6 scope identifier to the wire */
1243 if (sa->sa_family == AF_INET6) {
1244 char *q = strchr(portmsgbuf, '%');
1249 result = Curl_ftpsendf(conn, "%s |%d|%s|%s|", *modep, eprtaf,
1253 } else if (strcmp(*modep, "LPRT") == 0 ||
1254 strcmp(*modep, "PORT") == 0) {
1257 if (strcmp(*modep, "LPRT") == 0 && lprtaf < 0)
1259 if (strcmp(*modep, "PORT") == 0 && sa->sa_family != AF_INET)
1262 portmsgbuf[0] = '\0';
1263 if (strcmp(*modep, "LPRT") == 0) {
1264 snprintf(tmp, sizeof(tmp), "%d,%d", lprtaf, alen);
1265 if (strlcat(portmsgbuf, tmp, sizeof(portmsgbuf)) >=
1266 sizeof(portmsgbuf)) {
1271 for (i = 0; i < alen; i++) {
1273 snprintf(tmp, sizeof(tmp), ",%u", ap[i]);
1275 snprintf(tmp, sizeof(tmp), "%u", ap[i]);
1277 if (strlcat(portmsgbuf, tmp, sizeof(portmsgbuf)) >=
1278 sizeof(portmsgbuf)) {
1283 if (strcmp(*modep, "LPRT") == 0) {
1284 snprintf(tmp, sizeof(tmp), ",%d", plen);
1286 if (strlcat(portmsgbuf, tmp, sizeof(portmsgbuf)) >= sizeof(portmsgbuf))
1290 for (i = 0; i < plen; i++) {
1291 snprintf(tmp, sizeof(tmp), ",%u", pp[i]);
1293 if (strlcat(portmsgbuf, tmp, sizeof(portmsgbuf)) >=
1294 sizeof(portmsgbuf)) {
1299 result = Curl_ftpsendf(conn, "%s %s", *modep, portmsgbuf);
1304 result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
1308 if (ftpcode != 200) {
1317 failf(data, "PORT command attempts failed");
1318 return CURLE_FTP_PORT_FAILED;
1320 /* we set the secondary socket variable to this for now, it
1321 is only so that the cleanup function will close it in case
1322 we fail before the true secondary stuff is made */
1323 conn->sock[SECONDARYSOCKET] = portsock;
1326 /******************************************************************
1328 * Here's a piece of IPv4-specific code coming up
1331 struct sockaddr_in sa;
1332 struct Curl_dns_entry *h=NULL;
1333 unsigned short porttouse;
1334 char myhost[256] = "";
1335 bool sa_filled_in = FALSE;
1337 if(data->set.ftpport) {
1341 /* First check if the given name is an IP address */
1342 in=inet_addr(data->set.ftpport);
1344 if((in == CURL_INADDR_NONE) &&
1345 Curl_if2ip(data->set.ftpport, myhost, sizeof(myhost))) {
1346 rc = Curl_resolv(conn, myhost, 0, &h);
1348 rc = Curl_wait_for_resolv(conn, &h);
1351 size_t len = strlen(data->set.ftpport);
1353 rc = Curl_resolv(conn, data->set.ftpport, 0, &h);
1355 rc = Curl_wait_for_resolv(conn, &h);
1358 strcpy(myhost, data->set.ftpport); /* buffer overflow risk */
1362 /* pick a suitable default here */
1367 if (getsockname(conn->sock[FIRSTSOCKET],
1368 (struct sockaddr *)&sa, &sslen) < 0) {
1369 failf(data, "getsockname() failed");
1370 return CURLE_FTP_PORT_FAILED;
1373 sa_filled_in = TRUE; /* the sa struct is filled in */
1377 /* when we return from here, we can forget about this */
1378 Curl_resolv_unlock(data, h);
1380 if ( h || sa_filled_in) {
1381 if( (portsock = socket(AF_INET, SOCK_STREAM, 0)) >= 0 ) {
1384 /* we set the secondary socket variable to this for now, it
1385 is only so that the cleanup function will close it in case
1386 we fail before the true secondary stuff is made */
1387 conn->sock[SECONDARYSOCKET] = portsock;
1390 memset((char *)&sa, 0, sizeof(sa));
1391 memcpy((char *)&sa.sin_addr,
1394 sa.sin_family = AF_INET;
1395 sa.sin_addr.s_addr = INADDR_ANY;
1401 if(bind(portsock, (struct sockaddr *)&sa, size) >= 0) {
1402 /* we succeeded to bind */
1403 struct sockaddr_in add;
1404 socklen_t socksize = sizeof(add);
1406 if(getsockname(portsock, (struct sockaddr *) &add,
1408 failf(data, "getsockname() failed");
1409 return CURLE_FTP_PORT_FAILED;
1411 porttouse = ntohs(add.sin_port);
1413 if ( listen(portsock, 1) < 0 ) {
1414 failf(data, "listen(2) failed on socket");
1415 return CURLE_FTP_PORT_FAILED;
1419 failf(data, "bind(2) failed on socket");
1420 return CURLE_FTP_PORT_FAILED;
1424 failf(data, "socket(2) failed (%s)");
1425 return CURLE_FTP_PORT_FAILED;
1429 failf(data, "could't find my own IP address (%s)", myhost);
1430 return CURLE_FTP_PORT_FAILED;
1433 #ifdef HAVE_INET_NTOA_R
1437 unsigned short ip[5];
1438 (void) memcpy(&in.s_addr,
1439 h?*h->addr->h_addr_list:(char *)&sa.sin_addr.s_addr,
1440 sizeof (in.s_addr));
1442 #ifdef HAVE_INET_NTOA_R
1443 /* ignore the return code from inet_ntoa_r() as it is int or
1444 char * depending on system */
1445 inet_ntoa_r(in, ntoa_buf, sizeof(ntoa_buf));
1446 sscanf( ntoa_buf, "%hu.%hu.%hu.%hu",
1447 &ip[0], &ip[1], &ip[2], &ip[3]);
1449 sscanf( inet_ntoa(in), "%hu.%hu.%hu.%hu",
1450 &ip[0], &ip[1], &ip[2], &ip[3]);
1452 infof(data, "Telling server to connect to %d.%d.%d.%d:%d\n",
1453 ip[0], ip[1], ip[2], ip[3], porttouse);
1455 result=Curl_ftpsendf(conn, "PORT %d,%d,%d,%d,%d,%d",
1456 ip[0], ip[1], ip[2], ip[3],
1463 result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
1467 if(ftpcode != 200) {
1468 failf(data, "Server does not grok PORT, try without it!");
1469 return CURLE_FTP_PORT_FAILED;
1471 #endif /* end of ipv4-specific code */
1476 /***********************************************************************
1480 * Send the PASV command. PASV is the ftp client's way of asking the server to
1481 * open a second port that we can connect to (for the data transfer). This is
1482 * the opposite of PORT.
1486 CURLcode ftp_use_pasv(struct connectdata *conn,
1489 struct SessionHandle *data = conn->data;
1491 char *buf = data->state.buffer; /* this is our buffer */
1492 int ftpcode; /* receive FTP response codes in this */
1494 struct Curl_dns_entry *addr=NULL;
1495 Curl_ipconnect *conninfo;
1499 Here's the excecutive summary on what to do:
1501 PASV is RFC959, expect:
1502 227 Entering Passive Mode (a1,a2,a3,a4,p1,p2)
1504 LPSV is RFC1639, expect:
1505 228 Entering Long Passive Mode (4,4,a1,a2,a3,a4,2,p1,p2)
1507 EPSV is RFC2428, expect:
1508 229 Entering Extended Passive Mode (|||port|)
1512 const char *mode[] = { "EPSV", "PASV", NULL };
1513 int results[] = { 229, 227, 0 };
1515 unsigned short connectport; /* the local port connect() should use! */
1516 unsigned short newport=0; /* remote port, not necessary the local one */
1518 /* newhost must be able to hold a full IP-style address in ASCII, which
1519 in the IPv6 case means 5*8-1 = 39 letters */
1521 char *newhostp=NULL;
1523 for (modeoff = (data->set.ftp_use_epsv?0:1);
1524 mode[modeoff]; modeoff++) {
1525 result = Curl_ftpsendf(conn, "%s", mode[modeoff]);
1528 result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
1531 if (ftpcode == results[modeoff])
1535 if (!mode[modeoff]) {
1536 failf(data, "Odd return code after PASV");
1537 return CURLE_FTP_WEIRD_PASV_REPLY;
1539 else if (227 == results[modeoff]) {
1545 * New 227-parser June 3rd 1999.
1546 * It now scans for a sequence of six comma-separated numbers and
1547 * will take them as IP+port indicators.
1549 * Found reply-strings include:
1550 * "227 Entering Passive Mode (127,0,0,1,4,51)"
1551 * "227 Data transfer will passively listen to 127,0,0,1,4,51"
1552 * "227 Entering passive mode. 127,0,0,1,4,51"
1556 if (6 == sscanf(str, "%d,%d,%d,%d,%d,%d",
1557 &ip[0], &ip[1], &ip[2], &ip[3],
1558 &port[0], &port[1]))
1564 failf(data, "Couldn't interpret this 227-reply: %s", buf);
1565 return CURLE_FTP_WEIRD_227_FORMAT;
1568 sprintf(newhost, "%d.%d.%d.%d", ip[0], ip[1], ip[2], ip[3]);
1570 newport = (port[0]<<8) + port[1];
1572 else if (229 == results[modeoff]) {
1573 char *ptr = strchr(buf, '(');
1578 if(5 == sscanf(ptr, "%c%c%c%u%c",
1584 char sep1 = separator[0];
1587 /* The four separators should be identical, or else this is an oddly
1588 formatted reply and we bail out immediately. */
1589 for(i=1; i<4; i++) {
1590 if(separator[i] != sep1) {
1591 ptr=NULL; /* set to NULL to signal error */
1598 /* we should use the same host we already are connected to */
1599 newhostp = conn->name;
1606 failf(data, "Weirdly formatted EPSV reply");
1607 return CURLE_FTP_WEIRD_PASV_REPLY;
1611 return CURLE_FTP_CANT_RECONNECT;
1613 if(data->change.proxy && *data->change.proxy) {
1615 * This is a tunnel through a http proxy and we need to connect to the
1618 * We don't want to rely on a former host lookup that might've expired
1619 * now, instead we remake the lookup here and now!
1621 rc = Curl_resolv(conn, conn->proxyhost, conn->port, &addr);
1623 rc = Curl_wait_for_resolv(conn, &addr);
1626 (unsigned short)conn->port; /* we connect to the proxy's port */
1630 /* normal, direct, ftp connection */
1631 rc = Curl_resolv(conn, newhostp, newport, &addr);
1633 rc = Curl_wait_for_resolv(conn, &addr);
1636 failf(data, "Can't resolve new host %s:%d", newhostp, newport);
1637 return CURLE_FTP_CANT_GET_HOST;
1639 connectport = newport; /* we connect to the remote port */
1642 result = Curl_connecthost(conn,
1645 &conn->sock[SECONDARYSOCKET],
1649 Curl_resolv_unlock(data, addr); /* we're done using this address */
1655 * When this is used from the multi interface, this might've returned with
1656 * the 'connected' set to FALSE and thus we are now awaiting a non-blocking
1657 * connect to connect and we should not be "hanging" here waiting.
1660 if(data->set.verbose)
1661 /* this just dumps information about this second connection */
1662 ftp_pasv_verbose(conn, conninfo, newhostp, connectport);
1664 if(data->set.tunnel_thru_httpproxy) {
1665 /* We want "seamless" FTP operations through HTTP proxy tunnel */
1666 result = Curl_ConnectHTTPProxyTunnel(conn, SECONDARYSOCKET,
1668 if(CURLE_OK != result)
1676 * Curl_ftp_nextconnect()
1678 * This function shall be called when the second FTP connection has been
1679 * established and is confirmed connected.
1682 CURLcode Curl_ftp_nextconnect(struct connectdata *conn)
1684 struct SessionHandle *data=conn->data;
1685 char *buf = data->state.buffer; /* this is our buffer */
1688 int ftpcode; /* for ftp status */
1690 /* the ftp struct is already inited in Curl_ftp_connect() */
1691 struct FTP *ftp = conn->proto.ftp;
1692 curl_off_t *bytecountp = ftp->bytecountp;
1694 if(data->set.upload) {
1696 /* Set type to binary (unless specified ASCII) */
1697 result = ftp_transfertype(conn, data->set.ftp_ascii);
1701 /* Send any PREQUOTE strings after transfer type is set? (Wesley Laxton)*/
1702 if(data->set.prequote) {
1703 if ((result = ftp_sendquote(conn, data->set.prequote)) != CURLE_OK)
1707 if(conn->resume_from) {
1708 /* we're about to continue the uploading of a file */
1709 /* 1. get already existing file's size. We use the SIZE
1710 command for this which may not exist in the server!
1711 The SIZE command is not in RFC959. */
1713 /* 2. This used to set REST. But since we can do append, we
1714 don't another ftp command. We just skip the source file
1715 offset and then we APPEND the rest on the file instead */
1717 /* 3. pass file-size number of bytes in the source file */
1718 /* 4. lower the infilesize counter */
1719 /* => transfer as usual */
1721 if(conn->resume_from < 0 ) {
1722 /* we could've got a specified offset from the command line,
1723 but now we know we didn't */
1724 curl_off_t gottensize;
1726 if(CURLE_OK != ftp_getsize(conn, ftp->file, &gottensize)) {
1727 failf(data, "Couldn't get remote file size");
1728 return CURLE_FTP_COULDNT_GET_SIZE;
1730 conn->resume_from = gottensize;
1733 if(conn->resume_from) {
1734 /* do we still game? */
1735 curl_off_t passed=0;
1736 /* enable append instead */
1737 data->set.ftp_append = 1;
1739 /* Now, let's read off the proper amount of bytes from the
1740 input. If we knew it was a proper file we could've just
1741 fseek()ed but we only have a stream here */
1743 curl_off_t readthisamountnow = (conn->resume_from - passed);
1744 curl_off_t actuallyread;
1746 if(readthisamountnow > BUFSIZE)
1747 readthisamountnow = BUFSIZE;
1750 conn->fread(data->state.buffer, 1, (size_t)readthisamountnow,
1753 passed += actuallyread;
1754 if(actuallyread != readthisamountnow) {
1755 failf(data, "Could only read %" FORMAT_OFF_T
1756 " bytes from the input", passed);
1757 return CURLE_FTP_COULDNT_USE_REST;
1760 while(passed != conn->resume_from);
1762 /* now, decrease the size of the read */
1763 if(data->set.infilesize>0) {
1764 data->set.infilesize -= conn->resume_from;
1766 if(data->set.infilesize <= 0) {
1767 infof(data, "File already completely uploaded\n");
1769 /* no data to transfer */
1770 result=Curl_Transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
1772 /* Set no_transfer so that we won't get any error in
1773 * Curl_ftp_done() because we didn't transfer anything! */
1774 ftp->no_transfer = TRUE;
1779 /* we've passed, proceed as normal */
1783 /* Send everything on data->state.in to the socket */
1784 if(data->set.ftp_append) {
1785 /* we append onto the file instead of rewriting it */
1786 FTPSENDF(conn, "APPE %s", ftp->file);
1789 FTPSENDF(conn, "STOR %s", ftp->file);
1792 result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
1797 failf(data, "Failed FTP upload:%s", buf+3);
1798 /* oops, we never close the sockets! */
1799 return CURLE_FTP_COULDNT_STOR_FILE;
1802 if(data->set.ftp_use_port) {
1803 /* PORT means we are now awaiting the server to connect to us. */
1804 result = AllowServerConnect(conn);
1809 if(conn->ssl[SECONDARYSOCKET].use) {
1810 /* since we only have a plaintext TCP connection here, we must now
1812 infof(data, "Doing the SSL/TLS handshake on the data stream\n");
1813 result = Curl_SSLConnect(conn, SECONDARYSOCKET);
1820 /* When we know we're uploading a specified file, we can get the file
1821 size prior to the actual upload. */
1823 Curl_pgrsSetUploadSize(data, (double)data->set.infilesize);
1825 result = Curl_Transfer(conn, -1, -1, FALSE, NULL, /* no download */
1826 SECONDARYSOCKET, bytecountp);
1831 else if(!data->set.no_body) {
1832 /* Retrieve file or directory */
1834 curl_off_t downloadsize=-1;
1836 if(conn->bits.use_range && conn->range) {
1837 curl_off_t from, to;
1838 curl_off_t totalsize=-1;
1842 from=strtoofft(conn->range, &ptr, 0);
1843 while(ptr && *ptr && (isspace((int)*ptr) || (*ptr=='-')))
1845 to=strtoofft(ptr, &ptr2, 0);
1847 /* we didn't get any digit */
1850 if((-1 == to) && (from>=0)) {
1852 conn->resume_from = from;
1853 infof(data, "FTP RANGE %" FORMAT_OFF_T " to end of file\n", from);
1858 conn->maxdownload = -from;
1859 conn->resume_from = from;
1860 infof(data, "FTP RANGE the last %" FORMAT_OFF_T " bytes\n", totalsize);
1864 totalsize = to-from;
1865 conn->maxdownload = totalsize+1; /* include the last mentioned byte */
1866 conn->resume_from = from;
1867 infof(data, "FTP RANGE from %" FORMAT_OFF_T
1868 " getting %" FORMAT_OFF_T " bytes\n", from, conn->maxdownload);
1870 infof(data, "range-download from %" FORMAT_OFF_T
1871 " to %" FORMAT_OFF_T ", totally %" FORMAT_OFF_T " bytes\n",
1872 from, to, conn->maxdownload);
1873 ftp->dont_check = TRUE; /* dont check for successful transfer */
1876 if((data->set.ftp_list_only) || !ftp->file) {
1877 /* The specified path ends with a slash, and therefore we think this
1878 is a directory that is requested, use LIST. But before that we
1879 need to set ASCII transfer mode. */
1882 /* Set type to ASCII */
1883 result = ftp_transfertype(conn, TRUE /* ASCII enforced */);
1887 /* if this output is to be machine-parsed, the NLST command will be
1888 better used since the LIST command output is not specified or
1889 standard in any way */
1891 FTPSENDF(conn, "%s",
1892 data->set.customrequest?data->set.customrequest:
1893 (data->set.ftp_list_only?"NLST":"LIST"));
1896 curl_off_t foundsize;
1898 /* Set type to binary (unless specified ASCII) */
1899 result = ftp_transfertype(conn, data->set.ftp_ascii);
1903 /* Send any PREQUOTE strings after transfer type is set? */
1904 if(data->set.prequote) {
1905 if ((result = ftp_sendquote(conn, data->set.prequote)) != CURLE_OK)
1909 /* Attempt to get the size, it'll be useful in some cases: for resumed
1910 downloads and when talking to servers that don't give away the size
1911 in the RETR response line. */
1912 result = ftp_getsize(conn, ftp->file, &foundsize);
1913 if(CURLE_OK == result) {
1914 if (data->set.max_filesize && foundsize > data->set.max_filesize) {
1915 failf(data, "Maximum file size exceeded");
1916 return CURLE_FILESIZE_EXCEEDED;
1918 downloadsize = foundsize;
1921 if(conn->resume_from) {
1923 /* Daniel: (August 4, 1999)
1925 * We start with trying to use the SIZE command to figure out the size
1926 * of the file we're gonna get. If we can get the size, this is by far
1927 * the best way to know if we're trying to resume beyond the EOF.
1929 * Daniel, November 28, 2001. We *always* get the size on downloads
1930 * now, so it is done before this even when not doing resumes. I saved
1931 * the comment above for nostalgical reasons! ;-)
1933 if(CURLE_OK != result) {
1934 infof(data, "ftp server doesn't support SIZE\n");
1935 /* We couldn't get the size and therefore we can't know if there
1936 really is a part of the file left to get, although the server
1937 will just close the connection when we start the connection so it
1938 won't cause us any harm, just not make us exit as nicely. */
1941 /* We got a file size report, so we check that there actually is a
1942 part of the file left to get, or else we go home. */
1943 if(conn->resume_from< 0) {
1944 /* We're supposed to download the last abs(from) bytes */
1945 if(foundsize < -conn->resume_from) {
1946 failf(data, "Offset (%" FORMAT_OFF_T
1947 ") was beyond file size (%" FORMAT_OFF_T ")",
1948 conn->resume_from, foundsize);
1949 return CURLE_FTP_BAD_DOWNLOAD_RESUME;
1951 /* convert to size to download */
1952 downloadsize = -conn->resume_from;
1953 /* download from where? */
1954 conn->resume_from = foundsize - downloadsize;
1957 if(foundsize < conn->resume_from) {
1958 failf(data, "Offset (%" FORMAT_OFF_T
1959 ") was beyond file size (%" FORMAT_OFF_T ")",
1960 conn->resume_from, foundsize);
1961 return CURLE_FTP_BAD_DOWNLOAD_RESUME;
1963 /* Now store the number of bytes we are expected to download */
1964 downloadsize = foundsize-conn->resume_from;
1968 if (downloadsize == 0) {
1969 /* no data to transfer */
1970 result=Curl_Transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
1971 infof(data, "File already completely downloaded\n");
1973 /* Set no_transfer so that we won't get any error in Curl_ftp_done()
1974 * because we didn't transfer the any file */
1975 ftp->no_transfer = TRUE;
1979 /* Set resume file transfer offset */
1980 infof(data, "Instructs server to resume from offset %" FORMAT_OFF_T
1984 FTPSENDF(conn, "REST %" FORMAT_OFF_T, conn->resume_from);
1986 result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
1990 if(ftpcode != 350) {
1991 failf(data, "Couldn't use REST: %s", buf+4);
1992 return CURLE_FTP_COULDNT_USE_REST;
1996 FTPSENDF(conn, "RETR %s", ftp->file);
1999 result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
2003 if((ftpcode == 150) || (ftpcode == 125)) {
2007 150 Opening BINARY mode data connection for /etc/passwd (2241
2008 bytes). (ok, the file is being transfered)
2011 150 Opening ASCII mode data connection for /bin/ls
2014 150 ASCII data connection for /bin/ls (137.167.104.91,37445) (0 bytes).
2017 150 Opening ASCII mode data connection for /linux/fisk/kpanelrc (0.0.0.0,0) (545 bytes).
2020 125 Data connection already open; Transfer starting. */
2022 curl_off_t size=-1; /* default unknown size */
2026 * It appears that there are FTP-servers that return size 0 for files
2027 * when SIZE is used on the file while being in BINARY mode. To work
2028 * around that (stupid) behavior, we attempt to parse the RETR response
2029 * even if the SIZE returned size zero.
2031 * Debugging help from Salvatore Sorrentino on February 26, 2003.
2035 !data->set.ftp_ascii &&
2036 (downloadsize < 1)) {
2038 * It seems directory listings either don't show the size or very
2039 * often uses size 0 anyway. ASCII transfers may very well turn out
2040 * that the transfered amount of data is not the same as this line
2041 * tells, why using this number in those cases only confuses us.
2043 * Example D above makes this parsing a little tricky */
2045 bytes=strstr(buf, " bytes");
2048 /* this is a hint there is size information in there! ;-) */
2050 /* scan for the parenthesis and break there */
2053 /* if only skip digits, or else we're in deep trouble */
2054 if(!isdigit((int)*bytes)) {
2058 /* one more estep backwards */
2061 /* only if we have nothing but digits: */
2063 /* get the number! */
2064 size = strtoofft(bytes, NULL, 0);
2069 else if(downloadsize > -1)
2070 size = downloadsize;
2072 if(data->set.ftp_use_port) {
2073 result = AllowServerConnect(conn);
2078 if(conn->ssl[SECONDARYSOCKET].use) {
2079 /* since we only have a plaintext TCP connection here, we must now
2081 infof(data, "Doing the SSL/TLS handshake on the data stream\n");
2082 result = Curl_SSLConnect(conn, SECONDARYSOCKET);
2087 if(size > conn->maxdownload && conn->maxdownload > 0)
2088 size = conn->size = conn->maxdownload;
2090 infof(data, "Getting file with size: %" FORMAT_OFF_T "\n", size);
2093 result=Curl_Transfer(conn, SECONDARYSOCKET, size, FALSE,
2095 -1, NULL); /* no upload here */
2100 if(dirlist && (ftpcode == 450)) {
2101 /* simply no matching files */
2102 ftp->no_transfer = TRUE; /* don't think we should download anything */
2105 failf(data, "%s", buf+4);
2106 return CURLE_FTP_COULDNT_RETR_FILE;
2111 /* end of transfer */
2116 /***********************************************************************
2120 * This is the actual DO function for FTP. Get a file/directory according to
2121 * the options previously setup.
2125 CURLcode ftp_perform(struct connectdata *conn,
2126 bool *connected) /* for the TCP connect status after
2129 /* this is FTP and no proxy */
2130 CURLcode result=CURLE_OK;
2131 struct SessionHandle *data=conn->data;
2132 char *buf = data->state.buffer; /* this is our buffer */
2134 /* the ftp struct is already inited in Curl_ftp_connect() */
2135 struct FTP *ftp = conn->proto.ftp;
2137 /* Send any QUOTE strings? */
2138 if(data->set.quote) {
2139 if ((result = ftp_sendquote(conn, data->set.quote)) != CURLE_OK)
2143 /* This is a re-used connection. Since we change directory to where the
2144 transfer is taking place, we must now get back to the original dir
2145 where we ended up after login: */
2146 if (conn->bits.reuse && ftp->entrypath) {
2147 if ((result = ftp_cwd_and_mkd(conn, ftp->entrypath)) != CURLE_OK)
2152 int i; /* counter for loop */
2153 for (i=0; ftp->dirs[i]; i++) {
2154 /* RFC 1738 says empty components should be respected too, but
2155 that is plain stupid since CWD can't be used with an empty argument */
2156 if ((result = ftp_cwd_and_mkd(conn, ftp->dirs[i])) != CURLE_OK)
2161 /* Requested time of file or time-depended transfer? */
2162 if((data->set.get_filetime || data->set.timecondition) &&
2164 result = ftp_getfiletime(conn, ftp->file);
2167 case CURLE_FTP_COULDNT_RETR_FILE:
2169 if(data->set.timecondition) {
2170 if((data->info.filetime > 0) && (data->set.timevalue > 0)) {
2171 switch(data->set.timecondition) {
2172 case CURL_TIMECOND_IFMODSINCE:
2174 if(data->info.filetime < data->set.timevalue) {
2175 infof(data, "The requested document is not new enough\n");
2176 ftp->no_transfer = TRUE; /* mark this to not transfer data */
2180 case CURL_TIMECOND_IFUNMODSINCE:
2181 if(data->info.filetime > data->set.timevalue) {
2182 infof(data, "The requested document is not old enough\n");
2183 ftp->no_transfer = TRUE; /* mark this to not transfer data */
2190 infof(data, "Skipping time comparison\n");
2199 /* If we have selected NOBODY and HEADER, it means that we only want file
2200 information. Which in FTP can't be much more than the file size and
2202 if(data->set.no_body && data->set.include_header && ftp->file) {
2203 /* The SIZE command is _not_ RFC 959 specified, and therefor many servers
2204 may not support it! It is however the only way we have to get a file's
2206 curl_off_t filesize;
2210 ftp->no_transfer = TRUE; /* this means no actual transfer is made */
2212 /* Some servers return different sizes for different modes, and thus we
2213 must set the proper type before we check the size */
2214 result = ftp_transfertype(conn, data->set.ftp_ascii);
2218 /* failing to get size is not a serious error */
2219 result = ftp_getsize(conn, ftp->file, &filesize);
2221 if(CURLE_OK == result) {
2222 sprintf(buf, "Content-Length: %" FORMAT_OFF_T "\r\n", filesize);
2223 result = Curl_client_write(data, CLIENTWRITE_BOTH, buf, 0);
2228 /* Determine if server can respond to REST command and therefore
2229 whether it can do a range */
2230 FTPSENDF(conn, "REST 0", NULL);
2231 result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
2233 if ((CURLE_OK == result) && (ftpcode == 350)) {
2234 result = Curl_client_write(data, CLIENTWRITE_BOTH,
2235 (char *)"Accept-ranges: bytes\r\n", 0);
2240 /* If we asked for a time of the file and we actually got one as
2241 well, we "emulate" a HTTP-style header in our output. */
2243 #ifdef HAVE_STRFTIME
2244 if(data->set.get_filetime && (data->info.filetime>=0) ) {
2246 time_t clock = (time_t)data->info.filetime;
2247 #ifdef HAVE_GMTIME_R
2249 tm = (struct tm *)gmtime_r(&clock, &buffer);
2251 tm = gmtime(&clock);
2253 /* format: "Tue, 15 Nov 1994 12:45:26" */
2254 strftime(buf, BUFSIZE-1, "Last-Modified: %a, %d %b %Y %H:%M:%S GMT\r\n",
2256 result = Curl_client_write(data, CLIENTWRITE_BOTH, buf, 0);
2265 if(data->set.no_body)
2266 /* doesn't really transfer any data */
2267 ftp->no_transfer = TRUE;
2268 /* Get us a second connection up and connected */
2269 else if(data->set.ftp_use_port) {
2270 /* We have chosen to use the PORT command */
2271 result = ftp_use_port(conn);
2272 if(CURLE_OK == result) {
2273 /* we have the data connection ready */
2274 infof(data, "Ordered connect of the data stream with PORT!\n");
2275 *connected = TRUE; /* mark us "still connected" */
2279 /* We have chosen (this is default) to use the PASV command */
2280 result = ftp_use_pasv(conn, connected);
2281 if(CURLE_OK == result && *connected)
2282 infof(data, "Connected the data stream with PASV!\n");
2288 /***********************************************************************
2292 * This function is registered as 'curl_do' function. It decodes the path
2293 * parts etc as a wrapper to the actual DO function (ftp_perform).
2295 * The input argument is already checked for validity.
2297 * ftp->ctl_valid starts out as FALSE, and gets set to TRUE if we reach the
2298 * end of the function.
2300 CURLcode Curl_ftp(struct connectdata *conn)
2302 CURLcode retcode=CURLE_OK;
2304 struct SessionHandle *data = conn->data;
2307 char *slash_pos; /* position of the first '/' char in curpos */
2308 char *cur_pos=conn->ppath; /* current position in ppath. point at the begin
2309 of next path component */
2310 int path_part=0;/* current path component */
2312 /* the ftp struct is already inited in ftp_connect() */
2313 ftp = conn->proto.ftp;
2314 ftp->ctl_valid = FALSE;
2315 conn->size = -1; /* make sure this is unknown at this point */
2317 Curl_pgrsSetUploadCounter(data, 0);
2318 Curl_pgrsSetDownloadCounter(data, 0);
2319 Curl_pgrsSetUploadSize(data, 0);
2320 Curl_pgrsSetDownloadSize(data, 0);
2322 /* fixed : initialize ftp->dirs[xxx] to NULL !
2323 is done in Curl_ftp_connect() */
2325 /* parse the URL path into separate path components */
2326 while((slash_pos=strchr(cur_pos, '/'))) {
2327 /* 1 or 0 to indicate absolute directory */
2328 bool absolute_dir = (cur_pos - conn->ppath > 0) && (path_part == 0);
2330 /* seek out the next path component */
2331 if (slash_pos-cur_pos) {
2332 /* we skip empty path components, like "x//y" since the FTP command CWD
2333 requires a parameter and a non-existant parameter a) doesn't work on
2334 many servers and b) has no effect on the others. */
2335 ftp->dirs[path_part] = curl_unescape(cur_pos - absolute_dir,
2336 slash_pos - cur_pos + absolute_dir);
2338 if (!ftp->dirs[path_part]) { /* run out of memory ... */
2339 failf(data, "no memory");
2341 return CURLE_OUT_OF_MEMORY;
2345 cur_pos = slash_pos + 1; /* jump to the rest of the string */
2350 cur_pos = slash_pos + 1; /* jump to the rest of the string */
2351 if(++path_part >= (CURL_MAX_FTP_DIRDEPTH-1)) {
2352 /* too deep, we need the last entry to be kept NULL at all
2353 times to signal end of list */
2354 failf(data, "too deep dir hierarchy");
2356 return CURLE_URL_MALFORMAT;
2361 ftp->file = cur_pos; /* the rest is the file name */
2364 ftp->file = curl_unescape(ftp->file, 0);
2365 if(NULL == ftp->file) {
2367 failf(data, "no memory");
2368 return CURLE_OUT_OF_MEMORY;
2372 ftp->file=NULL; /* instead of point to a zero byte, we make it a NULL
2375 retcode = ftp_perform(conn, &connected);
2377 if(CURLE_OK == retcode) {
2379 retcode = Curl_ftp_nextconnect(conn);
2381 if(retcode && (conn->sock[SECONDARYSOCKET] >= 0)) {
2382 /* Failure detected, close the second socket if it was created already */
2383 sclose(conn->sock[SECONDARYSOCKET]);
2384 conn->sock[SECONDARYSOCKET] = -1;
2387 if(ftp->no_transfer)
2388 /* no data to transfer */
2389 retcode=Curl_Transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
2391 /* since we didn't connect now, we want do_more to get called */
2392 conn->bits.do_more = TRUE;
2397 ftp->ctl_valid = TRUE;
2401 /***********************************************************************
2405 * Sends the formated string as a ftp command to a ftp server
2407 * NOTE: we build the command in a fixed-length buffer, which sets length
2408 * restrictions on the command!
2410 CURLcode Curl_ftpsendf(struct connectdata *conn,
2411 const char *fmt, ...)
2413 ssize_t bytes_written;
2417 CURLcode res = CURLE_OK;
2421 vsnprintf(s, 250, fmt, ap);
2424 strcat(s, "\r\n"); /* append a trailing CRLF */
2427 write_len = strlen(s);
2430 res = Curl_write(conn, conn->sock[FIRSTSOCKET], sptr, write_len,
2436 if(conn->data->set.verbose)
2437 Curl_debug(conn->data, CURLINFO_HEADER_OUT, sptr, bytes_written);
2439 if(bytes_written != (ssize_t)write_len) {
2440 write_len -= bytes_written;
2441 sptr += bytes_written;
2450 /***********************************************************************
2454 * This should be called before calling sclose() on an ftp control connection
2455 * (not data connections). We should then wait for the response from the
2456 * server before returning. The calling code should then try to close the
2460 CURLcode Curl_ftp_quit(struct connectdata *conn)
2464 CURLcode ret = CURLE_OK;
2466 if(conn->proto.ftp->ctl_valid) {
2467 ret = Curl_ftpsendf(conn, "%s", "QUIT");
2469 ret = Curl_GetFTPResponse(&nread, conn, &ftpcode);
2475 /***********************************************************************
2477 * Curl_ftp_disconnect()
2479 * Disconnect from an FTP server. Cleanup protocol-specific per-connection
2482 CURLcode Curl_ftp_disconnect(struct connectdata *conn)
2484 struct FTP *ftp= conn->proto.ftp;
2486 /* We cannot send quit unconditionally. If this connection is stale or
2487 bad in any way, sending quit and waiting around here will make the
2488 disconnect wait in vain and cause more problems than we need to.
2490 Curl_ftp_quit() will check the state of ftp->ctl_valid. If it's ok it
2491 will try to send the QUIT command, otherwise it will just return.
2494 /* The FTP session may or may not have been allocated/setup at this point! */
2496 (void)Curl_ftp_quit(conn); /* ignore errors on the QUIT */
2499 free(ftp->entrypath);
2506 ftp->file = NULL; /* zero */
2513 /***********************************************************************
2517 * Makes a directory on the FTP server.
2521 CURLcode ftp_mkd(struct connectdata *conn, char *path)
2523 CURLcode result=CURLE_OK;
2524 int ftpcode; /* for ftp status */
2527 /* Create a directory on the remote server */
2528 FTPSENDF(conn, "MKD %s", path);
2530 result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
2537 infof( conn->data , "Created remote directory %s\n" , path );
2540 failf(conn->data, "Permission denied to make directory %s", path);
2541 result = CURLE_FTP_ACCESS_DENIED;
2544 failf(conn->data, "unrecognized MKD response: %d", ftpcode );
2545 result = CURLE_FTP_ACCESS_DENIED;
2551 /***********************************************************************
2555 * Send 'CWD' to the remote server to Change Working Directory. It is the ftp
2556 * version of the unix 'cd' command. This function is only called from the
2557 * ftp_cwd_and_mkd() function these days.
2559 * This function does NOT call failf().
2562 CURLcode ftp_cwd(struct connectdata *conn, char *path)
2568 FTPSENDF(conn, "CWD %s", path);
2569 result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
2571 /* According to RFC959, CWD is supposed to return 250 on success, but
2572 there seem to be non-compliant FTP servers out there that return 200,
2573 so we accept any '2xy' code here. */
2574 if (ftpcode/100 != 2)
2575 result = CURLE_FTP_ACCESS_DENIED;
2581 /***********************************************************************
2585 * Change to the given directory. If the directory is not present, and we
2586 * have been told to allow it, then create the directory and cd to it.
2589 static CURLcode ftp_cwd_and_mkd(struct connectdata *conn, char *path)
2593 result = ftp_cwd(conn, path);
2595 if(conn->data->set.ftp_create_missing_dirs) {
2596 result = ftp_mkd(conn, path);
2598 /* ftp_mkd() calls failf() itself */
2600 result = ftp_cwd(conn, path);
2603 failf(conn->data, "Couldn't cd to %s", path);
2608 #endif /* CURL_DISABLE_FTP */