8
0
mirror of https://github.com/FirebirdSQL/firebird.git synced 2025-02-02 10:00:38 +01:00

Backported fix for CORE-5472: Problems with dbcrypt key transfer

This commit is contained in:
AlexPeshkoff 2017-03-16 12:16:30 +03:00
parent 6acbc9048d
commit 2fdb281759
53 changed files with 3762 additions and 2689 deletions

View File

@ -439,6 +439,37 @@
#
#KeyHolderPlugin =
# ----------------------------
#
# Ability to use encrypted security database
#
# If one relies on network encryption feature with crypt key generated
# by authentication plugin (like SRP does) to transfer database crypt
# keys over the wire then use of encrypted security databases is a kind of
# vicious circle. In order to send DB crypt key over the wire in secure way
# wire transfers should be already encrypted but this requires wire crypt key
# from authentication plugin which needs to open security database for hash
# validation which in turn requires DB crypt key. Luckily in most cases there
# is no big need to encrypt security database - it protects itself quite well
# if you use high quality passwords. But in some cases it's desired to have
# security database encrypted, for example if one wants to use self security
# database feature for encrypted database. In that case special care should be
# taken to encrypt that key before passing it to server using callback. Make
# sure your keys are well encrypted before enabling this parameter. Take into
# account that with CryptSecurityDatabase=TRUE unencrypted by firebird protocol
# key transfer may take place even with not encrypted security database.
# This feature is not supported by legacy authentication plugin - if you care
# about security please never use legacy authentication.
#
# Type: boolean
#
# Per-database configurable.
#
#########################################################################
# Please understand what are you doing before enabling this feature !!! #
#########################################################################
#
#CryptSecurityDatabase = false
# ----------------------------
#

File diff suppressed because it is too large Load Diff

View File

@ -25,6 +25,7 @@
*/
#include "../interfaces/ifaceExamples.h"
#include <firebird/Message.h>
using namespace Firebird;
@ -79,7 +80,13 @@ public:
status->dispose();
}
enum Action {NONE, ENC, DEC};
enum Action {NONE, ENC, DEC, EX_LCL, EX_RMT};
// Switches/actions have the following meanings:
// ENC(-e) - encrypt database
// DEC(-d) - decrypt database
// EX_LCL(-l) - execute some predefined select command (demonstrates that database can respond to select request)
// EX_RMT(-r) - execute select using execute statement in remote datasource (demonstrates that dbcrypt key is
// passed to target database when using execute statement)
void execute(const char* dbName, const Action a)
{
@ -104,18 +111,55 @@ public:
throw "startTransaction";
}
if (a == ENC)
switch(a)
{
case ENC:
att->execute(status, tra, 0,
"ALTER DATABASE ENCRYPT WITH \"DbCrypt_example\"", 3, NULL, NULL, NULL, NULL);
if (status->getState() & IStatus::STATE_ERRORS)
throw "execute";
}
if (a == DEC)
{
break;
case DEC:
att->execute(status, tra, 0, "ALTER DATABASE DECRYPT", 3, NULL, NULL, NULL, NULL);
if (status->getState() & IStatus::STATE_ERRORS)
throw "execute";
break;
case EX_LCL:
case EX_RMT:
{
FB_MESSAGE(Output, CheckStatusWrapper,
(FB_VARCHAR(31), logon)
) output(status, master);
const char* sqlL = "select current_user from rdb$database";
const char* sqlR = "execute block returns(logon varchar(31)) as begin "
"execute statement 'select current_user from rdb$database' "
"on external 'localhost:employee' as user 'test' password 'test' into :logon; "
"suspend; end";
const char* sql = a == EX_LCL ? sqlL : sqlR;
curs = att->openCursor(status, tra, 0, sql, 3, NULL, NULL, output.getMetadata(), NULL, 0);
if (status->getState() & IStatus::STATE_ERRORS)
throw "openCursor";
printf("\nExec SQL: %s\nReturns:\n", sql);
while (curs->fetchNext(status, output.getData()) == IStatus::RESULT_OK)
{
unsigned l = output->logonNull ? 0 : output->logon.length;
printf("%*.*s\n", l, l, output->logon.str);
}
printf("done.\n");
if (status->getState() & IStatus::STATE_ERRORS)
throw "fetchNext";
curs->close(status);
if (status->getState() & IStatus::STATE_ERRORS)
throw "close";
curs = NULL;
break;
}
}
if (tra)
@ -126,7 +170,7 @@ public:
tra = NULL;
}
printf("Providing key for crypt plugin - press enter to continue ...");
printf("\nProviding key for crypt plugin - press enter to continue ...");
getchar();
att->detach(status);
@ -151,13 +195,14 @@ private:
IProvider* p;
IAttachment* att;
ITransaction* tra;
IResultSet* curs;
CryptKey key;
};
int usage()
{
fprintf(stderr, "Usage: CryptApplication [ -e | -d ] { db-name }\n");
fprintf(stderr, "Usage: cryptAppSample [ -e | -d | -l | -r ] { db-name }\n");
return 2;
}
@ -181,6 +226,12 @@ int main(int ac, char** av)
case 'd':
act = App::DEC;
break;
case 'l':
act = App::EX_LCL;
break;
case 'r':
act = App::EX_RMT;
break;
default:
return usage();
}

View File

