From 29197adf314128770e5671a6a38962b2f5190a82 Mon Sep 17 00:00:00 2001 From: Vlad Khorsun Date: Sun, 29 Sep 2024 23:33:14 +0300 Subject: [PATCH 1/2] If client fails to connect using Win_SSPI plugin with Negotiate security package, try again using NTLM security package. This allows new client connect to the old server that uses legacy NTLM security package. --- src/auth/trusted/AuthSspi.cpp | 12 ++- src/auth/trusted/AuthSspi.h | 4 + src/remote/client/interface.cpp | 155 ++++++++++++++++++-------------- 3 files changed, 105 insertions(+), 66 deletions(-) diff --git a/src/auth/trusted/AuthSspi.cpp b/src/auth/trusted/AuthSspi.cpp index 1af4f72762..515271b1ec 100644 --- a/src/auth/trusted/AuthSspi.cpp +++ b/src/auth/trusted/AuthSspi.cpp @@ -67,6 +67,15 @@ namespace namespace Auth { + +static thread_local bool legacySSP = false; + +void setLegacySSP(bool value) +{ + legacySSP = value; +} + + HINSTANCE AuthSspi::library = 0; bool AuthSspi::initEntries() @@ -109,7 +118,8 @@ AuthSspi::AuthSspi() groupNames(*getDefaultMemoryPool()), sessionKey(*getDefaultMemoryPool()) { TimeStamp timeOut; - hasCredentials = initEntries() && (fAcquireCredentialsHandle(0, NEGOSSP_NAME_A, + hasCredentials = initEntries() && (fAcquireCredentialsHandle(0, + legacySSP ? NTLMSP_NAME_A : NEGOSSP_NAME_A, SECPKG_CRED_BOTH, 0, 0, 0, 0, &secHndl, &timeOut) == SEC_E_OK); } diff --git a/src/auth/trusted/AuthSspi.h b/src/auth/trusted/AuthSspi.h index 92030bbb12..8988a0d6b5 100644 --- a/src/auth/trusted/AuthSspi.h +++ b/src/auth/trusted/AuthSspi.h @@ -145,6 +145,10 @@ private: void registerTrustedClient(Firebird::IPluginManager* iPlugin); void registerTrustedServer(Firebird::IPluginManager* iPlugin); +// Set per-thread flag that specify which security package should be used by +// newly created plugin instances: true - use NTLM, false - use Negotiate. +void setLegacySSP(bool value); + } // namespace Auth #endif // TRUSTED_AUTH diff --git a/src/remote/client/interface.cpp b/src/remote/client/interface.cpp index 22bd0f8ace..72efb3e9b2 100644 --- a/src/remote/client/interface.cpp +++ b/src/remote/client/interface.cpp @@ -7405,91 +7405,116 @@ static rem_port* analyze(ClntAuthBlock& cBlock, PathName& attach_name, unsigned cBlock.loadClnt(pb, &parSet); pb.deleteWithTag(parSet.auth_block); - authenticateStep0(cBlock); bool needFile = !(flags & ANALYZE_EMP_NAME); + const PathName save_attach_name(attach_name); + bool legacySSP = false; + Auth::setLegacySSP(legacySSP); + while (true) + { + authenticateStep0(cBlock); + + try + { #ifdef WIN_NT - if (ISC_analyze_protocol(PROTOCOL_XNET, attach_name, node_name, NULL, needFile)) - port = XNET_analyze(&cBlock, attach_name, flags & ANALYZE_USER_VFY, cBlock.getConfig(), ref_db_name); - else + if (ISC_analyze_protocol(PROTOCOL_XNET, attach_name, node_name, NULL, needFile)) + port = XNET_analyze(&cBlock, attach_name, flags & ANALYZE_USER_VFY, cBlock.getConfig(), ref_db_name); + else #endif - if (ISC_analyze_protocol(PROTOCOL_INET4, attach_name, node_name, INET_SEPARATOR, needFile)) - inet_af = AF_INET; - else if (ISC_analyze_protocol(PROTOCOL_INET6, attach_name, node_name, INET_SEPARATOR, needFile)) - inet_af = AF_INET6; + if (ISC_analyze_protocol(PROTOCOL_INET4, attach_name, node_name, INET_SEPARATOR, needFile)) + inet_af = AF_INET; + else if (ISC_analyze_protocol(PROTOCOL_INET6, attach_name, node_name, INET_SEPARATOR, needFile)) + inet_af = AF_INET6; - if (inet_af != AF_UNSPEC || - ISC_analyze_protocol(PROTOCOL_INET, attach_name, node_name, INET_SEPARATOR, needFile) || - ISC_analyze_tcp(attach_name, node_name, needFile)) - { - if (node_name.isEmpty()) - node_name = INET_LOCALHOST; - else - { - ISC_unescape(node_name); - ISC_utf8ToSystem(node_name); - } - - port = INET_analyze(&cBlock, attach_name, node_name.c_str(), flags & ANALYZE_USER_VFY, pb, - cBlock.getConfig(), ref_db_name, cryptCb, inet_af); - } - - // We have a local connection string. If it's a file on a network share, - // try to connect to the corresponding host remotely. - if (flags & ANALYZE_MOUNTS) - { -#ifdef WIN_NT - if (!port) - { - PathName expanded_name = attach_name; - if (ISC_analyze_pclan(expanded_name, node_name)) + if (inet_af != AF_UNSPEC || + ISC_analyze_protocol(PROTOCOL_INET, attach_name, node_name, INET_SEPARATOR, needFile) || + ISC_analyze_tcp(attach_name, node_name, needFile)) { - ISC_unescape(node_name); - ISC_utf8ToSystem(node_name); + if (node_name.isEmpty()) + node_name = INET_LOCALHOST; + else + { + ISC_unescape(node_name); + ISC_utf8ToSystem(node_name); + } - port = INET_analyze(&cBlock, expanded_name, node_name.c_str(), flags & ANALYZE_USER_VFY, pb, - cBlock.getConfig(), ref_db_name, cryptCb); + port = INET_analyze(&cBlock, attach_name, node_name.c_str(), flags & ANALYZE_USER_VFY, pb, + cBlock.getConfig(), ref_db_name, cryptCb, inet_af); } - } + + // We have a local connection string. If it's a file on a network share, + // try to connect to the corresponding host remotely. + if (flags & ANALYZE_MOUNTS) + { +#ifdef WIN_NT + if (!port) + { + PathName expanded_name = attach_name; + if (ISC_analyze_pclan(expanded_name, node_name)) + { + ISC_unescape(node_name); + ISC_utf8ToSystem(node_name); + + port = INET_analyze(&cBlock, expanded_name, node_name.c_str(), flags & ANALYZE_USER_VFY, pb, + cBlock.getConfig(), ref_db_name, cryptCb); + } + } #endif #ifndef NO_NFS - if (!port) - { - PathName expanded_name = attach_name; - if (ISC_analyze_nfs(expanded_name, node_name)) - { - ISC_unescape(node_name); - ISC_utf8ToSystem(node_name); + if (!port) + { + PathName expanded_name = attach_name; + if (ISC_analyze_nfs(expanded_name, node_name)) + { + ISC_unescape(node_name); + ISC_utf8ToSystem(node_name); - port = INET_analyze(&cBlock, expanded_name, node_name.c_str(), flags & ANALYZE_USER_VFY, pb, - cBlock.getConfig(), ref_db_name, cryptCb); - } - } + port = INET_analyze(&cBlock, expanded_name, node_name.c_str(), flags & ANALYZE_USER_VFY, pb, + cBlock.getConfig(), ref_db_name, cryptCb); + } + } #endif - } + } - if ((flags & ANALYZE_LOOPBACK) && !port) - { - // We have a local connection string. - // If we are in loopback mode attempt connect to a localhost. + if ((flags & ANALYZE_LOOPBACK) && !port) + { + // We have a local connection string. + // If we are in loopback mode attempt connect to a localhost. - if (node_name.isEmpty()) - { + if (node_name.isEmpty()) + { #ifdef WIN_NT - if (!port) - { - port = XNET_analyze(&cBlock, attach_name, flags & ANALYZE_USER_VFY, - cBlock.getConfig(), ref_db_name); - } + if (!port) + { + port = XNET_analyze(&cBlock, attach_name, flags & ANALYZE_USER_VFY, + cBlock.getConfig(), ref_db_name); + } #endif - if (!port) - { - port = INET_analyze(&cBlock, attach_name, INET_LOCALHOST, flags & ANALYZE_USER_VFY, pb, - cBlock.getConfig(), ref_db_name, cryptCb); + if (!port) + { + port = INET_analyze(&cBlock, attach_name, INET_LOCALHOST, flags & ANALYZE_USER_VFY, pb, + cBlock.getConfig(), ref_db_name, cryptCb); + } + } } + + break; + } + catch (const Exception&) + { + const char* const pluginName = cBlock.plugins.name(); + if (legacySSP || fb_utils::stricmp(pluginName, "WIN_SSPI") != 0) + throw; + + // Retry connect with failed plugin only and using legacy security package + legacySSP = true; + Auth::setLegacySSP(legacySSP); + attach_name = save_attach_name; + + cBlock.plugins.set(pluginName); } } From 3092eee7e323ae5a026a92455d0682fb6db0193d Mon Sep 17 00:00:00 2001 From: Vlad Khorsun Date: Mon, 30 Sep 2024 00:27:05 +0300 Subject: [PATCH 2/2] Fixed non-Windows builds --- src/remote/client/interface.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/remote/client/interface.cpp b/src/remote/client/interface.cpp index 72efb3e9b2..195de4bbf7 100644 --- a/src/remote/client/interface.cpp +++ b/src/remote/client/interface.cpp @@ -7408,8 +7408,11 @@ static rem_port* analyze(ClntAuthBlock& cBlock, PathName& attach_name, unsigned bool needFile = !(flags & ANALYZE_EMP_NAME); const PathName save_attach_name(attach_name); + +#ifdef TRUSTED_AUTH bool legacySSP = false; Auth::setLegacySSP(legacySSP); +#endif while (true) { @@ -7505,6 +7508,7 @@ static rem_port* analyze(ClntAuthBlock& cBlock, PathName& attach_name, unsigned } catch (const Exception&) { +#ifdef TRUSTED_AUTH const char* const pluginName = cBlock.plugins.name(); if (legacySSP || fb_utils::stricmp(pluginName, "WIN_SSPI") != 0) throw; @@ -7515,6 +7519,9 @@ static rem_port* analyze(ClntAuthBlock& cBlock, PathName& attach_name, unsigned attach_name = save_attach_name; cBlock.plugins.set(pluginName); +#else + throw; +#endif } }