mirror of
https://github.com/FirebirdSQL/firebird.git
synced 2025-01-22 20:03:02 +01:00
Implemented CORE-5442: Enhance control upon ability to share database crypt key between attachments in SS
This commit is contained in:
parent
d5146be51e
commit
e722a4095c
@ -7,7 +7,8 @@
|
||||
<META NAME="AUTHOR" CONTENT="alex ">
|
||||
<META NAME="CREATED" CONTENT="20130531;10003100">
|
||||
<META NAME="CHANGEDBY" CONTENT="Alex Peshkoff">
|
||||
<META NAME="CHANGED" CONTENT="20160905;13142600">
|
||||
<META NAME="CHANGED" CONTENT="20170109;20251600">
|
||||
<META NAME="CHANGEDBY" CONTENT="Alex Peshkoff">
|
||||
<META NAME="CHANGEDBY" CONTENT="Alex Peshkoff">
|
||||
<META NAME="CHANGEDBY" CONTENT="Alex Peshkoff">
|
||||
<STYLE TYPE="text/css">
|
||||
@ -587,10 +588,10 @@ namespace Firebird), timestamp – with class FbTimestamp, containing
|
||||
two public data members date and time of appropriate class, char -
|
||||
with struct <A HREF="#FbChar">FbChar</A> and varchar – with struct
|
||||
<A HREF="#FbVarChar">FbVarChar</A>. For each field preprocessor
|
||||
creates two data members in the message – </FONT><FONT SIZE=4><I>name</I></FONT><FONT SIZE=4>
|
||||
for field/parameter value and </FONT><FONT SIZE=4><I>nameNull</I></FONT><FONT SIZE=4>
|
||||
for NULL indicator. Message constructor has 2 parameters – pointer
|
||||
to status wrapper and master interface:</FONT></P>
|
||||
creates two data members in the message – </FONT><FONT SIZE=4><I>name</I></FONT>
|
||||
<FONT SIZE=4>for field/parameter value and </FONT><FONT SIZE=4><I>nameNull</I></FONT>
|
||||
<FONT SIZE=4>for NULL indicator. Message constructor has 2 parameters
|
||||
– pointer to status wrapper and master interface:</FONT></P>
|
||||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4><I>FB_MESSAGE(Output,
|
||||
ThrowStatusWrapper,</I></FONT></P>
|
||||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4><I>(FB_SMALLINT,
|
||||
@ -748,16 +749,15 @@ completed in FB3, we expect to have something more interesting in
|
||||
next version. The minimum existing support is as follows: <A HREF="#Attachment">IAttachment</A>
|
||||
contains call queEvents() which performs almost same functions as
|
||||
isc_que_events() call. Instead the pair of parameters
|
||||
</FONT><FONT SIZE=4><I>FPTR_EVENT_CALLBACK ast</I></FONT><FONT SIZE=4>
|
||||
and </FONT><FONT SIZE=4><I>void* arg</I></FONT><FONT SIZE=4>,
|
||||
required to invoke user code when event happens in firebird engine,
|
||||
callback interface IEventCallback is used. This is traditional
|
||||
approach which helps to avoid non-safe casts from void* in user
|
||||
function. Another important difference is that instead event
|
||||
identifier (a kind of handler) this function returns reference
|
||||
counted interface <A HREF="#Events">IEvents</A> having method
|
||||
cancel() used when waiting for event should be stopped. Unlike
|
||||
identifier which is automatically destroyed when event arrives
|
||||
</FONT><FONT SIZE=4><I>FPTR_EVENT_CALLBACK ast</I></FONT> <FONT SIZE=4>and
|
||||
</FONT><FONT SIZE=4><I>void* arg</I></FONT><FONT SIZE=4>, required to
|
||||
invoke user code when event happens in firebird engine, callback
|
||||
interface IEventCallback is used. This is traditional approach which
|
||||
helps to avoid non-safe casts from void* in user function. Another
|
||||
important difference is that instead event identifier (a kind of
|
||||
handler) this function returns reference counted interface <A HREF="#Events">IEvents</A>
|
||||
having method cancel() used when waiting for event should be stopped.
|
||||
Unlike identifier which is automatically destroyed when event arrives
|
||||
interface can not be automatically destroyed – in case when event
|
||||
is received right before canceling interface call to cancel() would
|
||||
cause segfault when interface is already destroyed. Therefore
|
||||
@ -890,7 +890,7 @@ services tasks do not forget to close an interface:</FONT></P>
|
||||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4>To write a plugin means to
|
||||
implement some interfaces and place your implementation into dynamic
|
||||
library (.dll in windows or .so in linux) later referenced as </FONT><FONT SIZE=4><I>plugin
|
||||
module</I></FONT><FONT SIZE=4> or just </FONT><FONT SIZE=4><I>module</I></FONT><FONT SIZE=4>.
|
||||
module</I></FONT> <FONT SIZE=4>or just </FONT><FONT SIZE=4><I>module</I></FONT><FONT SIZE=4>.
|
||||
In most cases single plugin is place in dynamic library but in common
|
||||
case. One of that interfaces – <A HREF="#PluginModule">IPluginModule</A>
|
||||
– is module-wide (as more or less clear from it's name), others are
|
||||
@ -920,9 +920,9 @@ be aware what plugin modules were loaded and must be notified if
|
||||
operating system tries to unload one of that modules without explicit
|
||||
plugin manager command (this may happen first of all when using
|
||||
embedded access – when exit() is called in a program or main
|
||||
firebird library </FONT><FONT SIZE=4><I><SPAN STYLE="font-weight: normal">fbclient</SPAN></I></FONT><FONT SIZE=4>
|
||||
is unloaded). Primary task of IPluginModule interface is that
|
||||
notification. First of all one must decide - how to detect that
|
||||
firebird library </FONT><FONT SIZE=4><I><SPAN STYLE="font-weight: normal">fbclient</SPAN></I></FONT>
|
||||
<FONT SIZE=4>is unloaded). Primary task of IPluginModule interface is
|
||||
that notification. First of all one must decide - how to detect that
|
||||
module is going to be unloaded? When dynamic library is unloaded for
|
||||
some reason a lot of OS-dependent actions is performed and some of
|
||||
that actions may be used to detect this fact in the program. When
|
||||
@ -2073,8 +2073,8 @@ moment when given timer should alarm.</FONT></P>
|
||||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>void
|
||||
start(StatusType* status, ITimer* timer, ISC_UINT64 microSeconds) –
|
||||
start <A HREF="#Timer">ITimer</A> to alarm after given delay (in
|
||||
microseconds, 10</FONT><SUP><FONT SIZE=4>-6</FONT></SUP><FONT SIZE=4>
|
||||
seconds). Timer will be waked up only once after this call.</FONT></P>
|
||||
microseconds, 10</FONT><SUP><FONT SIZE=4>-6</FONT></SUP> <FONT SIZE=4>seconds).
|
||||
Timer will be waked up only once after this call.</FONT></P>
|
||||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>void stop(StatusType*
|
||||
status, ITimer* timer) – stop <A HREF="#Timer">ITimer</A>. It's
|
||||
not an error to stop not started timer thus avoiding problems with
|
||||
@ -2706,6 +2706,14 @@ interface is main interface of database crypt key holder plugin.</FONT></P>
|
||||
(for example) check digital signature of crypt plugin before sending
|
||||
a key to it in order to avoid use of modified crypt plugin able to
|
||||
steal secret key.</FONT></P>
|
||||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>FB_BOOLEAN
|
||||
useOnlyOwnKeys(StatusType* status) – informs firebird engine can a
|
||||
key, provided by another key holder, be used or not. Makes sense
|
||||
only for SuperServer – only it can share database crypt keys
|
||||
between attachments. Returning FB_TRUE from this method enforces
|
||||
firebird to make sure that this particular key holder (and therefore
|
||||
in turn attachment related to it) provides correct crypt key before
|
||||
letting it to work with database.</FONT></P>
|
||||
</OL>
|
||||
<P STYLE="margin-bottom: 0in"><BR>
|
||||
</P>
|
||||
|
@ -108,6 +108,17 @@ public:
|
||||
return key;
|
||||
}
|
||||
|
||||
FB_BOOLEAN useOnlyOwnKeys(CheckStatusWrapper* status)
|
||||
{
|
||||
IConfigEntry* e = getEntry(status, "OnlyOwnKey");
|
||||
if (!e)
|
||||
return FB_TRUE; // safe default
|
||||
|
||||
FB_BOOLEAN rc = e->getBoolValue();
|
||||
e->release();
|
||||
return rc;
|
||||
}
|
||||
|
||||
private:
|
||||
class CallbackInterface : public ICryptKeyCallbackImpl<CallbackInterface, CheckStatusWrapper>
|
||||
{
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* PROGRAM: Firebird interface.
|
||||
* MODULE: ImplementHelper.h
|
||||
* MODULE: GetPlugins.h
|
||||
* DESCRIPTION: Tools to help access plugins.
|
||||
*
|
||||
* The contents of this file are subject to the Initial
|
||||
@ -82,6 +82,16 @@ public:
|
||||
return currentPlugin;
|
||||
}
|
||||
|
||||
P* makeInstance()
|
||||
{
|
||||
if (!hasData())
|
||||
return NULL;
|
||||
|
||||
P* p = (P*) pluginSet->getPlugin(&status);
|
||||
check(&status);
|
||||
return p;
|
||||
}
|
||||
|
||||
void next()
|
||||
{
|
||||
if (hasData())
|
||||
|
@ -732,6 +732,11 @@ interface KeyHolderPlugin : PluginBase
|
||||
// Missing key with given name is not an error condition for keyHandle().
|
||||
// It should just return NULL in this case
|
||||
CryptKeyCallback keyHandle(Status status, const string keyName);
|
||||
|
||||
version: // 3.0.1 => 4.0
|
||||
// With returning true here KeyHolder attachment can use only keys, provided by this KeyHolder.
|
||||
// Use of keys, got by database crypt plugin from other attachments, is prohibited.
|
||||
boolean useOnlyOwnKeys(Status status);
|
||||
}
|
||||
|
||||
|
||||
|
@ -2905,6 +2905,7 @@ namespace Firebird
|
||||
{
|
||||
int (CLOOP_CARG *keyCallback)(IKeyHolderPlugin* self, IStatus* status, ICryptKeyCallback* callback) throw();
|
||||
ICryptKeyCallback* (CLOOP_CARG *keyHandle)(IKeyHolderPlugin* self, IStatus* status, const char* keyName) throw();
|
||||
FB_BOOLEAN (CLOOP_CARG *useOnlyOwnKeys)(IKeyHolderPlugin* self, IStatus* status) throw();
|
||||
};
|
||||
|
||||
protected:
|
||||
@ -2918,7 +2919,7 @@ namespace Firebird
|
||||
}
|
||||
|
||||
public:
|
||||
static const unsigned VERSION = 4;
|
||||
static const unsigned VERSION = 5;
|
||||
|
||||
template <typename StatusType> int keyCallback(StatusType* status, ICryptKeyCallback* callback)
|
||||
{
|
||||
@ -2935,6 +2936,20 @@ namespace Firebird
|
||||
StatusType::checkException(status);
|
||||
return ret;
|
||||
}
|
||||
|
||||
template <typename StatusType> FB_BOOLEAN useOnlyOwnKeys(StatusType* status)
|
||||
{
|
||||
if (cloopVTable->version < 5)
|
||||
{
|
||||
StatusType::setVersionError(status, "IKeyHolderPlugin", cloopVTable->version, 5);
|
||||
StatusType::checkException(status);
|
||||
return 0;
|
||||
}
|
||||
StatusType::clearException(status);
|
||||
FB_BOOLEAN ret = static_cast<VTable*>(this->cloopVTable)->useOnlyOwnKeys(this, status);
|
||||
StatusType::checkException(status);
|
||||
return ret;
|
||||
}
|
||||
};
|
||||
|
||||
class IDbCryptInfo : public IReferenceCounted
|
||||
@ -11230,6 +11245,7 @@ namespace Firebird
|
||||
this->getOwner = &Name::cloopgetOwnerDispatcher;
|
||||
this->keyCallback = &Name::cloopkeyCallbackDispatcher;
|
||||
this->keyHandle = &Name::cloopkeyHandleDispatcher;
|
||||
this->useOnlyOwnKeys = &Name::cloopuseOnlyOwnKeysDispatcher;
|
||||
}
|
||||
} vTable;
|
||||
|
||||
@ -11266,6 +11282,21 @@ namespace Firebird
|
||||
}
|
||||
}
|
||||
|
||||
static FB_BOOLEAN CLOOP_CARG cloopuseOnlyOwnKeysDispatcher(IKeyHolderPlugin* self, IStatus* status) throw()
|
||||
{
|
||||
StatusType status2(status);
|
||||
|
||||
try
|
||||
{
|
||||
return static_cast<Name*>(self)->Name::useOnlyOwnKeys(&status2);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
StatusType::catchException(&status2);
|
||||
return static_cast<FB_BOOLEAN>(0);
|
||||
}
|
||||
}
|
||||
|
||||
static void CLOOP_CARG cloopsetOwnerDispatcher(IPluginBase* self, IReferenceCounted* r) throw()
|
||||
{
|
||||
try
|
||||
@ -11332,6 +11363,7 @@ namespace Firebird
|
||||
|
||||
virtual int keyCallback(StatusType* status, ICryptKeyCallback* callback) = 0;
|
||||
virtual ICryptKeyCallback* keyHandle(StatusType* status, const char* keyName) = 0;
|
||||
virtual FB_BOOLEAN useOnlyOwnKeys(StatusType* status) = 0;
|
||||
};
|
||||
|
||||
template <typename Name, typename StatusType, typename Base>
|
||||
|
@ -265,10 +265,12 @@ namespace Jrd {
|
||||
: PermanentStorage(*tdbb->getDatabase()->dbb_permanent),
|
||||
sync(this),
|
||||
keyName(getPool()),
|
||||
keyHolderPlugins(getPool()),
|
||||
keyHolderPlugins(getPool(), this),
|
||||
hash(getPool()),
|
||||
dbInfo(FB_NEW DbInfo(this)),
|
||||
cryptThreadId(0),
|
||||
cryptPlugin(NULL),
|
||||
checkPlugin(NULL),
|
||||
dbb(*tdbb->getDatabase()),
|
||||
cryptAtt(NULL),
|
||||
slowIO(0),
|
||||
@ -364,14 +366,15 @@ namespace Jrd {
|
||||
loadPlugin(hdr->hdr_crypt_plugin);
|
||||
|
||||
string valid;
|
||||
calcValidation(valid);
|
||||
calcValidation(valid, cryptPlugin);
|
||||
if (hc.find(Ods::HDR_crypt_hash))
|
||||
{
|
||||
string hash;
|
||||
hc.getString(hash);
|
||||
if (hash != valid)
|
||||
(Arg::Gds(isc_bad_crypt_key) << keyName).raise();
|
||||
}
|
||||
else
|
||||
hash = valid;
|
||||
}
|
||||
|
||||
if (flags & CRYPT_HDR_INIT)
|
||||
@ -409,9 +412,21 @@ namespace Jrd {
|
||||
status_exception::raise(&status);
|
||||
}
|
||||
|
||||
keyHolderPlugins.init(p, keyName.c_str());
|
||||
keyHolderPlugins.init(p, keyName);
|
||||
cryptPlugin = p;
|
||||
cryptPlugin->addRef();
|
||||
|
||||
// May be load second instance to validate keys
|
||||
if (checkPlugin)
|
||||
{
|
||||
PluginManagerInterfacePtr()->releasePlugin(checkPlugin);
|
||||
checkPlugin = NULL;
|
||||
}
|
||||
if (dbb.dbb_config->getServerMode() == MODE_SUPER)
|
||||
{
|
||||
checkPlugin = cryptControl.makeInstance();
|
||||
keyHolderPlugins.validate(checkPlugin, NULL, keyName);
|
||||
}
|
||||
}
|
||||
|
||||
void CryptoManager::prepareChangeCryptState(thread_db* tdbb, const MetaName& plugName,
|
||||
@ -472,13 +487,13 @@ namespace Jrd {
|
||||
}
|
||||
}
|
||||
|
||||
void CryptoManager::calcValidation(string& valid)
|
||||
void CryptoManager::calcValidation(string& valid, IDbCryptPlugin* plugin)
|
||||
{
|
||||
// crypt verifier
|
||||
const char* sample = "0123456789ABCDEF";
|
||||
char result[16];
|
||||
FbLocalStatus sv;
|
||||
cryptPlugin->encrypt(&sv, sizeof(result), sample, result);
|
||||
plugin->encrypt(&sv, sizeof(result), sample, result);
|
||||
if (sv->getState() & IStatus::STATE_ERRORS)
|
||||
Arg::StatusVector(&sv).raise();
|
||||
|
||||
@ -487,6 +502,13 @@ namespace Jrd {
|
||||
Sha1::hashBased64(valid, verifier);
|
||||
}
|
||||
|
||||
bool CryptoManager::checkValidation(IDbCryptPlugin* plugin)
|
||||
{
|
||||
string valid;
|
||||
calcValidation(valid, plugin);
|
||||
return valid == hash;
|
||||
}
|
||||
|
||||
void CryptoManager::changeCryptState(thread_db* tdbb, const string& plugName)
|
||||
{
|
||||
if (plugName.length() > 31)
|
||||
@ -550,8 +572,7 @@ namespace Jrd {
|
||||
{
|
||||
header->hdr_flags |= Ods::hdr_encrypted;
|
||||
plugName.copyTo(header->hdr_crypt_plugin, sizeof(header->hdr_crypt_plugin));
|
||||
string hash;
|
||||
calcValidation(hash);
|
||||
calcValidation(hash, cryptPlugin);
|
||||
hc.deleteWithTag(Ods::HDR_crypt_hash);
|
||||
hc.insertString(Ods::HDR_crypt_hash, hash);
|
||||
|
||||
@ -619,7 +640,15 @@ namespace Jrd {
|
||||
{
|
||||
keyHolderPlugins.attach(att, dbb.dbb_config);
|
||||
|
||||
IDbCryptPlugin* p = checkPlugin;
|
||||
|
||||
lockAndReadHeader(tdbb, CRYPT_HDR_INIT);
|
||||
|
||||
if (p && p == checkPlugin)
|
||||
{
|
||||
if (!keyHolderPlugins.validate(checkPlugin, att, keyName))
|
||||
(Arg::Gds(isc_bad_crypt_key) << keyName).raise();
|
||||
}
|
||||
}
|
||||
|
||||
void CryptoManager::terminateCryptThread(thread_db*, bool wait)
|
||||
@ -1132,49 +1161,6 @@ namespace Jrd {
|
||||
return (crypt ? fb_info_crypt_encrypted : 0) | (process ? fb_info_crypt_process : 0);
|
||||
}
|
||||
|
||||
CryptoManager::HolderAttachments::HolderAttachments(MemoryPool& p)
|
||||
: keyHolder(NULL), attachments(p)
|
||||
{ }
|
||||
|
||||
void CryptoManager::HolderAttachments::setPlugin(IKeyHolderPlugin* kh)
|
||||
{
|
||||
keyHolder = kh;
|
||||
keyHolder->addRef();
|
||||
}
|
||||
|
||||
CryptoManager::HolderAttachments::~HolderAttachments()
|
||||
{
|
||||
if (keyHolder)
|
||||
{
|
||||
PluginManagerInterfacePtr()->releasePlugin(keyHolder);
|
||||
}
|
||||
}
|
||||
|
||||
void CryptoManager::HolderAttachments::registerAttachment(Attachment* att)
|
||||
{
|
||||
attachments.add(att);
|
||||
}
|
||||
|
||||
bool CryptoManager::HolderAttachments::unregisterAttachment(Attachment* att)
|
||||
{
|
||||
unsigned i = attachments.getCount();
|
||||
while (i--)
|
||||
{
|
||||
if (attachments[i] == att)
|
||||
{
|
||||
attachments.remove(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return attachments.getCount() == 0;
|
||||
}
|
||||
|
||||
bool CryptoManager::HolderAttachments::operator==(IKeyHolderPlugin* kh) const
|
||||
{
|
||||
// ASF: I think there should be a better way to do this.
|
||||
return keyHolder->cloopVTable == kh->cloopVTable;
|
||||
}
|
||||
|
||||
void CryptoManager::KeyHolderPlugins::attach(Attachment* att, Config* config)
|
||||
{
|
||||
MutexLockGuard g(holdersMutex, FB_FUNCTION);
|
||||
@ -1184,31 +1170,42 @@ namespace Jrd {
|
||||
{
|
||||
IKeyHolderPlugin* keyPlugin = keyControl.plugin();
|
||||
FbLocalStatus st;
|
||||
if (keyPlugin->keyCallback(&st, att->att_crypt_callback) > 0)
|
||||
bool flProvide = false;
|
||||
if (keyPlugin->keyCallback(&st, att->att_crypt_callback))
|
||||
flProvide = true;
|
||||
else
|
||||
{
|
||||
// holder accepted attachment's key
|
||||
HolderAttachments* ha = NULL;
|
||||
st.check();
|
||||
flProvide = !keyPlugin->useOnlyOwnKeys(&st);
|
||||
// Ignore error condition to support old plugins
|
||||
}
|
||||
|
||||
if (flProvide)
|
||||
{
|
||||
// holder is going to provide a key
|
||||
PerAttHolders* pa = NULL;
|
||||
|
||||
for (unsigned i = 0; i < knownHolders.getCount(); ++i)
|
||||
{
|
||||
if (knownHolders[i] == keyPlugin)
|
||||
if (knownHolders[i].first == att)
|
||||
{
|
||||
ha = &knownHolders[i];
|
||||
pa = &knownHolders[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!ha)
|
||||
if ((!pa) && config->getServerMode() == MODE_SUPER)
|
||||
{
|
||||
ha = &(knownHolders.add());
|
||||
ha->setPlugin(keyPlugin);
|
||||
pa = &(knownHolders.add());
|
||||
pa->first = att;
|
||||
}
|
||||
|
||||
ha->registerAttachment(att);
|
||||
break; // Do not need >1 key from attachment to single DB
|
||||
if (pa)
|
||||
{
|
||||
pa->second.add(keyPlugin);
|
||||
keyPlugin->addRef();
|
||||
}
|
||||
}
|
||||
else
|
||||
st.check();
|
||||
}
|
||||
}
|
||||
|
||||
@ -1216,33 +1213,130 @@ namespace Jrd {
|
||||
{
|
||||
MutexLockGuard g(holdersMutex, FB_FUNCTION);
|
||||
|
||||
unsigned i = knownHolders.getCount();
|
||||
while (i--)
|
||||
for (unsigned i = 0; i < knownHolders.getCount(); ++i)
|
||||
{
|
||||
if (knownHolders[i].unregisterAttachment(att))
|
||||
if (knownHolders[i].first == att)
|
||||
{
|
||||
releaseHolders(knownHolders[i]);
|
||||
knownHolders.remove(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CryptoManager::KeyHolderPlugins::init(IDbCryptPlugin* crypt, const char* keyName)
|
||||
void CryptoManager::KeyHolderPlugins::releaseHolders(PerAttHolders& pa)
|
||||
{
|
||||
unsigned j = 0;
|
||||
for (; j < pa.second.getCount(); ++j)
|
||||
{
|
||||
PluginManagerInterfacePtr()->releasePlugin(pa.second[j]);
|
||||
}
|
||||
pa.second.removeCount(0, j);
|
||||
}
|
||||
|
||||
void CryptoManager::KeyHolderPlugins::init(IDbCryptPlugin* crypt, const MetaName& keyName)
|
||||
{
|
||||
MutexLockGuard g(holdersMutex, FB_FUNCTION);
|
||||
|
||||
Firebird::HalfStaticArray<Firebird::IKeyHolderPlugin*, 64> holdersVector;
|
||||
unsigned int length = knownHolders.getCount();
|
||||
IKeyHolderPlugin** vector = holdersVector.getBuffer(length);
|
||||
for (unsigned i = 0; i < length; ++i)
|
||||
for (unsigned i = 0; i < knownHolders.getCount(); ++i)
|
||||
{
|
||||
vector[i] = knownHolders[i].getPlugin();
|
||||
PerAttHolders pa = knownHolders[i];
|
||||
for (unsigned j = 0; j < pa.second.getCount(); ++j)
|
||||
holdersVector.push(pa.second[j]);
|
||||
}
|
||||
|
||||
FbLocalStatus st;
|
||||
crypt->setKey(&st, length, vector, keyName);
|
||||
crypt->setKey(&st, holdersVector.getCount(), holdersVector.begin(), keyName.c_str());
|
||||
st.check();
|
||||
}
|
||||
|
||||
bool CryptoManager::KeyHolderPlugins::validateHoldersGroup(PerAttHolders& pa, IDbCryptPlugin* crypt, const MetaName& keyName)
|
||||
{
|
||||
FbLocalStatus st;
|
||||
fb_assert(holdersMutex.locked());
|
||||
|
||||
for (unsigned j = 0; j < pa.second.getCount(); ++j)
|
||||
{
|
||||
IKeyHolderPlugin* keyHolder = pa.second[j];
|
||||
if (!keyHolder->useOnlyOwnKeys(&st))
|
||||
return true;
|
||||
|
||||
crypt->setKey(&st, 1, &keyHolder, keyName.c_str());
|
||||
if (st.isSuccess() && mgr->checkValidation(crypt))
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CryptoManager::KeyHolderPlugins::validate(IDbCryptPlugin* crypt, Attachment* att, const MetaName& keyName)
|
||||
{
|
||||
FbLocalStatus st;
|
||||
MutexLockGuard g(holdersMutex, FB_FUNCTION);
|
||||
|
||||
// Check for current attachment
|
||||
for (unsigned i = 0; i < knownHolders.getCount(); ++i)
|
||||
{
|
||||
PerAttHolders& pa = knownHolders[i];
|
||||
if (pa.first == att)
|
||||
{
|
||||
bool empty = (pa.second.getCount() == 0);
|
||||
bool result = empty ? false : validateHoldersGroup(pa, crypt, keyName);
|
||||
|
||||
releaseHolders(pa);
|
||||
knownHolders.remove(i);
|
||||
|
||||
if (empty)
|
||||
break;
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
// Special case - holders not needed at all
|
||||
crypt->setKey(&st, 0, NULL, keyName.c_str());
|
||||
if (st.isSuccess() && mgr->checkValidation(crypt))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void CryptoManager::KeyHolderPlugins::validate(IDbCryptPlugin* crypt, const MetaName& keyName)
|
||||
{
|
||||
FbLocalStatus st;
|
||||
MutexLockGuard g(holdersMutex, FB_FUNCTION);
|
||||
fb_assert(mgr->dbb.dbb_sync.isLocked());
|
||||
|
||||
// Special case - holders not needed at all
|
||||
crypt->setKey(&st, 0, NULL, keyName.c_str());
|
||||
if (st.isSuccess() && mgr->checkValidation(crypt))
|
||||
return;
|
||||
|
||||
// Loop through whole attathment list of DBB, shutdown attachments missing any holders
|
||||
for (Attachment* att = mgr->dbb.dbb_attachments; att; att = att->att_next)
|
||||
{
|
||||
for (unsigned i = 0; i < knownHolders.getCount(); ++i)
|
||||
{
|
||||
if (knownHolders[i].first == att)
|
||||
goto found;
|
||||
}
|
||||
att->signalCancel();
|
||||
found:;
|
||||
}
|
||||
|
||||
// Loop through internal attachments list closing one missing valid holders
|
||||
for (unsigned i = 0; i < knownHolders.getCount(); ++i)
|
||||
{
|
||||
if (!validateHoldersGroup(knownHolders[i], crypt, keyName))
|
||||
knownHolders[i].first->signalCancel();
|
||||
|
||||
// Cleanup holders list
|
||||
releaseHolders(knownHolders[i]);
|
||||
}
|
||||
|
||||
knownHolders.clear();
|
||||
}
|
||||
|
||||
void CryptoManager::addClumplet(string& signature, ClumpletReader& block, UCHAR tag)
|
||||
{
|
||||
if (block.find(tag))
|
||||
|
@ -294,6 +294,8 @@ public:
|
||||
|
||||
void cryptThread();
|
||||
|
||||
bool checkValidation(Firebird::IDbCryptPlugin* crypt);
|
||||
|
||||
ULONG getCurrentPage() const;
|
||||
UCHAR getCurrentState() const;
|
||||
|
||||
@ -319,42 +321,28 @@ private:
|
||||
char buf[MAX_PAGE_SIZE + PAGE_ALIGNMENT - 1];
|
||||
};
|
||||
|
||||
class HolderAttachments
|
||||
{
|
||||
public:
|
||||
explicit HolderAttachments(Firebird::MemoryPool& p);
|
||||
~HolderAttachments();
|
||||
|
||||
void registerAttachment(Attachment* att);
|
||||
bool unregisterAttachment(Attachment* att);
|
||||
|
||||
void setPlugin(Firebird::IKeyHolderPlugin* kh);
|
||||
Firebird::IKeyHolderPlugin* getPlugin() const
|
||||
{
|
||||
return keyHolder;
|
||||
}
|
||||
|
||||
bool operator==(Firebird::IKeyHolderPlugin* kh) const;
|
||||
|
||||
private:
|
||||
Firebird::IKeyHolderPlugin* keyHolder;
|
||||
Firebird::HalfStaticArray<Attachment*, 32> attachments;
|
||||
};
|
||||
|
||||
class KeyHolderPlugins
|
||||
{
|
||||
public:
|
||||
explicit KeyHolderPlugins(Firebird::MemoryPool& p)
|
||||
: knownHolders(p)
|
||||
explicit KeyHolderPlugins(Firebird::MemoryPool& p, CryptoManager* m)
|
||||
: knownHolders(p), mgr(m)
|
||||
{ }
|
||||
|
||||
void attach(Attachment* att, Config* config);
|
||||
void init(Firebird::IDbCryptPlugin* crypt, const Firebird::MetaName& keyName);
|
||||
bool validate(Firebird::IDbCryptPlugin* crypt, Attachment*, const Firebird::MetaName& keyName);
|
||||
void validate(Firebird::IDbCryptPlugin* crypt, const Firebird::MetaName& keyName);
|
||||
void detach(Attachment* att);
|
||||
void init(Firebird::IDbCryptPlugin* crypt, const char* keyName);
|
||||
|
||||
private:
|
||||
Firebird::Mutex holdersMutex;
|
||||
Firebird::ObjectsArray<HolderAttachments> knownHolders;
|
||||
typedef Firebird::Pair<Firebird::Right<Attachment*,
|
||||
Firebird::HalfStaticArray<Firebird::IKeyHolderPlugin*, 4>>> PerAttHolders;
|
||||
Firebird::ObjectsArray<PerAttHolders> knownHolders;
|
||||
CryptoManager* mgr;
|
||||
|
||||
bool validateHoldersGroup(PerAttHolders& pa, Firebird::IDbCryptPlugin* crypt, const Firebird::MetaName& keyName);
|
||||
void releaseHolders(PerAttHolders& pa);
|
||||
};
|
||||
|
||||
class DbInfo;
|
||||
@ -398,7 +386,8 @@ private:
|
||||
void loadPlugin(const char* pluginName);
|
||||
ULONG getLastPage(thread_db* tdbb);
|
||||
void writeDbHeader(thread_db* tdbb, ULONG runpage);
|
||||
void calcValidation(Firebird::string& valid);
|
||||
void calcValidation(Firebird::string& valid, Firebird::IDbCryptPlugin* plugin);
|
||||
void checkValidation();
|
||||
|
||||
void lockAndReadHeader(thread_db* tdbb, unsigned flags = 0);
|
||||
static const unsigned CRYPT_HDR_INIT = 0x01;
|
||||
@ -414,9 +403,11 @@ private:
|
||||
ULONG currentPage;
|
||||
Firebird::Mutex pluginLoadMtx, cryptThreadMtx;
|
||||
KeyHolderPlugins keyHolderPlugins;
|
||||
Firebird::string hash;
|
||||
Firebird::RefPtr<DbInfo> dbInfo;
|
||||
Thread::Handle cryptThreadId;
|
||||
Firebird::IDbCryptPlugin* cryptPlugin;
|
||||
Firebird::IDbCryptPlugin* checkPlugin;
|
||||
Database& dbb;
|
||||
Lock* stateLock;
|
||||
Lock* threadLock;
|
||||
|
@ -101,6 +101,11 @@ namespace Jrd
|
||||
return localStatusVector.isEmpty();
|
||||
}
|
||||
|
||||
bool isSuccess() const
|
||||
{
|
||||
return localStatusVector.isEmpty();
|
||||
}
|
||||
|
||||
private:
|
||||
Firebird::LocalStatus localStatus;
|
||||
SW localStatusVector;
|
||||
|
Loading…
Reference in New Issue
Block a user