@ -77,6 +77,7 @@ public:
// IKeyHolderPlugin implementation
int keyCallback(CheckStatusWrapper* status, ICryptKeyCallback* callback);
ICryptKeyCallback* keyHandle(CheckStatusWrapper* status, const char* keyName);
ICryptKeyCallback* chainHandle(CheckStatusWrapper* status);
int release()
{
@ -200,8 +201,6 @@ IConfigEntry* CryptKeyHolder::getEntry(CheckStatusWrapper* status, const char* e
int CryptKeyHolder::keyCallback(CheckStatusWrapper* status, ICryptKeyCallback* callback)
{
status->init();
if (key != 0)
return 1;
@ -258,6 +257,12 @@ ICryptKeyCallback* CryptKeyHolder::keyHandle(CheckStatusWrapper* status, const c
return NULL;
}
ICryptKeyCallback* CryptKeyHolder::chainHandle(CheckStatusWrapper* status)
{
return &callbackInterface;
}
class Factory : public IPluginFactoryImpl<Factory, CheckStatusWrapper>
{
public:

View File

@ -236,7 +236,9 @@ void DbCrypt::setKey(CheckStatusWrapper* status, unsigned int length, IKeyHolder
return;
if (callback && callback->callback(0, NULL, 1, &key) == 1)
{
return;
}
}
key = 0;

View File

@ -1,2 +1,39 @@
All files in this directory are trivial samples.
They do not perform any real data encryption and should not be used in production!
**************************************************************************************
* All files in this directory are trivial samples. *
* They do not perform any real data encryption and should not be used in production! *
**************************************************************************************
Brief description of the sample.
Sample contains 3 components - DbCrypt plugin, KeyHolder plugin and application, which can pass
crypt key to server. Plugins do not perform any real encryption (XOR with single byte hardly can
be treated as encryption though makes database useless without crypt plugin), key is sent between
components in plain form - they just demonstrate what calls in plugins should be done and what
methods should be implemented in order for plugin to start to work.
Depending upon settings in configuration file plugins may use different ways to manage encryption
key. DbCrypt's configuration file may contain following parameters:
Auto - boolean value, when FALSE plugin queries KeyHolder plugin for key value (this is default),
when TRUE get key value from "Value" configuration parameter.
Value - integer value (lower byte is actually used), used in "Auto" mode as key value (default 90).
CryptKeyHolder's configuration file may contain following parameters:
Auto - boolean value, when FALSE plugin queries client application for key value (this is default),
when TRUE get key value from configuration file by name or use default (90) for unnamed key.
Key{Name} - integer value, a key with name "Name" (i.e. when one issues "ALTER DATABASE ENCRYPT ...
KEY Doggy" configuration parameter KeyDoggy should be present).
OnlyOwnKey - boolean value, enables/disables use of a key from another key holder in SuperServer.
Default value is TRUE (i.e. only key, owned by this KeyHolder, can be used by related
attachment).
Crypt application has a few parameters making it possible to demonstrate different operations.
-e - Encrypt database (use gstat to monitor crypt progress).
-d - Decrypt database.
-l - Locally execute SELECT statement returning name of currently attached user.
-r - Execute same statement using remote datasource 'localhost:employee'. To make it work
user "test" with password "test" should be created in employee database. If employee was
encrypted in advance this demonstrates passing database crypt key through the chain of
key holders.
cryptDb.pas is a minimum (XOR using fixed key hardcoded in plugin body) sample of database crypt
plugin written on Pascal. Was tested with both FreePascal and Delphi.

View File

@ -123,6 +123,9 @@ int DebugServer::authenticate(Firebird::CheckStatusWrapper* status, Firebird::IS
return AUTH_FAILED;
}
void DebugServer::setDbCryptCallback(Firebird::CheckStatusWrapper*, Firebird::ICryptKeyCallback*)
{ /* ignore it */ }
int DebugServer::release()
{
if (--refCounter == 0)

View File

@ -54,6 +54,7 @@ public:
int authenticate(Firebird::CheckStatusWrapper* status, Firebird::IServerBlock* sBlock,
Firebird::IWriter* writerInterface);
void setDbCryptCallback(Firebird::CheckStatusWrapper*, Firebird::ICryptKeyCallback*);
int release();
private:

View File

@ -55,7 +55,7 @@ public:
: server(NULL), data(getPool()), account(getPool()),
clientPubKey(getPool()), serverPubKey(getPool()),
verifier(getPool()), salt(getPool()), sessionKey(getPool()),
secDbName(NULL)
secDbName(NULL), cryptCallback(NULL)
{
LocalStatus ls;
CheckStatusWrapper s(&ls);
@ -65,6 +65,7 @@ public:
// IServer implementation
int authenticate(CheckStatusWrapper* status, IServerBlock* sBlock, IWriter* writerInterface);
void setDbCryptCallback(CheckStatusWrapper* status, ICryptKeyCallback* callback);
int release();
private:
@ -82,6 +83,7 @@ private:
UCharBuffer sessionKey;
RefPtr<IFirebirdConf> config;
const char* secDbName;
ICryptKeyCallback* cryptCallback;
};
int SrpServer::authenticate(CheckStatusWrapper* status, IServerBlock* sb, IWriter* writerInterface)
@ -130,6 +132,12 @@ int SrpServer::authenticate(CheckStatusWrapper* status, IServerBlock* sb, IWrite
try
{
if (cryptCallback)
{
p->setDbCryptCallback(status, cryptCallback);
status->init(); // ignore possible errors like missing call in provider
}
ClumpletWriter dpb(ClumpletReader::dpbList, MAX_DPB_SIZE);
dpb.insertByte(isc_dpb_sec_attach, TRUE);
dpb.insertString(isc_dpb_user_name, SYSDBA_USER_NAME, fb_strlen(SYSDBA_USER_NAME));
@ -287,6 +295,11 @@ int SrpServer::authenticate(CheckStatusWrapper* status, IServerBlock* sb, IWrite
return AUTH_CONTINUE;
}
void SrpServer::setDbCryptCallback(CheckStatusWrapper* status, ICryptKeyCallback* callback)
{
cryptCallback = callback;
}
int SrpServer::release()
{
if (--refCounter == 0)

View File

@ -134,6 +134,7 @@ public:
// IServer implementation
int authenticate(Firebird::CheckStatusWrapper* status, Firebird::IServerBlock* sBlock,
Firebird::IWriter* writerInterface);
void setDbCryptCallback(Firebird::CheckStatusWrapper*, Firebird::ICryptKeyCallback*) { } // ignore
int release();
private:

View File

@ -54,7 +54,7 @@ public:
}
GetPlugins(unsigned int interfaceType,
Config* knownConfig, const char* namesList = NULL)
const Config* knownConfig, const char* namesList = NULL)
: masterInterface(), pluginInterface(),
pluginSet(NULL), currentPlugin(NULL),
ls(*getDefaultMemoryPool()), status(&ls)

View File

@ -33,12 +33,12 @@ namespace Firebird
class RefCounted
{
public:
virtual int addRef()
virtual int addRef() const
{
return ++m_refCnt;
}
virtual int release()
virtual int release() const
{
fb_assert(m_refCnt.value() > 0);
const int refCnt = --m_refCnt;
@ -56,7 +56,7 @@ namespace Firebird
}
private:
AtomicCounter m_refCnt;
mutable AtomicCounter m_refCnt;
};
// reference counted object guard

View File

@ -69,12 +69,14 @@ public:
}
}
/* void changeDefaultConfig(Config* newConfig)
/* It was a kind of getting ready for changing config remotely...
void changeDefaultConfig(Config* newConfig)
{
defaultConfig = newConfig;
}
*/
const Firebird::RefPtr<Config>& getDefaultConfig() const
Firebird::RefPtr<const Config>& getDefaultConfig()
{
return defaultConfig;
}
@ -92,7 +94,7 @@ public:
}
private:
Firebird::RefPtr<Config> defaultConfig;
Firebird::RefPtr<const Config> defaultConfig;
ConfigImpl(const ConfigImpl&);
void operator=(const ConfigImpl&);
@ -192,7 +194,8 @@ const Config::ConfigEntry Config::entries[MAX_CONFIG_KEY] =
{TYPE_STRING, "KeyHolderPlugin", (ConfigValue) ""},
{TYPE_BOOLEAN, "RemoteAccess", (ConfigValue) true},
{TYPE_BOOLEAN, "IPv6V6Only", (ConfigValue) false},
{TYPE_BOOLEAN, "WireCompression", (ConfigValue) false}
{TYPE_BOOLEAN, "WireCompression", (ConfigValue) false},
{TYPE_BOOLEAN, "CryptSecurityDatabase", (ConfigValue) false}
};
/******************************************************************************
@ -254,7 +257,7 @@ Config::Config(const ConfigFile& file, const Config& base, const Firebird::PathN
notifyDatabase = notify;
}
void Config::notify()
void Config::notify() const
{
if (!notifyDatabase.hasData())
return;
@ -262,7 +265,7 @@ void Config::notify()
notifyDatabase.erase();
}
void Config::merge(Firebird::RefPtr<Config>& config, const Firebird::string* dpbConfig)
void Config::merge(Firebird::RefPtr<const Config>& config, const Firebird::string* dpbConfig)
{
if (dpbConfig && dpbConfig->hasData())
{
@ -336,7 +339,7 @@ Config::~Config()
* Public interface
*/
const Firebird::RefPtr<Config>& Config::getDefaultConfig()
const Firebird::RefPtr<const Config>& Config::getDefaultConfig()
{
return firebirdConf().getDefaultConfig();
}
@ -788,3 +791,8 @@ bool Config::getWireCompression() const
{
return get<bool>(KEY_WIRE_COMPRESSION);
}
bool Config::getCryptSecurityDatabase() const
{
return get<bool>(KEY_ENCRYPT_SECURITY_DATABASE);
}

View File

@ -140,6 +140,7 @@ public:
KEY_REMOTE_ACCESS,
KEY_IPV6_V6ONLY,
KEY_WIRE_COMPRESSION,
KEY_ENCRYPT_SECURITY_DATABASE,
MAX_CONFIG_KEY // keep it last
};
@ -172,7 +173,7 @@ private:
static const ConfigEntry entries[MAX_CONFIG_KEY];
ConfigValue values[MAX_CONFIG_KEY];
Firebird::PathName notifyDatabase;
mutable Firebird::PathName notifyDatabase;
public:
explicit Config(const ConfigFile& file); // use to build default config
@ -182,7 +183,7 @@ public:
// Call it when database with given config is created
void notify();
void notify() const;
// Check for missing firebird.conf
@ -197,10 +198,10 @@ public:
static const Firebird::PathName* getCommandLineRootDirectory();
// Master config - needed to provide per-database config
static const Firebird::RefPtr<Config>& getDefaultConfig();
static const Firebird::RefPtr<const Config>& getDefaultConfig();
// Merge config entries from DPB into existing config
static void merge(Firebird::RefPtr<Config>& config, const Firebird::string* dpbConfig);
static void merge(Firebird::RefPtr<const Config>& config, const Firebird::string* dpbConfig);
// reports key to be used by the following functions
static unsigned int getKeyByName(ConfigName name);
@ -343,6 +344,8 @@ public:
bool getRemoteAccess() const;
bool getWireCompression() const;
bool getCryptSecurityDatabase() const;
};
// Implementation of interface to access master configuration file
@ -350,7 +353,7 @@ class FirebirdConf FB_FINAL :
public Firebird::RefCntIface<Firebird::IFirebirdConfImpl<FirebirdConf, Firebird::CheckStatusWrapper> >
{
public:
FirebirdConf(Config* existingConfig)
FirebirdConf(const Config* existingConfig)
: config(existingConfig)
{ }
@ -363,7 +366,7 @@ public:
int release();
private:
Firebird::RefPtr<Config> config;
Firebird::RefPtr<const Config> config;
};
// Create default instance of IFirebirdConf interface

View File

@ -227,7 +227,7 @@ namespace
}
PathName name;
RefPtr<Config> config;
RefPtr<const Config> config;
#ifdef HAVE_ID_BY_NAME
Id* id;
#endif
@ -417,7 +417,7 @@ static inline bool hasSeparator(const PathName& name)
// Search for 'alias' in databases.conf, return its value in 'file' if found. Else set file to alias.
// Returns true if alias is found in databases.conf.
static bool resolveAlias(const PathName& alias, PathName& file, RefPtr<Config>* config)
static bool resolveAlias(const PathName& alias, PathName& file, RefPtr<const Config>* config)
{
PathName correctedAlias = alias;
replace_dir_sep(correctedAlias);
@ -492,7 +492,7 @@ static bool setPath(const PathName& filename, PathName& expandedName)
// Returns true if alias was found in databases.conf
bool expandDatabaseName(Firebird::PathName alias,
Firebird::PathName& file,
Firebird::RefPtr<Config>* config)
Firebird::RefPtr<const Config>* config)
{
try
{

View File

@ -30,7 +30,7 @@ class Config;
bool expandDatabaseName(Firebird::PathName alias,
Firebird::PathName& file,
Firebird::RefPtr<Config>* config);
Firebird::RefPtr<const Config>* config);
bool notifyDatabaseName(const Firebird::PathName& file);

View File

@ -41,7 +41,7 @@ void raise()
namespace Auth {
Get::Get(Config* firebirdConf)
Get::Get(const Config* firebirdConf)
: GetPlugins<Firebird::IManagement>(IPluginManager::TYPE_AUTH_USER_MANAGEMENT, firebirdConf)
{
if (!hasData())
@ -50,7 +50,7 @@ Get::Get(Config* firebirdConf)
}
}
Get::Get(Config* firebirdConf, const char* plugName)
Get::Get(const Config* firebirdConf, const char* plugName)
: GetPlugins<Firebird::IManagement>(IPluginManager::TYPE_AUTH_USER_MANAGEMENT, firebirdConf, plugName)
{
if (!hasData())

View File

@ -259,8 +259,8 @@ public:
class Get : public Firebird::GetPlugins<Firebird::IManagement>
{
public:
explicit Get(Config* firebirdConf);
Get(Config* firebirdConf, const char* plugName);
explicit Get(const Config* firebirdConf);
Get(const Config* firebirdConf, const char* plugName);
};
int setGsecCode(int code, unsigned int operation);

View File

@ -439,6 +439,9 @@ typedef ISC_STATUS API_ROUTINE prototype_fb_cancel_operation(ISC_STATUS *,
isc_db_handle *,
USHORT);
typedef ISC_STATUS API_ROUTINE prototype_fb_database_crypt_callback(ISC_STATUS *,
void *);
struct FirebirdApiPointers
{
prototype_isc_attach_database *isc_attach_database;
@ -519,6 +522,7 @@ struct FirebirdApiPointers
prototype_isc_service_query *isc_service_query;
prototype_isc_service_start *isc_service_start;
prototype_fb_cancel_operation *fb_cancel_operation;
prototype_fb_database_crypt_callback *fb_database_crypt_callback;
};
#endif

View File

@ -589,6 +589,8 @@ interface Server : Auth
{
[notImplemented(Auth::AUTH_FAILED)]
int authenticate(Status status, ServerBlock sBlock, Writer writerInterface);
version: // 3.0.1 => 4.0
void setDbCryptCallback(Status status, CryptKeyCallback cryptCallback);
}
// .. and corresponding client
@ -727,6 +729,8 @@ version: // 3.0.1 => 3.0.2
// 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);
// Communication in a chain of key holders - get callback interface for chaining holders
CryptKeyCallback chainHandle(Status status);
}

View File

@ -2339,6 +2339,7 @@ namespace Firebird
struct VTable : public IAuth::VTable
{
int (CLOOP_CARG *authenticate)(IServer* self, IStatus* status, IServerBlock* sBlock, IWriter* writerInterface) throw();
void (CLOOP_CARG *setDbCryptCallback)(IServer* self, IStatus* status, ICryptKeyCallback* cryptCallback) throw();
};
protected:
@ -2352,7 +2353,7 @@ namespace Firebird
}
public:
static const unsigned VERSION = 5;
static const unsigned VERSION = 6;
template <typename StatusType> int authenticate(StatusType* status, IServerBlock* sBlock, IWriter* writerInterface)
{
@ -2361,6 +2362,19 @@ namespace Firebird
StatusType::checkException(status);
return ret;
}
template <typename StatusType> void setDbCryptCallback(StatusType* status, ICryptKeyCallback* cryptCallback)
{
if (cloopVTable->version < 6)
{
StatusType::setVersionError(status, "IServer", cloopVTable->version, 6);
StatusType::checkException(status);
return;
}
StatusType::clearException(status);
static_cast<VTable*>(this->cloopVTable)->setDbCryptCallback(this, status, cryptCallback);
StatusType::checkException(status);
}
};
class IClient : public IAuth
@ -2843,6 +2857,7 @@ namespace Firebird
int (CLOOP_CARG *keyCallback)(IKeyHolderPlugin* self, IStatus* status, ICryptKeyCallback* callback) throw();
ICryptKeyCallback* (CLOOP_CARG *keyHandle)(IKeyHolderPlugin* self, IStatus* status, const char* keyName) throw();
FB_BOOLEAN (CLOOP_CARG *useOnlyOwnKeys)(IKeyHolderPlugin* self, IStatus* status) throw();
ICryptKeyCallback* (CLOOP_CARG *chainHandle)(IKeyHolderPlugin* self, IStatus* status) throw();
};
protected:
@ -2887,6 +2902,20 @@ namespace Firebird
StatusType::checkException(status);
return ret;
}
template <typename StatusType> ICryptKeyCallback* chainHandle(StatusType* status)
{
if (cloopVTable->version < 5)
{
StatusType::setVersionError(status, "IKeyHolderPlugin", cloopVTable->version, 5);
StatusType::checkException(status);
return 0;
}
StatusType::clearException(status);
ICryptKeyCallback* ret = static_cast<VTable*>(this->cloopVTable)->chainHandle(this, status);
StatusType::checkException(status);
return ret;
}
};
class IDbCryptInfo : public IReferenceCounted
@ -9798,6 +9827,7 @@ namespace Firebird
this->setOwner = &Name::cloopsetOwnerDispatcher;
this->getOwner = &Name::cloopgetOwnerDispatcher;
this->authenticate = &Name::cloopauthenticateDispatcher;
this->setDbCryptCallback = &Name::cloopsetDbCryptCallbackDispatcher;
}
} vTable;
@ -9819,6 +9849,20 @@ namespace Firebird
}
}
static void CLOOP_CARG cloopsetDbCryptCallbackDispatcher(IServer* self, IStatus* status, ICryptKeyCallback* cryptCallback) throw()
{
StatusType status2(status);
try
{
static_cast<Name*>(self)->Name::setDbCryptCallback(&status2, cryptCallback);
}
catch (...)
{
StatusType::catchException(&status2);
}
}
static void CLOOP_CARG cloopsetOwnerDispatcher(IPluginBase* self, IReferenceCounted* r) throw()
{
try
@ -9884,6 +9928,7 @@ namespace Firebird
}
virtual int authenticate(StatusType* status, IServerBlock* sBlock, IWriter* writerInterface) = 0;
virtual void setDbCryptCallback(StatusType* status, ICryptKeyCallback* cryptCallback) = 0;
};
template <typename Name, typename StatusType, typename Base>
@ -11031,6 +11076,7 @@ namespace Firebird
this->keyCallback = &Name::cloopkeyCallbackDispatcher;
this->keyHandle = &Name::cloopkeyHandleDispatcher;
this->useOnlyOwnKeys = &Name::cloopuseOnlyOwnKeysDispatcher;
this->chainHandle = &Name::cloopchainHandleDispatcher;
}
} vTable;
@ -11082,6 +11128,21 @@ namespace Firebird
}
}
static ICryptKeyCallback* CLOOP_CARG cloopchainHandleDispatcher(IKeyHolderPlugin* self, IStatus* status) throw()
{
StatusType status2(status);
try
{
return static_cast<Name*>(self)->Name::chainHandle(&status2);
}
catch (...)
{
StatusType::catchException(&status2);
return static_cast<ICryptKeyCallback*>(0);
}
}
static void CLOOP_CARG cloopsetOwnerDispatcher(IPluginBase* self, IReferenceCounted* r) throw()
{
try
@ -11149,6 +11210,7 @@ namespace Firebird
virtual int keyCallback(StatusType* status, ICryptKeyCallback* callback) = 0;
virtual ICryptKeyCallback* keyHandle(StatusType* status, const char* keyName) = 0;
virtual FB_BOOLEAN useOnlyOwnKeys(StatusType* status) = 0;
virtual ICryptKeyCallback* chainHandle(StatusType* status) = 0;
};
template <typename Name, typename StatusType, typename Base>

