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 #if (defined(NETWARE) && defined(__NOVELL_LIBC__))
70 #define in_addr_t unsigned long
73 #include <curl/curl.h>
82 #include "http.h" /* for HTTP proxy tunnel stuff */
90 #include "strtoofft.h"
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 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_cwd(struct connectdata *conn, char *path);
118 static CURLcode ftp_mkd(struct connectdata *conn, char *path);
119 static CURLcode ftp_cwd_and_mkd(struct connectdata *conn, char *path);
121 /* easy-to-use macro: */
122 #define FTPSENDF(x,y,z) if((result = Curl_ftpsendf(x,y,z))) return result
124 static void freedirs(struct FTP *ftp)
127 for (i=0; ftp->dirs[i]; i++){
133 /***********************************************************************
135 * AllowServerConnect()
137 * When we've issue the PORT command, we have told the server to connect
138 * to us. This function will sit and wait here until the server has
142 static CURLcode AllowServerConnect(struct connectdata *conn)
146 struct SessionHandle *data = conn->data;
147 curl_socket_t sock = conn->sock[SECONDARYSOCKET];
148 struct timeval now = Curl_tvnow();
149 long timespent = Curl_tvdiff(Curl_tvnow(), now)/1000;
150 long timeout = data->set.connecttimeout?data->set.connecttimeout:
151 (data->set.timeout?data->set.timeout: 0);
155 FD_SET(sock, &rdset);
158 timeout -= timespent;
160 failf(data, "Timed out before server could connect to us");
161 return CURLE_OPERATION_TIMEDOUT;
165 /* we give the server 60 seconds to connect to us, or a custom timeout */
166 dt.tv_sec = (int)(timeout?timeout:60);
169 switch (select(sock+1, &rdset, NULL, NULL, &dt)) {
172 failf(data, "Error while waiting for server connect");
173 return CURLE_FTP_PORT_FAILED;
174 case 0: /* timeout */
176 failf(data, "Timeout while waiting for server connect");
177 return CURLE_FTP_PORT_FAILED;
179 /* we have received data here */
182 size_t size = sizeof(struct sockaddr_in);
183 struct sockaddr_in add;
185 getsockname(sock, (struct sockaddr *) &add, (socklen_t *)&size);
186 s=accept(sock, (struct sockaddr *) &add, (socklen_t *)&size);
188 sclose(sock); /* close the first socket */
190 if (CURL_SOCKET_BAD == s) {
192 failf(data, "Error accept()ing server connect");
193 return CURLE_FTP_PORT_FAILED;
195 infof(data, "Connection accepted from server\n");
197 conn->sock[SECONDARYSOCKET] = s;
198 Curl_nonblock(s, TRUE); /* enable non-blocking */
207 /* --- parse FTP server responses --- */
210 * Curl_GetFTPResponse() is supposed to be invoked after each command sent to
211 * a remote FTP server. This function will wait and read all lines of the
212 * response and extract the relevant return code for the invoking function.
215 CURLcode Curl_GetFTPResponse(ssize_t *nreadp, /* return number of bytes read */
216 struct connectdata *conn,
217 int *ftpcode) /* return the ftp-code */
219 /* Brand new implementation.
220 * We cannot read just one byte per read() and then go back to select()
221 * as it seems that the OpenSSL read() stuff doesn't grok that properly.
223 * Alas, read as much as possible, split up into lines, use the ending
224 * line in a response or continue reading. */
226 curl_socket_t sockfd = conn->sock[FIRSTSOCKET];
227 int perline; /* count bytes per line */
231 long timeout; /* timeout in seconds */
232 struct timeval interval;
235 struct SessionHandle *data = conn->data;
237 int code=0; /* default ftp "error code" to return */
238 char *buf = data->state.buffer;
239 CURLcode result = CURLE_OK;
240 struct FTP *ftp = conn->proto.ftp;
241 struct timeval now = Curl_tvnow();
244 *ftpcode = 0; /* 0 for errors */
246 FD_ZERO (&readfd); /* clear it */
247 FD_SET (sockfd, &readfd); /* read socket */
249 /* get this in a backup variable to be able to restore it on each lap in the
260 while((*nreadp<BUFSIZE) && (keepon && !result)) {
261 /* check and reset timeout value every lap */
262 if(data->set.ftp_response_timeout )
263 /* if CURLOPT_FTP_RESPONSE_TIMEOUT is set, use that to determine
264 remaining time. Also, use "now" as opposed to "conn->now"
265 because ftp_response_timeout is only supposed to govern
266 the response for any given ftp response, not for the time
267 from connect to the given ftp response. */
268 timeout = data->set.ftp_response_timeout - /* timeout time */
269 Curl_tvdiff(Curl_tvnow(), now)/1000; /* spent time */
270 else if(data->set.timeout)
271 /* if timeout is requested, find out how much remaining time we have */
272 timeout = data->set.timeout - /* timeout time */
273 Curl_tvdiff(Curl_tvnow(), conn->now)/1000; /* spent time */
275 /* Even without a requested timeout, we only wait response_time
276 seconds for the full response to arrive before we bail out */
277 timeout = ftp->response_time -
278 Curl_tvdiff(Curl_tvnow(), now)/1000; /* spent time */
281 failf(data, "FTP response timeout");
282 return CURLE_OPERATION_TIMEDOUT; /* already too little time */
286 readfd = rkeepfd; /* set every lap */
287 interval.tv_sec = 1; /* use 1 second timeout intervals */
288 interval.tv_usec = 0;
290 switch (select (sockfd+1, &readfd, NULL, NULL, &interval)) {
291 case -1: /* select() error, stop reading */
292 result = CURLE_RECV_ERROR;
293 failf(data, "FTP response aborted due to select() error: %d", errno);
295 case 0: /* timeout */
296 if(Curl_pgrsUpdate(conn))
297 return CURLE_ABORTED_BY_CALLBACK;
298 continue; /* just continue in our loop for the timeout duration */
304 if(CURLE_OK == result) {
306 * This code previously didn't use the kerberos sec_read() code
307 * to read, but when we use Curl_read() it may do so. Do confirm
308 * that this is still ok and then remove this comment!
311 /* we had data in the "cache", copy that instead of doing an actual
314 * Dave Meyer, December 2003:
315 * ftp->cache_size is cast to int here. This should be safe,
316 * because it would have been populated with something of size
317 * int to begin with, even though its datatype may be larger
320 memcpy(ptr, ftp->cache, (int)ftp->cache_size);
321 gotbytes = (int)ftp->cache_size;
322 free(ftp->cache); /* free the cache */
323 ftp->cache = NULL; /* clear the pointer */
324 ftp->cache_size = 0; /* zero the size just in case */
327 int res = Curl_read(conn, sockfd, ptr, BUFSIZE-*nreadp, &gotbytes);
330 continue; /* go looping again */
338 else if(gotbytes <= 0) {
340 result = CURLE_RECV_ERROR;
341 failf(data, "FTP response reading failed");
344 /* we got a whole chunk of data, which can be anything from one
345 * byte to a set of lines and possible just a piece of the last
350 for(i = 0; i < gotbytes; ptr++, i++) {
353 /* a newline is CRLF in ftp-talk, so the CR is ignored as
354 the line isn't really terminated until the LF comes */
356 /* output debug output if that is requested */
357 if(data->set.verbose)
358 Curl_debug(data, CURLINFO_HEADER_IN, line_start, perline);
361 * We pass all response-lines to the callback function registered
362 * for "headers". The response lines can be seen as a kind of
365 result = Curl_client_write(data, CLIENTWRITE_HEADER,
366 line_start, perline);
370 #define lastline(line) (isdigit((int)line[0]) && isdigit((int)line[1]) && \
371 isdigit((int)line[2]) && (' ' == line[3]))
373 if(perline>3 && lastline(line_start)) {
374 /* This is the end of the last line, copy the last
375 * line to the start of the buffer and zero terminate,
376 * for old times sake (and krb4)! */
379 for(meow=line_start, n=0; meow<ptr; meow++, n++)
381 *meow=0; /* zero terminate */
383 line_start = ptr+1; /* advance pointer */
384 i++; /* skip this before getting out */
387 perline=0; /* line starts over here */
391 if(!keepon && (i != gotbytes)) {
392 /* We found the end of the response lines, but we didn't parse the
393 full chunk of data we have read from the server. We therefore
394 need to store the rest of the data to be checked on the next
395 invoke as it may actually contain another end of response
396 already! Cleverly figured out by Eric Lavigne in December
398 ftp->cache_size = gotbytes - i;
399 ftp->cache = (char *)malloc((int)ftp->cache_size);
401 memcpy(ftp->cache, line_start, (int)ftp->cache_size);
403 return CURLE_OUT_OF_MEMORY; /**BANG**/
405 } /* there was data */
407 } /* while there's buffer left and loop is requested */
413 /* handle the security-oriented responses 6xx ***/
414 /* FIXME: some errorchecking perhaps... ***/
417 Curl_sec_read_msg(conn, buf, prot_safe);
420 Curl_sec_read_msg(conn, buf, prot_private);
423 Curl_sec_read_msg(conn, buf, prot_confidential);
426 /* normal ftp stuff we pass through! */
432 *ftpcode=code; /* return the initial number like this */
434 /* store the latest code for later retrieval */
435 conn->data->info.httpcode=code;
440 static const char *ftpauth[]= {
445 * Curl_ftp_connect() should do everything that is to be considered a part of
446 * the connection phase.
448 CURLcode Curl_ftp_connect(struct connectdata *conn)
450 /* this is FTP and no proxy */
452 struct SessionHandle *data=conn->data;
453 char *buf = data->state.buffer; /* this is our buffer */
458 ftp = (struct FTP *)malloc(sizeof(struct FTP));
460 return CURLE_OUT_OF_MEMORY;
462 memset(ftp, 0, sizeof(struct FTP));
463 conn->proto.ftp = ftp;
465 /* We always support persistant connections on ftp */
466 conn->bits.close = FALSE;
468 /* get some initial data into the ftp struct */
469 ftp->bytecountp = &conn->bytecount;
471 /* no need to duplicate them, this connectdata struct won't change */
472 ftp->user = conn->user;
473 ftp->passwd = conn->passwd;
474 ftp->response_time = 3600; /* set default response time-out */
476 if (data->set.tunnel_thru_httpproxy) {
477 /* We want "seamless" FTP operations through HTTP proxy tunnel */
478 result = Curl_ConnectHTTPProxyTunnel(conn, FIRSTSOCKET,
479 conn->hostname, conn->remote_port);
480 if(CURLE_OK != result)
484 if(conn->protocol & PROT_FTPS) {
485 /* FTPS is simply ftp with SSL for the control channel */
486 /* now, perform the SSL initialization for this socket */
487 result = Curl_SSLConnect(conn, FIRSTSOCKET);
492 /* The first thing we do is wait for the "220*" line: */
493 result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
498 failf(data, "This doesn't seem like a nice ftp-server response");
499 return CURLE_FTP_WEIRD_SERVER_REPLY;
503 /* if not anonymous login, try a secure login */
506 /* request data protection level (default is 'clear') */
507 Curl_sec_request_prot(conn, "private");
509 /* We set private first as default, in case the line below fails to
511 Curl_sec_request_prot(conn, data->set.krb4_level);
513 if(Curl_sec_login(conn) != 0)
514 infof(data, "Logging in with password in cleartext!\n");
516 infof(data, "Authentication successful\n");
520 if(data->set.ftp_ssl && !conn->ssl[FIRSTSOCKET].use) {
521 /* we don't have a SSL/TLS connection, try a FTPS connection now */
523 for (try = 0; ftpauth[try]; try++) {
525 FTPSENDF(conn, "AUTH %s", ftpauth[try]);
527 result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
532 /* RFC2228 (page 5) says:
534 * If the server is willing to accept the named security mechanism, and
535 * does not require any security data, it must respond with reply code
539 if((ftpcode == 234) || (ftpcode == 334)) {
540 result = Curl_SSLConnect(conn, FIRSTSOCKET);
543 conn->protocol |= PROT_FTPS;
544 conn->ssl[SECONDARYSOCKET].use = FALSE; /* clear-text data */
551 FTPSENDF(conn, "USER %s", ftp->user?ftp->user:"");
553 /* wait for feedback */
554 result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
559 /* 530 User ... access denied
560 (the server denies to log the specified user) */
561 failf(data, "Access denied: %s", &buf[4]);
562 return CURLE_FTP_ACCESS_DENIED;
564 else if(ftpcode == 331) {
565 /* 331 Password required for ...
566 (the server requires to send the user's password too) */
567 FTPSENDF(conn, "PASS %s", ftp->passwd?ftp->passwd:"");
568 result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
573 /* 530 Login incorrect.
574 (the username and/or the password are incorrect) */
575 failf(data, "the username and/or the password are incorrect");
576 return CURLE_FTP_USER_PASSWORD_INCORRECT;
578 else if(ftpcode == 230) {
579 /* 230 User ... logged in.
580 (user successfully logged in) */
582 infof(data, "We have successfully logged in\n");
585 failf(data, "Odd return code after PASS");
586 return CURLE_FTP_WEIRD_PASS_REPLY;
589 else if(buf[0] == '2') {
590 /* 230 User ... logged in.
591 (the user logged in without password) */
592 infof(data, "We have successfully logged in\n");
593 if (conn->ssl[FIRSTSOCKET].use) {
595 /* we are logged in (with Kerberos)
596 * now set the requested protection level
598 if(conn->sec_complete)
599 Curl_sec_set_protection_level(conn);
601 /* we may need to issue a KAUTH here to have access to the files
602 * do it if user supplied a password
604 if(conn->passwd && *conn->passwd) {
605 result = Curl_krb_kauth(conn);
613 failf(data, "Odd return code after USER");
614 return CURLE_FTP_WEIRD_USER_REPLY;
617 if(conn->ssl[FIRSTSOCKET].use) {
618 /* PBSZ = PROTECTION BUFFER SIZE.
620 The 'draft-murray-auth-ftp-ssl' (draft 12, page 7) says:
622 Specifically, the PROT command MUST be preceded by a PBSZ command
623 and a PBSZ command MUST be preceded by a successful security data
624 exchange (the TLS negotiation in this case)
628 Thus the PBSZ command must still be issued, but must have a parameter
629 of '0' to indicate that no buffering is taking place and the data
630 connection should not be encapsulated.
632 FTPSENDF(conn, "PBSZ %d", 0);
633 result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
637 /* For TLS, the data connection can have one of two security levels.
639 1)Clear (requested by 'PROT C')
641 2)Private (requested by 'PROT P')
643 if(!conn->ssl[SECONDARYSOCKET].use) {
644 FTPSENDF(conn, "PROT %c", 'P');
645 result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
650 /* We have enabled SSL for the data connection! */
651 conn->ssl[SECONDARYSOCKET].use = TRUE;
653 /* FTP servers typically responds with 500 if they decide to reject
658 /* send PWD to discover our entry point */
659 FTPSENDF(conn, "PWD", NULL);
661 /* wait for feedback */
662 result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
667 char *dir = (char *)malloc(nread+1);
669 char *ptr=&buf[4]; /* start on the first letter */
672 return CURLE_OUT_OF_MEMORY;
674 /* Reply format is like
675 257<space>"<directory-name>"<space><commentary> and the RFC959 says
677 The directory name can contain any character; embedded double-quotes
678 should be escaped by double-quotes (the "quote-doubling" convention).
681 /* it started good */
686 /* "quote-doubling" */
692 *store = '\0'; /* zero terminate */
693 break; /* get out of this loop */
701 ftp->entrypath =dir; /* remember this */
702 infof(data, "Entry path is '%s'\n", ftp->entrypath);
705 /* couldn't get the path */
707 infof(data, "Failed to figure out path\n");
712 /* We couldn't read the PWD response! */
718 /***********************************************************************
722 * The DONE function. This does what needs to be done after a single DO has
725 * Input argument is already checked for validity.
727 CURLcode Curl_ftp_done(struct connectdata *conn)
729 struct SessionHandle *data = conn->data;
730 struct FTP *ftp = conn->proto.ftp;
733 CURLcode result=CURLE_OK;
735 /* free the dir tree parts */
743 if(data->set.upload) {
744 if((-1 != data->set.infilesize) &&
745 (data->set.infilesize != *ftp->bytecountp) &&
747 failf(data, "Uploaded unaligned file size (%" FORMAT_OFF_T
748 " out of %" FORMAT_OFF_T " bytes)",
749 *ftp->bytecountp, data->set.infilesize);
750 conn->bits.close = TRUE; /* close this connection since we don't
751 know what state this error leaves us in */
752 return CURLE_PARTIAL_FILE;
756 if((-1 != conn->size) && (conn->size != *ftp->bytecountp) &&
757 (conn->maxdownload != *ftp->bytecountp)) {
758 failf(data, "Received only partial file: %" FORMAT_OFF_T " bytes",
760 conn->bits.close = TRUE; /* close this connection since we don't
761 know what state this error leaves us in */
762 return CURLE_PARTIAL_FILE;
764 else if(!ftp->dont_check &&
767 /* We consider this an error, but there's no true FTP error received
768 why we need to continue to "read out" the server response too.
769 We don't want to leave a "waiting" server reply if we'll get told
770 to make a second request on this same connection! */
771 failf(data, "No data was received!");
772 result = CURLE_FTP_COULDNT_RETR_FILE;
777 Curl_sec_fflush_fd(conn, conn->sock[SECONDARYSOCKET]);
779 /* shut down the socket to inform the server we're done */
780 sclose(conn->sock[SECONDARYSOCKET]);
781 conn->sock[SECONDARYSOCKET] = CURL_SOCKET_BAD;
783 if(!ftp->no_transfer) {
784 /* Let's see what the server says about the transfer we just performed,
785 but lower the timeout as sometimes this connection has died while
786 the data has been transfered. This happens when doing through NATs
787 etc that abandon old silent connections.
789 ftp->response_time = 60; /* give it only a minute for now */
791 result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
793 ftp->response_time = 3600; /* set this back to one hour waits */
795 if(!nread && (CURLE_OPERATION_TIMEDOUT == result)) {
796 failf(data, "control connection looks dead");
803 if(!ftp->dont_check) {
804 /* 226 Transfer complete, 250 Requested file action okay, completed. */
805 if((ftpcode != 226) && (ftpcode != 250)) {
806 failf(data, "server did not report OK, got %d", ftpcode);
807 return CURLE_FTP_WRITE_ERROR;
812 /* clear these for next connection */
813 ftp->no_transfer = FALSE;
814 ftp->dont_check = FALSE;
816 /* Send any post-transfer QUOTE strings? */
817 if(!result && data->set.postquote)
818 result = ftp_sendquote(conn, data->set.postquote);
823 /***********************************************************************
827 * Where a 'quote' means a list of custom commands to send to the server.
828 * The quote list is passed as an argument.
832 CURLcode ftp_sendquote(struct connectdata *conn, struct curl_slist *quote)
834 struct curl_slist *item;
842 FTPSENDF(conn, "%s", item->data);
844 result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
848 if (ftpcode >= 400) {
849 failf(conn->data, "QUOT string not accepted: %s", item->data);
850 return CURLE_FTP_QUOTE_ERROR;
860 /***********************************************************************
864 * Get the timestamp of the given file.
867 CURLcode ftp_getfiletime(struct connectdata *conn, char *file)
869 CURLcode result=CURLE_OK;
870 int ftpcode; /* for ftp status */
872 char *buf = conn->data->state.buffer;
874 /* we have requested to get the modified-time of the file, this is yet
875 again a grey area as the MDTM is not kosher RFC959 */
876 FTPSENDF(conn, "MDTM %s", file);
878 result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
885 /* we got a time. Format should be: "YYYYMMDDHHMMSS[.sss]" where the
886 last .sss part is optional and means fractions of a second */
887 int year, month, day, hour, minute, second;
888 if(6 == sscanf(buf+4, "%04d%02d%02d%02d%02d%02d",
889 &year, &month, &day, &hour, &minute, &second)) {
890 /* we have a time, reformat it */
891 time_t secs=time(NULL);
892 sprintf(buf, "%04d%02d%02d %02d:%02d:%02d GMT",
893 year, month, day, hour, minute, second);
894 /* now, convert this into a time() value: */
895 conn->data->info.filetime = curl_getdate(buf, &secs);
900 infof(conn->data, "unsupported MDTM reply format\n");
902 case 550: /* "No such file or directory" */
903 failf(conn->data, "Given file does not exist");
904 result = CURLE_FTP_COULDNT_RETR_FILE;
910 /***********************************************************************
914 * Set transfer type. We only deal with ASCII or BINARY so this function
917 static CURLcode ftp_transfertype(struct connectdata *conn,
920 struct SessionHandle *data = conn->data;
925 FTPSENDF(conn, "TYPE %s", ascii?"A":"I");
927 result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
932 failf(data, "Couldn't set %s mode",
933 ascii?"ASCII":"binary");
934 return ascii? CURLE_FTP_COULDNT_SET_ASCII:CURLE_FTP_COULDNT_SET_BINARY;
940 /***********************************************************************
944 * Returns the file size (in bytes) of the given remote file.
948 CURLcode ftp_getsize(struct connectdata *conn, char *file,
951 struct SessionHandle *data = conn->data;
954 char *buf=data->state.buffer;
957 FTPSENDF(conn, "SIZE %s", file);
958 result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
963 /* get the size from the ascii string: */
964 *size = strtoofft(buf+4, NULL, 0);
967 return CURLE_FTP_COULDNT_GET_SIZE;
972 /***************************************************************************
976 * This function only outputs some informationals about this second connection
977 * when we've issued a PASV command before and thus we have connected to a
978 * possibly new IP address.
982 ftp_pasv_verbose(struct connectdata *conn,
983 Curl_ipconnect *addr,
984 char *newhost, /* ascii version */
988 /*****************************************************************
990 * IPv4-only code section
994 struct hostent * answer;
996 #ifdef HAVE_INET_NTOA_R
999 /* The array size trick below is to make this a large chunk of memory
1000 suitably 8-byte aligned on 64-bit platforms. This was thoughtfully
1001 suggested by Philip Gladstone. */
1002 long bigbuf[9000 / sizeof(long)];
1004 #if defined(HAVE_INET_ADDR)
1006 # if defined(HAVE_GETHOSTBYADDR_R)
1009 char *hostent_buf = (char *)bigbuf; /* get a char * to the buffer */
1011 address = inet_addr(newhost);
1012 # ifdef HAVE_GETHOSTBYADDR_R
1014 # ifdef HAVE_GETHOSTBYADDR_R_5
1015 /* AIX, Digital Unix (OSF1, Tru64) style:
1016 extern int gethostbyaddr_r(char *addr, size_t len, int type,
1017 struct hostent *htent, struct hostent_data *ht_data); */
1019 /* Fred Noz helped me try this out, now it at least compiles! */
1021 /* Bjorn Reese (November 28 2001):
1022 The Tru64 man page on gethostbyaddr_r() says that
1023 the hostent struct must be filled with zeroes before the call to
1026 ... as must be struct hostent_data Craig Markwardt 19 Sep 2002. */
1028 memset(hostent_buf, 0, sizeof(struct hostent)+sizeof(struct hostent_data));
1030 if(gethostbyaddr_r((char *) &address,
1031 sizeof(address), AF_INET,
1032 (struct hostent *)hostent_buf,
1033 (struct hostent_data *)(hostent_buf + sizeof(*answer))))
1036 answer=(struct hostent *)hostent_buf;
1039 # ifdef HAVE_GETHOSTBYADDR_R_7
1040 /* Solaris and IRIX */
1041 answer = gethostbyaddr_r((char *) &address, sizeof(address), AF_INET,
1042 (struct hostent *)bigbuf,
1043 hostent_buf + sizeof(*answer),
1044 sizeof(bigbuf) - sizeof(*answer),
1047 # ifdef HAVE_GETHOSTBYADDR_R_8
1049 if(gethostbyaddr_r((char *) &address, sizeof(address), AF_INET,
1050 (struct hostent *)hostent_buf,
1051 hostent_buf + sizeof(*answer),
1052 sizeof(bigbuf) - sizeof(*answer),
1055 answer=NULL; /* error */
1059 (void)hostent_buf; /* avoid compiler warning */
1060 answer = gethostbyaddr((char *) &address, sizeof(address), AF_INET);
1065 (void) memcpy(&in.s_addr, addr, sizeof (Curl_ipconnect));
1066 infof(conn->data, "Connecting to %s (%s) port %u\n",
1067 answer?answer->h_name:newhost,
1068 #if defined(HAVE_INET_NTOA_R)
1069 inet_ntoa_r(in, ntoa_buf, sizeof(ntoa_buf)),
1076 /*****************************************************************
1078 * IPv6-only code section
1080 char hbuf[NI_MAXHOST]; /* ~1KB */
1081 char nbuf[NI_MAXHOST]; /* ~1KB */
1082 char sbuf[NI_MAXSERV]; /* around 32 */
1083 (void)port; /* prevent compiler warning */
1084 if (getnameinfo(addr->ai_addr, addr->ai_addrlen,
1085 nbuf, sizeof(nbuf), sbuf, sizeof(sbuf), NIFLAGS)) {
1086 snprintf(nbuf, sizeof(nbuf), "?");
1087 snprintf(sbuf, sizeof(sbuf), "?");
1090 if (getnameinfo(addr->ai_addr, addr->ai_addrlen,
1091 hbuf, sizeof(hbuf), NULL, 0, 0)) {
1092 infof(conn->data, "Connecting to %s (%s) port %s\n", nbuf, newhost, sbuf);
1095 infof(conn->data, "Connecting to %s (%s) port %s\n", hbuf, nbuf, sbuf);
1100 /***********************************************************************
1104 * Send the proper PORT command. PORT is the ftp client's way of telling the
1105 * server that *WE* open a port that we listen on an awaits the server to
1106 * connect to. This is the opposite of PASV.
1110 CURLcode ftp_use_port(struct connectdata *conn)
1112 struct SessionHandle *data=conn->data;
1113 curl_socket_t portsock= CURL_SOCKET_BAD;
1115 int ftpcode; /* receive FTP response codes in this */
1119 /******************************************************************
1121 * Here's a piece of IPv6-specific code coming up
1125 struct addrinfo hints, *res, *ai;
1126 struct sockaddr_storage ss;
1128 char hbuf[NI_MAXHOST];
1130 struct sockaddr *sa=(struct sockaddr *)&ss;
1133 char portmsgbuf[4096], tmp[4096];
1135 const char *mode[] = { "EPRT", "LPRT", "PORT", NULL };
1141 * we should use Curl_if2ip? given pickiness of recent ftpd,
1142 * I believe we should use the same address as the control connection.
1145 rc = getsockname(conn->sock[FIRSTSOCKET], (struct sockaddr *)&ss, &sslen);
1147 failf(data, "getsockname() returned %d\n", rc);
1148 return CURLE_FTP_PORT_FAILED;
1151 rc = getnameinfo((struct sockaddr *)&ss, sslen, hbuf, sizeof(hbuf), NULL, 0,
1154 failf(data, "getnameinfo() returned %d\n", rc);
1155 return CURLE_FTP_PORT_FAILED;
1158 memset(&hints, 0, sizeof(hints));
1159 hints.ai_family = sa->sa_family;
1160 /*hints.ai_family = ss.ss_family;
1161 this way can be used if sockaddr_storage is properly defined, as glibc
1163 hints.ai_socktype = SOCK_STREAM;
1164 hints.ai_flags = AI_PASSIVE;
1166 rc = getaddrinfo(hbuf, NULL, &hints, &res);
1168 failf(data, "getaddrinfo() returned %d\n", rc);
1169 return CURLE_FTP_PORT_FAILED;
1172 portsock = CURL_SOCKET_BAD;
1174 for (ai = res; ai; ai = ai->ai_next) {
1176 * Workaround for AIX5 getaddrinfo() problem (it doesn't set ai_socktype):
1178 if (ai->ai_socktype == 0)
1179 ai->ai_socktype = hints.ai_socktype;
1181 portsock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
1182 if (portsock == CURL_SOCKET_BAD) {
1183 error = Curl_ourerrno();
1187 if (bind(portsock, ai->ai_addr, ai->ai_addrlen) < 0) {
1188 error = Curl_ourerrno();
1190 portsock = CURL_SOCKET_BAD;
1194 if (listen(portsock, 1) < 0) {
1195 error = Curl_ourerrno();
1197 portsock = CURL_SOCKET_BAD;
1204 if (portsock == CURL_SOCKET_BAD) {
1205 failf(data, "%s", Curl_strerror(conn,error));
1206 return CURLE_FTP_PORT_FAILED;
1210 if (getsockname(portsock, sa, &sslen) < 0) {
1211 failf(data, "%s", Curl_strerror(conn,Curl_ourerrno()));
1212 return CURLE_FTP_PORT_FAILED;
1215 for (modep = (char **)(data->set.ftp_use_eprt?&mode[0]:&mode[2]);
1216 modep && *modep; modep++) {
1220 switch (sa->sa_family) {
1222 ap = (unsigned char *)&((struct sockaddr_in *)&ss)->sin_addr;
1223 alen = sizeof(((struct sockaddr_in *)&ss)->sin_addr);
1224 pp = (unsigned char *)&((struct sockaddr_in *)&ss)->sin_port;
1225 plen = sizeof(((struct sockaddr_in *)&ss)->sin_port);
1230 ap = (unsigned char *)&((struct sockaddr_in6 *)&ss)->sin6_addr;
1231 alen = sizeof(((struct sockaddr_in6 *)&ss)->sin6_addr);
1232 pp = (unsigned char *)&((struct sockaddr_in6 *)&ss)->sin6_port;
1233 plen = sizeof(((struct sockaddr_in6 *)&ss)->sin6_port);
1239 lprtaf = eprtaf = -1;
1243 if (strcmp(*modep, "EPRT") == 0) {
1246 if (getnameinfo((struct sockaddr *)&ss, sslen,
1247 portmsgbuf, sizeof(portmsgbuf), tmp, sizeof(tmp),
1251 /* do not transmit IPv6 scope identifier to the wire */
1252 if (sa->sa_family == AF_INET6) {
1253 char *q = strchr(portmsgbuf, '%');
1258 result = Curl_ftpsendf(conn, "%s |%d|%s|%s|", *modep, eprtaf,
1263 else if (strcmp(*modep, "LPRT") == 0 ||
1264 strcmp(*modep, "PORT") == 0) {
1267 if (strcmp(*modep, "LPRT") == 0 && lprtaf < 0)
1269 if (strcmp(*modep, "PORT") == 0 && sa->sa_family != AF_INET)
1272 portmsgbuf[0] = '\0';
1273 if (strcmp(*modep, "LPRT") == 0) {
1274 snprintf(tmp, sizeof(tmp), "%d,%d", lprtaf, alen);
1275 if (strlcat(portmsgbuf, tmp, sizeof(portmsgbuf)) >=
1276 sizeof(portmsgbuf)) {
1281 for (i = 0; i < alen; i++) {
1283 snprintf(tmp, sizeof(tmp), ",%u", ap[i]);
1285 snprintf(tmp, sizeof(tmp), "%u", ap[i]);
1287 if (strlcat(portmsgbuf, tmp, sizeof(portmsgbuf)) >=
1288 sizeof(portmsgbuf)) {
1293 if (strcmp(*modep, "LPRT") == 0) {
1294 snprintf(tmp, sizeof(tmp), ",%d", plen);
1296 if (strlcat(portmsgbuf, tmp, sizeof(portmsgbuf)) >= sizeof(portmsgbuf))
1300 for (i = 0; i < plen; i++) {
1301 snprintf(tmp, sizeof(tmp), ",%u", pp[i]);
1303 if (strlcat(portmsgbuf, tmp, sizeof(portmsgbuf)) >=
1304 sizeof(portmsgbuf)) {
1309 result = Curl_ftpsendf(conn, "%s %s", *modep, portmsgbuf);
1314 result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
1318 if (ftpcode != 200) {
1327 failf(data, "PORT command attempts failed");
1328 return CURLE_FTP_PORT_FAILED;
1330 /* we set the secondary socket variable to this for now, it
1331 is only so that the cleanup function will close it in case
1332 we fail before the true secondary stuff is made */
1333 conn->sock[SECONDARYSOCKET] = portsock;
1336 /******************************************************************
1338 * Here's a piece of IPv4-specific code coming up
1341 struct sockaddr_in sa;
1342 struct Curl_dns_entry *h=NULL;
1343 unsigned short porttouse;
1344 char myhost[256] = "";
1345 bool sa_filled_in = FALSE;
1347 if(data->set.ftpport) {
1351 /* First check if the given name is an IP address */
1352 in=inet_addr(data->set.ftpport);
1354 if((in == CURL_INADDR_NONE) &&
1355 Curl_if2ip(data->set.ftpport, myhost, sizeof(myhost))) {
1356 rc = Curl_resolv(conn, myhost, 0, &h);
1358 rc = Curl_wait_for_resolv(conn, &h);
1361 size_t len = strlen(data->set.ftpport);
1363 rc = Curl_resolv(conn, data->set.ftpport, 0, &h);
1365 rc = Curl_wait_for_resolv(conn, &h);
1368 strcpy(myhost, data->set.ftpport); /* buffer overflow risk */
1372 /* pick a suitable default here */
1377 if (getsockname(conn->sock[FIRSTSOCKET],
1378 (struct sockaddr *)&sa, &sslen) < 0) {
1379 failf(data, "getsockname() failed");
1380 return CURLE_FTP_PORT_FAILED;
1383 sa_filled_in = TRUE; /* the sa struct is filled in */
1387 /* when we return from here, we can forget about this */
1388 Curl_resolv_unlock(data, h);
1390 if ( h || sa_filled_in) {
1391 if( (portsock = socket(AF_INET, SOCK_STREAM, 0)) != CURL_SOCKET_BAD ) {
1394 /* we set the secondary socket variable to this for now, it
1395 is only so that the cleanup function will close it in case
1396 we fail before the true secondary stuff is made */
1397 conn->sock[SECONDARYSOCKET] = portsock;
1400 memset((char *)&sa, 0, sizeof(sa));
1401 memcpy((char *)&sa.sin_addr,
1404 sa.sin_family = AF_INET;
1405 sa.sin_addr.s_addr = INADDR_ANY;
1411 if(bind(portsock, (struct sockaddr *)&sa, size) >= 0) {
1412 /* we succeeded to bind */
1413 struct sockaddr_in add;
1414 socklen_t socksize = sizeof(add);
1416 if(getsockname(portsock, (struct sockaddr *) &add,
1418 failf(data, "getsockname() failed");
1419 return CURLE_FTP_PORT_FAILED;
1421 porttouse = ntohs(add.sin_port);
1423 if ( listen(portsock, 1) < 0 ) {
1424 failf(data, "listen(2) failed on socket");
1425 return CURLE_FTP_PORT_FAILED;
1429 failf(data, "bind(2) failed on socket");
1430 return CURLE_FTP_PORT_FAILED;
1434 failf(data, "socket(2) failed (%s)");
1435 return CURLE_FTP_PORT_FAILED;
1439 failf(data, "could't find my own IP address (%s)", myhost);
1440 return CURLE_FTP_PORT_FAILED;
1443 #ifdef HAVE_INET_NTOA_R
1447 unsigned short ip[5];
1448 (void) memcpy(&in.s_addr,
1449 h?*h->addr->h_addr_list:(char *)&sa.sin_addr.s_addr,
1450 sizeof (in.s_addr));
1452 #ifdef HAVE_INET_NTOA_R
1453 /* ignore the return code from inet_ntoa_r() as it is int or
1454 char * depending on system */
1455 inet_ntoa_r(in, ntoa_buf, sizeof(ntoa_buf));
1456 sscanf( ntoa_buf, "%hu.%hu.%hu.%hu",
1457 &ip[0], &ip[1], &ip[2], &ip[3]);
1459 sscanf( inet_ntoa(in), "%hu.%hu.%hu.%hu",
1460 &ip[0], &ip[1], &ip[2], &ip[3]);
1462 infof(data, "Telling server to connect to %d.%d.%d.%d:%d\n",
1463 ip[0], ip[1], ip[2], ip[3], porttouse);
1465 result=Curl_ftpsendf(conn, "PORT %d,%d,%d,%d,%d,%d",
1466 ip[0], ip[1], ip[2], ip[3],
1473 result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
1477 if(ftpcode != 200) {
1478 failf(data, "Server does not grok PORT, try without it!");
1479 return CURLE_FTP_PORT_FAILED;
1481 #endif /* end of ipv4-specific code */
1486 /***********************************************************************
1490 * Send the PASV command. PASV is the ftp client's way of asking the server to
1491 * open a second port that we can connect to (for the data transfer). This is
1492 * the opposite of PORT.
1496 CURLcode ftp_use_pasv(struct connectdata *conn,
1499 struct SessionHandle *data = conn->data;
1501 char *buf = data->state.buffer; /* this is our buffer */
1502 int ftpcode; /* receive FTP response codes in this */
1504 struct Curl_dns_entry *addr=NULL;
1505 Curl_ipconnect *conninfo;
1509 Here's the excecutive summary on what to do:
1511 PASV is RFC959, expect:
1512 227 Entering Passive Mode (a1,a2,a3,a4,p1,p2)
1514 LPSV is RFC1639, expect:
1515 228 Entering Long Passive Mode (4,4,a1,a2,a3,a4,2,p1,p2)
1517 EPSV is RFC2428, expect:
1518 229 Entering Extended Passive Mode (|||port|)
1522 const char *mode[] = { "EPSV", "PASV", NULL };
1523 int results[] = { 229, 227, 0 };
1525 unsigned short connectport; /* the local port connect() should use! */
1526 unsigned short newport=0; /* remote port, not necessary the local one */
1528 /* newhost must be able to hold a full IP-style address in ASCII, which
1529 in the IPv6 case means 5*8-1 = 39 letters */
1531 char *newhostp=NULL;
1533 for (modeoff = (data->set.ftp_use_epsv?0:1);
1534 mode[modeoff]; modeoff++) {
1535 result = Curl_ftpsendf(conn, "%s", mode[modeoff]);
1538 result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
1541 if (ftpcode == results[modeoff])
1545 if (!mode[modeoff]) {
1546 failf(data, "Odd return code after PASV");
1547 return CURLE_FTP_WEIRD_PASV_REPLY;
1549 else if (227 == results[modeoff]) {
1555 * New 227-parser June 3rd 1999.
1556 * It now scans for a sequence of six comma-separated numbers and
1557 * will take them as IP+port indicators.
1559 * Found reply-strings include:
1560 * "227 Entering Passive Mode (127,0,0,1,4,51)"
1561 * "227 Data transfer will passively listen to 127,0,0,1,4,51"
1562 * "227 Entering passive mode. 127,0,0,1,4,51"
1566 if (6 == sscanf(str, "%d,%d,%d,%d,%d,%d",
1567 &ip[0], &ip[1], &ip[2], &ip[3],
1568 &port[0], &port[1]))
1574 failf(data, "Couldn't interpret this 227-reply: %s", buf);
1575 return CURLE_FTP_WEIRD_227_FORMAT;
1578 sprintf(newhost, "%d.%d.%d.%d", ip[0], ip[1], ip[2], ip[3]);
1580 newport = (port[0]<<8) + port[1];
1582 else if (229 == results[modeoff]) {
1583 char *ptr = strchr(buf, '(');
1588 if(5 == sscanf(ptr, "%c%c%c%u%c",
1594 char sep1 = separator[0];
1597 /* The four separators should be identical, or else this is an oddly
1598 formatted reply and we bail out immediately. */
1599 for(i=1; i<4; i++) {
1600 if(separator[i] != sep1) {
1601 ptr=NULL; /* set to NULL to signal error */
1608 /* we should use the same host we already are connected to */
1609 newhostp = conn->name;
1616 failf(data, "Weirdly formatted EPSV reply");
1617 return CURLE_FTP_WEIRD_PASV_REPLY;
1621 return CURLE_FTP_CANT_RECONNECT;
1623 if(data->change.proxy && *data->change.proxy) {
1625 * This is a tunnel through a http proxy and we need to connect to the
1628 * We don't want to rely on a former host lookup that might've expired
1629 * now, instead we remake the lookup here and now!
1631 rc = Curl_resolv(conn, conn->proxyhost, conn->port, &addr);
1633 rc = Curl_wait_for_resolv(conn, &addr);
1636 (unsigned short)conn->port; /* we connect to the proxy's port */
1640 /* normal, direct, ftp connection */
1641 rc = Curl_resolv(conn, newhostp, newport, &addr);
1643 rc = Curl_wait_for_resolv(conn, &addr);
1646 failf(data, "Can't resolve new host %s:%d", newhostp, newport);
1647 return CURLE_FTP_CANT_GET_HOST;
1649 connectport = newport; /* we connect to the remote port */
1652 result = Curl_connecthost(conn,
1655 &conn->sock[SECONDARYSOCKET],
1659 Curl_resolv_unlock(data, addr); /* we're done using this address */
1665 * When this is used from the multi interface, this might've returned with
1666 * the 'connected' set to FALSE and thus we are now awaiting a non-blocking
1667 * connect to connect and we should not be "hanging" here waiting.
1670 if(data->set.verbose)
1671 /* this just dumps information about this second connection */
1672 ftp_pasv_verbose(conn, conninfo, newhostp, connectport);
1674 if(data->set.tunnel_thru_httpproxy) {
1675 /* We want "seamless" FTP operations through HTTP proxy tunnel */
1676 result = Curl_ConnectHTTPProxyTunnel(conn, SECONDARYSOCKET,
1678 if(CURLE_OK != result)
1686 * Curl_ftp_nextconnect()
1688 * This function shall be called when the second FTP connection has been
1689 * established and is confirmed connected.
1692 CURLcode Curl_ftp_nextconnect(struct connectdata *conn)
1694 struct SessionHandle *data=conn->data;
1695 char *buf = data->state.buffer; /* this is our buffer */
1698 int ftpcode; /* for ftp status */
1700 /* the ftp struct is already inited in Curl_ftp_connect() */
1701 struct FTP *ftp = conn->proto.ftp;
1702 curl_off_t *bytecountp = ftp->bytecountp;
1704 if(data->set.upload) {
1706 /* Set type to binary (unless specified ASCII) */
1707 result = ftp_transfertype(conn, data->set.ftp_ascii);
1711 /* Send any PREQUOTE strings after transfer type is set? (Wesley Laxton)*/
1712 if(data->set.prequote) {
1713 if ((result = ftp_sendquote(conn, data->set.prequote)) != CURLE_OK)
1717 if(conn->resume_from) {
1718 /* we're about to continue the uploading of a file */
1719 /* 1. get already existing file's size. We use the SIZE
1720 command for this which may not exist in the server!
1721 The SIZE command is not in RFC959. */
1723 /* 2. This used to set REST. But since we can do append, we
1724 don't another ftp command. We just skip the source file
1725 offset and then we APPEND the rest on the file instead */
1727 /* 3. pass file-size number of bytes in the source file */
1728 /* 4. lower the infilesize counter */
1729 /* => transfer as usual */
1731 if(conn->resume_from < 0 ) {
1732 /* we could've got a specified offset from the command line,
1733 but now we know we didn't */
1734 curl_off_t gottensize;
1736 if(CURLE_OK != ftp_getsize(conn, ftp->file, &gottensize)) {
1737 failf(data, "Couldn't get remote file size");
1738 return CURLE_FTP_COULDNT_GET_SIZE;
1740 conn->resume_from = gottensize;
1743 if(conn->resume_from) {
1744 /* do we still game? */
1745 curl_off_t passed=0;
1746 /* enable append instead */
1747 data->set.ftp_append = 1;
1749 /* Now, let's read off the proper amount of bytes from the
1750 input. If we knew it was a proper file we could've just
1751 fseek()ed but we only have a stream here */
1753 curl_off_t readthisamountnow = (conn->resume_from - passed);
1754 curl_off_t actuallyread;
1756 if(readthisamountnow > BUFSIZE)
1757 readthisamountnow = BUFSIZE;
1760 conn->fread(data->state.buffer, 1, (size_t)readthisamountnow,
1763 passed += actuallyread;
1764 if(actuallyread != readthisamountnow) {
1765 failf(data, "Could only read %" FORMAT_OFF_T
1766 " bytes from the input", passed);
1767 return CURLE_FTP_COULDNT_USE_REST;
1770 while(passed != conn->resume_from);
1772 /* now, decrease the size of the read */
1773 if(data->set.infilesize>0) {
1774 data->set.infilesize -= conn->resume_from;
1776 if(data->set.infilesize <= 0) {
1777 infof(data, "File already completely uploaded\n");
1779 /* no data to transfer */
1780 result=Curl_Transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
1782 /* Set no_transfer so that we won't get any error in
1783 * Curl_ftp_done() because we didn't transfer anything! */
1784 ftp->no_transfer = TRUE;
1789 /* we've passed, proceed as normal */
1793 /* Send everything on data->state.in to the socket */
1794 if(data->set.ftp_append) {
1795 /* we append onto the file instead of rewriting it */
1796 FTPSENDF(conn, "APPE %s", ftp->file);
1799 FTPSENDF(conn, "STOR %s", ftp->file);
1802 result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
1807 failf(data, "Failed FTP upload:%s", buf+3);
1808 /* oops, we never close the sockets! */
1809 return CURLE_FTP_COULDNT_STOR_FILE;
1812 if(data->set.ftp_use_port) {
1813 /* PORT means we are now awaiting the server to connect to us. */
1814 result = AllowServerConnect(conn);
1819 if(conn->ssl[SECONDARYSOCKET].use) {
1820 /* since we only have a plaintext TCP connection here, we must now
1822 infof(data, "Doing the SSL/TLS handshake on the data stream\n");
1823 result = Curl_SSLConnect(conn, SECONDARYSOCKET);
1830 /* When we know we're uploading a specified file, we can get the file
1831 size prior to the actual upload. */
1833 Curl_pgrsSetUploadSize(data, data->set.infilesize);
1835 result = Curl_Transfer(conn, -1, -1, FALSE, NULL, /* no download */
1836 SECONDARYSOCKET, bytecountp);
1841 else if(!data->set.no_body) {
1842 /* Retrieve file or directory */
1844 curl_off_t downloadsize=-1;
1846 if(conn->bits.use_range && conn->range) {
1847 curl_off_t from, to;
1848 curl_off_t totalsize=-1;
1852 from=strtoofft(conn->range, &ptr, 0);
1853 while(ptr && *ptr && (isspace((int)*ptr) || (*ptr=='-')))
1855 to=strtoofft(ptr, &ptr2, 0);
1857 /* we didn't get any digit */
1860 if((-1 == to) && (from>=0)) {
1862 conn->resume_from = from;
1863 infof(data, "FTP RANGE %" FORMAT_OFF_T " to end of file\n", from);
1868 conn->maxdownload = -from;
1869 conn->resume_from = from;
1870 infof(data, "FTP RANGE the last %" FORMAT_OFF_T " bytes\n", totalsize);
1874 totalsize = to-from;
1875 conn->maxdownload = totalsize+1; /* include the last mentioned byte */
1876 conn->resume_from = from;
1877 infof(data, "FTP RANGE from %" FORMAT_OFF_T
1878 " getting %" FORMAT_OFF_T " bytes\n", from, conn->maxdownload);
1880 infof(data, "range-download from %" FORMAT_OFF_T
1881 " to %" FORMAT_OFF_T ", totally %" FORMAT_OFF_T " bytes\n",
1882 from, to, conn->maxdownload);
1883 ftp->dont_check = TRUE; /* dont check for successful transfer */
1886 if((data->set.ftp_list_only) || !ftp->file) {
1887 /* The specified path ends with a slash, and therefore we think this
1888 is a directory that is requested, use LIST. But before that we
1889 need to set ASCII transfer mode. */
1892 /* Set type to ASCII */
1893 result = ftp_transfertype(conn, TRUE /* ASCII enforced */);
1897 /* if this output is to be machine-parsed, the NLST command will be
1898 better used since the LIST command output is not specified or
1899 standard in any way */
1901 FTPSENDF(conn, "%s",
1902 data->set.customrequest?data->set.customrequest:
1903 (data->set.ftp_list_only?"NLST":"LIST"));
1906 curl_off_t foundsize;
1908 /* Set type to binary (unless specified ASCII) */
1909 result = ftp_transfertype(conn, data->set.ftp_ascii);
1913 /* Send any PREQUOTE strings after transfer type is set? */
1914 if(data->set.prequote) {
1915 if ((result = ftp_sendquote(conn, data->set.prequote)) != CURLE_OK)
1919 /* Attempt to get the size, it'll be useful in some cases: for resumed
1920 downloads and when talking to servers that don't give away the size
1921 in the RETR response line. */
1922 result = ftp_getsize(conn, ftp->file, &foundsize);
1923 if(CURLE_OK == result) {
1924 if (data->set.max_filesize && foundsize > data->set.max_filesize) {
1925 failf(data, "Maximum file size exceeded");
1926 return CURLE_FILESIZE_EXCEEDED;
1928 downloadsize = foundsize;
1931 if(conn->resume_from) {
1933 /* Daniel: (August 4, 1999)
1935 * We start with trying to use the SIZE command to figure out the size
1936 * of the file we're gonna get. If we can get the size, this is by far
1937 * the best way to know if we're trying to resume beyond the EOF.
1939 * Daniel, November 28, 2001. We *always* get the size on downloads
1940 * now, so it is done before this even when not doing resumes. I saved
1941 * the comment above for nostalgical reasons! ;-)
1943 if(CURLE_OK != result) {
1944 infof(data, "ftp server doesn't support SIZE\n");
1945 /* We couldn't get the size and therefore we can't know if there
1946 really is a part of the file left to get, although the server
1947 will just close the connection when we start the connection so it
1948 won't cause us any harm, just not make us exit as nicely. */
1951 /* We got a file size report, so we check that there actually is a
1952 part of the file left to get, or else we go home. */
1953 if(conn->resume_from< 0) {
1954 /* We're supposed to download the last abs(from) bytes */
1955 if(foundsize < -conn->resume_from) {
1956 failf(data, "Offset (%" FORMAT_OFF_T
1957 ") was beyond file size (%" FORMAT_OFF_T ")",
1958 conn->resume_from, foundsize);
1959 return CURLE_FTP_BAD_DOWNLOAD_RESUME;
1961 /* convert to size to download */
1962 downloadsize = -conn->resume_from;
1963 /* download from where? */
1964 conn->resume_from = foundsize - downloadsize;
1967 if(foundsize < conn->resume_from) {
1968 failf(data, "Offset (%" FORMAT_OFF_T
1969 ") was beyond file size (%" FORMAT_OFF_T ")",
1970 conn->resume_from, foundsize);
1971 return CURLE_FTP_BAD_DOWNLOAD_RESUME;
1973 /* Now store the number of bytes we are expected to download */
1974 downloadsize = foundsize-conn->resume_from;
1978 if (downloadsize == 0) {
1979 /* no data to transfer */
1980 result=Curl_Transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
1981 infof(data, "File already completely downloaded\n");
1983 /* Set no_transfer so that we won't get any error in Curl_ftp_done()
1984 * because we didn't transfer the any file */
1985 ftp->no_transfer = TRUE;
1989 /* Set resume file transfer offset */
1990 infof(data, "Instructs server to resume from offset %" FORMAT_OFF_T
1994 FTPSENDF(conn, "REST %" FORMAT_OFF_T, conn->resume_from);
1996 result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
2000 if(ftpcode != 350) {
2001 failf(data, "Couldn't use REST: %s", buf+4);
2002 return CURLE_FTP_COULDNT_USE_REST;
2006 FTPSENDF(conn, "RETR %s", ftp->file);
2009 result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
2013 if((ftpcode == 150) || (ftpcode == 125)) {
2017 150 Opening BINARY mode data connection for /etc/passwd (2241
2018 bytes). (ok, the file is being transfered)
2021 150 Opening ASCII mode data connection for /bin/ls
2024 150 ASCII data connection for /bin/ls (137.167.104.91,37445) (0 bytes).
2027 150 Opening ASCII mode data connection for /linux/fisk/kpanelrc (0.0.0.0,0) (545 bytes).
2030 125 Data connection already open; Transfer starting. */
2032 curl_off_t size=-1; /* default unknown size */
2036 * It appears that there are FTP-servers that return size 0 for files
2037 * when SIZE is used on the file while being in BINARY mode. To work
2038 * around that (stupid) behavior, we attempt to parse the RETR response
2039 * even if the SIZE returned size zero.
2041 * Debugging help from Salvatore Sorrentino on February 26, 2003.
2045 !data->set.ftp_ascii &&
2046 (downloadsize < 1)) {
2048 * It seems directory listings either don't show the size or very
2049 * often uses size 0 anyway. ASCII transfers may very well turn out
2050 * that the transfered amount of data is not the same as this line
2051 * tells, why using this number in those cases only confuses us.
2053 * Example D above makes this parsing a little tricky */
2055 bytes=strstr(buf, " bytes");
2058 /* this is a hint there is size information in there! ;-) */
2060 /* scan for the parenthesis and break there */
2063 /* if only skip digits, or else we're in deep trouble */
2064 if(!isdigit((int)*bytes)) {
2068 /* one more estep backwards */
2071 /* only if we have nothing but digits: */
2073 /* get the number! */
2074 size = strtoofft(bytes, NULL, 0);
2079 else if(downloadsize > -1)
2080 size = downloadsize;
2082 if(data->set.ftp_use_port) {
2083 result = AllowServerConnect(conn);
2088 if(conn->ssl[SECONDARYSOCKET].use) {
2089 /* since we only have a plaintext TCP connection here, we must now
2091 infof(data, "Doing the SSL/TLS handshake on the data stream\n");
2092 result = Curl_SSLConnect(conn, SECONDARYSOCKET);
2097 if(size > conn->maxdownload && conn->maxdownload > 0)
2098 size = conn->size = conn->maxdownload;
2100 infof(data, "Getting file with size: %" FORMAT_OFF_T "\n", size);
2103 result=Curl_Transfer(conn, SECONDARYSOCKET, size, FALSE,
2105 -1, NULL); /* no upload here */
2110 if(dirlist && (ftpcode == 450)) {
2111 /* simply no matching files */
2112 ftp->no_transfer = TRUE; /* don't think we should download anything */
2115 failf(data, "%s", buf+4);
2116 return CURLE_FTP_COULDNT_RETR_FILE;
2121 /* end of transfer */
2126 /***********************************************************************
2130 * This is the actual DO function for FTP. Get a file/directory according to
2131 * the options previously setup.
2135 CURLcode ftp_perform(struct connectdata *conn,
2136 bool *connected) /* for the TCP connect status after
2139 /* this is FTP and no proxy */
2140 CURLcode result=CURLE_OK;
2141 struct SessionHandle *data=conn->data;
2142 char *buf = data->state.buffer; /* this is our buffer */
2144 /* the ftp struct is already inited in Curl_ftp_connect() */
2145 struct FTP *ftp = conn->proto.ftp;
2147 /* Send any QUOTE strings? */
2148 if(data->set.quote) {
2149 if ((result = ftp_sendquote(conn, data->set.quote)) != CURLE_OK)
2153 /* This is a re-used connection. Since we change directory to where the
2154 transfer is taking place, we must now get back to the original dir
2155 where we ended up after login: */
2156 if (conn->bits.reuse && ftp->entrypath) {
2157 if ((result = ftp_cwd_and_mkd(conn, ftp->entrypath)) != CURLE_OK)
2162 int i; /* counter for loop */
2163 for (i=0; ftp->dirs[i]; i++) {
2164 /* RFC 1738 says empty components should be respected too, but
2165 that is plain stupid since CWD can't be used with an empty argument */
2166 if ((result = ftp_cwd_and_mkd(conn, ftp->dirs[i])) != CURLE_OK)
2171 /* Requested time of file or time-depended transfer? */
2172 if((data->set.get_filetime || data->set.timecondition) &&
2174 result = ftp_getfiletime(conn, ftp->file);
2177 case CURLE_FTP_COULDNT_RETR_FILE:
2179 if(data->set.timecondition) {
2180 if((data->info.filetime > 0) && (data->set.timevalue > 0)) {
2181 switch(data->set.timecondition) {
2182 case CURL_TIMECOND_IFMODSINCE:
2184 if(data->info.filetime < data->set.timevalue) {
2185 infof(data, "The requested document is not new enough\n");
2186 ftp->no_transfer = TRUE; /* mark this to not transfer data */
2190 case CURL_TIMECOND_IFUNMODSINCE:
2191 if(data->info.filetime > data->set.timevalue) {
2192 infof(data, "The requested document is not old enough\n");
2193 ftp->no_transfer = TRUE; /* mark this to not transfer data */
2200 infof(data, "Skipping time comparison\n");
2209 /* If we have selected NOBODY and HEADER, it means that we only want file
2210 information. Which in FTP can't be much more than the file size and
2212 if(data->set.no_body && data->set.include_header && ftp->file) {
2213 /* The SIZE command is _not_ RFC 959 specified, and therefor many servers
2214 may not support it! It is however the only way we have to get a file's
2216 curl_off_t filesize;
2220 ftp->no_transfer = TRUE; /* this means no actual transfer is made */
2222 /* Some servers return different sizes for different modes, and thus we
2223 must set the proper type before we check the size */
2224 result = ftp_transfertype(conn, data->set.ftp_ascii);
2228 /* failing to get size is not a serious error */
2229 result = ftp_getsize(conn, ftp->file, &filesize);
2231 if(CURLE_OK == result) {
2232 sprintf(buf, "Content-Length: %" FORMAT_OFF_T "\r\n", filesize);
2233 result = Curl_client_write(data, CLIENTWRITE_BOTH, buf, 0);
2238 /* Determine if server can respond to REST command and therefore
2239 whether it can do a range */
2240 FTPSENDF(conn, "REST 0", NULL);
2241 result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
2243 if ((CURLE_OK == result) && (ftpcode == 350)) {
2244 result = Curl_client_write(data, CLIENTWRITE_BOTH,
2245 (char *)"Accept-ranges: bytes\r\n", 0);
2250 /* If we asked for a time of the file and we actually got one as
2251 well, we "emulate" a HTTP-style header in our output. */
2253 #ifdef HAVE_STRFTIME
2254 if(data->set.get_filetime && (data->info.filetime>=0) ) {
2256 time_t clock = (time_t)data->info.filetime;
2257 #ifdef HAVE_GMTIME_R
2259 tm = (struct tm *)gmtime_r(&clock, &buffer);
2261 tm = gmtime(&clock);
2263 /* format: "Tue, 15 Nov 1994 12:45:26" */
2264 strftime(buf, BUFSIZE-1, "Last-Modified: %a, %d %b %Y %H:%M:%S GMT\r\n",
2266 result = Curl_client_write(data, CLIENTWRITE_BOTH, buf, 0);
2275 if(data->set.no_body)
2276 /* doesn't really transfer any data */
2277 ftp->no_transfer = TRUE;
2278 /* Get us a second connection up and connected */
2279 else if(data->set.ftp_use_port) {
2280 /* We have chosen to use the PORT command */
2281 result = ftp_use_port(conn);
2282 if(CURLE_OK == result) {
2283 /* we have the data connection ready */
2284 infof(data, "Ordered connect of the data stream with PORT!\n");
2285 *connected = TRUE; /* mark us "still connected" */
2289 /* We have chosen (this is default) to use the PASV command */
2290 result = ftp_use_pasv(conn, connected);
2291 if(CURLE_OK == result && *connected)
2292 infof(data, "Connected the data stream with PASV!\n");
2298 /***********************************************************************
2302 * This function is registered as 'curl_do' function. It decodes the path
2303 * parts etc as a wrapper to the actual DO function (ftp_perform).
2305 * The input argument is already checked for validity.
2307 * ftp->ctl_valid starts out as FALSE, and gets set to TRUE if we reach the
2308 * end of the function.
2310 CURLcode Curl_ftp(struct connectdata *conn)
2312 CURLcode retcode=CURLE_OK;
2314 struct SessionHandle *data = conn->data;
2317 char *slash_pos; /* position of the first '/' char in curpos */
2318 char *cur_pos=conn->ppath; /* current position in ppath. point at the begin
2319 of next path component */
2320 int path_part=0;/* current path component */
2322 /* the ftp struct is already inited in ftp_connect() */
2323 ftp = conn->proto.ftp;
2324 ftp->ctl_valid = FALSE;
2325 conn->size = -1; /* make sure this is unknown at this point */
2327 Curl_pgrsSetUploadCounter(data, 0);
2328 Curl_pgrsSetDownloadCounter(data, 0);
2329 Curl_pgrsSetUploadSize(data, 0);
2330 Curl_pgrsSetDownloadSize(data, 0);
2332 /* fixed : initialize ftp->dirs[xxx] to NULL !
2333 is done in Curl_ftp_connect() */
2335 /* parse the URL path into separate path components */
2336 while((slash_pos=strchr(cur_pos, '/'))) {
2337 /* 1 or 0 to indicate absolute directory */
2338 bool absolute_dir = (cur_pos - conn->ppath > 0) && (path_part == 0);
2340 /* seek out the next path component */
2341 if (slash_pos-cur_pos) {
2342 /* we skip empty path components, like "x//y" since the FTP command CWD
2343 requires a parameter and a non-existant parameter a) doesn't work on
2344 many servers and b) has no effect on the others. */
2345 ftp->dirs[path_part] = curl_unescape(cur_pos - absolute_dir,
2346 slash_pos - cur_pos + absolute_dir);
2348 if (!ftp->dirs[path_part]) { /* run out of memory ... */
2349 failf(data, "no memory");
2351 return CURLE_OUT_OF_MEMORY;
2355 cur_pos = slash_pos + 1; /* jump to the rest of the string */
2360 cur_pos = slash_pos + 1; /* jump to the rest of the string */
2361 if(++path_part >= (CURL_MAX_FTP_DIRDEPTH-1)) {
2362 /* too deep, we need the last entry to be kept NULL at all
2363 times to signal end of list */
2364 failf(data, "too deep dir hierarchy");
2366 return CURLE_URL_MALFORMAT;
2371 ftp->file = cur_pos; /* the rest is the file name */
2374 ftp->file = curl_unescape(ftp->file, 0);
2375 if(NULL == ftp->file) {
2377 failf(data, "no memory");
2378 return CURLE_OUT_OF_MEMORY;
2382 ftp->file=NULL; /* instead of point to a zero byte, we make it a NULL
2385 retcode = ftp_perform(conn, &connected);
2387 if(CURLE_OK == retcode) {
2389 retcode = Curl_ftp_nextconnect(conn);
2391 if(retcode && (conn->sock[SECONDARYSOCKET] != CURL_SOCKET_BAD)) {
2392 /* Failure detected, close the second socket if it was created already */
2393 sclose(conn->sock[SECONDARYSOCKET]);
2394 conn->sock[SECONDARYSOCKET] = CURL_SOCKET_BAD;
2397 if(ftp->no_transfer)
2398 /* no data to transfer */
2399 retcode=Curl_Transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
2401 /* since we didn't connect now, we want do_more to get called */
2402 conn->bits.do_more = TRUE;
2407 ftp->ctl_valid = TRUE;
2411 /***********************************************************************
2415 * Sends the formated string as a ftp command to a ftp server
2417 * NOTE: we build the command in a fixed-length buffer, which sets length
2418 * restrictions on the command!
2420 CURLcode Curl_ftpsendf(struct connectdata *conn,
2421 const char *fmt, ...)
2423 ssize_t bytes_written;
2427 CURLcode res = CURLE_OK;
2431 vsnprintf(s, 250, fmt, ap);
2434 strcat(s, "\r\n"); /* append a trailing CRLF */
2437 write_len = strlen(s);
2440 res = Curl_write(conn, conn->sock[FIRSTSOCKET], sptr, write_len,
2446 if(conn->data->set.verbose)
2447 Curl_debug(conn->data, CURLINFO_HEADER_OUT, sptr, bytes_written);
2449 if(bytes_written != (ssize_t)write_len) {
2450 write_len -= bytes_written;
2451 sptr += bytes_written;
2460 /***********************************************************************
2464 * This should be called before calling sclose() on an ftp control connection
2465 * (not data connections). We should then wait for the response from the
2466 * server before returning. The calling code should then try to close the
2470 CURLcode Curl_ftp_quit(struct connectdata *conn)
2474 CURLcode ret = CURLE_OK;
2476 if(conn->proto.ftp->ctl_valid) {
2477 ret = Curl_ftpsendf(conn, "%s", "QUIT");
2479 ret = Curl_GetFTPResponse(&nread, conn, &ftpcode);
2485 /***********************************************************************
2487 * Curl_ftp_disconnect()
2489 * Disconnect from an FTP server. Cleanup protocol-specific per-connection
2492 CURLcode Curl_ftp_disconnect(struct connectdata *conn)
2494 struct FTP *ftp= conn->proto.ftp;
2496 /* We cannot send quit unconditionally. If this connection is stale or
2497 bad in any way, sending quit and waiting around here will make the
2498 disconnect wait in vain and cause more problems than we need to.
2500 Curl_ftp_quit() will check the state of ftp->ctl_valid. If it's ok it
2501 will try to send the QUIT command, otherwise it will just return.
2504 /* The FTP session may or may not have been allocated/setup at this point! */
2506 (void)Curl_ftp_quit(conn); /* ignore errors on the QUIT */
2509 free(ftp->entrypath);
2516 ftp->file = NULL; /* zero */
2523 /***********************************************************************
2527 * Makes a directory on the FTP server.
2531 CURLcode ftp_mkd(struct connectdata *conn, char *path)
2533 CURLcode result=CURLE_OK;
2534 int ftpcode; /* for ftp status */
2537 /* Create a directory on the remote server */
2538 FTPSENDF(conn, "MKD %s", path);
2540 result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
2547 infof( conn->data , "Created remote directory %s\n" , path );
2550 failf(conn->data, "Permission denied to make directory %s", path);
2551 result = CURLE_FTP_ACCESS_DENIED;
2554 failf(conn->data, "unrecognized MKD response: %d", ftpcode );
2555 result = CURLE_FTP_ACCESS_DENIED;
2561 /***********************************************************************
2565 * Send 'CWD' to the remote server to Change Working Directory. It is the ftp
2566 * version of the unix 'cd' command. This function is only called from the
2567 * ftp_cwd_and_mkd() function these days.
2569 * This function does NOT call failf().
2572 CURLcode ftp_cwd(struct connectdata *conn, char *path)
2578 FTPSENDF(conn, "CWD %s", path);
2579 result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
2581 /* According to RFC959, CWD is supposed to return 250 on success, but
2582 there seem to be non-compliant FTP servers out there that return 200,
2583 so we accept any '2xy' code here. */
2584 if (ftpcode/100 != 2)
2585 result = CURLE_FTP_ACCESS_DENIED;
2591 /***********************************************************************
2595 * Change to the given directory. If the directory is not present, and we
2596 * have been told to allow it, then create the directory and cd to it.
2599 static CURLcode ftp_cwd_and_mkd(struct connectdata *conn, char *path)
2603 result = ftp_cwd(conn, path);
2605 if(conn->data->set.ftp_create_missing_dirs) {
2606 result = ftp_mkd(conn, path);
2608 /* ftp_mkd() calls failf() itself */
2610 result = ftp_cwd(conn, path);
2613 failf(conn->data, "Couldn't cd to %s", path);
2618 #endif /* CURL_DISABLE_FTP */