commit 299a194cc86ea81c40d2146dd095dda3954efc81 Author: Tomas Korbar Date: Tue May 6 12:01:10 2025 +0200 Ensure proper closing of TLS connection diff --git a/src/buffer.cc b/src/buffer.cc index 9ee6580..e54e20e 100644 --- a/src/buffer.cc +++ b/src/buffer.cc @@ -491,23 +491,31 @@ int IOBuffer::Do() if(Done() || Error()) return STALL; int res=0; + int remaining_size; switch(mode) { case PUT: - if(Size()==0) - return STALL; - res=Put_LL(buffer+buffer_ptr,Size()); - if(res>0) - { - RateAdd(res); - buffer_ptr+=res; - event_time=now; - if(eof) - PutEOF_LL(); - return MOVED; + remaining_size = Size(); + if (remaining_size > 0) { + res=Put_LL(buffer+buffer_ptr, remaining_size); + if (res <= 0) { + return STALL; + } + RateAdd(res); + buffer_ptr+=res; + event_time=now; + if (eof) { + /* We do not have to check for return value of PutEOF_LL here as + * We MOVED anyway and find out whether it was a success in next Do */ + PutEOF_LL(); + } + return MOVED; + } + if (eof && PutEOF_LL()) { + event_time=now; + return MOVED; } break; - case GET: if(eof) return STALL; diff --git a/src/buffer_ssl.cc b/src/buffer_ssl.cc index 9e701c2..6dd8680 100644 --- a/src/buffer_ssl.cc +++ b/src/buffer_ssl.cc @@ -39,10 +39,11 @@ int IOBufferSSL::Do() // nothing to write, but may need to do handshake if(!ssl->handshake_done) { - if(Put_LL("",0)<0) - return MOVED; - if(ssl->handshake_done && eof) - ssl->shutdown(); + if(Put_LL("",0)<0) + return MOVED; + } + if(ssl->handshake_done && eof && IOBufferSSL::PutEOF_LL()) { + return MOVED; } if(ssl->handshake_done && !eof) return m; @@ -103,8 +104,17 @@ int IOBufferSSL::Put_LL(const char *buf,int size) int IOBufferSSL::PutEOF_LL() { - if(Size()==0) - ssl->shutdown(); + int res; + if(Size()==0) { + res = ssl->shutdown(); + if (res == ssl->RETRY) { + SetNotReady(ssl->fd,want_mask()); + return 1; + } else if (res == ssl->ERROR) { + SetError(ssl->error,ssl->fatal); + return -1; + } + } return 0; } diff --git a/src/buffer_ssl.h b/src/buffer_ssl.h index d3cf7f0..8915066 100644 --- a/src/buffer_ssl.h +++ b/src/buffer_ssl.h @@ -42,7 +42,7 @@ public: IOBufferSSL(const Ref& s,dir_t m) : IOBuffer(m), ssl(s) {} ~IOBufferSSL(); int Do(); - bool Done() { return IOBuffer::Done() && ssl->handshake_done; } + bool Done() { return IOBuffer::Done() && ssl->handshake_done && ssl->goodbye_done; } }; #endif diff --git a/src/lftp_ssl.cc b/src/lftp_ssl.cc index 0a0078a..8820b6f 100644 --- a/src/lftp_ssl.cc +++ b/src/lftp_ssl.cc @@ -45,6 +45,7 @@ lftp_ssl_base::lftp_ssl_base(int fd1,handshake_mode_t m,const char *h) { fd=fd1; handshake_done=false; + goodbye_done=false; handshake_mode=m; fatal=false; cert_error=false; @@ -347,10 +348,24 @@ void lftp_ssl_gnutls::load_keys() Log::global->Format(9, "Loaded %d CRLs\n", res); gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE, cred); } -void lftp_ssl_gnutls::shutdown() +/* Try to shutdown the tls connection, return 1 if needed to call again otherwise 0*/ +int lftp_ssl_gnutls::shutdown() { - if(handshake_done) - gnutls_bye(session,GNUTLS_SHUT_RDWR); // FIXME - E_AGAIN + int res; + if(handshake_done) { + res = gnutls_bye(session,GNUTLS_SHUT_RDWR); + if (res == GNUTLS_E_SUCCESS) { + goodbye_done = true; + return DONE; + } else if (res == GNUTLS_E_AGAIN || res == GNUTLS_E_INTERRUPTED) { + return RETRY; + } + fatal=check_fatal(res); + set_error("gnutls_bye",gnutls_strerror(res)); + return ERROR; + } + goodbye_done = true; + return DONE; } lftp_ssl_gnutls::~lftp_ssl_gnutls() { @@ -849,10 +864,23 @@ void lftp_ssl_openssl::load_keys() } } } -void lftp_ssl_openssl::shutdown() +int lftp_ssl_openssl::shutdown() { - if(handshake_done) - SSL_shutdown(ssl); + int res; + if(handshake_done) { + res = SSL_shutdown(ssl); + if (res == 1) { + goodbye_done = true; + return DONE; + } else if (res == 0) { + return RETRY; + } + fatal=check_fatal(res); + set_error("SSL_shutdown",strerror()); + return ERROR; + } + goodbye_done = true; + return DONE; } lftp_ssl_openssl::~lftp_ssl_openssl() { diff --git a/src/lftp_ssl.h b/src/lftp_ssl.h index 17a91b0..8e0cc85 100644 --- a/src/lftp_ssl.h +++ b/src/lftp_ssl.h @@ -37,6 +37,7 @@ class lftp_ssl_base { public: bool handshake_done; + bool goodbye_done; int fd; xstring_c hostname; enum handshake_mode_t { CLIENT, SERVER } handshake_mode; @@ -107,7 +108,7 @@ public: bool want_out(); void copy_sid(const lftp_ssl_gnutls *); void load_keys(); - void shutdown(); + int shutdown(); }; typedef lftp_ssl_gnutls lftp_ssl; #elif USE_OPENSSL @@ -143,7 +144,7 @@ public: bool want_out(); void copy_sid(const lftp_ssl_openssl *); void load_keys(); - void shutdown(); + int shutdown(); }; typedef lftp_ssl_openssl lftp_ssl; #endif