View File

@ -326,6 +326,7 @@ type
IClientBlock_putDataPtr = procedure(this: IClientBlock; status: IStatus; length: Cardinal; data: Pointer); cdecl;
IClientBlock_newKeyPtr = function(this: IClientBlock; status: IStatus): ICryptKey; cdecl;
IServer_authenticatePtr = function(this: IServer; status: IStatus; sBlock: IServerBlock; writerInterface: IWriter): Integer; cdecl;
IServer_setDbCryptCallbackPtr = procedure(this: IServer; status: IStatus; cryptCallback: ICryptKeyCallback); cdecl;
IClient_authenticatePtr = function(this: IClient; status: IStatus; cBlock: IClientBlock): Integer; cdecl;
IUserField_enteredPtr = function(this: IUserField): Integer; cdecl;
IUserField_specifiedPtr = function(this: IUserField): Integer; cdecl;
@ -363,6 +364,7 @@ type
IKeyHolderPlugin_keyCallbackPtr = function(this: IKeyHolderPlugin; status: IStatus; callback: ICryptKeyCallback): Integer; cdecl;
IKeyHolderPlugin_keyHandlePtr = function(this: IKeyHolderPlugin; status: IStatus; keyName: PAnsiChar): ICryptKeyCallback; cdecl;
IKeyHolderPlugin_useOnlyOwnKeysPtr = function(this: IKeyHolderPlugin; status: IStatus): Boolean; cdecl;
IKeyHolderPlugin_chainHandlePtr = function(this: IKeyHolderPlugin; status: IStatus): ICryptKeyCallback; cdecl;
IDbCryptInfo_getDatabaseFullPathPtr = function(this: IDbCryptInfo; status: IStatus): PAnsiChar; cdecl;
IDbCryptPlugin_setKeyPtr = procedure(this: IDbCryptPlugin; status: IStatus; length: Cardinal; sources: IKeyHolderPluginPtr; keyName: PAnsiChar); cdecl;
IDbCryptPlugin_encryptPtr = procedure(this: IDbCryptPlugin; status: IStatus; length: Cardinal; from: Pointer; to_: Pointer); cdecl;
@ -1626,12 +1628,14 @@ type
ServerVTable = class(AuthVTable)
authenticate: IServer_authenticatePtr;
setDbCryptCallback: IServer_setDbCryptCallbackPtr;
end;
IServer = class(IAuth)
const VERSION = 5;
const VERSION = 6;
function authenticate(status: IStatus; sBlock: IServerBlock; writerInterface: IWriter): Integer;
procedure setDbCryptCallback(status: IStatus; cryptCallback: ICryptKeyCallback);
end;
IServerImpl = class(IServer)
@ -1642,6 +1646,7 @@ type
procedure setOwner(r: IReferenceCounted); virtual; abstract;
function getOwner(): IReferenceCounted; virtual; abstract;
function authenticate(status: IStatus; sBlock: IServerBlock; writerInterface: IWriter): Integer; virtual; abstract;
procedure setDbCryptCallback(status: IStatus; cryptCallback: ICryptKeyCallback); virtual; abstract;
end;
ClientVTable = class(AuthVTable)
@ -1904,14 +1909,16 @@ type
keyCallback: IKeyHolderPlugin_keyCallbackPtr;
keyHandle: IKeyHolderPlugin_keyHandlePtr;
useOnlyOwnKeys: IKeyHolderPlugin_useOnlyOwnKeysPtr;
chainHandle: IKeyHolderPlugin_chainHandlePtr;
end;
IKeyHolderPlugin = class(IPluginBase)
const VERSION = 7;
const VERSION = 8;
function keyCallback(status: IStatus; callback: ICryptKeyCallback): Integer;
function keyHandle(status: IStatus; keyName: PAnsiChar): ICryptKeyCallback;
function useOnlyOwnKeys(status: IStatus): Boolean;
function chainHandle(status: IStatus): ICryptKeyCallback;
end;
IKeyHolderPluginImpl = class(IKeyHolderPlugin)
@ -1924,6 +1931,7 @@ type
function keyCallback(status: IStatus; callback: ICryptKeyCallback): Integer; virtual; abstract;
function keyHandle(status: IStatus; keyName: PAnsiChar): ICryptKeyCallback; virtual; abstract;
function useOnlyOwnKeys(status: IStatus): Boolean; virtual; abstract;
function chainHandle(status: IStatus): ICryptKeyCallback; virtual; abstract;
end;
DbCryptInfoVTable = class(ReferenceCountedVTable)
@ -5751,6 +5759,12 @@ begin
FbException.checkException(status);
end;
procedure IServer.setDbCryptCallback(status: IStatus; cryptCallback: ICryptKeyCallback);
begin
ServerVTable(vTable).setDbCryptCallback(Self, status, cryptCallback);
FbException.checkException(status);
end;
function IClient.authenticate(status: IStatus; cBlock: IClientBlock): Integer;
begin
Result := ClientVTable(vTable).authenticate(Self, status, cBlock);
@ -5953,6 +5967,12 @@ begin
FbException.checkException(status);
end;
function IKeyHolderPlugin.chainHandle(status: IStatus): ICryptKeyCallback;
begin
Result := KeyHolderPluginVTable(vTable).chainHandle(Self, status);
FbException.checkException(status);
end;
function IDbCryptInfo.getDatabaseFullPath(status: IStatus): PAnsiChar;
begin
Result := DbCryptInfoVTable(vTable).getDatabaseFullPath(Self, status);
@ -9254,6 +9274,15 @@ begin
end
end;
procedure IServerImpl_setDbCryptCallbackDispatcher(this: IServer; status: IStatus; cryptCallback: ICryptKeyCallback); cdecl;
begin
try
IServerImpl(this).setDbCryptCallback(status, cryptCallback);
except
on e: Exception do FbException.catchException(status, e);
end
end;
var
IServerImpl_vTable: ServerVTable;
@ -9873,6 +9902,15 @@ begin
end
end;
function IKeyHolderPluginImpl_chainHandleDispatcher(this: IKeyHolderPlugin; status: IStatus): ICryptKeyCallback; cdecl;
begin
try
Result := IKeyHolderPluginImpl(this).chainHandle(status);
except
on e: Exception do FbException.catchException(status, e);
end
end;
var
IKeyHolderPluginImpl_vTable: KeyHolderPluginVTable;
@ -12575,12 +12613,13 @@ initialization
IClientBlockImpl_vTable.newKey := @IClientBlockImpl_newKeyDispatcher;
IServerImpl_vTable := ServerVTable.create;
IServerImpl_vTable.version := 5;
IServerImpl_vTable.version := 6;
IServerImpl_vTable.addRef := @IServerImpl_addRefDispatcher;
IServerImpl_vTable.release := @IServerImpl_releaseDispatcher;
IServerImpl_vTable.setOwner := @IServerImpl_setOwnerDispatcher;
IServerImpl_vTable.getOwner := @IServerImpl_getOwnerDispatcher;
IServerImpl_vTable.authenticate := @IServerImpl_authenticateDispatcher;
IServerImpl_vTable.setDbCryptCallback := @IServerImpl_setDbCryptCallbackDispatcher;
IClientImpl_vTable := ClientVTable.create;
IClientImpl_vTable.version := 5;
@ -12665,7 +12704,7 @@ initialization
ICryptKeyCallbackImpl_vTable.callback := @ICryptKeyCallbackImpl_callbackDispatcher;
IKeyHolderPluginImpl_vTable := KeyHolderPluginVTable.create;
IKeyHolderPluginImpl_vTable.version := 7;
IKeyHolderPluginImpl_vTable.version := 8;
IKeyHolderPluginImpl_vTable.addRef := @IKeyHolderPluginImpl_addRefDispatcher;
IKeyHolderPluginImpl_vTable.release := @IKeyHolderPluginImpl_releaseDispatcher;
IKeyHolderPluginImpl_vTable.setOwner := @IKeyHolderPluginImpl_setOwnerDispatcher;
@ -12673,6 +12712,7 @@ initialization
IKeyHolderPluginImpl_vTable.keyCallback := @IKeyHolderPluginImpl_keyCallbackDispatcher;
IKeyHolderPluginImpl_vTable.keyHandle := @IKeyHolderPluginImpl_keyHandleDispatcher;
IKeyHolderPluginImpl_vTable.useOnlyOwnKeys := @IKeyHolderPluginImpl_useOnlyOwnKeysDispatcher;
IKeyHolderPluginImpl_vTable.chainHandle := @IKeyHolderPluginImpl_chainHandleDispatcher;
IDbCryptInfoImpl_vTable := DbCryptInfoVTable.create;
IDbCryptInfoImpl_vTable.version := 3;

View File

