mirror of
https://github.com/FirebirdSQL/firebird.git
synced 2025-01-22 18:43:02 +01:00
Implemented CORE-5100: Improve control over database crypt keys
This commit is contained in:
parent
91f7b5ec56
commit
bebf1d5a70
@ -85,7 +85,7 @@ class CryptKeyHolder : public IKeyHolderPluginImpl<CryptKeyHolder, CheckStatusWr
|
||||
{
|
||||
public:
|
||||
explicit CryptKeyHolder(IPluginConfig* cnf) throw()
|
||||
: callbackInterface(this), config(cnf), key(0), owner(NULL)
|
||||
: callbackInterface(this), named(NULL), config(cnf), key(0), owner(NULL)
|
||||
{
|
||||
config->addRef();
|
||||
}
|
||||
@ -139,12 +139,12 @@ private:
|
||||
{
|
||||
public:
|
||||
explicit CallbackInterface(CryptKeyHolder* p)
|
||||
: parent(p)
|
||||
: holder(p)
|
||||
{ }
|
||||
|
||||
unsigned int callback(unsigned int, const void*, unsigned int length, void* buffer)
|
||||
{
|
||||
UCHAR k = parent->getKey();
|
||||
UCHAR k = holder->getKey();
|
||||
if (!k)
|
||||
{
|
||||
return 0;
|
||||
@ -157,16 +157,38 @@ private:
|
||||
return 1;
|
||||
}
|
||||
|
||||
IPluginModule* getModule()
|
||||
private:
|
||||
CryptKeyHolder* holder;
|
||||
};
|
||||
|
||||
class NamedCallback : public ICryptKeyCallbackImpl<NamedCallback, CheckStatusWrapper>
|
||||
{
|
||||
public:
|
||||
NamedCallback(NamedCallback *n, const char* nm, UCHAR k)
|
||||
: next(n), key(k)
|
||||
{
|
||||
return &module;
|
||||
strncpy(name, nm, sizeof(name));
|
||||
name[sizeof(name) - 1] = 0;
|
||||
}
|
||||
|
||||
private:
|
||||
CryptKeyHolder* parent;
|
||||
unsigned int callback(unsigned int, const void*, unsigned int length, void* buffer)
|
||||
{
|
||||
memcpy(buffer, &key, 1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
~NamedCallback()
|
||||
{
|
||||
delete next;
|
||||
}
|
||||
|
||||
char name[32];
|
||||
NamedCallback* next;
|
||||
UCHAR key;
|
||||
};
|
||||
|
||||
CallbackInterface callbackInterface;
|
||||
NamedCallback *named;
|
||||
|
||||
IPluginConfig* config;
|
||||
UCHAR key;
|
||||
@ -174,18 +196,21 @@ private:
|
||||
AtomicCounter refCounter;
|
||||
IReferenceCounted* owner;
|
||||
|
||||
void noKeyError(CheckStatusWrapper* status);
|
||||
IConfigEntry* getEntry(CheckStatusWrapper* status, const char* entryName);
|
||||
};
|
||||
|
||||
void CryptKeyHolder::noKeyError(CheckStatusWrapper* status)
|
||||
IConfigEntry* CryptKeyHolder::getEntry(CheckStatusWrapper* status, const char* entryName)
|
||||
{
|
||||
ISC_STATUS_ARRAY vector;
|
||||
vector[0] = isc_arg_gds;
|
||||
vector[1] = isc_random;
|
||||
vector[2] = isc_arg_string;
|
||||
vector[3] = (ISC_STATUS) "Key not set";
|
||||
vector[4] = isc_arg_end;
|
||||
status->setErrors(vector);
|
||||
IConfig* def = config->getDefaultConfig(status);
|
||||
if (status->getState() & Firebird::IStatus::STATE_ERRORS)
|
||||
return NULL;
|
||||
|
||||
IConfigEntry* confEntry = def->find(status, entryName);
|
||||
def->release();
|
||||
if (status->getState() & Firebird::IStatus::STATE_ERRORS)
|
||||
return NULL;
|
||||
|
||||
return confEntry;
|
||||
}
|
||||
|
||||
int CryptKeyHolder::keyCallback(CheckStatusWrapper* status, ICryptKeyCallback* callback)
|
||||
@ -195,14 +220,7 @@ int CryptKeyHolder::keyCallback(CheckStatusWrapper* status, ICryptKeyCallback* c
|
||||
if (key != 0)
|
||||
return 1;
|
||||
|
||||
IConfig* def = config->getDefaultConfig(status);
|
||||
if (status->getState() & Firebird::IStatus::STATE_ERRORS)
|
||||
return 1;
|
||||
|
||||
IConfigEntry* confEntry = def->find(status, "Auto");
|
||||
def->release();
|
||||
if (status->getState() & Firebird::IStatus::STATE_ERRORS)
|
||||
return 1;
|
||||
IConfigEntry* confEntry = getEntry(status, "Auto");
|
||||
|
||||
if (confEntry)
|
||||
{
|
||||
@ -226,12 +244,33 @@ int CryptKeyHolder::keyCallback(CheckStatusWrapper* status, ICryptKeyCallback* c
|
||||
|
||||
ICryptKeyCallback* CryptKeyHolder::keyHandle(CheckStatusWrapper* status, const char* keyName)
|
||||
{
|
||||
if (strcmp(keyName, "sample") != 0)
|
||||
if (keyName[0] == 0)
|
||||
return &callbackInterface;
|
||||
|
||||
for (NamedCallback* n = named; n; n = n->next)
|
||||
{
|
||||
return NULL;
|
||||
if (strcmp(keyName, n->name) == 0)
|
||||
return n;
|
||||
}
|
||||
|
||||
return &callbackInterface;
|
||||
char kn[40];
|
||||
strcpy(kn, "Key");
|
||||
strncat(kn, keyName, sizeof(kn));
|
||||
kn[sizeof(kn) - 1] = 0;
|
||||
|
||||
IConfigEntry* confEntry = getEntry(status, kn);
|
||||
if (confEntry)
|
||||
{
|
||||
UCHAR k = confEntry->getIntValue();
|
||||
confEntry->release();
|
||||
if (k > 0 && k < 256)
|
||||
{
|
||||
named = new NamedCallback(named, keyName, static_cast<UCHAR>(k));
|
||||
return named;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
class Factory : public IPluginFactoryImpl<Factory, CheckStatusWrapper>
|
||||
|
@ -95,7 +95,8 @@ public:
|
||||
// ICryptPlugin implementation
|
||||
void encrypt(CheckStatusWrapper* status, unsigned int length, const void* from, void* to);
|
||||
void decrypt(CheckStatusWrapper* status, unsigned int length, const void* from, void* to);
|
||||
void setKey(CheckStatusWrapper* status, unsigned int length, IKeyHolderPlugin** sources);
|
||||
void setKey(CheckStatusWrapper* status, const char* keyName,
|
||||
unsigned int length, IKeyHolderPlugin** sources);
|
||||
|
||||
int release()
|
||||
{
|
||||
@ -129,6 +130,7 @@ public:
|
||||
|
||||
private:
|
||||
IPluginConfig* config;
|
||||
char savedKeyName[32];
|
||||
UCHAR key;
|
||||
|
||||
AtomicCounter refCounter;
|
||||
@ -139,11 +141,20 @@ private:
|
||||
|
||||
void DbCrypt::noKeyError(CheckStatusWrapper* status)
|
||||
{
|
||||
char msg[100];
|
||||
strcpy(msg, "Crypt key ");
|
||||
if (savedKeyName[0])
|
||||
{
|
||||
strcat(msg, savedKeyName);
|
||||
strcat(msg, " ");
|
||||
}
|
||||
strcat(msg, "not set");
|
||||
|
||||
ISC_STATUS_ARRAY vector;
|
||||
vector[0] = isc_arg_gds;
|
||||
vector[1] = isc_random;
|
||||
vector[2] = isc_arg_string;
|
||||
vector[3] = (ISC_STATUS)"Key not set";
|
||||
vector[3] = (ISC_STATUS)msg;
|
||||
vector[4] = isc_arg_end;
|
||||
status->setErrors(vector);
|
||||
}
|
||||
@ -186,13 +197,17 @@ void DbCrypt::decrypt(CheckStatusWrapper* status, unsigned int length, const voi
|
||||
}
|
||||
}
|
||||
|
||||
void DbCrypt::setKey(CheckStatusWrapper* status, unsigned int length, IKeyHolderPlugin** sources)
|
||||
void DbCrypt::setKey(CheckStatusWrapper* status, const char* keyName,
|
||||
unsigned int length, IKeyHolderPlugin** sources)
|
||||
{
|
||||
status->init();
|
||||
|
||||
if (key != 0)
|
||||
return;
|
||||
|
||||
strncpy(savedKeyName, keyName ? keyName : "", sizeof(savedKeyName));
|
||||
savedKeyName[sizeof(savedKeyName) - 1] = 0;
|
||||
|
||||
IConfig* def = config->getDefaultConfig(status);
|
||||
if (status->getState() & Firebird::IStatus::STATE_ERRORS)
|
||||
return;
|
||||
@ -230,7 +245,7 @@ void DbCrypt::setKey(CheckStatusWrapper* status, unsigned int length, IKeyHolder
|
||||
|
||||
for (unsigned n = 0; n < length; ++n)
|
||||
{
|
||||
ICryptKeyCallback* callback = sources[n]->keyHandle(status, "sample");
|
||||
ICryptKeyCallback* callback = sources[n]->keyHandle(status, savedKeyName);
|
||||
if (status->getState() & Firebird::IStatus::STATE_ERRORS)
|
||||
return;
|
||||
|
||||
|
@ -1626,6 +1626,10 @@ C --
|
||||
PARAMETER (GDS__login_error = 335545106)
|
||||
INTEGER*4 GDS__already_opened
|
||||
PARAMETER (GDS__already_opened = 335545107)
|
||||
INTEGER*4 GDS__bad_crypt_key
|
||||
PARAMETER (GDS__bad_crypt_key = 335545108)
|
||||
INTEGER*4 GDS__encrypt_error
|
||||
PARAMETER (GDS__encrypt_error = 335545109)
|
||||
INTEGER*4 GDS__gfix_db_name
|
||||
PARAMETER (GDS__gfix_db_name = 335740929)
|
||||
INTEGER*4 GDS__gfix_invalid_sw
|
||||
|
@ -1621,6 +1621,10 @@ const
|
||||
gds_login_error = 335545106;
|
||||
isc_already_opened = 335545107;
|
||||
gds_already_opened = 335545107;
|
||||
isc_bad_crypt_key = 335545108;
|
||||
gds_bad_crypt_key = 335545108;
|
||||
isc_encrypt_error = 335545109;
|
||||
gds_encrypt_error = 335545109;
|
||||
isc_gfix_db_name = 335740929;
|
||||
gds_gfix_db_name = 335740929;
|
||||
isc_gfix_invalid_sw = 335740930;
|
||||
|
@ -29,6 +29,7 @@
|
||||
#include "firebird.h"
|
||||
|
||||
#include "../common/classes/ClumpletReader.h"
|
||||
#include "../common/classes/MetaName.h"
|
||||
#include "fb_exception.h"
|
||||
|
||||
#include "../jrd/ibase.h"
|
||||
@ -784,6 +785,14 @@ string& ClumpletReader::getString(string& str) const
|
||||
return str;
|
||||
}
|
||||
|
||||
MetaName& ClumpletReader::getString(MetaName& str) const
|
||||
{
|
||||
const UCHAR* ptr = getBytes();
|
||||
const FB_SIZE_T length = getClumpLength();
|
||||
str.assign(reinterpret_cast<const char*>(ptr), length);
|
||||
return str;
|
||||
}
|
||||
|
||||
PathName& ClumpletReader::getPath(PathName& str) const
|
||||
{
|
||||
const UCHAR* ptr = getBytes();
|
||||
|
@ -40,6 +40,8 @@
|
||||
|
||||
namespace Firebird {
|
||||
|
||||
class MetaName;
|
||||
|
||||
// This class provides read access for clumplet structure
|
||||
// Note: it doesn't make a copy of buffer it reads
|
||||
class ClumpletReader : protected AutoStorage
|
||||
@ -100,6 +102,7 @@ public:
|
||||
bool getBoolean() const;
|
||||
SINT64 getBigInt() const;
|
||||
string& getString(string& str) const;
|
||||
MetaName& getString(MetaName& str) const;
|
||||
PathName& getPath(PathName& str) const;
|
||||
void getData(UCharBuffer& data) const;
|
||||
const UCHAR* getBytes() const;
|
||||
|
@ -30,6 +30,7 @@
|
||||
#include "firebird.h"
|
||||
|
||||
#include "../common/classes/ClumpletWriter.h"
|
||||
#include "../common/classes/MetaName.h"
|
||||
#include "fb_exception.h"
|
||||
|
||||
#include "../jrd/ibase.h"
|
||||
@ -183,7 +184,7 @@ void ClumpletWriter::reset(const UCHAR* buffer, const FB_SIZE_T buffLen)
|
||||
}
|
||||
else
|
||||
{
|
||||
UCHAR tag = (kind == SpbStart || kind == UnTagged || kind == WideUnTagged) ? getBufferTag() : 0;
|
||||
UCHAR tag = (kind == SpbStart || kind == UnTagged || kind == WideUnTagged) ? 0 : getBufferTag();
|
||||
initNewBuffer(tag);
|
||||
}
|
||||
rewind();
|
||||
@ -250,16 +251,26 @@ void ClumpletWriter::insertString(UCHAR tag, const string& str)
|
||||
insertString(tag, str.c_str(), str.length());
|
||||
}
|
||||
|
||||
void ClumpletWriter::insertPath(UCHAR tag, const PathName& str)
|
||||
void ClumpletWriter::insertString(UCHAR tag, const MetaName& str)
|
||||
{
|
||||
insertString(tag, str.c_str(), str.length());
|
||||
}
|
||||
|
||||
void ClumpletWriter::insertString(UCHAR tag, const char* str)
|
||||
{
|
||||
insertString(tag, str, strlen(str));
|
||||
}
|
||||
|
||||
void ClumpletWriter::insertString(UCHAR tag, const char* str, FB_SIZE_T length)
|
||||
{
|
||||
insertBytesLengthCheck(tag, str, length);
|
||||
}
|
||||
|
||||
void ClumpletWriter::insertPath(UCHAR tag, const PathName& str)
|
||||
{
|
||||
insertString(tag, str.c_str(), str.length());
|
||||
}
|
||||
|
||||
void ClumpletWriter::insertBytes(UCHAR tag, const void* bytes, FB_SIZE_T length)
|
||||
{
|
||||
insertBytesLengthCheck(tag, bytes, length);
|
||||
|
@ -73,7 +73,9 @@ public:
|
||||
void insertBigInt(UCHAR tag, const SINT64 value);
|
||||
void insertBytes(UCHAR tag, const void* bytes, FB_SIZE_T length);
|
||||
void insertString(UCHAR tag, const string& str);
|
||||
void insertString(UCHAR tag, const MetaName& str);
|
||||
void insertPath(UCHAR tag, const PathName& str);
|
||||
void insertString(UCHAR tag, const char* str);
|
||||
void insertString(UCHAR tag, const char* str, FB_SIZE_T length);
|
||||
void insertByte(UCHAR tag, const UCHAR byte);
|
||||
void insertTag(UCHAR tag);
|
||||
|
@ -11577,6 +11577,7 @@ string AlterDatabaseNode::internalPrint(NodePrinter& printer) const
|
||||
NODE_PRINT(printer, setDefaultCollation);
|
||||
NODE_PRINT(printer, files);
|
||||
NODE_PRINT(printer, cryptPlugin);
|
||||
NODE_PRINT(printer, keyName);
|
||||
|
||||
return "AlterDatabaseNode";
|
||||
}
|
||||
@ -11660,7 +11661,7 @@ void AlterDatabaseNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratc
|
||||
if (clauses & CLAUSE_CRYPT)
|
||||
{
|
||||
Database* const db = tdbb->getDatabase();
|
||||
db->dbb_crypto_manager->prepareChangeCryptState(tdbb, cryptPlugin);
|
||||
db->dbb_crypto_manager->prepareChangeCryptState(tdbb, cryptPlugin, keyName);
|
||||
|
||||
DFW_post_work(transaction, dfw_db_crypt, cryptPlugin.c_str(), 0);
|
||||
}
|
||||
|
@ -2228,7 +2228,8 @@ public:
|
||||
setDefaultCharSet(p),
|
||||
setDefaultCollation(p),
|
||||
files(p),
|
||||
cryptPlugin(p)
|
||||
cryptPlugin(p),
|
||||
keyName(p)
|
||||
{
|
||||
}
|
||||
|
||||
@ -2263,6 +2264,7 @@ public:
|
||||
Firebird::MetaName setDefaultCollation;
|
||||
Firebird::Array<NestConst<DbFileClause> > files;
|
||||
Firebird::MetaName cryptPlugin;
|
||||
Firebird::MetaName keyName;
|
||||
};
|
||||
|
||||
|
||||
|
@ -3961,7 +3961,7 @@ db_alter_clause($alterDatabaseNode)
|
||||
{ $alterDatabaseNode->clauses |= AlterDatabaseNode::CLAUSE_END_BACKUP; }
|
||||
| SET DEFAULT CHARACTER SET symbol_character_set_name
|
||||
{ $alterDatabaseNode->setDefaultCharSet = *$5; }
|
||||
| ENCRYPT WITH valid_symbol_name
|
||||
| ENCRYPT WITH valid_symbol_name crypt_key_clause($alterDatabaseNode)
|
||||
{
|
||||
setClauseFlag($alterDatabaseNode->clauses, AlterDatabaseNode::CLAUSE_CRYPT, "CRYPT");
|
||||
$alterDatabaseNode->cryptPlugin = *$3;
|
||||
@ -3974,6 +3974,12 @@ db_alter_clause($alterDatabaseNode)
|
||||
{ $alterDatabaseNode->linger = 0; }
|
||||
;
|
||||
|
||||
%type crypt_key_clause(<alterDatabaseNode>)
|
||||
crypt_key_clause($alterDatabaseNode)
|
||||
: /* nothing */
|
||||
| KEY valid_symbol_name
|
||||
{ $alterDatabaseNode->keyName = *$2; }
|
||||
;
|
||||
|
||||
// ALTER TRIGGER
|
||||
|
||||
|
@ -720,11 +720,11 @@ interface KeyHolderPlugin : PluginBase
|
||||
interface DbCryptPlugin : PluginBase
|
||||
{
|
||||
// When database crypt plugin is loaded, setKey() is called to provide information
|
||||
// about key holders, available for a given database.
|
||||
// about key holders, available for a given database and key name for database.
|
||||
// It's supposed that crypt plugin will invoke keyHandle() function from them
|
||||
// to access callback interface for getting actual crypt key.
|
||||
// If crypt plugin fails to find appropriate key in sources, it should raise error.
|
||||
void setKey(Status status, uint length, KeyHolderPlugin* sources);
|
||||
void setKey(Status status, const string keyName, uint length, KeyHolderPlugin* sources);
|
||||
void encrypt(Status status, uint length, const void* from, void* to);
|
||||
void decrypt(Status status, uint length, const void* from, void* to);
|
||||
}
|
||||
|
@ -2871,7 +2871,7 @@ namespace Firebird
|
||||
public:
|
||||
struct VTable : public IPluginBase::VTable
|
||||
{
|
||||
void (CLOOP_CARG *setKey)(IDbCryptPlugin* self, IStatus* status, unsigned length, IKeyHolderPlugin** sources) throw();
|
||||
void (CLOOP_CARG *setKey)(IDbCryptPlugin* self, IStatus* status, const char* keyName, unsigned length, IKeyHolderPlugin** sources) throw();
|
||||
void (CLOOP_CARG *encrypt)(IDbCryptPlugin* self, IStatus* status, unsigned length, const void* from, void* to) throw();
|
||||
void (CLOOP_CARG *decrypt)(IDbCryptPlugin* self, IStatus* status, unsigned length, const void* from, void* to) throw();
|
||||
};
|
||||
@ -2889,10 +2889,10 @@ namespace Firebird
|
||||
public:
|
||||
static const unsigned VERSION = 4;
|
||||
|
||||
template <typename StatusType> void setKey(StatusType* status, unsigned length, IKeyHolderPlugin** sources)
|
||||
template <typename StatusType> void setKey(StatusType* status, const char* keyName, unsigned length, IKeyHolderPlugin** sources)
|
||||
{
|
||||
StatusType::clearException(status);
|
||||
static_cast<VTable*>(this->cloopVTable)->setKey(this, status, length, sources);
|
||||
static_cast<VTable*>(this->cloopVTable)->setKey(this, status, keyName, length, sources);
|
||||
StatusType::checkException(status);
|
||||
}
|
||||
|
||||
@ -11093,13 +11093,13 @@ namespace Firebird
|
||||
this->cloopVTable = &vTable;
|
||||
}
|
||||
|
||||
static void CLOOP_CARG cloopsetKeyDispatcher(IDbCryptPlugin* self, IStatus* status, unsigned length, IKeyHolderPlugin** sources) throw()
|
||||
static void CLOOP_CARG cloopsetKeyDispatcher(IDbCryptPlugin* self, IStatus* status, const char* keyName, unsigned length, IKeyHolderPlugin** sources) throw()
|
||||
{
|
||||
StatusType status2(status);
|
||||
|
||||
try
|
||||
{
|
||||
static_cast<Name*>(self)->Name::setKey(&status2, length, sources);
|
||||
static_cast<Name*>(self)->Name::setKey(&status2, keyName, length, sources);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
@ -11199,7 +11199,7 @@ namespace Firebird
|
||||
{
|
||||
}
|
||||
|
||||
virtual void setKey(StatusType* status, unsigned length, IKeyHolderPlugin** sources) = 0;
|
||||
virtual void setKey(StatusType* status, const char* keyName, unsigned length, IKeyHolderPlugin** sources) = 0;
|
||||
virtual void encrypt(StatusType* status, unsigned length, const void* from, void* to) = 0;
|
||||
virtual void decrypt(StatusType* status, unsigned length, const void* from, void* to) = 0;
|
||||
};
|
||||
|
@ -809,6 +809,8 @@ static const struct {
|
||||
{"map_down", 335545105},
|
||||
{"login_error", 335545106},
|
||||
{"already_opened", 335545107},
|
||||
{"bad_crypt_key", 335545108},
|
||||
{"encrypt_error", 335545109},
|
||||
{"gfix_db_name", 335740929},
|
||||
{"gfix_invalid_sw", 335740930},
|
||||
{"gfix_incmp_sw", 335740932},
|
||||
|
@ -843,6 +843,8 @@ const ISC_STATUS isc_invalid_attachment_charset = 335545104L;
|
||||
const ISC_STATUS isc_map_down = 335545105L;
|
||||
const ISC_STATUS isc_login_error = 335545106L;
|
||||
const ISC_STATUS isc_already_opened = 335545107L;
|
||||
const ISC_STATUS isc_bad_crypt_key = 335545108L;
|
||||
const ISC_STATUS isc_encrypt_error = 335545109L;
|
||||
const ISC_STATUS isc_gfix_db_name = 335740929L;
|
||||
const ISC_STATUS isc_gfix_invalid_sw = 335740930L;
|
||||
const ISC_STATUS isc_gfix_incmp_sw = 335740932L;
|
||||
@ -1306,7 +1308,7 @@ const ISC_STATUS isc_trace_switch_user_only = 337182757L;
|
||||
const ISC_STATUS isc_trace_switch_param_miss = 337182758L;
|
||||
const ISC_STATUS isc_trace_param_act_notcompat = 337182759L;
|
||||
const ISC_STATUS isc_trace_mandatory_switch_miss = 337182760L;
|
||||
const ISC_STATUS isc_err_max = 1250;
|
||||
const ISC_STATUS isc_err_max = 1252;
|
||||
|
||||
#else /* c definitions */
|
||||
|
||||
@ -2119,6 +2121,8 @@ const ISC_STATUS isc_err_max = 1250;
|
||||
#define isc_map_down 335545105L
|
||||
#define isc_login_error 335545106L
|
||||
#define isc_already_opened 335545107L
|
||||
#define isc_bad_crypt_key 335545108L
|
||||
#define isc_encrypt_error 335545109L
|
||||
#define isc_gfix_db_name 335740929L
|
||||
#define isc_gfix_invalid_sw 335740930L
|
||||
#define isc_gfix_incmp_sw 335740932L
|
||||
@ -2582,7 +2586,7 @@ const ISC_STATUS isc_err_max = 1250;
|
||||
#define isc_trace_switch_param_miss 337182758L
|
||||
#define isc_trace_param_act_notcompat 337182759L
|
||||
#define isc_trace_mandatory_switch_miss 337182760L
|
||||
#define isc_err_max 1250
|
||||
#define isc_err_max 1252
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -812,6 +812,8 @@ Data source : @4"}, /* eds_statement */
|
||||
{335545105, "Some database(s) were shutdown when trying to read mapping data"}, /* map_down */
|
||||
{335545106, "Error occurred during login, please check server firebird.log for details"}, /* login_error */
|
||||
{335545107, "Database already opened with engine instance, incompatible with current"}, /* already_opened */
|
||||
{335545108, "Invalid crypt key @1"}, /* bad_crypt_key */
|
||||
{335545109, "Page requires encyption but crypt plugin is missing"}, /* encrypt_error */
|
||||
{335740929, "data base file name (@1) already given"}, /* gfix_db_name */
|
||||
{335740930, "invalid switch @1"}, /* gfix_invalid_sw */
|
||||
{335740932, "incompatible switch combination"}, /* gfix_incmp_sw */
|
||||
|
@ -808,6 +808,8 @@ static const struct {
|
||||
{335545105, -901}, /* 785 map_down */
|
||||
{335545106, -902}, /* 786 login_error */
|
||||
{335545107, -902}, /* 787 already_opened */
|
||||
{335545108, -902}, /* 788 bad_crypt_key */
|
||||
{335545109, -901}, /* 789 encrypt_error */
|
||||
{335740929, -901}, /* 1 gfix_db_name */
|
||||
{335740930, -901}, /* 2 gfix_invalid_sw */
|
||||
{335740932, -901}, /* 4 gfix_incmp_sw */
|
||||
|
@ -743,7 +743,7 @@ static const struct {
|
||||
{335545040, "22001"}, // 720 cp_name_too_long
|
||||
{335545041, "42818"}, // 721 cp_process_active
|
||||
{335545042, "42818"}, // 722 cp_already_crypted
|
||||
{335545043, "39000"}, // 723 decrypt_error
|
||||
{335545043, "XX000"}, // 723 decrypt_error
|
||||
{335545044, "39000"}, // 724 no_providers
|
||||
{335545045, "42818"}, // 725 null_spb
|
||||
{335545046, "42000"}, // 726 max_args_exceeded
|
||||
@ -808,6 +808,8 @@ static const struct {
|
||||
{335545105, "08004"}, // 785 map_down
|
||||
{335545106, "08006"}, // 786 login_error
|
||||
{335545107, "08006"}, // 787 already_opened
|
||||
{335545108, "08006"}, // 788 bad_crypt_key
|
||||
{335545109, "XX000"}, // 789 encrypt_error
|
||||
{335740929, "00000"}, // 1 gfix_db_name
|
||||
{335740930, "00000"}, // 2 gfix_invalid_sw
|
||||
{335740932, "00000"}, // 4 gfix_incmp_sw
|
||||
|
@ -48,6 +48,8 @@
|
||||
#include "../common/isc_proto.h"
|
||||
#include "../common/classes/GetPlugins.h"
|
||||
#include "../common/classes/RefMutex.h"
|
||||
#include "../common/classes/ClumpletWriter.h"
|
||||
#include "../common/sha.h"
|
||||
|
||||
using namespace Firebird;
|
||||
|
||||
@ -83,23 +85,16 @@ namespace {
|
||||
return header;
|
||||
}
|
||||
|
||||
// This routine is looking for a clumplet on header page but is not ready to handle continuation
|
||||
// Fortunately, modern pages of size 4k and bigger can contain everything on one page.
|
||||
bool searchEntry(UCHAR type, UCHAR& out_len, const UCHAR* &entry)
|
||||
// This routine is getting clumplets from header page but is not ready to handle continuation
|
||||
// Fortunately, modern pages of size 4k and bigger can fit everything on one page.
|
||||
void getClumplets(ClumpletWriter& writer)
|
||||
{
|
||||
const UCHAR* end = ((const UCHAR*) header) + header->hdr_page_size;
|
||||
for (const UCHAR* p = header->hdr_data; (p < end - 2) && (*p != Ods::HDR_end); p += 2u + p[1])
|
||||
{
|
||||
if (*p == type)
|
||||
{
|
||||
out_len = p[1];
|
||||
entry = p + 2;
|
||||
if (entry + out_len > end)
|
||||
out_len = end - entry;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
const UCHAR* p = header->hdr_data;
|
||||
const UCHAR* const end = reinterpret_cast<const UCHAR*>(header) + header->hdr_page_size;
|
||||
while ((p < end - 2) && (*p != Ods::HDR_end))
|
||||
p += 2u + p[1];
|
||||
|
||||
writer.reset(header->hdr_data, p - header->hdr_data);
|
||||
}
|
||||
|
||||
private:
|
||||
@ -112,7 +107,8 @@ namespace {
|
||||
public:
|
||||
CchHdr(Jrd::thread_db* p_tdbb, USHORT lockType)
|
||||
: window(Jrd::HEADER_PAGE_NUMBER),
|
||||
tdbb(p_tdbb)
|
||||
tdbb(p_tdbb),
|
||||
wrtFlag(false)
|
||||
{
|
||||
void* h = CCH_FETCH(tdbb, &window, lockType, pag_header);
|
||||
if (!h)
|
||||
@ -124,10 +120,30 @@ namespace {
|
||||
|
||||
Ods::header_page* write()
|
||||
{
|
||||
CCH_MARK_MUST_WRITE(tdbb, &window);
|
||||
if (!wrtFlag)
|
||||
{
|
||||
CCH_MARK_MUST_WRITE(tdbb, &window);
|
||||
wrtFlag = true;
|
||||
}
|
||||
return const_cast<Ods::header_page*>(operator->());
|
||||
}
|
||||
|
||||
void setClumplets(const ClumpletWriter& writer)
|
||||
{
|
||||
Ods::header_page* hdr = write();
|
||||
UCHAR* const to = hdr->hdr_data;
|
||||
UCHAR* const end = reinterpret_cast<UCHAR*>(hdr) + hdr->hdr_page_size;
|
||||
const unsigned limit = (end - to) - 1;
|
||||
|
||||
const unsigned length = writer.getBufferLength();
|
||||
fb_assert(length <= limit);
|
||||
if (length > limit)
|
||||
(Arg::Gds(isc_random) << "HDR page clumplets overflow").raise();
|
||||
|
||||
memcpy(to, writer.getBuffer(), length);
|
||||
to[length] = Ods::HDR_end;
|
||||
}
|
||||
|
||||
~CchHdr()
|
||||
{
|
||||
CCH_RELEASE(tdbb, &window);
|
||||
@ -136,6 +152,7 @@ namespace {
|
||||
private:
|
||||
Jrd::WIN window;
|
||||
Jrd::thread_db* tdbb;
|
||||
bool wrtFlag;
|
||||
};
|
||||
|
||||
class PhysHdr : public Header
|
||||
@ -222,6 +239,7 @@ namespace Jrd {
|
||||
CryptoManager::CryptoManager(thread_db* tdbb)
|
||||
: PermanentStorage(*tdbb->getDatabase()->dbb_permanent),
|
||||
sync(this),
|
||||
keyName(getPool()),
|
||||
keyHolderPlugins(getPool()),
|
||||
cryptThreadId(0),
|
||||
cryptPlugin(NULL),
|
||||
@ -310,9 +328,27 @@ namespace Jrd {
|
||||
PhysHdr hdr(tdbb);
|
||||
crypt = hdr->hdr_flags & Ods::hdr_encrypted;
|
||||
process = hdr->hdr_flags & Ods::hdr_crypt_process;
|
||||
if (crypt || process)
|
||||
|
||||
if ((crypt || process) && !cryptPlugin)
|
||||
{
|
||||
ClumpletWriter hc(ClumpletWriter::UnTagged, hdr->hdr_page_size);
|
||||
hdr.getClumplets(hc);
|
||||
if (hc.find(Ods::HDR_crypt_key))
|
||||
hc.getString(keyName);
|
||||
else
|
||||
keyName = "";
|
||||
|
||||
loadPlugin(hdr->hdr_crypt_plugin);
|
||||
|
||||
string valid;
|
||||
calcValidation(valid);
|
||||
if (hc.find(Ods::HDR_crypt_hash))
|
||||
{
|
||||
string hash;
|
||||
hc.getString(hash);
|
||||
if (hash != valid)
|
||||
(Arg::Gds(isc_bad_crypt_key) << keyName).raise();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -337,12 +373,13 @@ namespace Jrd {
|
||||
|
||||
// do not assign cryptPlugin directly before key init complete
|
||||
IDbCryptPlugin* p = cryptControl.plugin();
|
||||
keyHolderPlugins.init(p);
|
||||
keyHolderPlugins.init(p, keyName.c_str());
|
||||
cryptPlugin = p;
|
||||
cryptPlugin->addRef();
|
||||
}
|
||||
|
||||
void CryptoManager::prepareChangeCryptState(thread_db* tdbb, const Firebird::MetaName& plugName)
|
||||
void CryptoManager::prepareChangeCryptState(thread_db* tdbb, const MetaName& plugName,
|
||||
const MetaName& key)
|
||||
{
|
||||
if (plugName.length() > MAX_PLUGIN_NAME_LEN)
|
||||
{
|
||||
@ -371,12 +408,28 @@ namespace Jrd {
|
||||
if (cryptPlugin)
|
||||
(Arg::Gds(isc_cp_already_crypted)).raise();
|
||||
|
||||
keyName = key;
|
||||
loadPlugin(plugName.c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CryptoManager::changeCryptState(thread_db* tdbb, const Firebird::string& plugName)
|
||||
void CryptoManager::calcValidation(string& valid)
|
||||
{
|
||||
// crypt verifier
|
||||
const char* sample = "0123456789ABCDEF";
|
||||
char result[16];
|
||||
FbLocalStatus sv;
|
||||
cryptPlugin->encrypt(&sv, sizeof(result), sample, result);
|
||||
if (sv->getState() & IStatus::STATE_ERRORS)
|
||||
Arg::StatusVector(&sv).raise();
|
||||
|
||||
// calculate it's hash
|
||||
const string verifier(result, sizeof(result));
|
||||
Sha1::hashBased64(valid, verifier);
|
||||
}
|
||||
|
||||
void CryptoManager::changeCryptState(thread_db* tdbb, const string& plugName)
|
||||
{
|
||||
if (plugName.length() > 31)
|
||||
{
|
||||
@ -423,17 +476,31 @@ namespace Jrd {
|
||||
|
||||
// Write modified header page
|
||||
Ods::header_page* header = hdr.write();
|
||||
ClumpletWriter hc(ClumpletWriter::UnTagged, header->hdr_page_size);
|
||||
hdr.getClumplets(hc);
|
||||
|
||||
if (crypt)
|
||||
{
|
||||
header->hdr_flags |= Ods::hdr_encrypted;
|
||||
plugName.copyTo(header->hdr_crypt_plugin, sizeof(header->hdr_crypt_plugin));
|
||||
string hash;
|
||||
calcValidation(hash);
|
||||
hc.insertString(Ods::HDR_crypt_hash, hash);
|
||||
}
|
||||
else
|
||||
{
|
||||
header->hdr_flags &= ~Ods::hdr_encrypted;
|
||||
hc.deleteWithTag(Ods::HDR_crypt_hash);
|
||||
}
|
||||
|
||||
// Set hdr_crypt_page for crypt thread
|
||||
if (crypt && keyName.hasData())
|
||||
hc.insertString(Ods::HDR_crypt_key, keyName);
|
||||
else
|
||||
hc.deleteWithTag(Ods::HDR_crypt_key);
|
||||
|
||||
hdr.setClumplets(hc);
|
||||
|
||||
// Setup hdr_crypt_page for crypt thread
|
||||
header->hdr_crypt_page = 1;
|
||||
header->hdr_flags |= Ods::hdr_crypt_process;
|
||||
process = true;
|
||||
@ -848,8 +915,7 @@ namespace Jrd {
|
||||
fb_assert(cryptPlugin);
|
||||
if (!cryptPlugin)
|
||||
{
|
||||
(Arg::Gds(isc_decrypt_error) <<
|
||||
Arg::Gds(isc_random) << "Missing crypt plugin").copyTo(sv);
|
||||
Arg::Gds(isc_encrypt_error).copyTo(sv);
|
||||
return FAILED_CRYPT;
|
||||
}
|
||||
|
||||
@ -950,7 +1016,7 @@ namespace Jrd {
|
||||
{
|
||||
IKeyHolderPlugin* keyPlugin = keyControl.plugin();
|
||||
FbLocalStatus st;
|
||||
if (keyPlugin->keyCallback(&st, att->att_crypt_callback) == 1) //// FIXME: 1 ???
|
||||
if (keyPlugin->keyCallback(&st, att->att_crypt_callback) > 0)
|
||||
{
|
||||
// holder accepted attachment's key
|
||||
HolderAttachments* ha = NULL;
|
||||
@ -992,7 +1058,7 @@ namespace Jrd {
|
||||
}
|
||||
}
|
||||
|
||||
void CryptoManager::KeyHolderPlugins::init(IDbCryptPlugin* crypt)
|
||||
void CryptoManager::KeyHolderPlugins::init(IDbCryptPlugin* crypt, const char* keyName)
|
||||
{
|
||||
MutexLockGuard g(holdersMutex, FB_FUNCTION);
|
||||
|
||||
@ -1005,7 +1071,7 @@ namespace Jrd {
|
||||
}
|
||||
|
||||
FbLocalStatus st;
|
||||
crypt->setKey(&st, length, vector);
|
||||
crypt->setKey(&st, keyName, length, vector);
|
||||
st.check();
|
||||
}
|
||||
|
||||
|
@ -35,6 +35,7 @@
|
||||
#include "../common/classes/fb_string.h"
|
||||
#include "../common/classes/objects_array.h"
|
||||
#include "../common/classes/condition.h"
|
||||
#include "../common/classes/MetaName.h"
|
||||
#include "../common/ThreadStart.h"
|
||||
#include "../jrd/ods.h"
|
||||
#include "../jrd/status.h"
|
||||
@ -259,7 +260,8 @@ public:
|
||||
|
||||
void shutdown(thread_db* tdbb);
|
||||
|
||||
void prepareChangeCryptState(thread_db* tdbb, const Firebird::MetaName& plugName);
|
||||
void prepareChangeCryptState(thread_db* tdbb, const Firebird::MetaName& plugName,
|
||||
const Firebird::MetaName& key);
|
||||
void changeCryptState(thread_db* tdbb, const Firebird::string& plugName);
|
||||
void attach(thread_db* tdbb, Attachment* att);
|
||||
void detach(thread_db* tdbb, Attachment* att);
|
||||
@ -334,7 +336,7 @@ private:
|
||||
|
||||
void attach(Attachment* att, Config* config);
|
||||
void detach(Attachment* att);
|
||||
void init(Firebird::IDbCryptPlugin* crypt);
|
||||
void init(Firebird::IDbCryptPlugin* crypt, const char* keyName);
|
||||
|
||||
private:
|
||||
Firebird::Mutex holdersMutex;
|
||||
@ -351,12 +353,14 @@ private:
|
||||
void loadPlugin(const char* pluginName);
|
||||
ULONG getLastPage(thread_db* tdbb);
|
||||
void writeDbHeader(thread_db* tdbb, ULONG runpage);
|
||||
void calcValidation(Firebird::string& valid);
|
||||
|
||||
void lockAndReadHeader(thread_db* tdbb, unsigned flags = 0);
|
||||
static const unsigned CRYPT_HDR_INIT = 0x01;
|
||||
static const unsigned CRYPT_HDR_NOWAIT = 0x02;
|
||||
|
||||
BarSync sync;
|
||||
Firebird::MetaName keyName;
|
||||
ULONG currentPage;
|
||||
Firebird::Mutex pluginLoadMtx, cryptThreadMtx;
|
||||
KeyHolderPlugins keyHolderPlugins;
|
||||
|
@ -429,7 +429,9 @@ const UCHAR HDR_sweep_interval = 4; // Transactions between sweeps
|
||||
const UCHAR HDR_password_file_key = 5; // Key to compare to password db
|
||||
const UCHAR HDR_difference_file = 6; // Delta file that is used during backup lock
|
||||
const UCHAR HDR_backup_guid = 7; // UID generated on each switch into backup mode
|
||||
const UCHAR HDR_max = 8; // Maximum HDR_clump value
|
||||
const UCHAR HDR_crypt_key = 8; // Name of a key used to crypt database
|
||||
const UCHAR HDR_crypt_hash = 9; // Validator of key correctness
|
||||
const UCHAR HDR_max = 10; // Maximum HDR_clump value
|
||||
|
||||
// Header page flags
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
/* 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 (?, ?, ?, ?);
|
||||
--
|
||||
('2015-12-30 17:52:25', 'JRD', 0, 788)
|
||||
('2016-02-03 14:51:49', 'JRD', 0, 790)
|
||||
('2015-03-17 18:33:00', 'QLI', 1, 533)
|
||||
('2015-01-07 18:01:51', 'GFIX', 3, 134)
|
||||
('1996-11-07 13:39:40', 'GPRE', 4, 1)
|
||||
|
@ -895,6 +895,8 @@ Data source : @4', NULL, NULL)
|
||||
('map_down', NULL, 'Mapping.cpp', NULL, 0, 785, NULL, 'Some database(s) were shutdown when trying to read mapping data', NULL, NULL);
|
||||
('login_error', NULL, 'server.cpp', NULL, 0, 786, NULL, 'Error occurred during login, please check server firebird.log for details', NULL, NULL);
|
||||
('already_opened', 'lockDatabaseFile', 'unix.cpp', NULL, 0, 787, NULL, 'Database already opened with engine instance, incompatible with current', NULL, NULL);
|
||||
('bad_crypt_key', NULL, 'CryptoManager.cpp', NULL, 0, 788, NULL, 'Invalid crypt key @1', NULL, NULL);
|
||||
('encrypt_error', NULL, 'CryptoManager.cpp', NULL, 0, 789, NULL, 'Page requires encyption but crypt plugin is missing', NULL, NULL);
|
||||
-- QLI
|
||||
(NULL, NULL, NULL, NULL, 1, 0, NULL, 'expected type', NULL, NULL);
|
||||
(NULL, NULL, NULL, NULL, 1, 1, NULL, 'bad block type', NULL, NULL);
|
||||
|
@ -729,7 +729,7 @@ set bulk_insert INSERT INTO SYSTEM_ERRORS (SQL_CODE, SQL_CLASS, SQL_SUBCLASS, FA
|
||||
(-104, '22', '001', 0, 720, 'cp_name_too_long', NULL, NULL)
|
||||
(-901, '42', '818', 0, 721, 'cp_process_active', NULL, NULL)
|
||||
(-901, '42', '818', 0, 722, 'cp_already_crypted', NULL, NULL)
|
||||
(-902, '39', '000', 0, 723, 'decrypt_error', NULL, NULL)
|
||||
(-902, 'XX', '000', 0, 723, 'decrypt_error', NULL, NULL)
|
||||
(-902, '39', '000', 0, 724, 'no_providers', NULL, NULL)
|
||||
(-104, '42', '818', 0, 725, 'null_spb', NULL, NULL)
|
||||
(-833, '42', '000', 0, 726, 'max_args_exceeded', NULL, NULL)
|
||||
@ -794,6 +794,8 @@ set bulk_insert INSERT INTO SYSTEM_ERRORS (SQL_CODE, SQL_CLASS, SQL_SUBCLASS, FA
|
||||
(-901, '08', '004', 0, 785, 'map_down', NULL, NULL)
|
||||
(-902, '08', '006', 0, 786, 'login_error', NULL, NULL)
|
||||
(-902, '08', '006', 0, 787, 'already_opened', NULL, NULL)
|
||||
(-902, '08', '006', 0, 788, 'bad_crypt_key', NULL, NULL)
|
||||
(-901, 'XX', '000', 0, 789, 'encrypt_error', NULL, NULL)
|
||||
-- GFIX
|
||||
(-901, '00', '000', 3, 1, 'gfix_db_name', NULL, NULL)
|
||||
(-901, '00', '000', 3, 2, 'gfix_invalid_sw', NULL, NULL)
|
||||
|
@ -281,6 +281,14 @@ void PPG_print_header(const header_page* header, ULONG page,
|
||||
break;
|
||||
}
|
||||
|
||||
case HDR_crypt_key:
|
||||
uSvc->printf(false, "\tEncryption key name:\t%*.*s\n", p[1], p[1], p + 2);
|
||||
break;
|
||||
|
||||
case HDR_crypt_hash:
|
||||
uSvc->printf(false, "\tKey hash:\t%*.*s\n", p[1], p[1], p + 2);
|
||||
break;
|
||||
|
||||
default:
|
||||
if (*p > HDR_max)
|
||||
uSvc->printf(false, "\tUnrecognized option %d, length %d\n", p[0], p[1]);
|
||||
|
Loading…
Reference in New Issue
Block a user