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

Fixed CORE-6093: Errors simultaneously accessing security database from two engines

This commit is contained in:
Alex Peshkoff 2019-07-03 14:12:06 +03:00
parent d7fc847bff
commit 6bb80e1845
11 changed files with 1169 additions and 1074 deletions

File diff suppressed because it is too large Load Diff

View File

@ -48,15 +48,14 @@
namespace {
const unsigned int INIT_KEY = ((~0) - 1);
unsigned int secDbKey = INIT_KEY;
const unsigned int SZ_LOGIN = 31;
const unsigned int SZ_NAME = 31;
typedef Field<Varying> Varfield;
typedef Field<ISC_QUAD> Blob;
typedef Field<FB_BOOLEAN> Boolean;
Firebird::GlobalPtr<Firebird::ConfigKeys> keys;
} // anonymous namespace
namespace Auth {
@ -221,12 +220,8 @@ public:
(Firebird::Arg::Gds(isc_random) << "Database is already attached in SRP").raise();
}
if (secDbKey == INIT_KEY)
{
secDbKey = config->getKey("SecurityDatabase");
}
unsigned int secDbKey = keys->getKey(config, "SecurityDatabase");
const char* secDbName = config->asString(secDbKey);
if (!(secDbName && secDbName[0]))
{
Firebird::Arg::Gds(isc_secdb_name).raise();

View File

@ -39,8 +39,7 @@ using namespace Firebird;
namespace {
const unsigned int INIT_KEY = ((~0) - 1);
unsigned int secDbKey = INIT_KEY;
GlobalPtr<ConfigKeys> keys;
const unsigned int SZ_LOGIN = 31;
@ -132,11 +131,7 @@ int SrpServer::authenticate(CheckStatusWrapper* status, IServerBlock* sb, IWrite
// read salt and verifier from database
// obviously we need something like attachments cache here
if (secDbKey == INIT_KEY)
{
secDbKey = config->getKey("SecurityDatabase");
}
unsigned int secDbKey = keys->getKey(config, "SecurityDatabase");
secDbName = config->asString(secDbKey);
if (!(secDbName && secDbName[0]))
{

View File

@ -100,8 +100,7 @@ static bool grantRevokeAdmin(ISC_STATUS* isc_status, FB_API_HANDLE database, FB_
}
const static unsigned int INIT_KEY = ((~0) - 1);
static unsigned int secDbKey = INIT_KEY;
static Firebird::GlobalPtr<Firebird::ConfigKeys> keys;
namespace Auth {
@ -120,12 +119,8 @@ void SecurityDatabaseManagement::start(Firebird::CheckStatusWrapper* st, Firebir
{
st->init();
if (secDbKey == INIT_KEY)
{
secDbKey = config->getKey("SecurityDatabase");
}
unsigned int secDbKey = keys->getKey(config, "SecurityDatabase");
const char* secDbName = config->asString(secDbKey);
if (!(secDbName && secDbName[0]))
{
Firebird::Arg::Gds(isc_secdb_name).raise();

View File

@ -471,8 +471,7 @@ int SecurityDatabase::shutdown()
return FB_SUCCESS;
}
const static unsigned int INIT_KEY = ((~0) - 1);
static unsigned int secDbKey = INIT_KEY;
static Firebird::GlobalPtr<Firebird::ConfigKeys> keys;
int SecurityDatabaseServer::authenticate(Firebird::CheckStatusWrapper* status, IServerBlock* sBlock,
IWriter* writerInterface)
@ -488,10 +487,7 @@ int SecurityDatabaseServer::authenticate(Firebird::CheckStatusWrapper* status, I
RefPtr<IFirebirdConf> config(REF_NO_INCR, iParameter->getFirebirdConf(&s));
check(&s);
if (secDbKey == INIT_KEY)
{
secDbKey = config->getKey("SecurityDatabase");
}
unsigned int secDbKey = keys->getKey(config, "SecurityDatabase");
const char* tmp = config->asString(secDbKey);
if (!tmp)
{

View File

@ -29,6 +29,7 @@
#include "firebird.h"
#include "../common/classes/fb_tls.h"
#include "../common/classes/ImplementHelper.h"
#include "../common/status.h"
namespace
{
@ -66,6 +67,23 @@ IMaster* CachedMasterInterface::getMasterInterface()
return cached;
}
unsigned int ConfigKeys::getKey(IFirebirdConf* config, const char* keyName)
{
FbLocalStatus status;
unsigned int version = config->getVersion(&status) & 0xFFFF0000;
for (const_iterator itr = this->begin(); itr != this->end(); ++itr)
{
if (((*itr) & 0xFFFF0000) == version)
return *itr;
}
unsigned int secDbKey = config->getKey(keyName);
if (secDbKey != INVALID_KEY)
this->push(secDbKey);
return secDbKey;
}
#ifdef NOT_USED_OR_REPLACED
class IDebug

View File

@ -389,6 +389,19 @@ inline void check(IStatus* status)
}
// Config keys cache
class ConfigKeys : private HalfStaticArray<unsigned int, 8>
{
public:
ConfigKeys(MemoryPool& p)
: HalfStaticArray<unsigned int, 8>(p)
{ }
const static unsigned int INVALID_KEY = ~0u;
unsigned int getKey(IFirebirdConf* config, const char* keyName);
};
// debugger for reference counters
#ifdef NEVERDEF

View File

@ -31,6 +31,7 @@
#include "../jrd/constants.h"
#include "firebird/Interface.h"
#include "../common/db_alias.h"
#include "../jrd/build_no.h"
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
@ -764,23 +765,58 @@ const char* Config::getPlugins(unsigned int type) const
return NULL; // compiler warning silencer
}
// array format: major, minor, release, build
static unsigned short fileVerNumber[4] = {FILE_VER_NUMBER};
static inline unsigned int getPartialVersion()
{
// major // minor
return (fileVerNumber[0] << 24) | (fileVerNumber[1] << 16);
}
static inline unsigned int getFullVersion()
{
// build_no
return getPartialVersion() | fileVerNumber[3];
}
static unsigned int PARTIAL_MASK = 0xFFFF0000;
static unsigned int KEY_MASK = 0xFFFF;
static inline void checkKey(unsigned int& key)
{
if (key & PARTIAL_MASK != getPartialVersion())
key = KEY_MASK;
else
key &= KEY_MASK;
}
unsigned int FirebirdConf::getVersion(Firebird::CheckStatusWrapper* status)
{
return getFullVersion();
}
unsigned int FirebirdConf::getKey(const char* name)
{
return Config::getKeyByName(name);
return Config::getKeyByName(name) | getPartialVersion();
}
ISC_INT64 FirebirdConf::asInteger(unsigned int key)
{
checkKey(key);
return config->getInt(key);
}
const char* FirebirdConf::asString(unsigned int key)
{
checkKey(key);
return config->getString(key);
}
FB_BOOLEAN FirebirdConf::asBoolean(unsigned int key)
{
checkKey(key);
return config->getBoolean(key);
}
@ -795,6 +831,7 @@ int FirebirdConf::release()
return 1;
}
const char* Config::getSecurityDatabase() const
{
return get<const char*>(KEY_SECURITY_DATABASE);

View File

@ -406,6 +406,7 @@ public:
SINT64 asInteger(unsigned int key);
const char* asString(unsigned int key);
FB_BOOLEAN asBoolean(unsigned int key);
unsigned int getVersion(Firebird::CheckStatusWrapper* status);
int release();

View File

@ -187,6 +187,7 @@ interface FirebirdConf : ReferenceCounted
// Get integer key by it's name
// Value ~0 means name is invalid
// Keys are stable: one can use once obtained key in other instances of this interface
// provided they have same minor version (upper 16 bits match with getVersion())
uint getKey(const string name);
// Use to access integer values
int64 asInteger(uint key);
@ -194,6 +195,10 @@ interface FirebirdConf : ReferenceCounted
const string asString(uint key);
// Use to access boolean values
boolean asBoolean(uint key);
version: // 3.0 => 4.0
// Use to access version of configuration manager serving this interface
// Format: major byte, minor byte, buildno 2-byte
uint getVersion(Status status);
}
// This interface is passed to plugin's factory as it's single parameter

View File

@ -611,6 +611,7 @@ namespace Firebird
ISC_INT64 (CLOOP_CARG *asInteger)(IFirebirdConf* self, unsigned key) throw();
const char* (CLOOP_CARG *asString)(IFirebirdConf* self, unsigned key) throw();
FB_BOOLEAN (CLOOP_CARG *asBoolean)(IFirebirdConf* self, unsigned key) throw();
unsigned (CLOOP_CARG *getVersion)(IFirebirdConf* self, IStatus* status) throw();
};
protected:
@ -624,7 +625,7 @@ namespace Firebird
}
public:
static const unsigned VERSION = 3;
static const unsigned VERSION = 4;
unsigned getKey(const char* name)
{
@ -649,6 +650,20 @@ namespace Firebird
FB_BOOLEAN ret = static_cast<VTable*>(this->cloopVTable)->asBoolean(this, key);
return ret;
}
template <typename StatusType> unsigned getVersion(StatusType* status)
{
if (cloopVTable->version < 4)
{
StatusType::setVersionError(status, "IFirebirdConf", cloopVTable->version, 4);
StatusType::checkException(status);
return 0;
}
StatusType::clearException(status);
unsigned ret = static_cast<VTable*>(this->cloopVTable)->getVersion(this, status);
StatusType::checkException(status);
return ret;
}
};
class IPluginConfig : public IReferenceCounted
@ -7113,6 +7128,7 @@ namespace Firebird
this->asInteger = &Name::cloopasIntegerDispatcher;
this->asString = &Name::cloopasStringDispatcher;
this->asBoolean = &Name::cloopasBooleanDispatcher;
this->getVersion = &Name::cloopgetVersionDispatcher;
}
} vTable;
@ -7171,6 +7187,21 @@ namespace Firebird
}
}
static unsigned CLOOP_CARG cloopgetVersionDispatcher(IFirebirdConf* self, IStatus* status) throw()
{
StatusType status2(status);
try
{
return static_cast<Name*>(self)->Name::getVersion(&status2);
}
catch (...)
{
StatusType::catchException(&status2);
return static_cast<unsigned>(0);
}
}
static void CLOOP_CARG cloopaddRefDispatcher(IReferenceCounted* self) throw()
{
try
@ -7214,6 +7245,7 @@ namespace Firebird
virtual ISC_INT64 asInteger(unsigned key) = 0;
virtual const char* asString(unsigned key) = 0;
virtual FB_BOOLEAN asBoolean(unsigned key) = 0;
virtual unsigned getVersion(StatusType* status) = 0;
};
template <typename Name, typename StatusType, typename Base>