@ -47,7 +47,7 @@
#include "../jrd/Monitoring.h"
#include "../jrd/os/pio_proto.h"
#include "../common/isc_proto.h"
#include "../common/classes/GetPlugins.h"
#include "../common/classes/auto.h"
#include "../common/classes/RefMutex.h"
#include "../common/classes/ClumpletWriter.h"
#include "../common/sha.h"
@ -69,6 +69,19 @@ namespace {
const UCHAR CRYPT_INIT = LCK_EX;
const int MAX_PLUGIN_NAME_LEN = 31;
class ReleasePlugin
{
public:
static void clear(IPluginBase* ptr)
{
if (ptr)
{
PluginManagerInterfacePtr()->releasePlugin(ptr);
}
}
};
}
@ -279,7 +292,7 @@ namespace Jrd {
dbInfo(FB_NEW DbInfo(this)),
cryptThreadId(0),
cryptPlugin(NULL),
checkPlugin(NULL),
checkFactory(NULL),
dbb(*tdbb->getDatabase()),
cryptAtt(NULL),
slowIO(0),
@ -300,6 +313,7 @@ namespace Jrd {
delete stateLock;
delete threadLock;
delete checkFactory;
dbInfo->destroy();
}
@ -372,7 +386,7 @@ namespace Jrd {
else
keyName = "";
loadPlugin(hdr->hdr_crypt_plugin);
loadPlugin(tdbb, hdr->hdr_crypt_plugin);
string valid;
calcValidation(valid, cryptPlugin);
@ -387,10 +401,10 @@ namespace Jrd {
}
if (flags & CRYPT_HDR_INIT)
checkDigitalSignature(hdr);
checkDigitalSignature(tdbb, hdr);
}
void CryptoManager::loadPlugin(const char* pluginName)
void CryptoManager::loadPlugin(thread_db* tdbb, const char* pluginName)
{
if (cryptPlugin)
{
@ -403,14 +417,14 @@ namespace Jrd {
return;
}
GetPlugins<IDbCryptPlugin> cryptControl(IPluginManager::TYPE_DB_CRYPT, dbb.dbb_config, pluginName);
if (!cryptControl.hasData())
AutoPtr<Factory> cryptControl(FB_NEW Factory(IPluginManager::TYPE_DB_CRYPT, dbb.dbb_config, pluginName));
if (!cryptControl->hasData())
{
(Arg::Gds(isc_no_crypt_plugin) << pluginName).raise();
}
// do not assign cryptPlugin directly before key init complete
IDbCryptPlugin* p = cryptControl.plugin();
IDbCryptPlugin* p = cryptControl->plugin();
FbLocalStatus status;
p->setInfo(&status, dbInfo);
@ -425,16 +439,15 @@ namespace Jrd {
cryptPlugin = p;
cryptPlugin->addRef();
// May be load second instance to validate keys
if (checkPlugin)
{
PluginManagerInterfacePtr()->releasePlugin(checkPlugin);
checkPlugin = NULL;
}
// remove old factory if present
delete checkFactory;
checkFactory = NULL;
// store new one
if (dbb.dbb_config->getServerMode() == MODE_SUPER)
{
checkPlugin = cryptControl.makeInstance();
keyHolderPlugins.validate(checkPlugin, NULL, keyName);
checkFactory = cryptControl.release();
keyHolderPlugins.validateNewAttachment(tdbb->getAttachment(), keyName);
}
}
@ -489,7 +502,7 @@ namespace Jrd {
}
keyName = key;
loadPlugin(plugName.c_str());
loadPlugin(tdbb, plugName.c_str());
}
}
}
@ -566,7 +579,7 @@ namespace Jrd {
// Load plugin
if (newCryptState)
{
loadPlugin(plugName.c_str());
loadPlugin(tdbb, plugName.c_str());
}
crypt = newCryptState;
@ -586,6 +599,9 @@ namespace Jrd {
hc.deleteWithTag(Ods::HDR_crypt_key);
if (keyName.hasData())
hc.insertString(Ods::HDR_crypt_key, keyName);
if (checkFactory)
keyHolderPlugins.validateExistingAttachments(keyName);
}
else
header->hdr_flags &= ~Ods::hdr_encrypted;
@ -597,7 +613,7 @@ namespace Jrd {
header->hdr_flags |= Ods::hdr_crypt_process;
process = true;
digitalySignDatabase(hdr);
digitalySignDatabase(tdbb, hdr);
hdr.flush();
}
catch (const Exception&)
@ -647,13 +663,13 @@ namespace Jrd {
{
keyHolderPlugins.attach(att, dbb.dbb_config);
IDbCryptPlugin* p = checkPlugin;
Factory* f = checkFactory;
lockAndReadHeader(tdbb, CRYPT_HDR_INIT);
if (p && p == checkPlugin)
if (f && f == checkFactory)
{
if (!keyHolderPlugins.validate(checkPlugin, att, keyName))
if (!keyHolderPlugins.validateNewAttachment(att, keyName))
(Arg::Gds(isc_bad_crypt_key) << keyName).raise();
}
}
@ -719,7 +735,7 @@ namespace Jrd {
crypt = hdr->hdr_flags & Ods::hdr_encrypted ? true : false;
// If we are going to start crypt thread, we need plugin to be loaded
loadPlugin(hdr->hdr_crypt_plugin);
loadPlugin(tdbb, hdr->hdr_crypt_plugin);
releasingLock = true;
LCK_release(tdbb, threadLock);
@ -959,7 +975,7 @@ namespace Jrd {
}
}
digitalySignDatabase(hdr);
digitalySignDatabase(tdbb, hdr);
hdr.flush();
}
@ -1164,7 +1180,7 @@ namespace Jrd {
return (crypt ? fb_info_crypt_encrypted : 0) | (process ? fb_info_crypt_process : 0);
}
void CryptoManager::KeyHolderPlugins::attach(Attachment* att, Config* config)
void CryptoManager::KeyHolderPlugins::attach(Attachment* att, const Config* config)
{
MutexLockGuard g(holdersMutex, FB_FUNCTION);
@ -1197,7 +1213,7 @@ namespace Jrd {
}
}
if ((!pa) && config->getServerMode() == MODE_SUPER)
if (!pa)
{
pa = &(knownHolders.add());
pa->first = att;
@ -1254,7 +1270,7 @@ namespace Jrd {
st.check();
}
bool CryptoManager::KeyHolderPlugins::validateHoldersGroup(PerAttHolders& pa, IDbCryptPlugin* crypt, const MetaName& keyName)
bool CryptoManager::KeyHolderPlugins::validateHoldersGroup(PerAttHolders& pa, const MetaName& keyName)
{
FbLocalStatus st;
fb_assert(holdersMutex.locked());
@ -1265,14 +1281,13 @@ namespace Jrd {
if (!keyHolder->useOnlyOwnKeys(&st))
return true;
crypt->setKey(&st, 1, &keyHolder, keyName.c_str());
if (st.isSuccess() && mgr->checkValidation(crypt))
if (validateHolder(keyHolder, keyName))
return true;
}
return true;
return false;
}
bool CryptoManager::KeyHolderPlugins::validate(IDbCryptPlugin* crypt, Attachment* att, const MetaName& keyName)
bool CryptoManager::KeyHolderPlugins::validateNewAttachment(Attachment* att, const MetaName& keyName)
{
FbLocalStatus st;
MutexLockGuard g(holdersMutex, FB_FUNCTION);
@ -1284,10 +1299,7 @@ namespace Jrd {
if (pa.first == att)
{
bool empty = (pa.second.getCount() == 0);
bool result = empty ? false : validateHoldersGroup(pa, crypt, keyName);
releaseHolders(pa);
knownHolders.remove(i);
bool result = empty ? false : validateHoldersGroup(pa, keyName);
if (empty)
break;
@ -1297,47 +1309,66 @@ namespace Jrd {
}
// Special case - holders not needed at all
crypt->setKey(&st, 0, NULL, keyName.c_str());
if (st.isSuccess() && mgr->checkValidation(crypt))
return true;
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());
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::validate(IDbCryptPlugin* crypt, const MetaName& keyName)
void CryptoManager::KeyHolderPlugins::validateExistingAttachments(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))
if (validateHolder(NULL, keyName))
return;
// Loop through whole attathment list of DBB, shutdown attachments missing any holders
// 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)
goto found;
{
found = true;
break;
}
}
att->signalCancel();
found:;
if (!found)
att->signalShutdown();
}
// 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]);
if (!validateHoldersGroup(knownHolders[i], keyName))
knownHolders[i].first->signalShutdown();
}
knownHolders.clear();
}
void CryptoManager::addClumplet(string& signature, ClumpletReader& block, UCHAR tag)
@ -1351,7 +1382,7 @@ found:;
}
}
void CryptoManager::calcDigitalSignature(string& signature, const Header& hdr)
void CryptoManager::calcDigitalSignature(thread_db* tdbb, string& signature, const Header& hdr)
{
/*
We use the following items to calculate digital signature (hash of encrypted string)
@ -1380,7 +1411,7 @@ found:;
unsigned len = signature.length();
len &= ~(QUANTUM - 1);
loadPlugin(hdr->hdr_crypt_plugin);
loadPlugin(tdbb, hdr->hdr_crypt_plugin);
string enc;
FbLocalStatus sv;
@ -1392,7 +1423,7 @@ found:;
}
void CryptoManager::digitalySignDatabase(CchHdr& hdr)
void CryptoManager::digitalySignDatabase(thread_db* tdbb, CchHdr& hdr)
{
ClumpletWriter hc(ClumpletWriter::UnTagged, hdr->hdr_page_size);
hdr.getClumplets(hc);
@ -1404,7 +1435,7 @@ found:;
{
wf = true;
string signature;
calcDigitalSignature(signature, hdr);
calcDigitalSignature(tdbb, signature, hdr);
hc.insertString(Ods::HDR_crypt_checksum, signature);
}
@ -1412,7 +1443,7 @@ found:;
hdr.setClumplets(hc);
}
void CryptoManager::checkDigitalSignature(const Header& hdr)
void CryptoManager::checkDigitalSignature(thread_db* tdbb, const Header& hdr)
{
// if (hdr->hdr_flags & (Ods::hdr_crypt_process | Ods::hdr_encrypted))
// Restricted check to ensure compatibility with 3.0.0 databases - only for active crypt process
@ -1427,7 +1458,7 @@ found:;
string sig1, sig2;
hc.getString(sig1);
calcDigitalSignature(sig2, hdr);
calcDigitalSignature(tdbb, sig2, hdr);
if (sig1 != sig2)
(Arg::Gds(isc_random) << message).raise();
}

View File

@ -36,6 +36,7 @@
#include "../common/classes/objects_array.h"
#include "../common/classes/condition.h"
#include "../common/classes/MetaName.h"
#include "../common/classes/GetPlugins.h"
#include "../common/ThreadStart.h"
#include "../jrd/ods.h"
#include "../jrd/status.h"
@ -268,6 +269,8 @@ private:
class CryptoManager FB_FINAL : public Firebird::PermanentStorage, public BarSync::IBar
{
public:
typedef Firebird::GetPlugins<Firebird::IDbCryptPlugin> Factory;
explicit CryptoManager(thread_db* tdbb);
~CryptoManager();
@ -324,14 +327,16 @@ private:
class KeyHolderPlugins
{
public:
typedef CryptoManager::Factory Factory;
explicit KeyHolderPlugins(Firebird::MemoryPool& p, CryptoManager* m)
: knownHolders(p), mgr(m)
{ }
void attach(Attachment* att, Config* config);
void attach(Attachment* att, const 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);
bool validateNewAttachment(Attachment*, const Firebird::MetaName& keyName);
void validateExistingAttachments(const Firebird::MetaName& keyName);
void detach(Attachment* att);
private:
@ -341,7 +346,8 @@ private:
Firebird::ObjectsArray<PerAttHolders> knownHolders;
CryptoManager* mgr;
bool validateHoldersGroup(PerAttHolders& pa, Firebird::IDbCryptPlugin* crypt, const Firebird::MetaName& keyName);
bool validateHoldersGroup(PerAttHolders& pa, const Firebird::MetaName& keyName);
bool validateHolder(Firebird::IKeyHolderPlugin* keyHolder, const Firebird::MetaName& keyName);
void releaseHolders(PerAttHolders& pa);
};
@ -383,7 +389,7 @@ private:
void doOnTakenWriteSync(thread_db* tdbb);
void doOnAst(thread_db* tdbb);
void loadPlugin(const char* pluginName);
void loadPlugin(thread_db* tdbb, const char* pluginName);
ULONG getLastPage(thread_db* tdbb);
void writeDbHeader(thread_db* tdbb, ULONG runpage);
void calcValidation(Firebird::string& valid, Firebird::IDbCryptPlugin* plugin);
@ -394,9 +400,9 @@ private:
static const unsigned CRYPT_HDR_NOWAIT = 0x02;
void addClumplet(Firebird::string& value, Firebird::ClumpletReader& block, UCHAR tag);
void calcDigitalSignature(Firebird::string& signature, const class Header& hdr);
void digitalySignDatabase(class CchHdr& hdr);
void checkDigitalSignature(const class Header& hdr);
void calcDigitalSignature(thread_db* tdbb, Firebird::string& signature, const class Header& hdr);
void digitalySignDatabase(thread_db* tdbb, class CchHdr& hdr);
void checkDigitalSignature(thread_db* tdbb, const class Header& hdr);
BarSync sync;
Firebird::MetaName keyName;
@ -407,7 +413,7 @@ private:
Firebird::RefPtr<DbInfo> dbInfo;
Thread::Handle cryptThreadId;
Firebird::IDbCryptPlugin* cryptPlugin;
Firebird::IDbCryptPlugin* checkPlugin;
Factory* checkFactory;
Database& dbb;
Lock* stateLock;
Lock* threadLock;

View File

@ -461,7 +461,7 @@ public:
BackupManager* dbb_backup_manager; // physical backup manager
Firebird::TimeStamp dbb_creation_date; // creation date
ExternalFileDirectoryList* dbb_external_file_directory_list;
Firebird::RefPtr<Config> dbb_config;
Firebird::RefPtr<const Config> dbb_config;
SharedCounter dbb_shared_counter;
CryptoManager* dbb_crypto_manager;

View File

@ -120,7 +120,7 @@ void EventManager::destroy(EventManager* eventMgr)
}
EventManager::EventManager(const Firebird::string& id, Firebird::RefPtr<Config> conf)
EventManager::EventManager(const Firebird::string& id, Firebird::RefPtr<const Config> conf)
: PID(getpid()),
m_process(NULL),
m_processOffset(0),

View File

@ -51,7 +51,7 @@ public:
static void init(Attachment*);
static void destroy(EventManager*);
EventManager(const Firebird::string& id, Firebird::RefPtr<Config> conf);
EventManager(const Firebird::string& id, Firebird::RefPtr<const Config> conf);
~EventManager();
void deleteSession(SLONG);
@ -104,7 +104,7 @@ private:
SLONG m_processOffset;
Firebird::string m_dbId;
Firebird::RefPtr<Config> m_config;
Firebird::RefPtr<const Config> m_config;
Firebird::AutoPtr<Firebird::SharedMemory<evh> > m_sharedMemory;
Firebird::Semaphore m_startupSemaphore;

View File

@ -106,7 +106,7 @@ namespace Jrd
}
private:
RefPtr<Config> config;
RefPtr<const Config> config;
};
}

View File

@ -124,12 +124,32 @@ void IscConnection::attach(thread_db* tdbb, const PathName& dbName, const string
FbLocalStatus status;
{
EngineCallbackGuard guard(tdbb, *this, FB_FUNCTION);
m_iscProvider.isc_attach_database(&status, m_dbName.length(), m_dbName.c_str(),
&m_handle, newDpb.getBufferLength(),
reinterpret_cast<const char*>(newDpb.getBuffer()));
}
if (status->getState() & IStatus::STATE_ERRORS) {
raise(&status, tdbb, "attach");
ICryptKeyCallback* cb = tdbb->getAttachment()->att_crypt_callback;
try
{
m_iscProvider.fb_database_crypt_callback(&status, cb);
if (status->getState() & IStatus::STATE_ERRORS) {
raise(&status, tdbb, "crypt_callback");
}
m_iscProvider.isc_attach_database(&status, m_dbName.length(), m_dbName.c_str(),
&m_handle, newDpb.getBufferLength(),
reinterpret_cast<const char*>(newDpb.getBuffer()));
if (status->getState() & IStatus::STATE_ERRORS) {
raise(&status, tdbb, "attach");
}
}
catch(const Exception&)
{
m_iscProvider.fb_database_crypt_callback(&status, NULL);
throw;
}
m_iscProvider.fb_database_crypt_callback(&status, NULL);
if (status->getState() & IStatus::STATE_ERRORS) {
raise(&status, tdbb, "crypt_callback");
}
}
char buff[16];
@ -1474,6 +1494,15 @@ ISC_STATUS ISC_EXPORT IscProvider::fb_cancel_operation(FbStatusVector* user_stat
return notImplemented(user_status);
}
ISC_STATUS ISC_EXPORT IscProvider::fb_database_crypt_callback(FbStatusVector* user_status,
void* cb)
{
if (m_api.fb_database_crypt_callback)
return m_api.fb_database_crypt_callback(IscStatus(user_status), cb);
return notImplemented(user_status);
}
void IscProvider::loadAPI()
{
FbLocalStatus status;
@ -1565,7 +1594,8 @@ static FirebirdApiPointers isc_callbacks =
PROTO(isc_service_detach),
PROTO(isc_service_query),
PROTO(isc_service_start),
PROTO(fb_cancel_operation)
PROTO(fb_cancel_operation),
PROTO(fb_database_crypt_callback)
};

View File

@ -482,6 +482,9 @@ public:
virtual ISC_STATUS ISC_EXPORT fb_cancel_operation(Jrd::FbStatusVector*,
isc_db_handle*,
USHORT);
virtual ISC_STATUS ISC_EXPORT fb_database_crypt_callback(Jrd::FbStatusVector*,
void*);
};

View File

@ -178,7 +178,7 @@ void validatePassword(thread_db* tdbb, const PathName& file, ClumpletWriter& dpb
Arg::Gds loginError(isc_login_error);
// Build list of client/server plugins
RefPtr<Config> config;
RefPtr<const Config> config;
PathName list;
expandDatabaseName(file, list /* unused value */, &config);
PathName serverList = config->getPlugins(IPluginManager::TYPE_AUTH_SERVER);

