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 HAVE_NI_WITHSCOPEID
109 #define NIFLAGS NI_NUMERICHOST | NI_NUMERICSERV | NI_WITHSCOPEID
111 #define NIFLAGS NI_NUMERICHOST | NI_NUMERICSERV
114 /* Local API functions */
115 static CURLcode ftp_sendquote(struct connectdata *conn,
116 struct curl_slist *quote);
117 static CURLcode ftp_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);
120 static CURLcode ftp_quit(struct connectdata *conn);
122 /* easy-to-use macro: */
123 #define FTPSENDF(x,y,z) if((result = Curl_ftpsendf(x,y,z))) return result
125 static void freedirs(struct FTP *ftp)
129 for (i=0; i < ftp->dirdepth; i++){
144 /***********************************************************************
146 * AllowServerConnect()
148 * When we've issue the PORT command, we have told the server to connect
149 * to us. This function will sit and wait here until the server has
153 static CURLcode AllowServerConnect(struct connectdata *conn)
157 struct SessionHandle *data = conn->data;
158 curl_socket_t sock = conn->sock[SECONDARYSOCKET];
159 struct timeval now = Curl_tvnow();
160 long timespent = Curl_tvdiff(Curl_tvnow(), now)/1000;
161 long timeout = data->set.connecttimeout?data->set.connecttimeout:
162 (data->set.timeout?data->set.timeout: 0);
166 FD_SET(sock, &rdset);
169 timeout -= timespent;
171 failf(data, "Timed out before server could connect to us");
172 return CURLE_OPERATION_TIMEDOUT;
176 /* we give the server 60 seconds to connect to us, or a custom timeout */
177 dt.tv_sec = (int)(timeout?timeout:60);
180 switch (select(sock+1, &rdset, NULL, NULL, &dt)) {
183 failf(data, "Error while waiting for server connect");
184 return CURLE_FTP_PORT_FAILED;
185 case 0: /* timeout */
187 failf(data, "Timeout while waiting for server connect");
188 return CURLE_FTP_PORT_FAILED;
190 /* we have received data here */
193 size_t size = sizeof(struct sockaddr_in);
194 struct sockaddr_in add;
196 getsockname(sock, (struct sockaddr *) &add, (socklen_t *)&size);
197 s=accept(sock, (struct sockaddr *) &add, (socklen_t *)&size);
199 sclose(sock); /* close the first socket */
201 if (CURL_SOCKET_BAD == s) {
203 failf(data, "Error accept()ing server connect");
204 return CURLE_FTP_PORT_FAILED;
206 infof(data, "Connection accepted from server\n");
208 conn->sock[SECONDARYSOCKET] = s;
209 Curl_nonblock(s, TRUE); /* enable non-blocking */
218 /* --- parse FTP server responses --- */
221 * Curl_GetFTPResponse() is supposed to be invoked after each command sent to
222 * a remote FTP server. This function will wait and read all lines of the
223 * response and extract the relevant return code for the invoking function.
226 CURLcode Curl_GetFTPResponse(ssize_t *nreadp, /* return number of bytes read */
227 struct connectdata *conn,
228 int *ftpcode) /* return the ftp-code */
230 /* Brand new implementation.
231 * We cannot read just one byte per read() and then go back to select()
232 * as it seems that the OpenSSL read() stuff doesn't grok that properly.
234 * Alas, read as much as possible, split up into lines, use the ending
235 * line in a response or continue reading. */
237 curl_socket_t sockfd = conn->sock[FIRSTSOCKET];
238 int perline; /* count bytes per line */
242 long timeout; /* timeout in seconds */
243 struct timeval interval;
246 struct SessionHandle *data = conn->data;
248 int code=0; /* default ftp "error code" to return */
249 char *buf = data->state.buffer;
250 CURLcode result = CURLE_OK;
251 struct FTP *ftp = conn->proto.ftp;
252 struct timeval now = Curl_tvnow();
255 *ftpcode = 0; /* 0 for errors */
257 FD_ZERO (&readfd); /* clear it */
258 FD_SET (sockfd, &readfd); /* read socket */
260 /* get this in a backup variable to be able to restore it on each lap in the
271 while((*nreadp<BUFSIZE) && (keepon && !result)) {
272 /* check and reset timeout value every lap */
273 if(data->set.ftp_response_timeout )
274 /* if CURLOPT_FTP_RESPONSE_TIMEOUT is set, use that to determine
275 remaining time. Also, use "now" as opposed to "conn->now"
276 because ftp_response_timeout is only supposed to govern
277 the response for any given ftp response, not for the time
278 from connect to the given ftp response. */
279 timeout = data->set.ftp_response_timeout - /* timeout time */
280 Curl_tvdiff(Curl_tvnow(), now)/1000; /* spent time */
281 else if(data->set.timeout)
282 /* if timeout is requested, find out how much remaining time we have */
283 timeout = data->set.timeout - /* timeout time */
284 Curl_tvdiff(Curl_tvnow(), conn->now)/1000; /* spent time */
286 /* Even without a requested timeout, we only wait response_time
287 seconds for the full response to arrive before we bail out */
288 timeout = ftp->response_time -
289 Curl_tvdiff(Curl_tvnow(), now)/1000; /* spent time */
292 failf(data, "FTP response timeout");
293 return CURLE_OPERATION_TIMEDOUT; /* already too little time */
297 readfd = rkeepfd; /* set every lap */
298 interval.tv_sec = 1; /* use 1 second timeout intervals */
299 interval.tv_usec = 0;
301 switch (select (sockfd+1, &readfd, NULL, NULL, &interval)) {
302 case -1: /* select() error, stop reading */
303 result = CURLE_RECV_ERROR;
304 failf(data, "FTP response aborted due to select() error: %d", errno);
306 case 0: /* timeout */
307 if(Curl_pgrsUpdate(conn))
308 return CURLE_ABORTED_BY_CALLBACK;
309 continue; /* just continue in our loop for the timeout duration */
315 if(CURLE_OK == result) {
317 * This code previously didn't use the kerberos sec_read() code
318 * to read, but when we use Curl_read() it may do so. Do confirm
319 * that this is still ok and then remove this comment!
322 /* we had data in the "cache", copy that instead of doing an actual
325 * Dave Meyer, December 2003:
326 * ftp->cache_size is cast to int here. This should be safe,
327 * because it would have been populated with something of size
328 * int to begin with, even though its datatype may be larger
331 memcpy(ptr, ftp->cache, (int)ftp->cache_size);
332 gotbytes = (int)ftp->cache_size;
333 free(ftp->cache); /* free the cache */
334 ftp->cache = NULL; /* clear the pointer */
335 ftp->cache_size = 0; /* zero the size just in case */
338 int res = Curl_read(conn, sockfd, ptr, BUFSIZE-*nreadp, &gotbytes);
341 continue; /* go looping again */
349 else if(gotbytes <= 0) {
351 result = CURLE_RECV_ERROR;
352 failf(data, "FTP response reading failed");
355 /* we got a whole chunk of data, which can be anything from one
356 * byte to a set of lines and possible just a piece of the last
360 conn->headerbytecount += gotbytes;
363 for(i = 0; i < gotbytes; ptr++, i++) {
366 /* a newline is CRLF in ftp-talk, so the CR is ignored as
367 the line isn't really terminated until the LF comes */
369 /* output debug output if that is requested */
370 if(data->set.verbose)
371 Curl_debug(data, CURLINFO_HEADER_IN, line_start, perline);
374 * We pass all response-lines to the callback function registered
375 * for "headers". The response lines can be seen as a kind of
378 result = Curl_client_write(data, CLIENTWRITE_HEADER,
379 line_start, perline);
383 #define lastline(line) (isdigit((int)line[0]) && isdigit((int)line[1]) && \
384 isdigit((int)line[2]) && (' ' == line[3]))
386 if(perline>3 && lastline(line_start)) {
387 /* This is the end of the last line, copy the last
388 * line to the start of the buffer and zero terminate,
389 * for old times sake (and krb4)! */
392 for(meow=line_start, n=0; meow<ptr; meow++, n++)
394 *meow=0; /* zero terminate */
396 line_start = ptr+1; /* advance pointer */
397 i++; /* skip this before getting out */
400 perline=0; /* line starts over here */
404 if(!keepon && (i != gotbytes)) {
405 /* We found the end of the response lines, but we didn't parse the
406 full chunk of data we have read from the server. We therefore
407 need to store the rest of the data to be checked on the next
408 invoke as it may actually contain another end of response
409 already! Cleverly figured out by Eric Lavigne in December
411 ftp->cache_size = gotbytes - i;
412 ftp->cache = (char *)malloc((int)ftp->cache_size);
414 memcpy(ftp->cache, line_start, (int)ftp->cache_size);
416 return CURLE_OUT_OF_MEMORY; /**BANG**/
418 } /* there was data */
420 } /* while there's buffer left and loop is requested */
426 /* handle the security-oriented responses 6xx ***/
427 /* FIXME: some errorchecking perhaps... ***/
430 Curl_sec_read_msg(conn, buf, prot_safe);
433 Curl_sec_read_msg(conn, buf, prot_private);
436 Curl_sec_read_msg(conn, buf, prot_confidential);
439 /* normal ftp stuff we pass through! */
445 *ftpcode=code; /* return the initial number like this */
447 /* store the latest code for later retrieval */
448 conn->data->info.httpcode=code;
453 static const char *ftpauth[]= {
458 * Curl_ftp_connect() should do everything that is to be considered a part of
459 * the connection phase.
461 CURLcode Curl_ftp_connect(struct connectdata *conn)
463 /* this is FTP and no proxy */
465 struct SessionHandle *data=conn->data;
466 char *buf = data->state.buffer; /* this is our buffer */
471 ftp = (struct FTP *)malloc(sizeof(struct FTP));
473 return CURLE_OUT_OF_MEMORY;
475 memset(ftp, 0, sizeof(struct FTP));
476 conn->proto.ftp = ftp;
478 /* We always support persistant connections on ftp */
479 conn->bits.close = FALSE;
481 /* get some initial data into the ftp struct */
482 ftp->bytecountp = &conn->bytecount;
484 /* no need to duplicate them, this connectdata struct won't change */
485 ftp->user = conn->user;
486 ftp->passwd = conn->passwd;
487 ftp->response_time = 3600; /* set default response time-out */
489 if (data->set.tunnel_thru_httpproxy) {
490 /* We want "seamless" FTP operations through HTTP proxy tunnel */
491 result = Curl_ConnectHTTPProxyTunnel(conn, FIRSTSOCKET,
492 conn->host.name, conn->remote_port);
493 if(CURLE_OK != result)
497 if(conn->protocol & PROT_FTPS) {
498 /* FTPS is simply ftp with SSL for the control channel */
499 /* now, perform the SSL initialization for this socket */
500 result = Curl_SSLConnect(conn, FIRSTSOCKET);
505 /* The first thing we do is wait for the "220*" line: */
506 result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
511 failf(data, "This doesn't seem like a nice ftp-server response");
512 return CURLE_FTP_WEIRD_SERVER_REPLY;
516 /* if not anonymous login, try a secure login */
519 /* request data protection level (default is 'clear') */
520 Curl_sec_request_prot(conn, "private");
522 /* We set private first as default, in case the line below fails to
524 Curl_sec_request_prot(conn, data->set.krb4_level);
526 if(Curl_sec_login(conn) != 0)
527 infof(data, "Logging in with password in cleartext!\n");
529 infof(data, "Authentication successful\n");
533 if(data->set.ftp_ssl && !conn->ssl[FIRSTSOCKET].use) {
534 /* we don't have a SSL/TLS connection, try a FTPS connection now */
536 for (try = 0; ftpauth[try]; try++) {
538 FTPSENDF(conn, "AUTH %s", ftpauth[try]);
540 result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
545 /* RFC2228 (page 5) says:
547 * If the server is willing to accept the named security mechanism, and
548 * does not require any security data, it must respond with reply code
552 if((ftpcode == 234) || (ftpcode == 334)) {
553 result = Curl_SSLConnect(conn, FIRSTSOCKET);
556 conn->protocol |= PROT_FTPS;
557 conn->ssl[SECONDARYSOCKET].use = FALSE; /* clear-text data */
564 FTPSENDF(conn, "USER %s", ftp->user?ftp->user:"");
566 /* wait for feedback */
567 result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
572 /* 530 User ... access denied
573 (the server denies to log the specified user) */
574 failf(data, "Access denied: %s", &buf[4]);
575 return CURLE_FTP_ACCESS_DENIED;
577 else if(ftpcode == 331) {
578 /* 331 Password required for ...
579 (the server requires to send the user's password too) */
580 FTPSENDF(conn, "PASS %s", ftp->passwd?ftp->passwd:"");
581 result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
586 /* 530 Login incorrect.
587 (the username and/or the password are incorrect) */
588 failf(data, "the username and/or the password are incorrect");
589 return CURLE_FTP_USER_PASSWORD_INCORRECT;
591 else if(ftpcode == 230) {
592 /* 230 User ... logged in.
593 (user successfully logged in) */
595 infof(data, "We have successfully logged in\n");
598 failf(data, "Odd return code after PASS");
599 return CURLE_FTP_WEIRD_PASS_REPLY;
602 else if(buf[0] == '2') {
603 /* 230 User ... logged in.
604 (the user logged in without password) */
605 infof(data, "We have successfully logged in\n");
606 if (conn->ssl[FIRSTSOCKET].use) {
608 /* We are logged in with Kerberos, now set the requested protection
611 if(conn->sec_complete)
612 Curl_sec_set_protection_level(conn);
614 /* We may need to issue a KAUTH here to have access to the files
615 * do it if user supplied a password
617 if(conn->passwd && *conn->passwd) {
618 result = Curl_krb_kauth(conn);
626 failf(data, "Odd return code after USER");
627 return CURLE_FTP_WEIRD_USER_REPLY;
630 if(conn->ssl[FIRSTSOCKET].use) {
631 /* PBSZ = PROTECTION BUFFER SIZE.
633 The 'draft-murray-auth-ftp-ssl' (draft 12, page 7) says:
635 Specifically, the PROT command MUST be preceded by a PBSZ command
636 and a PBSZ command MUST be preceded by a successful security data
637 exchange (the TLS negotiation in this case)
641 Thus the PBSZ command must still be issued, but must have a parameter
642 of '0' to indicate that no buffering is taking place and the data
643 connection should not be encapsulated.
645 FTPSENDF(conn, "PBSZ %d", 0);
646 result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
650 /* For TLS, the data connection can have one of two security levels.
652 1)Clear (requested by 'PROT C')
654 2)Private (requested by 'PROT P')
656 if(!conn->ssl[SECONDARYSOCKET].use) {
657 FTPSENDF(conn, "PROT %c", 'P');
658 result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
663 /* We have enabled SSL for the data connection! */
664 conn->ssl[SECONDARYSOCKET].use = TRUE;
666 /* FTP servers typically responds with 500 if they decide to reject
671 /* send PWD to discover our entry point */
672 FTPSENDF(conn, "PWD", NULL);
674 /* wait for feedback */
675 result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
680 char *dir = (char *)malloc(nread+1);
682 char *ptr=&buf[4]; /* start on the first letter */
685 return CURLE_OUT_OF_MEMORY;
687 /* Reply format is like
688 257<space>"<directory-name>"<space><commentary> and the RFC959 says
690 The directory name can contain any character; embedded double-quotes
691 should be escaped by double-quotes (the "quote-doubling" convention).
694 /* it started good */
699 /* "quote-doubling" */
705 *store = '\0'; /* zero terminate */
706 break; /* get out of this loop */
714 ftp->entrypath =dir; /* remember this */
715 infof(data, "Entry path is '%s'\n", ftp->entrypath);
718 /* couldn't get the path */
720 infof(data, "Failed to figure out path\n");
725 /* We couldn't read the PWD response! */
731 /***********************************************************************
735 * The DONE function. This does what needs to be done after a single DO has
738 * Input argument is already checked for validity.
740 CURLcode Curl_ftp_done(struct connectdata *conn)
742 struct SessionHandle *data = conn->data;
743 struct FTP *ftp = conn->proto.ftp;
746 CURLcode result=CURLE_OK;
747 bool was_ctl_valid = ftp->ctl_valid;
749 /* free the dir tree and file parts */
752 ftp->ctl_valid = FALSE;
754 if(data->set.upload) {
755 if((-1 != data->set.infilesize) &&
756 (data->set.infilesize != *ftp->bytecountp) &&
758 failf(data, "Uploaded unaligned file size (%" FORMAT_OFF_T
759 " out of %" FORMAT_OFF_T " bytes)",
760 *ftp->bytecountp, data->set.infilesize);
761 conn->bits.close = TRUE; /* close this connection since we don't
762 know what state this error leaves us in */
763 return CURLE_PARTIAL_FILE;
767 if((-1 != conn->size) && (conn->size != *ftp->bytecountp) &&
768 (conn->maxdownload != *ftp->bytecountp)) {
769 failf(data, "Received only partial file: %" FORMAT_OFF_T " bytes",
771 conn->bits.close = TRUE; /* close this connection since we don't
772 know what state this error leaves us in */
773 return CURLE_PARTIAL_FILE;
775 else if(!ftp->dont_check &&
778 /* We consider this an error, but there's no true FTP error received
779 why we need to continue to "read out" the server response too.
780 We don't want to leave a "waiting" server reply if we'll get told
781 to make a second request on this same connection! */
782 failf(data, "No data was received!");
783 result = CURLE_FTP_COULDNT_RETR_FILE;
787 ftp->ctl_valid = was_ctl_valid;
790 Curl_sec_fflush_fd(conn, conn->sock[SECONDARYSOCKET]);
792 /* shut down the socket to inform the server we're done */
793 sclose(conn->sock[SECONDARYSOCKET]);
794 conn->sock[SECONDARYSOCKET] = CURL_SOCKET_BAD;
796 if(!ftp->no_transfer) {
797 /* Let's see what the server says about the transfer we just performed,
798 but lower the timeout as sometimes this connection has died while
799 the data has been transfered. This happens when doing through NATs
800 etc that abandon old silent connections.
802 ftp->response_time = 60; /* give it only a minute for now */
804 result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
806 ftp->response_time = 3600; /* set this back to one hour waits */
808 if(!nread && (CURLE_OPERATION_TIMEDOUT == result)) {
809 failf(data, "control connection looks dead");
816 if(!ftp->dont_check) {
817 /* 226 Transfer complete, 250 Requested file action okay, completed. */
818 if((ftpcode != 226) && (ftpcode != 250)) {
819 failf(data, "server did not report OK, got %d", ftpcode);
820 return CURLE_FTP_WRITE_ERROR;
825 /* clear these for next connection */
826 ftp->no_transfer = FALSE;
827 ftp->dont_check = FALSE;
829 /* Send any post-transfer QUOTE strings? */
830 if(!result && data->set.postquote)
831 result = ftp_sendquote(conn, data->set.postquote);
836 /***********************************************************************
840 * Where a 'quote' means a list of custom commands to send to the server.
841 * The quote list is passed as an argument.
845 CURLcode ftp_sendquote(struct connectdata *conn, struct curl_slist *quote)
847 struct curl_slist *item;
855 FTPSENDF(conn, "%s", item->data);
857 result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
861 if (ftpcode >= 400) {
862 failf(conn->data, "QUOT string not accepted: %s", item->data);
863 return CURLE_FTP_QUOTE_ERROR;
873 /***********************************************************************
877 * Get the timestamp of the given file.
880 CURLcode ftp_getfiletime(struct connectdata *conn, char *file)
882 CURLcode result=CURLE_OK;
883 int ftpcode; /* for ftp status */
885 char *buf = conn->data->state.buffer;
887 /* we have requested to get the modified-time of the file, this is yet
888 again a grey area as the MDTM is not kosher RFC959 */
889 FTPSENDF(conn, "MDTM %s", file);
891 result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
898 /* we got a time. Format should be: "YYYYMMDDHHMMSS[.sss]" where the
899 last .sss part is optional and means fractions of a second */
900 int year, month, day, hour, minute, second;
901 if(6 == sscanf(buf+4, "%04d%02d%02d%02d%02d%02d",
902 &year, &month, &day, &hour, &minute, &second)) {
903 /* we have a time, reformat it */
904 time_t secs=time(NULL);
905 sprintf(buf, "%04d%02d%02d %02d:%02d:%02d GMT",
906 year, month, day, hour, minute, second);
907 /* now, convert this into a time() value: */
908 conn->data->info.filetime = curl_getdate(buf, &secs);
913 infof(conn->data, "unsupported MDTM reply format\n");
915 case 550: /* "No such file or directory" */
916 failf(conn->data, "Given file does not exist");
917 result = CURLE_FTP_COULDNT_RETR_FILE;
923 /***********************************************************************
927 * Set transfer type. We only deal with ASCII or BINARY so this function
930 static CURLcode ftp_transfertype(struct connectdata *conn,
933 struct SessionHandle *data = conn->data;
938 FTPSENDF(conn, "TYPE %s", ascii?"A":"I");
940 result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
945 failf(data, "Couldn't set %s mode",
946 ascii?"ASCII":"binary");
947 return ascii? CURLE_FTP_COULDNT_SET_ASCII:CURLE_FTP_COULDNT_SET_BINARY;
953 /***********************************************************************
957 * Returns the file size (in bytes) of the given remote file.
961 CURLcode ftp_getsize(struct connectdata *conn, char *file,
964 struct SessionHandle *data = conn->data;
967 char *buf=data->state.buffer;
970 FTPSENDF(conn, "SIZE %s", file);
971 result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
976 /* get the size from the ascii string: */
977 *size = curlx_strtoofft(buf+4, NULL, 0);
980 return CURLE_FTP_COULDNT_GET_SIZE;
985 /***************************************************************************
989 * This function only outputs some informationals about this second connection
990 * when we've issued a PASV command before and thus we have connected to a
991 * possibly new IP address.
995 ftp_pasv_verbose(struct connectdata *conn,
996 Curl_ipconnect *addr,
997 char *newhost, /* ascii version */
1001 /*****************************************************************
1003 * IPv4-only code section
1007 struct hostent * answer;
1009 #ifdef HAVE_INET_NTOA_R
1012 /* The array size trick below is to make this a large chunk of memory
1013 suitably 8-byte aligned on 64-bit platforms. This was thoughtfully
1014 suggested by Philip Gladstone. */
1015 long bigbuf[9000 / sizeof(long)];
1017 #if defined(HAVE_INET_ADDR)
1019 # if defined(HAVE_GETHOSTBYADDR_R)
1022 char *hostent_buf = (char *)bigbuf; /* get a char * to the buffer */
1024 address = inet_addr(newhost);
1025 # ifdef HAVE_GETHOSTBYADDR_R
1027 # ifdef HAVE_GETHOSTBYADDR_R_5
1028 /* AIX, Digital Unix (OSF1, Tru64) style:
1029 extern int gethostbyaddr_r(char *addr, size_t len, int type,
1030 struct hostent *htent, struct hostent_data *ht_data); */
1032 /* Fred Noz helped me try this out, now it at least compiles! */
1034 /* Bjorn Reese (November 28 2001):
1035 The Tru64 man page on gethostbyaddr_r() says that
1036 the hostent struct must be filled with zeroes before the call to
1039 ... as must be struct hostent_data Craig Markwardt 19 Sep 2002. */
1041 memset(hostent_buf, 0, sizeof(struct hostent)+sizeof(struct hostent_data));
1043 if(gethostbyaddr_r((char *) &address,
1044 sizeof(address), AF_INET,
1045 (struct hostent *)hostent_buf,
1046 (struct hostent_data *)(hostent_buf + sizeof(*answer))))
1049 answer=(struct hostent *)hostent_buf;
1052 # ifdef HAVE_GETHOSTBYADDR_R_7
1053 /* Solaris and IRIX */
1054 answer = gethostbyaddr_r((char *) &address, sizeof(address), AF_INET,
1055 (struct hostent *)bigbuf,
1056 hostent_buf + sizeof(*answer),
1057 sizeof(bigbuf) - sizeof(*answer),
1060 # ifdef HAVE_GETHOSTBYADDR_R_8
1062 if(gethostbyaddr_r((char *) &address, sizeof(address), AF_INET,
1063 (struct hostent *)hostent_buf,
1064 hostent_buf + sizeof(*answer),
1065 sizeof(bigbuf) - sizeof(*answer),
1068 answer=NULL; /* error */
1072 (void)hostent_buf; /* avoid compiler warning */
1073 answer = gethostbyaddr((char *) &address, sizeof(address), AF_INET);
1078 (void) memcpy(&in.s_addr, addr, sizeof (Curl_ipconnect));
1079 infof(conn->data, "Connecting to %s (%s) port %u\n",
1080 answer?answer->h_name:newhost,
1081 #if defined(HAVE_INET_NTOA_R)
1082 inet_ntoa_r(in, ntoa_buf, sizeof(ntoa_buf)),
1089 /*****************************************************************
1091 * IPv6-only code section
1093 char hbuf[NI_MAXHOST]; /* ~1KB */
1094 char nbuf[NI_MAXHOST]; /* ~1KB */
1095 char sbuf[NI_MAXSERV]; /* around 32 */
1096 (void)port; /* prevent compiler warning */
1097 if (getnameinfo(addr->ai_addr, addr->ai_addrlen,
1098 nbuf, sizeof(nbuf), sbuf, sizeof(sbuf), NIFLAGS)) {
1099 snprintf(nbuf, sizeof(nbuf), "?");
1100 snprintf(sbuf, sizeof(sbuf), "?");
1103 if (getnameinfo(addr->ai_addr, addr->ai_addrlen,
1104 hbuf, sizeof(hbuf), NULL, 0, 0)) {
1105 infof(conn->data, "Connecting to %s (%s) port %s\n", nbuf, newhost, sbuf);
1108 infof(conn->data, "Connecting to %s (%s) port %s\n", hbuf, nbuf, sbuf);
1113 /***********************************************************************
1117 * Send the proper PORT command. PORT is the ftp client's way of telling the
1118 * server that *WE* open a port that we listen on an awaits the server to
1119 * connect to. This is the opposite of PASV.
1123 CURLcode ftp_use_port(struct connectdata *conn)
1125 struct SessionHandle *data=conn->data;
1126 curl_socket_t portsock= CURL_SOCKET_BAD;
1128 int ftpcode; /* receive FTP response codes in this */
1132 /******************************************************************
1134 * Here's a piece of IPv6-specific code coming up
1138 struct addrinfo hints, *res, *ai;
1139 struct sockaddr_storage ss;
1141 char hbuf[NI_MAXHOST];
1143 struct sockaddr *sa=(struct sockaddr *)&ss;
1146 char portmsgbuf[4096], tmp[4096];
1148 const char *mode[] = { "EPRT", "LPRT", "PORT", NULL };
1154 * we should use Curl_if2ip? given pickiness of recent ftpd,
1155 * I believe we should use the same address as the control connection.
1158 rc = getsockname(conn->sock[FIRSTSOCKET], (struct sockaddr *)&ss, &sslen);
1160 failf(data, "getsockname() returned %d\n", rc);
1161 return CURLE_FTP_PORT_FAILED;
1164 rc = getnameinfo((struct sockaddr *)&ss, sslen, hbuf, sizeof(hbuf), NULL, 0,
1167 failf(data, "getnameinfo() returned %d\n", rc);
1168 return CURLE_FTP_PORT_FAILED;
1171 memset(&hints, 0, sizeof(hints));
1172 hints.ai_family = sa->sa_family;
1173 /*hints.ai_family = ss.ss_family;
1174 this way can be used if sockaddr_storage is properly defined, as glibc
1176 hints.ai_socktype = SOCK_STREAM;
1177 hints.ai_flags = AI_PASSIVE;
1179 rc = getaddrinfo(hbuf, NULL, &hints, &res);
1181 failf(data, "getaddrinfo() returned %d\n", rc);
1182 return CURLE_FTP_PORT_FAILED;
1185 portsock = CURL_SOCKET_BAD;
1187 for (ai = res; ai; ai = ai->ai_next) {
1189 * Workaround for AIX5 getaddrinfo() problem (it doesn't set ai_socktype):
1191 if (ai->ai_socktype == 0)
1192 ai->ai_socktype = hints.ai_socktype;
1194 portsock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
1195 if (portsock == CURL_SOCKET_BAD) {
1196 error = Curl_ourerrno();
1200 if (bind(portsock, ai->ai_addr, ai->ai_addrlen) < 0) {
1201 error = Curl_ourerrno();
1203 portsock = CURL_SOCKET_BAD;
1207 if (listen(portsock, 1) < 0) {
1208 error = Curl_ourerrno();
1210 portsock = CURL_SOCKET_BAD;
1217 if (portsock == CURL_SOCKET_BAD) {
1218 failf(data, "%s", Curl_strerror(conn,error));
1219 return CURLE_FTP_PORT_FAILED;
1223 if (getsockname(portsock, sa, &sslen) < 0) {
1224 failf(data, "%s", Curl_strerror(conn,Curl_ourerrno()));
1225 return CURLE_FTP_PORT_FAILED;
1228 for (modep = (char **)(data->set.ftp_use_eprt?&mode[0]:&mode[2]);
1229 modep && *modep; modep++) {
1233 switch (sa->sa_family) {
1235 ap = (unsigned char *)&((struct sockaddr_in *)&ss)->sin_addr;
1236 alen = sizeof(((struct sockaddr_in *)&ss)->sin_addr);
1237 pp = (unsigned char *)&((struct sockaddr_in *)&ss)->sin_port;
1238 plen = sizeof(((struct sockaddr_in *)&ss)->sin_port);
1243 ap = (unsigned char *)&((struct sockaddr_in6 *)&ss)->sin6_addr;
1244 alen = sizeof(((struct sockaddr_in6 *)&ss)->sin6_addr);
1245 pp = (unsigned char *)&((struct sockaddr_in6 *)&ss)->sin6_port;
1246 plen = sizeof(((struct sockaddr_in6 *)&ss)->sin6_port);
1252 lprtaf = eprtaf = -1;
1256 if (strcmp(*modep, "EPRT") == 0) {
1259 if (getnameinfo((struct sockaddr *)&ss, sslen,
1260 portmsgbuf, sizeof(portmsgbuf), tmp, sizeof(tmp),
1264 /* do not transmit IPv6 scope identifier to the wire */
1265 if (sa->sa_family == AF_INET6) {
1266 char *q = strchr(portmsgbuf, '%');
1271 result = Curl_ftpsendf(conn, "%s |%d|%s|%s|", *modep, eprtaf,
1276 else if (strcmp(*modep, "LPRT") == 0 ||
1277 strcmp(*modep, "PORT") == 0) {
1280 if (strcmp(*modep, "LPRT") == 0 && lprtaf < 0)
1282 if (strcmp(*modep, "PORT") == 0 && sa->sa_family != AF_INET)
1285 portmsgbuf[0] = '\0';
1286 if (strcmp(*modep, "LPRT") == 0) {
1287 snprintf(tmp, sizeof(tmp), "%d,%d", lprtaf, alen);
1288 if (strlcat(portmsgbuf, tmp, sizeof(portmsgbuf)) >=
1289 sizeof(portmsgbuf)) {
1294 for (i = 0; i < alen; i++) {
1296 snprintf(tmp, sizeof(tmp), ",%u", ap[i]);
1298 snprintf(tmp, sizeof(tmp), "%u", ap[i]);
1300 if (strlcat(portmsgbuf, tmp, sizeof(portmsgbuf)) >=
1301 sizeof(portmsgbuf)) {
1306 if (strcmp(*modep, "LPRT") == 0) {
1307 snprintf(tmp, sizeof(tmp), ",%d", plen);
1309 if (strlcat(portmsgbuf, tmp, sizeof(portmsgbuf)) >= sizeof(portmsgbuf))
1313 for (i = 0; i < plen; i++) {
1314 snprintf(tmp, sizeof(tmp), ",%u", pp[i]);
1316 if (strlcat(portmsgbuf, tmp, sizeof(portmsgbuf)) >=
1317 sizeof(portmsgbuf)) {
1322 result = Curl_ftpsendf(conn, "%s %s", *modep, portmsgbuf);
1327 result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
1331 if (ftpcode != 200) {
1340 failf(data, "PORT command attempts failed");
1341 return CURLE_FTP_PORT_FAILED;
1343 /* we set the secondary socket variable to this for now, it
1344 is only so that the cleanup function will close it in case
1345 we fail before the true secondary stuff is made */
1346 conn->sock[SECONDARYSOCKET] = portsock;
1349 /******************************************************************
1351 * Here's a piece of IPv4-specific code coming up
1354 struct sockaddr_in sa;
1355 struct Curl_dns_entry *h=NULL;
1356 unsigned short porttouse;
1357 char myhost[256] = "";
1358 bool sa_filled_in = FALSE;
1360 if(data->set.ftpport) {
1364 /* First check if the given name is an IP address */
1365 in=inet_addr(data->set.ftpport);
1367 if((in == CURL_INADDR_NONE) &&
1368 Curl_if2ip(data->set.ftpport, myhost, sizeof(myhost))) {
1369 rc = Curl_resolv(conn, myhost, 0, &h);
1370 if(rc == CURLRESOLV_PENDING)
1371 rc = Curl_wait_for_resolv(conn, &h);
1374 size_t len = strlen(data->set.ftpport);
1376 rc = Curl_resolv(conn, data->set.ftpport, 0, &h);
1377 if(rc == CURLRESOLV_PENDING)
1378 rc = Curl_wait_for_resolv(conn, &h);
1381 strcpy(myhost, data->set.ftpport); /* buffer overflow risk */
1385 /* pick a suitable default here */
1390 if (getsockname(conn->sock[FIRSTSOCKET],
1391 (struct sockaddr *)&sa, &sslen) < 0) {
1392 failf(data, "getsockname() failed");
1393 return CURLE_FTP_PORT_FAILED;
1396 sa_filled_in = TRUE; /* the sa struct is filled in */
1400 /* when we return from here, we can forget about this */
1401 Curl_resolv_unlock(data, h);
1403 if ( h || sa_filled_in) {
1404 if( (portsock = socket(AF_INET, SOCK_STREAM, 0)) != CURL_SOCKET_BAD ) {
1407 /* we set the secondary socket variable to this for now, it
1408 is only so that the cleanup function will close it in case
1409 we fail before the true secondary stuff is made */
1410 conn->sock[SECONDARYSOCKET] = portsock;
1413 memset((char *)&sa, 0, sizeof(sa));
1414 memcpy((char *)&sa.sin_addr,
1417 sa.sin_family = AF_INET;
1418 sa.sin_addr.s_addr = INADDR_ANY;
1424 if(bind(portsock, (struct sockaddr *)&sa, size) >= 0) {
1425 /* we succeeded to bind */
1426 struct sockaddr_in add;
1427 socklen_t socksize = sizeof(add);
1429 if(getsockname(portsock, (struct sockaddr *) &add,
1431 failf(data, "getsockname() failed");
1432 return CURLE_FTP_PORT_FAILED;
1434 porttouse = ntohs(add.sin_port);
1436 if ( listen(portsock, 1) < 0 ) {
1437 failf(data, "listen(2) failed on socket");
1438 return CURLE_FTP_PORT_FAILED;
1442 failf(data, "bind(2) failed on socket");
1443 return CURLE_FTP_PORT_FAILED;
1447 failf(data, "socket(2) failed (%s)");
1448 return CURLE_FTP_PORT_FAILED;
1452 failf(data, "could't find my own IP address (%s)", myhost);
1453 return CURLE_FTP_PORT_FAILED;
1456 #ifdef HAVE_INET_NTOA_R
1460 unsigned short ip[5];
1461 (void) memcpy(&in.s_addr,
1462 h?*h->addr->h_addr_list:(char *)&sa.sin_addr.s_addr,
1463 sizeof (in.s_addr));
1465 #ifdef HAVE_INET_NTOA_R
1466 /* ignore the return code from inet_ntoa_r() as it is int or
1467 char * depending on system */
1468 inet_ntoa_r(in, ntoa_buf, sizeof(ntoa_buf));
1469 sscanf( ntoa_buf, "%hu.%hu.%hu.%hu",
1470 &ip[0], &ip[1], &ip[2], &ip[3]);
1472 sscanf( inet_ntoa(in), "%hu.%hu.%hu.%hu",
1473 &ip[0], &ip[1], &ip[2], &ip[3]);
1475 infof(data, "Telling server to connect to %d.%d.%d.%d:%d\n",
1476 ip[0], ip[1], ip[2], ip[3], porttouse);
1478 result=Curl_ftpsendf(conn, "PORT %d,%d,%d,%d,%d,%d",
1479 ip[0], ip[1], ip[2], ip[3],
1486 result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
1490 if(ftpcode != 200) {
1491 failf(data, "Server does not grok PORT, try without it!");
1492 return CURLE_FTP_PORT_FAILED;
1494 #endif /* end of ipv4-specific code */
1499 /***********************************************************************
1503 * Send the PASV command. PASV is the ftp client's way of asking the server to
1504 * open a second port that we can connect to (for the data transfer). This is
1505 * the opposite of PORT.
1509 CURLcode ftp_use_pasv(struct connectdata *conn,
1512 struct SessionHandle *data = conn->data;
1514 char *buf = data->state.buffer; /* this is our buffer */
1515 int ftpcode; /* receive FTP response codes in this */
1517 struct Curl_dns_entry *addr=NULL;
1518 Curl_ipconnect *conninfo;
1522 Here's the excecutive summary on what to do:
1524 PASV is RFC959, expect:
1525 227 Entering Passive Mode (a1,a2,a3,a4,p1,p2)
1527 LPSV is RFC1639, expect:
1528 228 Entering Long Passive Mode (4,4,a1,a2,a3,a4,2,p1,p2)
1530 EPSV is RFC2428, expect:
1531 229 Entering Extended Passive Mode (|||port|)
1535 const char *mode[] = { "EPSV", "PASV", NULL };
1536 int results[] = { 229, 227, 0 };
1538 unsigned short connectport; /* the local port connect() should use! */
1539 unsigned short newport=0; /* remote port, not necessary the local one */
1541 /* newhost must be able to hold a full IP-style address in ASCII, which
1542 in the IPv6 case means 5*8-1 = 39 letters */
1544 char *newhostp=NULL;
1546 for (modeoff = (data->set.ftp_use_epsv?0:1);
1547 mode[modeoff]; modeoff++) {
1548 result = Curl_ftpsendf(conn, "%s", mode[modeoff]);
1551 result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
1554 if (ftpcode == results[modeoff])
1558 if (!mode[modeoff]) {
1559 failf(data, "Odd return code after PASV");
1560 return CURLE_FTP_WEIRD_PASV_REPLY;
1562 else if (227 == results[modeoff]) {
1568 * New 227-parser June 3rd 1999.
1569 * It now scans for a sequence of six comma-separated numbers and
1570 * will take them as IP+port indicators.
1572 * Found reply-strings include:
1573 * "227 Entering Passive Mode (127,0,0,1,4,51)"
1574 * "227 Data transfer will passively listen to 127,0,0,1,4,51"
1575 * "227 Entering passive mode. 127,0,0,1,4,51"
1579 if (6 == sscanf(str, "%d,%d,%d,%d,%d,%d",
1580 &ip[0], &ip[1], &ip[2], &ip[3],
1581 &port[0], &port[1]))
1587 failf(data, "Couldn't interpret this 227-reply: %s", buf);
1588 return CURLE_FTP_WEIRD_227_FORMAT;
1591 sprintf(newhost, "%d.%d.%d.%d", ip[0], ip[1], ip[2], ip[3]);
1593 newport = (port[0]<<8) + port[1];
1595 else if (229 == results[modeoff]) {
1596 char *ptr = strchr(buf, '(');
1601 if(5 == sscanf(ptr, "%c%c%c%u%c",
1607 char sep1 = separator[0];
1610 /* The four separators should be identical, or else this is an oddly
1611 formatted reply and we bail out immediately. */
1612 for(i=1; i<4; i++) {
1613 if(separator[i] != sep1) {
1614 ptr=NULL; /* set to NULL to signal error */
1621 /* we should use the same host we already are connected to */
1622 newhostp = conn->host.name;
1629 failf(data, "Weirdly formatted EPSV reply");
1630 return CURLE_FTP_WEIRD_PASV_REPLY;
1634 return CURLE_FTP_CANT_RECONNECT;
1636 if(data->change.proxy && *data->change.proxy) {
1638 * This is a tunnel through a http proxy and we need to connect to the
1641 * We don't want to rely on a former host lookup that might've expired
1642 * now, instead we remake the lookup here and now!
1644 rc = Curl_resolv(conn, conn->proxy.name, conn->port, &addr);
1645 if(rc == CURLRESOLV_PENDING)
1646 rc = Curl_wait_for_resolv(conn, &addr);
1649 (unsigned short)conn->port; /* we connect to the proxy's port */
1653 /* normal, direct, ftp connection */
1654 rc = Curl_resolv(conn, newhostp, newport, &addr);
1655 if(rc == CURLRESOLV_PENDING)
1656 rc = Curl_wait_for_resolv(conn, &addr);
1659 failf(data, "Can't resolve new host %s:%d", newhostp, newport);
1660 return CURLE_FTP_CANT_GET_HOST;
1662 connectport = newport; /* we connect to the remote port */
1665 result = Curl_connecthost(conn,
1668 &conn->sock[SECONDARYSOCKET],
1672 Curl_resolv_unlock(data, addr); /* we're done using this address */
1678 * When this is used from the multi interface, this might've returned with
1679 * the 'connected' set to FALSE and thus we are now awaiting a non-blocking
1680 * connect to connect and we should not be "hanging" here waiting.
1683 if(data->set.verbose)
1684 /* this just dumps information about this second connection */
1685 ftp_pasv_verbose(conn, conninfo, newhostp, connectport);
1687 if(data->set.tunnel_thru_httpproxy) {
1688 /* We want "seamless" FTP operations through HTTP proxy tunnel */
1689 result = Curl_ConnectHTTPProxyTunnel(conn, SECONDARYSOCKET,
1691 if(CURLE_OK != result)
1699 * Curl_ftp_nextconnect()
1701 * This function shall be called when the second FTP connection has been
1702 * established and is confirmed connected.
1705 CURLcode Curl_ftp_nextconnect(struct connectdata *conn)
1707 struct SessionHandle *data=conn->data;
1708 char *buf = data->state.buffer; /* this is our buffer */
1711 int ftpcode; /* for ftp status */
1713 /* the ftp struct is already inited in Curl_ftp_connect() */
1714 struct FTP *ftp = conn->proto.ftp;
1715 curl_off_t *bytecountp = ftp->bytecountp;
1717 if(data->set.upload) {
1719 /* Set type to binary (unless specified ASCII) */
1720 result = ftp_transfertype(conn, data->set.ftp_ascii);
1724 /* Send any PREQUOTE strings after transfer type is set? (Wesley Laxton)*/
1725 if(data->set.prequote) {
1726 if ((result = ftp_sendquote(conn, data->set.prequote)) != CURLE_OK)
1730 if(conn->resume_from) {
1731 /* we're about to continue the uploading of a file */
1732 /* 1. get already existing file's size. We use the SIZE
1733 command for this which may not exist in the server!
1734 The SIZE command is not in RFC959. */
1736 /* 2. This used to set REST. But since we can do append, we
1737 don't another ftp command. We just skip the source file
1738 offset and then we APPEND the rest on the file instead */
1740 /* 3. pass file-size number of bytes in the source file */
1741 /* 4. lower the infilesize counter */
1742 /* => transfer as usual */
1744 if(conn->resume_from < 0 ) {
1745 /* we could've got a specified offset from the command line,
1746 but now we know we didn't */
1747 curl_off_t gottensize;
1749 if(CURLE_OK != ftp_getsize(conn, ftp->file, &gottensize)) {
1750 failf(data, "Couldn't get remote file size");
1751 return CURLE_FTP_COULDNT_GET_SIZE;
1753 conn->resume_from = gottensize;
1756 if(conn->resume_from) {
1757 /* do we still game? */
1758 curl_off_t passed=0;
1759 /* enable append instead */
1760 data->set.ftp_append = 1;
1762 /* Now, let's read off the proper amount of bytes from the
1763 input. If we knew it was a proper file we could've just
1764 fseek()ed but we only have a stream here */
1766 curl_off_t readthisamountnow = (conn->resume_from - passed);
1767 curl_off_t actuallyread;
1769 if(readthisamountnow > BUFSIZE)
1770 readthisamountnow = BUFSIZE;
1773 conn->fread(data->state.buffer, 1, (size_t)readthisamountnow,
1776 passed += actuallyread;
1777 if(actuallyread != readthisamountnow) {
1778 failf(data, "Could only read %" FORMAT_OFF_T
1779 " bytes from the input", passed);
1780 return CURLE_FTP_COULDNT_USE_REST;
1783 while(passed != conn->resume_from);
1785 /* now, decrease the size of the read */
1786 if(data->set.infilesize>0) {
1787 data->set.infilesize -= conn->resume_from;
1789 if(data->set.infilesize <= 0) {
1790 infof(data, "File already completely uploaded\n");
1792 /* no data to transfer */
1793 result=Curl_Transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
1795 /* Set no_transfer so that we won't get any error in
1796 * Curl_ftp_done() because we didn't transfer anything! */
1797 ftp->no_transfer = TRUE;
1802 /* we've passed, proceed as normal */
1806 /* Send everything on data->state.in to the socket */
1807 if(data->set.ftp_append) {
1808 /* we append onto the file instead of rewriting it */
1809 FTPSENDF(conn, "APPE %s", ftp->file);
1812 FTPSENDF(conn, "STOR %s", ftp->file);
1815 result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
1820 failf(data, "Failed FTP upload:%s", buf+3);
1821 /* oops, we never close the sockets! */
1822 return CURLE_FTP_COULDNT_STOR_FILE;
1825 if(data->set.ftp_use_port) {
1826 /* PORT means we are now awaiting the server to connect to us. */
1827 result = AllowServerConnect(conn);
1832 if(conn->ssl[SECONDARYSOCKET].use) {
1833 /* since we only have a plaintext TCP connection here, we must now
1835 infof(data, "Doing the SSL/TLS handshake on the data stream\n");
1836 result = Curl_SSLConnect(conn, SECONDARYSOCKET);
1843 /* When we know we're uploading a specified file, we can get the file
1844 size prior to the actual upload. */
1846 Curl_pgrsSetUploadSize(data, data->set.infilesize);
1848 result = Curl_Transfer(conn, -1, -1, FALSE, NULL, /* no download */
1849 SECONDARYSOCKET, bytecountp);
1854 else if(!conn->bits.no_body) {
1855 /* Retrieve file or directory */
1857 curl_off_t downloadsize=-1;
1859 if(conn->bits.use_range && conn->range) {
1860 curl_off_t from, to;
1861 curl_off_t totalsize=-1;
1865 from=curlx_strtoofft(conn->range, &ptr, 0);
1866 while(ptr && *ptr && (isspace((int)*ptr) || (*ptr=='-')))
1868 to=curlx_strtoofft(ptr, &ptr2, 0);
1870 /* we didn't get any digit */
1873 if((-1 == to) && (from>=0)) {
1875 conn->resume_from = from;
1876 infof(data, "FTP RANGE %" FORMAT_OFF_T " to end of file\n", from);
1881 conn->maxdownload = -from;
1882 conn->resume_from = from;
1883 infof(data, "FTP RANGE the last %" FORMAT_OFF_T " bytes\n", totalsize);
1887 totalsize = to-from;
1888 conn->maxdownload = totalsize+1; /* include the last mentioned byte */
1889 conn->resume_from = from;
1890 infof(data, "FTP RANGE from %" FORMAT_OFF_T
1891 " getting %" FORMAT_OFF_T " bytes\n", from, conn->maxdownload);
1893 infof(data, "range-download from %" FORMAT_OFF_T
1894 " to %" FORMAT_OFF_T ", totally %" FORMAT_OFF_T " bytes\n",
1895 from, to, conn->maxdownload);
1896 ftp->dont_check = TRUE; /* dont check for successful transfer */
1899 if((data->set.ftp_list_only) || !ftp->file) {
1900 /* The specified path ends with a slash, and therefore we think this
1901 is a directory that is requested, use LIST. But before that we
1902 need to set ASCII transfer mode. */
1905 /* Set type to ASCII */
1906 result = ftp_transfertype(conn, TRUE /* ASCII enforced */);
1910 /* if this output is to be machine-parsed, the NLST command will be
1911 better used since the LIST command output is not specified or
1912 standard in any way */
1914 FTPSENDF(conn, "%s",
1915 data->set.customrequest?data->set.customrequest:
1916 (data->set.ftp_list_only?"NLST":"LIST"));
1919 curl_off_t foundsize;
1921 /* Set type to binary (unless specified ASCII) */
1922 result = ftp_transfertype(conn, data->set.ftp_ascii);
1926 /* Send any PREQUOTE strings after transfer type is set? */
1927 if(data->set.prequote) {
1928 if ((result = ftp_sendquote(conn, data->set.prequote)) != CURLE_OK)
1932 /* Attempt to get the size, it'll be useful in some cases: for resumed
1933 downloads and when talking to servers that don't give away the size
1934 in the RETR response line. */
1935 result = ftp_getsize(conn, ftp->file, &foundsize);
1936 if(CURLE_OK == result) {
1937 if (data->set.max_filesize && foundsize > data->set.max_filesize) {
1938 failf(data, "Maximum file size exceeded");
1939 return CURLE_FILESIZE_EXCEEDED;
1941 downloadsize = foundsize;
1944 if(conn->resume_from) {
1946 /* Daniel: (August 4, 1999)
1948 * We start with trying to use the SIZE command to figure out the size
1949 * of the file we're gonna get. If we can get the size, this is by far
1950 * the best way to know if we're trying to resume beyond the EOF.
1952 * Daniel, November 28, 2001. We *always* get the size on downloads
1953 * now, so it is done before this even when not doing resumes. I saved
1954 * the comment above for nostalgical reasons! ;-)
1956 if(CURLE_OK != result) {
1957 infof(data, "ftp server doesn't support SIZE\n");
1958 /* We couldn't get the size and therefore we can't know if there
1959 really is a part of the file left to get, although the server
1960 will just close the connection when we start the connection so it
1961 won't cause us any harm, just not make us exit as nicely. */
1964 /* We got a file size report, so we check that there actually is a
1965 part of the file left to get, or else we go home. */
1966 if(conn->resume_from< 0) {
1967 /* We're supposed to download the last abs(from) bytes */
1968 if(foundsize < -conn->resume_from) {
1969 failf(data, "Offset (%" FORMAT_OFF_T
1970 ") was beyond file size (%" FORMAT_OFF_T ")",
1971 conn->resume_from, foundsize);
1972 return CURLE_FTP_BAD_DOWNLOAD_RESUME;
1974 /* convert to size to download */
1975 downloadsize = -conn->resume_from;
1976 /* download from where? */
1977 conn->resume_from = foundsize - downloadsize;
1980 if(foundsize < conn->resume_from) {
1981 failf(data, "Offset (%" FORMAT_OFF_T
1982 ") was beyond file size (%" FORMAT_OFF_T ")",
1983 conn->resume_from, foundsize);
1984 return CURLE_FTP_BAD_DOWNLOAD_RESUME;
1986 /* Now store the number of bytes we are expected to download */
1987 downloadsize = foundsize-conn->resume_from;
1991 if (downloadsize == 0) {
1992 /* no data to transfer */
1993 result=Curl_Transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
1994 infof(data, "File already completely downloaded\n");
1996 /* Set no_transfer so that we won't get any error in Curl_ftp_done()
1997 * because we didn't transfer the any file */
1998 ftp->no_transfer = TRUE;
2002 /* Set resume file transfer offset */
2003 infof(data, "Instructs server to resume from offset %" FORMAT_OFF_T
2007 FTPSENDF(conn, "REST %" FORMAT_OFF_T, conn->resume_from);
2009 result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
2013 if(ftpcode != 350) {
2014 failf(data, "Couldn't use REST: %s", buf+4);
2015 return CURLE_FTP_COULDNT_USE_REST;
2019 FTPSENDF(conn, "RETR %s", ftp->file);
2022 result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
2026 if((ftpcode == 150) || (ftpcode == 125)) {
2030 150 Opening BINARY mode data connection for /etc/passwd (2241
2031 bytes). (ok, the file is being transfered)
2034 150 Opening ASCII mode data connection for /bin/ls
2037 150 ASCII data connection for /bin/ls (137.167.104.91,37445) (0 bytes).
2040 150 Opening ASCII mode data connection for /linux/fisk/kpanelrc (0.0.0.0,0) (545 bytes).
2043 125 Data connection already open; Transfer starting. */
2045 curl_off_t size=-1; /* default unknown size */
2049 * It appears that there are FTP-servers that return size 0 for files
2050 * when SIZE is used on the file while being in BINARY mode. To work
2051 * around that (stupid) behavior, we attempt to parse the RETR response
2052 * even if the SIZE returned size zero.
2054 * Debugging help from Salvatore Sorrentino on February 26, 2003.
2058 !data->set.ftp_ascii &&
2059 (downloadsize < 1)) {
2061 * It seems directory listings either don't show the size or very
2062 * often uses size 0 anyway. ASCII transfers may very well turn out
2063 * that the transfered amount of data is not the same as this line
2064 * tells, why using this number in those cases only confuses us.
2066 * Example D above makes this parsing a little tricky */
2068 bytes=strstr(buf, " bytes");
2071 /* this is a hint there is size information in there! ;-) */
2073 /* scan for the parenthesis and break there */
2076 /* if only skip digits, or else we're in deep trouble */
2077 if(!isdigit((int)*bytes)) {
2081 /* one more estep backwards */
2084 /* only if we have nothing but digits: */
2086 /* get the number! */
2087 size = curlx_strtoofft(bytes, NULL, 0);
2092 else if(downloadsize > -1)
2093 size = downloadsize;
2095 if(data->set.ftp_use_port) {
2096 result = AllowServerConnect(conn);
2101 if(conn->ssl[SECONDARYSOCKET].use) {
2102 /* since we only have a plaintext TCP connection here, we must now
2104 infof(data, "Doing the SSL/TLS handshake on the data stream\n");
2105 result = Curl_SSLConnect(conn, SECONDARYSOCKET);
2110 if(size > conn->maxdownload && conn->maxdownload > 0)
2111 size = conn->size = conn->maxdownload;
2113 infof(data, "Getting file with size: %" FORMAT_OFF_T "\n", size);
2116 result=Curl_Transfer(conn, SECONDARYSOCKET, size, FALSE,
2118 -1, NULL); /* no upload here */
2123 if(dirlist && (ftpcode == 450)) {
2124 /* simply no matching files */
2125 ftp->no_transfer = TRUE; /* don't think we should download anything */
2128 failf(data, "%s", buf+4);
2129 return CURLE_FTP_COULDNT_RETR_FILE;
2134 /* end of transfer */
2139 /***********************************************************************
2143 * This is the actual DO function for FTP. Get a file/directory according to
2144 * the options previously setup.
2148 CURLcode ftp_perform(struct connectdata *conn,
2149 bool *connected) /* for the TCP connect status after
2152 /* this is FTP and no proxy */
2153 CURLcode result=CURLE_OK;
2154 struct SessionHandle *data=conn->data;
2155 char *buf = data->state.buffer; /* this is our buffer */
2157 /* the ftp struct is already inited in Curl_ftp_connect() */
2158 struct FTP *ftp = conn->proto.ftp;
2160 /* Send any QUOTE strings? */
2161 if(data->set.quote) {
2162 if ((result = ftp_sendquote(conn, data->set.quote)) != CURLE_OK)
2166 /* This is a re-used connection. Since we change directory to where the
2167 transfer is taking place, we must now get back to the original dir
2168 where we ended up after login: */
2169 if (conn->bits.reuse && ftp->entrypath) {
2170 if ((result = ftp_cwd_and_mkd(conn, ftp->entrypath)) != CURLE_OK)
2175 int i; /* counter for loop */
2176 for (i=0; i < ftp->dirdepth; i++) {
2177 /* RFC 1738 says empty components should be respected too, but
2178 that is plain stupid since CWD can't be used with an empty argument */
2179 if ((result = ftp_cwd_and_mkd(conn, ftp->dirs[i])) != CURLE_OK)
2184 /* Requested time of file or time-depended transfer? */
2185 if((data->set.get_filetime || data->set.timecondition) &&
2187 result = ftp_getfiletime(conn, ftp->file);
2190 case CURLE_FTP_COULDNT_RETR_FILE:
2192 if(data->set.timecondition) {
2193 if((data->info.filetime > 0) && (data->set.timevalue > 0)) {
2194 switch(data->set.timecondition) {
2195 case CURL_TIMECOND_IFMODSINCE:
2197 if(data->info.filetime < data->set.timevalue) {
2198 infof(data, "The requested document is not new enough\n");
2199 ftp->no_transfer = TRUE; /* mark this to not transfer data */
2203 case CURL_TIMECOND_IFUNMODSINCE:
2204 if(data->info.filetime > data->set.timevalue) {
2205 infof(data, "The requested document is not old enough\n");
2206 ftp->no_transfer = TRUE; /* mark this to not transfer data */
2213 infof(data, "Skipping time comparison\n");
2222 /* If we have selected NOBODY and HEADER, it means that we only want file
2223 information. Which in FTP can't be much more than the file size and
2225 if(conn->bits.no_body && data->set.include_header && ftp->file) {
2226 /* The SIZE command is _not_ RFC 959 specified, and therefor many servers
2227 may not support it! It is however the only way we have to get a file's
2229 curl_off_t filesize;
2233 ftp->no_transfer = TRUE; /* this means no actual transfer is made */
2235 /* Some servers return different sizes for different modes, and thus we
2236 must set the proper type before we check the size */
2237 result = ftp_transfertype(conn, data->set.ftp_ascii);
2241 /* failing to get size is not a serious error */
2242 result = ftp_getsize(conn, ftp->file, &filesize);
2244 if(CURLE_OK == result) {
2245 sprintf(buf, "Content-Length: %" FORMAT_OFF_T "\r\n", filesize);
2246 result = Curl_client_write(data, CLIENTWRITE_BOTH, buf, 0);
2251 /* Determine if server can respond to REST command and therefore
2252 whether it can do a range */
2253 FTPSENDF(conn, "REST 0", NULL);
2254 result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
2256 if ((CURLE_OK == result) && (ftpcode == 350)) {
2257 result = Curl_client_write(data, CLIENTWRITE_BOTH,
2258 (char *)"Accept-ranges: bytes\r\n", 0);
2263 /* If we asked for a time of the file and we actually got one as
2264 well, we "emulate" a HTTP-style header in our output. */
2266 #ifdef HAVE_STRFTIME
2267 if(data->set.get_filetime && (data->info.filetime>=0) ) {
2269 time_t clock = (time_t)data->info.filetime;
2270 #ifdef HAVE_GMTIME_R
2272 tm = (struct tm *)gmtime_r(&clock, &buffer);
2274 tm = gmtime(&clock);
2276 /* format: "Tue, 15 Nov 1994 12:45:26" */
2277 strftime(buf, BUFSIZE-1, "Last-Modified: %a, %d %b %Y %H:%M:%S GMT\r\n",
2279 result = Curl_client_write(data, CLIENTWRITE_BOTH, buf, 0);
2288 if(conn->bits.no_body)
2289 /* doesn't really transfer any data */
2290 ftp->no_transfer = TRUE;
2291 /* Get us a second connection up and connected */
2292 else if(data->set.ftp_use_port) {
2293 /* We have chosen to use the PORT command */
2294 result = ftp_use_port(conn);
2295 if(CURLE_OK == result) {
2296 /* we have the data connection ready */
2297 infof(data, "Ordered connect of the data stream with PORT!\n");
2298 *connected = TRUE; /* mark us "still connected" */
2302 /* We have chosen (this is default) to use the PASV command */
2303 result = ftp_use_pasv(conn, connected);
2304 if(CURLE_OK == result && *connected)
2305 infof(data, "Connected the data stream with PASV!\n");
2311 /***********************************************************************
2315 * This function is registered as 'curl_do' function. It decodes the path
2316 * parts etc as a wrapper to the actual DO function (ftp_perform).
2318 * The input argument is already checked for validity.
2320 * ftp->ctl_valid starts out as FALSE, and gets set to TRUE if we reach the
2321 * Curl_ftp_done() function without finding any major problem.
2323 CURLcode Curl_ftp(struct connectdata *conn)
2325 CURLcode retcode=CURLE_OK;
2327 struct SessionHandle *data = conn->data;
2330 char *slash_pos; /* position of the first '/' char in curpos */
2331 char *cur_pos=conn->path; /* current position in ppath. point at the begin
2332 of next path component */
2334 /* the ftp struct is already inited in ftp_connect() */
2335 ftp = conn->proto.ftp;
2336 ftp->ctl_valid = FALSE;
2337 conn->size = -1; /* make sure this is unknown at this point */
2339 Curl_pgrsSetUploadCounter(data, 0);
2340 Curl_pgrsSetDownloadCounter(data, 0);
2341 Curl_pgrsSetUploadSize(data, 0);
2342 Curl_pgrsSetDownloadSize(data, 0);
2345 ftp->diralloc = 5; /* default dir depth to allocate */
2346 ftp->dirs = (char **)malloc(ftp->diralloc * sizeof(ftp->dirs[0]));
2348 return CURLE_OUT_OF_MEMORY;
2349 ftp->dirs[0] = NULL; /* to start with */
2351 /* parse the URL path into separate path components */
2352 while((slash_pos=strchr(cur_pos, '/'))) {
2353 /* 1 or 0 to indicate absolute directory */
2354 bool absolute_dir = (cur_pos - conn->path > 0) && (ftp->dirdepth == 0);
2356 /* seek out the next path component */
2357 if (slash_pos-cur_pos) {
2358 /* we skip empty path components, like "x//y" since the FTP command CWD
2359 requires a parameter and a non-existant parameter a) doesn't work on
2360 many servers and b) has no effect on the others. */
2361 ftp->dirs[ftp->dirdepth] = curl_unescape(cur_pos - absolute_dir,
2362 slash_pos - cur_pos +
2365 if (!ftp->dirs[ftp->dirdepth]) { /* run out of memory ... */
2366 failf(data, "no memory");
2368 return CURLE_OUT_OF_MEMORY;
2372 cur_pos = slash_pos + 1; /* jump to the rest of the string */
2377 cur_pos = slash_pos + 1; /* jump to the rest of the string */
2378 if(++ftp->dirdepth >= ftp->diralloc) {
2381 ftp->diralloc *= 2; /* double the size each time */
2382 bigger = realloc(ftp->dirs, ftp->diralloc * sizeof(ftp->dirs[0]));
2385 return CURLE_OUT_OF_MEMORY;
2387 ftp->dirs = (char **)bigger;
2392 ftp->file = cur_pos; /* the rest is the file name */
2395 ftp->file = curl_unescape(ftp->file, 0);
2396 if(NULL == ftp->file) {
2398 failf(data, "no memory");
2399 return CURLE_OUT_OF_MEMORY;
2403 ftp->file=NULL; /* instead of point to a zero byte, we make it a NULL
2406 retcode = ftp_perform(conn, &connected);
2408 if(CURLE_OK == retcode) {
2410 retcode = Curl_ftp_nextconnect(conn);
2412 if(retcode && (conn->sock[SECONDARYSOCKET] != CURL_SOCKET_BAD)) {
2413 /* Failure detected, close the second socket if it was created already */
2414 sclose(conn->sock[SECONDARYSOCKET]);
2415 conn->sock[SECONDARYSOCKET] = CURL_SOCKET_BAD;
2418 if(ftp->no_transfer)
2419 /* no data to transfer */
2420 retcode=Curl_Transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
2422 /* since we didn't connect now, we want do_more to get called */
2423 conn->bits.do_more = TRUE;
2428 ftp->ctl_valid = TRUE; /* seems good */
2433 /***********************************************************************
2437 * Sends the formated string as a ftp command to a ftp server
2439 * NOTE: we build the command in a fixed-length buffer, which sets length
2440 * restrictions on the command!
2442 CURLcode Curl_ftpsendf(struct connectdata *conn,
2443 const char *fmt, ...)
2445 ssize_t bytes_written;
2449 CURLcode res = CURLE_OK;
2453 vsnprintf(s, 250, fmt, ap);
2456 strcat(s, "\r\n"); /* append a trailing CRLF */
2459 write_len = strlen(s);
2462 res = Curl_write(conn, conn->sock[FIRSTSOCKET], sptr, write_len,
2468 if(conn->data->set.verbose)
2469 Curl_debug(conn->data, CURLINFO_HEADER_OUT, sptr, bytes_written);
2471 if(bytes_written != (ssize_t)write_len) {
2472 write_len -= bytes_written;
2473 sptr += bytes_written;
2482 /***********************************************************************
2486 * This should be called before calling sclose() on an ftp control connection
2487 * (not data connections). We should then wait for the response from the
2488 * server before returning. The calling code should then try to close the
2492 static CURLcode ftp_quit(struct connectdata *conn)
2496 CURLcode ret = CURLE_OK;
2498 if(conn->proto.ftp->ctl_valid) {
2499 ret = Curl_ftpsendf(conn, "%s", "QUIT");
2501 ret = Curl_GetFTPResponse(&nread, conn, &ftpcode);
2507 /***********************************************************************
2509 * Curl_ftp_disconnect()
2511 * Disconnect from an FTP server. Cleanup protocol-specific per-connection
2514 CURLcode Curl_ftp_disconnect(struct connectdata *conn)
2516 struct FTP *ftp= conn->proto.ftp;
2518 /* We cannot send quit unconditionally. If this connection is stale or
2519 bad in any way, sending quit and waiting around here will make the
2520 disconnect wait in vain and cause more problems than we need to.
2522 ftp_quit() will check the state of ftp->ctl_valid. If it's ok it
2523 will try to send the QUIT command, otherwise it will just return.
2526 /* The FTP session may or may not have been allocated/setup at this point! */
2528 (void)ftp_quit(conn); /* ignore errors on the QUIT */
2531 free(ftp->entrypath);
2541 /***********************************************************************
2545 * Makes a directory on the FTP server.
2549 CURLcode ftp_mkd(struct connectdata *conn, char *path)
2551 CURLcode result=CURLE_OK;
2552 int ftpcode; /* for ftp status */
2555 /* Create a directory on the remote server */
2556 FTPSENDF(conn, "MKD %s", path);
2558 result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
2565 infof( conn->data , "Created remote directory %s\n" , path );
2568 failf(conn->data, "Permission denied to make directory %s", path);
2569 result = CURLE_FTP_ACCESS_DENIED;
2572 failf(conn->data, "unrecognized MKD response: %d", ftpcode );
2573 result = CURLE_FTP_ACCESS_DENIED;
2579 /***********************************************************************
2583 * Send 'CWD' to the remote server to Change Working Directory. It is the ftp
2584 * version of the unix 'cd' command. This function is only called from the
2585 * ftp_cwd_and_mkd() function these days.
2587 * This function does NOT call failf().
2590 CURLcode ftp_cwd(struct connectdata *conn, char *path)
2596 FTPSENDF(conn, "CWD %s", path);
2597 result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
2599 /* According to RFC959, CWD is supposed to return 250 on success, but
2600 there seem to be non-compliant FTP servers out there that return 200,
2601 so we accept any '2xy' code here. */
2602 if (ftpcode/100 != 2)
2603 result = CURLE_FTP_ACCESS_DENIED;
2609 /***********************************************************************
2613 * Change to the given directory. If the directory is not present, and we
2614 * have been told to allow it, then create the directory and cd to it.
2617 static CURLcode ftp_cwd_and_mkd(struct connectdata *conn, char *path)
2621 result = ftp_cwd(conn, path);
2623 if(conn->data->set.ftp_create_missing_dirs) {
2624 result = ftp_mkd(conn, path);
2626 /* ftp_mkd() calls failf() itself */
2628 result = ftp_cwd(conn, path);
2631 failf(conn->data, "Couldn't cd to %s", path);
2636 #endif /* CURL_DISABLE_FTP */