mirror of
https://github.com/FirebirdSQL/firebird.git
synced 2025-01-22 22:43:03 +01:00
Frontported CORE-5735: Additional keyholder opens unauthorized connections to encrypted database
This commit is contained in:
parent
50ad173172
commit
a8473b0ee3
@ -3787,12 +3787,12 @@ interface is main interface of database crypt key holder plugin.</font></p>
|
|||||||
<li/>
|
<li/>
|
||||||
<p style="margin-bottom: 0cm"><font size="4" style="font-size: 14pt">FB_BOOLEAN
|
<p style="margin-bottom: 0cm"><font size="4" style="font-size: 14pt">FB_BOOLEAN
|
||||||
useOnlyOwnKeys(StatusType* status) – informs firebird engine
|
useOnlyOwnKeys(StatusType* status) – informs firebird engine
|
||||||
whether a key, provided by another key holder, be used or not. Makes
|
whether a key, provided by key holder, can be used in other attachments.
|
||||||
sense only for SuperServer – only it can share database crypt keys
|
Makes sense only for SuperServer – only it can share database crypt keys
|
||||||
between attachments. Returning FB_TRUE from this method enforces
|
between attachments. Returning FB_TRUE from this method enforces
|
||||||
firebird to make sure that this particular key holder (and therefore
|
firebird to make sure that this particular key holder (and therefore
|
||||||
in turn attachment related to it) provides correct crypt key before
|
in turn attachment related to it) provides correct crypt key for
|
||||||
letting it to work with database.</font></p>
|
any other attachment to this database.</font></p>
|
||||||
<li/>
|
<li/>
|
||||||
<p style="margin-bottom: 0cm"><font size="4" style="font-size: 14pt">ICryptKeyCallback*
|
<p style="margin-bottom: 0cm"><font size="4" style="font-size: 14pt">ICryptKeyCallback*
|
||||||
chainHandle(StatusType* status) – support of a chain of key
|
chainHandle(StatusType* status) – support of a chain of key
|
||||||
|
@ -1818,6 +1818,8 @@ C --
|
|||||||
PARAMETER (GDS__hdr_overflow = 335545202)
|
PARAMETER (GDS__hdr_overflow = 335545202)
|
||||||
INTEGER*4 GDS__vld_plugins
|
INTEGER*4 GDS__vld_plugins
|
||||||
PARAMETER (GDS__vld_plugins = 335545203)
|
PARAMETER (GDS__vld_plugins = 335545203)
|
||||||
|
INTEGER*4 GDS__db_crypt_key
|
||||||
|
PARAMETER (GDS__db_crypt_key = 335545204)
|
||||||
INTEGER*4 GDS__gfix_db_name
|
INTEGER*4 GDS__gfix_db_name
|
||||||
PARAMETER (GDS__gfix_db_name = 335740929)
|
PARAMETER (GDS__gfix_db_name = 335740929)
|
||||||
INTEGER*4 GDS__gfix_invalid_sw
|
INTEGER*4 GDS__gfix_invalid_sw
|
||||||
|
@ -1813,6 +1813,8 @@ const
|
|||||||
gds_hdr_overflow = 335545202;
|
gds_hdr_overflow = 335545202;
|
||||||
isc_vld_plugins = 335545203;
|
isc_vld_plugins = 335545203;
|
||||||
gds_vld_plugins = 335545203;
|
gds_vld_plugins = 335545203;
|
||||||
|
isc_db_crypt_key = 335545204;
|
||||||
|
gds_db_crypt_key = 335545204;
|
||||||
isc_gfix_db_name = 335740929;
|
isc_gfix_db_name = 335740929;
|
||||||
gds_gfix_db_name = 335740929;
|
gds_gfix_db_name = 335740929;
|
||||||
isc_gfix_invalid_sw = 335740930;
|
isc_gfix_invalid_sw = 335740930;
|
||||||
|
@ -905,6 +905,7 @@ static const struct {
|
|||||||
{"map_overflow", 335545201},
|
{"map_overflow", 335545201},
|
||||||
{"hdr_overflow", 335545202},
|
{"hdr_overflow", 335545202},
|
||||||
{"vld_plugins", 335545203},
|
{"vld_plugins", 335545203},
|
||||||
|
{"db_crypt_key", 335545204},
|
||||||
{"gfix_db_name", 335740929},
|
{"gfix_db_name", 335740929},
|
||||||
{"gfix_invalid_sw", 335740930},
|
{"gfix_invalid_sw", 335740930},
|
||||||
{"gfix_incmp_sw", 335740932},
|
{"gfix_incmp_sw", 335740932},
|
||||||
|
@ -939,6 +939,7 @@ const ISC_STATUS isc_map_event = 335545200L;
|
|||||||
const ISC_STATUS isc_map_overflow = 335545201L;
|
const ISC_STATUS isc_map_overflow = 335545201L;
|
||||||
const ISC_STATUS isc_hdr_overflow = 335545202L;
|
const ISC_STATUS isc_hdr_overflow = 335545202L;
|
||||||
const ISC_STATUS isc_vld_plugins = 335545203L;
|
const ISC_STATUS isc_vld_plugins = 335545203L;
|
||||||
|
const ISC_STATUS isc_db_crypt_key = 335545204L;
|
||||||
const ISC_STATUS isc_gfix_db_name = 335740929L;
|
const ISC_STATUS isc_gfix_db_name = 335740929L;
|
||||||
const ISC_STATUS isc_gfix_invalid_sw = 335740930L;
|
const ISC_STATUS isc_gfix_invalid_sw = 335740930L;
|
||||||
const ISC_STATUS isc_gfix_incmp_sw = 335740932L;
|
const ISC_STATUS isc_gfix_incmp_sw = 335740932L;
|
||||||
@ -1413,7 +1414,7 @@ const ISC_STATUS isc_trace_switch_user_only = 337182757L;
|
|||||||
const ISC_STATUS isc_trace_switch_param_miss = 337182758L;
|
const ISC_STATUS isc_trace_switch_param_miss = 337182758L;
|
||||||
const ISC_STATUS isc_trace_param_act_notcompat = 337182759L;
|
const ISC_STATUS isc_trace_param_act_notcompat = 337182759L;
|
||||||
const ISC_STATUS isc_trace_mandatory_switch_miss = 337182760L;
|
const ISC_STATUS isc_trace_mandatory_switch_miss = 337182760L;
|
||||||
const ISC_STATUS isc_err_max = 1357;
|
const ISC_STATUS isc_err_max = 1358;
|
||||||
|
|
||||||
#else /* c definitions */
|
#else /* c definitions */
|
||||||
|
|
||||||
@ -2322,6 +2323,7 @@ const ISC_STATUS isc_err_max = 1357;
|
|||||||
#define isc_map_overflow 335545201L
|
#define isc_map_overflow 335545201L
|
||||||
#define isc_hdr_overflow 335545202L
|
#define isc_hdr_overflow 335545202L
|
||||||
#define isc_vld_plugins 335545203L
|
#define isc_vld_plugins 335545203L
|
||||||
|
#define isc_db_crypt_key 335545204L
|
||||||
#define isc_gfix_db_name 335740929L
|
#define isc_gfix_db_name 335740929L
|
||||||
#define isc_gfix_invalid_sw 335740930L
|
#define isc_gfix_invalid_sw 335740930L
|
||||||
#define isc_gfix_incmp_sw 335740932L
|
#define isc_gfix_incmp_sw 335740932L
|
||||||
@ -2796,7 +2798,7 @@ const ISC_STATUS isc_err_max = 1357;
|
|||||||
#define isc_trace_switch_param_miss 337182758L
|
#define isc_trace_switch_param_miss 337182758L
|
||||||
#define isc_trace_param_act_notcompat 337182759L
|
#define isc_trace_param_act_notcompat 337182759L
|
||||||
#define isc_trace_mandatory_switch_miss 337182760L
|
#define isc_trace_mandatory_switch_miss 337182760L
|
||||||
#define isc_err_max 1357
|
#define isc_err_max 1358
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -908,6 +908,7 @@ Data source : @4"}, /* eds_statement */
|
|||||||
{335545201, "Global mapping memory overflow"}, /* map_overflow */
|
{335545201, "Global mapping memory overflow"}, /* map_overflow */
|
||||||
{335545202, "Header page overflow - too many clumplets on it"}, /* hdr_overflow */
|
{335545202, "Header page overflow - too many clumplets on it"}, /* hdr_overflow */
|
||||||
{335545203, "No matching client/server authentication plugins configured for execute statement in embedded datasource"}, /* vld_plugins */
|
{335545203, "No matching client/server authentication plugins configured for execute statement in embedded datasource"}, /* vld_plugins */
|
||||||
|
{335545204, "Missing database encryption key for your attachment"}, /* db_crypt_key */
|
||||||
{335740929, "data base file name (@1) already given"}, /* gfix_db_name */
|
{335740929, "data base file name (@1) already given"}, /* gfix_db_name */
|
||||||
{335740930, "invalid switch @1"}, /* gfix_invalid_sw */
|
{335740930, "invalid switch @1"}, /* gfix_invalid_sw */
|
||||||
{335740932, "incompatible switch combination"}, /* gfix_incmp_sw */
|
{335740932, "incompatible switch combination"}, /* gfix_incmp_sw */
|
||||||
|
@ -904,6 +904,7 @@ static const struct {
|
|||||||
{335545201, -902}, /* 881 map_overflow */
|
{335545201, -902}, /* 881 map_overflow */
|
||||||
{335545202, -901}, /* 882 hdr_overflow */
|
{335545202, -901}, /* 882 hdr_overflow */
|
||||||
{335545203, -901}, /* 883 vld_plugins */
|
{335545203, -901}, /* 883 vld_plugins */
|
||||||
|
{335545204, -902}, /* 884 db_crypt_key */
|
||||||
{335740929, -901}, /* 1 gfix_db_name */
|
{335740929, -901}, /* 1 gfix_db_name */
|
||||||
{335740930, -901}, /* 2 gfix_invalid_sw */
|
{335740930, -901}, /* 2 gfix_invalid_sw */
|
||||||
{335740932, -901}, /* 4 gfix_incmp_sw */
|
{335740932, -901}, /* 4 gfix_incmp_sw */
|
||||||
|
@ -904,6 +904,7 @@ static const struct {
|
|||||||
{335545201, "54000"}, // 881 map_overflow
|
{335545201, "54000"}, // 881 map_overflow
|
||||||
{335545202, "54000"}, // 882 hdr_overflow
|
{335545202, "54000"}, // 882 hdr_overflow
|
||||||
{335545203, "28000"}, // 883 vld_plugins
|
{335545203, "28000"}, // 883 vld_plugins
|
||||||
|
{335545204, "08004"}, // 884 db_crypt_key
|
||||||
{335740929, "00000"}, // 1 gfix_db_name
|
{335740929, "00000"}, // 1 gfix_db_name
|
||||||
{335740930, "00000"}, // 2 gfix_invalid_sw
|
{335740930, "00000"}, // 2 gfix_invalid_sw
|
||||||
{335740932, "00000"}, // 4 gfix_incmp_sw
|
{335740932, "00000"}, // 4 gfix_incmp_sw
|
||||||
|
@ -278,7 +278,8 @@ namespace Jrd {
|
|||||||
: PermanentStorage(*tdbb->getDatabase()->dbb_permanent),
|
: PermanentStorage(*tdbb->getDatabase()->dbb_permanent),
|
||||||
sync(this),
|
sync(this),
|
||||||
keyName(getPool()),
|
keyName(getPool()),
|
||||||
keyHolderPlugins(getPool(), this),
|
keyProviders(getPool()),
|
||||||
|
keyConsumers(getPool()),
|
||||||
hash(getPool()),
|
hash(getPool()),
|
||||||
dbInfo(FB_NEW DbInfo(this)),
|
dbInfo(FB_NEW DbInfo(this)),
|
||||||
cryptThreadId(0),
|
cryptThreadId(0),
|
||||||
@ -430,7 +431,47 @@ namespace Jrd {
|
|||||||
IDbCryptPlugin* p = cryptControl->plugin();
|
IDbCryptPlugin* p = cryptControl->plugin();
|
||||||
setDbInfo(p);
|
setDbInfo(p);
|
||||||
|
|
||||||
keyHolderPlugins.init(p, keyName);
|
bool fLoad = false, fTry = false;
|
||||||
|
bool holderLess = false;
|
||||||
|
for (GetPlugins<IKeyHolderPlugin> keyControl(IPluginManager::TYPE_KEY_HOLDER, dbb.dbb_config);
|
||||||
|
keyControl.hasData(); keyControl.next())
|
||||||
|
{
|
||||||
|
IKeyHolderPlugin* keyPlugin = keyControl.plugin();
|
||||||
|
|
||||||
|
FbLocalStatus st;
|
||||||
|
int keyCallbackRc = keyPlugin->keyCallback(&st, tdbb->getAttachment()->att_crypt_callback);
|
||||||
|
st.check();
|
||||||
|
if (!keyCallbackRc)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
fTry = true;
|
||||||
|
p->setKey(&st, 1, &keyPlugin, keyName.c_str());
|
||||||
|
if (st.isSuccess())
|
||||||
|
{
|
||||||
|
if (!keyPlugin->useOnlyOwnKeys(&st))
|
||||||
|
{
|
||||||
|
MutexLockGuard g(holdersMutex, FB_FUNCTION);
|
||||||
|
keyProviders.push(tdbb->getAttachment());
|
||||||
|
}
|
||||||
|
fLoad = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!fTry)
|
||||||
|
{
|
||||||
|
FbLocalStatus status;
|
||||||
|
p->setKey(&status, 0, NULL, keyName.c_str());
|
||||||
|
if (status.isSuccess())
|
||||||
|
{
|
||||||
|
holderLess = true;
|
||||||
|
fLoad = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!fLoad)
|
||||||
|
Arg::Gds(isc_db_crypt_key).raise();
|
||||||
|
|
||||||
cryptPlugin = p;
|
cryptPlugin = p;
|
||||||
cryptPlugin->addRef();
|
cryptPlugin->addRef();
|
||||||
|
|
||||||
@ -439,11 +480,8 @@ namespace Jrd {
|
|||||||
checkFactory = NULL;
|
checkFactory = NULL;
|
||||||
|
|
||||||
// store new one
|
// store new one
|
||||||
if (dbb.dbb_config->getServerMode() == MODE_SUPER)
|
if (dbb.dbb_config->getServerMode() == MODE_SUPER && !holderLess)
|
||||||
{
|
|
||||||
checkFactory = cryptControl.release();
|
checkFactory = cryptControl.release();
|
||||||
keyHolderPlugins.validateNewAttachment(tdbb->getAttachment(), keyName);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CryptoManager::prepareChangeCryptState(thread_db* tdbb, const MetaName& plugName,
|
void CryptoManager::prepareChangeCryptState(thread_db* tdbb, const MetaName& plugName,
|
||||||
@ -598,7 +636,25 @@ namespace Jrd {
|
|||||||
hc.insertString(Ods::HDR_crypt_key, keyName);
|
hc.insertString(Ods::HDR_crypt_key, keyName);
|
||||||
|
|
||||||
if (checkFactory)
|
if (checkFactory)
|
||||||
keyHolderPlugins.validateExistingAttachments(keyName);
|
{
|
||||||
|
// Create local copy of existing attachments
|
||||||
|
AttVector existing;
|
||||||
|
{
|
||||||
|
SyncLockGuard dsGuard(&dbb.dbb_sync, SYNC_EXCLUSIVE, FB_FUNCTION);
|
||||||
|
for (Attachment* att = dbb.dbb_attachments; att; att = att->att_next)
|
||||||
|
existing.push(att);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Loop through attachments
|
||||||
|
MutexLockGuard g(holdersMutex, FB_FUNCTION);
|
||||||
|
|
||||||
|
for (unsigned n = 0; n < existing.getCount(); ++n)
|
||||||
|
validateAttachment(tdbb, existing[n], true);
|
||||||
|
|
||||||
|
// In case of missing providers close consumers
|
||||||
|
if (keyProviders.getCount() == 0)
|
||||||
|
shutdownConsumers(tdbb);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
header->hdr_flags &= ~Ods::hdr_encrypted;
|
header->hdr_flags &= ~Ods::hdr_encrypted;
|
||||||
@ -640,6 +696,16 @@ namespace Jrd {
|
|||||||
startCryptThread(tdbb);
|
startCryptThread(tdbb);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CryptoManager::shutdownConsumers(thread_db* tdbb)
|
||||||
|
{
|
||||||
|
MutexLockGuard g(holdersMutex, FB_FUNCTION);
|
||||||
|
|
||||||
|
for (unsigned i = 0; i < keyConsumers.getCount(); ++i)
|
||||||
|
keyConsumers[i]->signalShutdown(isc_db_crypt_key);
|
||||||
|
|
||||||
|
keyConsumers.clear();
|
||||||
|
}
|
||||||
|
|
||||||
void CryptoManager::blockingAstChangeCryptState()
|
void CryptoManager::blockingAstChangeCryptState()
|
||||||
{
|
{
|
||||||
AsyncContextHolder tdbb(&dbb, FB_FUNCTION);
|
AsyncContextHolder tdbb(&dbb, FB_FUNCTION);
|
||||||
@ -656,18 +722,94 @@ namespace Jrd {
|
|||||||
LCK_convert(tdbb, stateLock, CRYPT_RELEASE, LCK_NO_WAIT);
|
LCK_convert(tdbb, stateLock, CRYPT_RELEASE, LCK_NO_WAIT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool CryptoManager::validateAttachment(thread_db* tdbb, Attachment* att, bool consume)
|
||||||
|
{
|
||||||
|
bool fLoad = false, fProvide = false;
|
||||||
|
for (GetPlugins<IKeyHolderPlugin> keyControl(IPluginManager::TYPE_KEY_HOLDER, dbb.dbb_config);
|
||||||
|
keyControl.hasData(); keyControl.next())
|
||||||
|
{
|
||||||
|
// check does keyHolder want to provide a key for us
|
||||||
|
IKeyHolderPlugin* keyHolder = keyControl.plugin();
|
||||||
|
|
||||||
|
FbLocalStatus st;
|
||||||
|
int keyCallbackRc = keyHolder->keyCallback(&st, att->att_crypt_callback);
|
||||||
|
st.check();
|
||||||
|
if (!keyCallbackRc)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// validate a key
|
||||||
|
AutoPtr<IDbCryptPlugin, ReleasePlugin> crypt(checkFactory->makeInstance());
|
||||||
|
setDbInfo(crypt);
|
||||||
|
crypt->setKey(&st, 1, &keyHolder, keyName.c_str());
|
||||||
|
|
||||||
|
if (st.isSuccess())
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (checkValidation(crypt))
|
||||||
|
fLoad = true;
|
||||||
|
}
|
||||||
|
catch (const Exception&)
|
||||||
|
{ } // Ignore possible errors, continue analysis
|
||||||
|
|
||||||
|
if (fLoad)
|
||||||
|
fProvide = !keyHolder->useOnlyOwnKeys(&st);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apply results
|
||||||
|
|
||||||
|
if (fProvide)
|
||||||
|
keyProviders.push(att);
|
||||||
|
else if (consume && !fLoad)
|
||||||
|
keyConsumers.push(att);
|
||||||
|
|
||||||
|
return fLoad;
|
||||||
|
}
|
||||||
|
|
||||||
void CryptoManager::attach(thread_db* tdbb, Attachment* att)
|
void CryptoManager::attach(thread_db* tdbb, Attachment* att)
|
||||||
{
|
{
|
||||||
keyHolderPlugins.attach(att, dbb.dbb_config);
|
if (checkFactory)
|
||||||
|
{
|
||||||
|
MutexLockGuard g(holdersMutex, FB_FUNCTION);
|
||||||
|
|
||||||
Factory* f = checkFactory;
|
if (!validateAttachment(tdbb, att, false))
|
||||||
|
{
|
||||||
|
if (keyProviders.getCount() == 0)
|
||||||
|
Arg::Gds(isc_db_crypt_key).raise();
|
||||||
|
|
||||||
|
keyConsumers.push(att);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
lockAndReadHeader(tdbb, CRYPT_HDR_INIT);
|
lockAndReadHeader(tdbb, CRYPT_HDR_INIT);
|
||||||
|
}
|
||||||
|
|
||||||
if (f && f == checkFactory)
|
void CryptoManager::detach(thread_db* tdbb, Attachment* att)
|
||||||
{
|
{
|
||||||
if (!keyHolderPlugins.validateNewAttachment(att, keyName))
|
if (!checkFactory)
|
||||||
(Arg::Gds(isc_bad_crypt_key) << keyName).raise();
|
return;
|
||||||
|
|
||||||
|
MutexLockGuard g(holdersMutex, FB_FUNCTION);
|
||||||
|
for (unsigned n = 0; n < keyConsumers.getCount(); ++n)
|
||||||
|
{
|
||||||
|
if (keyConsumers[n] == att)
|
||||||
|
{
|
||||||
|
keyConsumers.remove(n);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (unsigned n = 0; n < keyProviders.getCount(); ++n)
|
||||||
|
{
|
||||||
|
if (keyProviders[n] == att)
|
||||||
|
{
|
||||||
|
keyProviders.remove(n);
|
||||||
|
if (keyProviders.getCount() == 0)
|
||||||
|
shutdownConsumers(tdbb);
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1193,203 +1335,6 @@ namespace Jrd {
|
|||||||
return keyName.c_str();
|
return keyName.c_str();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CryptoManager::KeyHolderPlugins::attach(Attachment* att, const Config* config)
|
|
||||||
{
|
|
||||||
MutexLockGuard g(holdersMutex, FB_FUNCTION);
|
|
||||||
|
|
||||||
for (GetPlugins<IKeyHolderPlugin> keyControl(IPluginManager::TYPE_KEY_HOLDER, config);
|
|
||||||
keyControl.hasData(); keyControl.next())
|
|
||||||
{
|
|
||||||
IKeyHolderPlugin* keyPlugin = keyControl.plugin();
|
|
||||||
FbLocalStatus st;
|
|
||||||
bool flProvide = false;
|
|
||||||
|
|
||||||
if (keyPlugin->keyCallback(&st, att->att_crypt_callback))
|
|
||||||
flProvide = true;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
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].first == att)
|
|
||||||
{
|
|
||||||
pa = &knownHolders[i];
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!pa)
|
|
||||||
{
|
|
||||||
pa = &(knownHolders.add());
|
|
||||||
pa->first = att;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pa)
|
|
||||||
{
|
|
||||||
pa->second.add(keyPlugin);
|
|
||||||
keyPlugin->addRef();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void CryptoManager::KeyHolderPlugins::detach(Attachment* att)
|
|
||||||
{
|
|
||||||
MutexLockGuard g(holdersMutex, FB_FUNCTION);
|
|
||||||
|
|
||||||
for (unsigned i = 0; i < knownHolders.getCount(); ++i)
|
|
||||||
{
|
|
||||||
if (knownHolders[i].first == att)
|
|
||||||
{
|
|
||||||
releaseHolders(knownHolders[i]);
|
|
||||||
knownHolders.remove(i);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
|
|
||||||
for (unsigned i = 0; i < knownHolders.getCount(); ++i)
|
|
||||||
{
|
|
||||||
PerAttHolders pa = knownHolders[i];
|
|
||||||
for (unsigned j = 0; j < pa.second.getCount(); ++j)
|
|
||||||
holdersVector.push(pa.second[j]);
|
|
||||||
}
|
|
||||||
|
|
||||||
FbLocalStatus st;
|
|
||||||
crypt->setKey(&st, holdersVector.getCount(), holdersVector.begin(), keyName.c_str());
|
|
||||||
st.check();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool CryptoManager::KeyHolderPlugins::validateHoldersGroup(PerAttHolders& pa, 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;
|
|
||||||
|
|
||||||
if (validateHolder(keyHolder, keyName))
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool CryptoManager::KeyHolderPlugins::validateNewAttachment(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, keyName);
|
|
||||||
|
|
||||||
if (empty)
|
|
||||||
break;
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Special case - holders not needed at all
|
|
||||||
return validateHolder(NULL, keyName);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool CryptoManager::KeyHolderPlugins::validateHolder(IKeyHolderPlugin* keyHolder, const MetaName& keyName)
|
|
||||||
{
|
|
||||||
fb_assert(mgr->checkFactory);
|
|
||||||
if (!mgr->checkFactory)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
FbLocalStatus st;
|
|
||||||
|
|
||||||
AutoPtr<IDbCryptPlugin, ReleasePlugin> crypt(mgr->checkFactory->makeInstance());
|
|
||||||
mgr->setDbInfo(crypt);
|
|
||||||
crypt->setKey(&st, keyHolder ? 1 : 0, &keyHolder, keyName.c_str());
|
|
||||||
|
|
||||||
if (st.isSuccess())
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if (mgr->checkValidation(crypt))
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
catch (const Exception&)
|
|
||||||
{ } // Ignore possible errors, continue analysis
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void CryptoManager::KeyHolderPlugins::validateExistingAttachments(const MetaName& keyName)
|
|
||||||
{
|
|
||||||
FbLocalStatus st;
|
|
||||||
|
|
||||||
// Special case - holders not needed at all
|
|
||||||
if (validateHolder(NULL, keyName))
|
|
||||||
return;
|
|
||||||
|
|
||||||
// Loop through whole attachments list of DBB, shutdown attachments missing any holders
|
|
||||||
fb_assert(!mgr->dbb.dbb_sync.isLocked());
|
|
||||||
MutexLockGuard g(holdersMutex, FB_FUNCTION);
|
|
||||||
SyncLockGuard dsGuard(&mgr->dbb.dbb_sync, SYNC_EXCLUSIVE, FB_FUNCTION);
|
|
||||||
for (Attachment* att = mgr->dbb.dbb_attachments; att; att = att->att_next)
|
|
||||||
{
|
|
||||||
bool found = false;
|
|
||||||
for (unsigned i = 0; i < knownHolders.getCount(); ++i)
|
|
||||||
{
|
|
||||||
if (knownHolders[i].first == att)
|
|
||||||
{
|
|
||||||
found = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!found)
|
|
||||||
att->signalShutdown(0 /* no special shutdown code */);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Loop through internal attachments list closing one missing valid holders
|
|
||||||
for (unsigned i = 0; i < knownHolders.getCount(); ++i)
|
|
||||||
{
|
|
||||||
if (!validateHoldersGroup(knownHolders[i], keyName))
|
|
||||||
knownHolders[i].first->signalShutdown(0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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))
|
||||||
|
@ -270,6 +270,7 @@ class CryptoManager FB_FINAL : public Firebird::PermanentStorage, public BarSync
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
typedef Firebird::GetPlugins<Firebird::IDbCryptPlugin> Factory;
|
typedef Firebird::GetPlugins<Firebird::IDbCryptPlugin> Factory;
|
||||||
|
typedef Firebird::HalfStaticArray<Attachment*, 16> AttVector;
|
||||||
|
|
||||||
explicit CryptoManager(thread_db* tdbb);
|
explicit CryptoManager(thread_db* tdbb);
|
||||||
~CryptoManager();
|
~CryptoManager();
|
||||||
@ -326,33 +327,6 @@ private:
|
|||||||
char buf[MAX_PAGE_SIZE + PAGE_ALIGNMENT - 1];
|
char buf[MAX_PAGE_SIZE + PAGE_ALIGNMENT - 1];
|
||||||
};
|
};
|
||||||
|
|
||||||
class KeyHolderPlugins
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
typedef CryptoManager::Factory Factory;
|
|
||||||
|
|
||||||
explicit KeyHolderPlugins(Firebird::MemoryPool& p, CryptoManager* m)
|
|
||||||
: knownHolders(p), mgr(m)
|
|
||||||
{ }
|
|
||||||
|
|
||||||
void attach(Attachment* att, const Config* config);
|
|
||||||
void init(Firebird::IDbCryptPlugin* crypt, const Firebird::MetaName& keyName);
|
|
||||||
bool validateNewAttachment(Attachment*, const Firebird::MetaName& keyName);
|
|
||||||
void validateExistingAttachments(const Firebird::MetaName& keyName);
|
|
||||||
void detach(Attachment* att);
|
|
||||||
|
|
||||||
private:
|
|
||||||
Firebird::Mutex holdersMutex;
|
|
||||||
typedef Firebird::Pair<Firebird::Right<Attachment*,
|
|
||||||
Firebird::HalfStaticArray<Firebird::IKeyHolderPlugin*, 4> > > PerAttHolders;
|
|
||||||
Firebird::ObjectsArray<PerAttHolders> knownHolders;
|
|
||||||
CryptoManager* mgr;
|
|
||||||
|
|
||||||
bool validateHoldersGroup(PerAttHolders& pa, const Firebird::MetaName& keyName);
|
|
||||||
bool validateHolder(Firebird::IKeyHolderPlugin* keyHolder, const Firebird::MetaName& keyName);
|
|
||||||
void releaseHolders(PerAttHolders& pa);
|
|
||||||
};
|
|
||||||
|
|
||||||
class DbInfo;
|
class DbInfo;
|
||||||
friend class DbInfo;
|
friend class DbInfo;
|
||||||
|
|
||||||
@ -392,10 +366,12 @@ private:
|
|||||||
void doOnAst(thread_db* tdbb);
|
void doOnAst(thread_db* tdbb);
|
||||||
|
|
||||||
void loadPlugin(thread_db* tdbb, const char* pluginName);
|
void loadPlugin(thread_db* tdbb, const char* pluginName);
|
||||||
|
bool validateAttachment(thread_db* tdbb, Attachment* att, bool consume);
|
||||||
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, Firebird::IDbCryptPlugin* plugin);
|
void calcValidation(Firebird::string& valid, Firebird::IDbCryptPlugin* plugin);
|
||||||
void checkValidation();
|
void checkValidation();
|
||||||
|
void shutdownConsumers(thread_db* tdbb);
|
||||||
|
|
||||||
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;
|
||||||
@ -409,8 +385,8 @@ private:
|
|||||||
BarSync sync;
|
BarSync sync;
|
||||||
Firebird::MetaName keyName;
|
Firebird::MetaName keyName;
|
||||||
ULONG currentPage;
|
ULONG currentPage;
|
||||||
Firebird::Mutex pluginLoadMtx, cryptThreadMtx;
|
Firebird::Mutex pluginLoadMtx, cryptThreadMtx, holdersMutex;
|
||||||
KeyHolderPlugins keyHolderPlugins;
|
AttVector keyProviders, keyConsumers;
|
||||||
Firebird::string hash;
|
Firebird::string hash;
|
||||||
Firebird::RefPtr<DbInfo> dbInfo;
|
Firebird::RefPtr<DbInfo> dbInfo;
|
||||||
Thread::Handle cryptThreadId;
|
Thread::Handle cryptThreadId;
|
||||||
|
@ -6925,6 +6925,9 @@ static void release_attachment(thread_db* tdbb, Jrd::Attachment* attachment)
|
|||||||
if (!attachment)
|
if (!attachment)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
if (dbb->dbb_crypto_manager)
|
||||||
|
dbb->dbb_crypto_manager->detach(tdbb, attachment);
|
||||||
|
|
||||||
Monitoring::cleanupAttachment(tdbb);
|
Monitoring::cleanupAttachment(tdbb);
|
||||||
|
|
||||||
dbb->dbb_extManager.closeAttachment(tdbb, attachment);
|
dbb->dbb_extManager.closeAttachment(tdbb, attachment);
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/* MAX_NUMBER is the next number to be used, always one more than the highest message number. */
|
/* MAX_NUMBER is the next number to be used, always one more than the highest message number. */
|
||||||
set bulk_insert INSERT INTO FACILITIES (LAST_CHANGE, FACILITY, FAC_CODE, MAX_NUMBER) VALUES (?, ?, ?, ?);
|
set bulk_insert INSERT INTO FACILITIES (LAST_CHANGE, FACILITY, FAC_CODE, MAX_NUMBER) VALUES (?, ?, ?, ?);
|
||||||
--
|
--
|
||||||
('2017-11-10 18:40:00', 'JRD', 0, 884)
|
('2018-02-01 17:40:00', 'JRD', 0, 885)
|
||||||
('2015-03-17 18:33:00', 'QLI', 1, 533)
|
('2015-03-17 18:33:00', 'QLI', 1, 533)
|
||||||
('2015-01-07 18:01:51', 'GFIX', 3, 134)
|
('2015-01-07 18:01:51', 'GFIX', 3, 134)
|
||||||
('1996-11-07 13:39:40', 'GPRE', 4, 1)
|
('1996-11-07 13:39:40', 'GPRE', 4, 1)
|
||||||
|
@ -991,6 +991,7 @@ Data source : @4', NULL, NULL)
|
|||||||
('map_overflow', NULL, 'Mapping.cpp', NULL, 0, 881, NULL, 'Global mapping memory overflow', NULL, NULL);
|
('map_overflow', NULL, 'Mapping.cpp', NULL, 0, 881, NULL, 'Global mapping memory overflow', NULL, NULL);
|
||||||
('hdr_overflow', NULL, 'CryptoManager.cpp', NULL, 0, 882, NULL, 'Header page overflow - too many clumplets on it', NULL, NULL);
|
('hdr_overflow', NULL, 'CryptoManager.cpp', NULL, 0, 882, NULL, 'Header page overflow - too many clumplets on it', NULL, NULL);
|
||||||
('vld_plugins', NULL, 'ValidatePassword.cpp', NULL, 0, 883, NULL, 'No matching client/server authentication plugins configured for execute statement in embedded datasource', NULL, NULL);
|
('vld_plugins', NULL, 'ValidatePassword.cpp', NULL, 0, 883, NULL, 'No matching client/server authentication plugins configured for execute statement in embedded datasource', NULL, NULL);
|
||||||
|
('db_crypt_key', NULL, 'CryptoManager.cpp', NULL, 0, 884, NULL, 'Missing database encryption key for your attachment', NULL, NULL);
|
||||||
-- QLI
|
-- QLI
|
||||||
(NULL, NULL, NULL, NULL, 1, 0, NULL, 'expected type', NULL, NULL);
|
(NULL, NULL, NULL, NULL, 1, 0, NULL, 'expected type', NULL, NULL);
|
||||||
(NULL, NULL, NULL, NULL, 1, 1, NULL, 'bad block type', NULL, NULL);
|
(NULL, NULL, NULL, NULL, 1, 1, NULL, 'bad block type', NULL, NULL);
|
||||||
|
@ -890,6 +890,7 @@ set bulk_insert INSERT INTO SYSTEM_ERRORS (SQL_CODE, SQL_CLASS, SQL_SUBCLASS, FA
|
|||||||
(-902, '54', '000', 0, 881, 'map_overflow', NULL, NULL)
|
(-902, '54', '000', 0, 881, 'map_overflow', NULL, NULL)
|
||||||
(-901, '54', '000', 0, 882, 'hdr_overflow', NULL, NULL)
|
(-901, '54', '000', 0, 882, 'hdr_overflow', NULL, NULL)
|
||||||
(-901, '28', '000', 0, 883, 'vld_plugins', NULL, NULL)
|
(-901, '28', '000', 0, 883, 'vld_plugins', NULL, NULL)
|
||||||
|
(-902, '08', '004', 0, 884, 'db_crypt_key', NULL, NULL)
|
||||||
-- GFIX
|
-- GFIX
|
||||||
(-901, '00', '000', 3, 1, 'gfix_db_name', NULL, NULL)
|
(-901, '00', '000', 3, 1, 'gfix_db_name', NULL, NULL)
|
||||||
(-901, '00', '000', 3, 2, 'gfix_invalid_sw', NULL, NULL)
|
(-901, '00', '000', 3, 2, 'gfix_invalid_sw', NULL, NULL)
|
||||||
|
@ -194,6 +194,21 @@ public:
|
|||||||
if (networkCallback.isStopped())
|
if (networkCallback.isStopped())
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
Reference r(*port);
|
||||||
|
loadClientKey();
|
||||||
|
unsigned rc = keyCallback ?
|
||||||
|
keyCallback->callback(dataLength, data, bufferLength, buffer) :
|
||||||
|
// use legacy behavior if holders to do wish to accept keys from client
|
||||||
|
networkCallback.callback(dataLength, data, bufferLength, buffer);
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
void loadClientKey()
|
||||||
|
{
|
||||||
|
if (keyCallback)
|
||||||
|
return;
|
||||||
|
|
||||||
Reference r(*port);
|
Reference r(*port);
|
||||||
|
|
||||||
for (GetPlugins<IKeyHolderPlugin> kh(IPluginManager::TYPE_KEY_HOLDER, port->getPortConfig());
|
for (GetPlugins<IKeyHolderPlugin> kh(IPluginManager::TYPE_KEY_HOLDER, port->getPortConfig());
|
||||||
@ -215,14 +230,6 @@ public:
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned rc = keyCallback ?
|
|
||||||
keyCallback->callback(dataLength, data, bufferLength, buffer) :
|
|
||||||
// use legacy behavior if holders to do wish to accept keys from client
|
|
||||||
networkCallback.callback(dataLength, data, bufferLength, buffer);
|
|
||||||
|
|
||||||
//stop();
|
|
||||||
return rc;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void wakeup(unsigned int length, const void* data)
|
void wakeup(unsigned int length, const void* data)
|
||||||
@ -259,6 +266,7 @@ public:
|
|||||||
|
|
||||||
ICryptKeyCallback* getInterface()
|
ICryptKeyCallback* getInterface()
|
||||||
{
|
{
|
||||||
|
cryptCallback.loadClientKey();
|
||||||
return &cryptCallback;
|
return &cryptCallback;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user