View File

@ -958,7 +958,7 @@ public:
void get(const UCHAR*, USHORT, bool&);
void setBuffers(RefPtr<Config> config)
void setBuffers(RefPtr<const Config> config)
{
if (dpb_buffers == 0)
{
@ -1035,7 +1035,7 @@ static VdnResult verifyDatabaseName(const PathName&, FbStatusVector*, bool);
static void unwindAttach(thread_db* tdbb, const Exception& ex, FbStatusVector* userStatus,
Jrd::Attachment* attachment, Database* dbb, bool internalFlag);
static JAttachment* initAttachment(thread_db*, const PathName&, const PathName&, RefPtr<Config>, bool,
static JAttachment* initAttachment(thread_db*, const PathName&, const PathName&, RefPtr<const Config>, bool,
const DatabaseOptions&, RefMutexUnlock&, IPluginConfig*, JProvider*);
static JAttachment* create_attachment(const PathName&, Database*, const DatabaseOptions&, bool newDb);
static void prepare_tra(thread_db*, jrd_tra*, USHORT, const UCHAR*);
@ -1045,7 +1045,7 @@ static void release_attachment(thread_db*, Jrd::Attachment*);
static void rollback(thread_db*, jrd_tra*, const bool);
static void purge_attachment(thread_db* tdbb, StableAttachmentPart* sAtt, unsigned flags = 0);
static void getUserInfo(UserId&, const DatabaseOptions&, const char*, const char*,
const RefPtr<Config>*, bool, ICryptKeyCallback*);
const RefPtr<const Config>*, bool, ICryptKeyCallback*);
static void makeRoleName(Database*, string&, DatabaseOptions&);
static THREAD_ENTRY_DECLARE shutdown_thread(THREAD_ENTRY_PARAM);
@ -1394,7 +1394,7 @@ JAttachment* JProvider::internalAttach(CheckStatusWrapper* user_status, const ch
UserId userId;
DatabaseOptions options;
RefPtr<Config> config;
RefPtr<const Config> config;
bool invalid_client_SQL_dialect = false;
PathName org_filename, expanded_name;
bool is_alias = false;
@ -2432,7 +2432,7 @@ JAttachment* JProvider::createDatabase(CheckStatusWrapper* user_status, const ch
DatabaseOptions options;
PathName org_filename, expanded_name;
bool is_alias = false;
Firebird::RefPtr<Config> config;
Firebird::RefPtr<const Config> config;
try
{
@ -5973,7 +5973,7 @@ void DatabaseOptions::get(const UCHAR* dpb, USHORT dpb_length, bool& invalid_cli
static JAttachment* initAttachment(thread_db* tdbb, const PathName& expanded_name,
const PathName& alias_name, RefPtr<Config> config, bool attach_flag,
const PathName& alias_name, RefPtr<const Config> config, bool attach_flag,
const DatabaseOptions& options, RefMutexUnlock& initGuard, IPluginConfig* pConf,
JProvider* provider)
{
@ -7112,7 +7112,7 @@ static VdnResult verifyDatabaseName(const PathName& name, FbStatusVector* status
if (!securityNameBuffer->hasData())
{
const RefPtr<Config> defConf(Config::getDefaultConfig());
const RefPtr<const Config> defConf(Config::getDefaultConfig());
securityNameBuffer->assign(defConf->getSecurityDatabase());
expandedSecurityNameBuffer->assign(securityNameBuffer);
ISC_expand_filename(expandedSecurityNameBuffer, false);
@ -7147,7 +7147,7 @@ static VdnResult verifyDatabaseName(const PathName& name, FbStatusVector* status
**/
static void getUserInfo(UserId& user, const DatabaseOptions& options,
const char* aliasName, const char* dbName, const RefPtr<Config>* config, bool creating,
const char* aliasName, const char* dbName, const RefPtr<const Config>* config, bool creating,
ICryptKeyCallback* cryptCb)
{
bool wheel = false;

View File

@ -729,7 +729,7 @@ Service::Service(const TEXT* service_name, USHORT spb_length, const UCHAR* spb_d
if (svc_auth_block.hasData())
{
PathName dummy;
RefPtr<Config> config;
RefPtr<const Config> config;
expandDatabaseName(svc_expected_db, dummy, &config);
string trusted_role;
@ -1309,7 +1309,7 @@ ISC_STATUS Service::query2(thread_db* /*tdbb*/,
{
// The path to the user security database (security2.fdb)
char* pb = reinterpret_cast<char*>(buffer);
const RefPtr<Config> defConf(Config::getDefaultConfig());
const RefPtr<const Config> defConf(Config::getDefaultConfig());
strcpy(pb, defConf->getSecurityDatabase());
if (!(info = INF_put_item(item, static_cast<USHORT>(strlen(pb)), buffer, info, end)))
@ -1763,7 +1763,7 @@ void Service::query(USHORT send_item_length,
{
// The path to the user security database (security2.fdb)
char* pb = reinterpret_cast<char*>(buffer);
const RefPtr<Config> defConf(Config::getDefaultConfig());
const RefPtr<const Config> defConf(Config::getDefaultConfig());
strcpy(pb, defConf->getSecurityDatabase());
if (!(info = INF_put_item(item, static_cast<USHORT>(strlen(pb)), buffer, info, end)))

View File

@ -286,7 +286,7 @@ void TraceManager::update_session(const TraceSession& session)
if (session.ses_auth.hasData())
{
PathName dummy;
RefPtr<Config> config;
RefPtr<const Config> config;
expandDatabaseName(service->getExpectedDb(), dummy, &config);
try

View File

@ -167,7 +167,7 @@ Firebird::GlobalPtr<LockManager::DbLockMgrMap> LockManager::g_lmMap;
Firebird::GlobalPtr<Firebird::Mutex> LockManager::g_mapMutex;
LockManager* LockManager::create(const Firebird::string& id, RefPtr<Config> conf)
LockManager* LockManager::create(const Firebird::string& id, RefPtr<const Config> conf)
{
Firebird::MutexLockGuard guard(g_mapMutex, FB_FUNCTION);
@ -208,7 +208,7 @@ void LockManager::destroy(LockManager* lockMgr)
}
LockManager::LockManager(const Firebird::string& id, RefPtr<Config> conf)
LockManager::LockManager(const Firebird::string& id, RefPtr<const Config> conf)
: PID(getpid()),
m_bugcheck(false),
m_sharedFileCreated(false),

View File

@ -398,7 +398,7 @@ class LockManager : private Firebird::RefCounted,
const int PID;
public:
static LockManager* create(const Firebird::string&, Firebird::RefPtr<Config>);
static LockManager* create(const Firebird::string&, Firebird::RefPtr<const Config>);
static void destroy(LockManager*);
bool initializeOwner(Firebird::CheckStatusWrapper*, LOCK_OWNER_T, UCHAR, SRQ_PTR*);
@ -421,7 +421,7 @@ public:
void exceptionHandler(const Firebird::Exception& ex, ThreadFinishSync<LockManager*>::ThreadRoutine* routine);
private:
explicit LockManager(const Firebird::string&, Firebird::RefPtr<Config>);
explicit LockManager(const Firebird::string&, Firebird::RefPtr<const Config>);
~LockManager();
void acquire_shmem(SRQ_PTR);
@ -500,7 +500,7 @@ private:
bool m_blockage;
Firebird::string m_dbId;
Firebird::RefPtr<Config> m_config;
Firebird::RefPtr<const Config> m_config;
// configurations parameters - cached values
const ULONG m_acquireSpins;

View File

@ -693,7 +693,8 @@ static Rvnt* add_event(rem_port*);
static void add_other_params(rem_port*, ClumpletWriter&, const ParametersSet&);
static void add_working_directory(ClumpletWriter&, const PathName&);
static rem_port* analyze(ClntAuthBlock& cBlock, PathName& attach_name, unsigned flags,
ClumpletWriter& pb, const ParametersSet& parSet, PathName& node_name, PathName* ref_db_name);
ClumpletWriter& pb, const ParametersSet& parSet, PathName& node_name, PathName* ref_db_name,
Firebird::ICryptKeyCallback* cryptCb);
static void batch_gds_receive(rem_port*, struct rmtque *, USHORT);
static void batch_dsql_fetch(rem_port*, struct rmtque *, USHORT);
static void clear_queue(rem_port*);
@ -798,7 +799,7 @@ IAttachment* RProvider::attach(CheckStatusWrapper* status, const char* filename,
PathName node_name;
ClntAuthBlock cBlock(&expanded_name, &newDpb, &dpbParam);
rem_port* port = analyze(cBlock, expanded_name, flags, newDpb, dpbParam, node_name, NULL);
rem_port* port = analyze(cBlock, expanded_name, flags, newDpb, dpbParam, node_name, NULL, cryptCallback);
if (!port)
{
@ -1420,7 +1421,7 @@ Firebird::IAttachment* RProvider::create(CheckStatusWrapper* status, const char*
PathName node_name;
ClntAuthBlock cBlock(&expanded_name, &newDpb, &dpbParam);
rem_port* port = analyze(cBlock, expanded_name, flags, newDpb, dpbParam, node_name, NULL);
rem_port* port = analyze(cBlock, expanded_name, flags, newDpb, dpbParam, node_name, NULL, cryptCallback);
if (!port)
{
@ -4631,7 +4632,7 @@ Firebird::IService* RProvider::attachSvc(CheckStatusWrapper* status, const char*
if (newSpb.find(isc_spb_expected_db))
newSpb.getPath(refDbName);
rem_port* port = analyze(cBlock, expanded_name, flags, newSpb, spbParam, node_name, &refDbName);
rem_port* port = analyze(cBlock, expanded_name, flags, newSpb, spbParam, node_name, &refDbName, cryptCallback);
RefMutexGuard portGuard(*port->port_sync, FB_FUNCTION);
Rdb* rdb = port->port_context;
@ -5400,7 +5401,8 @@ static void secureAuthentication(ClntAuthBlock& cBlock, rem_port* port)
static rem_port* analyze(ClntAuthBlock& cBlock, PathName& attach_name, unsigned flags,
ClumpletWriter& pb, const ParametersSet& parSet, PathName& node_name, PathName* ref_db_name)
ClumpletWriter& pb, const ParametersSet& parSet, PathName& node_name, PathName* ref_db_name,
Firebird::ICryptKeyCallback* cryptCb)
{
/**************************************
*
@ -5463,7 +5465,7 @@ static rem_port* analyze(ClntAuthBlock& cBlock, PathName& attach_name, unsigned
}
port = INET_analyze(&cBlock, attach_name, node_name.c_str(), flags & ANALYZE_UV, pb,
cBlock.getConfig(), ref_db_name, inet_af);
cBlock.getConfig(), ref_db_name, cryptCb, inet_af);
}
// We have a local connection string. If it's a file on a network share,
@ -5497,7 +5499,7 @@ static rem_port* analyze(ClntAuthBlock& cBlock, PathName& attach_name, unsigned
ISC_utf8ToSystem(node_name);
port = INET_analyze(&cBlock, expanded_name, node_name.c_str(), flags & ANALYZE_UV, pb,
cBlock.getConfig(), ref_db_name);
cBlock.getConfig(), ref_db_name, cryptCb);
}
}
#endif
@ -5526,7 +5528,7 @@ static rem_port* analyze(ClntAuthBlock& cBlock, PathName& attach_name, unsigned
if (!port)
{
port = INET_analyze(&cBlock, attach_name, INET_LOCALHOST, flags & ANALYZE_UV, pb,
cBlock.getConfig(), ref_db_name);
cBlock.getConfig(), ref_db_name, cryptCb);
}
}
}

View File

@ -457,7 +457,7 @@ static rem_port* inet_try_connect( PACKET*,
const PathName&,
const TEXT*,
ClumpletReader&,
RefPtr<Config>*,
RefPtr<const Config>*,
const PathName*,
int);
static bool inet_write(XDR*);
@ -538,8 +538,9 @@ rem_port* INET_analyze(ClntAuthBlock* cBlock,
const TEXT* node_name,
bool uv_flag,
ClumpletReader &dpb,
RefPtr<Config>* config,
RefPtr<const Config>* config,
const PathName* ref_db_name,
Firebird::ICryptKeyCallback* cryptCb,
int af)
{
/**************************************
@ -619,7 +620,8 @@ rem_port* INET_analyze(ClntAuthBlock* cBlock,
REMOTE_PROTOCOL(PROTOCOL_VERSION11, ptype_lazy_send, 2),
REMOTE_PROTOCOL(PROTOCOL_VERSION12, ptype_lazy_send, 3),
REMOTE_PROTOCOL(PROTOCOL_VERSION13, ptype_lazy_send, 4),
REMOTE_PROTOCOL(PROTOCOL_VERSION14, ptype_lazy_send, 5)
REMOTE_PROTOCOL(PROTOCOL_VERSION14, ptype_lazy_send, 5),
REMOTE_PROTOCOL(PROTOCOL_VERSION15, ptype_lazy_send, 6)
};
fb_assert(FB_NELEM(protocols_to_try) <= FB_NELEM(cnct->p_cnct_versions));
cnct->p_cnct_count = FB_NELEM(protocols_to_try);
@ -634,51 +636,96 @@ rem_port* INET_analyze(ClntAuthBlock* cBlock,
}
rem_port* port = inet_try_connect(packet, rdb, file_name, node_name, dpb, config, ref_db_name, af);
P_ACPT* accept;
P_ACPT* accept = NULL;
switch (packet->p_operation)
for(;;)
{
case op_accept_data:
case op_cond_accept:
accept = &packet->p_acpd;
if (cBlock)
accept = NULL;
switch (packet->p_operation)
{
cBlock->storeDataForPlugin(packet->p_acpd.p_acpt_data.cstr_length,
packet->p_acpd.p_acpt_data.cstr_address);
cBlock->authComplete = packet->p_acpd.p_acpt_authenticated;
port->addServerKeys(&packet->p_acpd.p_acpt_keys);
cBlock->resetClnt(&file_name, &packet->p_acpd.p_acpt_keys);
}
break;
case op_accept_data:
case op_cond_accept:
accept = &packet->p_acpd;
if (cBlock)
{
cBlock->storeDataForPlugin(packet->p_acpd.p_acpt_data.cstr_length,
packet->p_acpd.p_acpt_data.cstr_address);
cBlock->authComplete = packet->p_acpd.p_acpt_authenticated;
port->addServerKeys(&packet->p_acpd.p_acpt_keys);
cBlock->resetClnt(&file_name, &packet->p_acpd.p_acpt_keys);
}
break;
case op_accept:
if (cBlock)
{
cBlock->resetClnt(&file_name);
}
accept = &packet->p_acpt;
break;
case op_accept:
if (cBlock)
{
cBlock->resetClnt(&file_name);
}
accept = &packet->p_acpt;
break;
case op_response:
try
{
LocalStatus warning; // Ignore connect warnings for a while
CheckStatusWrapper statusWrapper(&warning);
REMOTE_check_response(&statusWrapper, rdb, packet, false);
}
catch (const Exception&)
{
case op_crypt_key_callback:
try
{
UCharBuffer buf;
P_CRYPT_CALLBACK* cc = &packet->p_cc;
if (cryptCb)
{
if (cc->p_cc_reply <= 0)
{
cc->p_cc_reply = 1;
}
UCHAR* reply = buf.getBuffer(cc->p_cc_reply);
unsigned l = cryptCb->callback(cc->p_cc_data.cstr_length,
cc->p_cc_data.cstr_address, cc->p_cc_reply, reply);
REMOTE_free_packet(port, packet, true);
cc->p_cc_data.cstr_length = l;
cc->p_cc_data.cstr_address = reply;
}
else
{
REMOTE_free_packet(port, packet, true);
cc->p_cc_data.cstr_length = 0;
}
packet->p_operation = op_crypt_key_callback;
cc->p_cc_reply = 0;
port->send(packet);
port->receive(packet);
continue;
}
catch (const Exception&)
{
disconnect(port);
delete rdb;
throw;
}
case op_response:
try
{
LocalStatus warning; // Ignore connect warnings for a while
CheckStatusWrapper statusWrapper(&warning);
REMOTE_check_response(&statusWrapper, rdb, packet, false);
}
catch (const Exception&)
{
disconnect(port);
delete rdb;
throw;
}
// fall through - response is not a required accept
default:
disconnect(port);
delete rdb;
throw;
Arg::Gds(isc_connect_reject).raise();
break;
}
// fall through - response is not a required accept
default:
disconnect(port);
delete rdb;
Arg::Gds(isc_connect_reject).raise();
break;
break; // Always leave for() loop here
}
fb_assert(accept);
@ -720,7 +767,7 @@ rem_port* INET_connect(const TEXT* name,
PACKET* packet,
USHORT flag,
ClumpletReader* dpb,
RefPtr<Config>* config,
RefPtr<const Config>* config,
int af)
{
/**************************************
@ -2662,7 +2709,7 @@ static rem_port* inet_try_connect(PACKET* packet,
const PathName& file_name,
const TEXT* node_name,
ClumpletReader& dpb,
RefPtr<Config>* config,
RefPtr<const Config>* config,
const PathName* ref_db_name,
int af)
{

View File

@ -34,10 +34,10 @@ namespace Firebird
}
rem_port* INET_analyze(ClntAuthBlock*, const Firebird::PathName&, const TEXT*,
bool, Firebird::ClumpletReader&, Firebird::RefPtr<Config>*,
const Firebird::PathName*, int af = AF_UNSPEC);
bool, Firebird::ClumpletReader&, Firebird::RefPtr<const Config>*,
const Firebird::PathName*, Firebird::ICryptKeyCallback*, int af = AF_UNSPEC);
rem_port* INET_connect(const TEXT*, struct packet*, USHORT, Firebird::ClumpletReader*,
Firebird::RefPtr<Config>*, int af = AF_UNSPEC);
Firebird::RefPtr<const Config>*, int af = AF_UNSPEC);
rem_port* INET_reconnect(SOCKET);
rem_port* INET_server(SOCKET);
void setStopMainThread(FPTR_INT func);

View File

@ -72,7 +72,7 @@ static void disconnect(rem_port*);
static void exit_handler(void*);
#endif
static void force_close(rem_port*);
static rem_str* make_pipe_name(const RefPtr<Config>&, const TEXT*, const TEXT*, const TEXT*);
static rem_str* make_pipe_name(const RefPtr<const Config>&, const TEXT*, const TEXT*, const TEXT*);
static rem_port* receive(rem_port*, PACKET*);
static int send_full(rem_port*, PACKET*);
static int send_partial(rem_port*, PACKET*);
@ -104,7 +104,7 @@ rem_port* WNET_analyze(ClntAuthBlock* cBlock,
const PathName& file_name,
const TEXT* node_name,
bool uv_flag,
RefPtr<Config>* config,
RefPtr<const Config>* config,
const Firebird::PathName* ref_db_name)
{
/**************************************
@ -269,7 +269,7 @@ rem_port* WNET_analyze(ClntAuthBlock* cBlock,
}
rem_port* WNET_connect(const TEXT* name, PACKET* packet, USHORT flag, Firebird::RefPtr<Config>* config)
rem_port* WNET_connect(const TEXT* name, PACKET* packet, USHORT flag, Firebird::RefPtr<const Config>* config)
{
/**************************************
*
@ -800,7 +800,7 @@ static void exit_handler(void* main_port)
#endif
static rem_str* make_pipe_name(const RefPtr<Config>& config, const TEXT* connect_name,
static rem_str* make_pipe_name(const RefPtr<const Config>& config, const TEXT* connect_name,
const TEXT* suffix_name, const TEXT* str_pid)
{
/**************************************

View File

@ -32,8 +32,8 @@ extern "C" {
rem_port* WNET_analyze(ClntAuthBlock*, const Firebird::PathName&, const TEXT*, bool,
Firebird::RefPtr<Config>*, const Firebird::PathName*);
rem_port* WNET_connect(const TEXT*, struct packet*, USHORT, Firebird::RefPtr<Config>*);
Firebird::RefPtr<const Config>*, const Firebird::PathName*);
rem_port* WNET_connect(const TEXT*, struct packet*, USHORT, Firebird::RefPtr<const Config>*);
rem_port* WNET_reconnect(HANDLE);

View File

@ -148,7 +148,7 @@ namespace Remote
{
}
rem_port* connect_client(PACKET*, const RefPtr<Config>*);
rem_port* connect_client(PACKET*, const RefPtr<const Config>*);
void server_shutdown(rem_port* port);
private:
@ -238,7 +238,7 @@ static void xnet_log_error(const char* err_msg)
rem_port* XNET_analyze(ClntAuthBlock* cBlock,
const PathName& file_name,
bool uv_flag,
RefPtr<Config>* config,
RefPtr<const Config>* config,
const Firebird::PathName* ref_db_name)
{
/**************************************
@ -403,7 +403,7 @@ rem_port* XNET_analyze(ClntAuthBlock* cBlock,
rem_port* XNET_connect(PACKET* packet,
USHORT flag,
Firebird::RefPtr<Config>* config)
Firebird::RefPtr<const Config>* config)
{
/**************************************
*
@ -1087,7 +1087,7 @@ static void raise_lostconn_or_syserror(const char* msg)
}
rem_port* XnetClientEndPoint::connect_client(PACKET* packet, const RefPtr<Config>* config)
rem_port* XnetClientEndPoint::connect_client(PACKET* packet, const RefPtr<const Config>* config)
{
/**************************************
*
@ -1100,7 +1100,7 @@ rem_port* XnetClientEndPoint::connect_client(PACKET* packet, const RefPtr<Config
*
**************************************/
const Firebird::RefPtr<Config>& conf(config ? *config : Config::getDefaultConfig());
const Firebird::RefPtr<const Config>& conf(config ? *config : Config::getDefaultConfig());
if (!xnet_initialized)
{

View File

@ -32,9 +32,9 @@
#define rem_port void
#endif
rem_port* XNET_analyze(ClntAuthBlock*, const Firebird::PathName&, bool, Firebird::RefPtr<Config>*,
rem_port* XNET_analyze(ClntAuthBlock*, const Firebird::PathName&, bool, Firebird::RefPtr<const Config>*,
const Firebird::PathName*);
rem_port* XNET_connect(struct packet*, USHORT, Firebird::RefPtr<Config>*);
rem_port* XNET_connect(struct packet*, USHORT, Firebird::RefPtr<const Config>*);
rem_port* XNET_reconnect(ULONG);
#endif // REMOTE_XNET_PROTO_H

View File

@ -798,7 +798,9 @@ bool_t xdr_protocol(XDR* xdrs, PACKET* p)
MAP(xdr_cstring, cc->p_cc_data);
rem_port* port = (rem_port*) xdrs->x_public;
if (port->port_protocol >= PROTOCOL_VERSION14)
// If the protocol is 0 we are in the process of establishing a connection.
// crypt_key_callback at this phaze means server protocol is at least P15
if (port->port_protocol >= PROTOCOL_VERSION14 || port->port_protocol == 0)
MAP(xdr_short, reinterpret_cast<SSHORT&>(cc->p_cc_reply));
DEBUG_PRINTSIZE(xdrs, p->p_operation);

View File

@ -82,6 +82,11 @@ const USHORT PROTOCOL_VERSION13 = (FB_PROTOCOL_FLAG | 13);
const USHORT PROTOCOL_VERSION14 = (FB_PROTOCOL_FLAG | 14);
// Protocol 15:
// - supports crypt key callback at connect phaze
const USHORT PROTOCOL_VERSION15 = (FB_PROTOCOL_FLAG | 15);
// Architecture types
enum P_ARCH

View File

@ -61,7 +61,7 @@ void REMOTE_reset_request (struct Rrq *, struct RMessage*);
void REMOTE_reset_statement (struct Rsr *);
bool_t REMOTE_getbytes (XDR*, SCHAR*, u_int);
LegacyPlugin REMOTE_legacy_auth(const char* nm, int protocol);
Firebird::RefPtr<Config> REMOTE_get_config(const Firebird::PathName* dbName,
Firebird::RefPtr<const Config> REMOTE_get_config(const Firebird::PathName* dbName,
const Firebird::string* dpb_config = NULL);
void REMOTE_check_response(Firebird::IStatus* warning, Rdb* rdb, PACKET* packet, bool checkKeys = false);
bool REMOTE_inflate(rem_port*, PacketReceive*, UCHAR*, SSHORT, SSHORT*);

View File

@ -604,7 +604,12 @@ void rem_port::linkParent(rem_port* const parent)
parent->port_clients = parent->port_next = this;
}
const Firebird::RefPtr<Config>& rem_port::getPortConfig() const
const Firebird::RefPtr<const Config>& rem_port::getPortConfig() const
{
return port_config.hasData() ? port_config : Config::getDefaultConfig();
}
Firebird::RefPtr<const Config> rem_port::getPortConfig()
{
return port_config.hasData() ? port_config : Config::getDefaultConfig();
}
@ -1006,7 +1011,7 @@ void ClntAuthBlock::resetClnt(const Firebird::PathName* fileName, const CSTRING*
plugins.set(final.c_str());
}
Firebird::RefPtr<Config>* ClntAuthBlock::getConfig()
Firebird::RefPtr<const Config>* ClntAuthBlock::getConfig()
{
return clntConfig.hasData() ? &clntConfig : NULL;
}
@ -1017,10 +1022,10 @@ void ClntAuthBlock::storeDataForPlugin(unsigned int length, const unsigned char*
HANDSHAKE_DEBUG(fprintf(stderr, "Cli: accepted data for plugin length=%d\n", length));
}
Firebird::RefPtr<Config> REMOTE_get_config(const Firebird::PathName* dbName,
Firebird::RefPtr<const Config> REMOTE_get_config(const Firebird::PathName* dbName,
const Firebird::string* dpb_config)
{
Firebird::RefPtr<Config> config;
Firebird::RefPtr<const Config> config;
if (dbName && dbName->hasData())
{

View File

@ -703,7 +703,7 @@ private:
Firebird::UCharBuffer dataForPlugin, dataFromPlugin;
Firebird::HalfStaticArray<InternalCryptKey*, 1> cryptKeys; // Wire crypt keys that came from plugin(s) last time
Firebird::string dpbConfig; // Used to recreate config with new filename
Firebird::RefPtr<Config> clntConfig; // Used to get plugins list and pass to port
Firebird::RefPtr<const Config> clntConfig; // Used to get plugins list and pass to port
unsigned nextKey; // First key to be analyzed
bool hasCryptKey; // DPB contains disk crypt key, may be passed only over encrypted wire
@ -733,7 +733,7 @@ public:
Firebird::PathName getPluginName();
void tryNewKeys(rem_port*);
void releaseKeys(unsigned from);
Firebird::RefPtr<Config>* getConfig();
Firebird::RefPtr<const Config>* getConfig();
// Firebird::IClientBlock implementation
int release();
@ -947,7 +947,7 @@ struct rem_port : public Firebird::GlobalStorage, public Firebird::RefCounted
OBJCT port_last_object_id; // cached last id
Firebird::ObjectsArray< Firebird::Array<char> > port_queue;
FB_SIZE_T port_qoffset; // current packet in the queue
Firebird::RefPtr<Config> port_config; // connection-specific configuration info
Firebird::RefPtr<const Config> port_config; // connection-specific configuration info
// Authentication and crypt stuff
ServerAuthBase* port_srv_auth;
@ -1023,7 +1023,8 @@ public:
static bool checkCompression();
void linkParent(rem_port* const parent);
void unlinkParent();
const Firebird::RefPtr<Config>& getPortConfig() const;
Firebird::RefPtr<const Config> getPortConfig();
const Firebird::RefPtr<const Config>& getPortConfig() const;
void versionInfo(Firebird::string& version) const;
bool extractNewKeys(CSTRING* to, bool flagPlugList = false)

View File

@ -399,7 +399,7 @@ int CLIB_ROUTINE main( int argc, char** argv)
ISC_STATUS_ARRAY status;
isc_db_handle db_handle = 0L;
const Firebird::RefPtr<Config> defConf(Config::getDefaultConfig());
const Firebird::RefPtr<const Config> defConf(Config::getDefaultConfig());
const char* path = defConf->getSecurityDatabase();
const char dpb[] = {isc_dpb_version1, isc_dpb_sec_attach, 1, 1, isc_dpb_address_path, 0};

View File

@ -105,7 +105,175 @@ public:
namespace {
// DB crypt key passthrough
class NetworkCallback : public VersionedIface<ICryptKeyCallbackImpl<NetworkCallback, CheckStatusWrapper> >
{
public:
explicit NetworkCallback(rem_port* prt)
: port(prt), l(0), d(NULL), stopped(false), wake(false)
{ }
unsigned int callback(unsigned int dataLength, const void* data,
unsigned int bufferLength, void* buffer)
{
if (stopped)
return 0;
if (port->port_protocol < PROTOCOL_VERSION13)
return 0;
Reference r(*port);
d = buffer;
l = bufferLength;
PACKET p;
p.p_operation = op_crypt_key_callback;
p.p_cc.p_cc_data.cstr_length = dataLength;
p.p_cc.p_cc_data.cstr_address = (UCHAR*) data;
p.p_cc.p_cc_reply = bufferLength;
port->send(&p);
if (!sem.tryEnter(60))
return 0;
return l;
}
void wakeup(unsigned int length, const void* data)
{
if (l > length)
l = length;
memcpy(d, data, l);
wake = true;
sem.release();
}
void stop()
{
stopped = true;
}
bool isStopped() const
{
return stopped;
}
private:
rem_port* port;
Semaphore sem;
unsigned int l;
void* d;
bool stopped;
public:
bool wake;
};
class CryptKeyCallback : public VersionedIface<ICryptKeyCallbackImpl<CryptKeyCallback, CheckStatusWrapper> >
{
public:
explicit CryptKeyCallback(rem_port* prt)
: port(prt), networkCallback(prt), keyHolder(NULL), keyCallback(NULL)
{ }
~CryptKeyCallback()
{
if (keyHolder)
PluginManagerInterfacePtr()->releasePlugin(keyHolder);
}
unsigned int callback(unsigned int dataLength, const void* data,
unsigned int bufferLength, void* buffer)
{
if (keyCallback)
return keyCallback->callback(dataLength, data, bufferLength, buffer);
if (networkCallback.isStopped())
return 0;
Reference r(*port);
for (GetPlugins<IKeyHolderPlugin> kh(IPluginManager::TYPE_KEY_HOLDER, port->getPortConfig());
kh.hasData(); kh.next())
{
IKeyHolderPlugin* keyPlugin = kh.plugin();
LocalStatus ls;
CheckStatusWrapper st(&ls);
networkCallback.wake = false;
if (keyPlugin->keyCallback(&st, &networkCallback) && networkCallback.wake)
{
// current holder has a key and it seems to be from the client
keyHolder = keyPlugin;
keyHolder->addRef();
keyCallback = keyHolder->chainHandle(&st);
if (st.isEmpty() && keyCallback)
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)
{
networkCallback.wakeup(length, data);
}
void stop()
{
networkCallback.stop();
}
private:
rem_port* port;
NetworkCallback networkCallback;
IKeyHolderPlugin* keyHolder;
ICryptKeyCallback* keyCallback;
};
class ServerCallback : public ServerCallbackBase, public GlobalStorage
{
public:
explicit ServerCallback(rem_port* prt)
: cryptCallback(prt)
{ }
~ServerCallback()
{ }
void wakeup(unsigned int length, const void* data)
{
cryptCallback.wakeup(length, data);
}
ICryptKeyCallback* getInterface()
{
return &cryptCallback;
}
void stop()
{
cryptCallback.stop();
}
private:
CryptKeyCallback cryptCallback;
};
// Disable attempts to brute-force logins/passwords
class FailedLogin
{
public:
@ -287,6 +455,7 @@ static void getMultiPartConnectParameter(T& putTo, Firebird::ClumpletReader& id,
// delayed authentication block for auth callback
class ServerAuth : public GlobalStorage, public ServerAuthBase
{
public:
@ -379,6 +548,11 @@ public:
authPort->port_srv_auth_block->setDataForPlugin(u);
}
#endif
if (!authPort->port_server_crypt_callback)
{
authPort->port_server_crypt_callback = FB_NEW ServerCallback(authPort);
}
}
~ServerAuth()
@ -425,6 +599,13 @@ public:
{
authServer = authItr->plugin();
authPort->port_srv_auth_block->authBlockWriter.setPlugin(authItr->name());
if (authPort->getPortConfig()->getCryptSecurityDatabase() &&
authPort->port_protocol >= PROTOCOL_VERSION15 &&
authPort->port_server_crypt_callback)
{
authServer->setDbCryptCallback(&st, authPort->port_server_crypt_callback->getInterface());
}
}
// if we asked for more data but received nothing switch to next plugin
@ -774,6 +955,9 @@ private:
Rvnt* event;
};
// Stores types of known wire crypt keys
class CryptKeyTypeManager : public PermanentStorage
{
class CryptKeyType : public PermanentStorage
@ -868,91 +1052,6 @@ private:
InitInstance<CryptKeyTypeManager> knownCryptKeyTypes;
class CryptKeyCallback : public VersionedIface<ICryptKeyCallbackImpl<CryptKeyCallback, CheckStatusWrapper> >
{
public:
explicit CryptKeyCallback(rem_port* prt)
: port(prt), l(0), d(NULL), stopped(false)
{ }
unsigned int callback(unsigned int dataLength, const void* data,
unsigned int bufferLength, void* buffer)
{
if (stopped)
return 0;
Reference r(*port);
PACKET p;
p.p_operation = op_crypt_key_callback;
p.p_cc.p_cc_data.cstr_length = dataLength;
p.p_cc.p_cc_data.cstr_address = (UCHAR*) data;
p.p_cc.p_cc_reply = bufferLength;
port->send(&p);
if (!sem.tryEnter(10))
return 0;
if (bufferLength > l)
bufferLength = l;
memcpy(buffer, d, bufferLength);
if (l)
sem2.release();
return l;
}
void wakeup(unsigned int length, const void* data)
{
l = length;
d = data;
sem.release();
if (l)
sem2.enter();
}
void stop()
{
stopped = true;
}
private:
rem_port* port;
Semaphore sem, sem2;
unsigned int l;
const void* d;
bool stopped;
};
class ServerCallback : public ServerCallbackBase, public GlobalStorage
{
public:
explicit ServerCallback(rem_port* prt)
: cryptCallback(prt)
{ }
~ServerCallback()
{ }
void wakeup(unsigned int length, const void* data)
{
cryptCallback.wakeup(length, data);
}
ICryptKeyCallback* getInterface()
{
return &cryptCallback;
}
void stop()
{
cryptCallback.stop();
}
private:
CryptKeyCallback cryptCallback;
};
} // anonymous
static void free_request(server_req_t*);
@ -1715,11 +1814,8 @@ static bool accept_connection(rem_port* port, P_CNCT* connect, PACKET* send)
for (const p_cnct::p_cnct_repeat* const end = protocol + connect->p_cnct_count;
protocol < end; protocol++)
{
if ((protocol->p_cnct_version == PROTOCOL_VERSION10 ||
protocol->p_cnct_version == PROTOCOL_VERSION11 ||
protocol->p_cnct_version == PROTOCOL_VERSION12 ||
protocol->p_cnct_version == PROTOCOL_VERSION13 ||
protocol->p_cnct_version == PROTOCOL_VERSION14) &&
if ((protocol->p_cnct_version >= PROTOCOL_VERSION10 &&
protocol->p_cnct_version <= PROTOCOL_VERSION15) &&
(protocol->p_cnct_architecture == arch_generic ||
protocol->p_cnct_architecture == ARCHITECTURE) &&
protocol->p_cnct_weight >= weight)
@ -2239,13 +2335,10 @@ void DatabaseAuth::accept(PACKET* send, Auth::WriterImplementation* authBlock)
const UCHAR* dpb = pb->getBuffer();
unsigned int dl = (ULONG) pb->getBufferLength();
if (!authPort->port_server_crypt_callback)
{
authPort->port_server_crypt_callback = FB_NEW ServerCallback(authPort);
}
LocalStatus ls;
CheckStatusWrapper status_vector(&ls);
fb_assert(authPort->port_server_crypt_callback);
provider->setDbCryptCallback(&status_vector, authPort->port_server_crypt_callback->getInterface());
if (!(status_vector.getState() & Firebird::IStatus::STATE_ERRORS))
@ -5378,16 +5471,13 @@ ISC_STATUS rem_port::service_attach(const char* service_name,
// they will be stuffed in the SPB if so.
REMOTE_get_timeout_params(this, spb);
if (!port_server_crypt_callback)
{
port_server_crypt_callback = FB_NEW ServerCallback(this);
}
DispatcherPtr provider;
LocalStatus ls;
CheckStatusWrapper status_vector(&ls);
fb_assert(port_server_crypt_callback);
provider->setDbCryptCallback(&status_vector, port_server_crypt_callback->getInterface());
if (!(status_vector.getState() & Firebird::IStatus::STATE_ERRORS))
{
dumpAuthBlock("rem_port::service_attach()", spb, isc_spb_auth_block);
@ -6500,7 +6590,7 @@ void SrvAuthBlock::createPluginsItr()
REMOTE_makeList(pluginList, final);
RefPtr<Config> portConf(port->getPortConfig());
RefPtr<const Config> portConf(port->getPortConfig());
plugins = FB_NEW AuthServerPlugins(IPluginManager::TYPE_AUTH_SERVER, portConf, pluginList.c_str());
}

View File

@ -379,7 +379,7 @@ int gsec(Firebird::UtilSvc* uSvc)
}
else
{
const Firebird::RefPtr<Config> defConf(Config::getDefaultConfig());
const Firebird::RefPtr<const Config> defConf(Config::getDefaultConfig());
databaseName = defConf->getSecurityDatabase();
}
@ -460,8 +460,8 @@ int gsec(Firebird::UtilSvc* uSvc)
Firebird::string databaseText;
databaseText.printf("SecurityDatabase = %s\n", databaseName.c_str());
ConfigFile gsecDatabase(ConfigFile::USE_TEXT, databaseText.c_str());
Firebird::RefPtr<Config> defaultConfig(Config::getDefaultConfig());
Firebird::RefPtr<Config> pseudoConfig(FB_NEW Config(gsecDatabase, *defaultConfig));
Firebird::RefPtr<const Config> defaultConfig(Config::getDefaultConfig());
Firebird::RefPtr<const Config> pseudoConfig(FB_NEW Config(gsecDatabase, *defaultConfig));
uSvc->checkService();

View File

@ -560,7 +560,7 @@ namespace
{
if (!firebirdConf.hasData())
{
RefPtr<Config> specificConf(Config::getDefaultConfig());
RefPtr<const Config> specificConf(Config::getDefaultConfig());
firebirdConf = FB_NEW FirebirdConf(specificConf);
}
@ -1253,7 +1253,7 @@ public:
try
{
PathName dummy;
Firebird::RefPtr<Config> config;
Firebird::RefPtr<const Config> config;
expandDatabaseName(dbName, dummy, &config);
IFirebirdConf* firebirdConf = FB_NEW FirebirdConf(config);

View File

@ -5673,7 +5673,7 @@ YAttachment* Dispatcher::attachOrCreateDatabase(Firebird::CheckStatusWrapper* st
orgFilename.rtrim();
PathName expandedFilename;
RefPtr<Config> config;
RefPtr<const Config> config;
if (expandDatabaseName(orgFilename, expandedFilename, &config))
{
expandedFilename = orgFilename;
@ -5800,7 +5800,7 @@ YService* Dispatcher::attachServiceManager(CheckStatusWrapper* status, const cha
}
// Build correct config
RefPtr<Config> config(Config::getDefaultConfig());
RefPtr<const Config> config(Config::getDefaultConfig());
if (spbWriter.find(isc_spb_config))
{
string spb_config;