mirror of
https://github.com/FirebirdSQL/firebird.git
synced 2025-01-22 22:43:03 +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="AUTHOR" CONTENT="alex ">
|
||||||
<META NAME="CREATED" CONTENT="20130531;10003100">
|
<META NAME="CREATED" CONTENT="20130531;10003100">
|
||||||
<META NAME="CHANGEDBY" CONTENT="Alex Peshkoff">
|
<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">
|
||||||
<META NAME="CHANGEDBY" CONTENT="Alex Peshkoff">
|
<META NAME="CHANGEDBY" CONTENT="Alex Peshkoff">
|
||||||
<STYLE TYPE="text/css">
|
<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 -
|
two public data members date and time of appropriate class, char -
|
||||||
with struct <A HREF="#FbChar">FbChar</A> and varchar – with struct
|
with struct <A HREF="#FbChar">FbChar</A> and varchar – with struct
|
||||||
<A HREF="#FbVarChar">FbVarChar</A>. For each field preprocessor
|
<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>
|
creates two data members in the message – </FONT><FONT SIZE=4><I>name</I></FONT>
|
||||||
for field/parameter value and </FONT><FONT SIZE=4><I>nameNull</I></FONT><FONT SIZE=4>
|
<FONT SIZE=4>for field/parameter value and </FONT><FONT SIZE=4><I>nameNull</I></FONT>
|
||||||
for NULL indicator. Message constructor has 2 parameters – pointer
|
<FONT SIZE=4>for NULL indicator. Message constructor has 2 parameters
|
||||||
to status wrapper and master interface:</FONT></P>
|
– pointer to status wrapper and master interface:</FONT></P>
|
||||||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4><I>FB_MESSAGE(Output,
|
<P STYLE="margin-bottom: 0in"><FONT SIZE=4><I>FB_MESSAGE(Output,
|
||||||
ThrowStatusWrapper,</I></FONT></P>
|
ThrowStatusWrapper,</I></FONT></P>
|
||||||
<P STYLE="margin-bottom: 0in"><FONT SIZE=4><I>(FB_SMALLINT,
|
<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>
|
next version. The minimum existing support is as follows: <A HREF="#Attachment">IAttachment</A>
|
||||||
contains call queEvents() which performs almost same functions as
|
contains call queEvents() which performs almost same functions as
|
||||||
isc_que_events() call. Instead the pair of parameters
|
isc_que_events() call. Instead the pair of parameters
|
||||||
</FONT><FONT SIZE=4><I>FPTR_EVENT_CALLBACK ast</I></FONT><FONT SIZE=4>
|
</FONT><FONT SIZE=4><I>FPTR_EVENT_CALLBACK ast</I></FONT> <FONT SIZE=4>and
|
||||||
and </FONT><FONT SIZE=4><I>void* arg</I></FONT><FONT SIZE=4>,
|
</FONT><FONT SIZE=4><I>void* arg</I></FONT><FONT SIZE=4>, required to
|
||||||
required to invoke user code when event happens in firebird engine,
|
invoke user code when event happens in firebird engine, callback
|
||||||
callback interface IEventCallback is used. This is traditional
|
interface IEventCallback is used. This is traditional approach which
|
||||||
approach which helps to avoid non-safe casts from void* in user
|
helps to avoid non-safe casts from void* in user function. Another
|
||||||
function. Another important difference is that instead event
|
important difference is that instead event identifier (a kind of
|
||||||
identifier (a kind of handler) this function returns reference
|
handler) this function returns reference counted interface <A HREF="#Events">IEvents</A>
|
||||||
counted interface <A HREF="#Events">IEvents</A> having method
|
having method cancel() used when waiting for event should be stopped.
|
||||||
cancel() used when waiting for event should be stopped. Unlike
|
Unlike identifier which is automatically destroyed when event arrives
|
||||||
identifier which is automatically destroyed when event arrives
|
|
||||||
interface can not be automatically destroyed – in case when event
|
interface can not be automatically destroyed – in case when event
|
||||||
is received right before canceling interface call to cancel() would
|
is received right before canceling interface call to cancel() would
|
||||||
cause segfault when interface is already destroyed. Therefore
|
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
|
<P STYLE="margin-bottom: 0in"><FONT SIZE=4>To write a plugin means to
|
||||||
implement some interfaces and place your implementation into dynamic
|
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
|
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
|
In most cases single plugin is place in dynamic library but in common
|
||||||
case. One of that interfaces – <A HREF="#PluginModule">IPluginModule</A>
|
case. One of that interfaces – <A HREF="#PluginModule">IPluginModule</A>
|
||||||
– is module-wide (as more or less clear from it's name), others are
|
– 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
|
operating system tries to unload one of that modules without explicit
|
||||||
plugin manager command (this may happen first of all when using
|
plugin manager command (this may happen first of all when using
|
||||||
embedded access – when exit() is called in a program or main
|
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>
|
firebird library </FONT><FONT SIZE=4><I><SPAN STYLE="font-weight: normal">fbclient</SPAN></I></FONT>
|
||||||
is unloaded). Primary task of IPluginModule interface is that
|
<FONT SIZE=4>is unloaded). Primary task of IPluginModule interface is
|
||||||
notification. First of all one must decide - how to detect that
|
that notification. First of all one must decide - how to detect that
|
||||||
module is going to be unloaded? When dynamic library is unloaded for
|
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
|
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
|
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
|
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>void
|
||||||
start(StatusType* status, ITimer* timer, ISC_UINT64 microSeconds) –
|
start(StatusType* status, ITimer* timer, ISC_UINT64 microSeconds) –
|
||||||
start <A HREF="#Timer">ITimer</A> to alarm after given delay (in
|
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>
|
microseconds, 10</FONT><SUP><FONT SIZE=4>-6</FONT></SUP> <FONT SIZE=4>seconds).
|
||||||
seconds). Timer will be waked up only once after this call.</FONT></P>
|
Timer will be waked up only once after this call.</FONT></P>
|
||||||
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>void stop(StatusType*
|
<LI><P STYLE="margin-bottom: 0in"><FONT SIZE=4>void stop(StatusType*
|
||||||
status, ITimer* timer) – stop <A HREF="#Timer">ITimer</A>. It's
|
status, ITimer* timer) – stop <A HREF="#Timer">ITimer</A>. It's
|
||||||
not an error to stop not started timer thus avoiding problems with
|
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
|
(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
|
a key to it in order to avoid use of modified crypt plugin able to
|
||||||
steal secret key.</FONT></P>
|
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>
|
</OL>
|
||||||
<P STYLE="margin-bottom: 0in"><BR>
|
<P STYLE="margin-bottom: 0in"><BR>
|
||||||
</P>
|
</P>
|
||||||
|
@ -108,6 +108,17 @@ public:
|
|||||||
return key;
|
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:
|
private:
|
||||||
class CallbackInterface : public ICryptKeyCallbackImpl<CallbackInterface, CheckStatusWrapper>
|
class CallbackInterface : public ICryptKeyCallbackImpl<CallbackInterface, CheckStatusWrapper>
|
||||||
{
|
{
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* PROGRAM: Firebird interface.
|
* PROGRAM: Firebird interface.
|
||||||
* MODULE: ImplementHelper.h
|
* MODULE: GetPlugins.h
|
||||||
* DESCRIPTION: Tools to help access plugins.
|
* DESCRIPTION: Tools to help access plugins.
|
||||||
*
|
*
|
||||||
* The contents of this file are subject to the Initial
|
* The contents of this file are subject to the Initial
|
||||||
@ -82,6 +82,16 @@ public:
|
|||||||
return currentPlugin;
|
return currentPlugin;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
P* makeInstance()
|
||||||
|
{
|
||||||
|
if (!hasData())
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
P* p = (P*) pluginSet->getPlugin(&status);
|
||||||
|
check(&status);
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
void next()
|
void next()
|
||||||
{
|
{
|
||||||
if (hasData())
|
if (hasData())
|
||||||
|
@ -732,6 +732,11 @@ interface KeyHolderPlugin : PluginBase
|
|||||||
// Missing key with given name is not an error condition for keyHandle().
|
// Missing key with given name is not an error condition for keyHandle().
|
||||||
// It should just return NULL in this case
|
// It should just return NULL in this case
|
||||||
CryptKeyCallback keyHandle(Status status, const string keyName);
|
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();
|
int (CLOOP_CARG *keyCallback)(IKeyHolderPlugin* self, IStatus* status, ICryptKeyCallback* callback) throw();
|
||||||
ICryptKeyCallback* (CLOOP_CARG *keyHandle)(IKeyHolderPlugin* self, IStatus* status, const char* keyName) throw();
|
ICryptKeyCallback* (CLOOP_CARG *keyHandle)(IKeyHolderPlugin* self, IStatus* status, const char* keyName) throw();
|
||||||
|
FB_BOOLEAN (CLOOP_CARG *useOnlyOwnKeys)(IKeyHolderPlugin* self, IStatus* status) throw();
|
||||||
};
|
};
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
@ -2918,7 +2919,7 @@ namespace Firebird
|
|||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static const unsigned VERSION = 4;
|
static const unsigned VERSION = 5;
|
||||||
|
|
||||||
template <typename StatusType> int keyCallback(StatusType* status, ICryptKeyCallback* callback)
|
template <typename StatusType> int keyCallback(StatusType* status, ICryptKeyCallback* callback)
|
||||||
{
|
{
|
||||||
@ -2935,6 +2936,20 @@ namespace Firebird
|
|||||||
StatusType::checkException(status);
|
StatusType::checkException(status);
|
||||||
return ret;
|
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
|
class IDbCryptInfo : public IReferenceCounted
|
||||||
@ -11230,6 +11245,7 @@ namespace Firebird
|
|||||||
this->getOwner = &Name::cloopgetOwnerDispatcher;
|
this->getOwner = &Name::cloopgetOwnerDispatcher;
|
||||||
this->keyCallback = &Name::cloopkeyCallbackDispatcher;
|
this->keyCallback = &Name::cloopkeyCallbackDispatcher;
|
||||||
this->keyHandle = &Name::cloopkeyHandleDispatcher;
|
this->keyHandle = &Name::cloopkeyHandleDispatcher;
|
||||||
|
this->useOnlyOwnKeys = &Name::cloopuseOnlyOwnKeysDispatcher;
|
||||||
}
|
}
|
||||||
} vTable;
|
} 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()
|
static void CLOOP_CARG cloopsetOwnerDispatcher(IPluginBase* self, IReferenceCounted* r) throw()
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
@ -11332,6 +11363,7 @@ namespace Firebird
|
|||||||
|
|
||||||
virtual int keyCallback(StatusType* status, ICryptKeyCallback* callback) = 0;
|
virtual int keyCallback(StatusType* status, ICryptKeyCallback* callback) = 0;
|
||||||
virtual ICryptKeyCallback* keyHandle(StatusType* status, const char* keyName) = 0;
|
virtual ICryptKeyCallback* keyHandle(StatusType* status, const char* keyName) = 0;
|
||||||
|
virtual FB_BOOLEAN useOnlyOwnKeys(StatusType* status) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename Name, typename StatusType, typename Base>
|
template <typename Name, typename StatusType, typename Base>
|
||||||
|
@ -265,10 +265,12 @@ namespace Jrd {
|
|||||||
: PermanentStorage(*tdbb->getDatabase()->dbb_permanent),
|
: PermanentStorage(*tdbb->getDatabase()->dbb_permanent),
|
||||||
sync(this),
|
sync(this),
|
||||||
keyName(getPool()),
|
keyName(getPool()),
|
||||||
keyHolderPlugins(getPool()),
|
keyHolderPlugins(getPool(), this),
|
||||||
|
hash(getPool()),
|
||||||
dbInfo(FB_NEW DbInfo(this)),
|
dbInfo(FB_NEW DbInfo(this)),
|
||||||
cryptThreadId(0),
|
cryptThreadId(0),
|
||||||
cryptPlugin(NULL),
|
cryptPlugin(NULL),
|
||||||
|
checkPlugin(NULL),
|
||||||
dbb(*tdbb->getDatabase()),
|
dbb(*tdbb->getDatabase()),
|
||||||
cryptAtt(NULL),
|
cryptAtt(NULL),
|
||||||
slowIO(0),
|
slowIO(0),
|
||||||
@ -364,14 +366,15 @@ namespace Jrd {
|
|||||||
loadPlugin(hdr->hdr_crypt_plugin);
|
loadPlugin(hdr->hdr_crypt_plugin);
|
||||||
|
|
||||||
string valid;
|
string valid;
|
||||||
calcValidation(valid);
|
calcValidation(valid, cryptPlugin);
|
||||||
if (hc.find(Ods::HDR_crypt_hash))
|
if (hc.find(Ods::HDR_crypt_hash))
|
||||||
{
|
{
|
||||||
string hash;
|
|
||||||
hc.getString(hash);
|
hc.getString(hash);
|
||||||
if (hash != valid)
|
if (hash != valid)
|
||||||
(Arg::Gds(isc_bad_crypt_key) << keyName).raise();
|
(Arg::Gds(isc_bad_crypt_key) << keyName).raise();
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
hash = valid;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (flags & CRYPT_HDR_INIT)
|
if (flags & CRYPT_HDR_INIT)
|
||||||
@ -409,9 +412,21 @@ namespace Jrd {
|
|||||||
status_exception::raise(&status);
|
status_exception::raise(&status);
|
||||||
}
|
}
|
||||||
|
|
||||||
keyHolderPlugins.init(p, keyName.c_str());
|
keyHolderPlugins.init(p, keyName);
|
||||||
cryptPlugin = p;
|
cryptPlugin = p;
|
||||||
cryptPlugin->addRef();
|
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,
|
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
|
// crypt verifier
|
||||||
const char* sample = "0123456789ABCDEF";
|
const char* sample = "0123456789ABCDEF";
|
||||||
char result[16];
|
char result[16];
|
||||||
FbLocalStatus sv;
|
FbLocalStatus sv;
|
||||||
cryptPlugin->encrypt(&sv, sizeof(result), sample, result);
|
plugin->encrypt(&sv, sizeof(result), sample, result);
|
||||||
if (sv->getState() & IStatus::STATE_ERRORS)
|
if (sv->getState() & IStatus::STATE_ERRORS)
|
||||||
Arg::StatusVector(&sv).raise();
|
Arg::StatusVector(&sv).raise();
|
||||||
|
|
||||||
@ -487,6 +502,13 @@ namespace Jrd {
|
|||||||
Sha1::hashBased64(valid, verifier);
|
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)
|
void CryptoManager::changeCryptState(thread_db* tdbb, const string& plugName)
|
||||||
{
|
{
|
||||||
if (plugName.length() > 31)
|
if (plugName.length() > 31)
|
||||||
@ -550,8 +572,7 @@ namespace Jrd {
|
|||||||
{
|
{
|
||||||
header->hdr_flags |= Ods::hdr_encrypted;
|
header->hdr_flags |= Ods::hdr_encrypted;
|
||||||
plugName.copyTo(header->hdr_crypt_plugin, sizeof(header->hdr_crypt_plugin));
|
plugName.copyTo(header->hdr_crypt_plugin, sizeof(header->hdr_crypt_plugin));
|
||||||
string hash;
|
calcValidation(hash, cryptPlugin);
|
||||||
calcValidation(hash);
|
|
||||||
hc.deleteWithTag(Ods::HDR_crypt_hash);
|
hc.deleteWithTag(Ods::HDR_crypt_hash);
|
||||||
hc.insertString(Ods::HDR_crypt_hash, hash);
|
hc.insertString(Ods::HDR_crypt_hash, hash);
|
||||||
|
|
||||||
@ -619,7 +640,15 @@ namespace Jrd {
|
|||||||
{
|
{
|
||||||
keyHolderPlugins.attach(att, dbb.dbb_config);
|
keyHolderPlugins.attach(att, dbb.dbb_config);
|
||||||
|
|
||||||
|
IDbCryptPlugin* p = checkPlugin;
|
||||||
|
|
||||||
lockAndReadHeader(tdbb, CRYPT_HDR_INIT);
|
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)
|
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);
|
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)
|
void CryptoManager::KeyHolderPlugins::attach(Attachment* att, Config* config)
|
||||||
{
|
{
|
||||||
MutexLockGuard g(holdersMutex, FB_FUNCTION);
|
MutexLockGuard g(holdersMutex, FB_FUNCTION);
|
||||||
@ -1184,31 +1170,42 @@ namespace Jrd {
|
|||||||
{
|
{
|
||||||
IKeyHolderPlugin* keyPlugin = keyControl.plugin();
|
IKeyHolderPlugin* keyPlugin = keyControl.plugin();
|
||||||
FbLocalStatus st;
|
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
|
st.check();
|
||||||
HolderAttachments* ha = NULL;
|
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)
|
for (unsigned i = 0; i < knownHolders.getCount(); ++i)
|
||||||
{
|
{
|
||||||
if (knownHolders[i] == keyPlugin)
|
if (knownHolders[i].first == att)
|
||||||
{
|
{
|
||||||
ha = &knownHolders[i];
|
pa = &knownHolders[i];
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!ha)
|
if ((!pa) && config->getServerMode() == MODE_SUPER)
|
||||||
{
|
{
|
||||||
ha = &(knownHolders.add());
|
pa = &(knownHolders.add());
|
||||||
ha->setPlugin(keyPlugin);
|
pa->first = att;
|
||||||
}
|
}
|
||||||
|
|
||||||
ha->registerAttachment(att);
|
if (pa)
|
||||||
break; // Do not need >1 key from attachment to single DB
|
{
|
||||||
|
pa->second.add(keyPlugin);
|
||||||
|
keyPlugin->addRef();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
|
||||||
st.check();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1216,33 +1213,130 @@ namespace Jrd {
|
|||||||
{
|
{
|
||||||
MutexLockGuard g(holdersMutex, FB_FUNCTION);
|
MutexLockGuard g(holdersMutex, FB_FUNCTION);
|
||||||
|
|
||||||
unsigned i = knownHolders.getCount();
|
for (unsigned i = 0; i < knownHolders.getCount(); ++i)
|
||||||
while (i--)
|
|
||||||
{
|
{
|
||||||
if (knownHolders[i].unregisterAttachment(att))
|
if (knownHolders[i].first == att)
|
||||||
{
|
{
|
||||||
|
releaseHolders(knownHolders[i]);
|
||||||
knownHolders.remove(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);
|
MutexLockGuard g(holdersMutex, FB_FUNCTION);
|
||||||
|
|
||||||
Firebird::HalfStaticArray<Firebird::IKeyHolderPlugin*, 64> holdersVector;
|
Firebird::HalfStaticArray<Firebird::IKeyHolderPlugin*, 64> holdersVector;
|
||||||
unsigned int length = knownHolders.getCount();
|
for (unsigned i = 0; i < knownHolders.getCount(); ++i)
|
||||||
IKeyHolderPlugin** vector = holdersVector.getBuffer(length);
|
|
||||||
for (unsigned i = 0; i < length; ++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;
|
FbLocalStatus st;
|
||||||
crypt->setKey(&st, length, vector, keyName);
|
crypt->setKey(&st, holdersVector.getCount(), holdersVector.begin(), keyName.c_str());
|
||||||
st.check();
|
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)
|
void CryptoManager::addClumplet(string& signature, ClumpletReader& block, UCHAR tag)
|
||||||
{
|
{
|
||||||
if (block.find(tag))
|
if (block.find(tag))
|
||||||
|
@ -294,6 +294,8 @@ public:
|
|||||||
|
|
||||||
void cryptThread();
|
void cryptThread();
|
||||||
|
|
||||||
|
bool checkValidation(Firebird::IDbCryptPlugin* crypt);
|
||||||
|
|
||||||
ULONG getCurrentPage() const;
|
ULONG getCurrentPage() const;
|
||||||
UCHAR getCurrentState() const;
|
UCHAR getCurrentState() const;
|
||||||
|
|
||||||
@ -319,42 +321,28 @@ private:
|
|||||||
char buf[MAX_PAGE_SIZE + PAGE_ALIGNMENT - 1];
|
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
|
class KeyHolderPlugins
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
explicit KeyHolderPlugins(Firebird::MemoryPool& p)
|
explicit KeyHolderPlugins(Firebird::MemoryPool& p, CryptoManager* m)
|
||||||
: knownHolders(p)
|
: knownHolders(p), mgr(m)
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
void attach(Attachment* att, Config* config);
|
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 detach(Attachment* att);
|
||||||
void init(Firebird::IDbCryptPlugin* crypt, const char* keyName);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Firebird::Mutex holdersMutex;
|
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;
|
class DbInfo;
|
||||||
@ -398,7 +386,8 @@ private:
|
|||||||
void loadPlugin(const char* pluginName);
|
void loadPlugin(const char* pluginName);
|
||||||
ULONG getLastPage(thread_db* tdbb);
|
ULONG getLastPage(thread_db* tdbb);
|
||||||
void writeDbHeader(thread_db* tdbb, ULONG runpage);
|
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);
|
void lockAndReadHeader(thread_db* tdbb, unsigned flags = 0);
|
||||||
static const unsigned CRYPT_HDR_INIT = 0x01;
|
static const unsigned CRYPT_HDR_INIT = 0x01;
|
||||||
@ -414,9 +403,11 @@ private:
|
|||||||
ULONG currentPage;
|
ULONG currentPage;
|
||||||
Firebird::Mutex pluginLoadMtx, cryptThreadMtx;
|
Firebird::Mutex pluginLoadMtx, cryptThreadMtx;
|
||||||
KeyHolderPlugins keyHolderPlugins;
|
KeyHolderPlugins keyHolderPlugins;
|
||||||
|
Firebird::string hash;
|
||||||
Firebird::RefPtr<DbInfo> dbInfo;
|
Firebird::RefPtr<DbInfo> dbInfo;
|
||||||
Thread::Handle cryptThreadId;
|
Thread::Handle cryptThreadId;
|
||||||
Firebird::IDbCryptPlugin* cryptPlugin;
|
Firebird::IDbCryptPlugin* cryptPlugin;
|
||||||
|
Firebird::IDbCryptPlugin* checkPlugin;
|
||||||
Database& dbb;
|
Database& dbb;
|
||||||
Lock* stateLock;
|
Lock* stateLock;
|
||||||
Lock* threadLock;
|
Lock* threadLock;
|
||||||
|
@ -101,6 +101,11 @@ namespace Jrd
|
|||||||
return localStatusVector.isEmpty();
|
return localStatusVector.isEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool isSuccess() const
|
||||||
|
{
|
||||||
|
return localStatusVector.isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Firebird::LocalStatus localStatus;
|
Firebird::LocalStatus localStatus;
|
||||||
SW localStatusVector;
|
SW localStatusVector;
|
||||||
|
Loading…
Reference in New Issue
Block a user