- Linus Nielsen Feltzing introduced the --ftp-ssl-ccc command line option to

curl that uses the new CURLOPT_FTP_SSL_CCC option in libcurl. If enabled, it
  will make libcurl shutdown SSL/TLS after the authentication is done on a
  FTP-SSL operation.
This commit is contained in:
Daniel Stenberg 2007-01-05 23:11:14 +00:00
parent b7aaa4d907
commit 4750e6f3c5
16 changed files with 269 additions and 20 deletions

View File

@ -6,6 +6,12 @@
Changelog
Daniel (5 January 2007)
- Linus Nielsen Feltzing introduced the --ftp-ssl-ccc command line option to
curl that uses the new CURLOPT_FTP_SSL_CCC option in libcurl. If enabled, it
will make libcurl shutdown SSL/TLS after the authentication is done on a
FTP-SSL operation.
Daniel (4 January 2007)
- David McCreedy made changes to allow base64 encoding/decoding to work on
non-ASCII platforms.

View File

@ -5,7 +5,7 @@ Curl and libcurl 7.16.1
Available command line options: 112
Available curl_easy_setopt() options: 133
Number of public functions in libcurl: 54
Amount of public web site mirrors: 39
Amount of public web site mirrors: 38
Number of known libcurl bindings: 35
Number of contributors: 524
@ -13,6 +13,7 @@ This release includes the following changes:
o Support for SCP and SFTP were added
o CURLOPT_CLOSEPOLICY is now deprecated
o --ftp-ssl-ccc and CURLOPT_FTP_SSL_CCC were added
This release includes the following bugfixes:
@ -67,6 +68,6 @@ advice from friends like these:
Matt Witherspoon, Alexey Simak, Martin Skinner, Sh Diao, Jared Lundell,
Stefan Krause, Sebastien Willemijns, Alexey Simak, Brendan Jurd,
Robson Braga Araujo, David McCreedy, Robert Foreman, Nathanael Nerode,
Victor Snezhko
Victor Snezhko, Linus Nielsen Feltzing
Thanks! (and sorry if I forgot to mention someone)

View File

@ -5,7 +5,7 @@
.\" * | (__| |_| | _ <| |___
.\" * \___|\___/|_| \_\_____|
.\" *
.\" * Copyright (C) 1998 - 2006, Daniel Stenberg, <daniel@haxx.se>, et al.
.\" * Copyright (C) 1998 - 2007, Daniel Stenberg, <daniel@haxx.se>, et al.
.\" *
.\" * This software is licensed as described in the file COPYING, which
.\" * you should have received as part of this distribution. The terms
@ -432,6 +432,14 @@ If this option is used twice, the second will again disable this.
Terminates the connection if the server doesn't support SSL/TLS.
(Added in 7.15.5)
If this option is used twice, the second will again disable this.
.IP "--ftp-ssl-ccc"
(FTP) Use CCC (Clear Command Channel)
Shuts down the SSL/TLS layer after authenticating. The rest of the
control channel communication will be unencrypted. This allows
NAT routers to follow the FTP transaction.
(Added in 7.16.1)
If this option is used twice, the second will again disable this.
.IP "-F/--form <name=content>"
(HTTP) This lets curl emulate a filled in form in which a user has pressed the

View File

@ -5,7 +5,7 @@
.\" * | (__| |_| | _ <| |___
.\" * \___|\___/|_| \_\_____|
.\" *
.\" * Copyright (C) 1998 - 2006, Daniel Stenberg, <daniel@haxx.se>, et al.
.\" * Copyright (C) 1998 - 2007, Daniel Stenberg, <daniel@haxx.se>, et al.
.\" *
.\" * This software is licensed as described in the file COPYING, which
.\" * you should have received as part of this distribution. The terms
@ -925,6 +925,12 @@ Try "AUTH SSL" first, and only if that fails try "AUTH TLS"
.IP CURLFTPAUTH_TLS
Try "AUTH TLS" first, and only if that fails try "AUTH SSL"
.RE
.IP CURLOPT_FTP_SSL_CCC
Pass a long that is set to 0 to disable and 1 to enable. If enabled, this
option makes libcurl use CCC (Clear Command Channel). It shuts down the
SSL/TLS layer after authenticating. The rest of the control channel
communication will be unencrypted. This allows NAT routers to follow the FTP
transaction. (Added in 7.16.1)
.IP CURLOPT_FTP_ACCOUNT
Pass a pointer to a zero-terminated string (or NULL to disable). When an FTP
server asks for "account data" after user name and password has been provided,

