mirror of
https://github.com/FirebirdSQL/firebird.git
synced 2025-01-24 20:43:04 +01:00
Merge pull request #255 from FirebirdSQL/SrpPerf3
Backported CORE-6237: Fixed performance issue with SRP plugin (added connections cache)
This commit is contained in:
commit
9e1109cbd8
@ -52,9 +52,14 @@ YValve_Objects:= $(call dirObjects,yvalve) $(call dirObjects,yvalve/config)
|
|||||||
AllObjects += $(YValve_Objects)
|
AllObjects += $(YValve_Objects)
|
||||||
|
|
||||||
|
|
||||||
|
# Authentication database connections cache
|
||||||
|
SecDbCache:= $(call makeObjects,auth,SecDbCache.cpp)
|
||||||
|
|
||||||
|
|
||||||
# Remote
|
# Remote
|
||||||
Remote_Common:= $(call dirObjects,remote) $(call dirObjects,auth/SecureRemotePassword)
|
Remote_Common:= $(call dirObjects,remote) $(call dirObjects,auth/SecureRemotePassword)
|
||||||
Remote_Server:= $(call dirObjects,remote/server) $(call dirObjects,auth/SecureRemotePassword/server)
|
Remote_Server:= $(call dirObjects,remote/server) $(call dirObjects,auth/SecureRemotePassword/server) \
|
||||||
|
$(SecDbCache)
|
||||||
Remote_Client:= $(call dirObjects,remote/client) $(call dirObjects,auth/SecureRemotePassword/client) \
|
Remote_Client:= $(call dirObjects,remote/client) $(call dirObjects,auth/SecureRemotePassword/client) \
|
||||||
$(call makeObjects,auth/SecurityDatabase,LegacyClient.cpp) \
|
$(call makeObjects,auth/SecurityDatabase,LegacyClient.cpp) \
|
||||||
$(call dirObjects,plugins/crypt/arc4)
|
$(call dirObjects,plugins/crypt/arc4)
|
||||||
@ -171,7 +176,7 @@ AllObjects += $(LEGACY_USERS_MANAGE_Objects)
|
|||||||
|
|
||||||
|
|
||||||
# Legacy authentication on server
|
# Legacy authentication on server
|
||||||
LEGACY_AUTH_SERVER_Objects:= $(call makeObjects,auth/SecurityDatabase,LegacyServer.cpp)
|
LEGACY_AUTH_SERVER_Objects:= $(call makeObjects,auth/SecurityDatabase,LegacyServer.cpp) $(SecDbCache)
|
||||||
|
|
||||||
AllObjects += $(LEGACY_AUTH_SERVER_Objects)
|
AllObjects += $(LEGACY_AUTH_SERVER_Objects)
|
||||||
|
|
||||||
|
@ -207,6 +207,7 @@
|
|||||||
</Link>
|
</Link>
|
||||||
</ItemDefinitionGroup>
|
</ItemDefinitionGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<ClCompile Include="..\..\..\src\auth\SecDbCache.cpp" />
|
||||||
<ClCompile Include="..\..\..\src\auth\SecureRemotePassword\server\SrpServer.cpp" />
|
<ClCompile Include="..\..\..\src\auth\SecureRemotePassword\server\SrpServer.cpp" />
|
||||||
<ClCompile Include="..\..\..\src\remote\server\os\win32\chop.cpp" />
|
<ClCompile Include="..\..\..\src\remote\server\os\win32\chop.cpp" />
|
||||||
<ClCompile Include="..\..\..\src\remote\server\os\win32\cntl.cpp" />
|
<ClCompile Include="..\..\..\src\remote\server\os\win32\cntl.cpp" />
|
||||||
|
@ -34,6 +34,9 @@
|
|||||||
<ClCompile Include="..\..\..\src\auth\SecureRemotePassword\server\SrpServer.cpp">
|
<ClCompile Include="..\..\..\src\auth\SecureRemotePassword\server\SrpServer.cpp">
|
||||||
<Filter>AUTH files</Filter>
|
<Filter>AUTH files</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\..\src\auth\SecDbCache.cpp">
|
||||||
|
<Filter>AUTH files</Filter>
|
||||||
|
</ClCompile>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<None Include="..\..\..\src\remote\server\os\win32\server.ico">
|
<None Include="..\..\..\src\remote\server\os\win32\server.ico">
|
||||||
|
@ -180,6 +180,7 @@
|
|||||||
</ProjectReference>
|
</ProjectReference>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<ClCompile Include="..\..\..\src\auth\SecDbCache.cpp" />
|
||||||
<ClCompile Include="..\..\..\src\auth\SecurityDatabase\LegacyServer.cpp" />
|
<ClCompile Include="..\..\..\src\auth\SecurityDatabase\LegacyServer.cpp" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||||
|
@ -20,5 +20,8 @@
|
|||||||
<ClCompile Include="..\..\..\src\auth\SecurityDatabase\LegacyServer.cpp">
|
<ClCompile Include="..\..\..\src\auth\SecurityDatabase\LegacyServer.cpp">
|
||||||
<Filter>AUTH files</Filter>
|
<Filter>AUTH files</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\..\src\auth\SecDbCache.cpp">
|
||||||
|
<Filter>AUTH files</Filter>
|
||||||
|
</ClCompile>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
@ -211,6 +211,7 @@
|
|||||||
</Link>
|
</Link>
|
||||||
</ItemDefinitionGroup>
|
</ItemDefinitionGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<ClCompile Include="..\..\..\src\auth\SecDbCache.cpp" />
|
||||||
<ClCompile Include="..\..\..\src\auth\SecureRemotePassword\server\SrpServer.cpp" />
|
<ClCompile Include="..\..\..\src\auth\SecureRemotePassword\server\SrpServer.cpp" />
|
||||||
<ClCompile Include="..\..\..\src\remote\server\os\win32\chop.cpp" />
|
<ClCompile Include="..\..\..\src\remote\server\os\win32\chop.cpp" />
|
||||||
<ClCompile Include="..\..\..\src\remote\server\os\win32\cntl.cpp" />
|
<ClCompile Include="..\..\..\src\remote\server\os\win32\cntl.cpp" />
|
||||||
|
@ -34,6 +34,9 @@
|
|||||||
<ClCompile Include="..\..\..\src\auth\SecureRemotePassword\server\SrpServer.cpp">
|
<ClCompile Include="..\..\..\src\auth\SecureRemotePassword\server\SrpServer.cpp">
|
||||||
<Filter>AUTH files</Filter>
|
<Filter>AUTH files</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\..\src\auth\SecDbCache.cpp">
|
||||||
|
<Filter>AUTH files</Filter>
|
||||||
|
</ClCompile>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<None Include="..\..\..\src\remote\server\os\win32\server.ico">
|
<None Include="..\..\..\src\remote\server\os\win32\server.ico">
|
||||||
|
@ -188,6 +188,7 @@
|
|||||||
</ProjectReference>
|
</ProjectReference>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<ClCompile Include="..\..\..\src\auth\SecDbCache.cpp" />
|
||||||
<ClCompile Include="..\..\..\src\auth\SecurityDatabase\LegacyServer.cpp" />
|
<ClCompile Include="..\..\..\src\auth\SecurityDatabase\LegacyServer.cpp" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||||
|
@ -20,5 +20,8 @@
|
|||||||
<ClCompile Include="..\..\..\src\auth\SecurityDatabase\LegacyServer.cpp">
|
<ClCompile Include="..\..\..\src\auth\SecurityDatabase\LegacyServer.cpp">
|
||||||
<Filter>AUTH files</Filter>
|
<Filter>AUTH files</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\..\src\auth\SecDbCache.cpp">
|
||||||
|
<Filter>AUTH files</Filter>
|
||||||
|
</ClCompile>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
@ -211,6 +211,7 @@
|
|||||||
</Link>
|
</Link>
|
||||||
</ItemDefinitionGroup>
|
</ItemDefinitionGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<ClCompile Include="..\..\..\src\auth\SecDbCache.cpp" />
|
||||||
<ClCompile Include="..\..\..\src\auth\SecureRemotePassword\server\SrpServer.cpp" />
|
<ClCompile Include="..\..\..\src\auth\SecureRemotePassword\server\SrpServer.cpp" />
|
||||||
<ClCompile Include="..\..\..\src\remote\server\os\win32\chop.cpp" />
|
<ClCompile Include="..\..\..\src\remote\server\os\win32\chop.cpp" />
|
||||||
<ClCompile Include="..\..\..\src\remote\server\os\win32\cntl.cpp" />
|
<ClCompile Include="..\..\..\src\remote\server\os\win32\cntl.cpp" />
|
||||||
|
@ -34,6 +34,9 @@
|
|||||||
<ClCompile Include="..\..\..\src\auth\SecureRemotePassword\server\SrpServer.cpp">
|
<ClCompile Include="..\..\..\src\auth\SecureRemotePassword\server\SrpServer.cpp">
|
||||||
<Filter>AUTH files</Filter>
|
<Filter>AUTH files</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\..\src\auth\SecDbCache.cpp">
|
||||||
|
<Filter>AUTH files</Filter>
|
||||||
|
</ClCompile>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<None Include="..\..\..\src\remote\server\os\win32\server.ico">
|
<None Include="..\..\..\src\remote\server\os\win32\server.ico">
|
||||||
|
@ -188,6 +188,7 @@
|
|||||||
</ProjectReference>
|
</ProjectReference>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<ClCompile Include="..\..\..\src\auth\SecDbCache.cpp" />
|
||||||
<ClCompile Include="..\..\..\src\auth\SecurityDatabase\LegacyServer.cpp" />
|
<ClCompile Include="..\..\..\src\auth\SecurityDatabase\LegacyServer.cpp" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||||
|
@ -20,5 +20,8 @@
|
|||||||
<ClCompile Include="..\..\..\src\auth\SecurityDatabase\LegacyServer.cpp">
|
<ClCompile Include="..\..\..\src\auth\SecurityDatabase\LegacyServer.cpp">
|
||||||
<Filter>AUTH files</Filter>
|
<Filter>AUTH files</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\..\src\auth\SecDbCache.cpp">
|
||||||
|
<Filter>AUTH files</Filter>
|
||||||
|
</ClCompile>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
158
src/auth/SecDbCache.cpp
Normal file
158
src/auth/SecDbCache.cpp
Normal file
@ -0,0 +1,158 @@
|
|||||||
|
/*
|
||||||
|
* PROGRAM: JRD Access Method
|
||||||
|
* MODULE: SecDbCache.cpp
|
||||||
|
* DESCRIPTION: Cached security database connection
|
||||||
|
*
|
||||||
|
* The contents of this file are subject to the Interbase Public
|
||||||
|
* License Version 1.0 (the "License"); you may not use this file
|
||||||
|
* except in compliance with the License. You may obtain a copy
|
||||||
|
* of the License at http://www.Inprise.com/IPL.html
|
||||||
|
*
|
||||||
|
* Software distributed under the License is distributed on an
|
||||||
|
* "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express
|
||||||
|
* or implied. See the License for the specific language governing
|
||||||
|
* rights and limitations under the License.
|
||||||
|
*
|
||||||
|
* The Original Code was created by Inprise Corporation
|
||||||
|
* and its predecessors. Portions created by Inprise Corporation are
|
||||||
|
* Copyright (C) Inprise Corporation.
|
||||||
|
*
|
||||||
|
* All Rights Reserved.
|
||||||
|
* Contributor(s): ______________________________________.
|
||||||
|
*
|
||||||
|
* 2003.02.02 Dmitry Yemanov: Implemented cached security database connection
|
||||||
|
* 2011 - 2020 Alexander Peshkov
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "firebird.h"
|
||||||
|
|
||||||
|
#include "../auth/SecDbCache.h"
|
||||||
|
#include "../jrd/status.h"
|
||||||
|
#include "../common/isc_proto.h"
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
|
||||||
|
using namespace Firebird;
|
||||||
|
|
||||||
|
namespace Auth {
|
||||||
|
|
||||||
|
void CachedSecurityDatabase::close()
|
||||||
|
{
|
||||||
|
Jrd::FbLocalStatus s;
|
||||||
|
TimerInterfacePtr()->start(&s, this, 10 * 1000 * 1000);
|
||||||
|
if (s->getState() & IStatus::STATE_ERRORS)
|
||||||
|
handler();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CachedSecurityDatabase::handler()
|
||||||
|
{
|
||||||
|
list->handler(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void PluginDatabases::getInstance(IPluginConfig* pluginConfig, RefPtr<CachedSecurityDatabase>& instance)
|
||||||
|
{
|
||||||
|
// Determine sec.db name based on existing config
|
||||||
|
PathName secDbName;
|
||||||
|
{ // config scope
|
||||||
|
Jrd::FbLocalStatus s;
|
||||||
|
RefPtr<IFirebirdConf> config(REF_NO_INCR, pluginConfig->getFirebirdConf(&s));
|
||||||
|
check(&s);
|
||||||
|
|
||||||
|
const unsigned int INIT_KEY = ((~0) - 1);
|
||||||
|
static unsigned int secDbKey = INIT_KEY;
|
||||||
|
if (secDbKey == INIT_KEY)
|
||||||
|
secDbKey = config->getKey("SecurityDatabase");
|
||||||
|
|
||||||
|
const char* tmp = config->asString(secDbKey);
|
||||||
|
if (!tmp)
|
||||||
|
Arg::Gds(isc_secdb_name).raise();
|
||||||
|
|
||||||
|
secDbName = tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
{ // guard scope
|
||||||
|
MutexLockGuard g(arrayMutex, FB_FUNCTION);
|
||||||
|
for (unsigned int i = 0; i < dbArray.getCount(); ++i)
|
||||||
|
{
|
||||||
|
if (secDbName == dbArray[i]->secureDbName)
|
||||||
|
{
|
||||||
|
instance = dbArray[i];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!instance)
|
||||||
|
{
|
||||||
|
instance = FB_NEW CachedSecurityDatabase(this, secDbName);
|
||||||
|
instance->addRef();
|
||||||
|
secDbName.copyTo(instance->secureDbName, sizeof(instance->secureDbName));
|
||||||
|
dbArray.add(instance);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int PluginDatabases::shutdown()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
MutexLockGuard g(arrayMutex, FB_FUNCTION);
|
||||||
|
for (unsigned int i = 0; i < dbArray.getCount(); ++i)
|
||||||
|
{
|
||||||
|
if (dbArray[i])
|
||||||
|
{
|
||||||
|
Jrd::FbLocalStatus s;
|
||||||
|
TimerInterfacePtr()->stop(&s, dbArray[i]);
|
||||||
|
check(&s);
|
||||||
|
dbArray[i]->release();
|
||||||
|
dbArray[i] = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
dbArray.clear();
|
||||||
|
}
|
||||||
|
catch (Exception &ex)
|
||||||
|
{
|
||||||
|
StaticStatusVector st;
|
||||||
|
ex.stuffException(st);
|
||||||
|
const ISC_STATUS* status = st.begin();
|
||||||
|
if (status[0] == 1 && status[1] != isc_att_shutdown)
|
||||||
|
{
|
||||||
|
iscLogStatus("Legacy security database shutdown", status);
|
||||||
|
}
|
||||||
|
|
||||||
|
return FB_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return FB_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PluginDatabases::handler(CachedSecurityDatabase* tgt)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
MutexLockGuard g(arrayMutex, FB_FUNCTION);
|
||||||
|
|
||||||
|
for (unsigned int i = 0; i < dbArray.getCount(); ++i)
|
||||||
|
{
|
||||||
|
if (dbArray[i] == tgt)
|
||||||
|
{
|
||||||
|
dbArray.remove(i);
|
||||||
|
tgt->release();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception &ex)
|
||||||
|
{
|
||||||
|
StaticStatusVector st;
|
||||||
|
ex.stuffException(st);
|
||||||
|
const ISC_STATUS* status = st.begin();
|
||||||
|
if (status[0] == 1 && status[1] != isc_att_shutdown)
|
||||||
|
{
|
||||||
|
iscLogStatus("Legacy security database timer handler", status);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Auth
|
109
src/auth/SecDbCache.h
Normal file
109
src/auth/SecDbCache.h
Normal file
@ -0,0 +1,109 @@
|
|||||||
|
/*
|
||||||
|
* PROGRAM: JRD Access Method
|
||||||
|
* MODULE: SecDbCache.h
|
||||||
|
* DESCRIPTION: Cached security database connection
|
||||||
|
*
|
||||||
|
* The contents of this file are subject to the Interbase Public
|
||||||
|
* License Version 1.0 (the "License"); you may not use this file
|
||||||
|
* except in compliance with the License. You may obtain a copy
|
||||||
|
* of the License at http://www.Inprise.com/IPL.html
|
||||||
|
*
|
||||||
|
* Software distributed under the License is distributed on an
|
||||||
|
* "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express
|
||||||
|
* or implied. See the License for the specific language governing
|
||||||
|
* rights and limitations under the License.
|
||||||
|
*
|
||||||
|
* The Original Code was created by Inprise Corporation
|
||||||
|
* and its predecessors. Portions created by Inprise Corporation are
|
||||||
|
* Copyright (C) Inprise Corporation.
|
||||||
|
*
|
||||||
|
* All Rights Reserved.
|
||||||
|
* Contributor(s): ______________________________________.
|
||||||
|
*
|
||||||
|
* 2003.02.02 Dmitry Yemanov: Implemented cached security database connection
|
||||||
|
* 2011 - 2020 Alexander Peshkov
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef FB_SECDBCACHE_H
|
||||||
|
#define FB_SECDBCACHE_H
|
||||||
|
|
||||||
|
#include "firebird/Interface.h"
|
||||||
|
#include "../common/classes/ImplementHelper.h"
|
||||||
|
#include "../common/classes/fb_string.h"
|
||||||
|
#include "../common/classes/array.h"
|
||||||
|
#include "../common/classes/alloc.h"
|
||||||
|
#include "../common/classes/auto.h"
|
||||||
|
|
||||||
|
|
||||||
|
namespace Auth {
|
||||||
|
|
||||||
|
class VSecDb
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
VSecDb()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual ~VSecDb()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual bool lookup(void* inMsg, void* outMsg) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class PluginDatabases;
|
||||||
|
|
||||||
|
class CachedSecurityDatabase FB_FINAL
|
||||||
|
: public Firebird::RefCntIface<Firebird::ITimerImpl<CachedSecurityDatabase, Firebird::CheckStatusWrapper> >
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
char secureDbName[MAXPATHLEN + 1];
|
||||||
|
|
||||||
|
CachedSecurityDatabase(PluginDatabases* l, const Firebird::PathName& nm)
|
||||||
|
: secDb(NULL), list(l)
|
||||||
|
{
|
||||||
|
nm.copyTo(secureDbName, sizeof secureDbName);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ITimer implementation
|
||||||
|
void handler();
|
||||||
|
|
||||||
|
int release()
|
||||||
|
{
|
||||||
|
if (--refCounter == 0)
|
||||||
|
{
|
||||||
|
delete this;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void close();
|
||||||
|
|
||||||
|
Firebird::Mutex mutex;
|
||||||
|
Firebird::AutoPtr<VSecDb> secDb;
|
||||||
|
PluginDatabases* list;
|
||||||
|
};
|
||||||
|
|
||||||
|
class PluginDatabases
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
PluginDatabases(MemoryPool& p)
|
||||||
|
: dbArray(p)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
private:
|
||||||
|
Firebird::HalfStaticArray<CachedSecurityDatabase*, 4> dbArray;
|
||||||
|
Firebird::Mutex arrayMutex;
|
||||||
|
|
||||||
|
public:
|
||||||
|
void getInstance(Firebird::IPluginConfig* pluginConfig, Firebird::RefPtr<CachedSecurityDatabase>& instance);
|
||||||
|
int shutdown();
|
||||||
|
void handler(CachedSecurityDatabase* tgt);
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Auth
|
||||||
|
|
||||||
|
#endif // FB_SECDBCACHE_H
|
@ -25,28 +25,51 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "firebird.h"
|
#include "firebird.h"
|
||||||
|
#include "firebird/Message.h"
|
||||||
|
|
||||||
#include "../auth/SecureRemotePassword/client/SrpClient.h"
|
#include "../auth/SecureRemotePassword/server/SrpServer.h"
|
||||||
#include "../auth/SecureRemotePassword/srp.h"
|
#include "../auth/SecureRemotePassword/srp.h"
|
||||||
#include "../common/classes/ImplementHelper.h"
|
#include "../common/classes/ImplementHelper.h"
|
||||||
#include "../common/classes/ClumpletWriter.h"
|
#include "../common/classes/ClumpletWriter.h"
|
||||||
#include "../auth/SecureRemotePassword/Message.h"
|
#include "../jrd/status.h"
|
||||||
|
#include "../common/isc_proto.h"
|
||||||
|
|
||||||
#include "../jrd/constants.h"
|
#include "../jrd/constants.h"
|
||||||
|
#include "../auth/SecDbCache.h"
|
||||||
|
|
||||||
using namespace Firebird;
|
using namespace Firebird;
|
||||||
|
using namespace Auth;
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
|
GlobalPtr<PluginDatabases> instances;
|
||||||
|
|
||||||
const unsigned int INIT_KEY = ((~0) - 1);
|
const unsigned int INIT_KEY = ((~0) - 1);
|
||||||
unsigned int secDbKey = INIT_KEY;
|
unsigned int secDbKey = INIT_KEY;
|
||||||
|
|
||||||
const unsigned int SZ_LOGIN = 31;
|
const unsigned int SZ_LOGIN = 31;
|
||||||
|
|
||||||
}
|
struct Metadata
|
||||||
|
{
|
||||||
|
Jrd::FbLocalStatus status;
|
||||||
|
FB_MESSAGE (Param, CheckStatusWrapper,
|
||||||
|
(FB_VARCHAR(SZ_LOGIN), login)
|
||||||
|
) param;
|
||||||
|
FB_MESSAGE (Data, CheckStatusWrapper,
|
||||||
|
(FB_VARCHAR(128), verifier)
|
||||||
|
(FB_VARCHAR(32), salt)
|
||||||
|
) data;
|
||||||
|
|
||||||
|
Metadata()
|
||||||
|
: param(&status, MasterInterfacePtr()), data(&status, MasterInterfacePtr())
|
||||||
|
{ }
|
||||||
|
|
||||||
namespace Auth {
|
Metadata(MemoryPool& p)
|
||||||
|
: status(p), param(&status, MasterInterfacePtr()), data(&status, MasterInterfacePtr())
|
||||||
|
{ }
|
||||||
|
};
|
||||||
|
|
||||||
|
InitInstance<Metadata> meta;
|
||||||
|
|
||||||
class SrpServer : public StdPlugin<IServerImpl<SrpServer, CheckStatusWrapper> >
|
class SrpServer : public StdPlugin<IServerImpl<SrpServer, CheckStatusWrapper> >
|
||||||
{
|
{
|
||||||
@ -55,13 +78,8 @@ public:
|
|||||||
: server(NULL), data(getPool()), account(getPool()),
|
: server(NULL), data(getPool()), account(getPool()),
|
||||||
clientPubKey(getPool()), serverPubKey(getPool()),
|
clientPubKey(getPool()), serverPubKey(getPool()),
|
||||||
verifier(getPool()), salt(getPool()), sessionKey(getPool()),
|
verifier(getPool()), salt(getPool()), sessionKey(getPool()),
|
||||||
secDbName(NULL), cryptCallback(NULL)
|
iParameter(par), secDbName(getPool()), cryptCallback(NULL)
|
||||||
{
|
{ }
|
||||||
LocalStatus ls;
|
|
||||||
CheckStatusWrapper s(&ls);
|
|
||||||
config.assignRefNoIncr(par->getFirebirdConf(&s));
|
|
||||||
check(&s);
|
|
||||||
}
|
|
||||||
|
|
||||||
// IServer implementation
|
// IServer implementation
|
||||||
int authenticate(CheckStatusWrapper* status, IServerBlock* sBlock, IWriter* writerInterface);
|
int authenticate(CheckStatusWrapper* status, IServerBlock* sBlock, IWriter* writerInterface);
|
||||||
@ -81,13 +99,105 @@ private:
|
|||||||
UCharBuffer verifier;
|
UCharBuffer verifier;
|
||||||
string salt;
|
string salt;
|
||||||
UCharBuffer sessionKey;
|
UCharBuffer sessionKey;
|
||||||
RefPtr<IFirebirdConf> config;
|
RefPtr<IPluginConfig> iParameter;
|
||||||
const char* secDbName;
|
PathName secDbName;
|
||||||
ICryptKeyCallback* cryptCallback;
|
ICryptKeyCallback* cryptCallback;
|
||||||
protected:
|
protected:
|
||||||
virtual RemotePassword* RemotePasswordFactory()=0;
|
virtual RemotePassword* RemotePasswordFactory()=0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class SecurityDatabase : public VSecDb
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
bool lookup(void* inMsg, void* outMsg)
|
||||||
|
{
|
||||||
|
Jrd::FbLocalStatus status;
|
||||||
|
|
||||||
|
stmt->execute(&status, tra, meta().param.getMetadata(), inMsg,
|
||||||
|
meta().data.getMetadata(), outMsg);
|
||||||
|
check(&status);
|
||||||
|
|
||||||
|
return false; // safe default
|
||||||
|
}
|
||||||
|
|
||||||
|
// This 2 are needed to satisfy temporarily different calling requirements
|
||||||
|
static int shutdown(const int, const int, void*)
|
||||||
|
{
|
||||||
|
return instances->shutdown();
|
||||||
|
}
|
||||||
|
static void cleanup()
|
||||||
|
{
|
||||||
|
instances->shutdown();
|
||||||
|
}
|
||||||
|
|
||||||
|
SecurityDatabase(const char* secDbName, ICryptKeyCallback* cryptCallback)
|
||||||
|
: att(NULL), tra(NULL), stmt(NULL)
|
||||||
|
{
|
||||||
|
Jrd::FbLocalStatus status;
|
||||||
|
|
||||||
|
DispatcherPtr p;
|
||||||
|
if (cryptCallback)
|
||||||
|
{
|
||||||
|
p->setDbCryptCallback(&status, cryptCallback);
|
||||||
|
status->init(); // ignore possible errors like missing call in provider
|
||||||
|
}
|
||||||
|
|
||||||
|
ClumpletWriter dpb(ClumpletReader::dpbList, MAX_DPB_SIZE);
|
||||||
|
dpb.insertByte(isc_dpb_sec_attach, TRUE);
|
||||||
|
dpb.insertString(isc_dpb_user_name, SYSDBA_USER_NAME, fb_strlen(SYSDBA_USER_NAME));
|
||||||
|
dpb.insertString(isc_dpb_config, ParsedList::getNonLoopbackProviders(secDbName));
|
||||||
|
att = p->attachDatabase(&status, secDbName, dpb.getBufferLength(), dpb.getBuffer());
|
||||||
|
check(&status);
|
||||||
|
HANDSHAKE_DEBUG(fprintf(stderr, "Srv SRP: attached sec db %s\n", secDbName));
|
||||||
|
|
||||||
|
const UCHAR tpb[] =
|
||||||
|
{
|
||||||
|
isc_tpb_version1,
|
||||||
|
isc_tpb_read,
|
||||||
|
isc_tpb_read_committed,
|
||||||
|
isc_tpb_rec_version,
|
||||||
|
isc_tpb_wait
|
||||||
|
};
|
||||||
|
tra = att->startTransaction(&status, sizeof(tpb), tpb);
|
||||||
|
check(&status);
|
||||||
|
HANDSHAKE_DEBUG(fprintf(stderr, "Srv: SRP1: started transaction\n"));
|
||||||
|
|
||||||
|
const char* sql =
|
||||||
|
"SELECT PLG$VERIFIER, PLG$SALT FROM PLG$SRP WHERE PLG$USER_NAME = ? AND PLG$ACTIVE";
|
||||||
|
stmt = att->prepare(&status, tra, 0, sql, 3, IStatement::PREPARE_PREFETCH_METADATA);
|
||||||
|
if (status->getState() & IStatus::STATE_ERRORS)
|
||||||
|
{
|
||||||
|
checkStatusVectorForMissingTable(status->getErrors());
|
||||||
|
status_exception::raise(&status);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
IAttachment* att;
|
||||||
|
ITransaction* tra;
|
||||||
|
IStatement* stmt;
|
||||||
|
|
||||||
|
~SecurityDatabase()
|
||||||
|
{
|
||||||
|
Jrd::FbLocalStatus status;
|
||||||
|
|
||||||
|
stmt->free(&status);
|
||||||
|
checkLogStatus(status);
|
||||||
|
|
||||||
|
tra->rollback(&status);
|
||||||
|
checkLogStatus(status);
|
||||||
|
|
||||||
|
att->detach(&status);
|
||||||
|
checkLogStatus(status);
|
||||||
|
}
|
||||||
|
|
||||||
|
void checkLogStatus(Jrd::FbLocalStatus& status)
|
||||||
|
{
|
||||||
|
if (!status.isSuccess())
|
||||||
|
iscLogStatus("Srp Server", &status);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
template <class SHA> class SrpServerImpl FB_FINAL : public SrpServer
|
template <class SHA> class SrpServerImpl FB_FINAL : public SrpServer
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@ -100,6 +210,7 @@ protected:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
int SrpServer::authenticate(CheckStatusWrapper* status, IServerBlock* sb, IWriter* writerInterface)
|
int SrpServer::authenticate(CheckStatusWrapper* status, IServerBlock* sb, IWriter* writerInterface)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
@ -126,110 +237,46 @@ int SrpServer::authenticate(CheckStatusWrapper* status, IServerBlock* sb, IWrite
|
|||||||
return AUTH_MORE_DATA;
|
return AUTH_MORE_DATA;
|
||||||
}
|
}
|
||||||
|
|
||||||
// read salt and verifier from database
|
// load verifier and salt from security database
|
||||||
// obviously we need something like attachments cache here
|
Metadata messages;
|
||||||
if (secDbKey == INIT_KEY)
|
messages.param->login.set(account.c_str());
|
||||||
{
|
messages.param->loginNull = 0;
|
||||||
secDbKey = config->getKey("SecurityDatabase");
|
messages.data.clear();
|
||||||
}
|
|
||||||
|
|
||||||
secDbName = config->asString(secDbKey);
|
{ // reference & mutex scope scope
|
||||||
if (!(secDbName && secDbName[0]))
|
// Get database block from cache
|
||||||
{
|
RefPtr<CachedSecurityDatabase> instance;
|
||||||
Arg::Gds(isc_secdb_name).raise();
|
instances->getInstance(iParameter, instance);
|
||||||
}
|
|
||||||
|
|
||||||
DispatcherPtr p;
|
|
||||||
IAttachment* att = NULL;
|
|
||||||
ITransaction* tra = NULL;
|
|
||||||
IStatement* stmt = NULL;
|
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (cryptCallback)
|
MutexLockGuard g(instance->mutex, FB_FUNCTION);
|
||||||
{
|
|
||||||
p->setDbCryptCallback(status, cryptCallback);
|
|
||||||
status->init(); // ignore possible errors like missing call in provider
|
|
||||||
}
|
|
||||||
|
|
||||||
ClumpletWriter dpb(ClumpletReader::dpbList, MAX_DPB_SIZE);
|
secDbName = instance->secureDbName;
|
||||||
dpb.insertByte(isc_dpb_sec_attach, TRUE);
|
if (!instance->secDb)
|
||||||
dpb.insertString(isc_dpb_user_name, SYSDBA_USER_NAME, fb_strlen(SYSDBA_USER_NAME));
|
instance->secDb = FB_NEW SecurityDatabase(instance->secureDbName, cryptCallback);
|
||||||
dpb.insertString(isc_dpb_config, Auth::ParsedList::getNonLoopbackProviders(secDbName));
|
|
||||||
|
|
||||||
att = p->attachDatabase(status, secDbName, dpb.getBufferLength(), dpb.getBuffer());
|
instance->secDb->lookup(messages.param.getData(), messages.data.getData());
|
||||||
check(status);
|
|
||||||
HANDSHAKE_DEBUG(fprintf(stderr, "Srv SRP: attached sec db %s\n", secDbName));
|
|
||||||
|
|
||||||
const UCHAR tpb[] =
|
|
||||||
{
|
|
||||||
isc_tpb_version1,
|
|
||||||
isc_tpb_read,
|
|
||||||
isc_tpb_read_committed,
|
|
||||||
isc_tpb_rec_version,
|
|
||||||
isc_tpb_wait
|
|
||||||
};
|
|
||||||
tra = att->startTransaction(status, sizeof(tpb), tpb);
|
|
||||||
check(status);
|
|
||||||
HANDSHAKE_DEBUG(fprintf(stderr, "Srv: SRP1: started transaction\n"));
|
|
||||||
|
|
||||||
const char* sql =
|
|
||||||
"SELECT PLG$VERIFIER, PLG$SALT FROM PLG$SRP WHERE PLG$USER_NAME = ? AND PLG$ACTIVE";
|
|
||||||
stmt = att->prepare(status, tra, 0, sql, 3, IStatement::PREPARE_PREFETCH_METADATA);
|
|
||||||
if (status->getState() & IStatus::STATE_ERRORS)
|
|
||||||
{
|
|
||||||
checkStatusVectorForMissingTable(status->getErrors());
|
|
||||||
status_exception::raise(status);
|
|
||||||
}
|
|
||||||
|
|
||||||
Meta im(stmt, false);
|
|
||||||
Message par(im);
|
|
||||||
Field<Varying> login(par);
|
|
||||||
login = account.c_str();
|
|
||||||
|
|
||||||
Meta om(stmt, true);
|
|
||||||
Message dat(om);
|
|
||||||
check(status);
|
|
||||||
Field<Varying> verify(dat);
|
|
||||||
Field<Varying> slt(dat);
|
|
||||||
HANDSHAKE_DEBUG(fprintf(stderr, "Srv: SRP1: Ready to run statement with login '%s'\n", account.c_str()));
|
|
||||||
|
|
||||||
stmt->execute(status, tra, par.getMetadata(), par.getBuffer(),
|
|
||||||
dat.getMetadata(), dat.getBuffer());
|
|
||||||
check(status);
|
|
||||||
HANDSHAKE_DEBUG(fprintf(stderr, "Srv: SRP1: Executed statement\n"));
|
|
||||||
|
|
||||||
verifier.assign(reinterpret_cast<const UCHAR*>(verify->data), verify->len);
|
|
||||||
dumpIt("Srv: verifier", verifier);
|
|
||||||
UCharBuffer s;
|
|
||||||
s.assign(reinterpret_cast<const UCHAR*>(slt->data), slt->len);
|
|
||||||
BigInteger(s).getText(salt);
|
|
||||||
dumpIt("Srv: salt", salt);
|
|
||||||
|
|
||||||
stmt->free(status);
|
|
||||||
check(status);
|
|
||||||
stmt = NULL;
|
|
||||||
|
|
||||||
tra->rollback(status);
|
|
||||||
check(status);
|
|
||||||
tra = NULL;
|
|
||||||
|
|
||||||
att->detach(status);
|
|
||||||
check(status);
|
|
||||||
att = NULL;
|
|
||||||
}
|
}
|
||||||
catch(const Exception&)
|
catch(const Exception&)
|
||||||
{
|
{
|
||||||
LocalStatus ls;
|
instance->close();
|
||||||
CheckStatusWrapper s(&ls);
|
|
||||||
|
|
||||||
if (stmt) stmt->free(&s);
|
|
||||||
if (tra) tra->rollback(&s);
|
|
||||||
if (att) att->detach(&s);
|
|
||||||
|
|
||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
instance->close();
|
||||||
|
}
|
||||||
|
HANDSHAKE_DEBUG(fprintf(stderr, "Srv: SRP1: Executed statement\n"));
|
||||||
|
|
||||||
|
verifier.assign(reinterpret_cast<const UCHAR*>(messages.data->verifier.str), messages.data->verifier.length);
|
||||||
|
dumpIt("Srv: verifier", verifier);
|
||||||
|
|
||||||
|
UCharBuffer s;
|
||||||
|
s.assign(reinterpret_cast<const UCHAR*>(messages.data->salt.str), messages.data->salt.length);
|
||||||
|
BigInteger(s).getText(salt);
|
||||||
|
dumpIt("Srv: salt", salt);
|
||||||
|
|
||||||
|
// create SRP-calculating server
|
||||||
server = RemotePasswordFactory();
|
server = RemotePasswordFactory();
|
||||||
server->genServerKey(serverPubKey, verifier);
|
server->genServerKey(serverPubKey, verifier);
|
||||||
|
|
||||||
@ -274,7 +321,7 @@ int SrpServer::authenticate(CheckStatusWrapper* status, IServerBlock* sb, IWrite
|
|||||||
{
|
{
|
||||||
return AUTH_FAILED;
|
return AUTH_FAILED;
|
||||||
}
|
}
|
||||||
writerInterface->setDb(status, secDbName);
|
writerInterface->setDb(status, secDbName.c_str());
|
||||||
if (status->getState() & IStatus::STATE_ERRORS)
|
if (status->getState() & IStatus::STATE_ERRORS)
|
||||||
{
|
{
|
||||||
return AUTH_FAILED;
|
return AUTH_FAILED;
|
||||||
@ -327,14 +374,16 @@ int SrpServer::release()
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace
|
|
||||||
{
|
|
||||||
SimpleFactory<SrpServerImpl<Sha1> > factory_sha1;
|
SimpleFactory<SrpServerImpl<Sha1> > factory_sha1;
|
||||||
SimpleFactory<SrpServerImpl<sha224> > factory_sha224;
|
SimpleFactory<SrpServerImpl<sha224> > factory_sha224;
|
||||||
SimpleFactory<SrpServerImpl<sha256> > factory_sha256;
|
SimpleFactory<SrpServerImpl<sha256> > factory_sha256;
|
||||||
SimpleFactory<SrpServerImpl<sha384> > factory_sha384;
|
SimpleFactory<SrpServerImpl<sha384> > factory_sha384;
|
||||||
SimpleFactory<SrpServerImpl<sha512> > factory_sha512;
|
SimpleFactory<SrpServerImpl<sha512> > factory_sha512;
|
||||||
}
|
|
||||||
|
} // anonymous namespace
|
||||||
|
|
||||||
|
|
||||||
|
namespace Auth {
|
||||||
|
|
||||||
void registerSrpServer(IPluginManager* iPlugin)
|
void registerSrpServer(IPluginManager* iPlugin)
|
||||||
{
|
{
|
||||||
|
@ -24,25 +24,22 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "firebird.h"
|
#include "firebird.h"
|
||||||
#include <string.h>
|
|
||||||
#include <stdlib.h>
|
#include "ibase.h"
|
||||||
#include <time.h>
|
#include "gen/iberror.h"
|
||||||
#include "../jrd/ibase.h"
|
|
||||||
#include "../auth/SecurityDatabase/LegacyServer.h"
|
|
||||||
#include "../auth/SecurityDatabase/LegacyHash.h"
|
|
||||||
#include "../common/enc_proto.h"
|
|
||||||
#include "../jrd/err_proto.h"
|
|
||||||
#include "../yvalve/gds_proto.h"
|
|
||||||
#include "../common/isc_proto.h"
|
|
||||||
#include "../jrd/jrd_proto.h"
|
|
||||||
#include "../jrd/scl.h"
|
|
||||||
#include "../common/config/config.h"
|
|
||||||
#include "../common/classes/objects_array.h"
|
|
||||||
#include "../common/classes/init.h"
|
|
||||||
#include "../common/classes/ImplementHelper.h"
|
|
||||||
#include "firebird/Interface.h"
|
#include "firebird/Interface.h"
|
||||||
|
|
||||||
|
#include "../auth/SecurityDatabase/LegacyServer.h"
|
||||||
|
#include "../auth/SecurityDatabase/LegacyHash.h"
|
||||||
|
#include "../auth/SecDbCache.h"
|
||||||
#include "../remote/remot_proto.h"
|
#include "../remote/remot_proto.h"
|
||||||
|
#include "../jrd/constants.h"
|
||||||
|
#include "../common/enc_proto.h"
|
||||||
|
#include "../jrd/status.h"
|
||||||
|
#include "../common/classes/init.h"
|
||||||
|
#include "../common/classes/ClumpletWriter.h"
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
#define PLUG_MODULE 1
|
#define PLUG_MODULE 1
|
||||||
|
|
||||||
@ -109,6 +106,8 @@ struct user_record
|
|||||||
SCHAR password[Auth::MAX_LEGACY_PASSWORD_LENGTH + 2];
|
SCHAR password[Auth::MAX_LEGACY_PASSWORD_LENGTH + 2];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
typedef char user_name[129];
|
||||||
|
|
||||||
// Transaction parameter buffer
|
// Transaction parameter buffer
|
||||||
|
|
||||||
const UCHAR TPB[4] =
|
const UCHAR TPB[4] =
|
||||||
@ -123,65 +122,50 @@ const UCHAR TPB[4] =
|
|||||||
|
|
||||||
namespace Auth {
|
namespace Auth {
|
||||||
|
|
||||||
|
GlobalPtr<PluginDatabases> instances;
|
||||||
|
|
||||||
|
|
||||||
class SecurityDatabaseServer FB_FINAL :
|
class SecurityDatabaseServer FB_FINAL :
|
||||||
public StdPlugin<IServerImpl<SecurityDatabaseServer, CheckStatusWrapper> >
|
public StdPlugin<IServerImpl<SecurityDatabaseServer, CheckStatusWrapper> >
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
explicit SecurityDatabaseServer(Firebird::IPluginConfig* p)
|
explicit SecurityDatabaseServer(IPluginConfig* p)
|
||||||
: iParameter(p)
|
: iParameter(p)
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
// IServer implementation
|
// IServer implementation
|
||||||
int authenticate(Firebird::CheckStatusWrapper* status, Firebird::IServerBlock* sBlock,
|
int authenticate(CheckStatusWrapper* status, IServerBlock* sBlock,
|
||||||
Firebird::IWriter* writerInterface);
|
IWriter* writerInterface);
|
||||||
void setDbCryptCallback(Firebird::CheckStatusWrapper*, Firebird::ICryptKeyCallback*) { } // ignore
|
void setDbCryptCallback(CheckStatusWrapper*, ICryptKeyCallback*) { } // ignore
|
||||||
int release();
|
int release();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Firebird::RefPtr<Firebird::IPluginConfig> iParameter;
|
RefPtr<IPluginConfig> iParameter;
|
||||||
};
|
};
|
||||||
|
|
||||||
class SecurityDatabase FB_FINAL : public RefCntIface<ITimerImpl<SecurityDatabase, CheckStatusWrapper> >
|
|
||||||
|
class SecurityDatabase : public VSecDb
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
int verify(IWriter* authBlock, IServerBlock* sBlock);
|
bool lookup(void* inMsg, void* outMsg);
|
||||||
|
|
||||||
// This 2 are needed to satisfy temporarily different calling requirements
|
// This 2 are needed to satisfy temporarily different calling requirements
|
||||||
static int shutdown(const int, const int, void*)
|
static int shutdown(const int, const int, void*)
|
||||||
{
|
{
|
||||||
return shutdown();
|
return instances->shutdown();
|
||||||
}
|
}
|
||||||
static void cleanup()
|
static void cleanup()
|
||||||
{
|
{
|
||||||
shutdown();
|
instances->shutdown();
|
||||||
}
|
}
|
||||||
|
|
||||||
static int shutdown();
|
SecurityDatabase(const char* secDbName)
|
||||||
|
|
||||||
char secureDbName[MAXPATHLEN];
|
|
||||||
|
|
||||||
SecurityDatabase()
|
|
||||||
: lookup_db(0), lookup_req(0)
|
: lookup_db(0), lookup_req(0)
|
||||||
{
|
{
|
||||||
}
|
prepare(secDbName);
|
||||||
|
|
||||||
// ITimer implementation
|
|
||||||
void handler();
|
|
||||||
|
|
||||||
int release()
|
|
||||||
{
|
|
||||||
if (--refCounter == 0)
|
|
||||||
{
|
|
||||||
delete this;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Firebird::Mutex mutex;
|
|
||||||
|
|
||||||
ISC_STATUS_ARRAY status;
|
ISC_STATUS_ARRAY status;
|
||||||
|
|
||||||
isc_db_handle lookup_db;
|
isc_db_handle lookup_db;
|
||||||
@ -189,8 +173,7 @@ private:
|
|||||||
|
|
||||||
~SecurityDatabase();
|
~SecurityDatabase();
|
||||||
|
|
||||||
bool lookup_user(const char*, char*);
|
void prepare(const char* secDbName);
|
||||||
void prepare();
|
|
||||||
void checkStatus(const char* callName, ISC_STATUS userError = isc_psw_db_error);
|
void checkStatus(const char* callName, ISC_STATUS userError = isc_psw_db_error);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -219,60 +202,8 @@ SecurityDatabase::~SecurityDatabase()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SecurityDatabase::lookup_user(const char* user_name, char* pwd)
|
|
||||||
{
|
|
||||||
bool found = false; // user found flag
|
|
||||||
char uname[129]; // user name buffer
|
|
||||||
user_record user; // user record
|
|
||||||
|
|
||||||
// Start by clearing the output data
|
void SecurityDatabase::prepare(const char* secureDbName)
|
||||||
|
|
||||||
if (pwd)
|
|
||||||
*pwd = '\0';
|
|
||||||
|
|
||||||
strncpy(uname, user_name, sizeof uname);
|
|
||||||
uname[sizeof uname - 1] = 0;
|
|
||||||
|
|
||||||
MutexLockGuard guard(mutex, FB_FUNCTION);
|
|
||||||
|
|
||||||
// Attach database and compile request
|
|
||||||
|
|
||||||
prepare();
|
|
||||||
|
|
||||||
// Lookup
|
|
||||||
|
|
||||||
isc_tr_handle lookup_trans = 0;
|
|
||||||
|
|
||||||
isc_start_transaction(status, &lookup_trans, 1, &lookup_db, sizeof(TPB), TPB);
|
|
||||||
checkStatus("isc_start_transaction", isc_psw_start_trans);
|
|
||||||
|
|
||||||
isc_start_and_send(status, &lookup_req, &lookup_trans, 0, sizeof(uname), uname, 0);
|
|
||||||
checkStatus("isc_start_and_send");
|
|
||||||
|
|
||||||
while (true)
|
|
||||||
{
|
|
||||||
isc_receive(status, &lookup_req, 1, sizeof(user), &user, 0);
|
|
||||||
checkStatus("isc_receive");
|
|
||||||
|
|
||||||
if (!user.flag || status[1])
|
|
||||||
break;
|
|
||||||
|
|
||||||
found = true;
|
|
||||||
|
|
||||||
if (pwd)
|
|
||||||
{
|
|
||||||
strncpy(pwd, user.password, MAX_LEGACY_PASSWORD_LENGTH);
|
|
||||||
pwd[MAX_LEGACY_PASSWORD_LENGTH] = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
isc_rollback_transaction(status, &lookup_trans);
|
|
||||||
checkStatus("isc_rollback_transaction");
|
|
||||||
|
|
||||||
return found;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SecurityDatabase::prepare()
|
|
||||||
{
|
{
|
||||||
if (lookup_db)
|
if (lookup_db)
|
||||||
{
|
{
|
||||||
@ -295,7 +226,7 @@ void SecurityDatabase::prepare()
|
|||||||
dpb.insertString(isc_dpb_trusted_auth, SYSDBA_USER_NAME, fb_strlen(SYSDBA_USER_NAME));
|
dpb.insertString(isc_dpb_trusted_auth, SYSDBA_USER_NAME, fb_strlen(SYSDBA_USER_NAME));
|
||||||
|
|
||||||
// Do not use loopback provider
|
// Do not use loopback provider
|
||||||
dpb.insertString(isc_dpb_config, Auth::ParsedList::getNonLoopbackProviders(secureDbName));
|
dpb.insertString(isc_dpb_config, ParsedList::getNonLoopbackProviders(secureDbName));
|
||||||
|
|
||||||
isc_db_handle tempHandle = 0;
|
isc_db_handle tempHandle = 0;
|
||||||
isc_attach_database(status, 0, secureDbName, &tempHandle,
|
isc_attach_database(status, 0, secureDbName, &tempHandle,
|
||||||
@ -315,74 +246,6 @@ void SecurityDatabase::prepare()
|
|||||||
checkStatus("isc_compile_request", isc_psw_attach);
|
checkStatus("isc_compile_request", isc_psw_attach);
|
||||||
}
|
}
|
||||||
|
|
||||||
/******************************************************************************
|
|
||||||
*
|
|
||||||
* Public interface
|
|
||||||
*/
|
|
||||||
|
|
||||||
int SecurityDatabase::verify(IWriter* authBlock, IServerBlock* sBlock)
|
|
||||||
{
|
|
||||||
const char* user = sBlock->getLogin();
|
|
||||||
string login(user ? user : "");
|
|
||||||
|
|
||||||
unsigned length;
|
|
||||||
const unsigned char* data = sBlock->getData(&length);
|
|
||||||
string passwordEnc;
|
|
||||||
if (data)
|
|
||||||
{
|
|
||||||
passwordEnc.assign(data, length);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!login.hasData())
|
|
||||||
{
|
|
||||||
return IAuth::AUTH_CONTINUE;
|
|
||||||
}
|
|
||||||
if (!passwordEnc.hasData())
|
|
||||||
{
|
|
||||||
return IAuth::AUTH_MORE_DATA;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Look up the user name in the userinfo database and use the parameters
|
|
||||||
// found there. This means that another database must be accessed, and
|
|
||||||
// that means the current context must be saved and restored.
|
|
||||||
|
|
||||||
char pw1[MAX_LEGACY_PASSWORD_LENGTH + 1];
|
|
||||||
if (!lookup_user(login.c_str(), pw1))
|
|
||||||
{
|
|
||||||
return IAuth::AUTH_CONTINUE;
|
|
||||||
}
|
|
||||||
pw1[MAX_LEGACY_PASSWORD_LENGTH] = 0;
|
|
||||||
string storedHash(pw1, MAX_LEGACY_PASSWORD_LENGTH);
|
|
||||||
storedHash.rtrim();
|
|
||||||
|
|
||||||
string newHash;
|
|
||||||
LegacyHash::hash(newHash, login, passwordEnc, storedHash);
|
|
||||||
if (newHash != storedHash)
|
|
||||||
{
|
|
||||||
bool legacyHash = Config::getLegacyHash();
|
|
||||||
if (legacyHash)
|
|
||||||
{
|
|
||||||
newHash.resize(MAX_LEGACY_PASSWORD_LENGTH + 2);
|
|
||||||
ENC_crypt(newHash.begin(), newHash.length(), passwordEnc.c_str(), LEGACY_PASSWORD_SALT);
|
|
||||||
newHash.recalculate_length();
|
|
||||||
newHash.erase(0, 2);
|
|
||||||
legacyHash = newHash == storedHash;
|
|
||||||
}
|
|
||||||
if (!legacyHash)
|
|
||||||
{
|
|
||||||
return IAuth::AUTH_CONTINUE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
LocalStatus ls;
|
|
||||||
CheckStatusWrapper s(&ls);
|
|
||||||
authBlock->add(&s, login.c_str());
|
|
||||||
check(&s);
|
|
||||||
authBlock->setDb(&s, secureDbName);
|
|
||||||
check(&s);
|
|
||||||
return IAuth::AUTH_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SecurityDatabase::checkStatus(const char* callName, ISC_STATUS userError)
|
void SecurityDatabase::checkStatus(const char* callName, ISC_STATUS userError)
|
||||||
{
|
{
|
||||||
if (status[1] == 0)
|
if (status[1] == 0)
|
||||||
@ -402,143 +265,136 @@ void SecurityDatabase::checkStatus(const char* callName, ISC_STATUS userError)
|
|||||||
secDbError.raise();
|
secDbError.raise();
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef HalfStaticArray<SecurityDatabase*, 4> InstancesArray;
|
bool SecurityDatabase::lookup(void* inMsg, void* outMsg)
|
||||||
GlobalPtr<InstancesArray> instances;
|
{
|
||||||
GlobalPtr<Mutex> instancesMutex;
|
isc_tr_handle lookup_trans = 0;
|
||||||
|
|
||||||
void SecurityDatabase::handler()
|
isc_start_transaction(status, &lookup_trans, 1, &lookup_db, sizeof(TPB), TPB);
|
||||||
{
|
checkStatus("isc_start_transaction", isc_psw_start_trans);
|
||||||
try
|
|
||||||
{
|
|
||||||
MutexLockGuard g(instancesMutex, FB_FUNCTION);
|
|
||||||
|
|
||||||
InstancesArray& curInstances(instances);
|
isc_start_and_send(status, &lookup_req, &lookup_trans, 0, sizeof(user_name), inMsg, 0);
|
||||||
for (unsigned int i = 0; i < curInstances.getCount(); ++i)
|
checkStatus("isc_start_and_send");
|
||||||
|
|
||||||
|
bool found = false;
|
||||||
|
while (true)
|
||||||
{
|
{
|
||||||
if (curInstances[i] == this)
|
user_record* user = static_cast<user_record*>(outMsg);
|
||||||
{
|
isc_receive(status, &lookup_req, 1, sizeof(user_record), user, 0);
|
||||||
curInstances.remove(i);
|
checkStatus("isc_receive");
|
||||||
release();
|
|
||||||
|
if (!user->flag || status[1])
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
}
|
found = true;
|
||||||
}
|
|
||||||
catch (Exception &ex)
|
|
||||||
{
|
|
||||||
StaticStatusVector st;
|
|
||||||
ex.stuffException(st);
|
|
||||||
const ISC_STATUS* status = st.begin();
|
|
||||||
if (status[0] == 1 && status[1] != isc_att_shutdown)
|
|
||||||
{
|
|
||||||
iscLogStatus("Legacy security database timer handler", status);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int SecurityDatabase::shutdown()
|
isc_rollback_transaction(status, &lookup_trans);
|
||||||
{
|
checkStatus("isc_rollback_transaction");
|
||||||
try
|
|
||||||
{
|
return found;
|
||||||
MutexLockGuard g(instancesMutex, FB_FUNCTION);
|
|
||||||
InstancesArray& curInstances(instances);
|
|
||||||
for (unsigned int i = 0; i < curInstances.getCount(); ++i)
|
|
||||||
{
|
|
||||||
if (curInstances[i])
|
|
||||||
{
|
|
||||||
LocalStatus ls;
|
|
||||||
CheckStatusWrapper s(&ls);
|
|
||||||
TimerInterfacePtr()->stop(&s, curInstances[i]);
|
|
||||||
check(&s);
|
|
||||||
curInstances[i]->release();
|
|
||||||
curInstances[i] = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
curInstances.clear();
|
|
||||||
}
|
|
||||||
catch (Exception &ex)
|
|
||||||
{
|
|
||||||
StaticStatusVector st;
|
|
||||||
ex.stuffException(st);
|
|
||||||
const ISC_STATUS* status = st.begin();
|
|
||||||
if (status[0] == 1 && status[1] != isc_att_shutdown)
|
|
||||||
{
|
|
||||||
iscLogStatus("Legacy security database shutdown", status);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return FB_FAILURE;
|
|
||||||
}
|
|
||||||
|
|
||||||
return FB_SUCCESS;
|
/******************************************************************************
|
||||||
}
|
*
|
||||||
|
* Public interface
|
||||||
|
*/
|
||||||
|
|
||||||
const static unsigned int INIT_KEY = ((~0) - 1);
|
int SecurityDatabaseServer::authenticate(CheckStatusWrapper* status, IServerBlock* sBlock,
|
||||||
static unsigned int secDbKey = INIT_KEY;
|
IWriter* authBlock)
|
||||||
|
|
||||||
int SecurityDatabaseServer::authenticate(Firebird::CheckStatusWrapper* status, IServerBlock* sBlock,
|
|
||||||
IWriter* writerInterface)
|
|
||||||
{
|
{
|
||||||
status->init();
|
status->init();
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
PathName secDbName;
|
const char* user = sBlock->getLogin();
|
||||||
{ // config scope
|
if (!user)
|
||||||
LocalStatus ls;
|
{
|
||||||
CheckStatusWrapper s(&ls);
|
HANDSHAKE_DEBUG(fprintf(stderr, "LegacyServer (nologin) %d\n", IAuth::AUTH_CONTINUE));
|
||||||
RefPtr<IFirebirdConf> config(REF_NO_INCR, iParameter->getFirebirdConf(&s));
|
return IAuth::AUTH_CONTINUE;
|
||||||
|
}
|
||||||
|
string login(user);
|
||||||
|
|
||||||
|
unsigned length;
|
||||||
|
const unsigned char* data = sBlock->getData(&length);
|
||||||
|
if (!(data && length))
|
||||||
|
{
|
||||||
|
HANDSHAKE_DEBUG(fprintf(stderr, "LegacyServer (nopw) %d\n", IAuth::AUTH_MORE_DATA));
|
||||||
|
return IAuth::AUTH_MORE_DATA;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool found = false;
|
||||||
|
char pw1[MAX_LEGACY_PASSWORD_LENGTH + 1];
|
||||||
|
PathName secureDbName;
|
||||||
|
{ // reference & mutex scope scope
|
||||||
|
// Get database block from cache
|
||||||
|
RefPtr<CachedSecurityDatabase> instance;
|
||||||
|
instances->getInstance(iParameter, instance);
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
MutexLockGuard g(instance->mutex, FB_FUNCTION);
|
||||||
|
|
||||||
|
secureDbName = instance->secureDbName;
|
||||||
|
if (!instance->secDb)
|
||||||
|
instance->secDb = FB_NEW SecurityDatabase(instance->secureDbName);
|
||||||
|
|
||||||
|
user_name uname; // user name buffer
|
||||||
|
login.copyTo(uname, sizeof uname);
|
||||||
|
user_record user_block; // user record
|
||||||
|
found = instance->secDb->lookup(uname, &user_block);
|
||||||
|
fb_utils::copy_terminate(pw1, user_block.password, MAX_LEGACY_PASSWORD_LENGTH + 1);
|
||||||
|
}
|
||||||
|
catch(const Exception&)
|
||||||
|
{
|
||||||
|
instance->close();
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
|
||||||
|
instance->close();
|
||||||
|
}
|
||||||
|
if (!found)
|
||||||
|
{
|
||||||
|
HANDSHAKE_DEBUG(fprintf(stderr, "LegacyServer (badlogin) %d\n", IAuth::AUTH_CONTINUE));
|
||||||
|
return IAuth::AUTH_CONTINUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
string storedHash(pw1, MAX_LEGACY_PASSWORD_LENGTH);
|
||||||
|
storedHash.rtrim();
|
||||||
|
storedHash.recalculate_length();
|
||||||
|
|
||||||
|
string passwordEnc;
|
||||||
|
passwordEnc.assign(data, length);
|
||||||
|
|
||||||
|
string newHash;
|
||||||
|
LegacyHash::hash(newHash, login, passwordEnc, storedHash);
|
||||||
|
if (newHash != storedHash)
|
||||||
|
{
|
||||||
|
bool legacyHash = Config::getLegacyHash();
|
||||||
|
if (legacyHash)
|
||||||
|
{
|
||||||
|
newHash.resize(MAX_LEGACY_PASSWORD_LENGTH + 2);
|
||||||
|
ENC_crypt(newHash.begin(), newHash.length(), passwordEnc.c_str(), LEGACY_PASSWORD_SALT);
|
||||||
|
newHash.recalculate_length();
|
||||||
|
newHash.erase(0, 2);
|
||||||
|
legacyHash = newHash == storedHash;
|
||||||
|
}
|
||||||
|
if (!legacyHash)
|
||||||
|
{
|
||||||
|
HANDSHAKE_DEBUG(fprintf(stderr, "LegacyServer (badpw) %d\n", IAuth::AUTH_CONTINUE));
|
||||||
|
return IAuth::AUTH_CONTINUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Jrd::FbLocalStatus s;
|
||||||
|
authBlock->add(&s, login.c_str());
|
||||||
check(&s);
|
check(&s);
|
||||||
|
authBlock->setDb(&s, secureDbName.c_str());
|
||||||
if (secDbKey == INIT_KEY)
|
check(&s);
|
||||||
{
|
HANDSHAKE_DEBUG(fprintf(stderr, "LegacyServer (OK) %d\n", IAuth::AUTH_SUCCESS));
|
||||||
secDbKey = config->getKey("SecurityDatabase");
|
return IAuth::AUTH_SUCCESS;
|
||||||
}
|
}
|
||||||
const char* tmp = config->asString(secDbKey);
|
catch (const Exception& ex)
|
||||||
if (!tmp)
|
|
||||||
{
|
|
||||||
Arg::Gds(isc_secdb_name).raise();
|
|
||||||
}
|
|
||||||
|
|
||||||
secDbName = tmp;
|
|
||||||
}
|
|
||||||
|
|
||||||
RefPtr<SecurityDatabase> instance;
|
|
||||||
|
|
||||||
{ // guard scope
|
|
||||||
MutexLockGuard g(instancesMutex, FB_FUNCTION);
|
|
||||||
InstancesArray& curInstances(instances);
|
|
||||||
for (unsigned int i = 0; i < curInstances.getCount(); ++i)
|
|
||||||
{
|
|
||||||
if (secDbName == curInstances[i]->secureDbName)
|
|
||||||
{
|
|
||||||
instance = curInstances[i];
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!instance)
|
|
||||||
{
|
|
||||||
instance = FB_NEW SecurityDatabase;
|
|
||||||
instance->addRef();
|
|
||||||
secDbName.copyTo(instance->secureDbName, sizeof(instance->secureDbName));
|
|
||||||
curInstances.add(instance);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int rc = instance->verify(writerInterface, sBlock);
|
|
||||||
#define USE_ATT_RQ_CACHE
|
|
||||||
#ifdef USE_ATT_RQ_CACHE
|
|
||||||
LocalStatus ls;
|
|
||||||
CheckStatusWrapper s(&ls);
|
|
||||||
TimerInterfacePtr()->start(&s, instance, 10 * 1000 * 1000);
|
|
||||||
if (s.getState() & IStatus::STATE_ERRORS)
|
|
||||||
instance->handler();
|
|
||||||
#else
|
|
||||||
instance->handler();
|
|
||||||
#endif
|
|
||||||
HANDSHAKE_DEBUG(fprintf(stderr, "LegacyServer: verify=%d\n", rc));
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
catch (const Firebird::Exception& ex)
|
|
||||||
{
|
{
|
||||||
ex.stuffException(status);
|
ex.stuffException(status);
|
||||||
HANDSHAKE_DEBUG(fprintf(stderr, "LegacyServer: exception status:\n"));
|
HANDSHAKE_DEBUG(fprintf(stderr, "LegacyServer: exception status:\n"));
|
||||||
@ -560,12 +416,12 @@ int SecurityDatabaseServer::release()
|
|||||||
}
|
}
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
Firebird::SimpleFactory<SecurityDatabaseServer> factory;
|
SimpleFactory<SecurityDatabaseServer> factory;
|
||||||
}
|
}
|
||||||
|
|
||||||
void registerLegacyServer(Firebird::IPluginManager* iPlugin)
|
void registerLegacyServer(IPluginManager* iPlugin)
|
||||||
{
|
{
|
||||||
iPlugin->registerPluginFactory(Firebird::IPluginManager::TYPE_AUTH_SERVER,
|
iPlugin->registerPluginFactory(IPluginManager::TYPE_AUTH_SERVER,
|
||||||
"Legacy_Auth", &factory);
|
"Legacy_Auth", &factory);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -27,20 +27,8 @@
|
|||||||
#ifndef AUTH_LEGACY_SERVER_H
|
#ifndef AUTH_LEGACY_SERVER_H
|
||||||
#define AUTH_LEGACY_SERVER_H
|
#define AUTH_LEGACY_SERVER_H
|
||||||
|
|
||||||
#include "../jrd/ibase.h"
|
|
||||||
#include "../common/utils_proto.h"
|
|
||||||
#include "../common/sha.h"
|
|
||||||
#include "gen/iberror.h"
|
|
||||||
#include "../common/classes/ClumpletWriter.h"
|
|
||||||
#include "../common/classes/ImplementHelper.h"
|
|
||||||
|
|
||||||
#include "firebird/Interface.h"
|
#include "firebird/Interface.h"
|
||||||
|
|
||||||
#ifdef HAVE_STDLIB_H
|
|
||||||
#include <stdlib.h>
|
|
||||||
#endif
|
|
||||||
#include <time.h>
|
|
||||||
|
|
||||||
namespace Auth {
|
namespace Auth {
|
||||||
|
|
||||||
void registerLegacyServer(Firebird::IPluginManager* iPlugin);
|
void registerLegacyServer(Firebird::IPluginManager* iPlugin);
|
||||||
|
Loading…
Reference in New Issue
Block a user