diff options
Diffstat (limited to 'common')
38 files changed, 248 insertions, 480 deletions
diff --git a/common/rdr/CMakeLists.txt b/common/rdr/CMakeLists.txt index 30c2403a..2897119b 100644 --- a/common/rdr/CMakeLists.txt +++ b/common/rdr/CMakeLists.txt @@ -20,6 +20,11 @@ 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() + if(GNUTLS_FOUND) target_include_directories(rdr SYSTEM PUBLIC ${GNUTLS_INCLUDE_DIR}) target_link_libraries(rdr ${GNUTLS_LIBRARIES}) diff --git a/common/rdr/HexInStream.cxx b/common/rdr/HexInStream.cxx index e23974e1..11f98498 100644 --- a/common/rdr/HexInStream.cxx +++ b/common/rdr/HexInStream.cxx @@ -21,14 +21,13 @@ #include <config.h> #endif +#include <algorithm> #include <rdr/HexInStream.h> #include <rdr/Exception.h> #include <rfb/util.h> using namespace rdr; -static inline int min(int a, int b) {return a<b ? a : b;} - HexInStream::HexInStream(InStream& is) : in_stream(is) { @@ -37,12 +36,11 @@ HexInStream::HexInStream(InStream& is) HexInStream::~HexInStream() { } - bool HexInStream::fillBuffer() { if (!in_stream.hasData(2)) return false; - size_t length = min(in_stream.avail()/2, availSpace()); + size_t length = std::min(in_stream.avail()/2, availSpace()); const uint8_t* iptr = in_stream.getptr(length*2); uint8_t* optr = (uint8_t*) end; diff --git a/common/rdr/HexOutStream.cxx b/common/rdr/HexOutStream.cxx index b1ab2dc0..efab77f8 100644 --- a/common/rdr/HexOutStream.cxx +++ b/common/rdr/HexOutStream.cxx @@ -20,14 +20,12 @@ #ifdef HAVE_CONFIG_H #include <config.h> #endif - +#include <algorithm> #include <rdr/HexOutStream.h> #include <rfb/util.h> using namespace rdr; -static inline size_t min(size_t a, size_t b) {return a<b ? a : b;} - HexOutStream::HexOutStream(OutStream& os) : out_stream(os) { @@ -41,7 +39,7 @@ bool HexOutStream::flushBuffer() { while (sentUpTo != ptr) { uint8_t* optr = out_stream.getptr(2); - size_t length = min(ptr-sentUpTo, out_stream.avail()/2); + 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); @@ -64,4 +62,3 @@ void HexOutStream::cork(bool enable) BufferedOutStream::cork(enable); out_stream.cork(enable); } - diff --git a/common/rfb/CConnection.cxx b/common/rfb/CConnection.cxx index 0db5f4c8..b4017dba 100644 --- a/common/rfb/CConnection.cxx +++ b/common/rfb/CConnection.cxx @@ -332,7 +332,7 @@ bool CConnection::processSecurityResultMsg() if (server.beforeVersion(3,8)) { state_ = RFBSTATE_INVALID; - throw AuthFailureException(); + throw AuthFailureException("Authentication failed"); } state_ = RFBSTATE_SECURITY_REASON; diff --git a/common/rfb/CConnection.h b/common/rfb/CConnection.h index dca98a92..b30a997b 100644 --- a/common/rfb/CConnection.h +++ b/common/rfb/CConnection.h @@ -35,7 +35,6 @@ namespace rfb { class CMsgReader; class CMsgWriter; class CSecurity; - class IdentityVerifier; class CConnection : public CMsgHandler { public: @@ -75,16 +74,11 @@ namespace rfb { // there is data to read on the InStream. void initialiseProtocol(); - // processMsg() should be called whenever there is either: - // - data available on the underlying network stream - // In this case, processMsg may return without processing an RFB message, - // if the available data does not result in an RFB message being ready - // to handle. e.g. if data is encrypted. - // NB: This makes it safe to call processMsg() in response to select() - // - data available on the CConnection's current InStream - // In this case, processMsg should always process the available RFB - // message before returning. - // NB: In either case, you must have called initialiseProtocol() first. + // processMsg() should be called whenever there is data available on + // the CConnection's current InStream. It will process at most one + // RFB message before returning. If there was insufficient data, + // then it will return false and should be called again once more + // data is available. bool processMsg(); // close() gracefully shuts down the connection to the server and diff --git a/common/rfb/CMakeLists.txt b/common/rfb/CMakeLists.txt index 360434a9..36535448 100644 --- a/common/rfb/CMakeLists.txt +++ b/common/rfb/CMakeLists.txt @@ -50,7 +50,6 @@ add_library(rfb STATIC SSecurityStack.cxx SSecurityVncAuth.cxx SSecurityVeNCrypt.cxx - ScaleFilters.cxx Timer.cxx TightDecoder.cxx TightEncoder.cxx @@ -101,6 +100,10 @@ if(GNUTLS_FOUND) target_sources(rfb PRIVATE CSecurityTLS.cxx SSecurityTLS.cxx) target_include_directories(rfb SYSTEM PUBLIC ${GNUTLS_INCLUDE_DIR}) target_link_libraries(rfb ${GNUTLS_LIBRARIES}) + # FIXME: Hack to block it marking gnutls_free() as dllimport + if(WIN32 AND BUILD_STATIC) + target_compile_definitions(rfb PRIVATE GNUTLS_INTERNAL_BUILD) + endif() endif() if (NETTLE_FOUND) diff --git a/common/rfb/CMsgHandler.cxx b/common/rfb/CMsgHandler.cxx index c3594af9..4489dbd4 100644 --- a/common/rfb/CMsgHandler.cxx +++ b/common/rfb/CMsgHandler.cxx @@ -59,11 +59,6 @@ void CMsgHandler::setExtendedDesktopSize(unsigned reason, unsigned result, server.setDimensions(width, height, layout); } -void CMsgHandler::setPixelFormat(const PixelFormat& pf) -{ - server.setPF(pf); -} - void CMsgHandler::setName(const char* name) { server.setName(name); diff --git a/common/rfb/CMsgHandler.h b/common/rfb/CMsgHandler.h index 16a53c6a..9e5f7de2 100644 --- a/common/rfb/CMsgHandler.h +++ b/common/rfb/CMsgHandler.h @@ -39,12 +39,12 @@ namespace rfb { CMsgHandler(); virtual ~CMsgHandler(); - // The following methods are called as corresponding messages are read. A - // derived class should override these methods as desired. Note that for - // the setDesktopSize(), setExtendedDesktopSize(), setPixelFormat(), - // setName(), serverInit() and clipboardCaps methods, a derived class - // should call on to CMsgHandler's methods to set the members of "server" - // appropriately. + // The following methods are called as corresponding messages are + // read. A derived class should override these methods as desired. + // Note that for the setDesktopSize(), setExtendedDesktopSize(), + // setName(), serverInit() and handleClipboardCaps() methods, a + // derived class should call on to CMsgHandler's methods to set the + // members of "server" appropriately. virtual void setDesktopSize(int w, int h); virtual void setExtendedDesktopSize(unsigned reason, unsigned result, @@ -53,7 +53,6 @@ namespace rfb { virtual void setCursor(int width, int height, const Point& hotspot, const uint8_t* data) = 0; virtual void setCursorPos(const Point& pos) = 0; - virtual void setPixelFormat(const PixelFormat& pf); virtual void setName(const char* name); virtual void fence(uint32_t flags, unsigned len, const uint8_t data[]); virtual void endOfContinuousUpdates(); diff --git a/common/rfb/CMsgWriter.cxx b/common/rfb/CMsgWriter.cxx index 7d757968..1bd8040f 100644 --- a/common/rfb/CMsgWriter.cxx +++ b/common/rfb/CMsgWriter.cxx @@ -173,7 +173,7 @@ void CMsgWriter::writeKeyEvent(uint32_t keysym, uint32_t keycode, bool down) } -void CMsgWriter::writePointerEvent(const Point& pos, int buttonMask) +void CMsgWriter::writePointerEvent(const Point& pos, uint8_t buttonMask) { Point p(pos); if (p.x < 0) p.x = 0; diff --git a/common/rfb/CMsgWriter.h b/common/rfb/CMsgWriter.h index 1b70a1d0..61df567f 100644 --- a/common/rfb/CMsgWriter.h +++ b/common/rfb/CMsgWriter.h @@ -54,7 +54,7 @@ namespace rfb { void writeFence(uint32_t flags, unsigned len, const uint8_t data[]); void writeKeyEvent(uint32_t keysym, uint32_t keycode, bool down); - void writePointerEvent(const Point& pos, int buttonMask); + void writePointerEvent(const Point& pos, uint8_t buttonMask); void writeClientCutText(const char* str); diff --git a/common/rfb/CSecurityDH.cxx b/common/rfb/CSecurityDH.cxx index 6d9650bd..f3b085c7 100644 --- a/common/rfb/CSecurityDH.cxx +++ b/common/rfb/CSecurityDH.cxx @@ -86,9 +86,9 @@ bool CSecurityDH::readKey() uint16_t gen = is->readU16(); keyLength = is->readU16(); if (keyLength < MinKeyLength) - throw AuthFailureException("DH key is too short"); + throw Exception("DH key is too short"); if (keyLength > MaxKeyLength) - throw AuthFailureException("DH key is too long"); + throw Exception("DH key is too long"); if (!is->hasDataOrRestore(keyLength * 2)) return false; is->clearRestorePoint(); @@ -112,7 +112,7 @@ void CSecurityDH::writeCredentials() std::vector<uint8_t> bBytes(keyLength); if (!rs.hasData(keyLength)) - throw ConnFailedException("failed to generate DH private key"); + throw Exception("failed to generate DH private key"); rs.readBytes(bBytes.data(), bBytes.size()); nettle_mpz_set_str_256_u(b, bBytes.size(), bBytes.data()); mpz_powm(k, A, b, p); @@ -132,13 +132,13 @@ void CSecurityDH::writeCredentials() uint8_t buf[128]; if (!rs.hasData(128)) - throw ConnFailedException("failed to generate random padding"); + throw Exception("failed to generate random padding"); rs.readBytes(buf, 128); if (username.size() >= 64) - throw AuthFailureException("username is too long"); + throw Exception("username is too long"); memcpy(buf, username.c_str(), username.size() + 1); if (password.size() >= 64) - throw AuthFailureException("password is too long"); + throw Exception("password is too long"); memcpy(buf + 64, password.c_str(), password.size() + 1); aes128_encrypt(&aesCtx, 128, buf, buf); diff --git a/common/rfb/CSecurityMSLogonII.cxx b/common/rfb/CSecurityMSLogonII.cxx index e721cdfc..dc817518 100644 --- a/common/rfb/CSecurityMSLogonII.cxx +++ b/common/rfb/CSecurityMSLogonII.cxx @@ -101,7 +101,7 @@ void CSecurityMSLogonII::writeCredentials() std::vector<uint8_t> bBytes(8); if (!rs.hasData(8)) - throw ConnFailedException("failed to generate DH private key"); + throw Exception("failed to generate DH private key"); rs.readBytes(bBytes.data(), bBytes.size()); nettle_mpz_set_str_256_u(b, bBytes.size(), bBytes.data()); mpz_powm(k, A, b, p); @@ -123,14 +123,14 @@ void CSecurityMSLogonII::writeCredentials() } if (!rs.hasData(256 + 64)) - throw ConnFailedException("failed to generate random padding"); + throw Exception("failed to generate random padding"); rs.readBytes(user, 256); rs.readBytes(pass, 64); if (username.size() >= 256) - throw AuthFailureException("username is too long"); + throw Exception("username is too long"); memcpy(user, username.c_str(), username.size() + 1); if (password.size() >= 64) - throw AuthFailureException("password is too long"); + throw Exception("password is too long"); memcpy(pass, password.c_str(), password.size() + 1); // DES-CBC with the original key as IV, and the reversed one as the DES key diff --git a/common/rfb/CSecurityRSAAES.cxx b/common/rfb/CSecurityRSAAES.cxx index 96d96b01..a78739ac 100644 --- a/common/rfb/CSecurityRSAAES.cxx +++ b/common/rfb/CSecurityRSAAES.cxx @@ -135,7 +135,7 @@ static void random_func(void* ctx, size_t length, uint8_t* dst) { rdr::RandomStream* rs = (rdr::RandomStream*)ctx; if (!rs->hasData(length)) - throw ConnFailedException("failed to generate random"); + throw Exception("failed to generate random"); rs->readBytes(dst, length); } @@ -156,7 +156,7 @@ void CSecurityRSAAES::writePublicKey() if (!rsa_generate_keypair(&clientPublicKey, &clientKey, &rs, random_func, nullptr, nullptr, clientKeyLength, 0)) - throw AuthFailureException("failed to generate key"); + throw Exception("failed to generate key"); clientKeyN = new uint8_t[rsaKeySize]; clientKeyE = new uint8_t[rsaKeySize]; nettle_mpz_get_str_256(rsaKeySize, clientKeyN, clientPublicKey.n); @@ -175,9 +175,9 @@ bool CSecurityRSAAES::readPublicKey() is->setRestorePoint(); serverKeyLength = is->readU32(); if (serverKeyLength < MinKeyLength) - throw AuthFailureException("server key is too short"); + throw Exception("server key is too short"); if (serverKeyLength > MaxKeyLength) - throw AuthFailureException("server key is too long"); + throw Exception("server key is too long"); size_t size = (serverKeyLength + 7) / 8; if (!is->hasDataOrRestore(size * 2)) return false; @@ -190,7 +190,7 @@ bool CSecurityRSAAES::readPublicKey() nettle_mpz_set_str_256_u(serverKey.n, size, serverKeyN); nettle_mpz_set_str_256_u(serverKey.e, size, serverKeyE); if (!rsa_public_key_prepare(&serverKey)) - throw AuthFailureException("server key is invalid"); + throw Exception("server key is invalid"); return true; } @@ -216,14 +216,14 @@ void CSecurityRSAAES::verifyServer() "Please verify that the information is correct and press \"Yes\". " "Otherwise press \"No\"", f[0], f[1], f[2], f[3], f[4], f[5], f[6], f[7]); if (!msg->showMsgBox(UserMsgBox::M_YESNO, title, text.c_str())) - throw AuthFailureException("server key mismatch"); + throw Exception("server key mismatch"); } void CSecurityRSAAES::writeRandom() { rdr::OutStream* os = cc->getOutStream(); if (!rs.hasData(keySize / 8)) - throw ConnFailedException("failed to generate random"); + throw Exception("failed to generate random"); rs.readBytes(clientRandom, keySize / 8); mpz_t x; mpz_init(x); @@ -237,7 +237,7 @@ void CSecurityRSAAES::writeRandom() } if (!res) { mpz_clear(x); - throw AuthFailureException("failed to encrypt random"); + throw Exception("failed to encrypt random"); } uint8_t* buffer = new uint8_t[serverKey.size]; nettle_mpz_get_str_256(serverKey.size, buffer, x); @@ -256,7 +256,7 @@ bool CSecurityRSAAES::readRandom() is->setRestorePoint(); size_t size = is->readU16(); if (size != clientKey.size) - throw AuthFailureException("client key length doesn't match"); + throw Exception("client key length doesn't match"); if (!is->hasDataOrRestore(size)) return false; is->clearRestorePoint(); @@ -269,7 +269,7 @@ bool CSecurityRSAAES::readRandom() if (!rsa_decrypt(&clientKey, &randomSize, serverRandom, x) || randomSize != (size_t)keySize / 8) { mpz_clear(x); - throw AuthFailureException("failed to decrypt server random"); + throw Exception("failed to decrypt server random"); } mpz_clear(x); return true; @@ -398,7 +398,7 @@ bool CSecurityRSAAES::readHash() sha256_digest(&ctx, hashSize, realHash); } if (memcmp(hash, realHash, hashSize) != 0) - throw AuthFailureException("hash doesn't match"); + throw Exception("hash doesn't match"); return true; } @@ -428,7 +428,7 @@ bool CSecurityRSAAES::readSubtype() return false; subtype = rais->readU8(); if (subtype != secTypeRA2UserPass && subtype != secTypeRA2Pass) - throw AuthFailureException("unknown RSA-AES subtype"); + throw Exception("unknown RSA-AES subtype"); return true; } @@ -444,7 +444,7 @@ void CSecurityRSAAES::writeCredentials() if (subtype == secTypeRA2UserPass) { if (username.size() > 255) - throw AuthFailureException("username is too long"); + throw Exception("username is too long"); raos->writeU8(username.size()); raos->writeBytes((const uint8_t*)username.data(), username.size()); } else { @@ -452,7 +452,7 @@ void CSecurityRSAAES::writeCredentials() } if (password.size() > 255) - throw AuthFailureException("password is too long"); + throw Exception("password is too long"); raos->writeU8(password.size()); raos->writeBytes((const uint8_t*)password.data(), password.size()); raos->flush(); diff --git a/common/rfb/CSecurityTLS.cxx b/common/rfb/CSecurityTLS.cxx index 8d8b58fd..2a7a1179 100644 --- a/common/rfb/CSecurityTLS.cxx +++ b/common/rfb/CSecurityTLS.cxx @@ -40,22 +40,13 @@ #include <rfb/Exception.h> #include <rfb/UserMsgBox.h> #include <rfb/util.h> +#include <rdr/TLSException.h> #include <rdr/TLSInStream.h> #include <rdr/TLSOutStream.h> #include <os/os.h> #include <gnutls/x509.h> -/* - * GNUTLS doesn't correctly export gnutls_free symbol which is - * a function pointer. Linking with Visual Studio 2008 Express will - * fail when you call gnutls_free(). - */ -#if WIN32 -#undef gnutls_free -#define gnutls_free free -#endif - using namespace rfb; static const char* configdirfn(const char* fn); @@ -88,8 +79,9 @@ CSecurityTLS::CSecurityTLS(CConnection* cc_, bool _anon) anon(_anon), tlsis(nullptr), tlsos(nullptr), rawis(nullptr), rawos(nullptr) { - if (gnutls_global_init() != GNUTLS_E_SUCCESS) - throw AuthFailureException("gnutls_global_init failed"); + int err = gnutls_global_init(); + if (err != GNUTLS_E_SUCCESS) + throw rdr::TLSException("gnutls_global_init()", err); } void CSecurityTLS::shutdown() @@ -149,17 +141,21 @@ bool CSecurityTLS::processMsg() client = cc; if (!session) { + int ret; + if (!is->hasData(1)) return false; if (is->readU8() == 0) - throw AuthFailureException("Server failed to initialize TLS session"); + throw Exception("Server failed to initialize TLS session"); - if (gnutls_init(&session, GNUTLS_CLIENT) != GNUTLS_E_SUCCESS) - throw AuthFailureException("gnutls_init failed"); + ret = gnutls_init(&session, GNUTLS_CLIENT); + if (ret != GNUTLS_E_SUCCESS) + throw rdr::TLSException("gnutls_init()", ret); - if (gnutls_set_default_priority(session) != GNUTLS_E_SUCCESS) - throw AuthFailureException("gnutls_set_default_priority failed"); + ret = gnutls_set_default_priority(session); + if (ret != GNUTLS_E_SUCCESS) + throw rdr::TLSException("gnutls_set_default_priority()", ret); setParam(); @@ -182,7 +178,7 @@ bool CSecurityTLS::processMsg() vlog.error("TLS Handshake failed: %s\n", gnutls_strerror (err)); shutdown(); - throw AuthFailureException("TLS Handshake failed"); + throw rdr::TLSException("TLS Handshake failed", err); } vlog.debug("TLS handshake completed with %s", @@ -209,7 +205,7 @@ void CSecurityTLS::setParam() prio = (char*)malloc(strlen(Security::GnuTLSPriority) + strlen(kx_anon_priority) + 1); if (prio == nullptr) - throw AuthFailureException("Not enough memory for GnuTLS priority string"); + throw Exception("Not enough memory for GnuTLS priority string"); strcpy(prio, Security::GnuTLSPriority); if (anon) @@ -222,7 +218,7 @@ void CSecurityTLS::setParam() if (ret != GNUTLS_E_SUCCESS) { if (ret == GNUTLS_E_INVALID_REQUEST) vlog.error("GnuTLS priority syntax error at: %s", err); - throw AuthFailureException("gnutls_set_priority_direct failed"); + throw rdr::TLSException("gnutls_set_priority_direct()", ret); } } else if (anon) { const char *err; @@ -234,7 +230,7 @@ void CSecurityTLS::setParam() if (ret != GNUTLS_E_SUCCESS) { if (ret == GNUTLS_E_INVALID_REQUEST) vlog.error("GnuTLS priority syntax error at: %s", err); - throw AuthFailureException("gnutls_set_default_priority_append failed"); + throw rdr::TLSException("gnutls_set_default_priority_append()", ret); } #else // We don't know what the system default priority is, so we guess @@ -245,7 +241,7 @@ void CSecurityTLS::setParam() prio = (char*)malloc(strlen(gnutls_default_priority) + strlen(kx_anon_priority) + 1); if (prio == nullptr) - throw AuthFailureException("Not enough memory for GnuTLS priority string"); + throw Exception("Not enough memory for GnuTLS priority string"); strcpy(prio, gnutls_default_priority); strcat(prio, kx_anon_priority); @@ -257,22 +253,25 @@ void CSecurityTLS::setParam() if (ret != GNUTLS_E_SUCCESS) { if (ret == GNUTLS_E_INVALID_REQUEST) vlog.error("GnuTLS priority syntax error at: %s", err); - throw AuthFailureException("gnutls_set_priority_direct failed"); + throw rdr::TLSException("gnutls_set_priority_direct()", ret); } #endif } if (anon) { - if (gnutls_anon_allocate_client_credentials(&anon_cred) != GNUTLS_E_SUCCESS) - throw AuthFailureException("gnutls_anon_allocate_client_credentials failed"); + ret = gnutls_anon_allocate_client_credentials(&anon_cred); + if (ret != GNUTLS_E_SUCCESS) + throw rdr::TLSException("gnutls_anon_allocate_client_credentials()", ret); - if (gnutls_credentials_set(session, GNUTLS_CRD_ANON, anon_cred) != GNUTLS_E_SUCCESS) - throw AuthFailureException("gnutls_credentials_set failed"); + ret = gnutls_credentials_set(session, GNUTLS_CRD_ANON, anon_cred); + if (ret != GNUTLS_E_SUCCESS) + throw rdr::TLSException("gnutls_credentials_set()", ret); vlog.debug("Anonymous session has been set"); } else { - if (gnutls_certificate_allocate_credentials(&cert_cred) != GNUTLS_E_SUCCESS) - throw AuthFailureException("gnutls_certificate_allocate_credentials failed"); + ret = gnutls_certificate_allocate_credentials(&cert_cred); + if (ret != GNUTLS_E_SUCCESS) + throw rdr::TLSException("gnutls_certificate_allocate_credentials()", ret); if (gnutls_certificate_set_x509_system_trust(cert_cred) < 1) vlog.error("Could not load system certificate trust store"); @@ -283,8 +282,9 @@ void CSecurityTLS::setParam() if (gnutls_certificate_set_x509_crl_file(cert_cred, X509CRL, GNUTLS_X509_FMT_PEM) < 0) vlog.error("Could not load user specified certificate revocation list"); - if (gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE, cert_cred) != GNUTLS_E_SUCCESS) - throw AuthFailureException("gnutls_credentials_set failed"); + ret = gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE, cert_cred); + if (ret != GNUTLS_E_SUCCESS) + throw rdr::TLSException("gnutls_credentials_set()", ret); if (gnutls_server_name_set(session, GNUTLS_NAME_DNS, client->getServerName(), @@ -306,7 +306,7 @@ void CSecurityTLS::checkSession() unsigned int status; const gnutls_datum_t *cert_list; unsigned int cert_list_size = 0; - int err; + int err, known; bool hostname_match; const char *hostsDir; @@ -317,12 +317,12 @@ void CSecurityTLS::checkSession() return; if (gnutls_certificate_type_get(session) != GNUTLS_CRT_X509) - throw AuthFailureException("unsupported certificate type"); + throw Exception("unsupported certificate type"); err = gnutls_certificate_verify_peers2(session, &status); if (err != 0) { vlog.error("server certificate verification failed: %s", gnutls_strerror(err)); - throw AuthFailureException("server certificate verification failed"); + throw rdr::TLSException("server certificate verification()", err); } if (status != 0) { @@ -340,11 +340,11 @@ void CSecurityTLS::checkSession() 0) < 0) throw Exception("Failed to get certificate error description"); - error = format("Invalid server certificate: %s", status_str.data); + error = (const char*)status_str.data; gnutls_free(status_str.data); - throw AuthFailureException(error.c_str()); + throw Exception("Invalid server certificate: %s", error.c_str()); } if (gnutls_certificate_verification_status_print(status, @@ -362,14 +362,14 @@ void CSecurityTLS::checkSession() cert_list = gnutls_certificate_get_peers(session, &cert_list_size); if (!cert_list_size) - throw AuthFailureException("empty certificate chain"); + throw Exception("empty certificate chain"); /* Process only server's certificate, not issuer's certificate */ gnutls_x509_crt_t crt; gnutls_x509_crt_init(&crt); if (gnutls_x509_crt_import(crt, &cert_list[0], GNUTLS_X509_FMT_DER) < 0) - throw AuthFailureException("decoding of certificate failed"); + throw Exception("decoding of certificate failed"); if (gnutls_x509_crt_check_hostname(crt, client->getServerName()) == 0) { vlog.info("Server certificate doesn't match given server name"); @@ -388,31 +388,32 @@ void CSecurityTLS::checkSession() hostsDir = os::getvncstatedir(); if (hostsDir == nullptr) { - throw AuthFailureException("Could not obtain VNC state directory " - "path for known hosts storage"); + throw Exception("Could not obtain VNC state directory path for " + "known hosts storage"); } std::string dbPath; dbPath = (std::string)hostsDir + "/x509_known_hosts"; - err = gnutls_verify_stored_pubkey(dbPath.c_str(), nullptr, - client->getServerName(), nullptr, - GNUTLS_CRT_X509, &cert_list[0], 0); + known = gnutls_verify_stored_pubkey(dbPath.c_str(), nullptr, + client->getServerName(), nullptr, + GNUTLS_CRT_X509, &cert_list[0], 0); /* Previously known? */ - if (err == GNUTLS_E_SUCCESS) { + if (known == GNUTLS_E_SUCCESS) { vlog.info("Server certificate found in known hosts file"); gnutls_x509_crt_deinit(crt); return; } - if ((err != GNUTLS_E_NO_CERTIFICATE_FOUND) && - (err != GNUTLS_E_CERTIFICATE_KEY_MISMATCH)) { - throw AuthFailureException("Could not load known hosts database"); + if ((known != GNUTLS_E_NO_CERTIFICATE_FOUND) && + (known != GNUTLS_E_CERTIFICATE_KEY_MISMATCH)) { + throw rdr::TLSException("Could not load known hosts database", known); } - if (gnutls_x509_crt_print(crt, GNUTLS_CRT_PRINT_ONELINE, &info)) - throw AuthFailureException("Could not find certificate to display"); + err = gnutls_x509_crt_print(crt, GNUTLS_CRT_PRINT_ONELINE, &info); + if (err != GNUTLS_E_SUCCESS) + throw rdr::TLSException("Could not find certificate to display", err); len = strlen((char*)info.data); for (size_t i = 0; i < len - 1; i++) { @@ -421,7 +422,7 @@ void CSecurityTLS::checkSession() } /* New host */ - if (err == GNUTLS_E_NO_CERTIFICATE_FOUND) { + if (known == GNUTLS_E_NO_CERTIFICATE_FOUND) { std::string text; vlog.info("Server host not previously known"); @@ -444,7 +445,7 @@ void CSecurityTLS::checkSession() if (!msg->showMsgBox(UserMsgBox::M_YESNO, "Unknown certificate issuer", text.c_str())) - throw AuthFailureException("Unknown certificate issuer"); + throw AuthCancelledException(); status &= ~(GNUTLS_CERT_INVALID | GNUTLS_CERT_SIGNER_NOT_FOUND | @@ -465,7 +466,7 @@ void CSecurityTLS::checkSession() if (!msg->showMsgBox(UserMsgBox::M_YESNO, "Certificate is not yet valid", text.c_str())) - throw AuthFailureException("Certificate is not yet valid"); + throw AuthCancelledException(); status &= ~GNUTLS_CERT_NOT_ACTIVATED; } @@ -484,7 +485,7 @@ void CSecurityTLS::checkSession() if (!msg->showMsgBox(UserMsgBox::M_YESNO, "Expired certificate", text.c_str())) - throw AuthFailureException("Expired certificate"); + throw AuthCancelledException(); status &= ~GNUTLS_CERT_EXPIRED; } @@ -503,14 +504,14 @@ void CSecurityTLS::checkSession() if (!msg->showMsgBox(UserMsgBox::M_YESNO, "Insecure certificate algorithm", text.c_str())) - throw AuthFailureException("Insecure certificate algorithm"); + throw AuthCancelledException(); status &= ~GNUTLS_CERT_INSECURE_ALGORITHM; } if (status != 0) { vlog.error("Unhandled certificate problems: 0x%x", status); - throw AuthFailureException("Unhandled certificate problems"); + throw Exception("Unhandled certificate problems"); } if (!hostname_match) { @@ -528,9 +529,9 @@ void CSecurityTLS::checkSession() if (!msg->showMsgBox(UserMsgBox::M_YESNO, "Certificate hostname mismatch", text.c_str())) - throw AuthFailureException("Certificate hostname mismatch"); + throw AuthCancelledException(); } - } else if (err == GNUTLS_E_CERTIFICATE_KEY_MISMATCH) { + } else if (known == GNUTLS_E_CERTIFICATE_KEY_MISMATCH) { std::string text; vlog.info("Server host key mismatch"); @@ -554,7 +555,7 @@ void CSecurityTLS::checkSession() if (!msg->showMsgBox(UserMsgBox::M_YESNO, "Unexpected server certificate", text.c_str())) - throw AuthFailureException("Unexpected server certificate"); + throw AuthCancelledException(); status &= ~(GNUTLS_CERT_INVALID | GNUTLS_CERT_SIGNER_NOT_FOUND | @@ -577,7 +578,7 @@ void CSecurityTLS::checkSession() if (!msg->showMsgBox(UserMsgBox::M_YESNO, "Unexpected server certificate", text.c_str())) - throw AuthFailureException("Unexpected server certificate"); + throw AuthCancelledException(); status &= ~GNUTLS_CERT_NOT_ACTIVATED; } @@ -598,7 +599,7 @@ void CSecurityTLS::checkSession() if (!msg->showMsgBox(UserMsgBox::M_YESNO, "Unexpected server certificate", text.c_str())) - throw AuthFailureException("Unexpected server certificate"); + throw AuthCancelledException(); status &= ~GNUTLS_CERT_EXPIRED; } @@ -619,14 +620,14 @@ void CSecurityTLS::checkSession() if (!msg->showMsgBox(UserMsgBox::M_YESNO, "Unexpected server certificate", text.c_str())) - throw AuthFailureException("Unexpected server certificate"); + throw AuthCancelledException(); status &= ~GNUTLS_CERT_INSECURE_ALGORITHM; } if (status != 0) { vlog.error("Unhandled certificate problems: 0x%x", status); - throw AuthFailureException("Unhandled certificate problems"); + throw Exception("Unhandled certificate problems"); } if (!hostname_match) { @@ -646,7 +647,7 @@ void CSecurityTLS::checkSession() if (!msg->showMsgBox(UserMsgBox::M_YESNO, "Unexpected server certificate", text.c_str())) - throw AuthFailureException("Unexpected server certificate"); + throw AuthCancelledException(); } } diff --git a/common/rfb/CSecurityVeNCrypt.cxx b/common/rfb/CSecurityVeNCrypt.cxx index 19dcabc3..3ebb3855 100644 --- a/common/rfb/CSecurityVeNCrypt.cxx +++ b/common/rfb/CSecurityVeNCrypt.cxx @@ -37,8 +37,6 @@ #include <rfb/LogWriter.h> using namespace rfb; -using namespace rdr; -using namespace std; static LogWriter vlog("CVeNCrypt"); @@ -68,8 +66,8 @@ CSecurityVeNCrypt::~CSecurityVeNCrypt() bool CSecurityVeNCrypt::processMsg() { - InStream* is = cc->getInStream(); - OutStream* os = cc->getOutStream(); + rdr::InStream* is = cc->getInStream(); + rdr::OutStream* os = cc->getOutStream(); /* get major, minor versions, send what we can support (or 0.0 for can't support it) */ if (!haveRecvdMajorVersion) { @@ -107,7 +105,7 @@ bool CSecurityVeNCrypt::processMsg() os->writeU8(0); os->writeU8(0); os->flush(); - throw AuthFailureException("The server reported an unsupported VeNCrypt version"); + throw Exception("The server reported an unsupported VeNCrypt version"); } haveSentVersion = true; @@ -119,8 +117,8 @@ bool CSecurityVeNCrypt::processMsg() return false; if (is->readU8()) - throw AuthFailureException("The server reported it could not support the " - "VeNCrypt version"); + throw Exception("The server reported it could not support the " + "VeNCrypt version"); haveAgreedVersion = true; } @@ -133,7 +131,7 @@ bool CSecurityVeNCrypt::processMsg() nAvailableTypes = is->readU8(); if (!nAvailableTypes) - throw AuthFailureException("The server reported no VeNCrypt sub-types"); + throw Exception("The server reported no VeNCrypt sub-types"); availableTypes = new uint32_t[nAvailableTypes]; haveNumberOfTypes = true; @@ -159,7 +157,7 @@ bool CSecurityVeNCrypt::processMsg() if (!haveChosenType) { chosenType = secTypeInvalid; uint8_t i; - list<uint32_t> secTypes; + std::list<uint32_t> secTypes; secTypes = security->GetEnabledExtSecTypes(); @@ -174,7 +172,7 @@ bool CSecurityVeNCrypt::processMsg() /* Set up the stack according to the chosen type: */ if (chosenType == secTypeInvalid || chosenType == secTypeVeNCrypt) - throw AuthFailureException("No valid VeNCrypt sub-type"); + throw Exception("No valid VeNCrypt sub-type"); vlog.info("Choosing security type %s (%d)", secTypeName(chosenType), chosenType); @@ -193,7 +191,7 @@ bool CSecurityVeNCrypt::processMsg() * happen, since if the server supports 0 sub-types, it doesn't support * this security type */ - throw AuthFailureException("The server reported 0 VeNCrypt sub-types"); + throw Exception("The server reported 0 VeNCrypt sub-types"); } return csecurity->processMsg(); diff --git a/common/rfb/Exception.h b/common/rfb/Exception.h index 827ced52..4520bc8c 100644 --- a/common/rfb/Exception.h +++ b/common/rfb/Exception.h @@ -23,20 +23,16 @@ namespace rfb { typedef rdr::Exception Exception; struct AuthFailureException : public Exception { - AuthFailureException() - : Exception("Authentication failure") {} AuthFailureException(const char* reason) - : Exception("Authentication failure: %s", reason) {} + : Exception("%s", reason) {} }; struct AuthCancelledException : public rfb::Exception { AuthCancelledException() : Exception("Authentication cancelled") {} }; struct ConnFailedException : public Exception { - ConnFailedException() - : Exception("Connection failed") {} ConnFailedException(const char* reason) - : Exception("Connection failed: %s", reason) {} + : Exception("%s", reason) {} }; } #endif diff --git a/common/rfb/InputHandler.h b/common/rfb/InputHandler.h deleted file mode 100644 index ad6c4be5..00000000 --- a/common/rfb/InputHandler.h +++ /dev/null @@ -1,43 +0,0 @@ -/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. - * - * 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. - */ -// -// InputHandler - abstract interface for accepting keyboard & -// pointer input and clipboard data. -// - -#ifndef __RFB_INPUTHANDLER_H__ -#define __RFB_INPUTHANDLER_H__ - -#include <stdint.h> - -#include <rfb/Rect.h> - -namespace rfb { - - class InputHandler { - public: - virtual ~InputHandler() {} - virtual void keyEvent(uint32_t /*keysym*/, uint32_t /*keycode*/, - bool /*down*/) { } - virtual void pointerEvent(const Point& /*pos*/, - int /*buttonMask*/) { } - virtual void clientCutText(const char* /*str*/) { } - }; - -} -#endif diff --git a/common/rfb/KeysymStr.c b/common/rfb/KeysymStr.c index 51d6e897..5bdb1558 100644 --- a/common/rfb/KeysymStr.c +++ b/common/rfb/KeysymStr.c @@ -34,6 +34,9 @@ in this Software without prior written authorization from The Open Group. #include "keysymdef.h" #include "KeysymStr.h" +/* Change the name of this to avoid conflict with libX11 */ +#define _XkeyTable _vncXkeyTable + #define NEEDKTABLE #define NEEDVTABLE #include "ks_tables.h" diff --git a/common/rfb/PixelBuffer.cxx b/common/rfb/PixelBuffer.cxx index f1354a43..0a287544 100644 --- a/common/rfb/PixelBuffer.cxx +++ b/common/rfb/PixelBuffer.cxx @@ -33,7 +33,6 @@ #include <rfb/PixelBuffer.h> using namespace rfb; -using namespace rdr; static LogWriter vlog("PixelBuffer"); diff --git a/common/rfb/SConnection.cxx b/common/rfb/SConnection.cxx index 866d19a2..08cef044 100644 --- a/common/rfb/SConnection.cxx +++ b/common/rfb/SConnection.cxx @@ -458,7 +458,7 @@ void SConnection::approveConnection(bool accept, const char* reason) os->writeU32(secResultFailed); if (!client.beforeVersion(3,8)) { // 3.8 onwards have failure message if (!reason) - reason = "Authentication failure"; + reason = "Connection rejected"; os->writeU32(strlen(reason)); os->writeBytes((const uint8_t*)reason, strlen(reason)); } @@ -476,7 +476,7 @@ void SConnection::approveConnection(bool accept, const char* reason) if (reason) throw AuthFailureException(reason); else - throw AuthFailureException(); + throw AuthFailureException("Connection rejected"); } } diff --git a/common/rfb/SConnection.h b/common/rfb/SConnection.h index 2ac53269..46b427ed 100644 --- a/common/rfb/SConnection.h +++ b/common/rfb/SConnection.h @@ -61,8 +61,11 @@ namespace rfb { // there is data to read on the InStream. void initialiseProtocol(); - // processMsg() should be called whenever there is data to read on the - // InStream. You must have called initialiseProtocol() first. + // processMsg() should be called whenever there is data available on + // the CConnection's current InStream. It will process at most one + // RFB message before returning. If there was insufficient data, + // then it will return false and should be called again once more + // data is available. bool processMsg(); // approveConnection() is called to either accept or reject the connection. diff --git a/common/rfb/SDesktop.h b/common/rfb/SDesktop.h index 94fcaa28..1d3c325f 100644 --- a/common/rfb/SDesktop.h +++ b/common/rfb/SDesktop.h @@ -40,14 +40,13 @@ #include <rfb/PixelBuffer.h> #include <rfb/VNCServer.h> -#include <rfb/InputHandler.h> #include <rfb/screenTypes.h> namespace network { class Socket; } namespace rfb { - class SDesktop : public InputHandler { + class SDesktop { public: // init() is called immediately when the VNCServer gets a reference // to the SDesktop, so that a reverse reference can be set up. @@ -91,10 +90,15 @@ namespace rfb { // signalling that a good time to render new data virtual void frameTick(uint64_t msc) { (void)msc; } - // InputHandler interface - // pointerEvent(), keyEvent() and clientCutText() are called in response to - // the relevant RFB protocol messages from clients. - // See InputHandler for method signatures. + // keyEvent() is called whenever a client sends an event that a + // key was pressed or released. + virtual void keyEvent(uint32_t /*keysym*/, uint32_t /*keycode*/, + bool /*down*/) {}; + + // pointerEvent() is called whenever a client sends an event that + // the pointer moved, or a button was pressed or released. + virtual void pointerEvent(const Point& /*pos*/, + uint8_t /*buttonMask*/) {}; // handleClipboardRequest() is called whenever a client requests // the server to send over its clipboard data. It will only be diff --git a/common/rfb/SMsgHandler.cxx b/common/rfb/SMsgHandler.cxx index 4ecfc2b2..03917926 100644 --- a/common/rfb/SMsgHandler.cxx +++ b/common/rfb/SMsgHandler.cxx @@ -74,6 +74,20 @@ void SMsgHandler::setEncodings(int nEncodings, const int32_t* encodings) supportsQEMUKeyEvent(); } +void SMsgHandler::keyEvent(uint32_t /*keysym*/, uint32_t /*keycode*/, + bool /*down*/) +{ +} + +void SMsgHandler::pointerEvent(const Point& /*pos*/, + uint8_t /*buttonMask*/) +{ +} + +void SMsgHandler::clientCutText(const char* /*str*/) +{ +} + void SMsgHandler::handleClipboardCaps(uint32_t flags, const uint32_t* lengths) { int i; diff --git a/common/rfb/SMsgHandler.h b/common/rfb/SMsgHandler.h index 20dc066f..cff8b1bd 100644 --- a/common/rfb/SMsgHandler.h +++ b/common/rfb/SMsgHandler.h @@ -27,14 +27,13 @@ #include <rfb/PixelFormat.h> #include <rfb/ClientParams.h> -#include <rfb/InputHandler.h> #include <rfb/ScreenSet.h> namespace rdr { class InStream; } namespace rfb { - class SMsgHandler : public InputHandler { + class SMsgHandler { public: SMsgHandler(); virtual ~SMsgHandler(); @@ -55,6 +54,13 @@ namespace rfb { virtual void enableContinuousUpdates(bool enable, int x, int y, int w, int h) = 0; + virtual void keyEvent(uint32_t keysym, uint32_t keycode, + bool down); + virtual void pointerEvent(const Point& pos, + uint8_t buttonMask); + + virtual void clientCutText(const char* str); + virtual void handleClipboardCaps(uint32_t flags, const uint32_t* lengths); virtual void handleClipboardRequest(uint32_t flags); @@ -64,9 +70,6 @@ namespace rfb { const size_t* lengths, const uint8_t* const* data); - // InputHandler interface - // The InputHandler methods will be called for the corresponding messages. - // supportsLocalCursor() is called whenever the status of // cp.supportsLocalCursor has changed. At the moment this happens on a // setEncodings message, but in the future this may be due to a message diff --git a/common/rfb/SSecurityPlain.cxx b/common/rfb/SSecurityPlain.cxx index 73a21335..e009de39 100644 --- a/common/rfb/SSecurityPlain.cxx +++ b/common/rfb/SSecurityPlain.cxx @@ -87,7 +87,7 @@ bool SSecurityPlain::processMsg() char password[1024]; if (!valid) - throw AuthFailureException("No password validator configured"); + throw Exception("No password validator configured"); if (state == 0) { if (!is->hasData(8)) @@ -114,7 +114,7 @@ bool SSecurityPlain::processMsg() username[ulen] = 0; plen = 0; if (!valid->validate(sc, username, password)) - throw AuthFailureException("invalid password or username"); + throw AuthFailureException("Authentication failed"); } return true; diff --git a/common/rfb/SSecurityRSAAES.cxx b/common/rfb/SSecurityRSAAES.cxx index 13e03b22..37860a10 100644 --- a/common/rfb/SSecurityRSAAES.cxx +++ b/common/rfb/SSecurityRSAAES.cxx @@ -155,18 +155,18 @@ void SSecurityRSAAES::loadPrivateKey() { FILE* file = fopen(keyFile, "rb"); if (!file) - throw ConnFailedException("failed to open key file"); + throw Exception("failed to open key file"); fseek(file, 0, SEEK_END); size_t size = ftell(file); if (size == 0 || size > MaxKeyFileSize) { fclose(file); - throw ConnFailedException("size of key file is zero or too big"); + throw Exception("size of key file is zero or too big"); } fseek(file, 0, SEEK_SET); std::vector<uint8_t> data(size); if (fread(data.data(), 1, data.size(), file) != size) { fclose(file); - throw ConnFailedException("failed to read key"); + throw Exception("failed to read key"); } fclose(file); @@ -183,7 +183,7 @@ void SSecurityRSAAES::loadPrivateKey() loadPKCS8Key(der.data(), der.size()); return; } - throw ConnFailedException("failed to import key"); + throw Exception("failed to import key"); } void SSecurityRSAAES::loadPKCS1Key(const uint8_t* data, size_t size) @@ -194,7 +194,7 @@ void SSecurityRSAAES::loadPKCS1Key(const uint8_t* data, size_t size) if (!rsa_keypair_from_der(&pub, &serverKey, 0, size, data)) { rsa_private_key_clear(&serverKey); rsa_public_key_clear(&pub); - throw ConnFailedException("failed to import key"); + throw Exception("failed to import key"); } serverKeyLength = serverKey.size * 8; serverKeyN = new uint8_t[serverKey.size]; @@ -234,7 +234,7 @@ void SSecurityRSAAES::loadPKCS8Key(const uint8_t* data, size_t size) loadPKCS1Key(i.data, i.length); return; failed: - throw ConnFailedException("failed to import key"); + throw Exception("failed to import key"); } bool SSecurityRSAAES::processMsg() @@ -561,11 +561,11 @@ void SSecurityRSAAES::verifyUserPass() #endif if (!valid->validate(sc, username, password)) { delete valid; - throw AuthFailureException("invalid password or username"); + throw AuthFailureException("Authentication failed"); } delete valid; #else - throw AuthFailureException("No password validator configured"); + throw Exception("No password validator configured"); #endif } @@ -576,7 +576,7 @@ void SSecurityRSAAES::verifyPass() pg->getVncAuthPasswd(&passwd, &passwdReadOnly); if (passwd.empty()) - throw AuthFailureException("No password configured for VNC Auth"); + throw Exception("No password configured"); if (password == passwd) { accessRights = AccessDefault; @@ -588,7 +588,7 @@ void SSecurityRSAAES::verifyPass() return; } - throw AuthFailureException(); + throw AuthFailureException("Authentication failed"); } const char* SSecurityRSAAES::getUserName() const diff --git a/common/rfb/SSecurityTLS.cxx b/common/rfb/SSecurityTLS.cxx index e2b82f89..67dced6c 100644 --- a/common/rfb/SSecurityTLS.cxx +++ b/common/rfb/SSecurityTLS.cxx @@ -34,6 +34,7 @@ #include <rfb/SConnection.h> #include <rfb/LogWriter.h> #include <rfb/Exception.h> +#include <rdr/TLSException.h> #include <rdr/TLSInStream.h> #include <rdr/TLSOutStream.h> #include <gnutls/x509.h> @@ -71,12 +72,15 @@ SSecurityTLS::SSecurityTLS(SConnection* sc_, bool _anon) cert_cred(nullptr), anon(_anon), tlsis(nullptr), tlsos(nullptr), rawis(nullptr), rawos(nullptr) { + int ret; + #if defined (SSECURITYTLS__USE_DEPRECATED_DH) dh_params = nullptr; #endif - if (gnutls_global_init() != GNUTLS_E_SUCCESS) - throw AuthFailureException("gnutls_global_init failed"); + ret = gnutls_global_init(); + if (ret != GNUTLS_E_SUCCESS) + throw rdr::TLSException("gnutls_global_init()", ret); } void SSecurityTLS::shutdown() @@ -138,17 +142,21 @@ SSecurityTLS::~SSecurityTLS() bool SSecurityTLS::processMsg() { + int err; + vlog.debug("Process security message (session %p)", session); if (!session) { rdr::InStream* is = sc->getInStream(); rdr::OutStream* os = sc->getOutStream(); - if (gnutls_init(&session, GNUTLS_SERVER) != GNUTLS_E_SUCCESS) - throw AuthFailureException("gnutls_init failed"); + err = gnutls_init(&session, GNUTLS_SERVER); + if (err != GNUTLS_E_SUCCESS) + throw rdr::TLSException("gnutls_init()", err); - if (gnutls_set_default_priority(session) != GNUTLS_E_SUCCESS) - throw AuthFailureException("gnutls_set_default_priority failed"); + err = gnutls_set_default_priority(session); + if (err != GNUTLS_E_SUCCESS) + throw rdr::TLSException("gnutls_set_default_priority()", err); try { setParams(); @@ -170,7 +178,6 @@ bool SSecurityTLS::processMsg() rawos = os; } - int err; err = gnutls_handshake(session); if (err != GNUTLS_E_SUCCESS) { if (!gnutls_error_is_fatal(err)) { @@ -179,7 +186,7 @@ bool SSecurityTLS::processMsg() } vlog.error("TLS Handshake failed: %s", gnutls_strerror (err)); shutdown(); - throw AuthFailureException("TLS Handshake failed"); + throw rdr::TLSException("TLS Handshake failed", err); } vlog.debug("TLS handshake completed with %s", @@ -204,7 +211,7 @@ void SSecurityTLS::setParams() prio = (char*)malloc(strlen(Security::GnuTLSPriority) + strlen(kx_anon_priority) + 1); if (prio == nullptr) - throw AuthFailureException("Not enough memory for GnuTLS priority string"); + throw Exception("Not enough memory for GnuTLS priority string"); strcpy(prio, Security::GnuTLSPriority); if (anon) @@ -217,7 +224,7 @@ void SSecurityTLS::setParams() if (ret != GNUTLS_E_SUCCESS) { if (ret == GNUTLS_E_INVALID_REQUEST) vlog.error("GnuTLS priority syntax error at: %s", err); - throw AuthFailureException("gnutls_set_priority_direct failed"); + throw rdr::TLSException("gnutls_set_priority_direct()", ret); } } else if (anon) { const char *err; @@ -229,7 +236,7 @@ void SSecurityTLS::setParams() if (ret != GNUTLS_E_SUCCESS) { if (ret == GNUTLS_E_INVALID_REQUEST) vlog.error("GnuTLS priority syntax error at: %s", err); - throw AuthFailureException("gnutls_set_default_priority_append failed"); + throw rdr::TLSException("gnutls_set_default_priority_append()", ret); } #else // We don't know what the system default priority is, so we guess @@ -240,7 +247,7 @@ void SSecurityTLS::setParams() prio = (char*)malloc(strlen(gnutls_default_priority) + strlen(kx_anon_priority) + 1); if (prio == nullptr) - throw AuthFailureException("Not enough memory for GnuTLS priority string"); + throw Exception("Not enough memory for GnuTLS priority string"); strcpy(prio, gnutls_default_priority); strcat(prio, kx_anon_priority); @@ -252,36 +259,41 @@ void SSecurityTLS::setParams() if (ret != GNUTLS_E_SUCCESS) { if (ret == GNUTLS_E_INVALID_REQUEST) vlog.error("GnuTLS priority syntax error at: %s", err); - throw AuthFailureException("gnutls_set_priority_direct failed"); + throw rdr::TLSException("gnutls_set_priority_direct()", ret); } #endif } #if defined (SSECURITYTLS__USE_DEPRECATED_DH) - if (gnutls_dh_params_init(&dh_params) != GNUTLS_E_SUCCESS) - throw AuthFailureException("gnutls_dh_params_init failed"); - - if (gnutls_dh_params_import_pkcs3(dh_params, &ffdhe_pkcs3_param, GNUTLS_X509_FMT_PEM) != GNUTLS_E_SUCCESS) - throw AuthFailureException("gnutls_dh_params_import_pkcs3 failed"); + ret = gnutls_dh_params_init(&dh_params); + if (ret != GNUTLS_E_SUCCESS) + throw rdr::TLSException("gnutls_dh_params_init()", ret); + + ret = gnutls_dh_params_import_pkcs3(dh_params, &ffdhe_pkcs3_param, + GNUTLS_X509_FMT_PEM); + if (ret != GNUTLS_E_SUCCESS) + throw rdr::TLSException("gnutls_dh_params_import_pkcs3()", ret); #endif if (anon) { - if (gnutls_anon_allocate_server_credentials(&anon_cred) != GNUTLS_E_SUCCESS) - throw AuthFailureException("gnutls_anon_allocate_server_credentials failed"); + ret = gnutls_anon_allocate_server_credentials(&anon_cred); + if (ret != GNUTLS_E_SUCCESS) + throw rdr::TLSException("gnutls_anon_allocate_server_credentials()", ret); #if defined (SSECURITYTLS__USE_DEPRECATED_DH) gnutls_anon_set_server_dh_params(anon_cred, dh_params); #endif - if (gnutls_credentials_set(session, GNUTLS_CRD_ANON, anon_cred) - != GNUTLS_E_SUCCESS) - throw AuthFailureException("gnutls_credentials_set failed"); + ret = gnutls_credentials_set(session, GNUTLS_CRD_ANON, anon_cred); + if (ret != GNUTLS_E_SUCCESS) + throw rdr::TLSException("gnutls_credentials_set()", ret); vlog.debug("Anonymous session has been set"); } else { - if (gnutls_certificate_allocate_credentials(&cert_cred) != GNUTLS_E_SUCCESS) - throw AuthFailureException("gnutls_certificate_allocate_credentials failed"); + ret = gnutls_certificate_allocate_credentials(&cert_cred); + if (ret != GNUTLS_E_SUCCESS) + throw rdr::TLSException("gnutls_certificate_allocate_credentials()", ret); #if defined (SSECURITYTLS__USE_DEPRECATED_DH) gnutls_certificate_set_dh_params(cert_cred, dh_params); @@ -291,16 +303,16 @@ void SSecurityTLS::setParams() case GNUTLS_E_SUCCESS: break; case GNUTLS_E_CERTIFICATE_KEY_MISMATCH: - throw AuthFailureException("Private key does not match certificate"); + throw Exception("Private key does not match certificate"); case GNUTLS_E_UNSUPPORTED_CERTIFICATE_TYPE: - throw AuthFailureException("Unsupported certificate type"); + throw Exception("Unsupported certificate type"); default: - throw AuthFailureException("Error loading X509 certificate or key"); + throw Exception("Error loading X509 certificate or key"); } - if (gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE, cert_cred) - != GNUTLS_E_SUCCESS) - throw AuthFailureException("gnutls_credentials_set failed"); + ret = gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE, cert_cred); + if (ret != GNUTLS_E_SUCCESS) + throw rdr::TLSException("gnutls_credentials_set()", ret); vlog.debug("X509 session has been set"); diff --git a/common/rfb/SSecurityVeNCrypt.cxx b/common/rfb/SSecurityVeNCrypt.cxx index ce160503..164ea927 100644 --- a/common/rfb/SSecurityVeNCrypt.cxx +++ b/common/rfb/SSecurityVeNCrypt.cxx @@ -33,8 +33,6 @@ #include <rdr/OutStream.h> using namespace rfb; -using namespace rdr; -using namespace std; static LogWriter vlog("SVeNCrypt"); @@ -101,8 +99,8 @@ bool SSecurityVeNCrypt::processMsg() case 0x0001: /* 0.1 Legacy VeNCrypt, not supported */ os->writeU8(0xFF); /* This is not OK */ os->flush(); - throw AuthFailureException("The client cannot support the server's " - "VeNCrypt version"); + throw Exception("The client cannot support the server's " + "VeNCrypt version"); case 0x0002: /* 0.2 */ os->writeU8(0); /* OK */ @@ -111,7 +109,7 @@ bool SSecurityVeNCrypt::processMsg() default: os->writeU8(0xFF); /* Not OK */ os->flush(); - throw AuthFailureException("The client returned an unsupported VeNCrypt version"); + throw Exception("The client returned an unsupported VeNCrypt version"); } } @@ -120,7 +118,7 @@ bool SSecurityVeNCrypt::processMsg() * followed by authentication types (uint32_t:s) */ if (!haveSentTypes) { - list<uint32_t> listSubTypes; + std::list<uint32_t> listSubTypes; listSubTypes = security->GetEnabledExtSecTypes(); @@ -140,7 +138,7 @@ bool SSecurityVeNCrypt::processMsg() os->flush(); haveSentTypes = true; } else - throw AuthFailureException("There are no VeNCrypt sub-types to send to the client"); + throw Exception("There are no VeNCrypt sub-types to send to the client"); } /* get type back from client (must be one of the ones we sent) */ @@ -165,7 +163,7 @@ bool SSecurityVeNCrypt::processMsg() /* Set up the stack according to the chosen type */ if (chosenType == secTypeInvalid || chosenType == secTypeVeNCrypt) - throw AuthFailureException("No valid VeNCrypt sub-type"); + throw Exception("No valid VeNCrypt sub-type"); ssecurity = security->GetSSecurity(sc, chosenType); } diff --git a/common/rfb/SSecurityVncAuth.cxx b/common/rfb/SSecurityVncAuth.cxx index 1276f68a..272c7ca1 100644 --- a/common/rfb/SSecurityVncAuth.cxx +++ b/common/rfb/SSecurityVncAuth.cxx @@ -100,7 +100,7 @@ bool SSecurityVncAuth::processMsg() pg->getVncAuthPasswd(&passwd, &passwdReadOnly); if (passwd.empty()) - throw AuthFailureException("No password configured for VNC Auth"); + throw Exception("No password configured"); if (verifyResponse(passwd.c_str())) { accessRights = AccessDefault; @@ -113,7 +113,7 @@ bool SSecurityVncAuth::processMsg() return true; } - throw AuthFailureException(); + throw AuthFailureException("Authentication failed"); } VncAuthPasswdParameter::VncAuthPasswdParameter(const char* name_, diff --git a/common/rfb/ScaleFilters.cxx b/common/rfb/ScaleFilters.cxx deleted file mode 100644 index 823dc740..00000000 --- a/common/rfb/ScaleFilters.cxx +++ /dev/null @@ -1,129 +0,0 @@ -/* Copyright (C) 2006 TightVNC Team. All Rights Reserved. - * - * 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 <string.h> -#include <assert.h> -#include <math.h> - -#include <rfb/Rect.h> -#include <rfb/ScaleFilters.h> - -using namespace rfb; - -// -// -=- 1-D filters functions -// - -// Nearest neighbor filter function -double nearest_neighbor(double x) { - if (x < -0.5) return 0.0; - if (x < 0.5) return 1.0; - return 0.0; -} - -// Linear filter function -double linear(double x) { - if (x < -1.0) return 0.0; - if (x < 0.0) return 1.0+x; - if (x < 1.0) return 1.0-x; - return 0.0; -} - -// Cubic filter functions -double cubic(double x) { - double t; - if (x < -2.0) return 0.0; - if (x < -1.0) {t = 2.0+x; return t*t*t/6.0;} - if (x < 0.0) return (4.0+x*x*(-6.0+x*-3.0))/6.0; - if (x < 1.0) return (4.0+x*x*(-6.0+x*3.0))/6.0; - if (x < 2.0) {t = 2.0-x; return t*t*t/6.0;} - return 0.0; -} - - -// -// -=- ScaleFilters class -// - -SFilter &ScaleFilters::operator[](unsigned int filter_id) { - assert(filter_id <= scaleFilterMaxNumber); - return filters[filter_id]; -} - -int ScaleFilters::getFilterIdByName(char *filterName) { - for (unsigned int i = 0; i <= scaleFilterMaxNumber; i++) { - if (strcasecmp(filters[i].name, filterName) == 0) return i; - } - return -1; -} - -void ScaleFilters::initFilters() { - filters[scaleFilterNearestNeighbor] = create("Nearest neighbor", 0.5, nearest_neighbor); - filters[scaleFilterBilinear] = create("Bilinear", 1, linear); - filters[scaleFilterBicubic] = create("Bicubic", 2, cubic); -} - -SFilter ScaleFilters::create(const char *name_, double radius_, filter_func func_) { - SFilter filter; - strncpy(filter.name, name_, sizeof(filter.name)-1); - filter.name[sizeof(filter.name)-1] = '\0'; - filter.radius = radius_; - filter.func = func_; - return filter; -} - -void ScaleFilters::makeWeightTabs(int filter_id, int src_x, int dst_x, SFilterWeightTab **pWeightTabs) { - double sxc; - double offset = 0.5; - double ratio = (double)dst_x / src_x; - double sourceScale = __rfbmax(1.0, 1.0/ratio); - double sourceRadius = __rfbmax(0.5, sourceScale * filters[filter_id].radius); - double sum, nc; - int i, ci; - - SFilter sFilter = filters[filter_id]; - - *pWeightTabs = new SFilterWeightTab[dst_x]; - SFilterWeightTab *weightTabs = *pWeightTabs; - - // Make the weight tab for the each dest x position - for (int x = 0; x < dst_x; x++) { - sxc = (double(x)+offset) / ratio; - - // Calculate the scale filter interval, [i0, i1) - int i0 = int(__rfbmax(sxc-sourceRadius+0.5, 0)); - int i1 = int(__rfbmin(sxc+sourceRadius+0.5, src_x)); - - weightTabs[x].i0 = i0; weightTabs[x].i1 = i1; - weightTabs[x].weight = new short[i1-i0]; - - // Calculate coeff to normalize the filter weights - for (sum = 0, i = i0; i < i1; i++) sum += sFilter.func((double(i)-sxc+0.5)/sourceScale); - if (sum == 0.) nc = (double)(WEIGHT_OF_ONE); else nc = (double)(WEIGHT_OF_ONE)/sum; - - - // Calculate the weight coeffs on the scale filter interval - for (ci = 0, i = i0; i < i1; i++) { - weightTabs[x].weight[ci++] = (short)floor((sFilter.func((double(i)-sxc+0.5)/sourceScale) * nc) + 0.5); - } - } -} diff --git a/common/rfb/ScaleFilters.h b/common/rfb/ScaleFilters.h deleted file mode 100644 index 23c87b64..00000000 --- a/common/rfb/ScaleFilters.h +++ /dev/null @@ -1,81 +0,0 @@ -/* Copyright (C) 2006 TightVNC Team. All Rights Reserved. - * - * 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. - */ - -// -=- ScaleFilters.h -// -// Definitions of the 1-D filters and routines using for the image scaling. -// -// - -namespace rfb { - - #define SCALE_ERROR (1e-7) - #define BITS_OF_CHANEL 8 - #define BITS_OF_WEIGHT 14 - #define FINALSHIFT (2 * BITS_OF_WEIGHT - BITS_OF_CHANEL) - #define WEIGHT_OF_ONE (1 << BITS_OF_WEIGHT) - - typedef double (*filter_func)(double x); - - const double pi = 3.14159265358979; - - const unsigned int scaleFilterNearestNeighbor = 0; - const unsigned int scaleFilterBilinear = 1; - const unsigned int scaleFilterBicubic = 2; - - const unsigned int scaleFilterMaxNumber = 2; - const unsigned int defaultScaleFilter = scaleFilterBilinear; - - // - // -=- Scale filters structures and routines - // - - // Scale filter stuct - typedef struct { - char name[30]; // Filter name - double radius; // Radius where filter function is nonzero - filter_func func; // Pointer to filter function - } SFilter; - - // Scale filter weight table - typedef struct { - short i0, i1; // Filter function interval, [i0..i1) - short *weight; // Weight coefficients on the filter function interval - } SFilterWeightTab; - - - // ScaleFilters class helps us using a set of 1-d scale filters. - class ScaleFilters { - public: - ScaleFilters() { initFilters(); }; - - SFilter &operator[](unsigned int filter_id); - - int getFilterIdByName(char *filterName); - - void makeWeightTabs(int filter, int src_x, int dst_x, SFilterWeightTab **weightTabs); - - protected: - void initFilters(); - - SFilter create(const char *name_, double radius_, filter_func func_); - - SFilter filters[scaleFilterMaxNumber+1]; - }; - -}; diff --git a/common/rfb/Security.cxx b/common/rfb/Security.cxx index 01191c65..3b0d95bf 100644 --- a/common/rfb/Security.cxx +++ b/common/rfb/Security.cxx @@ -30,7 +30,6 @@ #include <rfb/util.h> using namespace rfb; -using namespace std; static LogWriter vlog("Security"); @@ -51,7 +50,7 @@ Security::Security(StringParameter &secTypes) const std::list<uint8_t> Security::GetEnabledSecTypes(void) { - list<uint8_t> result; + std::list<uint8_t> result; /* Partial workaround for Vino's stupid behaviour. It doesn't allow * the basic authentication types as part of the VeNCrypt handshake, @@ -74,7 +73,7 @@ const std::list<uint8_t> Security::GetEnabledSecTypes(void) const std::list<uint32_t> Security::GetEnabledExtSecTypes(void) { - list<uint32_t> result; + std::list<uint32_t> result; for (uint32_t type : enabledSecTypes) if (type != secTypeVeNCrypt) /* Do not include VeNCrypt type to avoid loops */ diff --git a/common/rfb/SecurityClient.cxx b/common/rfb/SecurityClient.cxx index 63e0cadc..d1507eb5 100644 --- a/common/rfb/SecurityClient.cxx +++ b/common/rfb/SecurityClient.cxx @@ -27,7 +27,7 @@ #include <rfb/CSecurityVeNCrypt.h> #include <rfb/CSecurityVncAuth.h> #include <rfb/CSecurityPlain.h> -#include <rdr/Exception.h> +#include <rfb/Exception.h> #include <rfb/Security.h> #ifdef HAVE_GNUTLS #include <rfb/CSecurityTLS.h> @@ -38,7 +38,6 @@ #include <rfb/CSecurityMSLogonII.h> #endif -using namespace rdr; using namespace rfb; UserPasswdGetter *CSecurity::upg = nullptr; diff --git a/common/rfb/SecurityServer.cxx b/common/rfb/SecurityServer.cxx index 3e23a89d..b5297736 100644 --- a/common/rfb/SecurityServer.cxx +++ b/common/rfb/SecurityServer.cxx @@ -21,7 +21,7 @@ #include <config.h> #endif -#include <rdr/Exception.h> +#include <rfb/Exception.h> #include <rfb/Security.h> #include <rfb/SSecurityNone.h> #include <rfb/SSecurityStack.h> @@ -35,7 +35,6 @@ #include <rfb/SSecurityRSAAES.h> #endif -using namespace rdr; using namespace rfb; StringParameter SecurityServer::secTypes diff --git a/common/rfb/VNCSConnectionST.cxx b/common/rfb/VNCSConnectionST.cxx index a40a1a30..88deff8c 100644 --- a/common/rfb/VNCSConnectionST.cxx +++ b/common/rfb/VNCSConnectionST.cxx @@ -477,7 +477,7 @@ void VNCSConnectionST::setPixelFormat(const PixelFormat& pf) setCursor(); } -void VNCSConnectionST::pointerEvent(const Point& pos, int buttonMask) +void VNCSConnectionST::pointerEvent(const Point& pos, uint8_t buttonMask) { if (rfb::Server::idleTimeout) idleTimer.start(secsToMillis(rfb::Server::idleTimeout)); @@ -496,12 +496,12 @@ public: ~VNCSConnectionSTShiftPresser() { if (pressed) { vlog.debug("Releasing fake Shift_L"); - server->keyEvent(XK_Shift_L, 0, false); + server->keyEvent(XK_Shift_L, 0x2a, false); } } void press() { vlog.debug("Pressing fake Shift_L"); - server->keyEvent(XK_Shift_L, 0, true); + server->keyEvent(XK_Shift_L, 0x2a, true); pressed = true; } VNCServerST* server; @@ -550,8 +550,8 @@ void VNCSConnectionST::keyEvent(uint32_t keysym, uint32_t keycode, bool down) { if (lock == (uppercase == shift)) { vlog.debug("Inserting fake CapsLock to get in sync with client"); - server->keyEvent(XK_Caps_Lock, 0, true); - server->keyEvent(XK_Caps_Lock, 0, false); + server->keyEvent(XK_Caps_Lock, 0x3a, true); + server->keyEvent(XK_Caps_Lock, 0x3a, false); } } @@ -580,8 +580,8 @@ void VNCSConnectionST::keyEvent(uint32_t keysym, uint32_t keycode, bool down) { // } else if (lock == (number == shift)) { vlog.debug("Inserting fake NumLock to get in sync with client"); - server->keyEvent(XK_Num_Lock, 0, true); - server->keyEvent(XK_Num_Lock, 0, false); + server->keyEvent(XK_Num_Lock, 0x45, true); + server->keyEvent(XK_Num_Lock, 0x45, false); } } } @@ -706,8 +706,10 @@ void VNCSConnectionST::fence(uint32_t flags, unsigned len, const uint8_t data[]) return; } - if (len < 1) + if (len < 1) { vlog.error("Fence response of unexpected size received"); + return; + } type = data[0]; diff --git a/common/rfb/VNCSConnectionST.h b/common/rfb/VNCSConnectionST.h index e9badd72..d857ef32 100644 --- a/common/rfb/VNCSConnectionST.h +++ b/common/rfb/VNCSConnectionST.h @@ -123,7 +123,7 @@ namespace rfb { void queryConnection(const char* userName) override; void clientInit(bool shared) override; void setPixelFormat(const PixelFormat& pf) override; - void pointerEvent(const Point& pos, int buttonMask) override; + void pointerEvent(const Point& pos, uint8_t buttonMask) override; void keyEvent(uint32_t keysym, uint32_t keycode, bool down) override; void framebufferUpdateRequest(const Rect& r, diff --git a/common/rfb/VNCServerST.cxx b/common/rfb/VNCServerST.cxx index 705f7df2..114ff347 100644 --- a/common/rfb/VNCServerST.cxx +++ b/common/rfb/VNCServerST.cxx @@ -482,7 +482,7 @@ void VNCServerST::keyEvent(uint32_t keysym, uint32_t keycode, bool down) } void VNCServerST::pointerEvent(VNCSConnectionST* client, - const Point& pos, int buttonMask) + const Point& pos, uint8_t buttonMask) { time_t now = time(nullptr); if (rfb::Server::maxIdleTime) diff --git a/common/rfb/VNCServerST.h b/common/rfb/VNCServerST.h index 501882aa..6cc75a68 100644 --- a/common/rfb/VNCServerST.h +++ b/common/rfb/VNCServerST.h @@ -117,7 +117,7 @@ namespace rfb { // Event handlers void keyEvent(uint32_t keysym, uint32_t keycode, bool down); - void pointerEvent(VNCSConnectionST* client, const Point& pos, int buttonMask); + void pointerEvent(VNCSConnectionST* client, const Point& pos, uint8_t buttonMask); void handleClipboardRequest(VNCSConnectionST* client); void handleClipboardAnnounce(VNCSConnectionST* client, bool available); |