View File

@ -7,7 +7,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 1998 - 2006, Daniel Stenberg, <daniel@haxx.se>, et al.
* Copyright (C) 1998 - 2007, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@ -397,6 +397,8 @@ typedef enum {
generic so the error message will be of
interest when this has happened */
CURLE_FTP_SSL_CCC_FAILED, /* 80 - Failed to clear the FTP command
channel */
CURL_LAST /* never use! */
} CURLcode;
@ -1049,6 +1051,9 @@ typedef enum {
CINIT(SSH_PUBLIC_KEYFILE, OBJECTPOINT, 152),
CINIT(SSH_PRIVATE_KEYFILE, OBJECTPOINT, 153),
/* Send CCC (Clear Command Channel) after authentication */
CINIT(FTP_SSL_CCC, LONG, 154),
CURLOPT_LASTENTRY /* the last unused */
} CURLoption;

View File

@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 1998 - 2006, Daniel Stenberg, <daniel@haxx.se>, et al.
* Copyright (C) 1998 - 2007, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@ -666,6 +666,7 @@ static void state(struct connectdata *conn,
"ACCT",
"PBSZ",
"PROT",
"CCC",
"PWD",
"QUOTE",
"RETR_PREQUOTE",
@ -2545,6 +2546,27 @@ static CURLcode ftp_statemach_act(struct connectdata *conn)
/* we failed and bails out */
return CURLE_FTP_SSL_FAILED;
if(data->set.ftp_use_ccc) {
/* CCC - Clear Command Channel
*/
NBFTPSENDF(conn, "CCC", NULL);
state(conn, FTP_CCC);
}
else {
result = ftp_state_pwd(conn);
if(result)
return result;
}
break;
case FTP_CCC:
/* First shut down the SSL layer (note: this call will block) */
result = Curl_ssl_shutdown(conn, FIRSTSOCKET);
if(result)
return CURLE_FTP_SSL_CCC_FAILED;
/* Then continue as normal */
result = ftp_state_pwd(conn);
if(result)
return result;

View File

@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 1998 - 2006, Daniel Stenberg, <daniel@haxx.se>, et al.
* Copyright (C) 1998 - 2007, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@ -516,6 +516,72 @@ void Curl_gtls_close(struct connectdata *conn)
close_one(conn, 1);
}
/*
* This function is called to shut down the SSL layer but keep the
* socket open (CCC - Clear Command Channel)
*/
int Curl_gtls_shutdown(struct connectdata *conn, int sockindex)
{
int result;
int retval = 0;
struct SessionHandle *data = conn->data;
int done = 0;
ssize_t nread;
char buf[120];
/* This has only been tested on the proftpd server, and the mod_tls code
sends a close notify alert without waiting for a close notify alert in
response. Thus we wait for a close notify alert from the server, but
we do not send one. Let's hope other servers do the same... */
if(conn->ssl[sockindex].session) {
while(!done) {
int what = Curl_select(conn->sock[sockindex],
CURL_SOCKET_BAD, SSL_SHUTDOWN_TIMEOUT);
if(what > 0) {
/* Something to read, let's do it and hope that it is the close
notify alert from the server */
result = gnutls_record_recv(conn->ssl[sockindex].session,
buf, sizeof(buf));
switch(result) {
case 0:
/* This is the expected response. There was no data but only
the close notify alert */
done = 1;
break;
case GNUTLS_E_AGAIN:
case GNUTLS_E_INTERRUPTED:
infof(data, "GNUTLS_E_AGAIN || GNUTLS_E_INTERRUPTED\n");
break;
default:
retval = -1;
done = 1;
break;
}
}
else if(0 == what) {
/* timeout */
failf(data, "SSL shutdown timeout");
done = 1;
break;
}
else {
/* anything that gets here is fatally bad */
failf(data, "select on SSL socket, errno: %d", Curl_sockerrno());
retval = -1;
done = 1;
}
}
gnutls_deinit(conn->ssl[sockindex].session);
}
gnutls_certificate_free_credentials(conn->ssl[sockindex].cred);
conn->ssl[sockindex].session = NULL;
conn->ssl[sockindex].use = FALSE;
return retval;
}
/*
* If the read would block we return -1 and set 'wouldblock' to TRUE.
* Otherwise we return the amount of data read. Other errors should return -1

View File

@ -7,7 +7,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 1998 - 2006, Daniel Stenberg, <daniel@haxx.se>, et al.
* Copyright (C) 1998 - 2007, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@ -41,5 +41,6 @@ ssize_t Curl_gtls_recv(struct connectdata *conn, /* connection data */
bool *wouldblock);
void Curl_gtls_session_free(void *ptr);
size_t Curl_gtls_version(char *buffer, size_t size);
int Curl_gtls_shutdown(struct connectdata *conn, int sockindex);
#endif

