mirror of
https://github.com/FirebirdSQL/firebird.git
synced 2025-02-02 10:40:38 +01:00
Implemented #7951: Make it possible to handle attach errors in key holder plugin.
This commit is contained in:
parent
6dce8db8ca
commit
c2238907a7
@ -941,6 +941,21 @@ interface CryptKeyCallback : Versioned
|
|||||||
// any further details.
|
// any further details.
|
||||||
uint callback(uint dataLength, const void* data,
|
uint callback(uint dataLength, const void* data,
|
||||||
uint bufferLength, void* buffer);
|
uint bufferLength, void* buffer);
|
||||||
|
|
||||||
|
version: // 6.0
|
||||||
|
// Result returned by afterAttach()
|
||||||
|
const uint NO_RETRY = 0; // Returned by old plugins & stub
|
||||||
|
const uint DO_RETRY = 1;
|
||||||
|
|
||||||
|
// NULL in attStatus means attach was successful.
|
||||||
|
// DO_RETRY return will be ignored in this case, but plugin has a chance
|
||||||
|
// to reflect internally success.
|
||||||
|
[stub defaultAction]
|
||||||
|
uint afterAttach(Status status, const string dbName, const Status attStatus);
|
||||||
|
|
||||||
|
// interface not needed any more
|
||||||
|
[stub defaultAction]
|
||||||
|
void dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -3891,7 +3891,7 @@ namespace Firebird
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
#define FIREBIRD_ICRYPT_KEY_CALLBACK_VERSION 2u
|
#define FIREBIRD_ICRYPT_KEY_CALLBACK_VERSION 3u
|
||||||
|
|
||||||
class ICryptKeyCallback : public IVersioned
|
class ICryptKeyCallback : public IVersioned
|
||||||
{
|
{
|
||||||
@ -3899,6 +3899,8 @@ namespace Firebird
|
|||||||
struct VTable : public IVersioned::VTable
|
struct VTable : public IVersioned::VTable
|
||||||
{
|
{
|
||||||
unsigned (CLOOP_CARG *callback)(ICryptKeyCallback* self, unsigned dataLength, const void* data, unsigned bufferLength, void* buffer) CLOOP_NOEXCEPT;
|
unsigned (CLOOP_CARG *callback)(ICryptKeyCallback* self, unsigned dataLength, const void* data, unsigned bufferLength, void* buffer) CLOOP_NOEXCEPT;
|
||||||
|
unsigned (CLOOP_CARG *afterAttach)(ICryptKeyCallback* self, IStatus* status, const char* dbName, const IStatus* attStatus) CLOOP_NOEXCEPT;
|
||||||
|
void (CLOOP_CARG *dispose)(ICryptKeyCallback* self) CLOOP_NOEXCEPT;
|
||||||
};
|
};
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
@ -3914,11 +3916,37 @@ namespace Firebird
|
|||||||
public:
|
public:
|
||||||
static CLOOP_CONSTEXPR unsigned VERSION = FIREBIRD_ICRYPT_KEY_CALLBACK_VERSION;
|
static CLOOP_CONSTEXPR unsigned VERSION = FIREBIRD_ICRYPT_KEY_CALLBACK_VERSION;
|
||||||
|
|
||||||
|
static CLOOP_CONSTEXPR unsigned NO_RETRY = 0;
|
||||||
|
static CLOOP_CONSTEXPR unsigned DO_RETRY = 1;
|
||||||
|
|
||||||
unsigned callback(unsigned dataLength, const void* data, unsigned bufferLength, void* buffer)
|
unsigned callback(unsigned dataLength, const void* data, unsigned bufferLength, void* buffer)
|
||||||
{
|
{
|
||||||
unsigned ret = static_cast<VTable*>(this->cloopVTable)->callback(this, dataLength, data, bufferLength, buffer);
|
unsigned ret = static_cast<VTable*>(this->cloopVTable)->callback(this, dataLength, data, bufferLength, buffer);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename StatusType> unsigned afterAttach(StatusType* status, const char* dbName, const IStatus* attStatus)
|
||||||
|
{
|
||||||
|
if (cloopVTable->version < 3)
|
||||||
|
{
|
||||||
|
StatusType::setVersionError(status, "ICryptKeyCallback", cloopVTable->version, 3);
|
||||||
|
StatusType::checkException(status);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
StatusType::clearException(status);
|
||||||
|
unsigned ret = static_cast<VTable*>(this->cloopVTable)->afterAttach(this, status, dbName, attStatus);
|
||||||
|
StatusType::checkException(status);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void dispose()
|
||||||
|
{
|
||||||
|
if (cloopVTable->version < 3)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
static_cast<VTable*>(this->cloopVTable)->dispose(this);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
#define FIREBIRD_IKEY_HOLDER_PLUGIN_VERSION 5u
|
#define FIREBIRD_IKEY_HOLDER_PLUGIN_VERSION 5u
|
||||||
@ -14395,6 +14423,8 @@ namespace Firebird
|
|||||||
{
|
{
|
||||||
this->version = Base::VERSION;
|
this->version = Base::VERSION;
|
||||||
this->callback = &Name::cloopcallbackDispatcher;
|
this->callback = &Name::cloopcallbackDispatcher;
|
||||||
|
this->afterAttach = &Name::cloopafterAttachDispatcher;
|
||||||
|
this->dispose = &Name::cloopdisposeDispatcher;
|
||||||
}
|
}
|
||||||
} vTable;
|
} vTable;
|
||||||
|
|
||||||
@ -14413,6 +14443,33 @@ namespace Firebird
|
|||||||
return static_cast<unsigned>(0);
|
return static_cast<unsigned>(0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static unsigned CLOOP_CARG cloopafterAttachDispatcher(ICryptKeyCallback* self, IStatus* status, const char* dbName, const IStatus* attStatus) CLOOP_NOEXCEPT
|
||||||
|
{
|
||||||
|
StatusType status2(status);
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return static_cast<Name*>(self)->Name::afterAttach(&status2, dbName, attStatus);
|
||||||
|
}
|
||||||
|
catch (...)
|
||||||
|
{
|
||||||
|
StatusType::catchException(&status2);
|
||||||
|
return static_cast<unsigned>(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void CLOOP_CARG cloopdisposeDispatcher(ICryptKeyCallback* self) CLOOP_NOEXCEPT
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
static_cast<Name*>(self)->Name::dispose();
|
||||||
|
}
|
||||||
|
catch (...)
|
||||||
|
{
|
||||||
|
StatusType::catchException(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename Name, typename StatusType, typename Base = IVersionedImpl<Name, StatusType, Inherit<ICryptKeyCallback> > >
|
template <typename Name, typename StatusType, typename Base = IVersionedImpl<Name, StatusType, Inherit<ICryptKeyCallback> > >
|
||||||
@ -14429,6 +14486,13 @@ namespace Firebird
|
|||||||
}
|
}
|
||||||
|
|
||||||
virtual unsigned callback(unsigned dataLength, const void* data, unsigned bufferLength, void* buffer) = 0;
|
virtual unsigned callback(unsigned dataLength, const void* data, unsigned bufferLength, void* buffer) = 0;
|
||||||
|
virtual unsigned afterAttach(StatusType* status, const char* dbName, const IStatus* attStatus)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
virtual void dispose()
|
||||||
|
{
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename Name, typename StatusType, typename Base>
|
template <typename Name, typename StatusType, typename Base>
|
||||||
|
@ -490,6 +490,8 @@ type
|
|||||||
IWireCryptPlugin_getSpecificDataPtr = function(this: IWireCryptPlugin; status: IStatus; keyType: PAnsiChar; length: CardinalPtr): BytePtr; cdecl;
|
IWireCryptPlugin_getSpecificDataPtr = function(this: IWireCryptPlugin; status: IStatus; keyType: PAnsiChar; length: CardinalPtr): BytePtr; cdecl;
|
||||||
IWireCryptPlugin_setSpecificDataPtr = procedure(this: IWireCryptPlugin; status: IStatus; keyType: PAnsiChar; length: Cardinal; data: BytePtr); cdecl;
|
IWireCryptPlugin_setSpecificDataPtr = procedure(this: IWireCryptPlugin; status: IStatus; keyType: PAnsiChar; length: Cardinal; data: BytePtr); cdecl;
|
||||||
ICryptKeyCallback_callbackPtr = function(this: ICryptKeyCallback; dataLength: Cardinal; data: Pointer; bufferLength: Cardinal; buffer: Pointer): Cardinal; cdecl;
|
ICryptKeyCallback_callbackPtr = function(this: ICryptKeyCallback; dataLength: Cardinal; data: Pointer; bufferLength: Cardinal; buffer: Pointer): Cardinal; cdecl;
|
||||||
|
ICryptKeyCallback_afterAttachPtr = function(this: ICryptKeyCallback; status: IStatus; dbName: PAnsiChar; attStatus: IStatus): Cardinal; cdecl;
|
||||||
|
ICryptKeyCallback_disposePtr = procedure(this: ICryptKeyCallback); cdecl;
|
||||||
IKeyHolderPlugin_keyCallbackPtr = function(this: IKeyHolderPlugin; status: IStatus; callback: ICryptKeyCallback): Integer; cdecl;
|
IKeyHolderPlugin_keyCallbackPtr = function(this: IKeyHolderPlugin; status: IStatus; callback: ICryptKeyCallback): Integer; cdecl;
|
||||||
IKeyHolderPlugin_keyHandlePtr = function(this: IKeyHolderPlugin; status: IStatus; keyName: PAnsiChar): ICryptKeyCallback; cdecl;
|
IKeyHolderPlugin_keyHandlePtr = function(this: IKeyHolderPlugin; status: IStatus; keyName: PAnsiChar): ICryptKeyCallback; cdecl;
|
||||||
IKeyHolderPlugin_useOnlyOwnKeysPtr = function(this: IKeyHolderPlugin; status: IStatus): Boolean; cdecl;
|
IKeyHolderPlugin_useOnlyOwnKeysPtr = function(this: IKeyHolderPlugin; status: IStatus): Boolean; cdecl;
|
||||||
@ -2375,18 +2377,26 @@ type
|
|||||||
|
|
||||||
CryptKeyCallbackVTable = class(VersionedVTable)
|
CryptKeyCallbackVTable = class(VersionedVTable)
|
||||||
callback: ICryptKeyCallback_callbackPtr;
|
callback: ICryptKeyCallback_callbackPtr;
|
||||||
|
afterAttach: ICryptKeyCallback_afterAttachPtr;
|
||||||
|
dispose: ICryptKeyCallback_disposePtr;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
ICryptKeyCallback = class(IVersioned)
|
ICryptKeyCallback = class(IVersioned)
|
||||||
const VERSION = 2;
|
const VERSION = 3;
|
||||||
|
const NO_RETRY = Cardinal(0);
|
||||||
|
const DO_RETRY = Cardinal(1);
|
||||||
|
|
||||||
function callback(dataLength: Cardinal; data: Pointer; bufferLength: Cardinal; buffer: Pointer): Cardinal;
|
function callback(dataLength: Cardinal; data: Pointer; bufferLength: Cardinal; buffer: Pointer): Cardinal;
|
||||||
|
function afterAttach(status: IStatus; dbName: PAnsiChar; attStatus: IStatus): Cardinal;
|
||||||
|
procedure dispose();
|
||||||
end;
|
end;
|
||||||
|
|
||||||
ICryptKeyCallbackImpl = class(ICryptKeyCallback)
|
ICryptKeyCallbackImpl = class(ICryptKeyCallback)
|
||||||
constructor create;
|
constructor create;
|
||||||
|
|
||||||
function callback(dataLength: Cardinal; data: Pointer; bufferLength: Cardinal; buffer: Pointer): Cardinal; virtual; abstract;
|
function callback(dataLength: Cardinal; data: Pointer; bufferLength: Cardinal; buffer: Pointer): Cardinal; virtual; abstract;
|
||||||
|
function afterAttach(status: IStatus; dbName: PAnsiChar; attStatus: IStatus): Cardinal; virtual;
|
||||||
|
procedure dispose(); virtual;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
KeyHolderPluginVTable = class(PluginBaseVTable)
|
KeyHolderPluginVTable = class(PluginBaseVTable)
|
||||||
@ -8104,6 +8114,27 @@ begin
|
|||||||
Result := CryptKeyCallbackVTable(vTable).callback(Self, dataLength, data, bufferLength, buffer);
|
Result := CryptKeyCallbackVTable(vTable).callback(Self, dataLength, data, bufferLength, buffer);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
function ICryptKeyCallback.afterAttach(status: IStatus; dbName: PAnsiChar; attStatus: IStatus): Cardinal;
|
||||||
|
begin
|
||||||
|
if (vTable.version < 3) then begin
|
||||||
|
FbException.setVersionError(status, 'ICryptKeyCallback', vTable.version, 3);
|
||||||
|
Result := 0;
|
||||||
|
end
|
||||||
|
else begin
|
||||||
|
Result := CryptKeyCallbackVTable(vTable).afterAttach(Self, status, dbName, attStatus);
|
||||||
|
end;
|
||||||
|
FbException.checkException(status);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure ICryptKeyCallback.dispose();
|
||||||
|
begin
|
||||||
|
if (vTable.version < 3) then begin
|
||||||
|
end
|
||||||
|
else begin
|
||||||
|
CryptKeyCallbackVTable(vTable).dispose(Self);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
function IKeyHolderPlugin.keyCallback(status: IStatus; callback: ICryptKeyCallback): Integer;
|
function IKeyHolderPlugin.keyCallback(status: IStatus; callback: ICryptKeyCallback): Integer;
|
||||||
begin
|
begin
|
||||||
Result := KeyHolderPluginVTable(vTable).keyCallback(Self, status, callback);
|
Result := KeyHolderPluginVTable(vTable).keyCallback(Self, status, callback);
|
||||||
@ -13432,6 +13463,34 @@ begin
|
|||||||
end
|
end
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
function ICryptKeyCallbackImpl_afterAttachDispatcher(this: ICryptKeyCallback; status: IStatus; dbName: PAnsiChar; attStatus: IStatus): Cardinal; cdecl;
|
||||||
|
begin
|
||||||
|
Result := 0;
|
||||||
|
try
|
||||||
|
Result := ICryptKeyCallbackImpl(this).afterAttach(status, dbName, attStatus);
|
||||||
|
except
|
||||||
|
on e: Exception do FbException.catchException(status, e);
|
||||||
|
end
|
||||||
|
end;
|
||||||
|
|
||||||
|
function ICryptKeyCallbackImpl.afterAttach(status: IStatus; dbName: PAnsiChar; attStatus: IStatus): Cardinal;
|
||||||
|
begin
|
||||||
|
Result := 0;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure ICryptKeyCallbackImpl_disposeDispatcher(this: ICryptKeyCallback); cdecl;
|
||||||
|
begin
|
||||||
|
try
|
||||||
|
ICryptKeyCallbackImpl(this).dispose();
|
||||||
|
except
|
||||||
|
on e: Exception do FbException.catchException(nil, e);
|
||||||
|
end
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure ICryptKeyCallbackImpl.dispose();
|
||||||
|
begin
|
||||||
|
end;
|
||||||
|
|
||||||
var
|
var
|
||||||
ICryptKeyCallbackImpl_vTable: CryptKeyCallbackVTable;
|
ICryptKeyCallbackImpl_vTable: CryptKeyCallbackVTable;
|
||||||
|
|
||||||
@ -17517,8 +17576,10 @@ initialization
|
|||||||
IWireCryptPluginImpl_vTable.setSpecificData := @IWireCryptPluginImpl_setSpecificDataDispatcher;
|
IWireCryptPluginImpl_vTable.setSpecificData := @IWireCryptPluginImpl_setSpecificDataDispatcher;
|
||||||
|
|
||||||
ICryptKeyCallbackImpl_vTable := CryptKeyCallbackVTable.create;
|
ICryptKeyCallbackImpl_vTable := CryptKeyCallbackVTable.create;
|
||||||
ICryptKeyCallbackImpl_vTable.version := 2;
|
ICryptKeyCallbackImpl_vTable.version := 3;
|
||||||
ICryptKeyCallbackImpl_vTable.callback := @ICryptKeyCallbackImpl_callbackDispatcher;
|
ICryptKeyCallbackImpl_vTable.callback := @ICryptKeyCallbackImpl_callbackDispatcher;
|
||||||
|
ICryptKeyCallbackImpl_vTable.afterAttach := @ICryptKeyCallbackImpl_afterAttachDispatcher;
|
||||||
|
ICryptKeyCallbackImpl_vTable.dispose := @ICryptKeyCallbackImpl_disposeDispatcher;
|
||||||
|
|
||||||
IKeyHolderPluginImpl_vTable := KeyHolderPluginVTable.create;
|
IKeyHolderPluginImpl_vTable := KeyHolderPluginVTable.create;
|
||||||
IKeyHolderPluginImpl_vTable.version := 5;
|
IKeyHolderPluginImpl_vTable.version := 5;
|
||||||
|
@ -8393,7 +8393,10 @@ static bool init(CheckStatusWrapper* status, ClntAuthBlock& cBlock, rem_port* po
|
|||||||
|
|
||||||
port->port_client_crypt_callback = cryptCallback;
|
port->port_client_crypt_callback = cryptCallback;
|
||||||
cBlock.createCryptCallback(&port->port_client_crypt_callback);
|
cBlock.createCryptCallback(&port->port_client_crypt_callback);
|
||||||
|
auto cb = port->port_client_crypt_callback;
|
||||||
|
|
||||||
|
for(;;)
|
||||||
|
{
|
||||||
// Make attach packet
|
// Make attach packet
|
||||||
P_ATCH* attach = &packet->p_atch;
|
P_ATCH* attach = &packet->p_atch;
|
||||||
packet->p_operation = op;
|
packet->p_operation = op;
|
||||||
@ -8403,10 +8406,38 @@ static bool init(CheckStatusWrapper* status, ClntAuthBlock& cBlock, rem_port* po
|
|||||||
attach->p_atch_dpb.cstr_address = dpb.getBuffer();
|
attach->p_atch_dpb.cstr_address = dpb.getBuffer();
|
||||||
|
|
||||||
send_packet(port, packet);
|
send_packet(port, packet);
|
||||||
|
try
|
||||||
|
{
|
||||||
authReceiveResponse(false, cBlock, port, rdb, status, packet, true);
|
authReceiveResponse(false, cBlock, port, rdb, status, packet, true);
|
||||||
|
}
|
||||||
|
catch (const Exception& ex)
|
||||||
|
{
|
||||||
|
FbLocalStatus stAttach;
|
||||||
|
ex.stuffException(&stAttach);
|
||||||
|
|
||||||
|
const ISC_STATUS* v = stAttach->getErrors();
|
||||||
|
|
||||||
|
if (cb && (fb_utils::containsErrorCode(v, isc_bad_crypt_key) ||
|
||||||
|
fb_utils::containsErrorCode(v, isc_db_crypt_key)) &&
|
||||||
|
(cb->afterAttach(status, file_name.c_str(), &stAttach) == ICryptKeyCallback::DO_RETRY))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
status->init();
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
|
||||||
|
// response is success
|
||||||
|
if (cb)
|
||||||
|
{
|
||||||
|
cb->afterAttach(status, file_name.c_str(), nullptr);
|
||||||
|
status->init();
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
catch (const Exception& ex)
|
catch (const Exception& ex)
|
||||||
{
|
{
|
||||||
// report primary init error
|
// report primary init error
|
||||||
@ -9829,6 +9860,14 @@ Firebird::ICryptKeyCallback* ClntAuthBlock::ClientCrypt::create(const Config* co
|
|||||||
|
|
||||||
unsigned ClntAuthBlock::ClientCrypt::callback(unsigned dlen, const void* data, unsigned blen, void* buffer)
|
unsigned ClntAuthBlock::ClientCrypt::callback(unsigned dlen, const void* data, unsigned blen, void* buffer)
|
||||||
{
|
{
|
||||||
|
// if we have a retry iface - use it
|
||||||
|
if (afterIface)
|
||||||
|
{
|
||||||
|
unsigned retlen = afterIface->callback(dlen, data, blen, buffer);
|
||||||
|
HANDSHAKE_DEBUG(fprintf(stderr, "Iface %p returned %d\n", currentIface, retlen));
|
||||||
|
return retlen;
|
||||||
|
}
|
||||||
|
|
||||||
HANDSHAKE_DEBUG(fprintf(stderr, "dlen=%d blen=%d\n", dlen, blen));
|
HANDSHAKE_DEBUG(fprintf(stderr, "dlen=%d blen=%d\n", dlen, blen));
|
||||||
|
|
||||||
int loop = 0;
|
int loop = 0;
|
||||||
@ -9854,10 +9893,14 @@ unsigned ClntAuthBlock::ClientCrypt::callback(unsigned dlen, const void* data, u
|
|||||||
unsigned retlen = currentIface->callback(dlen, data, blen, buffer);
|
unsigned retlen = currentIface->callback(dlen, data, blen, buffer);
|
||||||
HANDSHAKE_DEBUG(fprintf(stderr, "Iface %p returned %d\n", currentIface, retlen));
|
HANDSHAKE_DEBUG(fprintf(stderr, "Iface %p returned %d\n", currentIface, retlen));
|
||||||
if (retlen)
|
if (retlen)
|
||||||
|
{
|
||||||
|
triedPlugins.add(pluginItr);
|
||||||
return retlen;
|
return retlen;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// no success with iface - clear it
|
// no success with iface - clear it
|
||||||
|
currentIface->dispose();
|
||||||
// appropriate data structures to be released by plugin cleanup code
|
// appropriate data structures to be released by plugin cleanup code
|
||||||
currentIface = nullptr;
|
currentIface = nullptr;
|
||||||
}
|
}
|
||||||
@ -9870,3 +9913,48 @@ unsigned ClntAuthBlock::ClientCrypt::callback(unsigned dlen, const void* data, u
|
|||||||
// no luck with suggested data
|
// no luck with suggested data
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsigned ClntAuthBlock::ClientCrypt::afterAttach(CheckStatusWrapper* st, const char* dbName, const IStatus* attStatus)
|
||||||
|
{
|
||||||
|
while (triedPlugins.hasData())
|
||||||
|
{
|
||||||
|
if (afterIface)
|
||||||
|
{
|
||||||
|
auto rc = afterIface->afterAttach(st, dbName, attStatus);
|
||||||
|
if (attStatus && (rc == NO_RETRY))
|
||||||
|
{
|
||||||
|
afterIface->dispose();
|
||||||
|
afterIface = nullptr;
|
||||||
|
triedPlugins.remove();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
FbLocalStatus st;
|
||||||
|
afterIface = triedPlugins.get()->chainHandle(&st);
|
||||||
|
check(&st, isc_interface_version_too_old);
|
||||||
|
fb_assert(afterIface);
|
||||||
|
if (!afterIface)
|
||||||
|
triedPlugins.remove();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return NO_RETRY;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClntAuthBlock::ClientCrypt::destroy()
|
||||||
|
{
|
||||||
|
if (currentIface)
|
||||||
|
{
|
||||||
|
currentIface->dispose();
|
||||||
|
currentIface = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (afterIface)
|
||||||
|
{
|
||||||
|
afterIface->dispose();
|
||||||
|
afterIface = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -712,6 +712,7 @@ public:
|
|||||||
virtual void wakeup(unsigned int length, const void* data) = 0;
|
virtual void wakeup(unsigned int length, const void* data) = 0;
|
||||||
virtual Firebird::ICryptKeyCallback* getInterface() = 0;
|
virtual Firebird::ICryptKeyCallback* getInterface() = 0;
|
||||||
virtual void stop() = 0;
|
virtual void stop() = 0;
|
||||||
|
virtual void destroy() = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
// CryptKey implementation
|
// CryptKey implementation
|
||||||
@ -859,21 +860,76 @@ private:
|
|||||||
unsigned nextKey; // First key to be analyzed
|
unsigned nextKey; // First key to be analyzed
|
||||||
|
|
||||||
class ClientCrypt final :
|
class ClientCrypt final :
|
||||||
public Firebird::VersionedIface<Firebird::ICryptKeyCallbackImpl<ClientCrypt, Firebird::CheckStatusWrapper> >
|
public Firebird::VersionedIface<Firebird::ICryptKeyCallbackImpl<ClientCrypt, Firebird::CheckStatusWrapper> >,
|
||||||
|
public Firebird::GlobalStorage
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
ClientCrypt()
|
ClientCrypt()
|
||||||
: pluginItr(Firebird::IPluginManager::TYPE_KEY_HOLDER, "NoDefault"), currentIface(nullptr)
|
: pluginItr(Firebird::IPluginManager::TYPE_KEY_HOLDER, "NoDefault"),
|
||||||
|
currentIface(nullptr), afterIface(nullptr),
|
||||||
|
triedPlugins(getPool())
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
|
~ClientCrypt()
|
||||||
|
{
|
||||||
|
destroy();
|
||||||
|
}
|
||||||
|
|
||||||
Firebird::ICryptKeyCallback* create(const Firebird::Config* conf);
|
Firebird::ICryptKeyCallback* create(const Firebird::Config* conf);
|
||||||
|
|
||||||
// Firebird::ICryptKeyCallback implementation
|
// Firebird::ICryptKeyCallback implementation
|
||||||
unsigned callback(unsigned dataLength, const void* data, unsigned bufferLength, void* buffer);
|
unsigned callback(unsigned dataLength, const void* data, unsigned bufferLength, void* buffer);
|
||||||
|
unsigned afterAttach(Firebird::CheckStatusWrapper* st, const char* dbName, const Firebird::IStatus* attStatus);
|
||||||
|
void destroy();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Firebird::GetPlugins<Firebird::IKeyHolderPlugin> pluginItr;
|
typedef Firebird::GetPlugins<Firebird::IKeyHolderPlugin> KeyHolderItr;
|
||||||
|
KeyHolderItr pluginItr;
|
||||||
Firebird::ICryptKeyCallback* currentIface;
|
Firebird::ICryptKeyCallback* currentIface;
|
||||||
|
Firebird::ICryptKeyCallback* afterIface;
|
||||||
|
|
||||||
|
class TriedPlugins
|
||||||
|
{
|
||||||
|
typedef Firebird::Pair<Firebird::Left<Firebird::PathName, Firebird::IKeyHolderPlugin*> > TriedPlugin;
|
||||||
|
Firebird::ObjectsArray<TriedPlugin> data;
|
||||||
|
|
||||||
|
public:
|
||||||
|
TriedPlugins(MemoryPool& p)
|
||||||
|
: data(p)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
void add(KeyHolderItr& itr)
|
||||||
|
{
|
||||||
|
for (auto& p : data)
|
||||||
|
{
|
||||||
|
if (p.first == itr.name())
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
TriedPlugin tp(itr.name(), itr.plugin());
|
||||||
|
data.add(tp);
|
||||||
|
tp.second->addRef();
|
||||||
|
}
|
||||||
|
|
||||||
|
void remove()
|
||||||
|
{
|
||||||
|
fb_assert(data.hasData());
|
||||||
|
data[0].second->release();
|
||||||
|
data.remove(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool hasData() const
|
||||||
|
{
|
||||||
|
return data.hasData();
|
||||||
|
}
|
||||||
|
|
||||||
|
Firebird::IKeyHolderPlugin* get()
|
||||||
|
{
|
||||||
|
return data[0].second;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
TriedPlugins triedPlugins;
|
||||||
};
|
};
|
||||||
ClientCrypt clientCrypt;
|
ClientCrypt clientCrypt;
|
||||||
Firebird::ICryptKeyCallback** createdInterface;
|
Firebird::ICryptKeyCallback** createdInterface;
|
||||||
|
@ -114,33 +114,6 @@ public:
|
|||||||
: port(prt), replyLength(0), replyData(NULL), stopped(false), wake(false)
|
: port(prt), replyLength(0), replyData(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 || port->port_type != rem_port::INET)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
Reference r(*port);
|
|
||||||
|
|
||||||
replyData = buffer;
|
|
||||||
replyLength = 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 replyLength;
|
|
||||||
}
|
|
||||||
|
|
||||||
void wakeup(unsigned int wakeLength, const void* wakeData)
|
void wakeup(unsigned int wakeLength, const void* wakeData)
|
||||||
{
|
{
|
||||||
if (replyLength > wakeLength)
|
if (replyLength > wakeLength)
|
||||||
@ -167,6 +140,34 @@ public:
|
|||||||
return stopped;
|
return stopped;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ICryptKeyCallback implementation
|
||||||
|
unsigned int callback(unsigned int dataLength, const void* data,
|
||||||
|
unsigned int bufferLength, void* buffer) override
|
||||||
|
{
|
||||||
|
if (stopped)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (port->port_protocol < PROTOCOL_VERSION13 || port->port_type != rem_port::INET)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
Reference r(*port);
|
||||||
|
|
||||||
|
replyData = buffer;
|
||||||
|
replyLength = 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 replyLength;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
rem_port* port;
|
rem_port* port;
|
||||||
Semaphore sem;
|
Semaphore sem;
|
||||||
@ -187,29 +188,11 @@ public:
|
|||||||
|
|
||||||
~CryptKeyCallback()
|
~CryptKeyCallback()
|
||||||
{
|
{
|
||||||
|
dispose();
|
||||||
if (keyHolder)
|
if (keyHolder)
|
||||||
PluginManagerInterfacePtr()->releasePlugin(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);
|
|
||||||
loadClientKey();
|
|
||||||
unsigned rc = keyCallback ?
|
|
||||||
keyCallback->callback(dataLength, data, bufferLength, buffer) :
|
|
||||||
// use legacy behavior if holders do wish to accept keys from client
|
|
||||||
networkCallback.callback(dataLength, data, bufferLength, buffer);
|
|
||||||
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
void loadClientKey()
|
void loadClientKey()
|
||||||
{
|
{
|
||||||
if (keyCallback)
|
if (keyCallback)
|
||||||
@ -256,6 +239,43 @@ public:
|
|||||||
networkCallback.stop();
|
networkCallback.stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ICryptKeyCallback implementation
|
||||||
|
unsigned int callback(unsigned int dataLength, const void* data,
|
||||||
|
unsigned int bufferLength, void* buffer) override
|
||||||
|
{
|
||||||
|
if (keyCallback)
|
||||||
|
return keyCallback->callback(dataLength, data, bufferLength, buffer);
|
||||||
|
|
||||||
|
if (networkCallback.isStopped())
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
Reference r(*port);
|
||||||
|
loadClientKey();
|
||||||
|
unsigned rc = keyCallback ?
|
||||||
|
keyCallback->callback(dataLength, data, bufferLength, buffer) :
|
||||||
|
// use legacy behavior if holders do wish to accept keys from client
|
||||||
|
networkCallback.callback(dataLength, data, bufferLength, buffer);
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned afterAttach(Firebird::CheckStatusWrapper* st, const char* dbName,
|
||||||
|
const Firebird::IStatus* attStatus) override
|
||||||
|
{
|
||||||
|
return NO_RETRY;
|
||||||
|
}
|
||||||
|
|
||||||
|
void dispose() override
|
||||||
|
{
|
||||||
|
if (keyCallback)
|
||||||
|
{
|
||||||
|
LocalStatus ls;
|
||||||
|
CheckStatusWrapper st(&ls);
|
||||||
|
keyCallback->dispose();
|
||||||
|
keyCallback = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
rem_port* port;
|
rem_port* port;
|
||||||
NetworkCallback networkCallback;
|
NetworkCallback networkCallback;
|
||||||
@ -273,22 +293,27 @@ public:
|
|||||||
~ServerCallback()
|
~ServerCallback()
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
void wakeup(unsigned int length, const void* data)
|
void wakeup(unsigned int length, const void* data) override
|
||||||
{
|
{
|
||||||
cryptCallback.wakeup(length, data);
|
cryptCallback.wakeup(length, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
ICryptKeyCallback* getInterface()
|
ICryptKeyCallback* getInterface() override
|
||||||
{
|
{
|
||||||
cryptCallback.loadClientKey();
|
cryptCallback.loadClientKey();
|
||||||
return &cryptCallback;
|
return &cryptCallback;
|
||||||
}
|
}
|
||||||
|
|
||||||
void stop()
|
void stop() override
|
||||||
{
|
{
|
||||||
cryptCallback.stop();
|
cryptCallback.stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void destroy() override
|
||||||
|
{
|
||||||
|
cryptCallback.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
CryptKeyCallback cryptCallback;
|
CryptKeyCallback cryptCallback;
|
||||||
};
|
};
|
||||||
@ -2494,6 +2519,7 @@ void DatabaseAuth::accept(PACKET* send, Auth::WriterImplementation* authBlock)
|
|||||||
CheckStatusWrapper status_vector(&ls);
|
CheckStatusWrapper status_vector(&ls);
|
||||||
|
|
||||||
fb_assert(authPort->port_server_crypt_callback);
|
fb_assert(authPort->port_server_crypt_callback);
|
||||||
|
authPort->port_server_crypt_callback->destroy();
|
||||||
provider->setDbCryptCallback(&status_vector, authPort->port_server_crypt_callback->getInterface());
|
provider->setDbCryptCallback(&status_vector, authPort->port_server_crypt_callback->getInterface());
|
||||||
|
|
||||||
if (!(status_vector.getState() & Firebird::IStatus::STATE_ERRORS))
|
if (!(status_vector.getState() & Firebird::IStatus::STATE_ERRORS))
|
||||||
@ -2512,12 +2538,13 @@ void DatabaseAuth::accept(PACKET* send, Auth::WriterImplementation* authBlock)
|
|||||||
#endif
|
#endif
|
||||||
rdb->rdb_port = authPort;
|
rdb->rdb_port = authPort;
|
||||||
rdb->rdb_iface = iface;
|
rdb->rdb_iface = iface;
|
||||||
|
|
||||||
|
authPort->port_server_crypt_callback->stop();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
CSTRING* const s = &send->p_resp.p_resp_data;
|
CSTRING* const s = &send->p_resp.p_resp_data;
|
||||||
authPort->extractNewKeys(s);
|
authPort->extractNewKeys(s);
|
||||||
authPort->port_server_crypt_callback->stop();
|
|
||||||
authPort->send_response(send, 0, s->cstr_length, &status_vector, false);
|
authPort->send_response(send, 0, s->cstr_length, &status_vector, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -6214,6 +6241,7 @@ ISC_STATUS rem_port::service_attach(const char* service_name,
|
|||||||
CheckStatusWrapper status_vector(&ls);
|
CheckStatusWrapper status_vector(&ls);
|
||||||
|
|
||||||
fb_assert(port_server_crypt_callback);
|
fb_assert(port_server_crypt_callback);
|
||||||
|
port_server_crypt_callback->destroy();
|
||||||
provider->setDbCryptCallback(&status_vector, port_server_crypt_callback->getInterface());
|
provider->setDbCryptCallback(&status_vector, port_server_crypt_callback->getInterface());
|
||||||
|
|
||||||
if (!(status_vector.getState() & Firebird::IStatus::STATE_ERRORS))
|
if (!(status_vector.getState() & Firebird::IStatus::STATE_ERRORS))
|
||||||
@ -6233,9 +6261,10 @@ ISC_STATUS rem_port::service_attach(const char* service_name,
|
|||||||
rdb->rdb_port = this;
|
rdb->rdb_port = this;
|
||||||
Svc* svc = rdb->rdb_svc = FB_NEW Svc;
|
Svc* svc = rdb->rdb_svc = FB_NEW Svc;
|
||||||
svc->svc_iface = iface;
|
svc->svc_iface = iface;
|
||||||
}
|
|
||||||
}
|
|
||||||
port_server_crypt_callback->stop();
|
port_server_crypt_callback->stop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return this->send_response(sendL, 0, sendL->p_resp.p_resp_data.cstr_length, &status_vector,
|
return this->send_response(sendL, 0, sendL->p_resp.p_resp_data.cstr_length, &status_vector,
|
||||||
false);
|
false);
|
||||||
|
Loading…
Reference in New Issue
Block a user