Ensure proper closing of TLS connection

Resolves: RHEL-91005
This commit is contained in:
Tomas Korbar 2025-05-06 11:37:43 +02:00
parent e56af2868f
commit 0c33be2a89
2 changed files with 212 additions and 1 deletions

204
lftp-4.9.2-tls-close.patch Normal file
View File

@ -0,0 +1,204 @@
commit 841fb0abfa8b84af5cb817a7b77006253e239aec
Author: Tomas Korbar <tkorbar@redhat.com>
Date: Mon May 5 13:08:54 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<lftp_ssl>& 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 89421ee..2d8ef3d 100644
--- a/src/lftp_ssl.cc
+++ b/src/lftp_ssl.cc
@@ -48,6 +48,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;
@@ -350,10 +351,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()
{
@@ -854,10 +869,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 87b92d4..9b2a615 100644
--- a/src/lftp_ssl.h
+++ b/src/lftp_ssl.h
@@ -38,6 +38,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;
@@ -108,7 +109,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
@@ -144,7 +145,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

View File

@ -1,7 +1,7 @@
Summary: A sophisticated file transfer program
Name: lftp
Version: 4.9.2
Release: 16%{?dist}
Release: 17%{?dist}
License: GPL-3.0-or-later
Source0: http://lftp.yar.ru/ftp/%{name}-%{version}.tar.xz
URL: http://lftp.yar.ru/
@ -19,6 +19,7 @@ Patch1: lftp-4.0.9-date_fmt.patch
Patch2: lftp-4.9.2-cdefs.patch
Patch3: lftp-4.9.2-gnutls-peers2.patch
Patch4: lftp-4.9.2-fedora-c99.patch
Patch5: lftp-4.9.2-tls-close.patch
%description
LFTP is a sophisticated ftp/http file transfer program. Like bash, it has job
@ -36,6 +37,8 @@ reliability in mind.
%patch 3 -p1 -b .gnutls-peers2
%patch 4 -p1 -b .fedora-c99
%patch 5 -p1 -b .tls-close
# Avoid trying to re-run autoconf
touch -r aclocal.m4 configure m4/needtrio.m4
@ -97,6 +100,10 @@ rm -r $RPM_BUILD_ROOT%{_datadir}/lftp
%{_datadir}/icons/hicolor/*/apps/*
%changelog
* Tue May 06 2025 Tomas Korbar <tkorbar@redhat.com> - 4.9.2-17
- Ensure proper closing of TLS connection
- Resolves: RHEL-91005
* Tue Oct 29 2024 Troy Dawson <tdawson@redhat.com> - 4.9.2-16
- Bump release for October 2024 mass rebuild:
Resolves: RHEL-64018