View File

@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 1998 - 2006, Daniel Stenberg, <daniel@haxx.se>, et al.
* Copyright (C) 1998 - 2007, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@ -397,6 +397,18 @@ void Curl_ssl_close(struct connectdata *conn)
}
}
CURLcode Curl_ssl_shutdown(struct connectdata *conn, int sockindex)
{
if(conn->ssl[sockindex].use) {
#ifdef USE_GNUTLS
return Curl_gtls_shutdown(conn, sockindex);
#else
return Curl_ossl_shutdown(conn, sockindex);
#endif
}
return CURLE_OK;
}
/* Selects an (Open)SSL crypto engine
*/
CURLcode Curl_ssl_set_engine(struct SessionHandle *data, const char *engine)

View File

@ -7,7 +7,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 1998 - 2006, Daniel Stenberg, <daniel@haxx.se>, et al.
* Copyright (C) 1998 - 2007, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@ -69,9 +69,13 @@ size_t Curl_ssl_version(char *buffer, size_t size);
int Curl_ssl_check_cxn(struct connectdata *conn);
CURLcode Curl_ssl_shutdown(struct connectdata *conn, int sockindex);
#if !defined(USE_SSL) && !defined(SSLGEN_C)
/* set up blank macros for none-SSL builds */
#define Curl_ssl_close_all(x)
#endif
#define SSL_SHUTDOWN_TIMEOUT 10000 /* ms */
#endif

View File

@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 1998 - 2006, Daniel Stenberg, <daniel@haxx.se>, et al.
* Copyright (C) 1998 - 2007, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@ -728,6 +728,102 @@ void Curl_ossl_close(struct connectdata *conn)
}
}
/*
* This function is called to shut down the SSL layer but keep the
* socket open (CCC - Clear Command Channel)
*/
int Curl_ossl_shutdown(struct connectdata *conn, int sockindex)
{
int result;
int retval = 0;
struct ssl_connect_data *connssl = &conn->ssl[sockindex];
struct SessionHandle *data = conn->data;
char buf[120]; /* We will use this for the OpenSSL error buffer, so it has
to be at least 120 bytes long. */
unsigned long sslerror;
ssize_t nread;
int err;
int done = 0;
/* This has only been tested on the proftpd server, and the mod_tls code
sends a close notify alert without waiting for a close notify alert in
response. Thus we wait for a close notify alert from the server, but
we do not send one. Let's hope other servers do the same... */
if(connssl->handle) {
while(!done) {
int what = Curl_select(conn->sock[sockindex],
CURL_SOCKET_BAD, SSL_SHUTDOWN_TIMEOUT);
if(what > 0) {
/* Something to read, let's do it and hope that it is the close
notify alert from the server */
nread = (ssize_t)SSL_read(conn->ssl[sockindex].handle, buf,
sizeof(buf));
err = SSL_get_error(conn->ssl[sockindex].handle, (int)nread);
switch(err) {
case SSL_ERROR_NONE: /* this is not an error */
case SSL_ERROR_ZERO_RETURN: /* no more data */
/* This is the expected response. There was no data but only
the close notify alert */
done = 1;
break;
case SSL_ERROR_WANT_READ:
/* there's data pending, re-invoke SSL_read() */
infof(data, "SSL_ERROR_WANT_READ\n");
break;
case SSL_ERROR_WANT_WRITE:
/* SSL wants a write. Really odd. Let's bail out. */
infof(data, "SSL_ERROR_WANT_WRITE\n");
done = 1;
break;
default:
/* openssl/ssl.h says "look at error stack/return value/errno" */
sslerror = ERR_get_error();
failf(conn->data, "SSL read: %s, errno %d",
ERR_error_string(sslerror, buf),
Curl_sockerrno() );
done = 1;
break;
}
}
else if(0 == what) {
/* timeout */
failf(data, "SSL shutdown timeout");
done = 1;
break;
}
else {
/* anything that gets here is fatally bad */
failf(data, "select on SSL socket, errno: %d", Curl_sockerrno());
retval = -1;
done = 1;
}
} /* while()-loop for the select() */
if(data->set.verbose) {
switch(SSL_get_shutdown(connssl->handle)) {
case SSL_SENT_SHUTDOWN:
infof(data, "SSL_get_shutdown() returned SSL_SENT_SHUTDOWN\n");
break;
case SSL_RECEIVED_SHUTDOWN:
infof(data, "SSL_get_shutdown() returned SSL_RECEIVED_SHUTDOWN\n");
break;
case SSL_SENT_SHUTDOWN|SSL_RECEIVED_SHUTDOWN:
infof(data, "SSL_get_shutdown() returned SSL_SENT_SHUTDOWN|"
"SSL_RECEIVED__SHUTDOWN\n");
break;
}
}
connssl->use = FALSE; /* get back to ordinary socket usage */
SSL_free (connssl->handle);
connssl->handle = NULL;
}
return retval;
}
void Curl_ossl_session_free(void *ptr)
{
/* free the ID */
@ -1629,7 +1725,7 @@ Curl_ossl_connect_common(struct connectdata *conn,
while(1) {
int what = Curl_select(readfd, writefd, nonblocking?0:(int)timeout_ms);
if(what > 0)
/* reabable or writable, go loop in the outer loop */
/* readable or writable, go loop in the outer loop */
break;
else if(0 == what) {
if (nonblocking) {

View File

@ -7,7 +7,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 1998 - 2006, Daniel Stenberg, <daniel@haxx.se>, et al.
* Copyright (C) 1998 - 2007, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@ -29,8 +29,8 @@
#include "urldata.h"
CURLcode Curl_ossl_connect(struct connectdata *conn, int sockindex);
CURLcode Curl_ossl_connect_nonblocking(struct connectdata *conn,
int sockindex,
CURLcode Curl_ossl_connect_nonblocking(struct connectdata *conn,
int sockindex,
bool *done);
void Curl_ossl_close(struct connectdata *conn); /* close a SSL connection */
/* tell OpenSSL to close down all open information regarding connections (and
@ -66,4 +66,6 @@ size_t Curl_ossl_version(char *buffer, size_t size);
int Curl_ossl_check_cxn(struct connectdata *cxn);
int Curl_ossl_seed(struct SessionHandle *data);
int Curl_ossl_shutdown(struct connectdata *conn, int sockindex);
#endif

View File

@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 2004 - 2006, Daniel Stenberg, <daniel@haxx.se>, et al.
* Copyright (C) 2004 - 2007, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@ -244,6 +244,9 @@ curl_easy_strerror(CURLcode error)
case CURLE_FTP_SSL_FAILED:
return "Requested FTP SSL level failed";
case CURLE_FTP_SSL_CCC_FAILED:
return "Failed to clear the FTP command channel";
case CURLE_SEND_FAIL_REWIND:
return "Send failed since rewinding of the data stream failed";

View File

@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 1998 - 2006, Daniel Stenberg, <daniel@haxx.se>, et al.
* Copyright (C) 1998 - 2007, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@ -1140,6 +1140,10 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option,
data->set.ftp_use_epsv = (bool)(0 != va_arg(param, long));
break;
case CURLOPT_FTP_SSL_CCC:
data->set.ftp_use_ccc = (bool)(0 != va_arg(param, long));
break;
case CURLOPT_FTP_SKIP_PASV_IP:
/*
* Enable or disable FTP_SKIP_PASV_IP, which will disable/enable the

View File

@ -7,7 +7,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 1998 - 2006, Daniel Stenberg, <daniel@haxx.se>, et al.
* Copyright (C) 1998 - 2007, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@ -302,7 +302,7 @@ struct HTTP {
***************************************************************************/
typedef enum {
FTP_STOP, /* do nothing state, stops the state machine */
FTP_WAIT220, /* waiting for the inintial 220 response immediately after
FTP_WAIT220, /* waiting for the initial 220 response immediately after
a connect */
FTP_AUTH,
FTP_USER,
@ -310,6 +310,7 @@ typedef enum {
FTP_ACCT,
FTP_PBSZ,
FTP_PROT,
FTP_CCC,
FTP_PWD,
FTP_QUOTE, /* waiting for a response to a command sent in a quote list */
FTP_RETR_PREQUOTE,
@ -1273,6 +1274,8 @@ struct UserDefined {
bool reuse_fresh; /* do not re-use an existing connection */
bool ftp_use_epsv; /* if EPSV is to be attempted or not */
bool ftp_use_eprt; /* if EPRT is to be attempted or not */
bool ftp_use_ccc; /* if CCC is to be attempted or not */
curl_ftpssl ftp_ssl; /* if AUTH TLS is to be attempted etc */
curl_ftpauth ftpsslauth; /* what AUTH XXX to be attempted */
bool no_signal; /* do not use any signal/alarm handler */

View File

@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 1998 - 2006, Daniel Stenberg, <daniel@haxx.se>, et al.
* Copyright (C) 1998 - 2007, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@ -349,6 +349,7 @@ struct Configurable {
bool ftp_ssl;
bool ftp_ssl_reqd;
bool ftp_ssl_control;
bool ftp_ssl_ccc;
char *socksproxy; /* set to server string */
int socksver; /* set to CURLPROXY_SOCKS* define */
@ -529,6 +530,7 @@ static void help(void)
" --ftp-ssl Try SSL/TLS for ftp transfer (F)",
" --ftp-ssl-control Require SSL/TLS for ftp login, clear for transfer (F)",
" --ftp-ssl-reqd Require SSL/TLS for ftp transfer (F)",
" --ftp-ssl-ccc Send CCC after authenticating (F)",
" -F/--form <name=content> Specify HTTP multipart POST data (H)",
" --form-string <name=string> Specify HTTP multipart POST data (H)",
" -g/--globoff Disable URL sequences and ranges using {} and []",
@ -1355,6 +1357,7 @@ static ParameterError getparameter(char *flag, /* f or -long-flag */
{"$v", "ftp-ssl-reqd", FALSE},
{"$w", "no-sessionid", FALSE},
{"$x", "ftp-ssl-control", FALSE},
{"$y", "ftp-ssl-ccc", FALSE},
{"0", "http1.0", FALSE},
{"1", "tlsv1", FALSE},
@ -1779,6 +1782,9 @@ static ParameterError getparameter(char *flag, /* f or -long-flag */
case 'x': /* --ftp-ssl-control */
config->ftp_ssl_control ^= TRUE;
break;
case 'y': /* --ftp-ssl-ccc */
config->ftp_ssl_ccc ^= TRUE;
break;
}
break;
case '#': /* --progress-bar */
@ -4002,6 +4008,10 @@ operate(struct Configurable *config, int argc, char *argv[])
else if(config->ftp_ssl_control)
curl_easy_setopt(curl, CURLOPT_FTP_SSL, CURLFTPSSL_CONTROL);
/* new in curl 7.16.1 */
if(config->ftp_ssl_ccc)
curl_easy_setopt(curl, CURLOPT_FTP_SSL_CCC, TRUE);
/* new in curl 7.11.1, modified in 7.15.2 */
if(config->socksproxy) {
curl_easy_setopt(curl, CURLOPT_PROXY, config->socksproxy);