diff options
Diffstat (limited to 'common/rdr')
-rw-r--r-- | common/rdr/BufferedInStream.cxx | 14 | ||||
-rw-r--r-- | common/rdr/BufferedOutStream.cxx | 13 | ||||
-rw-r--r-- | common/rdr/CMakeLists.txt | 11 | ||||
-rw-r--r-- | common/rdr/Exception.cxx | 135 | ||||
-rw-r--r-- | common/rdr/Exception.h | 80 | ||||
-rw-r--r-- | common/rdr/FdInStream.cxx | 9 | ||||
-rw-r--r-- | common/rdr/FdOutStream.cxx | 14 | ||||
-rw-r--r-- | common/rdr/FileInStream.cxx | 7 | ||||
-rw-r--r-- | common/rdr/HexInStream.cxx | 6 | ||||
-rw-r--r-- | common/rdr/HexOutStream.cxx | 7 | ||||
-rw-r--r-- | common/rdr/InStream.h | 13 | ||||
-rw-r--r-- | common/rdr/MemInStream.h | 1 | ||||
-rw-r--r-- | common/rdr/RandomStream.cxx | 14 | ||||
-rw-r--r-- | common/rdr/TLSException.cxx | 29 | ||||
-rw-r--r-- | common/rdr/TLSException.h | 8 | ||||
-rw-r--r-- | common/rdr/TLSInStream.cxx | 98 | ||||
-rw-r--r-- | common/rdr/TLSInStream.h | 18 | ||||
-rw-r--r-- | common/rdr/TLSOutStream.cxx | 82 | ||||
-rw-r--r-- | common/rdr/TLSOutStream.h | 17 | ||||
-rw-r--r-- | common/rdr/TLSSocket.cxx | 228 | ||||
-rw-r--r-- | common/rdr/TLSSocket.h | 81 | ||||
-rw-r--r-- | common/rdr/ZlibOutStream.cxx | 5 |
22 files changed, 425 insertions, 465 deletions
diff --git a/common/rdr/BufferedInStream.cxx b/common/rdr/BufferedInStream.cxx index bf94a950..bcdeef4a 100644 --- a/common/rdr/BufferedInStream.cxx +++ b/common/rdr/BufferedInStream.cxx @@ -23,9 +23,9 @@ #include <assert.h> -#include <rdr/BufferedInStream.h> +#include <core/string.h> -#include <rfb/util.h> +#include <rdr/BufferedInStream.h> using namespace rdr; @@ -64,12 +64,10 @@ void BufferedInStream::ensureSpace(size_t needed) uint8_t* newBuffer; if (needed > MAX_BUF_SIZE) - throw std::out_of_range(rfb::format("BufferedInStream overrun: " - "requested size of %lu bytes " - "exceeds maximum of %lu " - "bytes", - (long unsigned)needed, - (long unsigned)MAX_BUF_SIZE)); + throw std::out_of_range(core::format( + "BufferedInStream overrun: requested size of %lu bytes exceeds " + "maximum of %lu bytes", + (long unsigned)needed, (long unsigned)MAX_BUF_SIZE)); newSize = DEFAULT_BUF_SIZE; while (newSize < needed) diff --git a/common/rdr/BufferedOutStream.cxx b/common/rdr/BufferedOutStream.cxx index efb71dd7..e2b756bb 100644 --- a/common/rdr/BufferedOutStream.cxx +++ b/common/rdr/BufferedOutStream.cxx @@ -22,9 +22,9 @@ #include <config.h> #endif -#include <rdr/BufferedOutStream.h> +#include <core/string.h> -#include <rfb/util.h> +#include <rdr/BufferedOutStream.h> using namespace rdr; @@ -138,11 +138,10 @@ void BufferedOutStream::overrun(size_t needed) // We'll need to allocate more buffer space... if (totalNeeded > MAX_BUF_SIZE) - throw std::out_of_range(rfb::format("BufferedOutStream overrun: " - "requested size of %lu bytes " - "exceeds maximum of %lu bytes", - (long unsigned)totalNeeded, - (long unsigned)MAX_BUF_SIZE)); + throw std::out_of_range(core::format( + "BufferedOutStream overrun: requested size of %lu bytes exceeds " + "maximum of %lu bytes", + (long unsigned)totalNeeded, (long unsigned)MAX_BUF_SIZE)); newSize = DEFAULT_BUF_SIZE; while (newSize < totalNeeded) diff --git a/common/rdr/CMakeLists.txt b/common/rdr/CMakeLists.txt index 2897119b..526b2971 100644 --- a/common/rdr/CMakeLists.txt +++ b/common/rdr/CMakeLists.txt @@ -3,7 +3,6 @@ add_library(rdr STATIC AESOutStream.cxx BufferedInStream.cxx BufferedOutStream.cxx - Exception.cxx FdInStream.cxx FdOutStream.cxx FileInStream.cxx @@ -13,17 +12,14 @@ add_library(rdr STATIC TLSException.cxx TLSInStream.cxx TLSOutStream.cxx + TLSSocket.cxx ZlibInStream.cxx ZlibOutStream.cxx) target_include_directories(rdr PUBLIC ${CMAKE_SOURCE_DIR}/common) target_include_directories(rdr SYSTEM PUBLIC ${ZLIB_INCLUDE_DIRS}) -target_link_libraries(rdr ${ZLIB_LIBRARIES} os rfb) - -if(MSVC) - # undef min and max macro - target_compile_definitions(rfb PRIVATE NOMINMAX) -endif() +target_link_libraries(rdr core) +target_link_libraries(rdr ${ZLIB_LIBRARIES}) if(GNUTLS_FOUND) target_include_directories(rdr SYSTEM PUBLIC ${GNUTLS_INCLUDE_DIR}) @@ -32,7 +28,6 @@ endif() if (NETTLE_FOUND) target_include_directories(rdr SYSTEM PUBLIC ${NETTLE_INCLUDE_DIRS}) target_link_libraries(rdr ${NETTLE_LIBRARIES}) - target_link_directories(rdr PUBLIC ${NETTLE_LIBRARY_DIRS}) endif() if(WIN32) target_link_libraries(rdr ws2_32) diff --git a/common/rdr/Exception.cxx b/common/rdr/Exception.cxx deleted file mode 100644 index f0c04a6a..00000000 --- a/common/rdr/Exception.cxx +++ /dev/null @@ -1,135 +0,0 @@ -/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. - * Copyright (C) 2004 Red Hat Inc. - * Copyright (C) 2010 TigerVNC Team - * Copyright 2014-2024 Pierre Ossman for Cendio AB - * - * This is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This software is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this software; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, - * USA. - */ - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#include <stdio.h> -#include <stdarg.h> - -#include <rdr/Exception.h> -#include <rdr/TLSException.h> -#include <rfb/util.h> - -#ifdef _WIN32 -#include <winsock2.h> -#include <windows.h> -#include <ws2tcpip.h> -#else -#include <netdb.h> -#endif - -#include <string.h> - -using namespace rdr; - - -getaddrinfo_error::getaddrinfo_error(const char* s, int err_) noexcept - : std::runtime_error(rfb::format("%s: %s (%d)", s, - strerror(err_).c_str(), err_)), - err(err_) -{ -} - -getaddrinfo_error::getaddrinfo_error(const std::string& s, - int err_) noexcept - : std::runtime_error(rfb::format("%s: %s (%d)", s.c_str(), - strerror(err_).c_str(), err_)), - err(err_) -{ -} - -std::string getaddrinfo_error::strerror(int err_) const noexcept -{ -#ifdef _WIN32 - char str[256]; - - WideCharToMultiByte(CP_UTF8, 0, gai_strerrorW(err_), -1, str, - sizeof(str), nullptr, nullptr); - - return str; -#else - return gai_strerror(err_); -#endif -} - -posix_error::posix_error(const char* what_arg, int err_) noexcept - : std::runtime_error(rfb::format("%s: %s (%d)", what_arg, - strerror(err_).c_str(), err_)), - err(err_) -{ -} - -posix_error::posix_error(const std::string& what_arg, int err_) noexcept - : std::runtime_error(rfb::format("%s: %s (%d)", what_arg.c_str(), - strerror(err_).c_str(), err_)), - err(err_) -{ -} - -std::string posix_error::strerror(int err_) const noexcept -{ -#ifdef _WIN32 - char str[256]; - - WideCharToMultiByte(CP_UTF8, 0, _wcserror(err_), -1, str, - sizeof(str), nullptr, nullptr); - - return str; -#else - return ::strerror(err_); -#endif -} - -#ifdef WIN32 -win32_error::win32_error(const char* what_arg, unsigned err_) noexcept - : std::runtime_error(rfb::format("%s: %s (%d)", what_arg, - strerror(err_).c_str(), err_)), - err(err_) -{ -} - -win32_error::win32_error(const std::string& what_arg, - unsigned err_) noexcept - : std::runtime_error(rfb::format("%s: %s (%d)", what_arg.c_str(), - strerror(err_).c_str(), err_)), - err(err_) -{ -} - -std::string win32_error::strerror(unsigned err_) const noexcept -{ - wchar_t wstr[256]; - char str[256]; - - FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, - nullptr, err_, 0, wstr, sizeof(wstr), nullptr); - WideCharToMultiByte(CP_UTF8, 0, wstr, -1, str, - sizeof(str), nullptr, nullptr); - - int l = strlen(str); - if ((l >= 2) && (str[l-2] == '\r') && (str[l-1] == '\n')) - str[l-2] = 0; - - return str; -} -#endif diff --git a/common/rdr/Exception.h b/common/rdr/Exception.h deleted file mode 100644 index d3cecc18..00000000 --- a/common/rdr/Exception.h +++ /dev/null @@ -1,80 +0,0 @@ -/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. - * Copyright (C) 2004 Red Hat Inc. - * Copyright (C) 2010 TigerVNC Team - * Copyright 2015-2024 Pierre Ossman for Cendio AB - * - * This is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This software is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this software; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, - * USA. - */ - -#ifndef __RDR_EXCEPTION_H__ -#define __RDR_EXCEPTION_H__ - -#include <stdexcept> -#include <string> - -namespace rdr { - - class posix_error : public std::runtime_error { - public: - int err; - posix_error(const char* what_arg, int err_) noexcept; - posix_error(const std::string& what_arg, int err_) noexcept; - private: - std::string strerror(int err_) const noexcept; - }; - -#ifdef WIN32 - class win32_error : public std::runtime_error { - public: - unsigned err; - win32_error(const char* what_arg, unsigned err_) noexcept; - win32_error(const std::string& what_arg, unsigned err_) noexcept; - private: - std::string strerror(unsigned err_) const noexcept; - }; -#endif - -#ifdef WIN32 - class socket_error : public win32_error { - public: - socket_error(const char* what_arg, unsigned err_) noexcept : win32_error(what_arg, err_) {} - socket_error(const std::string& what_arg, unsigned err_) noexcept : win32_error(what_arg, err_) {} - }; -#else - class socket_error : public posix_error { - public: - socket_error(const char* what_arg, unsigned err_) noexcept : posix_error(what_arg, err_) {} - socket_error(const std::string& what_arg, unsigned err_) noexcept : posix_error(what_arg, err_) {} - }; -#endif - - class getaddrinfo_error : public std::runtime_error { - public: - int err; - getaddrinfo_error(const char* s, int err_) noexcept; - getaddrinfo_error(const std::string& s, int err_) noexcept; - private: - std::string strerror(int err_) const noexcept; - }; - - class end_of_stream : public std::runtime_error { - public: - end_of_stream() noexcept : std::runtime_error("End of stream") {} - }; - -} - -#endif diff --git a/common/rdr/FdInStream.cxx b/common/rdr/FdInStream.cxx index 23ea2f8c..25542a01 100644 --- a/common/rdr/FdInStream.cxx +++ b/common/rdr/FdInStream.cxx @@ -28,7 +28,7 @@ #include <winsock2.h> #define errorNumber WSAGetLastError() #define close closesocket -#include <os/winerrno.h> +#include <core/winerrno.h> #else #include <sys/types.h> #include <sys/socket.h> @@ -41,8 +41,9 @@ #include <sys/select.h> #endif +#include <core/Exception.h> + #include <rdr/FdInStream.h> -#include <rdr/Exception.h> using namespace rdr; @@ -92,7 +93,7 @@ size_t FdInStream::readFd(uint8_t* buf, size_t len) } while (n < 0 && errorNumber == EINTR); if (n < 0) - throw socket_error("select", errorNumber); + throw core::socket_error("select", errorNumber); if (n == 0) return 0; @@ -102,7 +103,7 @@ size_t FdInStream::readFd(uint8_t* buf, size_t len) } while (n < 0 && errorNumber == EINTR); if (n < 0) - throw socket_error("read", errorNumber); + throw core::socket_error("read", errorNumber); if (n == 0) throw end_of_stream(); diff --git a/common/rdr/FdOutStream.cxx b/common/rdr/FdOutStream.cxx index 6db8c0bb..416926c1 100644 --- a/common/rdr/FdOutStream.cxx +++ b/common/rdr/FdOutStream.cxx @@ -28,7 +28,7 @@ #ifdef _WIN32 #include <winsock2.h> #define errorNumber WSAGetLastError() -#include <os/winerrno.h> +#include <core/winerrno.h> #else #include <sys/types.h> #include <unistd.h> @@ -44,10 +44,10 @@ #include <sys/select.h> #endif -#include <rdr/FdOutStream.h> -#include <rdr/Exception.h> -#include <rfb/util.h> +#include <core/Exception.h> +#include <core/time.h> +#include <rdr/FdOutStream.h> using namespace rdr; @@ -68,7 +68,7 @@ FdOutStream::~FdOutStream() unsigned FdOutStream::getIdleTime() { - return rfb::msSince(&lastWrite); + return core::msSince(&lastWrite); } void FdOutStream::cork(bool enable) @@ -117,7 +117,7 @@ size_t FdOutStream::writeFd(const uint8_t* data, size_t length) } while (n < 0 && errorNumber == EINTR); if (n < 0) - throw socket_error("select", errorNumber); + throw core::socket_error("select", errorNumber); if (n == 0) return 0; @@ -134,7 +134,7 @@ size_t FdOutStream::writeFd(const uint8_t* data, size_t length) } while (n < 0 && (errorNumber == EINTR)); if (n < 0) - throw socket_error("write", errorNumber); + throw core::socket_error("write", errorNumber); gettimeofday(&lastWrite, nullptr); diff --git a/common/rdr/FileInStream.cxx b/common/rdr/FileInStream.cxx index df09ea76..4dbe2d1f 100644 --- a/common/rdr/FileInStream.cxx +++ b/common/rdr/FileInStream.cxx @@ -24,7 +24,8 @@ #include <errno.h> -#include <rdr/Exception.h> +#include <core/Exception.h> + #include <rdr/FileInStream.h> using namespace rdr; @@ -33,7 +34,7 @@ FileInStream::FileInStream(const char *fileName) { file = fopen(fileName, "rb"); if (!file) - throw posix_error("fopen", errno); + throw core::posix_error("fopen", errno); } FileInStream::~FileInStream(void) { @@ -48,7 +49,7 @@ bool FileInStream::fillBuffer() size_t n = fread((uint8_t*)end, 1, availSpace(), file); if (n == 0) { if (ferror(file)) - throw posix_error("fread", errno); + throw core::posix_error("fread", errno); if (feof(file)) throw end_of_stream(); return false; diff --git a/common/rdr/HexInStream.cxx b/common/rdr/HexInStream.cxx index 69c3e260..b5a8826c 100644 --- a/common/rdr/HexInStream.cxx +++ b/common/rdr/HexInStream.cxx @@ -22,8 +22,10 @@ #endif #include <algorithm> + +#include <core/string.h> + #include <rdr/HexInStream.h> -#include <rfb/util.h> using namespace rdr; @@ -44,7 +46,7 @@ bool HexInStream::fillBuffer() { uint8_t* optr = (uint8_t*) end; for (size_t i=0; i<length; i++) { - if (!rfb::hexToBin((const char*)&iptr[i*2], 2, &optr[i], 1)) + if (!core::hexToBin((const char*)&iptr[i*2], 2, &optr[i], 1)) throw std::runtime_error("HexInStream: Invalid input data"); } diff --git a/common/rdr/HexOutStream.cxx b/common/rdr/HexOutStream.cxx index efab77f8..b3749c0d 100644 --- a/common/rdr/HexOutStream.cxx +++ b/common/rdr/HexOutStream.cxx @@ -20,9 +20,12 @@ #ifdef HAVE_CONFIG_H #include <config.h> #endif + #include <algorithm> + +#include <core/string.h> + #include <rdr/HexOutStream.h> -#include <rfb/util.h> using namespace rdr; @@ -42,7 +45,7 @@ bool HexOutStream::flushBuffer() size_t length = std::min((size_t)(ptr-sentUpTo), out_stream.avail()/2); for (size_t i=0; i<length; i++) - rfb::binToHex(&sentUpTo[i], 1, (char*)&optr[i*2], 2); + core::binToHex(&sentUpTo[i], 1, (char*)&optr[i*2], 2); out_stream.setptr(length*2); sentUpTo += length; diff --git a/common/rdr/InStream.h b/common/rdr/InStream.h index 5623142c..7ad4996f 100644 --- a/common/rdr/InStream.h +++ b/common/rdr/InStream.h @@ -38,6 +38,11 @@ namespace rdr { + class end_of_stream : public std::runtime_error { + public: + end_of_stream() noexcept : std::runtime_error("End of stream") {} + }; + class InStream { public: @@ -182,9 +187,7 @@ namespace rdr { private: const uint8_t* restorePoint; -#ifdef RFB_INSTREAM_CHECK size_t checkedBytes; -#endif inline void check(size_t bytes) { #ifdef RFB_INSTREAM_CHECK @@ -204,11 +207,7 @@ namespace rdr { protected: - InStream() : restorePoint(nullptr) -#ifdef RFB_INSTREAM_CHECK - ,checkedBytes(0) -#endif - {} + InStream() : restorePoint(nullptr), checkedBytes(0) {} const uint8_t* ptr; const uint8_t* end; }; diff --git a/common/rdr/MemInStream.h b/common/rdr/MemInStream.h index 78ee2dee..a92e18f9 100644 --- a/common/rdr/MemInStream.h +++ b/common/rdr/MemInStream.h @@ -28,7 +28,6 @@ #define __RDR_MEMINSTREAM_H__ #include <rdr/InStream.h> -#include <rdr/Exception.h> namespace rdr { diff --git a/common/rdr/RandomStream.cxx b/common/rdr/RandomStream.cxx index 3a524102..9784c220 100644 --- a/common/rdr/RandomStream.cxx +++ b/common/rdr/RandomStream.cxx @@ -20,9 +20,11 @@ #include <config.h> #endif +#include <core/Exception.h> +#include <core/LogWriter.h> + #include <rdr/RandomStream.h> -#include <rdr/Exception.h> -#include <rfb/LogWriter.h> + #include <time.h> #include <stdlib.h> #ifndef WIN32 @@ -35,7 +37,7 @@ #endif #endif -static rfb::LogWriter vlog("RandomStream"); +static core::LogWriter vlog("RandomStream"); using namespace rdr; @@ -89,7 +91,7 @@ bool RandomStream::fillBuffer() { #ifdef RFB_HAVE_WINCRYPT if (provider) { if (!CryptGenRandom(provider, availSpace(), (uint8_t*)end)) - throw rdr::win32_error("Unable to CryptGenRandom", GetLastError()); + throw core::win32_error("Unable to CryptGenRandom", GetLastError()); end += availSpace(); } else { #else @@ -97,8 +99,8 @@ bool RandomStream::fillBuffer() { if (fp) { size_t n = fread((uint8_t*)end, 1, availSpace(), fp); if (n <= 0) - throw rdr::posix_error("Reading /dev/urandom or /dev/random " - "failed", errno); + throw core::posix_error( + "Reading /dev/urandom or /dev/random failed", errno); end += n; } else { #else diff --git a/common/rdr/TLSException.cxx b/common/rdr/TLSException.cxx index ee4f587b..8c93a3d3 100644 --- a/common/rdr/TLSException.cxx +++ b/common/rdr/TLSException.cxx @@ -22,9 +22,9 @@ #include <config.h> #endif -#include <rdr/TLSException.h> +#include <core/string.h> -#include <rfb/util.h> +#include <rdr/TLSException.h> #include <string.h> #include <stdio.h> @@ -35,11 +35,28 @@ using namespace rdr; #ifdef HAVE_GNUTLS -tls_error::tls_error(const char* s, int err_) noexcept - : std::runtime_error(rfb::format("%s: %s (%d)", s, - gnutls_strerror(err_), err_)), - err(err_) +tls_error::tls_error(const char* s, int err_, int alert_) noexcept + : std::runtime_error(core::format("%s: %s (%d)", s, + strerror(err_, alert_), err_)), + err(err_), alert(alert_) +{ +} + +const char* tls_error::strerror(int err_, int alert_) const noexcept { + const char* msg; + + msg = nullptr; + + if ((alert_ != -1) && + ((err_ == GNUTLS_E_WARNING_ALERT_RECEIVED) || + (err_ == GNUTLS_E_FATAL_ALERT_RECEIVED))) + msg = gnutls_alert_get_name((gnutls_alert_description_t)alert_); + + if (msg == nullptr) + msg = gnutls_strerror(err_); + + return msg; } #endif /* HAVE_GNUTLS */ diff --git a/common/rdr/TLSException.h b/common/rdr/TLSException.h index 62b090ba..75ee94f5 100644 --- a/common/rdr/TLSException.h +++ b/common/rdr/TLSException.h @@ -21,14 +21,16 @@ #ifndef __RDR_TLSEXCEPTION_H__ #define __RDR_TLSEXCEPTION_H__ -#include <rdr/Exception.h> +#include <stdexcept> namespace rdr { class tls_error : public std::runtime_error { public: - int err; - tls_error(const char* s, int err_) noexcept; + int err, alert; + tls_error(const char* s, int err_, int alert_=-1) noexcept; + private: + const char* strerror(int err_, int alert_) const noexcept; }; } diff --git a/common/rdr/TLSInStream.cxx b/common/rdr/TLSInStream.cxx index ee2739f4..3e5ea2be 100644 --- a/common/rdr/TLSInStream.cxx +++ b/common/rdr/TLSInStream.cxx @@ -1,7 +1,7 @@ /* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. * Copyright (C) 2005 Martin Koegler * Copyright (C) 2010 TigerVNC Team - * Copyright (C) 2012-2021 Pierre Ossman for Cendio AB + * Copyright 2012-2025 Pierre Ossman for Cendio AB * * This is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -23,74 +23,25 @@ #include <config.h> #endif -#include <rdr/Exception.h> -#include <rdr/TLSException.h> #include <rdr/TLSInStream.h> -#include <rfb/LogWriter.h> -#include <errno.h> +#include <rdr/TLSSocket.h> -#ifdef HAVE_GNUTLS -using namespace rdr; - -static rfb::LogWriter vlog("TLSInStream"); - -ssize_t TLSInStream::pull(gnutls_transport_ptr_t str, void* data, size_t size) -{ - TLSInStream* self= (TLSInStream*) str; - InStream *in = self->in; - - self->streamEmpty = false; - delete self->saved_exception; - self->saved_exception = nullptr; +#ifdef HAVE_GNUTLS - try { - if (!in->hasData(1)) { - self->streamEmpty = true; - gnutls_transport_set_errno(self->session, EAGAIN); - return -1; - } - - if (in->avail() < size) - size = in->avail(); - - in->readBytes((uint8_t*)data, size); - } catch (end_of_stream&) { - return 0; - } catch (socket_error& e) { - vlog.error("Failure reading TLS data: %s", e.what()); - gnutls_transport_set_errno(self->session, e.err); - self->saved_exception = new socket_error(e); - return -1; - } catch (std::exception& e) { - vlog.error("Failure reading TLS data: %s", e.what()); - gnutls_transport_set_errno(self->session, EINVAL); - self->saved_exception = new std::runtime_error(e.what()); - return -1; - } - - return size; -} +using namespace rdr; -TLSInStream::TLSInStream(InStream* _in, gnutls_session_t _session) - : session(_session), in(_in), saved_exception(nullptr) +TLSInStream::TLSInStream(TLSSocket* sock_) + : sock(sock_) { - gnutls_transport_ptr_t recv, send; - - gnutls_transport_set_pull_function(session, pull); - gnutls_transport_get_ptr2(session, &recv, &send); - gnutls_transport_set_ptr2(session, this, send); } TLSInStream::~TLSInStream() { - gnutls_transport_set_pull_function(session, nullptr); - - delete saved_exception; } bool TLSInStream::fillBuffer() { - size_t n = readTLS((uint8_t*) end, availSpace()); + size_t n = sock->readTLS((uint8_t*) end, availSpace()); if (n == 0) return false; end += n; @@ -98,39 +49,4 @@ bool TLSInStream::fillBuffer() return true; } -size_t TLSInStream::readTLS(uint8_t* buf, size_t len) -{ - int n; - - while (true) { - streamEmpty = false; - n = gnutls_record_recv(session, (void *) buf, len); - if (n == GNUTLS_E_INTERRUPTED || n == GNUTLS_E_AGAIN) { - // GnuTLS returns GNUTLS_E_AGAIN for a bunch of other scenarios - // other than the pull function returning EAGAIN, so we have to - // double check that the underlying stream really is empty - if (!streamEmpty) - continue; - else - return 0; - } - break; - }; - - if (n == GNUTLS_E_PULL_ERROR) { - if (dynamic_cast<socket_error*>(saved_exception)) - throw *dynamic_cast<socket_error*>(saved_exception); - else - throw std::runtime_error(saved_exception->what()); - } - - if (n < 0) - throw tls_error("readTLS", n); - - if (n == 0) - throw end_of_stream(); - - return n; -} - #endif diff --git a/common/rdr/TLSInStream.h b/common/rdr/TLSInStream.h index 2269b09d..94266e50 100644 --- a/common/rdr/TLSInStream.h +++ b/common/rdr/TLSInStream.h @@ -1,5 +1,6 @@ /* Copyright (C) 2005 Martin Koegler * Copyright (C) 2010 TigerVNC Team + * Copyright 2012-2025 Pierre Ossman for Cendio AB * * This is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -22,28 +23,25 @@ #ifdef HAVE_GNUTLS -#include <gnutls/gnutls.h> #include <rdr/BufferedInStream.h> namespace rdr { + class TLSSocket; + class TLSInStream : public BufferedInStream { public: - TLSInStream(InStream* in, gnutls_session_t session); + TLSInStream(TLSSocket* sock); virtual ~TLSInStream(); private: bool fillBuffer() override; - size_t readTLS(uint8_t* buf, size_t len); - static ssize_t pull(gnutls_transport_ptr_t str, void* data, size_t size); - - gnutls_session_t session; - InStream* in; - bool streamEmpty; - std::exception* saved_exception; + TLSSocket* sock; }; -}; + +} #endif + #endif diff --git a/common/rdr/TLSOutStream.cxx b/common/rdr/TLSOutStream.cxx index 365ffd60..ba9d182f 100644 --- a/common/rdr/TLSOutStream.cxx +++ b/common/rdr/TLSOutStream.cxx @@ -1,7 +1,7 @@ /* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. * Copyright (C) 2005 Martin Koegler * Copyright (C) 2010 TigerVNC Team - * Copyright (C) 2012-2021 Pierre Ossman for Cendio AB + * Copyright 2012-2025 Pierre Ossman for Cendio AB * * This is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -23,108 +23,42 @@ #include <config.h> #endif -#include <rdr/Exception.h> -#include <rdr/TLSException.h> #include <rdr/TLSOutStream.h> -#include <rfb/LogWriter.h> -#include <errno.h> +#include <rdr/TLSSocket.h> #ifdef HAVE_GNUTLS -using namespace rdr; - -static rfb::LogWriter vlog("TLSOutStream"); - -ssize_t TLSOutStream::push(gnutls_transport_ptr_t str, const void* data, - size_t size) -{ - TLSOutStream* self= (TLSOutStream*) str; - OutStream *out = self->out; - - delete self->saved_exception; - self->saved_exception = nullptr; - try { - out->writeBytes((const uint8_t*)data, size); - out->flush(); - } catch (socket_error& e) { - vlog.error("Failure sending TLS data: %s", e.what()); - gnutls_transport_set_errno(self->session, e.err); - self->saved_exception = new socket_error(e); - return -1; - } catch (std::exception& e) { - vlog.error("Failure sending TLS data: %s", e.what()); - gnutls_transport_set_errno(self->session, EINVAL); - self->saved_exception = new std::runtime_error(e.what()); - return -1; - } - - return size; -} +using namespace rdr; -TLSOutStream::TLSOutStream(OutStream* _out, gnutls_session_t _session) - : session(_session), out(_out), saved_exception(nullptr) +TLSOutStream::TLSOutStream(TLSSocket* sock_) + : sock(sock_) { - gnutls_transport_ptr_t recv, send; - - gnutls_transport_set_push_function(session, push); - gnutls_transport_get_ptr2(session, &recv, &send); - gnutls_transport_set_ptr2(session, recv, this); } TLSOutStream::~TLSOutStream() { -#if 0 - try { -// flush(); - } catch (Exception&) { - } -#endif - gnutls_transport_set_push_function(session, nullptr); - - delete saved_exception; } void TLSOutStream::flush() { BufferedOutStream::flush(); - out->flush(); + sock->out->flush(); } void TLSOutStream::cork(bool enable) { BufferedOutStream::cork(enable); - out->cork(enable); + sock->out->cork(enable); } bool TLSOutStream::flushBuffer() { while (sentUpTo < ptr) { - size_t n = writeTLS(sentUpTo, ptr - sentUpTo); + size_t n = sock->writeTLS(sentUpTo, ptr - sentUpTo); sentUpTo += n; } return true; } -size_t TLSOutStream::writeTLS(const uint8_t* data, size_t length) -{ - int n; - - n = gnutls_record_send(session, data, length); - if (n == GNUTLS_E_INTERRUPTED || n == GNUTLS_E_AGAIN) - return 0; - - if (n == GNUTLS_E_PUSH_ERROR) { - if (dynamic_cast<socket_error*>(saved_exception)) - throw *dynamic_cast<socket_error*>(saved_exception); - else - throw std::runtime_error(saved_exception->what()); - } - - if (n < 0) - throw tls_error("writeTLS", n); - - return n; -} - #endif diff --git a/common/rdr/TLSOutStream.h b/common/rdr/TLSOutStream.h index 659f16f0..aa9572ba 100644 --- a/common/rdr/TLSOutStream.h +++ b/common/rdr/TLSOutStream.h @@ -21,14 +21,16 @@ #define __RDR_TLSOUTSTREAM_H__ #ifdef HAVE_GNUTLS -#include <gnutls/gnutls.h> + #include <rdr/BufferedOutStream.h> namespace rdr { + class TLSSocket; + class TLSOutStream : public BufferedOutStream { public: - TLSOutStream(OutStream* out, gnutls_session_t session); + TLSOutStream(TLSSocket* out); virtual ~TLSOutStream(); void flush() override; @@ -36,15 +38,12 @@ namespace rdr { private: bool flushBuffer() override; - size_t writeTLS(const uint8_t* data, size_t length); - static ssize_t push(gnutls_transport_ptr_t str, const void* data, size_t size); - - gnutls_session_t session; - OutStream* out; - std::exception* saved_exception; + TLSSocket* sock; }; -}; + +} #endif + #endif diff --git a/common/rdr/TLSSocket.cxx b/common/rdr/TLSSocket.cxx new file mode 100644 index 00000000..a29e41c1 --- /dev/null +++ b/common/rdr/TLSSocket.cxx @@ -0,0 +1,228 @@ +/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. + * Copyright (C) 2005 Martin Koegler + * Copyright (C) 2010 TigerVNC Team + * Copyright (C) 2012-2025 Pierre Ossman for Cendio AB + * + * This is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + * USA. + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <core/Exception.h> +#include <core/LogWriter.h> + +#include <rdr/InStream.h> +#include <rdr/OutStream.h> +#include <rdr/TLSException.h> +#include <rdr/TLSSocket.h> + +#include <errno.h> + +#ifdef HAVE_GNUTLS + +using namespace rdr; + +static core::LogWriter vlog("TLSSocket"); + +TLSSocket::TLSSocket(InStream* in_, OutStream* out_, + gnutls_session_t session_) + : session(session_), in(in_), out(out_), tlsin(this), tlsout(this) +{ + gnutls_transport_set_pull_function( + session, [](gnutls_transport_ptr_t sock, void* data, size_t size) { + return ((TLSSocket*)sock)->pull(data, size); + }); + gnutls_transport_set_push_function( + session, [](gnutls_transport_ptr_t sock, const void* data, size_t size) { + return ((TLSSocket*)sock)->push(data, size); + }); + gnutls_transport_set_ptr(session, this); +} + +TLSSocket::~TLSSocket() +{ + gnutls_transport_set_pull_function(session, nullptr); + gnutls_transport_set_push_function(session, nullptr); + gnutls_transport_set_ptr(session, nullptr); +} + +bool TLSSocket::handshake() +{ + int err; + + err = gnutls_handshake(session); + if (err != GNUTLS_E_SUCCESS) { + gnutls_alert_description_t alert; + const char* msg; + + if ((err == GNUTLS_E_PULL_ERROR) || (err == GNUTLS_E_PUSH_ERROR)) + std::rethrow_exception(saved_exception); + + alert = gnutls_alert_get(session); + msg = nullptr; + + if ((err == GNUTLS_E_WARNING_ALERT_RECEIVED) || + (err == GNUTLS_E_FATAL_ALERT_RECEIVED)) + msg = gnutls_alert_get_name(alert); + + if (msg == nullptr) + msg = gnutls_strerror(err); + + if (!gnutls_error_is_fatal(err)) { + vlog.debug("Deferring completion of TLS handshake: %s", msg); + return false; + } + + vlog.error("TLS Handshake failed: %s\n", msg); + gnutls_alert_send_appropriate(session, err); + throw rdr::tls_error("TLS Handshake failed", err, alert); + } + + return true; +} + +void TLSSocket::shutdown() +{ + int ret; + + try { + if (tlsout.hasBufferedData()) { + tlsout.cork(false); + tlsout.flush(); + if (tlsout.hasBufferedData()) + vlog.error("Failed to flush remaining socket data on close"); + } + } catch (std::exception& e) { + vlog.error("Failed to flush remaining socket data on close: %s", e.what()); + } + + // FIXME: We can't currently wait for the response, so we only send + // our close and hope for the best + ret = gnutls_bye(session, GNUTLS_SHUT_WR); + if ((ret != GNUTLS_E_SUCCESS) && (ret != GNUTLS_E_INVALID_SESSION)) + vlog.error("TLS shutdown failed: %s", gnutls_strerror(ret)); +} + +size_t TLSSocket::readTLS(uint8_t* buf, size_t len) +{ + int n; + + while (true) { + streamEmpty = false; + n = gnutls_record_recv(session, (void *) buf, len); + if (n == GNUTLS_E_INTERRUPTED || n == GNUTLS_E_AGAIN) { + // GnuTLS returns GNUTLS_E_AGAIN for a bunch of other scenarios + // other than the pull function returning EAGAIN, so we have to + // double check that the underlying stream really is empty + if (!streamEmpty) + continue; + else + return 0; + } + break; + }; + + if (n == GNUTLS_E_PULL_ERROR) + std::rethrow_exception(saved_exception); + + if (n < 0) { + gnutls_alert_send_appropriate(session, n); + throw tls_error("readTLS", n, gnutls_alert_get(session)); + } + + if (n == 0) + throw end_of_stream(); + + return n; +} + +size_t TLSSocket::writeTLS(const uint8_t* data, size_t length) +{ + int n; + + n = gnutls_record_send(session, data, length); + if (n == GNUTLS_E_INTERRUPTED || n == GNUTLS_E_AGAIN) + return 0; + + if (n == GNUTLS_E_PUSH_ERROR) + std::rethrow_exception(saved_exception); + + if (n < 0) { + gnutls_alert_send_appropriate(session, n); + throw tls_error("writeTLS", n, gnutls_alert_get(session)); + } + + return n; +} + +ssize_t TLSSocket::pull(void* data, size_t size) +{ + streamEmpty = false; + saved_exception = nullptr; + + try { + if (!in->hasData(1)) { + streamEmpty = true; + gnutls_transport_set_errno(session, EAGAIN); + return -1; + } + + if (in->avail() < size) + size = in->avail(); + + in->readBytes((uint8_t*)data, size); + } catch (end_of_stream&) { + return 0; + } catch (std::exception& e) { + core::socket_error* se; + vlog.error("Failure reading TLS data: %s", e.what()); + se = dynamic_cast<core::socket_error*>(&e); + if (se) + gnutls_transport_set_errno(session, se->err); + else + gnutls_transport_set_errno(session, EINVAL); + saved_exception = std::current_exception(); + return -1; + } + + return size; +} + +ssize_t TLSSocket::push(const void* data, size_t size) +{ + saved_exception = nullptr; + + try { + out->writeBytes((const uint8_t*)data, size); + out->flush(); + } catch (std::exception& e) { + core::socket_error* se; + vlog.error("Failure sending TLS data: %s", e.what()); + se = dynamic_cast<core::socket_error*>(&e); + if (se) + gnutls_transport_set_errno(session, se->err); + else + gnutls_transport_set_errno(session, EINVAL); + saved_exception = std::current_exception(); + return -1; + } + + return size; +} + +#endif diff --git a/common/rdr/TLSSocket.h b/common/rdr/TLSSocket.h new file mode 100644 index 00000000..ca29f8bc --- /dev/null +++ b/common/rdr/TLSSocket.h @@ -0,0 +1,81 @@ +/* Copyright (C) 2005 Martin Koegler + * Copyright (C) 2010 TigerVNC Team + * Copyright 2012-2025 Pierre Ossman for Cendio AB + * + * This is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + * USA. + */ + +#ifndef __RDR_TLSSOCKET_H__ +#define __RDR_TLSSOCKET_H__ + +#ifdef HAVE_GNUTLS + +#include <exception> + +#include <gnutls/gnutls.h> + +#include <rdr/TLSInStream.h> +#include <rdr/TLSOutStream.h> + +namespace rdr { + + class InStream; + class OutStream; + + class TLSInStream; + class TLSOutStream; + + class TLSSocket { + public: + TLSSocket(InStream* in, OutStream* out, gnutls_session_t session); + virtual ~TLSSocket(); + + TLSInStream& inStream() { return tlsin; } + TLSOutStream& outStream() { return tlsout; } + + bool handshake(); + void shutdown(); + + protected: + /* Used by the stream classes */ + size_t readTLS(uint8_t* buf, size_t len); + size_t writeTLS(const uint8_t* data, size_t length); + + friend TLSInStream; + friend TLSOutStream; + + private: + ssize_t pull(void* data, size_t size); + ssize_t push(const void* data, size_t size); + + gnutls_session_t session; + + InStream* in; + OutStream* out; + + TLSInStream tlsin; + TLSOutStream tlsout; + + bool streamEmpty; + + std::exception_ptr saved_exception; + }; + +} + +#endif + +#endif diff --git a/common/rdr/ZlibOutStream.cxx b/common/rdr/ZlibOutStream.cxx index 73b5d459..1b8ac307 100644 --- a/common/rdr/ZlibOutStream.cxx +++ b/common/rdr/ZlibOutStream.cxx @@ -23,14 +23,15 @@ #include <stdio.h> +#include <core/LogWriter.h> + #include <rdr/ZlibOutStream.h> -#include <rfb/LogWriter.h> #include <zlib.h> #undef ZLIBOUT_DEBUG -static rfb::LogWriter vlog("ZlibOutStream"); +static core::LogWriter vlog("ZlibOutStream"); using namespace rdr; |