of a socket after it has been closed, when the FTP-SSL data connection is taken
down.
This commit is contained in:
Daniel Stenberg 2007-07-29 12:54:05 +00:00
parent 86ff3194fa
commit f1fa7b8ba4
12 changed files with 88 additions and 80 deletions

11
CHANGES
View File

@ -6,6 +6,17 @@
Changelog
Daniel S (29 July 2007)
- Jayesh A Shah filed bug report #1759542
(http://curl.haxx.se/bug/view.cgi?id=1759542) identifying a rather serious
problem with FTPS: libcurl closed the data connection socket and then later
in the flow it would call the SSL layer to do SSL shutdown which then would
use a socket that had already been closed - so if the application had opened
a new one in the mean time, libcurl could send gibberish that way! I worked
with "Greg" to properly diagnose and fix this. The fix affects code for all
SSL libraries we support, but it has only been truly verified to work fine
for the OpenSSL version. The others have only been code reviewed.
Daniel S (23 July 2007)
- Implemented the parts of Patrick Monnerat's OS/400 patch that introduces
support for the OS/400 Secure Sockets Layer library.

View File

@ -28,6 +28,7 @@ This release includes the following bugfixes:
o bad free of memory from libssh2
o the SFTP PWD command works
o HTTP Digest auth on a re-used connection
o FTPS data connection close
This release includes the following known bugs:
@ -48,6 +49,7 @@ advice from friends like these:
Dan Fandrich, Song Ma, Daniel Black, Giancarlo Formicuccia, Shmulik Regev,
Daniel Cater, Colin Hogben, Jofell Gallardo, Daniel Johnson,
Ralf S. Engelschall, James Housley, Chris Flerackers, Patrick Monnerat
Ralf S. Engelschall, James Housley, Chris Flerackers, Patrick Monnerat,
Jayesh A Shah
Thanks! (and sorry if I forgot to mention someone)

View File

@ -3115,6 +3115,14 @@ CURLcode Curl_ftp_done(struct connectdata *conn, CURLcode status, bool premature
shutdown(conn->sock[SECONDARYSOCKET],2); /* SD_BOTH */
#endif
if(conn->ssl[SECONDARYSOCKET].use) {
/* The secondary socket is using SSL so we must close down that part first
before we close the socket for real */
Curl_ssl_close(conn, SECONDARYSOCKET);
/* Note that we keep "use" set to TRUE since that (next) connection is
still requested to use SSL */
}
sclose(conn->sock[SECONDARYSOCKET]);
conn->sock[SECONDARYSOCKET] = CURL_SOCKET_BAD;

View File

@ -556,17 +556,17 @@ static void close_one(struct connectdata *conn,
if(conn->ssl[index].session) {
gnutls_bye(conn->ssl[index].session, GNUTLS_SHUT_RDWR);
gnutls_deinit(conn->ssl[index].session);
conn->ssl[index].session = NULL;
}
if(conn->ssl[index].cred)
if(conn->ssl[index].cred) {
gnutls_certificate_free_credentials(conn->ssl[index].cred);
conn->ssl[index].cred = NULL;
}
}
void Curl_gtls_close(struct connectdata *conn)
void Curl_gtls_close(struct connectdata *conn, int sockindex)
{
if(conn->ssl[0].use)
close_one(conn, 0);
if(conn->ssl[1].use)
close_one(conn, 1);
close_one(conn, sockindex);
}
/*
@ -631,8 +631,8 @@ int Curl_gtls_shutdown(struct connectdata *conn, int sockindex)
}
gnutls_certificate_free_credentials(conn->ssl[sockindex].cred);
conn->ssl[sockindex].cred = NULL;
conn->ssl[sockindex].session = NULL;
conn->ssl[sockindex].use = FALSE;
return retval;
}

View File

@ -384,18 +384,13 @@ Curl_nss_check_cxn(struct connectdata *conn)
/*
* This function is called when an SSL connection is closed.
*/
void Curl_nss_close(struct connectdata *conn)
void Curl_nss_close(struct connectdata *conn, int sockindex)
{
int i;
struct ssl_connect_data *connssl = &conn->ssl[sockindex];
for(i=0; i<2; i++) {
struct ssl_connect_data *connssl = &conn->ssl[i];
if(connssl->handle) {
PR_Close(connssl->handle);
connssl->handle = NULL;
}
connssl->use = FALSE; /* get back to ordinary socket usage */
if(connssl->handle) {
PR_Close(connssl->handle);
connssl->handle = NULL;
}
}

View File

@ -275,7 +275,7 @@ static int Curl_qsossl_close_one(struct ssl_connect_data * conn,
{
int rc;
if (!conn->handle)
if(!conn->handle)
return 0;
rc = SSL_Destroy(conn->handle);
@ -291,22 +291,16 @@ static int Curl_qsossl_close_one(struct ssl_connect_data * conn,
return -1;
}
conn->use = FALSE; /* get back to ordinary socket usage */
conn->handle = NULL;
return 0;
}
void Curl_qsossl_close(struct connectdata * conn)
void Curl_qsossl_close(struct connectdata *conn, int sockindex)
{
struct SessionHandle * data = conn->data;
struct ssl_connect_data * connssl = conn->ssl;
if(connssl->use)
(void) Curl_qsossl_close_one(connssl, data);
connssl++;
struct SessionHandle *data = conn->data;
struct ssl_connect_data *connssl = &conn->ssl[sockindex];
if(connssl->use)
(void) Curl_qsossl_close_one(connssl, data);

View File

@ -435,46 +435,43 @@ void Curl_ssl_close_all(struct SessionHandle *data)
#endif /* USE_SSL */
}
void Curl_ssl_close(struct connectdata *conn)
void Curl_ssl_close(struct connectdata *conn, int sockindex)
{
if(conn->ssl[FIRSTSOCKET].use) {
DEBUGASSERT((sockindex <= 1) && (sockindex >= -1));
#ifdef USE_SSLEAY
Curl_ossl_close(conn);
Curl_ossl_close(conn, sockindex);
#endif /* USE_SSLEAY */
#ifdef USE_GNUTLS
Curl_gtls_close(conn);
Curl_gtls_close(conn, sockindex);
#endif /* USE_GNUTLS */
#ifdef USE_NSS
Curl_nss_close(conn);
Curl_nss_close(conn, sockindex);
#endif /* USE_NSS */
#ifdef USE_QSOSSL
Curl_qsossl_close(conn);
Curl_qsossl_close(conn, sockindex);
#endif /* USE_QSOSSL */
conn->ssl[FIRSTSOCKET].use = FALSE;
}
}
CURLcode Curl_ssl_shutdown(struct connectdata *conn, int sockindex)
{
if(conn->ssl[sockindex].use) {
#ifdef USE_SSLEAY
if(Curl_ossl_shutdown(conn, sockindex))
return CURLE_SSL_SHUTDOWN_FAILED;
if(Curl_ossl_shutdown(conn, sockindex))
return CURLE_SSL_SHUTDOWN_FAILED;
#else
#ifdef USE_GNUTLS
if(Curl_gtls_shutdown(conn, sockindex))
return CURLE_SSL_SHUTDOWN_FAILED;
if(Curl_gtls_shutdown(conn, sockindex))
return CURLE_SSL_SHUTDOWN_FAILED;
#else
#ifdef USE_QSOSSL
if(Curl_qsossl_shutdown(conn, sockindex))
return CURLE_SSL_SHUTDOWN_FAILED;
#else
(void)conn;
(void)sockindex;
if(Curl_qsossl_shutdown(conn, sockindex))
return CURLE_SSL_SHUTDOWN_FAILED;
#endif /* USE_QSOSSL */
#endif /* USE_GNUTLS */
#endif /* USE_SSLEAY */
}
conn->ssl[sockindex].use = FALSE; /* get back to ordinary socket usage */
return CURLE_OK;
}

View File

@ -35,7 +35,7 @@ CURLcode Curl_ssl_connect(struct connectdata *conn, int sockindex);
CURLcode Curl_ssl_connect_nonblocking(struct connectdata *conn,
int sockindex,
bool *done);
void Curl_ssl_close(struct connectdata *conn);
void Curl_ssl_close(struct connectdata *conn, int sockindex);
/* tell the SSL stuff to close down all open information regarding
connections (and thus session ID caching etc) */
void Curl_ssl_close_all(struct SessionHandle *data);

View File

@ -703,35 +703,20 @@ struct curl_slist *Curl_ossl_engines_list(struct SessionHandle *data)
/*
* This function is called when an SSL connection is closed.
*/
void Curl_ossl_close(struct connectdata *conn)
void Curl_ossl_close(struct connectdata *conn, int sockindex)
{
int i;
/*
ERR_remove_state() frees the error queue associated with
thread pid. If pid == 0, the current thread will have its
error queue removed.
struct ssl_connect_data *connssl = &conn->ssl[sockindex];
Since error queue data structures are allocated
automatically for new threads, they must be freed when
threads are terminated in oder to avoid memory leaks.
*/
ERR_remove_state(0);
if(connssl->handle) {
(void)SSL_shutdown(connssl->handle);
SSL_set_connect_state(connssl->handle);
for(i=0; i<2; i++) {
struct ssl_connect_data *connssl = &conn->ssl[i];
if(connssl->handle) {
(void)SSL_shutdown(connssl->handle);
SSL_set_connect_state(connssl->handle);
SSL_free (connssl->handle);
connssl->handle = NULL;
}
if(connssl->ctx) {
SSL_CTX_free (connssl->ctx);
connssl->ctx = NULL;
}
connssl->use = FALSE; /* get back to ordinary socket usage */
SSL_free (connssl->handle);
connssl->handle = NULL;
}
if(connssl->ctx) {
SSL_CTX_free (connssl->ctx);
connssl->ctx = NULL;
}
}
@ -827,8 +812,6 @@ int Curl_ossl_shutdown(struct connectdata *conn, int sockindex)
#endif
}
connssl->use = FALSE; /* get back to ordinary socket usage */
SSL_free (connssl->handle);
connssl->handle = NULL;
}
@ -847,6 +830,17 @@ void Curl_ossl_session_free(void *ptr)
*/
int Curl_ossl_close_all(struct SessionHandle *data)
{
/*
ERR_remove_state() frees the error queue associated with
thread pid. If pid == 0, the current thread will have its
error queue removed.
Since error queue data structures are allocated
automatically for new threads, they must be freed when
threads are terminated in oder to avoid memory leaks.
*/
ERR_remove_state(0);
#ifdef HAVE_OPENSSL_ENGINE_H
if(data->state.engine) {
ENGINE_finish(data->state.engine);

View File

@ -32,10 +32,14 @@ CURLcode Curl_ossl_connect(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 */
/* close a SSL connection */
void Curl_ossl_close(struct connectdata *conn, int sockindex);
/* tell OpenSSL to close down all open information regarding connections (and
thus session ID caching etc) */
int Curl_ossl_close_all(struct SessionHandle *data);
/* Sets an OpenSSL engine */
CURLcode Curl_ossl_set_engine(struct SessionHandle *data, const char *engine);

View File

@ -1822,7 +1822,8 @@ static void conn_free(struct connectdata *conn)
Curl_destroy_thread_data(&conn->async);
#endif
Curl_ssl_close(conn);
Curl_ssl_close(conn, FIRSTSOCKET);
Curl_ssl_close(conn, SECONDARYSOCKET);
Curl_free_ssl_config(&conn->ssl_config);
@ -1892,7 +1893,7 @@ CURLcode Curl_disconnect(struct connectdata *conn)
allocated by libidn */
#endif
Curl_ssl_close(conn);
Curl_ssl_close(conn, FIRSTSOCKET);
/* Indicate to all handles on the pipe that we're dead */
if (IsPipeliningEnabled(data)) {

View File

@ -166,7 +166,9 @@ typedef enum {
/* struct for data related to each SSL connection */
struct ssl_connect_data {
bool use; /* use ssl encrypted communications TRUE/FALSE */
bool use; /* use ssl encrypted communications TRUE/FALSE, not
necessarily using it atm but at least asked to or
meaning to use it */
#ifdef USE_SSLEAY
/* these ones requires specific SSL-types */
SSL_CTX* ctx;