mirror of
https://github.com/curl/curl.git
synced 2026-08-24 22:43:38 +03:00
- 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:
parent
b7aaa4d907
commit
4750e6f3c5
16 changed files with 269 additions and 20 deletions
24
lib/ftp.c
24
lib/ftp.c
|
|
@ -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;
|
||||
|
|
|
|||
68
lib/gtls.c
68
lib/gtls.c
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
14
lib/sslgen.c
14
lib/sslgen.c
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
100
lib/ssluse.c
100
lib/ssluse.c
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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";
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue