8
0
mirror of https://github.com/FirebirdSQL/firebird.git synced 2025-01-22 17:23:03 +01:00

Merge pull request #8274 from FirebirdSQL/work/win_sspi_reconnect

If client fails to connect using Win_SSPI plugin with Negotiate security package, try again using NTLM security package.
This commit is contained in:
Vlad Khorsun 2024-09-30 22:40:41 +03:00 committed by GitHub
commit f62f1336e2
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 112 additions and 66 deletions

View File

@ -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);
}

View File

@ -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

View File

@ -7405,91 +7405,123 @@ 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);
#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
#ifdef TRUSTED_AUTH
bool legacySSP = false;
Auth::setLegacySSP(legacySSP);
#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 (inet_af != AF_UNSPEC ||
ISC_analyze_protocol(PROTOCOL_INET, attach_name, node_name, INET_SEPARATOR, needFile) ||
ISC_analyze_tcp(attach_name, node_name, needFile))
while (true)
{
if (node_name.isEmpty())
node_name = INET_LOCALHOST;
else
authenticateStep0(cBlock);
try
{
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))
{
ISC_unescape(node_name);
ISC_utf8ToSystem(node_name);
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
port = INET_analyze(&cBlock, expanded_name, node_name.c_str(), flags & ANALYZE_USER_VFY, pb,
cBlock.getConfig(), ref_db_name, cryptCb);
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))
{
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&)
{
#ifdef TRUSTED_AUTH
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);
#else
throw;
#endif
}
}