8
0
mirror of https://github.com/FirebirdSQL/firebird.git synced 2025-01-22 22:43:03 +01:00

Implemented CORE-3861: Make it possible to encrypt database

Also some cleanups, the most important are:                                                                                                                   
- meaningful ctor on Jrd::Lock, helping to avoid code dup                                                                                                     
- avoid unneeded h-file dependencies, making boot build engine dependent
This commit is contained in:
alexpeshkoff 2012-05-31 16:53:42 +00:00
parent ed2cf92cb0
commit 2a01e4bcf9
109 changed files with 2972 additions and 881 deletions

View File

@ -359,10 +359,10 @@ $(NBACKUP): $(NBACKUP_Objects) $(COMMON_LIB)
#
.PHONY: udr legacy_user_management trace auth_debug
makePluginName= $(PLUGINS)/$(LIB_PREFIX)$(1).$(SHRLIB_EXT)
UDR_PLUGIN = $(call makePluginName,udr_engine)
LEGACY_USER_MANAGER = $(call makePluginName,Legacy_UserManager)
SRP_USER_MANAGER = $(call makePluginName,Srp)
FBTRACE = $(call makePluginName,fbtrace)
AUTH_DEBUGGER = $(call makePluginName,Auth_Debug)
BUILD_DEBUG:=
@ -446,6 +446,7 @@ $(FIREBIRD_MSG): $(BUILD_FILE) msg.timestamp
$(BUILD_FILE): $(BUILD_Objects) $(COMMON_LIB)
$(EXE_LINK) $(EXE_LINK_OPTIONS) $^ -o $@ $(FIREBIRD_LIBRARY_LINK) $(LINK_LIBS)
#---------------------------------------------------------------------------
# This target builds the include files for distribution with the release

View File

@ -27,7 +27,14 @@
# Contributor(s):
# Adriano dos Santos Fernandes
#
ROOT=../..
ROOT=$(shell cd ../..; pwd)
ifeq ($(IsDeveloper), Y)
DefaultTarget := Debug
else
DefaultTarget := Release
endif
CPPFLAGS+= -I$(FIREBIRD)/include
@ -38,26 +45,23 @@ include $(ROOT)/gen/make.shared.variables
@SET_MAKE@
PLUGINS= $(FIREBIRD)/plugins
# Override make.defaults
LINK_PLUGIN_SYMBOLS = $(call LIB_LINK_MAPFILE,../$(PLUGIN_VERS))
UDR_Files = UdrCppExample.cpp
UDR_Sources = $(addprefix ../examples/udr/, $(UDR_Files))
UDR_Objects = $(addprefix $(OBJ)/, $(addsuffix .o, $(basename $(UDR_Sources))))
.PHONY: all udrcpp_example dc_example kh_example
all: udrcpp_example dc_example kh_example
UDR_Objects = $(call makeObjects,../examples/udr,UdrCppExample.cpp)
UDR_Plugin = $(PLUGINS)/udr/$(LIB_PREFIX)udrcpp_example.$(SHRLIB_EXT)
AllObjects = $(UDR_Objects)
Dependencies = $(AllObjects:.o=.d)
udrcpp_example: $(UDR_Plugin)
.PHONY: all udrcpp_example
all: udrcpp_example
udrcpp_example: $(PLUGINS)/udr/$(LIB_PREFIX)udrcpp_example.$(SHRLIB_EXT)
$(PLUGINS)/udr/$(LIB_PREFIX)udrcpp_example.$(SHRLIB_EXT): $(UDR_Objects)
$(UDR_Plugin): $(UDR_Objects)
ifeq ($(PLATFORM),DARWIN)
$(LIB_LINK) $(LIB_BUNDLE_OPTIONS) -o $@ $^ @PTHREAD_CFLAGS@ @PTHREAD_LIBS@ \
$(FIREBIRD_LIBRARY_LINK)
@ -67,6 +71,28 @@ else
$(FIREBIRD_LIBRARY_LINK)
endif
DC_Objects = $(call makeObjects,../examples/dbcrypt,DbCrypt.cpp)
DC_Plugin = $(call makePluginName,DbCrypt_example)
AllObjects += $(DC_Objects)
dc_example: $(DC_Plugin)
$(DC_Plugin): $(DC_Objects)
$(LINK_PLUGIN) $(call LIB_LINK_SONAME,$(notdir $@).0) -o $@ $^ $(LINK_PLUG_LIBS) $(FIREBIRD_LIBRARY_LINK)
KH_Objects = $(call makeObjects,../examples/dbcrypt,CryptKeyHolder.cpp)
KH_Plugin = $(call makePluginName,CryptKeyHolder_example)
AllObjects += $(KH_Objects)
kh_example: $(KH_Plugin)
$(KH_Plugin): $(KH_Objects)
$(LINK_PLUGIN) $(call LIB_LINK_SONAME,$(notdir $@).0) -o $@ $^ $(LINK_PLUG_LIBS) $(FIREBIRD_LIBRARY_LINK)
include $(ROOT)/gen/make.shared.targets
Dependencies = $(AllObjects:.o=.d)
-include $(Dependencies)

View File

@ -345,6 +345,8 @@ fb_get_master_interface
fb_get_database_handle
fb_get_transaction_handle
fb_database_crypt_callback
# Other misc functions
isc_ftof

View File

@ -336,7 +336,6 @@ FBSVCMGR = $(BIN)/fbsvcmgr$(EXEC_EXT)
FBTRACEMGR = $(BIN)/fbtracemgr$(EXEC_EXT)
GSTAT = $(BIN)/gstat$(EXEC_EXT)
NBACKUP = $(BIN)/nbackup$(EXEC_EXT)
FBTRACE = $(PLUGINS)/$(LIB_PREFIX)fbtrace.$(SHRLIB_EXT)
LOCKPRINT = $(BIN)/fb_lock_print$(EXEC_EXT)
GSEC = $(BIN)/gsec$(EXEC_EXT)
GFIX = $(BIN)/gfix$(EXEC_EXT)

View File

@ -15,6 +15,8 @@ endif
dirObjects= $(call dirMaster,$(1)) $(call dirOs,$(1)) $(call dirFallBack,$(1))
makePluginName= $(PLUGINS)/$(LIB_PREFIX)$(1).$(SHRLIB_EXT)
# Collect all object files here
AllObjects=

View File

@ -354,6 +354,7 @@ EXPORTS
fb_get_master_interface
fb_get_database_handle
fb_get_transaction_handle
fb_database_crypt_callback
gds__trace
gds__trace_raw

View File

@ -0,0 +1,217 @@
/*
* PROGRAM: Firebird samples.
* MODULE: CryptApplication.cpp
* DESCRIPTION: Sample of passing a key to crypt plugin
*
* The contents of this file are subject to the Initial
* Developer's Public License Version 1.0 (the "License");
* you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
* http://www.ibphoenix.com/main.nfs?a=ibphoenix&page=ibp_idpl.
*
* Software distributed under the License is distributed AS IS,
* WITHOUT WARRANTY OF ANY KIND, either express or implied.
* See the License for the specific language governing rights
* and limitations under the License.
*
* The Original Code was created by Alex Peshkov
* for the Firebird Open Source RDBMS project.
*
* Copyright (c) 2012 Alex Peshkov <peshkoff at mail.ru>
* and all contributors signed below.
*
* All Rights Reserved.
* Contributor(s): ______________________________________.
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ibase.h>
#include <firebird/Crypt.h>
#include <firebird/Provider.h>
using namespace Firebird;
class CryptKey : public ICryptKeyCallback
{
public:
unsigned int FB_CARG callback(unsigned int, const void*, unsigned int length, void* buffer)
{
if (length > 0 && buffer)
{
char k = 0x5a;
memcpy(buffer, &k, 1);
fprintf(stderr, "\nTransfered key to server\n");
}
return 1;
}
int FB_CARG getVersion()
{
return FB_CRYPT_CALLBACK_VERSION;
}
IPluginModule* FB_CARG getModule()
{
return NULL; // OK for application, not for plugin
}
};
class App
{
public:
App() :
master(fb_get_master_interface()), status(master->getStatus()),
p(NULL), att(NULL), tra(NULL)
{ }
~App()
{
if (tra)
{
tra->rollback(status);
if (!status->isSuccess())
{
print("rollback");
tra->release();
}
}
if (att)
{
att->detach(status);
if (!status->isSuccess())
{
print("detach");
att->release();
}
}
if (p)
{
p->release();
}
status->dispose();
}
enum Action {NONE, ENC, DEC};
void Execute(const char* dbName, const Action a)
{
status->init();
p = master->getDispatcher();
p->setDbCryptCallback(status, &key);
if (!status->isSuccess())
throw "setDbCryptCallback";
char s[256];
sprintf(s, "localhost:%s", dbName);
att = p->attachDatabase(status, s, 0, NULL);
if (!status->isSuccess())
throw "attachDatabase";
if (a != NONE)
{
tra = att->startTransaction(status, 0, NULL);
if (!status->isSuccess())
throw "startTransaction";
}
if (a == ENC)
{
att->execute(status, tra, 0,
"ALTER DATABASE ENCRYPT WITH \"DbCrypt_example\"", 3, 0, NULL, NULL);
if (!status->isSuccess())
throw "execute";
}
if (a == DEC)
{
att->execute(status, tra, 0, "ALTER DATABASE DECRYPT", 3, 0, NULL, NULL);
if (!status->isSuccess())
throw "execute";
}
if (tra)
{
tra->commit(status);
if (!status->isSuccess())
throw "commit";
tra = NULL;
}
printf("Providing key for crypt plugin - press enter to continue ...");
getchar();
att->detach(status);
if (!status->isSuccess())
throw "detach";
att = NULL;
p->release();
p = NULL;
}
void print(const char* where)
{
fprintf(stderr, "Error in %s: ", where);
isc_print_status(status->get());
}
private:
IMaster* master;
IStatus* status;
IProvider* p;
IAttachment* att;
ITransaction* tra;
CryptKey key;
};
int usage()
{
fprintf(stderr, "Usage: CryptApplication [ -e | -d ] { db-name }\n");
return 2;
}
int main(int ac, char** av)
{
App::Action act = App::NONE;
if (ac < 2 || ac > 3)
return usage();
if (ac == 3)
{
if (av[1][0] != '-')
return usage();
switch(av[1][1])
{
case 'e':
act = App::ENC;
break;
case 'd':
act = App::DEC;
break;
default:
return usage();
}
av++;
}
setenv("ISC_USER", "sysdba", 0);
setenv("ISC_PASSWORD", "masterkey", 0);
App app;
try
{
app.Execute(av[1], act);
}
catch(const char* where)
{
app.print(where);
return 1;
}
return 0;
}

View File

@ -0,0 +1,278 @@
/*
* PROGRAM: Firebird samples.
* MODULE: CryptKeyHolder.cpp
* DESCRIPTION: Sample of how key holder may be written.
*
* The contents of this file are subject to the Initial
* Developer's Public License Version 1.0 (the "License");
* you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
* http://www.ibphoenix.com/main.nfs?a=ibphoenix&page=ibp_idpl.
*
* Software distributed under the License is distributed AS IS,
* WITHOUT WARRANTY OF ANY KIND, either express or implied.
* See the License for the specific language governing rights
* and limitations under the License.
*
* The Original Code was created by Alex Peshkov
* for the Firebird Open Source RDBMS project.
*
* Copyright (c) 2012 Alex Peshkov <peshkoff at mail.ru>
* and all contributors signed below.
*
* All Rights Reserved.
* Contributor(s): ______________________________________.
*/
#include <stdio.h>
#include <string.h>
#include "firebird.h"
#include "firebird/Crypt.h"
#include "../common/classes/fb_atomic.h"
using namespace Firebird;
namespace
{
IMaster* master = NULL;
IPluginManager* pluginManager = NULL;
class PluginModule : public IPluginModule
{
public:
PluginModule()
: flag(false)
{ }
void registerMe()
{
pluginManager->registerModule(this);
flag = true;
}
~PluginModule()
{
if (flag)
{
pluginManager->unregisterModule(this);
doClean();
}
}
int FB_CARG getVersion()
{
return FB_PLUGIN_MODULE_VERSION;
}
IPluginModule* FB_CARG getModule()
{
return this;
}
void FB_CARG doClean()
{
flag = false;
}
private:
bool flag;
};
PluginModule module;
class CryptKeyHolder : public IKeyHolderPlugin
{
public:
explicit CryptKeyHolder(IPluginConfig* cnf)
: callbackInterface(this), config(cnf), key(0), owner(NULL)
{
config->addRef();
}
~CryptKeyHolder()
{
config->release();
}
// IKeyHolderPlugin implementation
virtual int FB_CARG keyCallback(IStatus* status, ICryptKeyCallback* callback);
virtual ICryptKeyCallback* FB_CARG keyHandle(IStatus* status, const char* keyName);
int FB_CARG release()
{
if (--refCounter == 0)
{
delete this;
return 0;
}
return 1;
}
void FB_CARG addRef()
{
++refCounter;
}
int FB_CARG getVersion()
{
return FB_KEYHOLDER_PLUGIN_VERSION;
}
IPluginModule* FB_CARG getModule()
{
return &module;
}
void FB_CARG setOwner(Firebird::IRefCounted* o)
{
owner = o;
}
IRefCounted* FB_CARG getOwner()
{
return owner;
}
UCHAR getKey()
{
return key;
}
private:
class CallbackInterface : public ICryptKeyCallback
{
public:
CallbackInterface(CryptKeyHolder* p)
: parent(p)
{ }
unsigned int FB_CARG callback(unsigned int, const void*, unsigned int length, void* buffer)
{
UCHAR k = parent->getKey();
if (!k)
{
return 0;
}
if (length > 0 && buffer)
{
memcpy(buffer, &k, 1);
}
return 1;
}
int FB_CARG getVersion()
{
return FB_CRYPT_CALLBACK_VERSION;
}
IPluginModule* FB_CARG getModule()
{
return &module;
}
private:
CryptKeyHolder* parent;
};
CallbackInterface callbackInterface;
IPluginConfig* config;
UCHAR key;
AtomicCounter refCounter;
IRefCounted* owner;
void noKeyError(IStatus* status);
};
void CryptKeyHolder::noKeyError(IStatus* status)
{
ISC_STATUS_ARRAY vector;
vector[0] = isc_arg_gds;
vector[1] = isc_random;
vector[2] = isc_arg_string;
vector[3] = (ISC_STATUS)"Key not set";
vector[4] = isc_arg_end;
status->set(vector);
}
int FB_CARG CryptKeyHolder::keyCallback(IStatus* status, ICryptKeyCallback* callback)
{
status->init();
if (key != 0)
{
return 1;
}
IConfig* def = config->getDefaultConfig();
IConfigEntry* confEntry = def->find("Auto");
def->release();
if (confEntry)
{
char v = *(confEntry->getValue());
confEntry->release();
if (v == '1' || v == 'y' || v == 'Y' || v == 't' || v == 'T')
{
key = 0x5a;
return 1;
}
}
if (callback && callback->callback(0, NULL, 1, &key) != 1)
{
key = 0;
return 0;
}
return 1;
}
ICryptKeyCallback* FB_CARG CryptKeyHolder::keyHandle(IStatus* status, const char* keyName)
{
if (strcmp(keyName, "sample") != 0)
{
return NULL;
}
return &callbackInterface;
}
class Factory : public IPluginFactory
{
public:
int FB_CARG getVersion()
{
return FB_PLUGIN_FACTORY_VERSION;
}
IPluginModule* FB_CARG getModule()
{
return &module;
}
IPluginBase* FB_CARG createPlugin(IPluginConfig* factoryParameter)
{
CryptKeyHolder* p = new CryptKeyHolder(factoryParameter);
p->addRef();
return p;
}
};
Factory factory;
} // anonymous namespace
extern "C" void FB_PLUGIN_ENTRY_POINT(Firebird::IMaster* m)
{
master = m;
pluginManager = master->getPluginManager();
module.registerMe();
pluginManager->registerPluginFactory(PluginType::KeyHolder, "CryptKeyHolder_example",
&factory);
}

View File

@ -0,0 +1,266 @@
/*
* PROGRAM: Firebird samples.
* MODULE: DbCrypt.cpp
* DESCRIPTION: Sample of how diskcrypt may be written.
*
* The contents of this file are subject to the Initial
* Developer's Public License Version 1.0 (the "License");
* you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
* http://www.ibphoenix.com/main.nfs?a=ibphoenix&page=ibp_idpl.
*
* Software distributed under the License is distributed AS IS,
* WITHOUT WARRANTY OF ANY KIND, either express or implied.
* See the License for the specific language governing rights
* and limitations under the License.
*
* The Original Code was created by Alex Peshkov
* for the Firebird Open Source RDBMS project.
*
* Copyright (c) 2012 Alex Peshkov <peshkoff at mail.ru>
* and all contributors signed below.
*
* All Rights Reserved.
* Contributor(s): ______________________________________.
*/
#include "firebird.h"
#include "firebird/Crypt.h"
#include "../common/classes/fb_atomic.h"
using namespace Firebird;
namespace
{
IMaster* master = NULL;
IPluginManager* pluginManager = NULL;
class PluginModule : public IPluginModule
{
public:
PluginModule()
: flag(false)
{ }
void registerMe()
{
pluginManager->registerModule(this);
flag = true;
}
~PluginModule()
{
if (flag)
{
pluginManager->unregisterModule(this);
doClean();
}
}
int FB_CARG getVersion()
{
return FB_PLUGIN_MODULE_VERSION;
}
IPluginModule* FB_CARG getModule()
{
return this;
}
void FB_CARG doClean()
{
flag = false;
}
private:
bool flag;
};
PluginModule module;
class DbCrypt : public IDbCryptPlugin
{
public:
explicit DbCrypt(IPluginConfig* cnf)
: config(cnf), key(0), owner(NULL)
{
config->addRef();
}
~DbCrypt()
{
config->release();
}
// ICryptPlugin implementation
void FB_CARG encrypt(IStatus* status, unsigned int length, const void* from, void* to);
void FB_CARG decrypt(IStatus* status, unsigned int length, const void* from, void* to);
void FB_CARG setKey(IStatus* status, unsigned int length, IKeyHolderPlugin** sources);
int FB_CARG release()
{
if (--refCounter == 0)
{
delete this;
return 0;
}
return 1;
}
void FB_CARG addRef()
{
++refCounter;
}
int FB_CARG getVersion()
{
return FB_DBCRYPT_PLUGIN_VERSION;
}
IPluginModule* FB_CARG getModule()
{
return &module;
}
void FB_CARG setOwner(Firebird::IRefCounted* o)
{
owner = o;
}
IRefCounted* FB_CARG getOwner()
{
return owner;
}
private:
IPluginConfig* config;
UCHAR key;
AtomicCounter refCounter;
IRefCounted* owner;
void noKeyError(IStatus* status);
};
void DbCrypt::noKeyError(IStatus* status)
{
ISC_STATUS_ARRAY vector;
vector[0] = isc_arg_gds;
vector[1] = isc_random;
vector[2] = isc_arg_string;
vector[3] = (ISC_STATUS)"Key not set";
vector[4] = isc_arg_end;
status->set(vector);
}
void FB_CARG DbCrypt::encrypt(IStatus* status, unsigned int length, const void* from, void* to)
{
status->init();
if (!key)
{
noKeyError(status);
return;
}
const UCHAR* f = static_cast<const UCHAR*>(from);
UCHAR* t = static_cast<UCHAR*>(to);
while(length--)
{
*t++ = (*f++) + key;
}
}
void FB_CARG DbCrypt::decrypt(IStatus* status, unsigned int length, const void* from, void* to)
{
status->init();
if (!key)
{
noKeyError(status);
return;
}
const UCHAR* f = static_cast<const UCHAR*>(from);
UCHAR* t = static_cast<UCHAR*>(to);
while(length--)
{
*t++ = (*f++) - key;
}
}
void FB_CARG DbCrypt::setKey(IStatus* status, unsigned int length, IKeyHolderPlugin** sources)
{
status->init();
if (key != 0)
return;
IConfig* def = config->getDefaultConfig();
IConfigEntry* confEntry = def->find("Auto");
def->release();
if (confEntry)
{
char v = *(confEntry->getValue());
confEntry->release();
if (v == '1' || v == 'y' || v == 'Y' || v == 't' || v == 'T')
{
key = 0x5a;
return;
}
}
for (unsigned n = 0; n < length; ++n)
{
ICryptKeyCallback* callback = sources[n]->keyHandle(status, "sample");
if (!status->isSuccess())
{
return;
}
if (callback && callback->callback(0, NULL, 1, &key) == 1)
{
return;
}
}
key = 0;
noKeyError(status);
}
class Factory : public IPluginFactory
{
public:
int FB_CARG getVersion()
{
return FB_PLUGIN_FACTORY_VERSION;
}
IPluginModule* FB_CARG getModule()
{
return &module;
}
IPluginBase* FB_CARG createPlugin(IPluginConfig* factoryParameter)
{
DbCrypt* p = new DbCrypt(factoryParameter);
p->addRef();
return p;
}
};
Factory factory;
} // anonymous namespace
extern "C" void FB_PLUGIN_ENTRY_POINT(Firebird::IMaster* m)
{
master = m;
pluginManager = master->getPluginManager();
module.registerMe();
pluginManager->registerPluginFactory(PluginType::DbCrypt, "DbCrypt_example",
&factory);
}

View File

@ -0,0 +1,2 @@
All files in this directory are trivial samples.
They do not perform any real data encryption and should not be used in production!

View File

@ -216,8 +216,7 @@ public:
dpb.insertString(isc_dpb_trusted_role, ADMIN_ROLE, strlen(ADMIN_ROLE));
}
Firebird::RefPtr<Firebird::IProvider> p(Firebird::MasterInterfacePtr()->getDispatcher());
p->release();
Firebird::DispatcherPtr p;
att = p->attachDatabase(status, secDbName, dpb.getBufferLength(), dpb.getBuffer());
if (!status->isSuccess())
{

View File

@ -123,8 +123,7 @@ int SrpServer::authenticate(IStatus* status, IServerBlock* sb, IWriter* writerIn
const char* str = "SYSDBA";
dpb.insertString(isc_dpb_user_name, str, strlen(str));
RefPtr<IProvider> p(MasterInterfacePtr()->getDispatcher());
p->release();
DispatcherPtr p;
att = p->attachDatabase(status, secDbName, dpb.getBufferLength(), dpb.getBuffer());
if (!status->isSuccess())

View File

@ -27,6 +27,7 @@
#include "firebird.h"
#include "../common/IntlUtil.h"
#include "../common/unicode_util.h"
#include "../jrd/intl.h"
#include "../jrd/intl_classes.h"
#include "../intl/country_codes.h"
#include "../common/classes/auto.h"

View File

@ -93,7 +93,6 @@
#include "firebird.h"
#include "gen/iberror.h"
#include "../jrd/jrd.h"
#include "../jrd/intl_classes.h"
#include "../common/IntlUtil.h"
#include "../common/classes/Aligner.h"
@ -380,5 +379,14 @@ ULONG TextType::canonical(ULONG srcLen, const UCHAR* src, ULONG dstLen, UCHAR* d
return srcLen / getCharSet()->minBytesPerChar();
}
BYTE TextType::getCanonicalWidth() const
{
return tt->texttype_canonical_width;
}
USHORT TextType::getFlags() const
{
return tt->texttype_flags;
}
} // namespace Jrd

View File

@ -30,6 +30,8 @@
#ifndef JRD_TEXTTYPE_H
#define JRD_TEXTTYPE_H
#include "../common/classes/MetaName.h"
struct texttype;
namespace Jrd {
@ -85,15 +87,8 @@ public:
return cs;
}
BYTE getCanonicalWidth() const
{
return tt->texttype_canonical_width;
}
USHORT getFlags() const
{
return tt->texttype_flags;
}
BYTE getCanonicalWidth() const;
USHORT getFlags() const;
public:
Firebird::MetaName name;

View File

@ -47,7 +47,7 @@ public:
{
LocalStatus status;
pluginSet = pluginInterface->getPlugins(&status, interfaceType,
(namesList ? namesList : Config::getPlugins(interfaceType)),
(namesList ? namesList : Config::getDefaultConfig()->getPlugins(interfaceType)),
desiredVersion, ui, NULL);
if (!pluginSet)
@ -67,7 +67,7 @@ public:
{
LocalStatus status;
pluginSet = pluginInterface->getPlugins(&status, interfaceType,
(namesList ? namesList : Config::getPlugins(interfaceType)),
(namesList ? namesList : knownConfig->getPlugins(interfaceType)),
desiredVersion, ui, new FirebirdConf(knownConfig));
if (!pluginSet)

View File

@ -232,6 +232,21 @@ public:
};
// Dispatcher access
class DispatcherPtr : public AccessAutoInterface<IProvider>
{
public:
DispatcherPtr()
: AccessAutoInterface<IProvider>(getMasterInterface()->getDispatcher())
{ }
~DispatcherPtr()
{
(*this)->release();
}
};
// When process exits, dynamically loaded modules (for us plugin modules)
// are unloaded first. As the result all global variables in plugin are already destroyed
// when yvalve is starting fb_shutdown(). This causes almost unavoidable segfault.

View File

@ -175,7 +175,9 @@ const Config::ConfigEntry Config::entries[MAX_CONFIG_KEY] =
{TYPE_BOOLEAN, "SharedCache", (ConfigValue) true},
{TYPE_BOOLEAN, "SharedDatabase", (ConfigValue) false},
{TYPE_STRING, "WireCrypt", (ConfigValue) NULL},
{TYPE_STRING, "CryptPlugin", (ConfigValue) "Arc4"}
{TYPE_STRING, "WireCryptPlugin", (ConfigValue) "Arc4"},
{TYPE_STRING, "DbCryptPlugin", (ConfigValue) ""},
{TYPE_STRING, "KeyHolderPlugin", (ConfigValue) ""}
};
/******************************************************************************
@ -663,22 +665,26 @@ bool Config::getMultiClientServer()
#endif
}
const char* Config::getPlugins(unsigned int type)
const char* Config::getPlugins(unsigned int type) const
{
switch (type)
{
case Firebird::PluginType::Provider:
return (const char*) getDefaultConfig()->values[KEY_PLUG_PROVIDERS];
return (const char*) values[KEY_PLUG_PROVIDERS];
case Firebird::PluginType::AuthServer:
return (const char*) getDefaultConfig()->values[KEY_PLUG_AUTH_SERVER];
return (const char*) values[KEY_PLUG_AUTH_SERVER];
case Firebird::PluginType::AuthClient:
return (const char*) getDefaultConfig()->values[KEY_PLUG_AUTH_CLIENT];
return (const char*) values[KEY_PLUG_AUTH_CLIENT];
case Firebird::PluginType::AuthUserManagement:
return (const char*) getDefaultConfig()->values[KEY_PLUG_AUTH_MANAGE];
return (const char*) values[KEY_PLUG_AUTH_MANAGE];
case Firebird::PluginType::Trace:
return (const char*) getDefaultConfig()->values[KEY_PLUG_TRACE];
case Firebird::PluginType::Crypt:
return (const char*) getDefaultConfig()->values[KEY_PLUG_CRYPT];
return (const char*) values[KEY_PLUG_TRACE];
case Firebird::PluginType::WireCrypt:
return (const char*) values[KEY_PLUG_WIRE_CRYPT];
case Firebird::PluginType::DbCrypt:
return (const char*) values[KEY_PLUG_DB_CRYPT];
case Firebird::PluginType::KeyHolder:
return (const char*) values[KEY_PLUG_KEY_HOLDER];
}
(Firebird::Arg::Gds(isc_random) << "Internal error in Config::getPlugins()").raise();

View File

@ -140,7 +140,9 @@ public:
KEY_SHARED_CACHE,
KEY_SHARED_DATABASE,
KEY_WIRE_CRYPT,
KEY_PLUG_CRYPT,
KEY_PLUG_WIRE_CRYPT,
KEY_PLUG_DB_CRYPT,
KEY_PLUG_KEY_HOLDER,
MAX_CONFIG_KEY // keep it last
};
@ -337,7 +339,7 @@ public:
static bool getMultiClientServer();
static const char* getPlugins(unsigned int type);
const char* getPlugins(unsigned int type) const;
const char* getSecurityDatabase() const;

View File

@ -42,7 +42,6 @@
#include "gen/iberror.h"
#include "../jrd/ibase.h"
#include "../jrd/jrd.h"
#include "../jrd/scl.h"
#include "../yvalve/gds_proto.h"
#include "../common/isc_proto.h"

View File

@ -47,7 +47,6 @@
#include <string.h>
#include <ctype.h>
#include "gen/iberror.h"
#include "../jrd/jrd.h"
#include "../yvalve/gds_proto.h"
#include "../common/isc_proto.h"
#include "../common/isc_f_proto.h"
@ -1296,9 +1295,9 @@ bool Mnt::get()
/**************************************
*
* g e t _ m o u n t s ( S Y S T E M _ V )
* ( E P S O N )
* ( M 8 8 K )
* ( U N I X W A R E )
* ( E P S O N )
* ( M 8 8 K )
* ( U N I X W A R E )
*
**************************************
*
@ -1401,7 +1400,9 @@ bool Mnt::get()
const char* start = device;
if (n<5)
return false;
{
return false;
}
const char* iflag = strchr(device, ':');
if (iflag)

View File

@ -23,7 +23,6 @@
#include "firebird.h"
#include <string.h>
#include "../jrd/jrd.h"
#include "../jrd/ibase.h"
#include "../jrd/val.h"
#include "../common/sdl.h"

View File

@ -34,6 +34,7 @@
#include "../jrd/intl_proto.h"
#include "../jrd/mov_proto.h"
#include "../jrd/par_proto.h"
#include "../jrd/Collation.h"
#include "../dsql/ddl_proto.h"
#include "../dsql/errd_proto.h"
#include "../dsql/gen_proto.h"

View File

@ -9946,6 +9946,22 @@ void AlterDatabaseNode::execute(thread_db* tdbb, DsqlCompilerScratch* /*dsqlScra
if (!tdbb->getAttachment()->locksmith())
status_exception::raise(Arg::Gds(isc_adm_task_denied));
if (cryptPlugin.hasData())
{
DFW_post_work(transaction, dfw_db_crypt, cryptPlugin.c_str(), 0);
}
if (clauses & CLAUSE_DECRYPT)
{
DFW_post_work(transaction, dfw_db_crypt, "", 0);
}
if (!(clauses & RDB_DATABASE_MASK))
{
// No clauses requiring rdb$database present - work is done
return;
}
// run all statements under savepoint control
AutoSavePoint savePoint(tdbb, transaction);

View File

@ -1950,9 +1950,12 @@ public:
class AlterDatabaseNode : public DdlNode
{
public:
static const unsigned CLAUSE_BEGIN_BACKUP = 0x01;
static const unsigned CLAUSE_END_BACKUP = 0x02;
static const unsigned CLAUSE_DROP_DIFFERENCE = 0x04;
static const unsigned CLAUSE_BEGIN_BACKUP = 0x01;
static const unsigned CLAUSE_END_BACKUP = 0x02;
static const unsigned CLAUSE_DROP_DIFFERENCE = 0x04;
static const unsigned CLAUSE_DECRYPT = 0x08;
static const unsigned RDB_DATABASE_MASK = CLAUSE_BEGIN_BACKUP | CLAUSE_END_BACKUP | CLAUSE_DROP_DIFFERENCE;
public:
AlterDatabaseNode(MemoryPool& p)
@ -1963,7 +1966,8 @@ public:
differenceFile(p),
setDefaultCharSet(p),
setDefaultCollation(p),
files(p)
files(p),
cryptPlugin(p)
{
}
@ -1996,6 +2000,7 @@ public:
Firebird::MetaName setDefaultCharSet;
Firebird::MetaName setDefaultCollation;
Firebird::Array<NestConst<DbFileClause> > files;
Firebird::MetaName cryptPlugin;
};

View File

@ -56,6 +56,7 @@
#include "../dsql/utld_proto.h"
#include "../dsql/DSqlDataTypeUtil.h"
#include "../jrd/DataTypeUtil.h"
#include "../jrd/Collation.h"
using namespace Firebird;
using namespace Jrd;

View File

@ -547,6 +547,8 @@ inline void check_copy_incr(char*& to, const char ch, const char* const string)
%token <legacyStr> BODY
%token <legacyStr> CONTINUE
%token <legacyStr> DDL
%token <legacyStr> DECRYPT
%token <legacyStr> ENCRYPT
%token <legacyStr> ENGINE
%token <legacyStr> NAME
%token <legacyStr> OVER
@ -3546,6 +3548,10 @@ db_alter_clause($alterDatabaseNode)
{ $alterDatabaseNode->clauses |= AlterDatabaseNode::CLAUSE_END_BACKUP; }
| SET DEFAULT CHARACTER SET symbol_character_set_name
{ $alterDatabaseNode->setDefaultCharSet = toName($5); }
| ENCRYPT WITH valid_symbol_name
{ $alterDatabaseNode->cryptPlugin = toName($3); }
| DECRYPT
{ $alterDatabaseNode->clauses |= AlterDatabaseNode::CLAUSE_DECRYPT; }
;
@ -6842,6 +6848,8 @@ non_reserved_word
| BODY
| CONTINUE
| DDL
| DECRYPT
| ENCRYPT
| ENGINE
| IDENTITY
| NAME

View File

@ -744,6 +744,11 @@ public:
fb_assert(false);
return NULL;
}
virtual int FB_CARG same(IVersioned* /*first*/, IVersioned* /*second*/)
{
return 0;
}
};

View File

@ -505,6 +505,7 @@
#define isc_spb_sts_record_versions 0x20
#define isc_spb_sts_table 0x40
#define isc_spb_sts_nocreation 0x80
#define isc_spb_sts_encryption 0x100
/***********************************/
/* Server configuration key values */

View File

@ -27,25 +27,70 @@
namespace Firebird {
class ICrypt : public IRefCounted
{
public:
virtual void FB_CARG transform(IStatus* status, unsigned int length, const void* from, void* to) = 0;
};
// Part 1. Network crypt.
#define FB_CRYPT_VERSION (FB_REFCOUNTED_VERSION + 1)
class ICryptPlugin : public IPluginBase
// Plugins of this type are used to crypt data, sent over the wire
// Plugin must support encrypt and decrypt operations
// Interface of plugin is the same for both client and server,
// and it may have differerent or same implementations for client and server
class IWireCryptPlugin : public IPluginBase
{
public:
// getKnownTypes() function must return list of acceptable keys' types
// special type 'builtin' means that crypt plugin knows itself where to get the key from
virtual const char* FB_CARG getKnownTypes(IStatus* status) = 0;
virtual ICrypt* FB_CARG getEncrypt(IStatus* status, FbCryptKey* key) = 0;
virtual ICrypt* FB_CARG getDecrypt(IStatus* status, FbCryptKey* key) = 0;
virtual void FB_CARG setKey(IStatus* status, FbCryptKey* key) = 0;
virtual void FB_CARG encrypt(IStatus* status, unsigned int length, const void* from, void* to) = 0;
virtual void FB_CARG decrypt(IStatus* status, unsigned int length, const void* from, void* to) = 0;
};
#define FB_CRYPT_PLUGIN_VERSION (FB_PLUGIN_VERSION + 3)
#define FB_WIRECRYPT_PLUGIN_VERSION (FB_PLUGIN_VERSION + 4)
// Part 2. Database crypt.
// This interface is used to transfer some data (related with crypt keys)
// between different components of firebird
class ICryptKeyCallback : public IVersioned
{
public:
virtual unsigned int FB_CARG callback(unsigned int dataLength, const void* data,
unsigned int bufferLength, void* buffer) = 0;
};
#define FB_CRYPT_CALLBACK_VERSION (FB_VERSIONED_VERSION + 1)
// Key holder accepts key(s) from attachment at database attach time
// (or gets them it some other arbitrary way)
// and sends it to database crypt plugin on request
class IKeyHolderPlugin : public IPluginBase
{
public:
// keyCallback() is called when new attachment is probably ready to provide keys
// to key holder plugin, ICryptKeyCallback interface is provided by attachment
virtual int FB_CARG keyCallback(IStatus* status, ICryptKeyCallback* callback) = 0;
// Crypt plugin calls keyHandle() whne it needs a key, stored in key holder
// Key is not returned directly - instead of it callback interface is returned
// Missing key with given name is not an error condition for keyHandle()
// It should just return NULL in this case
virtual ICryptKeyCallback* FB_CARG keyHandle(IStatus* status, const char* keyName) = 0;
};
#define FB_KEYHOLDER_PLUGIN_VERSION (FB_PLUGIN_VERSION + 2)
class IDbCryptPlugin : public IPluginBase
{
public:
// When database crypt plugin is loaded, setKey() is called to provide information
// about key holders, available for givaen database
// It's supposed that crypt plugin will invoke keyHandle() function from them
// to access callback interface for getting actual crypt key
// If crypt plugin fails to find appropriate key in sources, it should raise error
virtual void FB_CARG setKey(IStatus* status, unsigned int length, IKeyHolderPlugin** sources) = 0;
virtual void FB_CARG encrypt(IStatus* status, unsigned int length, const void* from, void* to) = 0;
virtual void FB_CARG decrypt(IStatus* status, unsigned int length, const void* from, void* to) = 0;
};
#define FB_DBCRYPT_PLUGIN_VERSION (FB_PLUGIN_VERSION + 3)
} // namespace Firebird

View File

@ -113,8 +113,11 @@ public:
virtual IDtc* FB_CARG getDtc() = 0;
virtual IAttachment* registerAttachment(IProvider* provider, IAttachment* attachment) = 0;
virtual ITransaction* registerTransaction(IAttachment* attachment, ITransaction* transaction) = 0;
// This function is required to compare interfaces based on vtables of them
virtual int FB_CARG same(IVersioned* first, IVersioned* second) = 0;
};
#define FB_MASTER_VERSION (FB_VERSIONED_VERSION + 9)
#define FB_MASTER_VERSION (FB_VERSIONED_VERSION + 10)
} // namespace Firebird

View File

@ -220,9 +220,11 @@ namespace PluginType {
static const unsigned int AuthUserManagement = 13;
static const unsigned int ExternalEngine = 14;
static const unsigned int Trace = 15;
static const unsigned int Crypt = 16;
static const unsigned int WireCrypt = 16;
static const unsigned int DbCrypt = 17;
static const unsigned int KeyHolder = 18;
static const unsigned int MaxType = 17; // keep in sync please
static const unsigned int MaxType = 19; // keep in sync please
};
} // namespace Firebird

View File

@ -36,6 +36,7 @@ namespace Firebird {
// This interfaces are implemented by yvalve code and by each of providers.
class IAttachment; // Forward
class ICryptKeyCallback; // From Crypt.h
struct FbMessage
{
@ -235,10 +236,11 @@ public:
virtual IAttachment* FB_CARG createDatabase(IStatus* status, const char* fileName,
unsigned int dpbLength, const unsigned char* dpb) = 0;
virtual IService* FB_CARG attachServiceManager(IStatus* status, const char* service,
unsigned int spbLength, const unsigned char* spb) = 0;
unsigned int spbLength, const unsigned char* spb) = 0;
virtual void FB_CARG shutdown(IStatus* status, unsigned int timeout, const int reason) = 0;
virtual void FB_CARG setDbCryptCallback(IStatus* status, ICryptKeyCallback* cryptCallback) = 0;
};
#define FB_PROVIDER_VERSION (FB_PLUGIN_VERSION + 4)
#define FB_PROVIDER_VERSION (FB_PLUGIN_VERSION + 5)
// DtcStart - structure to start transaction over >1 attachments (former TEB)
struct DtcStart

View File

@ -479,6 +479,7 @@
const USHORT f_mon_db_pages = 16;
const USHORT f_mon_db_stat_id = 17;
const USHORT f_mon_db_backup_state = 18;
const USHORT f_mon_db_crypt_page = 19;
// Relation 34 (MON$ATTACHMENTS)

View File

@ -368,11 +368,7 @@ void Jrd::Attachment::detachLocksFromAttachment()
Lock* long_lock = att_long_locks;
while (long_lock)
{
Lock* next = long_lock->lck_next;
long_lock->lck_attachment = NULL;
long_lock->lck_next = NULL;
long_lock->lck_prior = NULL;
long_lock = next;
long_lock = long_lock->detach();
}
att_long_locks = NULL;
}

View File

@ -44,6 +44,10 @@ namespace EDS {
class Connection;
}
namespace Firebird {
class ICryptKeyCallback;
}
class CharSetContainer;
namespace Jrd
@ -273,6 +277,7 @@ public:
Firebird::Array<JrdStatement*> att_internal; // internal statements
Firebird::Array<JrdStatement*> att_dyn_req; // internal dyn statements
Firebird::ICryptKeyCallback* att_crypt_callback; // callback for DB crypt
jrd_req* findSystemRequest(thread_db* tdbb, USHORT id, USHORT which);

View File

@ -99,6 +99,7 @@
#include "../jrd/intl_classes.h"
#include "../jrd/lck_proto.h"
#include "../jrd/intl_classes.h"
#include "../jrd/Collation.h"
#include "../common/TextType.h"
#include "../jrd/SimilarToMatcher.h"

View File

@ -36,6 +36,7 @@
namespace Jrd {
class Lock;
class BaseSubstringSimilarMatcher;
class Collation : public TextType
{

728
src/jrd/CryptoManager.cpp Normal file
View File

@ -0,0 +1,728 @@
/*
* PROGRAM: JRD access method
* MODULE: CryptoManager.cpp
* DESCRIPTION: Database encryption
*
* The contents of this file are subject to the Initial
* Developer's Public License Version 1.0 (the "License");
* you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
* http://www.ibphoenix.com/main.nfs?a=ibphoenix&page=ibp_idpl.
*
* Software distributed under the License is distributed AS IS,
* WITHOUT WARRANTY OF ANY KIND, either express or implied.
* See the License for the specific language governing rights
* and limitations under the License.
*
* The Original Code was created by Alex Peshkov
* for the Firebird Open Source RDBMS project.
*
* Copyright (c) 2008 Alex Peshkov <peshkoff at mail.ru>
* and all contributors signed below.
*
* All Rights Reserved.
* Contributor(s): ______________________________________.
*
*
*/
#include "firebird.h"
#include "firebird/Crypt.h"
#include "gen/iberror.h"
#include "../jrd/CryptoManager.h"
#include "../common/classes/alloc.h"
#include "../jrd/Database.h"
#include "../jrd/ods.h"
#include "../common/ThreadStart.h"
#include "../jrd/os/pio_proto.h"
#include "../common/StatusArg.h"
#include "../common/StatusHolder.h"
#include "../jrd/lck.h"
#include "../jrd/jrd.h"
#include "../jrd/pag.h"
#include "../jrd/nbak.h"
#include "../jrd/cch_proto.h"
#include "../jrd/lck_proto.h"
#include "../jrd/pag_proto.h"
#include "../common/isc_proto.h"
#include "../common/classes/GetPlugins.h"
using namespace Firebird;
namespace {
class SpareBuffer
{
public:
Ods::pag* get()
{
return buffer;
}
private:
Ods::pag buffer[MAX_PAGE_SIZE / sizeof(Ods::pag)];
};
THREAD_ENTRY_DECLARE cryptThreadStatic(THREAD_ENTRY_PARAM p)
{
Jrd::CryptoManager* cryptoManager = (Jrd::CryptoManager*)p;
cryptoManager->cryptThread();
return 0;
}
class Header
{
public:
Header(Jrd::thread_db* p_tdbb, USHORT lockType)
: tdbb(p_tdbb),
window(Jrd::HEADER_PAGE_NUMBER),
header((Ods::header_page*) CCH_FETCH(tdbb, &window, lockType, pag_header))
{
if (!header)
{
(Arg::Gds(isc_random) << "Header page fetch failed").raise();
}
}
Ods::header_page* write()
{
CCH_MARK_MUST_WRITE(tdbb, &window);
return header;
}
void depends(Stack<ULONG>& pages)
{
while(pages.hasData())
{
CCH_precedence(tdbb, &window, pages.pop());
}
}
const Ods::header_page* operator->() const
{
return header;
}
operator const Ods::header_page*() const
{
return header;
}
~Header()
{
CCH_RELEASE(tdbb, &window);
}
private:
Jrd::thread_db* tdbb;
Jrd::WIN window;
Ods::header_page* header;
};
class NoEntrypoint
{
public:
virtual void FB_CARG noEntrypoint(IStatus* s)
{
s->set(Arg::Gds(isc_wish_list).value());
}
};
MakeUpgradeInfo<NoEntrypoint> upInfo;
}
namespace Jrd {
CryptoManager::CryptoManager(thread_db* tdbb)
: PermanentStorage(*tdbb->getDatabase()->dbb_permanent),
keyHolderPlugins(getPool()),
cryptThreadId(0),
cryptPlugin(NULL),
dbb(*tdbb->getDatabase()),
needLock(true),
crypt(false),
process(false),
down(false)
{
stateLock = FB_NEW_RPT(getPool(), 0)
Lock(tdbb, LCK_crypt_status, this, blockingAstChangeCryptState);
threadLock = FB_NEW_RPT(getPool(), 0) Lock(tdbb, LCK_crypt);
takeStateLock(tdbb);
}
CryptoManager::~CryptoManager()
{
}
void CryptoManager::terminateCryptThread(thread_db*)
{
if (cryptThreadId)
{
down = true;
Thread::waitForCompletion(cryptThreadId);
cryptThreadId = 0;
}
}
void CryptoManager::shutdown(thread_db* tdbb)
{
terminateCryptThread(tdbb);
if (cryptPlugin)
{
PluginManagerInterfacePtr()->releasePlugin(cryptPlugin);
cryptPlugin = NULL;
}
if (stateLock)
{
LCK_release(tdbb, stateLock);
stateLock = NULL;
}
}
void CryptoManager::takeStateLock(thread_db* tdbb)
{
fb_assert(stateLock);
fb_assert(tdbb->getAttachment());
if (needLock)
{
if (!LCK_lock(tdbb, stateLock, LCK_SR, LCK_WAIT))
{
fb_assert(tdbb->tdbb_status_vector[1]);
ERR_punt();
}
fb_utils::init_status(tdbb->tdbb_status_vector);
needLock = false;
}
}
void CryptoManager::loadPlugin(const char* pluginName)
{
MutexLockGuard guard(pluginLoadMtx);
if (cryptPlugin)
{
return;
}
GetPlugins<IDbCryptPlugin> cryptControl(PluginType::DbCrypt, FB_DBCRYPT_PLUGIN_VERSION,
upInfo, dbb.dbb_config, pluginName);
if (!cryptControl.hasData())
{
(Arg::Gds(isc_random) <<
"Invalid crypt plugin name").raise();
}
// do not assign cryptPlugin directly before key init complete
IDbCryptPlugin* p = cryptControl.plugin();
keyHolderPlugins.init(p);
cryptPlugin = p;
cryptPlugin->addRef();
}
void CryptoManager::changeCryptState(thread_db* tdbb, const Firebird::string& plugName)
{
if (plugName.length() > 31)
{
(Arg::Gds(isc_random) <<
"Crypt plugin name should not be >31 bytes").raise();
}
bool newCryptState = plugName.hasData();
{ // window scope
Header hdr(tdbb, LCK_write);
// Check header page for flags
if (hdr->hdr_flags & Ods::hdr_crypt_process)
{
(Arg::Gds(isc_random) <<
"Crypt failed - already crypting database").raise();
}
bool headerCryptState = hdr->hdr_flags & Ods::hdr_encrypted;
if (headerCryptState == newCryptState)
{
(Arg::Gds(isc_random) <<
"Crypt failed - database is already in requested state").raise();
}
fb_assert(stateLock);
// Take exclusive stateLock
bool ret = needLock ? LCK_lock(tdbb, stateLock, LCK_PW, LCK_WAIT) :
LCK_convert(tdbb, stateLock, LCK_PW, LCK_WAIT);
if (!ret)
{
fb_assert(tdbb->tdbb_status_vector[1]);
ERR_punt();
}
fb_utils::init_status(tdbb->tdbb_status_vector);
needLock = false;
// Load plugin
if (newCryptState)
{
loadPlugin(plugName.c_str());
}
crypt = newCryptState;
// Write modified header page
Ods::header_page* header = hdr.write();
if (crypt)
{
header->hdr_flags |= Ods::hdr_encrypted;
plugName.copyTo(header->hdr_crypt_plugin, sizeof header->hdr_crypt_plugin);
}
else
{
header->hdr_flags &= ~Ods::hdr_encrypted;
}
header->hdr_flags |= Ods::hdr_crypt_process;
process = true;
}
// Trigger lock on ChangeCryptState
if (!LCK_convert(tdbb, stateLock, LCK_EX, LCK_WAIT))
{
ERR_punt();
}
if (!LCK_convert(tdbb, stateLock, LCK_SR, LCK_WAIT))
{
ERR_punt();
}
fb_utils::init_status(tdbb->tdbb_status_vector);
// Now we may set hdr_crypt_page for crypt thread
{ // window scope
Header hdr(tdbb, LCK_write);
Ods::header_page* header = hdr.write();
header->hdr_crypt_page = 1;
}
startCryptThread(tdbb);
}
void CryptoManager::blockingAstChangeCryptState()
{
AsyncContextHolder tdbb(&dbb);
fb_assert(stateLock);
LCK_release(tdbb, stateLock);
needLock = true;
}
void CryptoManager::startCryptThread(thread_db* tdbb)
{
// Take exclusive threadLock
// If can't take that lock - nothing to do, cryptThread already runs somewhere
if (LCK_lock(tdbb, threadLock, LCK_EX, LCK_NO_WAIT))
{
// Cleanup resources
terminateCryptThread(tdbb);
down = false;
// Determine current page from the header
Header hdr(tdbb, LCK_read);
process = hdr->hdr_flags & Ods::hdr_crypt_process ? true : false;
if (!process)
{
LCK_release(tdbb, threadLock);
return;
}
currentPage.setValue(hdr->hdr_crypt_page);
// Refresh encryption flag
crypt = hdr->hdr_flags & Ods::hdr_encrypted ? true : false;
// If we are going to start crypt thread, we really need plugin to be loaded
loadPlugin(hdr->hdr_crypt_plugin);
// ready to go
Thread::start(cryptThreadStatic, (THREAD_ENTRY_PARAM) this, 0, &cryptThreadId);
}
fb_utils::init_status(tdbb->tdbb_status_vector);
}
void CryptoManager::attach(thread_db* tdbb, Attachment* att)
{
keyHolderPlugins.attach(att, dbb.dbb_config);
}
void CryptoManager::cryptThread()
{
ISC_STATUS_ARRAY status_vector;
try
{
// establish context
UserId user;
user.usr_user_name = "(Crypt thread)";
Jrd::Attachment* const attachment = Jrd::Attachment::create(&dbb);
RefPtr<SysAttachment> jAtt(new SysAttachment(attachment));
attachment->att_interface = jAtt;
attachment->att_filename = dbb.dbb_filename;
attachment->att_user = &user;
BackgroundContextHolder tdbb(&dbb, attachment, status_vector);
tdbb->tdbb_quantum = SWEEP_QUANTUM;
ULONG lastPage = getLastPage(tdbb);
ULONG runpage = 1;
Stack<ULONG> pages;
try
{
do
{
// Check is there some job to do
while ((runpage = currentPage.exchangeAdd(+1)) < lastPage)
{
// forced terminate
if (down)
{
break;
}
// nbackup state check
if (dbb.dbb_backup_manager && dbb.dbb_backup_manager->getState() != nbak_state_normal)
{
if (currentPage.exchangeAdd(-1) >= lastPage)
{
// currentPage was set to last page by thread, closing database
break;
}
THD_sleep(100);
continue;
}
// scheduling
if (--tdbb->tdbb_quantum < 0)
{
JRD_reschedule(tdbb, SWEEP_QUANTUM, true);
}
// writing page to disk will change it's crypt status in usual way
WIN window(DB_PAGE_SPACE, runpage);
Ods::pag* page = CCH_FETCH(tdbb, &window, LCK_write, pag_undefined);
if (page && page->pag_type <= pag_max &&
(bool(page->pag_flags & Ods::crypted_page) != crypt) &&
Ods::pag_crypt_page[page->pag_type])
{
CCH_MARK(tdbb, &window);
pages.push(runpage);
}
CCH_RELEASE_TAIL(tdbb, &window);
// sometimes save currentPage into DB header
++runpage;
if ((runpage & 0x3FF) == 0)
{
writeDbHeader(tdbb, runpage, pages);
}
}
// At this moment of time all pages with number < lastpage
// are guaranteed to change crypt state. Check for added pages.
lastPage = getLastPage(tdbb);
} while (runpage < lastPage);
// Finalize crypt
if (!down)
{
writeDbHeader(tdbb, 0, pages);
}
// Release exclusive lock on StartCryptThread
LCK_release(tdbb, threadLock);
}
catch(const Exception&)
{
try
{
// try to save current state of crypt thread
writeDbHeader(tdbb, runpage, pages);
// Release exclusive lock on StartCryptThread
LCK_release(tdbb, threadLock);
}
catch(const Exception&)
{ }
throw;
}
}
catch(const Exception& ex)
{
// Error during context creation - we can't even release lock
iscLogException("Crypt thread:", ex);
}
}
void CryptoManager::writeDbHeader(thread_db* tdbb, ULONG runpage, Stack<ULONG>& pages)
{
Header hdr(tdbb, LCK_write);
hdr.depends(pages);
Ods::header_page* header = hdr.write();
header->hdr_crypt_page = runpage;
if (!runpage)
{
header->hdr_flags &= ~Ods::hdr_crypt_process;
process = false;
}
}
bool CryptoManager::cryptRead(jrd_file* file, BufferDesc* bdb, Ods::pag* page, ISC_STATUS* sv)
{
try
{
return bdb->bdb_bcb->bcb_database->dbb_crypto_manager->read(file, bdb, page, sv);
}
catch(const Exception& ex)
{
ex.stuff_exception(sv);
}
return false;
}
bool CryptoManager::cryptWrite(jrd_file* file, BufferDesc* bdb, Ods::pag* page, ISC_STATUS* sv)
{
try
{
return bdb->bdb_bcb->bcb_database->dbb_crypto_manager->write(file, bdb, page, sv);
}
catch(const Exception& ex)
{
ex.stuff_exception(sv);
}
return false;
}
bool CryptoManager::read(jrd_file* file, BufferDesc* bdb, Ods::pag* page, ISC_STATUS* sv)
{
if (!PIO_read(file, bdb, page, sv))
{
return false;
}
if (page->pag_flags & Ods::crypted_page)
{
if (!cryptPlugin)
{
// We are invoked from shared cache manager, i.e. no valid attachment in tdbb
// Therefore create system temporary attachment like in crypt thread to be able to work with locks
UserId user;
user.usr_user_name = "(Crypt plugin loader)";
Jrd::Attachment* const attachment = Jrd::Attachment::create(&dbb);
RefPtr<SysAttachment> jAtt(new SysAttachment(attachment));
attachment->att_interface = jAtt;
attachment->att_filename = dbb.dbb_filename;
attachment->att_user = &user;
BackgroundContextHolder tdbb(&dbb, attachment, sv);
// Lock crypt state
takeStateLock(tdbb);
Header hdr(tdbb, LCK_read);
crypt = hdr->hdr_flags & Ods::hdr_encrypted;
process = hdr->hdr_flags & Ods::hdr_crypt_process;
if (crypt || process)
{
loadPlugin(hdr->hdr_crypt_plugin);
}
if (!cryptPlugin)
{
(Arg::Gds(isc_random) << "Not crypt mode, but page appears encrypted").copyTo(sv);
return false;
}
}
LocalStatus status;
cryptPlugin->decrypt(&status, dbb.dbb_page_size - sizeof(page[0]), &page[1], &page[1]);
if (!status.isSuccess())
{
memcpy(sv, status.get(), sizeof(ISC_STATUS_ARRAY));
return false;
}
}
return true;
}
bool CryptoManager::write(jrd_file* file, BufferDesc* bdb, Ods::pag* page, ISC_STATUS* sv)
{
for (;;)
{
SpareBuffer spare_buffer;
Ods::pag* buffer = page;
if (crypt && cryptPlugin && Ods::pag_crypt_page[page->pag_type % (pag_max + 1)])
{
buffer = spare_buffer.get();
buffer[0] = page[0];
LocalStatus status;
cryptPlugin->encrypt(&status, dbb.dbb_page_size - sizeof(page[0]), &page[1], &buffer[1]);
if (!status.isSuccess())
{
memcpy(sv, status.get(), sizeof(ISC_STATUS_ARRAY));
return false;
}
buffer->pag_flags |= Ods::crypted_page;
}
else
{
buffer->pag_flags &= ~Ods::crypted_page;
}
return PIO_write(file, bdb, buffer, sv);
}
}
int CryptoManager::blockingAstChangeCryptState(void* object)
{
((CryptoManager*)object)->blockingAstChangeCryptState();
return 0;
}
ULONG CryptoManager::getCurrentPage()
{
return process ? currentPage.value() : 0;
}
ULONG CryptoManager::getLastPage(thread_db* tdbb)
{
return PAG_last_page(tdbb) + 1;
}
CryptoManager::HolderAttachments::HolderAttachments(MemoryPool& p)
: keyHolder(NULL), attachments(p)
{ }
void CryptoManager::HolderAttachments::setPlugin(IKeyHolderPlugin* kh)
{
keyHolder = kh;
keyHolder->addRef();
}
CryptoManager::HolderAttachments::~HolderAttachments()
{
if (keyHolder)
{
PluginManagerInterfacePtr()->releasePlugin(keyHolder);
}
}
void CryptoManager::HolderAttachments::registerAttachment(Attachment* att)
{
attachments.add(att);
}
IKeyHolderPlugin* CryptoManager::HolderAttachments::unregisterAttachment(Attachment* att)
{
for (unsigned i = 0; i < attachments.getCount(); ++i)
{
if (attachments[i] == att)
{
attachments.remove(i);
if (attachments.getCount() == 0)
{
return keyHolder; // to be removed from holdersVector
}
break;
}
}
return NULL;
}
bool CryptoManager::HolderAttachments::operator==(IKeyHolderPlugin* kh) const
{
return MasterInterfacePtr()->same(keyHolder, kh) != 0;
}
void CryptoManager::KeyHolderPlugins::attach(Attachment* att, Config* config)
{
MutexLockGuard g(holdersMutex);
for (GetPlugins<IKeyHolderPlugin> keyControl(PluginType::KeyHolder,
FB_KEYHOLDER_PLUGIN_VERSION, upInfo, config); keyControl.hasData(); keyControl.next())
{
IKeyHolderPlugin* keyPlugin = keyControl.plugin();
LocalStatus st;
if (keyPlugin->keyCallback(&st, att->att_crypt_callback) == 1)
{
// holder accepted attachment's key
HolderAttachments* ha = NULL;
for (unsigned i = 0; i < knownHolders.getCount(); ++i)
{
if (knownHolders[i] == keyPlugin)
{
ha = &knownHolders[i];
break;
}
}
if (!ha)
{
ha = &(knownHolders.add());
ha->setPlugin(keyPlugin);
}
ha->registerAttachment(att);
break; // Do not need >1 key from attachment to single DB
}
else if (!st.isSuccess())
{
status_exception::raise(st.get());
}
}
}
void CryptoManager::KeyHolderPlugins::detach(Attachment* att)
{
MutexLockGuard g(holdersMutex);
for (unsigned i = 0; i < knownHolders.getCount(); ++i)
{
IKeyHolderPlugin* keyPlugin = knownHolders[i].unregisterAttachment(att);
if (keyPlugin)
{
knownHolders.remove(i);
}
}
}
void CryptoManager::KeyHolderPlugins::init(IDbCryptPlugin* crypt)
{
MutexLockGuard g(holdersMutex);
Firebird::HalfStaticArray<Firebird::IKeyHolderPlugin*, 64> holdersVector;
unsigned int length = knownHolders.getCount();
IKeyHolderPlugin** vector = holdersVector.getBuffer(length);
for (unsigned i = 0; i < length; ++i)
{
vector[i] = knownHolders[i].getPlugin();
}
LocalStatus st;
crypt->setKey(&st, length, vector);
if (!st.isSuccess())
{
status_exception::raise(st.get());
}
}
} // namespace Jrd

147
src/jrd/CryptoManager.h Normal file
View File

@ -0,0 +1,147 @@
/*
* PROGRAM: JRD access method
* MODULE: CryptoManager.h
* DESCRIPTION: Database encryption
*
* The contents of this file are subject to the Initial
* Developer's Public License Version 1.0 (the "License");
* you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
* http://www.ibphoenix.com/main.nfs?a=ibphoenix&page=ibp_idpl.
*
* Software distributed under the License is distributed AS IS,
* WITHOUT WARRANTY OF ANY KIND, either express or implied.
* See the License for the specific language governing rights
* and limitations under the License.
*
* The Original Code was created by Alex Peshkov
* for the Firebird Open Source RDBMS project.
*
* Copyright (c) 2012 Alex Peshkov <peshkoff at mail.ru>
* and all contributors signed below.
*
* All Rights Reserved.
* Contributor(s): ______________________________________.
*
*
*/
#ifndef JRD_CRYPTO_MANAGER
#define JRD_CRYPTO_MANAGER
#include "../common/classes/alloc.h"
#include "../common/thd.h"
#include "../common/classes/fb_atomic.h"
#include "../common/classes/SyncObject.h"
#include "../common/classes/fb_string.h"
#include "../common/classes/objects_array.h"
#include "../common/classes/stack.h"
// forward
class Config;
namespace Firebird {
class IDbCryptPlugin;
class IKeyHolderPlugin;
}
namespace Ods {
struct pag;
}
namespace Jrd {
class Database;
class Attachment;
class jrd_file;
class BufferDesc;
class thread_db;
class Lock;
class CryptoManager : public Firebird::PermanentStorage
{
public:
CryptoManager(thread_db* tdbb);
void shutdown(thread_db* tdbb);
~CryptoManager();
void changeCryptState(thread_db* tdbb, const Firebird::string& plugName);
void attach(thread_db* tdbb, Attachment* att);
void detach(thread_db* tdbb, Attachment* att);
void startCryptThread(thread_db* tdbb);
void terminateCryptThread(thread_db* tdbb);
static bool cryptRead(jrd_file*, BufferDesc*, Ods::pag*, ISC_STATUS*);
static bool cryptWrite(jrd_file*, BufferDesc*, Ods::pag*, ISC_STATUS*);
void cryptThread();
ULONG getCurrentPage();
private:
class HolderAttachments
{
public:
HolderAttachments(Firebird::MemoryPool& p);
~HolderAttachments();
void registerAttachment(Attachment* att);
Firebird::IKeyHolderPlugin* unregisterAttachment(Attachment* att);
void setPlugin(Firebird::IKeyHolderPlugin* kh);
Firebird::IKeyHolderPlugin* getPlugin() const
{
return keyHolder;
}
bool operator==(Firebird::IKeyHolderPlugin* kh) const;
private:
Firebird::IKeyHolderPlugin* keyHolder;
Firebird::HalfStaticArray<Attachment*, 32> attachments;
};
class KeyHolderPlugins
{
public:
KeyHolderPlugins(Firebird::MemoryPool& p)
: knownHolders(p)
{ }
void attach(Attachment* att, Config* config);
void detach(Attachment* att);
void init(Firebird::IDbCryptPlugin* crypt);
private:
Firebird::Mutex holdersMutex;
Firebird::ObjectsArray<HolderAttachments> knownHolders;
};
static int blockingAstChangeCryptState(void*);
void blockingAstChangeCryptState();
void takeStateLock(thread_db* tdbb);
void loadPlugin(const char* pluginName);
ULONG getLastPage(thread_db* tdbb);
void writeDbHeader(thread_db* tdbb, ULONG runpage, Firebird::Stack<ULONG>& pages);
bool read(jrd_file*, BufferDesc*, Ods::pag*, ISC_STATUS*);
bool write(jrd_file*, BufferDesc*, Ods::pag*, ISC_STATUS*);
Firebird::AtomicCounter currentPage;
Firebird::Mutex pluginLoadMtx;
KeyHolderPlugins keyHolderPlugins;
ThreadId cryptThreadId;
Firebird::IDbCryptPlugin* cryptPlugin;
Database& dbb;
Lock* stateLock;
Lock* threadLock;
bool needLock, crypt, process, down;
};
} // namespace Jrd
#endif // JRD_CRYPTO_MANAGER

View File

@ -35,6 +35,7 @@
#include "../jrd/nbak.h"
#include "../jrd/tra.h"
#include "../jrd/lck_proto.h"
#include "../jrd/CryptoManager.h"
#include "../jrd/os/pio_proto.h"
// Thread data block
@ -87,6 +88,7 @@ namespace Jrd
delete dbb_monitoring_data;
delete dbb_backup_manager;
delete dbb_crypto_manager;
//Checkout dcoHolder(this);
@ -144,16 +146,10 @@ namespace Jrd
if (!counter->lock)
{
Lock* const lock = FB_NEW_RPT(*dbb->dbb_permanent, sizeof(SLONG)) Lock();
Lock* const lock = FB_NEW_RPT(*dbb->dbb_permanent, sizeof(SLONG)) Lock(tdbb, LCK_shared_counter, counter, blockingAst);
counter->lock = lock;
lock->lck_type = LCK_shared_counter;
lock->lck_owner_handle = LCK_get_owner_handle(tdbb, lock->lck_type);
lock->lck_parent = dbb->dbb_lock;
lock->lck_length = sizeof(SLONG);
lock->lck_key.lck_long = space;
lock->lck_dbb = dbb;
lock->lck_ast = blockingAst;
lock->lck_object = counter;
LCK_lock(tdbb, lock, LCK_PW, LCK_WAIT);
counter->isProtected = true;

View File

@ -75,7 +75,7 @@ class BackupManager;
class ExternalFileDirectoryList;
class MonitoringData;
class GarbageCollector;
class CryptoManager;
// general purpose vector
template <class T, BlockType TYPE = type_vec>
@ -264,8 +264,6 @@ public:
ValueCache m_counters[TOTAL_ITEMS];
};
typedef int (*crypt_routine) (const char*, void*, int, void*);
static Database* create()
{
Firebird::MemoryStats temp_stats;
@ -355,7 +353,6 @@ public:
Firebird::PathName dbb_filename; // filename string
Firebird::PathName dbb_database_name; // database ID (file name or alias)
Firebird::string dbb_encrypt_key; // encryption key
Firebird::SyncObject dbb_pools_sync;
Firebird::Array<MemoryPool*> dbb_pools; // pools
@ -387,9 +384,6 @@ public:
USHORT unflushed_writes; // unflushed writes
time_t last_flushed_write; // last flushed write time
crypt_routine dbb_encrypt; // External encryption routine
crypt_routine dbb_decrypt; // External decryption routine
TipCache* dbb_tip_cache; // cache of latest known state of all transactions in system
TransactionsVector* dbb_pc_transactions; // active precommitted transactions
BackupManager* dbb_backup_manager; // physical backup manager
@ -398,6 +392,7 @@ public:
Firebird::RefPtr<Config> dbb_config;
SharedCounter dbb_shared_counter;
CryptoManager* dbb_crypto_manager;
// returns true if primary file is located on raw device
bool onRawDevice() const;
@ -424,7 +419,6 @@ private:
dbb_extManager(*p),
dbb_filename(*p),
dbb_database_name(*p),
dbb_encrypt_key(*p),
dbb_pools(*p, 4),
dbb_stats(*p),
dbb_lock_owner_id(getLockOwnerId()),

View File

@ -45,6 +45,7 @@
#include "../jrd/os/pio_proto.h"
#include "../jrd/pag_proto.h"
#include "../jrd/thread_proto.h"
#include "../jrd/CryptoManager.h"
#include "../jrd/Relation.h"
#include "../jrd/RecordBuffer.h"
@ -420,13 +421,9 @@ DatabaseSnapshot::DatabaseSnapshot(thread_db* tdbb, MemoryPool& pool)
}
// Signal other processes to dump their data
Lock temp_lock, *lock = &temp_lock;
lock->lck_dbb = dbb;
Lock temp_lock(tdbb, LCK_monitor), *lock = &temp_lock;
lock->lck_length = sizeof(SLONG);
lock->lck_key.lck_long = 0;
lock->lck_type = LCK_monitor;
lock->lck_owner_handle = LCK_get_owner_handle(tdbb, lock->lck_type);
lock->lck_parent = dbb->dbb_lock;
if (LCK_lock(tdbb, lock, LCK_EX, LCK_WAIT))
LCK_release(tdbb, lock);
@ -919,8 +916,11 @@ void DatabaseSnapshot::putDatabase(const Database* database, Writer& writer, int
record.storeInteger(f_mon_db_pages, PageSpace::actAlloc(database));
// database state
switch (database->dbb_backup_manager->getState())
temp = backup_state_unknown;
if (database->dbb_backup_manager)
{
switch (database->dbb_backup_manager->getState())
{
case nbak_state_normal:
temp = backup_state_normal;
break;
@ -930,11 +930,16 @@ void DatabaseSnapshot::putDatabase(const Database* database, Writer& writer, int
case nbak_state_merge:
temp = backup_state_merge;
break;
default:
temp = backup_state_unknown;
}
}
record.storeInteger(f_mon_db_backup_state, temp);
// crypt thread status
if (database->dbb_crypto_manager)
{
record.storeInteger(f_mon_db_crypt_page, database->dbb_crypto_manager->getCurrentPage());
}
// statistics
record.storeGlobalId(f_mon_db_stat_id, getGlobalId(stat_id));
writer.putRecord(record);

View File

@ -389,6 +389,7 @@ class JProvider : public Firebird::StdPlugin<Firebird::IProvider, FB_PROVIDER_VE
{
public:
explicit JProvider(Firebird::IPluginConfig*)
: cryptCallback(NULL)
{
}
@ -405,10 +406,14 @@ public:
unsigned int dpbLength, const unsigned char* dpb);
virtual JService* FB_CARG attachServiceManager(Firebird::IStatus* status, const char* service,
unsigned int spbLength, const unsigned char* spb);
//virtual ITransaction* startTransaction(Firebird::IStatus* status, unsigned int count, ...);
//virtual ITransaction* startMultiple(Firebird::IStatus* status, MultipleTransaction* multi);
virtual void FB_CARG shutdown(Firebird::IStatus* status, unsigned int timeout, const int reason);
virtual void FB_CARG setDbCryptCallback(Firebird::IStatus* status,
Firebird::ICryptKeyCallback* cryptCallback);
virtual int FB_CARG release();
private:
Firebird::ICryptKeyCallback* cryptCallback;
};
} // namespace Jrd

View File

@ -201,16 +201,10 @@ Function* Function::loadMetadata(thread_db* tdbb, USHORT id, bool noscan, USHORT
if (!function->fun_existence_lock)
{
Lock* const lock = FB_NEW_RPT(*attachment->att_pool, 0) Lock;
Lock* const lock = FB_NEW_RPT(*attachment->att_pool, 0) Lock(tdbb, LCK_fun_exist, function, blockingAst);
function->fun_existence_lock = lock;
lock->lck_parent = dbb->dbb_lock;
lock->lck_dbb = dbb;
lock->lck_key.lck_long = function->getId();
lock->lck_length = sizeof(lock->lck_key.lck_long);
lock->lck_type = LCK_fun_exist;
lock->lck_owner_handle = LCK_get_owner_handle(tdbb, lock->lck_type);
lock->lck_object = function;
lock->lck_ast = blockingAst;
}
LCK_lock(tdbb, function->fun_existence_lock, LCK_SR, LCK_WAIT);
@ -521,7 +515,7 @@ int Function::blockingAst(void* ast_object)
try
{
Database* const dbb = function->fun_existence_lock->lck_dbb;
Jrd::Attachment* const att = function->fun_existence_lock->lck_attachment;
Jrd::Attachment* const att = function->fun_existence_lock->getLockAttachment();
AsyncContextHolder tdbb(dbb, att);

View File

@ -69,23 +69,15 @@ int GlobalRWLock::blocking_ast_cached_lock(void* ast_object)
return 0;
}
GlobalRWLock::GlobalRWLock(thread_db* tdbb, MemoryPool& p, locktype_t lckType,
GlobalRWLock::GlobalRWLock(thread_db* tdbb, MemoryPool& p, lck_t lckType,
lck_owner_t lock_owner, bool lock_caching, size_t lockLen, const UCHAR* lockStr)
: PermanentStorage(p), pendingLock(0), readers(0), pendingWriters(0), currentWriter(false),
lockCaching(lock_caching), blocking(false)
{
SET_TDBB(tdbb);
cachedLock = FB_NEW_RPT(getPool(), lockLen) Lock();
cachedLock->lck_type = static_cast<lck_t>(lckType);
cachedLock->lck_owner_handle = LCK_get_owner_handle_by_type(tdbb, lock_owner);
cachedLock = FB_NEW_RPT(getPool(), lockLen) Lock(tdbb, lock_owner, lckType, this, lockCaching ? blocking_ast_cached_lock : NULL);
cachedLock->lck_length = lockLen;
Database* dbb = tdbb->getDatabase();
cachedLock->lck_dbb = dbb;
cachedLock->lck_parent = dbb->dbb_lock;
cachedLock->lck_object = this;
cachedLock->lck_ast = lockCaching ? blocking_ast_cached_lock : NULL;
memcpy(&cachedLock->lck_key, lockStr, lockLen);
}

View File

@ -52,12 +52,12 @@ DEFINE_TRACE_ROUTINE(cos_trace);
namespace Jrd {
typedef USHORT locktype_t;
enum lck_t;
class GlobalRWLock : public Firebird::PermanentStorage
{
public:
GlobalRWLock(thread_db* tdbb, MemoryPool& p, locktype_t lckType,
GlobalRWLock(thread_db* tdbb, MemoryPool& p, lck_t lckType,
lck_owner_t lock_owner, bool lock_caching = true,
size_t lockLen = 0, const UCHAR* lockStr = NULL);

View File

@ -29,7 +29,9 @@
#include "../common/os/mod_loader.h"
#include "../common/intlobj_new.h"
#include "../jrd/intl_proto.h"
#include "../jrd/intl.h"
#include "../common/isc_proto.h"
#include "../common/utils_proto.h"
#include "../common/config/config.h"
#include "../common/classes/GenericMap.h"
#include "../common/classes/objects_array.h"

View File

@ -35,6 +35,7 @@
#include "../jrd/exe_proto.h"
#include "../jrd/met_proto.h"
#include "../jrd/scl_proto.h"
#include "../jrd/Collation.h"
using namespace Firebird;
using namespace Jrd;

View File

@ -32,6 +32,7 @@
#include "../jrd/exe.h"
#include "../jrd/btr.h"
#include "../jrd/intl.h"
#include "../jrd/Collation.h"
#include "../jrd/rse.h"
#include "../jrd/ods.h"
#include "../jrd/Optimizer.h"

View File

@ -30,6 +30,8 @@
#ifndef JRD_RECORDNUMBER_H
#define JRD_RECORDNUMBER_H
#include "../common/gdsassert.h"
const SINT64 BOF_NUMBER = QUADCONST(-1);
// This class is to be used everywhere you may need to handle record numbers. We
@ -215,4 +217,106 @@ private:
bool valid;
};
namespace Jrd
{
/* Blob id. A blob has two states -- temporary and permanent. In each
case, the blob id is 8 bytes (2 longwords) long. In the case of a
temporary blob, the first word is NULL and the second word points to
an internal blob block. In the case of a permanent blob, the first
word contains the relation id of the blob and the second the record
number of the first segment-clump. The two types of blobs can be
reliably distinguished by a zero or non-zero relation id. */
// This structure must occupy 8 bytes
struct bid
{
// This is how bid structure represented in public API.
// Must be present to enforce alignment rules when structure is declared on stack
struct bid_quad_struct
{
ULONG bid_quad_high;
ULONG bid_quad_low;
};
union // anonymous union
{
// Internal decomposition of the structure
RecordNumber::Packed bid_internal;
bid_quad_struct bid_quad;
};
ULONG& bid_temp_id()
{
// Make sure that compiler packed structure like we wanted
fb_assert(sizeof(*this) == 8);
return bid_internal.bid_temp_id();
}
ULONG bid_temp_id() const
{
// Make sure that compiler packed structure like we wanted
fb_assert(sizeof(*this) == 8);
return bid_internal.bid_temp_id();
}
bool isEmpty() const
{
// Make sure that compiler packed structure like we wanted
fb_assert(sizeof(*this) == 8);
return bid_quad.bid_quad_high == 0 && bid_quad.bid_quad_low == 0;
}
void clear()
{
// Make sure that compiler packed structure like we wanted
fb_assert(sizeof(*this) == 8);
bid_quad.bid_quad_high = 0;
bid_quad.bid_quad_low = 0;
}
void set_temporary(ULONG temp_id)
{
// Make sure that compiler packed structure like we wanted
fb_assert(sizeof(*this) == 8);
clear();
bid_temp_id() = temp_id;
}
void set_permanent(USHORT relation_id, RecordNumber num)
{
// Make sure that compiler packed structure like we wanted
fb_assert(sizeof(*this) == 8);
clear();
bid_internal.bid_relation_id = relation_id;
num.bid_encode(&bid_internal);
}
RecordNumber get_permanent_number() const
{
// Make sure that compiler packed structure like we wanted
fb_assert(sizeof(*this) == 8);
RecordNumber temp;
temp.bid_decode(&bid_internal);
return temp;
}
bool operator == (const bid& other) const
{
// Make sure that compiler packed structure like we wanted
fb_assert(sizeof(*this) == 8);
return bid_quad.bid_quad_high == other.bid_quad.bid_quad_high &&
bid_quad.bid_quad_low == other.bid_quad.bid_quad_low;
}
};
} //namespace Jrd
#endif // JRD_RECORDNUMBER_H

View File

@ -49,6 +49,7 @@
#include "../jrd/license.h"
#include "../jrd/trace/TraceManager.h"
#include "../jrd/trace/TraceObjects.h"
#include "../jrd/Collation.h"
#include "../common/classes/FpeControl.h"
#include <math.h>

View File

@ -83,11 +83,7 @@ void VirtualTable::erase(thread_db* tdbb, record_param* rpb)
const SLONG id = MOV_get_long(&desc, 0);
// Post a blocking request
Lock temp_lock;
temp_lock.lck_dbb = dbb;
temp_lock.lck_type = lock_type;
temp_lock.lck_parent = dbb->dbb_lock;
temp_lock.lck_owner_handle = LCK_get_owner_handle(tdbb, temp_lock.lck_type);
Lock temp_lock(tdbb, lock_type);
temp_lock.lck_length = sizeof(SLONG);
temp_lock.lck_key.lck_long = id;

View File

@ -45,14 +45,6 @@ namespace Ods
namespace Jrd
{
/* Blob id. A blob has two states -- temporary and permanent. In each
case, the blob id is 8 bytes (2 longwords) long. In the case of a
temporary blob, the first word is NULL and the second word points to
an internal blob block. In the case of a permanent blob, the first
word contains the relation id of the blob and the second the record
number of the first segment-clump. The two types of blobs can be
reliably distinguished by a zero or non-zero relation id. */
class Attachment;
class BlobControl;
class jrd_rel;
@ -66,96 +58,6 @@ class ArrayField;
struct impure_value;
// This structure must occupy 8 bytes
struct bid
{
// This is how bid structure represented in public API.
// Must be present to enforce alignment rules when structure is declared on stack
struct bid_quad_struct
{
ULONG bid_quad_high;
ULONG bid_quad_low;
};
union // anonymous union
{
// Internal decomposition of the structure
RecordNumber::Packed bid_internal;
bid_quad_struct bid_quad;
};
ULONG& bid_temp_id()
{
// Make sure that compiler packed structure like we wanted
fb_assert(sizeof(*this) == 8);
return bid_internal.bid_temp_id();
}
ULONG bid_temp_id() const
{
// Make sure that compiler packed structure like we wanted
fb_assert(sizeof(*this) == 8);
return bid_internal.bid_temp_id();
}
bool isEmpty() const
{
// Make sure that compiler packed structure like we wanted
fb_assert(sizeof(*this) == 8);
return bid_quad.bid_quad_high == 0 && bid_quad.bid_quad_low == 0;
}
void clear()
{
// Make sure that compiler packed structure like we wanted
fb_assert(sizeof(*this) == 8);
bid_quad.bid_quad_high = 0;
bid_quad.bid_quad_low = 0;
}
void set_temporary(ULONG temp_id)
{
// Make sure that compiler packed structure like we wanted
fb_assert(sizeof(*this) == 8);
clear();
bid_temp_id() = temp_id;
}
void set_permanent(USHORT relation_id, RecordNumber num)
{
// Make sure that compiler packed structure like we wanted
fb_assert(sizeof(*this) == 8);
clear();
bid_internal.bid_relation_id = relation_id;
num.bid_encode(&bid_internal);
}
RecordNumber get_permanent_number() const
{
// Make sure that compiler packed structure like we wanted
fb_assert(sizeof(*this) == 8);
RecordNumber temp;
temp.bid_decode(&bid_internal);
return temp;
}
bool operator == (const bid& other) const
{
// Make sure that compiler packed structure like we wanted
fb_assert(sizeof(*this) == 8);
return bid_quad.bid_quad_high == other.bid_quad.bid_quad_high &&
bid_quad.bid_quad_low == other.bid_quad.bid_quad_low;
}
};
// Your basic blob block.
class blb : public pool_alloc<type_blb>

View File

@ -208,13 +208,9 @@ static void checkForLowerKeySkip(bool&, const bool, const IndexNode&, const temp
BtrPageGCLock::BtrPageGCLock(thread_db* tdbb)
: Lock(tdbb, LCK_btr_dont_gc)
{
Database* dbb = tdbb->getDatabase();
lck_parent = dbb->dbb_lock;
lck_dbb = dbb;
lck_length = PageNumber::getLockLen();
lck_type = LCK_btr_dont_gc;
lck_owner_handle = LCK_get_owner_handle(tdbb, lck_type);
}
BtrPageGCLock::~BtrPageGCLock()

View File

@ -60,6 +60,7 @@
#include "../common/config/config.h"
#include "../common/classes/ClumpletWriter.h"
#include "../common/classes/MsgPrint.h"
#include "../jrd/CryptoManager.h"
using namespace Jrd;
using namespace Ods;
@ -229,7 +230,7 @@ int CCH_down_grade_dbb(void* ast_object)
{
Lock* const lock = dbb->dbb_lock;
AsyncContextHolder tdbb(dbb, lock->lck_attachment);
AsyncContextHolder tdbb(dbb, lock->getLockAttachment());
SyncLockGuard dsGuard(&dbb->dbb_sync, SYNC_EXCLUSIVE, "CCH_down_grade_dbb");
@ -839,7 +840,7 @@ void CCH_fetch_page(thread_db* tdbb, WIN* window, const bool read_shadow)
bdb->bdb_page.getPageSpaceID(), bdb->bdb_page.getPageNum(), bak_state, diff_page));
// Read page from disk as normal
while (!PIO_read(file, bdb, page, status))
while (!CryptoManager::cryptRead(file, bdb, page, status))
{
if (isTempPage || !read_shadow) {
break;
@ -884,7 +885,7 @@ void CCH_fetch_page(thread_db* tdbb, WIN* window, const bool read_shadow)
// this is a merge process.
NBAK_TRACE(("Re-reading page %d, state=%d, diff page=%d from DISK",
bdb->bdb_page, bak_state, diff_page));
while (!PIO_read(file, bdb, page, status))
while (!CryptoManager::cryptRead(file, bdb, page, status))
{
if (!read_shadow) {
break;
@ -2398,7 +2399,7 @@ bool CCH_write_all_shadows(thread_db* tdbb, Shadow* shadow, BufferDesc* bdb,
// shadow to be deleted at the next available opportunity when we
// know we don't have a page fetched
if (!PIO_write(sdw->sdw_file, bdb, page, status))
if (!CryptoManager::cryptWrite(sdw->sdw_file, bdb, page, status))
{
if (sdw->sdw_flags & SDW_manual) {
result = false;
@ -2484,17 +2485,9 @@ static Lock* alloc_page_lock(thread_db* tdbb, BufferDesc* bdb)
BufferControl *bcb = bdb->bdb_bcb;
const SSHORT lockLen = PageNumber::getLockLen();
Lock* lock = FB_NEW_RPT(*bcb->bcb_bufferpool, lockLen) Lock;
lock->lck_type = LCK_bdb;
lock->lck_owner_handle = LCK_get_owner_handle(tdbb, lock->lck_type);
Lock* lock = FB_NEW_RPT(*bcb->bcb_bufferpool, lockLen) Lock(tdbb, LCK_bdb, bdb, blocking_ast_bdb);
lock->lck_length = lockLen;
lock->lck_dbb = dbb;
lock->lck_parent = dbb->dbb_lock;
lock->lck_ast = blocking_ast_bdb;
lock->lck_object = bdb;
return lock;
}
@ -5024,7 +5017,7 @@ static bool write_page(thread_db* tdbb, BufferDesc* bdb, ISC_STATUS* const statu
// We need to write our pages to main database files
jrd_file* file = pageSpace->file;
while (!PIO_write(file, bdb, page, status))
while (!CryptoManager::cryptWrite(file, bdb, page, status))
{
if (isTempPage || !CCH_rollover_to_shadow(tdbb, dbb, file, inAst))
{

View File

@ -313,14 +313,10 @@ IndexLock* CMP_get_index_lock(thread_db* tdbb, jrd_rel* relation, USHORT id)
index->idl_id = id;
index->idl_count = 0;
Lock* lock = FB_NEW_RPT(*relation->rel_pool, 0) Lock;
Lock* lock = FB_NEW_RPT(*relation->rel_pool, 0) Lock(tdbb, LCK_idx_exist);
index->idl_lock = lock;
lock->lck_parent = dbb->dbb_lock;
lock->lck_dbb = dbb;
lock->lck_key.lck_long = (relation->rel_id << 16) | id;
lock->lck_length = sizeof(lock->lck_key.lck_long);
lock->lck_type = LCK_idx_exist;
lock->lck_owner_handle = LCK_get_owner_handle(tdbb, lock->lck_type);
return index;
}

View File

@ -41,6 +41,7 @@
#include "../jrd/err_proto.h"
#include "../jrd/intl_proto.h"
#include "../jrd/intl_classes.h"
#include "../jrd/Collation.h"
#include "../yvalve/gds_proto.h"
// CVC: I needed them here.
#include "../jrd/jrd.h"

View File

@ -125,6 +125,7 @@
#include "../jrd/ResultSet.h"
#include "../common/utils_proto.h"
#include "../common/classes/Hash.h"
#include "../jrd/CryptoManager.h"
#ifdef HAVE_UNISTD_H
#include <unistd.h>
@ -402,6 +403,7 @@ static bool user_management(thread_db*, SSHORT, DeferredWork*, jrd_tra*);
static bool drop_package_header(thread_db*, SSHORT, DeferredWork*, jrd_tra*);
static bool drop_package_body(thread_db*, SSHORT, DeferredWork*, jrd_tra*);
static bool grant_privileges(thread_db*, SSHORT, DeferredWork*, jrd_tra*);
static bool db_crypt(thread_db*, SSHORT, DeferredWork*, jrd_tra*);
// ----------------------------------------------------------------
@ -493,6 +495,7 @@ static const deferred_task task_table[] =
{ dfw_user_management, user_management },
{ dfw_check_not_null, check_not_null },
{ dfw_store_view_context_type, store_view_context_type },
{ dfw_db_crypt, db_crypt },
{ dfw_null, NULL }
};
@ -902,6 +905,24 @@ DeferredWork* DFW_post_system_work(thread_db* tdbb, enum dfw_t type, const dsc*
DeferredWork* DFW_post_work(jrd_tra* transaction, enum dfw_t type, const dsc* desc, USHORT id,
const MetaName& package)
{
/**************************************
*
* D F W _ p o s t _ w o r k
*
**************************************
*
* Functional description
* Post work to be deferred to commit time.
*
**************************************/
return DFW_post_work(transaction, type, get_string(desc), id, package);
}
DeferredWork* DFW_post_work(jrd_tra* transaction, enum dfw_t type, const string& name, USHORT id,
const MetaName& package)
{
/**************************************
*
* D F W _ p o s t _ w o r k
@ -935,7 +956,6 @@ DeferredWork* DFW_post_work(jrd_tra* transaction, enum dfw_t type, const dsc* de
job->hash.add(sp);
}
const string name = get_string(desc);
DeferredWork tmp(AutoStorage::getAutoMemoryPool(), 0, type, id, sav_number, name, package);
DeferredWork* work = sp->hash.lookup(tmp);
if (work)
@ -1479,6 +1499,35 @@ static bool end_backup(thread_db* tdbb, SSHORT phase, DeferredWork*, jrd_tra*)
return false;
}
static bool db_crypt(thread_db* tdbb, SSHORT phase, DeferredWork* work, jrd_tra*)
{
/**************************************
*
* d b _ c r y p t
*
**************************************
*
* Encrypt database using plugin dfw_name or decrypt if dfw_name is empty.
*
**************************************/
SET_TDBB(tdbb);
Database* const dbb = tdbb->getDatabase();
switch (phase)
{
case 1:
case 2:
return true;
case 3:
dbb->dbb_crypto_manager->changeCryptState(tdbb, work->dfw_name);
break;
}
return false;
}
static bool check_not_null(thread_db* tdbb, SSHORT phase, DeferredWork* work, jrd_tra* transaction)
{
/**************************************
@ -2767,13 +2816,10 @@ static bool create_relation(thread_db* tdbb, SSHORT phase, DeferredWork* work, j
case 3:
// Take a relation lock on rel id -1 before actually generating a relation id.
work->dfw_lock = lock = FB_NEW_RPT(*tdbb->getDefaultPool(), sizeof(SLONG)) Lock;
lock->lck_dbb = dbb;
work->dfw_lock = lock = FB_NEW_RPT(*tdbb->getDefaultPool(), sizeof(SLONG))
Lock(tdbb, LCK_relation);
lock->lck_length = sizeof(SLONG);
lock->lck_key.lck_long = -1;
lock->lck_type = LCK_relation;
lock->lck_owner_handle = LCK_get_owner_handle(tdbb, lock->lck_type);
lock->lck_parent = dbb->dbb_lock;
LCK_lock(tdbb, lock, LCK_EX, LCK_WAIT);

View File

@ -41,6 +41,8 @@ void DFW_perform_post_commit_work(Jrd::jrd_tra*);
Jrd::DeferredWork* DFW_post_system_work(Jrd::thread_db*, Jrd::dfw_t, const dsc*, USHORT);
Jrd::DeferredWork* DFW_post_work(Jrd::jrd_tra*, Jrd::dfw_t, const dsc*, USHORT,
const Firebird::MetaName& package = NULL);
Jrd::DeferredWork* DFW_post_work(Jrd::jrd_tra*, Jrd::dfw_t, const Firebird::string&, USHORT,
const Firebird::MetaName& package = NULL);
Jrd::DeferredWork* DFW_post_work_arg(Jrd::jrd_tra*, Jrd::DeferredWork*, const dsc*, USHORT);
Jrd::DeferredWork* DFW_post_work_arg(Jrd::jrd_tra*, Jrd::DeferredWork*, const dsc*, USHORT, Jrd::dfw_t);
void DFW_update_index(const TEXT*, USHORT, const Jrd::SelectivityList&, Jrd::jrd_tra*);

View File

@ -160,7 +160,9 @@ void InternalConnection::attach(thread_db* tdbb, const Firebird::string& dbName,
LocalStatus status;
{
EngineCallbackGuard guard(tdbb, *this);
m_attachment = JProvider::getInstance()->attachDatabase(&status, m_dbName.c_str(),
Firebird::RefPtr<JProvider> jInstance(JProvider::getInstance());
jInstance->setDbCryptCallback(&status, tdbb->getAttachment()->att_crypt_callback);
m_attachment = jInstance->attachDatabase(&status, m_dbName.c_str(),
m_dpb.getBufferLength(), m_dpb.getBuffer());
}

View File

@ -235,6 +235,24 @@ typedef struct paramvary {
#include "../dsql/sqlda_pub.h"
/*************************************/
/* Namespace compatibility for C/C++ */
/*************************************/
#ifdef __cplusplus
#define FB_NAMESPACE_FORWARD(n, x) namespace n { class x; }
#define FB_NAMESPACE_USE(n, x) n::x
#else
#define FB_NAMESPACE_FORWARD(n, x)
#define FB_NAMESPACE_USE(n, x) struct x
#endif
/************************/
/* Forward declarations */
/************************/
FB_NAMESPACE_FORWARD(Firebird, ICryptKeyCallback)
/***************************/
/* OSRI database functions */
/***************************/
@ -1161,6 +1179,13 @@ void ISC_EXPORT isc_get_client_version ( ISC_SCHAR *);
int ISC_EXPORT isc_get_client_major_version ();
int ISC_EXPORT isc_get_client_minor_version ();
/*******************************************/
/* Set callback for database crypt plugins */
/*******************************************/
ISC_STATUS ISC_EXPORT fb_database_crypt_callback(ISC_STATUS*,
FB_NAMESPACE_USE(Firebird, ICryptKeyCallback*));
#ifdef __cplusplus
} /* extern "C" */
#endif

View File

@ -63,6 +63,7 @@
#include "../jrd/mov_proto.h"
#include "../jrd/vio_proto.h"
#include "../jrd/tra_proto.h"
#include "../jrd/Collation.h"
using namespace Jrd;
@ -550,16 +551,11 @@ IndexBlock* IDX_create_index_block(thread_db* tdbb, jrd_rel* relation, USHORT id
// any modification to the index so that the cached information
// about the index will be discarded
Lock* lock = FB_NEW_RPT(*relation->rel_pool, 0) Lock;
Lock* lock = FB_NEW_RPT(*relation->rel_pool, 0)
Lock(tdbb, LCK_expression, index_block, index_block_flush);
index_block->idb_lock = lock;
lock->lck_parent = dbb->dbb_lock;
lock->lck_dbb = dbb;
lock->lck_key.lck_long = (relation->rel_id << 16) | index_block->idb_id;
lock->lck_length = sizeof(lock->lck_key.lck_long);
lock->lck_type = LCK_expression;
lock->lck_owner_handle = LCK_get_owner_handle(tdbb, lock->lck_type);
lock->lck_ast = index_block_flush;
lock->lck_object = index_block;
return index_block;
}
@ -1393,7 +1389,7 @@ static int index_block_flush(void* ast_object)
{
Lock* const lock = index_block->idb_lock;
Database* const dbb = lock->lck_dbb;
Jrd::Attachment* const att = lock->lck_attachment;
Jrd::Attachment* const att = lock->getLockAttachment();
AsyncContextHolder tdbb(dbb, att);

View File

@ -118,6 +118,7 @@
#include "../jrd/lck_proto.h"
#include "../jrd/met_proto.h"
#include "../common/intlobj_new.h"
#include "../jrd/Collation.h"
#include "../jrd/mov_proto.h"
#include "../jrd/IntlManager.h"
#include "../common/classes/init.h"
@ -170,7 +171,7 @@ public:
CsConvert lookupConverter(thread_db* tdbb, CHARSET_ID to_cs);
static CharSetContainer* lookupCharset(thread_db* tdbb, USHORT ttype);
static Lock* createCollationLock(thread_db* tdbb, USHORT ttype);
static Lock* createCollationLock(thread_db* tdbb, USHORT ttype, void* object = NULL);
private:
static bool lookupInternalCharSet(USHORT id, SubtypeInfo* info);
@ -281,7 +282,7 @@ bool CharSetContainer::lookupInternalCharSet(USHORT id, SubtypeInfo* info)
}
Lock* CharSetContainer::createCollationLock(thread_db* tdbb, USHORT ttype)
Lock* CharSetContainer::createCollationLock(thread_db* tdbb, USHORT ttype, void* object)
{
/**************************************
*
@ -293,15 +294,13 @@ Lock* CharSetContainer::createCollationLock(thread_db* tdbb, USHORT ttype)
* Create a collation lock.
*
**************************************/
Lock* lock = FB_NEW_RPT(*tdbb->getDatabase()->dbb_permanent, 0) Lock;
lock->lck_parent = tdbb->getDatabase()->dbb_lock;
lock->lck_dbb = tdbb->getDatabase();
// Could we have an AST on this lock? If yes, it will fail if we don't
// have lck_object to it, so set ast routine to NULL for safety.
Lock* lock = FB_NEW_RPT(*tdbb->getDatabase()->dbb_permanent, 0)
Lock(tdbb, LCK_tt_exist, object, object ? blocking_ast_collation : NULL);
lock->lck_key.lck_long = ttype;
lock->lck_length = sizeof(lock->lck_key.lck_long);
lock->lck_type = LCK_tt_exist;
lock->lck_owner_handle = LCK_get_owner_handle(tdbb, lock->lck_type);
lock->lck_object = NULL;
lock->lck_ast = blocking_ast_collation;
return lock;
}
@ -425,8 +424,7 @@ Collation* CharSetContainer::lookupCollation(thread_db* tdbb, USHORT tt_id)
if (id != 0)
{
Lock* lock = charset_collations[id]->existenceLock =
CharSetContainer::createCollationLock(tdbb, tt_id);
lock->lck_object = charset_collations[id];
CharSetContainer::createCollationLock(tdbb, tt_id, charset_collations[id]);
fb_assert(charset_collations[id]->useCount == 0);
fb_assert(!charset_collations[id]->obsolete);
@ -485,10 +483,6 @@ void CharSetContainer::unloadCollation(thread_db* tdbb, USHORT tt_id)
// signal other processes collation is gone
Lock* lock = CharSetContainer::createCollationLock(tdbb, tt_id);
// Could we have an AST on this lock? If yes, it will fail as we don't
// assign lck_object to it, so clear ast routine for safety.
lock->lck_ast = NULL;
LCK_lock(tdbb, lock, LCK_EX, LCK_WAIT);
LCK_release(tdbb, lock);
@ -1390,7 +1384,7 @@ static int blocking_ast_collation(void* ast_object)
try
{
Database* const dbb = tt->existenceLock->lck_dbb;
Jrd::Attachment* const att = tt->existenceLock->lck_attachment;
Jrd::Attachment* const att = tt->existenceLock->getLockAttachment();
AsyncContextHolder tdbb(dbb, att);

View File

@ -29,7 +29,6 @@
#define JRD_INTL_CLASSES_H
#include "firebird.h"
#include "../jrd/jrd.h"
#include "../common/intlobj_new.h"
#include "../jrd/constants.h"
@ -144,7 +143,4 @@ private:
} // namespace Jrd
#include "../jrd/Collation.h"
#endif // JRD_INTL_CLASSES_H

View File

@ -29,6 +29,7 @@
namespace Jrd {
class thread_db;
class Lock;
class Collation;
}
struct dsc;

View File

@ -125,10 +125,13 @@
#include "../common/utils_proto.h"
#include "../jrd/DebugInterface.h"
#include "../jrd/EngineInterface.h"
#include "../jrd/CryptoManager.h"
#include "../dsql/dsql.h"
#include "../dsql/dsql_proto.h"
#include "firebird/Crypt.h"
using namespace Jrd;
using namespace Firebird;
@ -487,6 +490,23 @@ namespace
ERR_post(Arg::Gds(isc_adm_task_denied));
}
}
class DefaultCallback : public AutoIface<ICryptKeyCallback, FB_CRYPT_CALLBACK_VERSION>
{
public:
unsigned int FB_CARG callback(unsigned int, const void*, unsigned int, void*)
{
return 0;
}
};
DefaultCallback defCallback;
ICryptKeyCallback* getCryptCallback(ICryptKeyCallback* callback)
{
return callback ? callback : &defCallback;
}
} // anonymous
@ -646,7 +666,6 @@ public:
AuthReader::AuthBlock dpb_auth_block;
string dpb_role_name;
string dpb_journal;
string dpb_key;
string dpb_lc_ctype;
PathName dpb_working_directory;
string dpb_set_db_charset;
@ -1009,20 +1028,6 @@ const ULONG SWEEP_INTERVAL = 20000;
const char DBL_QUOTE = '\042';
const char SINGLE_QUOTE = '\'';
// External hook definitions
/* dimitr: just uncomment the following line to use this feature.
Requires support from the PIO modules. Only Win32 is 100% ready
for this so far. Note that the database encryption code in the
PIO layer seems to be incompatible with the SUPERSERVER_V2 code.
2003.02.09 */
//#define ISC_DATABASE_ENCRYPTION
// The code that uses these constants was disabled by Adriano with comment "old PluginManager".
//static const char* CRYPT_IMAGE = "fbcrypt";
//static const char* ENCRYPT = "encrypt";
//static const char* DECRYPT = "decrypt";
static void trace_warning(thread_db* tdbb, Firebird::IStatus* userStatus, const char* func)
{
@ -1219,28 +1224,6 @@ JAttachment* FB_CARG JProvider::attachDatabase(IStatus* user_status, const char*
Arg::Str(org_filename));
}
// Worry about encryption key
if (dbb->dbb_decrypt)
{
if (dbb->dbb_filename.hasData() &&
(dbb->dbb_encrypt_key.hasData() || options.dpb_key.hasData()))
{
if ((dbb->dbb_encrypt_key.hasData() && options.dpb_key.isEmpty()) ||
(dbb->dbb_encrypt_key.empty() && options.dpb_key.hasData()) ||
(dbb->dbb_encrypt_key != options.dpb_key))
{
ERR_post(Arg::Gds(isc_no_priv) << Arg::Str("encryption") <<
Arg::Str("database") <<
Arg::Str(org_filename));
}
}
else if (options.dpb_key.hasData())
{
dbb->dbb_encrypt_key = options.dpb_key;
}
}
attachment = Jrd::Attachment::create(dbb);
RefPtr<JAttachment> jAtt(new JAttachment(attachment));
@ -1256,6 +1239,7 @@ JAttachment* FB_CARG JProvider::attachDatabase(IStatus* user_status, const char*
attachment->att_remote_process = options.dpb_remote_process;
attachment->att_next = dbb->dbb_attachments;
attachment->att_ext_call_depth = options.dpb_ext_call_depth;
attachment->att_crypt_callback = getCryptCallback(cryptCallback);
dbb->dbb_attachments = attachment;
dbb->dbb_flags &= ~DBB_being_opened;
@ -1359,10 +1343,15 @@ JAttachment* FB_CARG JProvider::attachDatabase(IStatus* user_status, const char*
PAG_init2(tdbb, 0);
PAG_header(tdbb, false);
dbb->dbb_crypto_manager = FB_NEW(*dbb->dbb_permanent) CryptoManager(tdbb);
dbb->dbb_crypto_manager->attach(tdbb, attachment);
// initialize shadowing as soon as the database is ready for it
// but before any real work is done
SDW_init(tdbb, options.dpb_activate_shadow, options.dpb_delete_shadow);
CCH_init2(tdbb);
dbb->dbb_crypto_manager->startCryptThread(tdbb);
}
else
{
@ -1380,6 +1369,8 @@ JAttachment* FB_CARG JProvider::attachDatabase(IStatus* user_status, const char*
INI_init(tdbb);
INI_init2(tdbb);
PAG_header(tdbb, true);
dbb->dbb_crypto_manager->attach(tdbb, attachment);
dbb->dbb_crypto_manager->startCryptThread(tdbb);
}
// Attachments to a ReadOnly database need NOT do garbage collection
@ -2338,12 +2329,6 @@ JAttachment* FB_CARG JProvider::createDatabase(IStatus* user_status, const char*
bool initing_security = false;
try {
if (options.dpb_key.hasData())
{
dbb->dbb_encrypt_key = options.dpb_key;
}
attachment = Jrd::Attachment::create(dbb);
RefPtr<JAttachment> jAtt(new JAttachment(attachment));
@ -2359,6 +2344,7 @@ JAttachment* FB_CARG JProvider::createDatabase(IStatus* user_status, const char*
attachment->att_remote_process = options.dpb_remote_process;
attachment->att_ext_call_depth = options.dpb_ext_call_depth;
attachment->att_next = dbb->dbb_attachments;
attachment->att_crypt_callback = getCryptCallback(cryptCallback);
dbb->dbb_attachments = attachment;
dbb->dbb_flags &= ~DBB_being_opened;
@ -2512,6 +2498,8 @@ JAttachment* FB_CARG JProvider::createDatabase(IStatus* user_status, const char*
INI_init2(tdbb);
PAG_format_pip(tdbb, *pageSpace);
dbb->dbb_crypto_manager = FB_NEW(*dbb->dbb_permanent) CryptoManager(tdbb);
if (options.dpb_set_page_buffers)
PAG_set_page_buffers(tdbb, options.dpb_page_buffers);
@ -3570,7 +3558,7 @@ void JRequest::send(IStatus* user_status, int level, unsigned int msg_type,
JService* JProvider::attachServiceManager(IStatus* user_status, const char* service_name,
unsigned int spbLength, const unsigned char* spb)
unsigned int spbLength, const unsigned char* spb)
{
/**************************************
*
@ -3588,7 +3576,7 @@ JService* JProvider::attachServiceManager(IStatus* user_status, const char* serv
{
ThreadContextHolder tdbb(user_status);
svc = new JService(new Service(service_name, spbLength, spb));
svc = new JService(new Service(service_name, spbLength, spb, cryptCallback));
svc->addRef();
}
catch (const Exception& ex)
@ -3990,6 +3978,13 @@ void JProvider::shutdown(IStatus* status, unsigned int timeout, const int reason
}
void JProvider::setDbCryptCallback(IStatus* status, ICryptKeyCallback* callback)
{
status->init();
cryptCallback = callback;
}
JTransaction* JAttachment::startTransaction(IStatus* user_status,
unsigned int tpbLength, const unsigned char* tpb)
{
@ -5371,14 +5366,10 @@ void DatabaseOptions::get(const UCHAR* dpb, USHORT dpb_length, bool& invalid_cli
break;
case isc_dpb_encrypt_key:
#ifdef ISC_DATABASE_ENCRYPTION
rdr.getString(dpb_key);
#else
// Just in case there WAS a customer using this unsupported
// feature - post an error when they try to access it in 4.0
// feature - post an error when they try to access it now
ERR_post(Arg::Gds(isc_uns_ext) <<
Arg::Gds(isc_random) << Arg::Str("Encryption not supported"));
#endif
Arg::Gds(isc_random) << Arg::Str("Passing encryption key in DPB not supported"));
break;
case isc_dpb_no_garbage_collect:
@ -5690,23 +5681,6 @@ static Database* init(thread_db* tdbb,
}
}
// Initialize a number of subsystems
#ifdef ISC_DATABASE_ENCRYPTION
// Lookup some external "hooks"
/*** ASF: old PluginManager
PluginManager::Plugin crypt_lib = PluginManager::enginePluginManager().findPlugin(CRYPT_IMAGE);
if (crypt_lib)
{
string encrypt_entrypoint(ENCRYPT);
string decrypt_entrypoint(DECRYPT);
dbb->dbb_encrypt = (Database::crypt_routine) crypt_lib.lookupSymbol(encrypt_entrypoint);
dbb->dbb_decrypt = (Database::crypt_routine) crypt_lib.lookupSymbol(decrypt_entrypoint);
}
***/
#endif
return dbb;
}
@ -5735,14 +5709,10 @@ static void init_database_locks(thread_db* tdbb)
PIO_get_unique_file_id(pageSpace->file, file_id);
size_t key_length = file_id.getCount();
Lock* lock = FB_NEW_RPT(*dbb->dbb_permanent, key_length) Lock;
Lock* lock = FB_NEW_RPT(*dbb->dbb_permanent, key_length)
Lock(tdbb, LCK_database, dbb, CCH_down_grade_dbb);
dbb->dbb_lock = lock;
lock->lck_type = LCK_database;
lock->lck_owner_handle = LCK_get_owner_handle(tdbb, lock->lck_type);
lock->lck_object = dbb;
lock->lck_length = key_length;
lock->lck_dbb = dbb;
lock->lck_ast = CCH_down_grade_dbb;
memcpy(lock->lck_key.lck_string, file_id.begin(), key_length);
// Try to get an exclusive lock on database.
@ -5777,15 +5747,10 @@ static void init_database_locks(thread_db* tdbb)
// Lock shared by all dbb owners, used to signal other processes
// to dump their monitoring data and synchronize operations
lock = FB_NEW_RPT(*dbb->dbb_permanent, sizeof(SLONG)) Lock();
lock = FB_NEW_RPT(*dbb->dbb_permanent, sizeof(SLONG))
Lock(tdbb, LCK_monitor, dbb, DatabaseSnapshot::blockingAst);
dbb->dbb_monitor_lock = lock;
lock->lck_type = LCK_monitor;
lock->lck_owner_handle = LCK_get_owner_handle(tdbb, lock->lck_type);
lock->lck_parent = dbb->dbb_lock;
lock->lck_length = sizeof(SLONG);
lock->lck_dbb = dbb;
lock->lck_object = dbb;
lock->lck_ast = DatabaseSnapshot::blockingAst;
LCK_lock(tdbb, lock, LCK_SR, LCK_WAIT);
}
@ -6063,11 +6028,18 @@ static void shutdown_database(Database* dbb, const bool release_pools)
#endif
VIO_fini(tdbb);
if (dbb->dbb_crypto_manager)
dbb->dbb_crypto_manager->terminateCryptThread(tdbb);
CCH_fini(tdbb);
if (dbb->dbb_backup_manager)
dbb->dbb_backup_manager->shutdown(tdbb);
if (dbb->dbb_crypto_manager)
dbb->dbb_crypto_manager->shutdown(tdbb);
if (dbb->dbb_monitor_lock)
LCK_release(tdbb, dbb->dbb_monitor_lock);

View File

@ -69,9 +69,8 @@ static bool internal_compatible(Lock*, const Lock*, USHORT);
static void internal_dequeue(thread_db*, Lock*);
static USHORT internal_downgrade(thread_db*, Arg::StatusVector&, Lock*);
static bool internal_enqueue(thread_db*, Arg::StatusVector&, Lock*, USHORT, SSHORT, bool);
static void set_lock_attachment(Lock*, Jrd::Attachment*);
static SLONG get_owner_handle_by_type(thread_db* tdbb, lck_owner_t lck_owner_type);
static SLONG get_owner_handle(thread_db* tdbb, enum lck_t lock_type);
#ifdef DEBUG_LCK
namespace
@ -334,8 +333,8 @@ bool LCK_convert(thread_db* tdbb, Lock* lock, USHORT level, SSHORT wait)
Database* dbb = lock->lck_dbb;
Jrd::Attachment* const old_attachment = lock->lck_attachment;
set_lock_attachment(lock, tdbb->getAttachment());
Jrd::Attachment* const old_attachment = lock->getLockAttachment();
lock->setLockAttachment(tdbb->getAttachment());
WaitCancelGuard guard(tdbb, lock, wait);
Arg::StatusVector statusVector;
@ -344,7 +343,7 @@ bool LCK_convert(thread_db* tdbb, Lock* lock, USHORT level, SSHORT wait)
if (!result)
{
set_lock_attachment(lock, old_attachment);
lock->setLockAttachment(old_attachment);
switch (statusVector.value()[1])
{
@ -450,7 +449,7 @@ void LCK_downgrade(thread_db* tdbb, Lock* lock)
if (lock->lck_physical == LCK_none)
{
lock->lck_id = lock->lck_data = 0;
set_lock_attachment(lock, NULL);
lock->setLockAttachment(NULL);
}
fb_assert(LCK_CHECK_LOCK(lock));
@ -494,11 +493,11 @@ void LCK_fini(thread_db* tdbb, enum lck_owner_t owner_type)
}
SLONG LCK_get_owner_handle(thread_db* tdbb, enum lck_t lock_type)
static SLONG get_owner_handle(thread_db* tdbb, enum lck_t lock_type)
{
/**************************************
*
* L C K _ g e t _ o w n e r _ h a n d l e
* g e t _ o w n e r _ h a n d l e
*
**************************************
*
@ -520,6 +519,8 @@ SLONG LCK_get_owner_handle(thread_db* tdbb, enum lck_t lock_type)
case LCK_backup_database:
case LCK_monitor:
case LCK_shared_counter:
case LCK_crypt:
case LCK_crypt_status:
handle = *LCK_OWNER_HANDLE_DBB(tdbb);
break;
@ -545,7 +546,7 @@ SLONG LCK_get_owner_handle(thread_db* tdbb, enum lck_t lock_type)
break;
default:
bug_lck("Invalid lock type in LCK_get_owner_handle()");
bug_lck("Invalid lock type in get_owner_handle()");
}
if (!handle)
@ -557,7 +558,7 @@ SLONG LCK_get_owner_handle(thread_db* tdbb, enum lck_t lock_type)
}
SLONG LCK_get_owner_handle_by_type(thread_db* tdbb, lck_owner_t lck_owner_type)
static SLONG get_owner_handle_by_type(thread_db* tdbb, lck_owner_t lck_owner_type)
{
/**********************************************************
*
@ -654,7 +655,7 @@ bool LCK_lock(thread_db* tdbb, Lock* lock, USHORT level, SSHORT wait)
#endif
Database* dbb = lock->lck_dbb;
set_lock_attachment(lock, tdbb->getAttachment());
lock->setLockAttachment(tdbb->getAttachment());
WaitCancelGuard guard(tdbb, lock, wait);
Arg::StatusVector statusVector;
@ -664,7 +665,7 @@ bool LCK_lock(thread_db* tdbb, Lock* lock, USHORT level, SSHORT wait)
if (!lock->lck_id)
{
set_lock_attachment(lock, NULL);
lock->setLockAttachment(NULL);
if (!wait)
{
statusVector.copyTo(tdbb->tdbb_status_vector);
@ -809,7 +810,7 @@ void LCK_release(thread_db* tdbb, Lock* lock)
lock->lck_physical = lock->lck_logical = LCK_none;
lock->lck_id = lock->lck_data = 0;
set_lock_attachment(lock, NULL);
lock->setLockAttachment(NULL);
fb_assert(LCK_CHECK_LOCK(lock));
}
@ -1042,7 +1043,7 @@ static void hash_allocate(Lock* lock)
**************************************/
fb_assert(LCK_CHECK_LOCK(lock));
Jrd::Attachment* const attachment = lock->lck_attachment;
Jrd::Attachment* const attachment = lock->getLockAttachment();
if (attachment)
{
@ -1070,7 +1071,7 @@ static Lock* hash_get_lock(Lock* lock, USHORT* hash_slot, Lock*** prior)
**************************************/
fb_assert(LCK_CHECK_LOCK(lock));
Jrd::Attachment* const att = lock->lck_attachment;
Jrd::Attachment* const att = lock->getLockAttachment();
if (!att)
return NULL;
@ -1131,7 +1132,7 @@ static void hash_insert_lock(Lock* lock)
**************************************/
fb_assert(LCK_CHECK_LOCK(lock));
Jrd::Attachment* const att = lock->lck_attachment;
Jrd::Attachment* const att = lock->getLockAttachment();
if (!att)
return;
@ -1494,53 +1495,97 @@ static bool internal_enqueue(thread_db* tdbb, Arg::StatusVector& statusVector, L
return lock->lck_id ? true : false;
}
static void set_lock_attachment(Lock* lock, Jrd::Attachment* attachment)
Lock::Lock(thread_db* tdbb, lck_t type, void* object, lock_ast_t ast)
: lck_dbb(tdbb->getDatabase()),
lck_attachment(0),
lck_compatible(0),
lck_compatible2(0),
lck_ast(ast),
lck_object(object),
lck_parent(type == LCK_database ? NULL : lck_dbb->dbb_lock),
lck_next(0),
lck_prior(0),
lck_collision(0),
lck_identical(0),
lck_id(0),
lck_owner_handle(get_owner_handle(tdbb, type)),
lck_length(0),
lck_type(type),
lck_logical(0),
lck_physical(0),
lck_data(0)
{
if (lock->lck_attachment == attachment)
lck_key.lck_long = 0;
lck_tail[0] = 0;
}
Lock::Lock(thread_db* tdbb, lck_owner_t ownerType, lck_t type, void* object, lock_ast_t ast)
: lck_dbb(tdbb->getDatabase()),
lck_attachment(0),
lck_compatible(0),
lck_compatible2(0),
lck_ast(ast),
lck_object(object),
lck_parent(type == LCK_database ? NULL : lck_dbb->dbb_lock),
lck_next(0),
lck_prior(0),
lck_collision(0),
lck_identical(0),
lck_id(0),
lck_owner_handle(get_owner_handle_by_type(tdbb, ownerType)),
lck_length(0),
lck_type(type),
lck_logical(0),
lck_physical(0),
lck_data(0)
{
lck_key.lck_long = 0;
lck_tail[0] = 0;
}
void Lock::setLockAttachment(Jrd::Attachment* attachment)
{
if (lck_attachment == attachment)
return;
Database* dbb = attachment ? attachment->att_database :
(lock->lck_attachment ? lock->lck_attachment->att_database : NULL);
(lck_attachment ? lck_attachment->att_database : NULL);
fb_assert(dbb);
if (!dbb)
return;
Sync lckSync(&dbb->dbb_lck_sync, "set_lock_attachment");
Sync lckSync(&dbb->dbb_lck_sync, "setLockAttachment");
lckSync.lock(SYNC_EXCLUSIVE);
// If lock has an attachment it must not be a part of linked list
fb_assert(!lock->lck_attachment ? !lock->lck_prior && !lock->lck_next : true);
fb_assert(!lck_attachment ? !lck_prior && !lck_next : true);
// Delist in old attachment
if (lock->lck_attachment)
if (lck_attachment)
{
// Check that attachment seems to be valid, check works only when DEBUG_GDS_ALLOC is defined
fb_assert(lock->lck_attachment->att_flags != 0xDEADBEEF);
fb_assert(lck_attachment->att_flags != 0xDEADBEEF);
Lock* const next = lock->lck_next;
Lock* const prior = lock->lck_prior;
if (prior)
if (lck_prior)
{
fb_assert(prior->lck_next == lock);
prior->lck_next = next;
fb_assert(lck_prior->lck_next == this);
lck_prior->lck_next = lck_next;
}
else
{
fb_assert(lock->lck_attachment->att_long_locks == lock);
lock->lck_attachment->att_long_locks = next;
fb_assert(lck_attachment->att_long_locks == this);
lck_attachment->att_long_locks = lck_next;
}
if (next)
if (lck_next)
{
fb_assert(next->lck_prior == lock);
next->lck_prior = prior;
fb_assert(lck_next->lck_prior == this);
lck_next->lck_prior = lck_prior;
}
lock->lck_next = NULL;
lock->lck_prior = NULL;
lck_next = NULL;
lck_prior = NULL;
}
@ -1550,14 +1595,23 @@ static void set_lock_attachment(Lock* lock, Jrd::Attachment* attachment)
// Check that attachment seems to be valid, check works only when DEBUG_GDS_ALLOC is defined
fb_assert(attachment->att_flags != 0xDEADBEEF);
lock->lck_next = attachment->att_long_locks;
lock->lck_prior = NULL;
attachment->att_long_locks = lock;
lck_next = attachment->att_long_locks;
lck_prior = NULL;
attachment->att_long_locks = this;
Lock* next = lock->lck_next;
if (next)
next->lck_prior = lock;
if (lck_next)
lck_next->lck_prior = this;
}
lock->lck_attachment = attachment;
lck_attachment = attachment;
}
Lock* Lock::detach()
{
Lock* next = lck_next;
lck_attachment = NULL;
lck_next = NULL;
lck_prior = NULL;
return next;
}

View File

@ -34,6 +34,7 @@ namespace Jrd {
class Database;
class Attachment;
class thread_db;
// Lock types
@ -63,7 +64,9 @@ enum lck_t {
LCK_btr_dont_gc, // Prevent removal of b-tree page from index
LCK_shared_counter, // Database-wide shared counter
LCK_fun_exist, // Function existence lock
LCK_rel_rescan // Relation forced rescan lock
LCK_rel_rescan, // Relation forced rescan lock
LCK_crypt, // Crypt lock for single crypt thread
LCK_crypt_status // Notifies about changed database encryption status
};
// Lock owner types
@ -76,33 +79,35 @@ enum lck_owner_t {
class Lock : public pool_alloc_rpt<UCHAR, type_lck>
{
public:
Lock()
: lck_parent(0),
lck_next(0),
lck_prior(0),
lck_collision(0),
lck_identical(0),
lck_compatible(0),
lck_compatible2(0),
lck_dbb(0),
lck_attachment(0),
lck_ast(0),
lck_object(0),
lck_id(0),
lck_owner_handle(0),
lck_length(0),
lck_logical(0),
lck_physical(0),
lck_data(0)
Lock(thread_db* tdbb, lck_t type, void* object = NULL, lock_ast_t ast = NULL);
Lock(thread_db* tdbb, lck_owner_t ownerType, lck_t type, void* object, lock_ast_t ast);
Lock* detach();
Attachment* getLockAttachment()
{
lck_key.lck_long = 0;
lck_tail[0] = 0;
return lck_attachment;
}
void setLockAttachment(Attachment* att);
#ifdef DEBUG_LCK
Firebird::SyncObject lck_sync;
#endif
Database* lck_dbb; // Database object is contained in
private:
Attachment* lck_attachment; // Attachment that owns lock, set only using set_lock_attachment()
public:
void* lck_compatible; // Enter into internal_enqueue() and treat as compatible
void* lck_compatible2; // Sub-level for internal compatibility
lock_ast_t lck_ast; // Blocking AST routine
void* lck_object; // Argument to be passed to AST
//private:
Lock* lck_parent;
Lock* lck_next; // lck_next and lck_prior form a doubly linked list of locks
@ -110,19 +115,13 @@ public:
Lock* lck_collision; // Collisions in compatibility table
Lock* lck_identical; // Identical locks in compatibility table
void* lck_compatible; // Enter into internal_enqueue() and treat as compatible
void* lck_compatible2; // Sub-level for internal compatibility
Database* lck_dbb; // Database object is contained in
Attachment* lck_attachment; // Attachment that owns lock, set only using set_lock_attachment()
lock_ast_t lck_ast; // Blocking AST routine
void* lck_object; // Argument to be passed to AST
lck_t lck_type; // Lock type
SLONG lck_id; // Lock id from the lock manager
SLONG lck_owner_handle; // Lock owner handle from the lock manager's point of view
SSHORT lck_length; // Length of lock key string
lck_t lck_type; // Lock type
public:
UCHAR lck_logical; // Logical lock level
UCHAR lck_physical; // Physical lock level
SLONG lck_data; // Data associated with a lock

View File

@ -37,8 +37,6 @@ bool LCK_convert(Jrd::thread_db*, Jrd::Lock*, USHORT, SSHORT);
bool LCK_convert_opt(Jrd::thread_db*, Jrd::Lock*, USHORT);
void LCK_downgrade(Jrd::thread_db*, Jrd::Lock*);
void LCK_fini(Jrd::thread_db*, Jrd::lck_owner_t);
SLONG LCK_get_owner_handle(Jrd::thread_db*, Jrd::lck_t);
SLONG LCK_get_owner_handle_by_type(Jrd::thread_db*, Jrd::lck_owner_t);
void LCK_init(Jrd::thread_db*, Jrd::lck_owner_t);
bool LCK_lock(Jrd::thread_db*, Jrd::Lock*, USHORT, SSHORT);
bool LCK_lock_opt(Jrd::thread_db*, Jrd::Lock*, USHORT, SSHORT);

View File

@ -1139,13 +1139,8 @@ void MET_dsql_cache_release(thread_db* tdbb, int type, const MetaName& name, con
LCK_release(tdbb, item->lock);
// notify others through AST to mark as obsolete
Database* const dbb = tdbb->getDatabase();
const size_t key_length = item->lock->lck_length;
AutoPtr<Lock> temp_lock(FB_NEW_RPT(*tdbb->getDefaultPool(), key_length) Lock());
temp_lock->lck_dbb = dbb;
temp_lock->lck_parent = dbb->dbb_lock;
temp_lock->lck_type = LCK_dsql_cache;
temp_lock->lck_owner_handle = LCK_get_owner_handle(tdbb, temp_lock->lck_type);
AutoPtr<Lock> temp_lock(FB_NEW_RPT(*tdbb->getDefaultPool(), key_length) Lock(tdbb, LCK_dsql_cache));
temp_lock->lck_length = key_length;
memcpy(temp_lock->lck_key.lck_string, item->lock->lck_key.lck_string, key_length);
@ -2873,16 +2868,11 @@ jrd_prc* MET_procedure(thread_db* tdbb, int id, bool noscan, USHORT flags)
if (!procedure->prc_existence_lock)
{
Lock* lock = FB_NEW_RPT(*dbb->dbb_permanent, 0) Lock;
Lock* lock = FB_NEW_RPT(*dbb->dbb_permanent, 0)
Lock(tdbb, LCK_prc_exist, procedure, blocking_ast_procedure);
procedure->prc_existence_lock = lock;
lock->lck_parent = dbb->dbb_lock;
lock->lck_dbb = dbb;
lock->lck_key.lck_long = procedure->getId();
lock->lck_length = sizeof(lock->lck_key.lck_long);
lock->lck_type = LCK_prc_exist;
lock->lck_owner_handle = LCK_get_owner_handle(tdbb, lock->lck_type);
lock->lck_object = procedure;
lock->lck_ast = blocking_ast_procedure;
}
LCK_lock(tdbb, procedure->prc_existence_lock, LCK_SR, LCK_WAIT);
@ -3187,29 +3177,19 @@ jrd_rel* MET_relation(thread_db* tdbb, USHORT id)
relation->rel_id = id;
{ // Scope block.
Lock* lock = FB_NEW_RPT(*pool, 0) Lock;
Lock* lock = FB_NEW_RPT(*pool, 0)
Lock(tdbb, LCK_rel_partners, relation, partners_ast_relation);
relation->rel_partners_lock = lock;
lock->lck_parent = dbb->dbb_lock;
lock->lck_dbb = dbb;
lock->lck_key.lck_long = relation->rel_id;
lock->lck_length = sizeof(lock->lck_key.lck_long);
lock->lck_type = LCK_rel_partners;
lock->lck_owner_handle = LCK_get_owner_handle(tdbb, lock->lck_type);
lock->lck_object = relation;
lock->lck_ast = partners_ast_relation;
}
{ // Scope block.
Lock* lock = FB_NEW_RPT(*pool, 0) Lock;
Lock* lock = FB_NEW_RPT(*pool, 0)
Lock(tdbb, LCK_rel_rescan, relation, rescan_ast_relation);
relation->rel_rescan_lock = lock;
lock->lck_parent = dbb->dbb_lock;
lock->lck_dbb = dbb;
lock->lck_key.lck_long = relation->rel_id;
lock->lck_length = sizeof(lock->lck_key.lck_long);
lock->lck_type = LCK_rel_rescan;
lock->lck_owner_handle = LCK_get_owner_handle(tdbb, lock->lck_type);
lock->lck_object = relation;
lock->lck_ast = rescan_ast_relation;
}
// This should check system flag instead.
@ -3218,16 +3198,11 @@ jrd_rel* MET_relation(thread_db* tdbb, USHORT id)
}
{ // Scope block.
Lock* lock = FB_NEW_RPT(*pool, 0) Lock;
Lock* lock = FB_NEW_RPT(*pool, 0)
Lock(tdbb, LCK_rel_exist, relation, blocking_ast_relation);
relation->rel_existence_lock = lock;
lock->lck_parent = dbb->dbb_lock;
lock->lck_dbb = dbb;
lock->lck_key.lck_long = relation->rel_id;
lock->lck_length = sizeof(lock->lck_key.lck_long);
lock->lck_type = LCK_rel_exist;
lock->lck_owner_handle = LCK_get_owner_handle(tdbb, lock->lck_type);
lock->lck_object = relation;
lock->lck_ast = blocking_ast_relation;
}
relation->rel_flags |= (REL_check_existence | REL_check_partners);
@ -3911,7 +3886,7 @@ static int blocking_ast_dsql_cache(void* ast_object)
try
{
Database* const dbb = item->lock->lck_dbb;
Jrd::Attachment* const att = item->lock->lck_attachment;
Jrd::Attachment* const att = item->lock->getLockAttachment();
AsyncContextHolder tdbb(dbb, att);
@ -3945,14 +3920,9 @@ static DSqlCacheItem* get_dsql_cache_item(thread_db* tdbb, int type, const Quali
{
item->obsolete = false;
item->locked = false;
item->lock = FB_NEW_RPT(*dbb->dbb_permanent, key.length()) Lock();
item->lock = FB_NEW_RPT(*dbb->dbb_permanent, key.length())
Lock(tdbb, LCK_dsql_cache, item, blocking_ast_dsql_cache);
item->lock->lck_type = LCK_dsql_cache;
item->lock->lck_owner_handle = LCK_get_owner_handle(tdbb, item->lock->lck_type);
item->lock->lck_parent = dbb->dbb_lock;
item->lock->lck_dbb = dbb;
item->lock->lck_object = item;
item->lock->lck_ast = blocking_ast_dsql_cache;
item->lock->lck_length = key.length();
memcpy(item->lock->lck_key.lck_string, key.c_str(), key.length());
}
@ -3986,7 +3956,7 @@ static int blocking_ast_procedure(void* ast_object)
try
{
Database* const dbb = procedure->prc_existence_lock->lck_dbb;
Jrd::Attachment* const att = procedure->prc_existence_lock->lck_attachment;
Jrd::Attachment* const att = procedure->prc_existence_lock->getLockAttachment();
AsyncContextHolder tdbb(dbb, att);
@ -4023,7 +3993,7 @@ static int blocking_ast_relation(void* ast_object)
try
{
Database* const dbb = relation->rel_existence_lock->lck_dbb;
Jrd::Attachment* const att = relation->rel_existence_lock->lck_attachment;
Jrd::Attachment* const att = relation->rel_existence_lock->getLockAttachment();
AsyncContextHolder tdbb(dbb, att);
@ -4051,7 +4021,7 @@ static int partners_ast_relation(void* ast_object)
try
{
Database* const dbb = relation->rel_partners_lock->lck_dbb;
Jrd::Attachment* const att = relation->rel_partners_lock->lck_attachment;
Jrd::Attachment* const att = relation->rel_partners_lock->getLockAttachment();
AsyncContextHolder tdbb(dbb, att);
@ -4072,7 +4042,7 @@ static int rescan_ast_relation(void* ast_object)
try
{
Database* const dbb = relation->rel_rescan_lock->lck_dbb;
Jrd::Attachment* const att = relation->rel_rescan_lock->lck_attachment;
Jrd::Attachment* const att = relation->rel_rescan_lock->getLockAttachment();
AsyncContextHolder tdbb(dbb, att);

View File

@ -344,3 +344,4 @@ NAME("MON$USER", nam_mon_user)
NAME("SEC$USERS", nam_sec_users)
NAME("MON$VARIABLE_NAME", nam_mon_var_name)
NAME("MON$VARIABLE_VALUE", nam_mon_var_value)
NAME("MON$CRYPT_PAGE", nam_mon_crypt_page)

View File

@ -45,6 +45,7 @@
#include "../yvalve/gds_proto.h"
#include "../common/os/guid.h"
#include "../common/os/isc_i_proto.h"
#include "../jrd/CryptoManager.h"
#ifdef HAVE_SYS_TYPES_H
#include <sys/types.h>
@ -348,7 +349,7 @@ ULONG BackupManager::getPageCount()
temp_bdb.bdb_buffer = buf;
temp_bdb.bdb_page = pageNum;
ISC_STATUS_ARRAY status;
if (!PIO_read(pageSpace->file, &temp_bdb, temp_bdb.bdb_buffer, status))
if (!CryptoManager::cryptRead(pageSpace->file, &temp_bdb, temp_bdb.bdb_buffer, status))
{
Firebird::status_exception::raise(status);
}
@ -608,7 +609,7 @@ ULONG BackupManager::allocateDifferencePage(thread_db* tdbb, ULONG db_page)
BufferDesc temp_bdb(database->dbb_bcb);
temp_bdb.bdb_page = last_allocated_page + 1;
temp_bdb.bdb_buffer = reinterpret_cast<Ods::pag*>(empty_buffer);
if (!PIO_write(diff_file, &temp_bdb, (Ods::pag*)empty_buffer, status_vector))
if (!PIO_write(diff_file, &temp_bdb, temp_bdb.bdb_buffer, status_vector))
return 0;
const bool alloc_page_full = alloc_buffer[0] == database->dbb_page_size / sizeof(ULONG) - 2;
@ -617,7 +618,7 @@ ULONG BackupManager::allocateDifferencePage(thread_db* tdbb, ULONG db_page)
// Pointer page is full. Its time to create new one.
temp_bdb.bdb_page = last_allocated_page + 2;
temp_bdb.bdb_buffer = reinterpret_cast<Ods::pag*>(empty_buffer);
if (!PIO_write(diff_file, &temp_bdb, (Ods::pag*)empty_buffer, status_vector))
if (!PIO_write(diff_file, &temp_bdb, temp_bdb.bdb_buffer, status_vector))
return 0;
}
@ -673,7 +674,7 @@ bool BackupManager::writeDifference(ISC_STATUS* status, ULONG diff_page, Ods::pa
temp_bdb.bdb_buffer = page;
// Check that diff page is not allocation page
fb_assert(diff_page % (database->dbb_page_size / sizeof(ULONG)));
if (!PIO_write(diff_file, &temp_bdb, page, status))
if (!CryptoManager::cryptWrite(diff_file, &temp_bdb, page, status))
return false;
return true;
}
@ -683,7 +684,7 @@ bool BackupManager::readDifference(thread_db* tdbb, ULONG diff_page, Ods::pag* p
BufferDesc temp_bdb(database->dbb_bcb);
temp_bdb.bdb_page = diff_page;
temp_bdb.bdb_buffer = page;
if (!PIO_read(diff_file, &temp_bdb, page, tdbb->tdbb_status_vector))
if (!CryptoManager::cryptRead(diff_file, &temp_bdb, page, tdbb->tdbb_status_vector))
return false;
NBAK_TRACE(("read_diff page=%d, diff=%d", page->pag_pageno, diff_page));
return true;
@ -769,11 +770,11 @@ bool BackupManager::actualizeState(thread_db* tdbb)
Ods::header_page* header = reinterpret_cast<Ods::header_page*>(spare_buffer);
BufferDesc temp_bdb(database->dbb_bcb);
temp_bdb.bdb_page = HEADER_PAGE_NUMBER;
temp_bdb.bdb_buffer = reinterpret_cast<Ods::pag*>(header);
temp_bdb.bdb_buffer = &header->hdr_header;
PageSpace* pageSpace = database->dbb_page_manager.findPageSpace(DB_PAGE_SPACE);
fb_assert(pageSpace);
jrd_file* file = pageSpace->file;
while (!PIO_read(file, &temp_bdb, temp_bdb.bdb_buffer, status))
while (!CryptoManager::cryptRead(file, &temp_bdb, temp_bdb.bdb_buffer, status))
{
if (!CCH_rollover_to_shadow(tdbb, database, file, false))
{

View File

@ -201,11 +201,22 @@ const USHORT MIN_NEW_PAGE_SIZE = 4096;
namespace Ods {
// Crypt page by type
const bool pag_crypt_page[pag_max + 1] = {false, false, false,
false, false, true, // data
false, true, true, // index, blob
false, false};
// pag_flags for any page type
const UCHAR crypted_page = 0x80; // Page encrypted
// Basic page header
struct pag
{
SCHAR pag_type;
UCHAR pag_type;
UCHAR pag_flags;
USHORT pag_reserved; // not used but anyway present because of alignment rules
ULONG pag_generation;
@ -231,7 +242,7 @@ struct blob_page
#define BLP_SIZE OFFSETA(Ods::blob_page*, blp_page)
// pag_flags
const UCHAR blp_pointers = 1; // Blob pointer page, not data page
const UCHAR blp_pointers = 0x01; // Blob pointer page, not data page
// B-tree page ("bucket")
@ -350,7 +361,10 @@ struct header_page
ULONG hdr_page_buffers; // Page buffers for database cache
TraNumber hdr_oldest_snapshot; // Oldest snapshot of active transactions
SLONG hdr_backup_pages; // The amount of pages in files locked for backup
SLONG hdr_misc[3]; // Stuff to be named later
ULONG hdr_crypt_page; // Page at which processing is in progress
ULONG hdr_top_crypt; // Last page to crypt
TEXT hdr_crypt_plugin[32]; // Name of plugin used to crypt this DB
SLONG hdr_misc[3]; // Stuff to be named later - reserved for minor changes
UCHAR hdr_data[1]; // Misc data
};
@ -374,12 +388,14 @@ const UCHAR HDR_max = 8; // Maximum HDR_clump value
// Header page flags
const USHORT hdr_active_shadow = 0x1; // 1 file is an active shadow file
const USHORT hdr_force_write = 0x2; // 2 database is forced write
// const USHORT hdr_no_checksums = 0x4; // 4 don't calculate checksums, not used since ODS 12
const USHORT hdr_no_reserve = 0x8; // 8 don't reserve space for versions
const USHORT hdr_SQL_dialect_3 = 0x10; // 16 database SQL dialect 3
const USHORT hdr_read_only = 0x20; // 32 Database in ReadOnly. If not set, DB is RW
const USHORT hdr_active_shadow = 0x1; // 1 file is an active shadow file
const USHORT hdr_force_write = 0x2; // 2 database is forced write
// const USHORT hdr_no_checksums = 0x4; // 4 don't calculate checksums, not used since ODS 12
const USHORT hdr_crypt_process = 0x4; // 4 Encryption status is changing now
const USHORT hdr_no_reserve = 0x8; // 8 don't reserve space for versions
const USHORT hdr_SQL_dialect_3 = 0x10; // 16 database SQL dialect 3
const USHORT hdr_read_only = 0x20; // 32 Database is ReadOnly. If not set, DB is RW
const USHORT hdr_encrypted = 0x40; // 64 Database is encrypted
// backup status mask - see bit values in nbak.h
const USHORT hdr_backup_mask = 0xC00;
const USHORT hdr_shutdown_mask = 0x1080;

View File

@ -57,6 +57,7 @@
#include "../jrd/rse.h"
#include "../jrd/ini.h"
#include "../jrd/intl.h"
#include "../jrd/Collation.h"
#include "../common/gdsassert.h"
#include "../jrd/btr_proto.h"
#include "../jrd/cch_proto.h"

View File

@ -64,6 +64,7 @@
#include "../jrd/ods_proto.h"
#include "../jrd/os/pio_proto.h"
#include "../common/classes/init.h"
#include "firebird/Crypt.h"
using namespace Jrd;
using namespace Firebird;
@ -101,12 +102,12 @@ using namespace Firebird;
#define O_BINARY 0
#endif
static const mode_t MASK = 0660;
#define FCNTL_BROKEN
// please undefine FCNTL_BROKEN for operating systems,
// that can successfully change BOTH O_DIRECT and O_SYNC using fcntl()
static const mode_t MASK = 0660;
#define FCNTL_BROKEN
static jrd_file* seek_file(jrd_file*, BufferDesc*, FB_UINT64*, ISC_STATUS*);
static jrd_file* setup_file(Database*, const PathName&, const int, const bool, const bool);
static bool lockDatabaseFile(int desc, const bool shareMode, const bool temporary = false);
@ -122,7 +123,6 @@ static int raw_devices_unlink_database (const PathName&);
static int openFile(const char*, const bool, const bool, const bool);
static void maybeCloseFile(int&);
int PIO_add_file(Database* dbb, jrd_file* main_file, const PathName& file_name, SLONG start)
{
/**************************************
@ -470,8 +470,7 @@ void PIO_header(Database* dbb, SCHAR* address, int length)
**************************************
*
* Functional description
* Read the page header. This assumes that the file has not been
* repositioned since the file was originally mapped.
* Read the page header.
*
**************************************/
int i;
@ -485,22 +484,6 @@ void PIO_header(Database* dbb, SCHAR* address, int length)
for (i = 0; i < IO_RETRY; i++)
{
#ifdef ISC_DATABASE_ENCRYPTION
if (dbb->dbb_encrypt_key)
{
SLONG spare_buffer[MAX_PAGE_SIZE / sizeof(SLONG)];
if ((bytes = pread(file->fil_desc, spare_buffer, length, 0)) == (FB_UINT64) -1)
{
if (SYSCALL_INTERRUPTED(errno))
continue;
unix_error("read", file, isc_io_read_err);
}
(*dbb->dbb_decrypt) (dbb->dbb_encrypt_key->str_data, spare_buffer, length, address);
}
else
#endif // ISC_DATABASE_ENCRYPTION
if ((bytes = pread(file->fil_desc, address, length, 0)) == (FB_UINT64) -1)
{
if (SYSCALL_INTERRUPTED(errno))
@ -706,38 +689,15 @@ bool PIO_read(jrd_file* file, BufferDesc* bdb, Ods::pag* page, ISC_STATUS* statu
const FB_UINT64 size = dbb->dbb_page_size;
#ifdef ISC_DATABASE_ENCRYPTION
if (dbb->dbb_encrypt_key)
for (i = 0; i < IO_RETRY; i++)
{
SLONG spare_buffer[MAX_PAGE_SIZE / sizeof(SLONG)];
for (i = 0; i < IO_RETRY; i++)
{
if (!(file = seek_file(file, bdb, &offset, status_vector)))
return false;
if ((bytes = pread (file->fil_desc, spare_buffer, size, LSEEK_OFFSET_CAST offset)) == size)
{
(*dbb->dbb_decrypt) (dbb->dbb_encrypt_key->str_data, spare_buffer, size, page);
break;
}
if (bytes == -1U && !SYSCALL_INTERRUPTED(errno))
return unix_error("read", file, isc_io_read_err, status_vector);
}
if (!(file = seek_file(file, bdb, &offset, status_vector)))
return false;
if ((bytes = pread(file->fil_desc, page, size, LSEEK_OFFSET_CAST offset)) == size)
break;
if (bytes == -1U && !SYSCALL_INTERRUPTED(errno))
return unix_error("read", file, isc_io_read_err, status_vector);
}
else
#endif // ISC_DATABASE_ENCRYPTION
{
for (i = 0; i < IO_RETRY; i++)
{
if (!(file = seek_file(file, bdb, &offset, status_vector)))
return false;
if ((bytes = pread(file->fil_desc, page, size, LSEEK_OFFSET_CAST offset)) == size)
break;
if (bytes == -1U && !SYSCALL_INTERRUPTED(errno))
return unix_error("read", file, isc_io_read_err, status_vector);
}
}
if (i == IO_RETRY)
{
@ -788,35 +748,14 @@ bool PIO_write(jrd_file* file, BufferDesc* bdb, Ods::pag* page, ISC_STATUS* stat
const SLONG size = dbb->dbb_page_size;
#ifdef ISC_DATABASE_ENCRYPTION
if (dbb->dbb_encrypt_key)
for (i = 0; i < IO_RETRY; i++)
{
SLONG spare_buffer[MAX_PAGE_SIZE / sizeof(SLONG)];
(*dbb->dbb_encrypt) (dbb->dbb_encrypt_key->str_data, page, size, spare_buffer);
for (i = 0; i < IO_RETRY; i++)
{
if (!(file = seek_file(file, bdb, &offset, status_vector)))
return false;
if ((bytes = pwrite(file->fil_desc, spare_buffer, size, LSEEK_OFFSET_CAST offset)) == size)
break;
if (bytes == -1U && !SYSCALL_INTERRUPTED(errno))
return unix_error("write", file, isc_io_write_err, status_vector);
}
}
else
#endif // ISC_DATABASE_ENCRYPTION
{
for (i = 0; i < IO_RETRY; i++)
{
if (!(file = seek_file(file, bdb, &offset, status_vector)))
return false;
if ((bytes = pwrite(file->fil_desc, page, size, LSEEK_OFFSET_CAST offset)) == size)
break;
if (bytes == (SLONG) -1 && !SYSCALL_INTERRUPTED(errno))
return unix_error("write", file, isc_io_write_err, status_vector);
}
if (!(file = seek_file(file, bdb, &offset, status_vector)))
return false;
if ((bytes = pwrite(file->fil_desc, page, size, LSEEK_OFFSET_CAST offset)) == size)
break;
if (bytes == (SLONG) -1 && !SYSCALL_INTERRUPTED(errno))
return unix_error("write", file, isc_io_write_err, status_vector);
}

View File

@ -96,6 +96,7 @@
#include "../jrd/TempSpace.h"
#include "../jrd/extds/ExtDS.h"
#include "../common/classes/DbImplementation.h"
#include "../jrd/CryptoManager.h"
namespace Ods
{
@ -300,7 +301,7 @@ USHORT PAG_add_file(thread_db* tdbb, const TEXT* file_name, SLONG start)
#endif
header->hdr_header.pag_pageno = window.win_page.getPageNum();
PIO_write(pageSpace->file, window.win_bdb, window.win_buffer, tdbb->tdbb_status_vector);
CryptoManager::cryptWrite(pageSpace->file, window.win_bdb, window.win_buffer, tdbb->tdbb_status_vector);
CCH_RELEASE(tdbb, &window);
next->fil_fudge = 1;
@ -330,7 +331,7 @@ USHORT PAG_add_file(thread_db* tdbb, const TEXT* file_name, SLONG start)
}
header->hdr_header.pag_pageno = window.win_page.getPageNum();
PIO_write(pageSpace->file, window.win_bdb, window.win_buffer, tdbb->tdbb_status_vector);
CryptoManager::cryptWrite(pageSpace->file, window.win_bdb, window.win_buffer, tdbb->tdbb_status_vector);
CCH_RELEASE(tdbb, &window);
if (file->fil_min_page)
file->fil_fudge = 1;
@ -761,16 +762,11 @@ SLONG PAG_attachment_id(thread_db* tdbb)
// Take out lock on attachment id
Lock* const lock = FB_NEW_RPT(*attachment->att_pool, sizeof(SLONG)) Lock();
Lock* const lock = FB_NEW_RPT(*attachment->att_pool, sizeof(SLONG))
Lock(tdbb, LCK_attachment, attachment, blocking_ast_attachment);
attachment->att_id_lock = lock;
lock->lck_type = LCK_attachment;
lock->lck_owner_handle = LCK_get_owner_handle(tdbb, lock->lck_type);
lock->lck_parent = dbb->dbb_lock;
lock->lck_length = sizeof(SLONG);
lock->lck_key.lck_long = attachment->att_attachment_id;
lock->lck_dbb = dbb;
lock->lck_ast = blocking_ast_attachment;
lock->lck_object = attachment;
LCK_lock(tdbb, lock, LCK_EX, LCK_WAIT);
return attachment->att_attachment_id;
@ -1316,7 +1312,7 @@ void PAG_init2(thread_db* tdbb, USHORT shadow_number)
temp_bdb.bdb_page = window.win_page;
// Read the required page into the local buffer
PIO_read(file, &temp_bdb, (PAG) header, status);
CryptoManager::cryptRead(file, &temp_bdb, (PAG) header, status);
if (shadow_number && !file->fil_min_page)
CCH_RELEASE(tdbb, &window);
@ -2178,12 +2174,8 @@ USHORT PageManager::getTempPageSpaceID(thread_db* tdbb)
if (!attachment->att_temp_pg_lock)
{
Lock* lock = FB_NEW_RPT(*attachment->att_pool, sizeof(SLONG)) Lock();
lock->lck_type = LCK_page_space;
lock->lck_owner_handle = LCK_get_owner_handle(tdbb, lock->lck_type);
lock->lck_parent = dbb->dbb_lock;
Lock* lock = FB_NEW_RPT(*attachment->att_pool, sizeof(SLONG)) Lock(tdbb, LCK_page_space);
lock->lck_length = sizeof(SLONG);
lock->lck_dbb = dbb;
PAG_attachment_id(tdbb);

View File

@ -29,6 +29,7 @@
#include "../jrd/evl_proto.h"
#include "../jrd/mov_proto.h"
#include "../jrd/intl_proto.h"
#include "../jrd/Collation.h"
#include "RecordSource.h"

View File

@ -478,6 +478,7 @@ RELATION(nam_mon_database, rel_mon_database, ODS_11_1, rel_virtual)
FIELD(f_mon_db_pages, nam_mon_pages, fld_counter, 0, ODS_11_1)
FIELD(f_mon_db_stat_id, nam_mon_stat_id, fld_stat_id, 0, ODS_11_1)
FIELD(f_mon_db_backup_state, nam_mon_backup_state, fld_backup_state, 0, ODS_11_1)
FIELD(f_mon_db_crypt_page, nam_mon_crypt_page, fld_counter, 0, ODS_12_0)
END_RELATION
// Relation 34 (MON$ATTACHMENTS)

View File

@ -134,16 +134,11 @@ Lock* RLCK_transaction_relation_lock(thread_db* tdbb, jrd_tra* transaction, jrd_
relation->rel_id + 1);
const SSHORT relLockLen = relation->getRelLockKeyLength();
lock = FB_NEW_RPT(*transaction->tra_pool, relLockLen) Lock();
lock->lck_dbb = tdbb->getDatabase();
lock->lck_length = relLockLen;
relation->getRelLockKey(tdbb, &lock->lck_key.lck_string[0]);
lock->lck_type = LCK_relation;
lock->lck_owner_handle = LCK_get_owner_handle(tdbb, lock->lck_type);
lock->lck_parent = tdbb->getDatabase()->dbb_lock;
// the lck_object is used here to find the relation
// block from the lock block
lock->lck_object = relation;
lock = FB_NEW_RPT(*transaction->tra_pool, relLockLen) Lock(tdbb, LCK_relation, relation);
lock->lck_length = relLockLen;
relation->getRelLockKey(tdbb, &lock->lck_key.lck_string[0]);
// enter all relation locks into the intra-process lock manager and treat
// them as compatible within the attachment according to IPLM rules
lock->lck_compatible = tdbb->getAttachment();

View File

@ -48,7 +48,7 @@
#include "../jrd/os/pio_proto.h"
#include "../jrd/sdw_proto.h"
#include "../jrd/Attachment.h"
#include "../jrd/CryptoManager.h"
using namespace Jrd;
using namespace Ods;
@ -209,7 +209,7 @@ int SDW_add_file(thread_db* tdbb, const TEXT* file_name, SLONG start, USHORT sha
temp_bdb.bdb_page = next->fil_min_page;
temp_bdb.bdb_buffer = (PAG) header;
header->hdr_header.pag_pageno = temp_bdb.bdb_page.getPageNum();
if (!PIO_write(shadow_file, &temp_bdb, reinterpret_cast<Ods::pag*>(header), 0))
if (!CryptoManager::cryptWrite(shadow_file, &temp_bdb, reinterpret_cast<Ods::pag*>(header), 0))
{
delete[] spare_buffer;
return 0;
@ -255,7 +255,7 @@ int SDW_add_file(thread_db* tdbb, const TEXT* file_name, SLONG start, USHORT sha
file->fil_fudge = 0;
temp_bdb.bdb_page = file->fil_min_page;
header->hdr_header.pag_pageno = temp_bdb.bdb_page.getPageNum();
if (!PIO_write( shadow_file, &temp_bdb, reinterpret_cast<Ods::pag*>(header), 0))
if (!CryptoManager::cryptWrite( shadow_file, &temp_bdb, reinterpret_cast<Ods::pag*>(header), 0))
{
delete[] spare_buffer;
return 0;
@ -328,14 +328,10 @@ void SDW_check(thread_db* tdbb)
{
if (SDW_lck_update(tdbb, 0))
{
Lock temp_lock;
Lock temp_lock(tdbb, LCK_update_shadow);
Lock* lock = &temp_lock;
lock->lck_dbb = dbb;
lock->lck_length = sizeof(SLONG);
lock->lck_key.lck_long = -1;
lock->lck_type = LCK_update_shadow;
lock->lck_owner_handle = LCK_get_owner_handle(tdbb, lock->lck_type);
lock->lck_parent = dbb->dbb_lock;
LCK_lock(tdbb, lock, LCK_EX, LCK_NO_WAIT);
if (lock->lck_physical == LCK_EX)
@ -591,15 +587,10 @@ void SDW_init(thread_db* tdbb, bool activate, bool delete_files)
header_page* header; // for sizeof here, used later
const USHORT key_length = sizeof(header->hdr_shadow_count);
Lock* lock = FB_NEW_RPT(*dbb->dbb_permanent, key_length) Lock();
Lock* lock = FB_NEW_RPT(*dbb->dbb_permanent, key_length)
Lock(tdbb, LCK_shadow, dbb, blocking_ast_shadowing);
dbb->dbb_shadow_lock = lock;
lock->lck_type = LCK_shadow;
lock->lck_owner_handle = LCK_get_owner_handle(tdbb, lock->lck_type);
lock->lck_parent = dbb->dbb_lock;
lock->lck_length = key_length;
lock->lck_dbb = dbb;
lock->lck_object = dbb;
lock->lck_ast = blocking_ast_shadowing;
if (activate)
activate_shadow(tdbb);
@ -748,14 +739,10 @@ bool SDW_rollover_to_shadow(thread_db* tdbb, jrd_file* file, const bool inAst)
SyncLockGuard guard(&dbb->dbb_shadow_sync, SYNC_EXCLUSIVE, "SDW_rollover_to_shadow");
Lock temp_lock;
Lock temp_lock(tdbb, LCK_update_shadow);
Lock* update_lock = &temp_lock;
update_lock->lck_dbb = dbb;
update_lock->lck_length = sizeof(SLONG);
update_lock->lck_key.lck_long = -1;
update_lock->lck_type = LCK_update_shadow;
update_lock->lck_owner_handle = LCK_get_owner_handle(tdbb, update_lock->lck_type);
update_lock->lck_parent = dbb->dbb_lock;
SLONG sdw_update_flags = SDW_rollover;
@ -1014,7 +1001,7 @@ void SDW_start(thread_db* tdbb, const TEXT* file_name,
(header_page*) CCH_FETCH(tdbb, &window, LCK_read, pag_header);
header_fetched++;
if (!PIO_read(shadow_file, window.win_bdb, (PAG) spare_page, tdbb->tdbb_status_vector))
if (!CryptoManager::cryptRead(shadow_file, window.win_bdb, (PAG) spare_page, tdbb->tdbb_status_vector))
{
ERR_punt();
}

View File

@ -63,7 +63,7 @@
#include "../common/classes/DbImplementation.h"
// Services table. Empty at BootBuild.
// Services table.
#include "../jrd/svc_tab.h"
// The switches tables. Needed only for utilities that run as service, too.
@ -643,6 +643,14 @@ void Service::fillDpb(ClumpletWriter& dpb)
{
dpb.insertTag(isc_dpb_utf8_filename);
}
if (svc_crypt_callback)
{
// That's not DPB-related, but anyway should be done before attach/create DB
if (fb_database_crypt_callback(svc_status, svc_crypt_callback) != 0)
{
status_exception::raise(svc_status);
}
}
}
void Service::need_admin_privs(Arg::StatusVector& status, const char* message)
@ -686,7 +694,8 @@ namespace
}
}
Service::Service(const TEXT* service_name, USHORT spb_length, const UCHAR* spb_data)
Service::Service(const TEXT* service_name, USHORT spb_length, const UCHAR* spb_data,
Firebird::ICryptKeyCallback* crypt_callback)
: svc_parsed_sw(getPool()),
svc_stdout_head(0), svc_stdout_tail(0), svc_service(NULL), svc_service_run(NULL),
svc_resp_alloc(getPool()), svc_resp_buf(0), svc_resp_ptr(0), svc_resp_buf_len(0),
@ -696,9 +705,9 @@ Service::Service(const TEXT* service_name, USHORT spb_length, const UCHAR* spb_d
svc_switches(getPool()), svc_perm_sw(getPool()), svc_address_path(getPool()),
svc_command_line(getPool()),
svc_network_protocol(getPool()), svc_remote_address(getPool()), svc_remote_process(getPool()),
svc_remote_pid(0), svc_current_guard(NULL)
svc_remote_pid(0), svc_trace_manager(NULL), svc_crypt_callback(crypt_callback),
svc_current_guard(NULL)
{
svc_trace_manager = NULL;
initStatus();
ThreadIdHolder holdId(svc_thread_strings);

View File

@ -49,6 +49,7 @@ namespace Firebird {
namespace Arg {
class StatusVector;
}
class ICryptKeyCallback;
}
namespace Jrd {
@ -151,7 +152,8 @@ public: // utilities interface with service
public: // external interface with service
// Attach - service ctor
Service(const TEXT* service_name, USHORT spb_length, const UCHAR* spb_data);
Service(const TEXT* service_name, USHORT spb_length, const UCHAR* spb_data,
Firebird::ICryptKeyCallback* crypt_callback);
// Start service thread
void start(USHORT spb_length, const UCHAR* spb_data);
// Query service state (v. 1 & 2)
@ -285,6 +287,7 @@ private:
SLONG svc_remote_pid;
TraceManager* svc_trace_manager;
Firebird::ICryptKeyCallback* svc_crypt_callback;
public:
struct StatusStringsHelper

View File

@ -210,6 +210,8 @@ int TipCache::snapshotState(thread_db* tdbb, TraNumber number)
*
**************************************/
fb_assert(m_dbb == tdbb->getDatabase());
if (number && m_dbb->dbb_pc_transactions)
{
if (TRA_precommited(tdbb, number, number))
@ -259,11 +261,7 @@ int TipCache::snapshotState(thread_db* tdbb, TraNumber number)
// see if we can get a lock on the transaction; if we can't
// then we know it is still active
Lock temp_lock;
temp_lock.lck_dbb = m_dbb;
temp_lock.lck_type = LCK_tra;
temp_lock.lck_owner_handle = LCK_get_owner_handle(tdbb, temp_lock.lck_type);
temp_lock.lck_parent = m_dbb->dbb_lock;
Lock temp_lock(tdbb, LCK_tra);
temp_lock.lck_length = sizeof(SLONG);
temp_lock.lck_key.lck_long = number;

View File

@ -72,6 +72,7 @@
#include "../jrd/trace/TraceManager.h"
#include "../jrd/trace/TraceJrdHelpers.h"
#include "../jrd/Function.h"
#include "../jrd/Collation.h"
const int DYN_MSG_FAC = 8;
@ -1621,12 +1622,7 @@ bool TRA_sweep(thread_db* tdbb, jrd_tra* trans)
// fill out a lock block, zeroing it out first
Lock temp_lock;
temp_lock.lck_dbb = dbb;
temp_lock.lck_object = trans;
temp_lock.lck_type = LCK_sweep;
temp_lock.lck_owner_handle = LCK_get_owner_handle(tdbb, temp_lock.lck_type);
temp_lock.lck_parent = dbb->dbb_lock;
Lock temp_lock(tdbb, LCK_sweep, trans);
temp_lock.lck_length = sizeof(SLONG);
if (!LCK_lock(tdbb, &temp_lock, LCK_EX, LCK_NO_WAIT))
@ -1784,11 +1780,7 @@ int TRA_wait(thread_db* tdbb, jrd_tra* trans, TraNumber number, jrd_tra::wait_t
if (wait != jrd_tra::tra_no_wait)
{
Lock temp_lock;
temp_lock.lck_dbb = dbb;
temp_lock.lck_type = LCK_tra;
temp_lock.lck_owner_handle = LCK_get_owner_handle(tdbb, temp_lock.lck_type);
temp_lock.lck_parent = dbb->dbb_lock;
Lock temp_lock(tdbb, LCK_tra);
temp_lock.lck_length = sizeof(SLONG);
temp_lock.lck_key.lck_long = number;
@ -1856,7 +1848,7 @@ static int blocking_ast_transaction(void* ast_object)
try
{
Database* const dbb = transaction->tra_cancel_lock->lck_dbb;
Jrd::Attachment* const att = transaction->tra_cancel_lock->lck_attachment;
Jrd::Attachment* const att = transaction->tra_cancel_lock->getLockAttachment();
AsyncContextHolder tdbb(dbb, att);
@ -1994,17 +1986,10 @@ static Lock* create_transaction_lock(thread_db* tdbb, void* object)
*
**************************************/
SET_TDBB(tdbb);
Database* dbb = tdbb->getDatabase();
Lock* lock = FB_NEW_RPT(*tdbb->getDefaultPool(), sizeof(SLONG)) Lock();
lock->lck_type = LCK_tra;
lock->lck_owner_handle = LCK_get_owner_handle(tdbb, lock->lck_type);
Lock* lock = FB_NEW_RPT(*tdbb->getDefaultPool(), sizeof(SLONG)) Lock(tdbb, LCK_tra, object);
lock->lck_length = sizeof(SLONG);
lock->lck_dbb = dbb;
lock->lck_parent = dbb->dbb_lock;
lock->lck_object = object;
return lock;
}
@ -2503,12 +2488,8 @@ static void start_sweeper(thread_db* tdbb, Database* dbb)
SET_TDBB(tdbb);
// fill out the lock block
Lock temp_lock;
temp_lock.lck_dbb = dbb;
temp_lock.lck_type = LCK_sweep;
temp_lock.lck_owner_handle = LCK_get_owner_handle(tdbb, temp_lock.lck_type);
temp_lock.lck_parent = dbb->dbb_lock;
temp_lock.lck_length = sizeof(SLONG);
Lock temp_lock(tdbb, LCK_sweep);
temp_lock.lck_length = sizeof(SLONG);
if (!LCK_lock(tdbb, &temp_lock, LCK_EX, LCK_NO_WAIT))
{
@ -3165,12 +3146,7 @@ static jrd_tra* transaction_start(thread_db* tdbb, jrd_tra* temp)
// more complicated by the fact that existing transaction may have oldest
// actives older than they are.
Lock temp_lock;
temp_lock.lck_dbb = dbb;
temp_lock.lck_object = trans;
temp_lock.lck_type = LCK_tra;
temp_lock.lck_owner_handle = LCK_get_owner_handle(tdbb, temp_lock.lck_type);
temp_lock.lck_parent = dbb->dbb_lock;
Lock temp_lock(tdbb, LCK_tra, trans);
temp_lock.lck_length = sizeof(SLONG);
trans->tra_oldest_active = number;
@ -3304,6 +3280,7 @@ static jrd_tra* transaction_start(thread_db* tdbb, jrd_tra* temp)
if (dbb->dbb_sweep_interval &&
!(tdbb->getAttachment()->att_flags & ATT_no_cleanup) &&
(trans->tra_oldest_active > trans->tra_oldest) &&
(trans->tra_oldest_active - trans->tra_oldest > dbb->dbb_sweep_interval) &&
oldest_state != tra_limbo)
{
@ -3324,16 +3301,11 @@ static jrd_tra* transaction_start(thread_db* tdbb, jrd_tra* temp)
// Allocate the cancellation lock
lock = FB_NEW_RPT(*trans->tra_pool, sizeof(SLONG)) Lock();
lock = FB_NEW_RPT(*trans->tra_pool, sizeof(SLONG))
Lock(tdbb, LCK_cancel, trans, blocking_ast_transaction);
trans->tra_cancel_lock = lock;
lock->lck_type = LCK_cancel;
lock->lck_owner_handle = LCK_get_owner_handle(tdbb, lock->lck_type);
lock->lck_parent = dbb->dbb_lock;
lock->lck_length = sizeof(SLONG);
lock->lck_key.lck_long = trans->tra_number;
lock->lck_dbb = dbb;
lock->lck_ast = blocking_ast_transaction;
lock->lck_object = trans;
// if the user asked us to restart all requests in this attachment,
// do so now using the new transaction

View File

@ -486,7 +486,8 @@ enum dfw_t {
dfw_arg_rel_name, // relation name of a trigger
dfw_arg_trg_type, // trigger type
dfw_arg_new_name, // new name
dfw_arg_field_not_null // set domain to not nullable
dfw_arg_field_not_null, // set domain to not nullable
dfw_db_crypt // change database encryption status
};
// Verb actions

View File

@ -34,7 +34,7 @@
#include "../common/classes/MetaName.h"
#include "../common/classes/QualifiedName.h"
#include "../jrd/blb.h"
#include "../jrd/RecordNumber.h"
#include "../common/dsc.h"
#include "../jrd/ExtEngineManager.h"

View File

@ -15,7 +15,7 @@ set bulk_insert INSERT INTO FACILITIES (LAST_CHANGE, FACILITY, FAC_CODE, MAX_NUM
('2006-09-10 03:04:31', 'JRD_BUGCHK', 15, 307)
('2009-12-21 04:00:05', 'ISQL', 17, 173)
('2010-07-10 10:50:30', 'GSEC', 18, 105)
('2009-12-26 14:22:00', 'GSTAT', 21, 50)
('2012-05-25 19:59:42', 'GSTAT', 21, 56)
('2009-12-18 19:33:34', 'FBSVCMGR', 22, 57)
('2009-07-18 12:12:12', 'UTL', 23, 2)
('2011-05-25 16:17:34', 'NBACKUP', 24, 74)

View File

@ -3048,6 +3048,12 @@ Analyzing database pages ...', NULL, NULL);
(NULL, 'main', 'dba.epp', NULL, 21, 47, NULL, ' Big record pages: @1', NULL, NULL);
(NULL, 'main', 'dba.epp', NULL, 21, 48, NULL, ' Blobs: @1, total length: @2, blob pages: @3', NULL, NULL);
(NULL, 'main', 'dba.epp', NULL, 21, 49, NULL, ' Level 0: @1, Level 1: @2, Level 2: @3', NULL, NULL);
(NULL, 'main', 'dba.epp', NULL, 21, 50, NULL, 'option -e is incompatible with options -a, -d, -h, -i, -r, -s and -t', NULL, NULL)
(NULL, 'dba_in_sw_table', 'dbaswi.h', NULL, 21, 51, NULL, ' -e analyze database encryption', NULL, NULL);
(NULL, 'main', 'dba.epp', NULL, 21, 52, NULL, 'Data pages: total @1, encrypted @2, non-crypted @3', NULL, NULL)
(NULL, 'main', 'dba.epp', NULL, 21, 53, NULL, 'Index pages: total @1, encrypted @2, non-crypted @3', NULL, NULL)
(NULL, 'main', 'dba.epp', NULL, 21, 54, NULL, 'Blob pages: total @1, encrypted @2, non-crypted @3', NULL, NULL)
(NULL, 'main', 'dba.epp', NULL, 21, 55, NULL, 'no encrypted database support, only -e and -h can be used', NULL, NULL)
-- FBSVCMGR
-- All messages use the new format.
('fbsvcmgr_bad_am', 'putAccessMode', 'fbsvcmgr.cpp', NULL, 22, 1, NULL, 'Wrong value for access mode', NULL, NULL);

View File

@ -34,20 +34,17 @@ using namespace Firebird;
namespace
{
class Cypher : public RefCntIface<ICrypt, FB_CRYPT_VERSION>
class Cypher : public GlobalStorage
{
public:
Cypher()
Cypher(unsigned int l, const unsigned char* key) throw()
: s1(0), s2(0)
{
for (unsigned int n = 0; n < sizeof(state); ++n)
{
state[n] = n;
}
}
void setKey(unsigned int l, const unsigned char* key)
{
for (unsigned int k1 = 0, k2 = 0; k1 < sizeof(state); ++k1)
{
k2 = (k2 + key[k1 % l] + state[k1]) & 0xff;
@ -55,11 +52,8 @@ public:
}
}
// ICrypt implementation
void FB_CARG transform(IStatus* status, unsigned int length, const void* from, void* to)
void transform(unsigned int length, const void* from, void* to) throw()
{
status->init();
unsigned char* t = static_cast<unsigned char*>(to);
const unsigned char* f = static_cast<const unsigned char*>(from);
@ -73,22 +67,12 @@ public:
}
}
int FB_CARG release()
{
if (--refCounter == 0)
{
delete this;
return 0;
}
return 1;
}
private:
unsigned char state[256];
unsigned char s1;
unsigned char s2;
void swap(unsigned char& c1, unsigned char& c2)
void swap(unsigned char& c1, unsigned char& c2) throw()
{
unsigned char temp = c1;
c1 = c2;
@ -101,20 +85,24 @@ private:
namespace Crypt {
class Arc4 : public StdPlugin<ICryptPlugin, FB_CRYPT_PLUGIN_VERSION>
class Arc4 : public StdPlugin<IWireCryptPlugin, FB_WIRECRYPT_PLUGIN_VERSION>
{
public:
explicit Arc4(IPluginConfig*)
: en(NULL), de(NULL)
{ }
// ICryptPlugin implementation
const char* FB_CARG getKnownTypes(IStatus* status);
ICrypt* FB_CARG getEncrypt(IStatus* status, FbCryptKey* key);
ICrypt* FB_CARG getDecrypt(IStatus* status, FbCryptKey* key);
void FB_CARG setKey(IStatus* status, FbCryptKey* key);
void FB_CARG encrypt(IStatus* status, unsigned int length, const void* from, void* to);
void FB_CARG decrypt(IStatus* status, unsigned int length, const void* from, void* to);
int FB_CARG release();
private:
ICrypt* createCypher(IStatus* status, unsigned int l, const void* key);
Cypher* createCypher(unsigned int l, const void* key);
Cypher* en;
Cypher* de;
};
int Arc4::release()
@ -127,37 +115,44 @@ int Arc4::release()
return 1;
}
ICrypt* Arc4::getEncrypt(IStatus* status, FbCryptKey* key)
{
return createCypher(status, key->encryptLength, key->encryptKey);
}
ICrypt* Arc4::getDecrypt(IStatus* status, FbCryptKey* key)
{
const void* k = key->decryptKey;
unsigned int l = key->decryptLength;
if (!k)
{
k = key->encryptKey;
l = key->encryptLength;
}
return createCypher(status, l, k);
}
ICrypt* Arc4::createCypher(IStatus* status, unsigned int l, const void* key)
void Arc4::setKey(IStatus* status, FbCryptKey* key)
{
status->init();
try
{
Cypher* rc = new Cypher;
rc->setKey(l, static_cast<const unsigned char*>(key));
return rc;
en = createCypher(key->encryptLength, key->encryptKey);
const void* k = key->decryptKey;
unsigned int l = key->decryptLength;
if (!k)
{
k = key->encryptKey;
l = key->encryptLength;
}
de = createCypher(l, k);
}
catch (const Exception& ex)
catch(const Exception& ex)
{
ex.stuffException(status);
}
return NULL;
}
void Arc4::encrypt(IStatus* status, unsigned int length, const void* from, void* to)
{
status->init();
en->transform(length, from, to);
}
void Arc4::decrypt(IStatus* status, unsigned int length, const void* from, void* to)
{
status->init();
de->transform(length, from, to);
}
Cypher* Arc4::createCypher(unsigned int l, const void* key)
{
return new Cypher(l, static_cast<const unsigned char*>(key));
}
const char* Arc4::getKnownTypes(IStatus* status)
@ -174,7 +169,7 @@ namespace
void registerArc4(IPluginManager* iPlugin)
{
iPlugin->registerPluginFactory(PluginType::Crypt, "Arc4", &factory);
iPlugin->registerPluginFactory(PluginType::WireCrypt, "Arc4", &factory);
}
} // namespace Crypt

View File

@ -61,6 +61,7 @@
#include "../common/Auth.h"
#include "../common/classes/GetPlugins.h"
#include "firebird/Provider.h"
#include "firebird/Crypt.h"
#include "../common/StatementMetadata.h"
#include "../common/IntlParametersBlock.h"
@ -464,17 +465,18 @@ class Provider : public Firebird::StdPlugin<Firebird::IProvider, FB_PROVIDER_VER
{
public:
explicit Provider(IPluginConfig*)
{
}
: cryptCallback(NULL)
{ }
// IProvider implementation
virtual IAttachment* FB_CARG attachDatabase(IStatus* status, const char* fileName,
unsigned int dpbLength, const unsigned char* dpb);
virtual IAttachment* FB_CARG createDatabase(IStatus* status, const char* fileName,
unsigned int dpbLength, const unsigned char* dpb);
virtual Firebird::IService* FB_CARG attachServiceManager(IStatus* status, const char* service,
unsigned int spbLength, const unsigned char* spb);
virtual IService* FB_CARG attachServiceManager(IStatus* status, const char* service,
unsigned int spbLength, const unsigned char* spb);
virtual void FB_CARG shutdown(IStatus* status, unsigned int timeout, const int reason);
virtual void FB_CARG setDbCryptCallback(IStatus* status, ICryptKeyCallback* cryptCallback);
virtual int FB_CARG release()
{
@ -488,16 +490,27 @@ public:
}
protected:
Firebird::IAttachment* attach(IStatus* status, const char* filename,
unsigned int dpb_length, const unsigned char* dpb, bool loopback);
Firebird::IAttachment* create(IStatus* status, const char* filename,
unsigned int dpb_length, const unsigned char* dpb, bool loopback);
Firebird::IService* attachSvc(IStatus* status, const char* service,
unsigned int spbLength, const unsigned char* spb, bool loopback);
IAttachment* attach(IStatus* status, const char* filename, unsigned int dpb_length,
const unsigned char* dpb, bool loopback);
IAttachment* create(IStatus* status, const char* filename, unsigned int dpb_length,
const unsigned char* dpb, bool loopback);
IService* attachSvc(IStatus* status, const char* service, unsigned int spbLength,
const unsigned char* spb, bool loopback);
private:
Firebird::ICryptKeyCallback* cryptCallback;
};
void Provider::shutdown(IStatus* /*status*/, unsigned int /*timeout*/, const int /*reason*/)
{ }
void Provider::shutdown(IStatus* status, unsigned int /*timeout*/, const int /*reason*/)
{
status->init();
}
void Provider::setDbCryptCallback(IStatus* status, ICryptKeyCallback* callback)
{
status->init();
cryptCallback = callback;
}
class Loopback : public Provider
{
@ -513,7 +526,7 @@ public:
virtual IAttachment* FB_CARG createDatabase(IStatus* status, const char* fileName,
unsigned int dpbLength, const unsigned char* dpb);
virtual Firebird::IService* FB_CARG attachServiceManager(IStatus* status, const char* service,
unsigned int spbLength, const unsigned char* spb);
unsigned int spbLength, const unsigned char* spb);
};
namespace {
@ -568,7 +581,7 @@ static void handle_error(ISC_STATUS);
static void info(IStatus*, Rdb*, P_OP, USHORT, USHORT, USHORT,
const UCHAR*, USHORT, const UCHAR*, ULONG, UCHAR*, ClntAuthBlock* cBlock = NULL);
static void init(IStatus*, ClntAuthBlock&, rem_port*, P_OP, PathName&,
ClumpletWriter&, IntlParametersBlock&);
ClumpletWriter&, IntlParametersBlock&, ICryptKeyCallback* cryptCallback);
static Rtr* make_transaction(Rdb*, USHORT);
static void mov_dsql_message(const UCHAR*, const rem_fmt*, UCHAR*, const rem_fmt*);
static void move_error(const Arg::StatusVector& v);
@ -636,8 +649,8 @@ inline static void defer_packet(rem_port* port, PACKET* packet, bool sent = fals
port->port_deferred_packets->add(p);
}
Firebird::IAttachment* Provider::attach(IStatus* status, const char* filename,
unsigned int dpb_length, const unsigned char* dpb, bool loopback)
IAttachment* Provider::attach(IStatus* status, const char* filename, unsigned int dpb_length,
const unsigned char* dpb, bool loopback)
{
/**************************************
*
@ -679,7 +692,7 @@ Firebird::IAttachment* Provider::attach(IStatus* status, const char* filename,
add_working_directory(newDpb, node_name);
IntlDpb intl;
init(status, cBlock, port, op_attach, expanded_name, newDpb, intl);
init(status, cBlock, port, op_attach, expanded_name, newDpb, intl, cryptCallback);
Attachment* a = new Attachment(port->port_context, filename);
a->addRef();
@ -1159,7 +1172,7 @@ IBlob* Attachment::createBlob(IStatus* status, ITransaction* apiTra, ISC_QUAD* b
Firebird::IAttachment* Provider::create(IStatus* status, const char* filename,
unsigned int dpb_length, const unsigned char* dpb, bool loopback)
unsigned int dpb_length, const unsigned char* dpb, bool loopback)
{
/**************************************
*
@ -1203,7 +1216,7 @@ Firebird::IAttachment* Provider::create(IStatus* status, const char* filename,
add_working_directory(newDpb, node_name);
IntlDpb intl;
init(status, cBlock, port, op_create, expanded_name, newDpb, intl);
init(status, cBlock, port, op_create, expanded_name, newDpb, intl, cryptCallback);
Firebird::IAttachment* a = new Attachment(rdb, filename);
a->addRef();
@ -1283,7 +1296,8 @@ void Attachment::getInfo(IStatus* status,
item_length, items, 0, 0, buffer_length, temp_buffer);
string version;
version.printf("%s/%s", GDS_VERSION, port->port_version->str_data);
version.printf("%s/%s%s", GDS_VERSION, port->port_version->str_data,
port->port_crypt_complete ? ":C" : "");
MERGE_database_info(temp_buffer, buffer, buffer_length,
DbImplementation::current.backwardCompatibleImplementation(), 3, 1,
@ -3818,7 +3832,7 @@ void Request::send(IStatus* status, int level, unsigned int msg_type,
Firebird::IService* Provider::attachSvc(IStatus* status, const char* service,
unsigned int spbLength, const unsigned char* spb, bool loopback)
unsigned int spbLength, const unsigned char* spb, bool loopback)
{
/**************************************
*
@ -3853,7 +3867,7 @@ Firebird::IService* Provider::attachSvc(IStatus* status, const char* service,
ClntAuthBlock cBlock(NULL);
cBlock.load(newSpb, &spbParam);
IntlSpb intl;
init(status, cBlock, port, op_service_attach, expanded_name, newSpb, intl);
init(status, cBlock, port, op_service_attach, expanded_name, newSpb, intl, cryptCallback);
cBlock.saveServiceDataTo(port);
@ -3870,7 +3884,7 @@ Firebird::IService* Provider::attachSvc(IStatus* status, const char* service,
Firebird::IService* Provider::attachServiceManager(IStatus* status, const char* service,
unsigned int spbLength, const unsigned char* spb)
unsigned int spbLength, const unsigned char* spb)
{
/**************************************
*
@ -3888,7 +3902,7 @@ Firebird::IService* Provider::attachServiceManager(IStatus* status, const char*
Firebird::IService* Loopback::attachServiceManager(IStatus* status, const char* service,
unsigned int spbLength, const unsigned char* spb)
unsigned int spbLength, const unsigned char* spb)
{
/**************************************
*
@ -5627,7 +5641,7 @@ static void authReceiveResponse(ClntAuthBlock& cBlock, rem_port* port, Rdb* rdb,
}
static void init(IStatus* status, ClntAuthBlock& cBlock, rem_port* port, P_OP op, PathName& file_name,
ClumpletWriter& dpb, IntlParametersBlock& intlParametersBlock)
ClumpletWriter& dpb, IntlParametersBlock& intlParametersBlock, ICryptKeyCallback* cryptCallback)
{
/**************************************
*
@ -5662,6 +5676,8 @@ static void init(IStatus* status, ClntAuthBlock& cBlock, rem_port* port, P_OP op
HANDSHAKE_DEBUG(fprintf(stderr, "init calls authFillParametersBlock\n"));
authFillParametersBlock(cBlock, dpb, ps, port);
port->port_client_crypt_callback = cryptCallback;
// Make attach packet
P_ATCH* attach = &packet->p_atch;
packet->p_operation = op;
@ -5877,6 +5893,63 @@ static void receive_packet(rem_port* port, PACKET* packet)
}
static void receive_packet_with_callback(rem_port* port, PACKET* packet)
{
/**************************************
*
* r e c e i v e _ p a c k e t _ w i t h _ c a l l b a c k
*
**************************************
*
* Functional description
* If received packet is request fro callback info from user,
* send requested info (or no data if callback not set) and
* wait for next packet.
*
**************************************/
for (;;)
{
if (!port->receive(packet))
{
Arg::Gds(isc_net_read_err).raise();
}
switch (packet->p_operation)
{
case op_crypt_key_callback:
{
P_CRYPT_CALLBACK* cc = &packet->p_cc;
UCharBuffer buf;
if (port->port_client_crypt_callback)
{
if (cc->p_cc_reply <= 0)
{
cc->p_cc_reply = 1;
}
UCHAR* reply = buf.getBuffer(cc->p_cc_reply);
unsigned l = port->port_client_crypt_callback->callback(cc->p_cc_data.cstr_length,
cc->p_cc_data.cstr_address, cc->p_cc_reply, reply);
cc->p_cc_data.cstr_length = l;
cc->p_cc_data.cstr_address = reply;
}
else
{
cc->p_cc_data.cstr_length = 0;
}
cc->p_cc_data.cstr_allocated = 0;
port->send(packet);
}
break;
default:
return;
}
}
}
static void receive_packet_noqueue(rem_port* port, PACKET* packet)
{
/**************************************
@ -5899,10 +5972,6 @@ static void receive_packet_noqueue(rem_port* port, PACKET* packet)
*
* See also cousin routine: send_packet, send_partial_packet
*
* Return codes:
* true - no errors.
* false - Network error occurred, error code in status
*
**************************************/
// Receive responses for all deferred packets that were already sent
@ -5928,10 +5997,7 @@ static void receive_packet_noqueue(rem_port* port, PACKET* packet)
bFreeStmt = (p->packet.p_sqlfree.p_sqlfree_option == DSQL_drop);
}
if (!port->receive(&p->packet))
{
Arg::Gds(isc_net_read_err).raise();
}
receive_packet_with_callback(port, &p->packet);
Rsr* statement = NULL;
if (bCheckResponse || bFreeStmt)
@ -5974,10 +6040,7 @@ static void receive_packet_noqueue(rem_port* port, PACKET* packet)
port->port_deferred_packets->remove(p);
}
if (!port->receive(packet))
{
Arg::Gds(isc_net_read_err).raise();
}
receive_packet_with_callback(port, packet);
}
@ -5992,9 +6055,6 @@ static void receive_queued_packet(rem_port* port, USHORT id)
* Functional description
* We're marked as having pending receives on the
* wire. Grab the first pending receive and return.
* Return codes:
* true - no errors.
* false - Network error occurred, error code in status
*
**************************************/
// Trivial case, nothing pending on the wire

View File

@ -2953,9 +2953,9 @@ static bool packet_receive(rem_port* port, UCHAR* buffer, SSHORT buffer_length,
n = recv(port->port_handle, reinterpret_cast<char*>(buffer), buffer_length, 0);
inetErrNo = INET_ERRNO;
if (n > 0 && port->port_recv_cipher)
if (n > 0 && port->port_crypt_plugin)
{
port->port_recv_cipher->transform(&st, n, buffer, buffer);
port->port_crypt_plugin->decrypt(&st, n, buffer, buffer);
if (!st.isSuccess())
{
status_exception::raise(st.get());
@ -3030,12 +3030,12 @@ static bool packet_send( rem_port* port, const SCHAR* buffer, SSHORT buffer_leng
// encrypt
HalfStaticArray<char, BUFFER_TINY> b;
if (port->port_send_cipher)
if (port->port_crypt_plugin && port->port_crypt_complete)
{
LocalStatus st;
char* d = b.getBuffer(buffer_length);
port->port_send_cipher->transform(&st, buffer_length, data, d);
port->port_crypt_plugin->encrypt(&st, buffer_length, data, d);
if (!st.isSuccess())
{
status_exception::raise(st.get());

View File

@ -774,6 +774,15 @@ bool_t xdr_protocol(XDR* xdrs, PACKET* p)
return P_TRUE(xdrs, p);
}
case op_crypt_key_callback:
{
P_CRYPT_CALLBACK* cc = &p->p_cc;
MAP(xdr_cstring, cc->p_cc_data);
DEBUG_PRINTSIZE(xdrs, p->p_operation);
return P_TRUE(xdrs, p);
}
///case op_insert:
default:
#ifdef DEV_BUILD

View File

@ -278,6 +278,7 @@ enum P_OP
op_abort_aux_connection = 95, // Async operation - stop waiting for async connection to arrive
op_crypt = 96,
op_crypt_key_callback = 97,
op_max
};
@ -642,6 +643,12 @@ typedef struct p_crypt
CSTRING p_key; // Key name / keys available on server
} P_CRYPT;
typedef struct p_crypt_callback
{
CSTRING p_cc_data; // User's data
USHORT p_cc_reply;
} P_CRYPT_CALLBACK;
// Generalize packet (sic!)
@ -685,6 +692,7 @@ typedef struct packet
P_CANCEL_OP p_cancel_op; // Cancel operation
P_AUTH_CONT p_auth_cont; // Request more auth data
P_CRYPT p_crypt; // Start wire crypt
P_CRYPT_CALLBACK p_cc; // Database crypt callback
public:
packet()

View File

@ -854,6 +854,10 @@ ServerAuthBase::~ServerAuthBase()
{
}
ServerCallbackBase::~ServerCallbackBase()
{
}
rem_port::~rem_port()
{
if (port_events_shutdown)
@ -867,6 +871,7 @@ rem_port::~rem_port()
delete port_host;
delete port_protocol_str;
delete port_address_str;
delete port_server_crypt_callback;
#ifdef DEBUG_XDR_MEMORY
delete port_packet_vector;
@ -877,10 +882,6 @@ rem_port::~rem_port()
delete port_crypt_keys.pop();
}
if (port_send_cipher)
port_send_cipher->release();
if (port_recv_cipher)
port_recv_cipher->release();
if (port_crypt_plugin)
Firebird::PluginManagerInterfacePtr()->releasePlugin(port_crypt_plugin);
@ -1264,51 +1265,45 @@ bool rem_port::tryKeyType(const KnownServerKey& srvKey, InternalCryptKey* cryptK
// we got correct key's type pair
// check what about crypt plugin for it
Remote::ParsedList clientPlugins;
REMOTE_parseList(clientPlugins, Config::getPlugins(Firebird::PluginType::Crypt));
REMOTE_parseList(clientPlugins, Config::getDefaultConfig()->getPlugins(Firebird::PluginType::WireCrypt));
for (unsigned n = 0; n < clientPlugins.getCount(); ++n)
{
Firebird::PathName p(clientPlugins[n]);
if (srvKey.plugins.find(" " + p + " ") != Firebird::PathName::npos)
{
Firebird::GetPlugins<Firebird::ICryptPlugin>
cp(Firebird::PluginType::Crypt, FB_CRYPT_PLUGIN_VERSION, upInfo, p.c_str());
Firebird::GetPlugins<Firebird::IWireCryptPlugin>
cp(Firebird::PluginType::WireCrypt, FB_WIRECRYPT_PLUGIN_VERSION, upInfo, p.c_str());
if (cp.hasData())
{
// looks like we've found correct crypt plugin and key for it
Firebird::ICryptPlugin* plugin = cp.plugin();
Firebird::LocalStatus st;
// Install decrypting cipher
port_recv_cipher = plugin->getDecrypt(&st, cryptKey);
// Looks like we've found correct crypt plugin and key for it
port_crypt_plugin = cp.plugin();
port_crypt_plugin->addRef();
// Pass key to plugin
port_crypt_plugin->setKey(&st, cryptKey);
if (!st.isSuccess())
{
Firebird::status_exception::raise(st.get());
}
// Now it's time to notify server about choice done
// Notice - port_crypt_complete flag is not set still,
// therefore sent packet will be not encrypted
PACKET crypt;
crypt.p_operation = op_crypt;
setCStr(crypt.p_crypt.p_key, cryptKey->type);
setCStr(crypt.p_crypt.p_plugin, p.c_str());
send(&crypt);
// Validate answer - decryptor is installed, therefore OK to do
// Validate answer - decryptor is not affected by port_crypt_complete,
// therefore OK to do
receive(&crypt);
checkResponse(&st, &crypt);
// Install encrypting cipher
port_send_cipher = plugin->getEncrypt(&st, cryptKey);
if (!st.isSuccess())
{
port_recv_cipher->release();
port_recv_cipher = NULL;
Firebird::status_exception::raise(st.get());
}
port_crypt_plugin = plugin;
port_crypt_plugin->addRef();
// Complete port-crypt init
port_crypt_complete = true;
// fprintf(stderr, "Installed cipher %s key %s\n", cp.name(), cryptKey->type);
return true;
}
}

View File

@ -87,7 +87,9 @@ const int BLOB_LENGTH = 16384;
namespace Firebird {
class Exception;
class IEventCallback;
class ICryptKeyCallback;
}
struct rem_port;
typedef Firebird::AutoPtr<UCHAR, Firebird::ArrayDelete<UCHAR> > UCharArrayAutoPtr;
@ -592,6 +594,14 @@ public:
virtual bool authenticate(PACKET* send) = 0;
};
class ServerCallbackBase
{
public:
virtual ~ServerCallbackBase();
virtual void wakeup(unsigned int length, const void* data) = 0;
virtual Firebird::ICryptKeyCallback* getInterface() = 0;
};
// Helper class to work with public structure FbCryptKey
class InternalCryptKey : public Firebird::FbCryptKey
{
@ -882,9 +892,9 @@ struct rem_port : public Firebird::GlobalStorage, public Firebird::RefCounted
// up to being turned off in firebird.conf
Firebird::ObjectsArray<KnownServerKey> port_known_server_keys; // Server sends to client
// keys known by it, they are stored here
Firebird::ICryptPlugin* port_crypt_plugin; // plugin holder
Firebird::ICrypt* port_send_cipher; // when not NULL - encrypts wire data
Firebird::ICrypt* port_recv_cipher; // when not NULL - decrypts wire data
Firebird::IWireCryptPlugin* port_crypt_plugin; // plugin used by port, when not NULL - crypts wire data
Firebird::ICryptKeyCallback* port_client_crypt_callback; // client callback to transfer database crypt key
ServerCallbackBase* port_server_crypt_callback; // server callback to transfer database crypt key
UCharArrayAutoPtr port_buffer;
@ -914,8 +924,8 @@ public:
port_queue(getPool()), port_qoffset(0),
port_srv_auth(NULL), port_srv_auth_block(NULL),
port_crypt_keys(getPool()), port_need_disk_crypt(false), port_crypt_complete(false),
port_known_server_keys(getPool()),
port_crypt_plugin(NULL), port_send_cipher(NULL), port_recv_cipher(NULL),
port_known_server_keys(getPool()), port_crypt_plugin(NULL),
port_client_crypt_callback(NULL), port_server_crypt_callback(NULL),
port_buffer(FB_NEW(getPool()) UCHAR[rpt])
{
addRef();

View File

@ -688,8 +688,8 @@ public:
: PermanentStorage(p), knownTypes(getPool())
{
LocalStatus st;
for (GetPlugins<ICryptPlugin> cpItr(PluginType::Crypt, FB_CRYPT_PLUGIN_VERSION,
upInfo); cpItr.hasData(); cpItr.next())
for (GetPlugins<IWireCryptPlugin> cpItr(PluginType::WireCrypt, FB_WIRECRYPT_PLUGIN_VERSION,
upInfo); cpItr.hasData(); cpItr.next())
{
const char* list = cpItr.plugin()->getKnownTypes(&st);
if (! st.isSuccess())
@ -744,6 +744,75 @@ private:
InitInstance<CryptKeyTypeManager> knownCryptKeyTypes;
class CryptKeyCallback : public VersionedIface<ICryptKeyCallback, FB_CRYPT_CALLBACK_VERSION>
{
public:
CryptKeyCallback(rem_port* prt)
: port(prt), l(0), d(NULL)
{ }
unsigned int FB_CARG callback(unsigned int dataLength, const void* data,
unsigned int bufferLength, void* buffer)
{
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);
sem.enter();
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();
}
private:
rem_port* port;
Semaphore sem, sem2;
unsigned int l;
const void* d;
};
class ServerCallback : public ServerCallbackBase, public GlobalStorage
{
public:
ServerCallback(rem_port* prt)
: cryptCallback(prt)
{ }
~ServerCallback()
{ }
void wakeup(unsigned int length, const void* data)
{
cryptCallback.wakeup(length, data);
}
ICryptKeyCallback* getInterface()
{
return &cryptCallback;
}
private:
CryptKeyCallback cryptCallback;
};
} // anonymous
static void free_request(server_req_t*);
@ -913,7 +982,7 @@ void SRVR_enum_attachments(ULONG& att_cnt, ULONG& dbs_cnt, ULONG& svc_cnt)
// using the service manager. It could be either isc_info_svc_svr_db_info2
// that adds the third counter, or a completely new information tag.
static IProvider* provider = fb_get_master_interface()->getDispatcher();
DispatcherPtr provider;
static const UCHAR spb_attach[] =
{
@ -1211,7 +1280,10 @@ void SRVR_multi_thread( rem_port* main_port, USHORT flags)
#ifdef DEV_BUILD
#ifndef WIN_NT
fprintf(stderr, "Server started successfully\n");
if (isatty(2))
{
fprintf(stderr, "Server started successfully\n");
}
#endif
#endif
// When this loop exits, the server will no longer receive requests
@ -1768,7 +1840,7 @@ static void attach_database(rem_port* port, P_OP operation, P_ATCH* attach, PACK
void DatabaseAuth::accept(PACKET* send, Auth::WriterImplementation* authBlock)
{
static IProvider* provider = fb_get_master_interface()->getDispatcher();
DispatcherPtr provider;
authBlock->store(pb, isc_dpb_auth_block);
@ -1809,21 +1881,31 @@ void DatabaseAuth::accept(PACKET* send, Auth::WriterImplementation* authBlock)
const UCHAR* dpb = pb->getBuffer();
unsigned int dl = pb->getBufferLength();
if (!authPort->port_server_crypt_callback)
{
authPort->port_server_crypt_callback = new ServerCallback(authPort);
}
LocalStatus status_vector;
ServAttachment iface(operation == op_attach ?
provider->attachDatabase(&status_vector, dbName.c_str(), dl, dpb) :
provider->createDatabase(&status_vector, dbName.c_str(), dl, dpb));
provider->setDbCryptCallback(&status_vector, authPort->port_server_crypt_callback->getInterface());
if (status_vector.isSuccess())
{
Rdb* rdb = new Rdb;
ServAttachment iface(operation == op_attach ?
provider->attachDatabase(&status_vector, dbName.c_str(), dl, dpb) :
provider->createDatabase(&status_vector, dbName.c_str(), dl, dpb));
authPort->port_context = rdb;
if (status_vector.isSuccess())
{
Rdb* rdb = new Rdb;
authPort->port_context = rdb;
#ifdef DEBUG_REMOTE_MEMORY
printf("attach_databases(server) allocate rdb %x\n", rdb);
printf("attach_databases(server) allocate rdb %x\n", rdb);
#endif
rdb->rdb_port = authPort;
rdb->rdb_iface = iface;
rdb->rdb_port = authPort;
rdb->rdb_iface = iface;
}
}
CSTRING* s = &send->p_resp.p_resp_data;
@ -3409,7 +3491,8 @@ void rem_port::info(P_OP op, P_INFO* stuff, PACKET* sendL)
if (status_vector.isSuccess())
{
string version;
version.printf("%s/%s", GDS_VERSION, this->port_version->str_data);
version.printf("%s/%s%s", GDS_VERSION, this->port_version->str_data,
this->port_crypt_complete ? ":C" : "");
info_db_len = MERGE_database_info(temp_buffer, //temp
buffer, stuff->p_info_buffer_length,
DbImplementation::current.backwardCompatibleImplementation(), 4, 1,
@ -4974,25 +5057,34 @@ ISC_STATUS rem_port::service_attach(const char* service_name,
spb->insertTag(isc_spb_auth_block);
}
if (!port_server_crypt_callback)
{
port_server_crypt_callback = new ServerCallback(this);
}
static IProvider* provider = fb_get_master_interface()->getDispatcher();
DispatcherPtr provider;
LocalStatus status_vector;
ServService iface(provider->attachServiceManager(&status_vector, service_name,
spb->getBufferLength(), spb->getBuffer()));
provider->setDbCryptCallback(&status_vector, port_server_crypt_callback->getInterface());
if (status_vector.isSuccess())
{
Rdb* rdb = new Rdb;
ServService iface(provider->attachServiceManager(&status_vector, service_name,
spb->getBufferLength(), spb->getBuffer()));
this->port_context = rdb;
if (status_vector.isSuccess())
{
Rdb* rdb = new Rdb;
this->port_context = rdb;
#ifdef DEBUG_REMOTE_MEMORY
printf("attach_service(server) allocate rdb %x\n", rdb);
printf("attach_service(server) allocate rdb %x\n", rdb);
#endif
rdb->rdb_port = this;
Svc* svc = rdb->rdb_svc = new Svc;
svc->svc_auth = authenticated ? Svc::SVCAUTH_PERM : Svc::SVCAUTH_NONE;
svc->svc_cached_spb = cache;
svc->svc_iface = iface;
rdb->rdb_port = this;
Svc* svc = rdb->rdb_svc = new Svc;
svc->svc_auth = authenticated ? Svc::SVCAUTH_PERM : Svc::SVCAUTH_NONE;
svc->svc_cached_spb = cache;
svc->svc_iface = iface;
}
}
return this->send_response(sendL, 0,
@ -5210,7 +5302,7 @@ void rem_port::start_crypt(P_CRYPT * crypt, PACKET* sendL)
PathName plugName(crypt->p_plugin.cstr_address, crypt->p_plugin.cstr_length);
// Check it's availability
Remote::ParsedList plugins;
REMOTE_parseList(plugins, Config::getPlugins(PluginType::Crypt));
REMOTE_parseList(plugins, Config::getDefaultConfig()->getPlugins(PluginType::WireCrypt));
bool found = false;
for (unsigned n = 0; n < plugins.getCount(); ++n)
{
@ -5226,30 +5318,23 @@ void rem_port::start_crypt(P_CRYPT * crypt, PACKET* sendL)
// good idea to add plugName later
}
GetPlugins<ICryptPlugin> cp(PluginType::Crypt, FB_CRYPT_PLUGIN_VERSION, upInfo, plugName.c_str());
GetPlugins<IWireCryptPlugin> cp(PluginType::WireCrypt, FB_WIRECRYPT_PLUGIN_VERSION, upInfo,
plugName.c_str());
if (!cp.hasData())
{
(Arg::Gds(isc_random) << "Bad plugin from client").raise();
// good idea to add plugName later
}
// Install decrypting cipher
// Initialize crypt key
LocalStatus st;
port_recv_cipher = cp.plugin()->getDecrypt(&st, key);
cp.plugin()->setKey(&st, key);
if (! st.isSuccess())
{
status_exception::raise(st.get());
}
// Install encrypting cipher
port_send_cipher = cp.plugin()->getEncrypt(&st, key);
if (! st.isSuccess())
{
port_recv_cipher->release();
port_recv_cipher = NULL;
status_exception::raise(st.get());
}
// Install plugin
port_crypt_plugin = cp.plugin();
port_crypt_plugin->addRef();
port_crypt_complete = true;
@ -5678,6 +5763,7 @@ SSHORT rem_port::asyncReceive(PACKET* asyncPacket, const UCHAR* buffer, SSHORT d
{
case op_cancel:
case op_abort_aux_connection:
case op_crypt_key_callback:
break;
default:
return 0;
@ -5710,7 +5796,12 @@ SSHORT rem_port::asyncReceive(PACKET* asyncPacket, const UCHAR* buffer, SSHORT d
port_async->abort_aux_connection();
}
break;
case op_crypt_key_callback:
port_server_crypt_callback->wakeup(asyncPacket->p_cc.p_cc_data.cstr_length,
asyncPacket->p_cc.p_cc_data.cstr_address);
break;
default:
fb_assert(false);
return 0;
}

View File

@ -413,6 +413,7 @@ const SvcSwitches statisticsOptions[] =
{"sts_hdr_pages", putOption, 0, isc_spb_sts_hdr_pages, 0},
{"sts_idx_pages", putOption, 0, isc_spb_sts_idx_pages, 0},
{"sts_sys_relations", putOption, 0, isc_spb_sts_sys_relations, 0},
{"sts_encryption", putOption, 0, isc_spb_sts_encryption, 0},
{0, 0, 0, 0, 0}
};

View File

@ -180,7 +180,7 @@ static void db_error(int);
static USHORT get_format_length(ISC_STATUS*, isc_db_handle, isc_tr_handle, ISC_QUAD&);
static dba_fil* db_open(const char*, USHORT);
static const pag* db_read(SLONG);
static const pag* db_read(SLONG page_number, bool ok_enc = false);
#ifdef WIN_NT
static void db_close(void* file_desc);
#else
@ -385,7 +385,6 @@ int gstat(Firebird::UtilSvc* uSvc)
if (argc == 1) // no parameters at all.
{
tddba->uSvc->setServiceStatus(GSTAT_MSG_FAC, 45, SafeArg());
dba_error(45); // use gstat -? to get help'
}
@ -394,6 +393,7 @@ int gstat(Firebird::UtilSvc* uSvc)
bool sw_index = false;
bool sw_version = false;
bool sw_header = false;
bool sw_enc = false;
//bool sw_log = false;
bool sw_record = false;
bool sw_relation = false;
@ -411,7 +411,6 @@ int gstat(Firebird::UtilSvc* uSvc)
{
if (name)
{
tddba->uSvc->setServiceStatus(GSTAT_MSG_FAC, 40, SafeArg());
dba_error(40); // database name was already specified
}
@ -426,7 +425,6 @@ int gstat(Firebird::UtilSvc* uSvc)
str = "-*NONE*";
dba_print(true, 20, SafeArg() << (str + 1)); // msg 20: unknown switch "%s"
print_help();
tddba->uSvc->setServiceStatus(GSTAT_MSG_FAC, 1, SafeArg() << (str + 1));
dba_error(1); // msg 1: found unknown switch
break; // redundant
}
@ -487,6 +485,9 @@ int gstat(Firebird::UtilSvc* uSvc)
case IN_SW_DBA_HEADER:
sw_header = true;
break;
case IN_SW_DBA_ENCRYPTION:
sw_enc = true;
break;
// case IN_SW_DBA_LOG:
// sw_log = true;
// break;
@ -505,7 +506,6 @@ int gstat(Firebird::UtilSvc* uSvc)
char tbname[MAX_SQL_IDENTIFIER_LEN + 5];
fb_utils::copy_terminate(tbname, *argv, MAX_SQL_IDENTIFIER_SIZE);
memcpy(tbname + MAX_SQL_IDENTIFIER_LEN, "...\0", 4);
tddba->uSvc->setServiceStatus(GSTAT_MSG_FAC, 42, SafeArg() << tbname);
dba_error(42, SafeArg() << tbname); // option -t got a too long table name @1
break;
}
@ -537,19 +537,21 @@ int gstat(Firebird::UtilSvc* uSvc)
if (sw_header && (sw_system || sw_data || sw_index || sw_record || sw_relation))
{
tddba->uSvc->setServiceStatus(GSTAT_MSG_FAC, 38, SafeArg());
dba_error(38); //option -h is incompatible with options -a, -d, -i, -r, -s and -t
}
if (sw_enc && (sw_header || sw_system || sw_data || sw_index || sw_record || sw_relation))
{
dba_error(50); //option -e is incompatible with options -a, -d, -h, -i, -r, -s and -t
}
if (!name)
{
tddba->uSvc->setServiceStatus(GSTAT_MSG_FAC, 2, SafeArg());
dba_error(2); // msg 2: please retry, giving a database name
}
if (sw_relation && !tddba->relations)
{
tddba->uSvc->setServiceStatus(GSTAT_MSG_FAC, 41, SafeArg());
dba_error(41); // option -t needs a table name.
}
@ -596,7 +598,6 @@ int gstat(Firebird::UtilSvc* uSvc)
if (!Ods::isSupported(header->hdr_ods_version, header->hdr_ods_minor))
{
const int oversion = (header->hdr_ods_version & ~ODS_FIREBIRD_FLAG);
tddba->uSvc->setServiceStatus(GSTAT_MSG_FAC, 3, SafeArg() << ODS_VERSION << oversion);
dba_error(3, SafeArg() << ODS_VERSION << oversion);
// msg 3: Wrong ODS version, expected %d, encountered %d?
}
@ -654,6 +655,64 @@ int gstat(Firebird::UtilSvc* uSvc)
if (sw_header)
dba_exit(FINI_OK, tddba);
if (sw_enc)
{
class Statist
{
public:
Statist()
: enc(0), non(0)
{ }
void print(USHORT messageNo)
{
dba_print(false, messageNo, SafeArg() << enc + non << enc << non);
// msg 5[2-4]: <TYPE> pages: total @1, encrypted @2, non-crypted @3
}
void log(UCHAR flags)
{
if (flags & crypted_page)
++enc;
else
++non;
}
private:
ULONG enc, non;
};
Statist data, index, blob;
for (page = 0; true; ++page)
{
const pag* p = db_read(page, true);
if (!p)
{
break;
}
switch(p->pag_type)
{
case pag_data:
data.log(p->pag_flags);
break;
case pag_index:
index.log(p->pag_flags);
break;
case pag_blob:
blob.log(p->pag_flags);
break;
}
}
uSvc->printf(false, "\n");
data.print(52);
index.print(53);
blob.print(54);
dba_exit(FINI_OK, tddba);
}
// print continuation file sequence
dba_print(false, 7);
@ -865,7 +924,6 @@ int gstat(Firebird::UtilSvc* uSvc)
checkForShutdown(tddba);
if (relation->rel_id == -1)
{
tddba->uSvc->setServiceStatus(GSTAT_MSG_FAC, 44, SafeArg() << relation->rel_name);
dba_error(44, SafeArg() << relation->rel_name);
// msg 44: table "@1" not found
}
@ -1748,7 +1806,7 @@ static dba_fil* db_open(const char* file_name, USHORT file_length)
}
static const pag* db_read( SLONG page_number)
static const pag* db_read( SLONG page_number, bool ok_enc)
{
/**************************************
*
@ -1805,11 +1863,19 @@ static const pag* db_read( SLONG page_number)
}
if (actual_length != tddba->page_size)
{
tddba->uSvc->setServiceStatus(GSTAT_MSG_FAC, 4, SafeArg());
if (ok_enc)
{
return NULL;
}
dba_error(4);
// msg 4: Unexpected end of database file.
}
if (tddba->global_buffer->pag_flags & Ods::crypted_page && !ok_enc)
{
dba_error(55);
}
return tddba->global_buffer;
}
#endif // ifdef WIN_NT
@ -1925,7 +1991,7 @@ static dba_fil* db_open(const char* file_name, USHORT file_length)
}
static const pag* db_read( SLONG page_number)
static const pag* db_read( SLONG page_number, bool ok_enc)
{
/**************************************
*
@ -1971,7 +2037,10 @@ static const pag* db_read( SLONG page_number)
}
if (!l)
{
tddba->uSvc->setServiceStatus(GSTAT_MSG_FAC, 4, SafeArg());
if (ok_enc)
{
return NULL;
}
dba_error(4);
// msg 4: Unexpected end of database file.
}
@ -1979,6 +2048,11 @@ static const pag* db_read( SLONG page_number)
length -= l;
}
if (tddba->global_buffer->pag_flags & Ods::crypted_page && !ok_enc)
{
dba_error(55);
}
return tddba->global_buffer;
}
#endif
@ -1999,7 +2073,11 @@ static void dba_error(USHORT errcode, const SafeArg& arg)
tdba* tddba = tdba::getSpecific();
tddba->page_number = -1;
dba_print(true, errcode, arg);
tddba->uSvc->setServiceStatus(GSTAT_MSG_FAC, errcode, arg);
if (!tddba->uSvc->isService())
{
dba_print(true, errcode, arg);
}
dba_exit(FINI_ERROR, tddba);
}

View File

@ -50,12 +50,14 @@ const int IN_SW_DBA_TRUSTED_ROLE = 14; // use predefined trusted role
const int IN_SW_DBA_TRUSTEDAUTH = 15; // trusted user name
#endif
const int IN_SW_DBA_FETCH_PASS = 16; // fetch password from file
const int IN_SW_DBA_HELP = 17; // show help
const int IN_SW_DBA_ENCRYPTION = 17; // analyze pages encryption
const int IN_SW_DBA_HELP = 18; // show help
const static struct Switches::in_sw_tab_t dba_in_sw_table[] =
{
{IN_SW_DBA_DATAIDX, 0, "ALL", 0,0,0, false, 22, 1, NULL}, // msg 22: -a analyze data and index pages
{IN_SW_DBA_DATA, isc_spb_sts_data_pages, "DATA", 0,0,0, false, 23, 1, NULL}, // msg 23: -d analyze data pages
{IN_SW_DBA_ENCRYPTION, isc_spb_sts_encryption, "ENCRYPTION", 0,0,0, false, 51, 1, NULL}, // msg 51: -e analyze database encryption
{IN_SW_DBA_HEADER, isc_spb_sts_hdr_pages, "HEADER", 0,0,0, false, 24, 1, NULL}, // msg 24: -h analyze header page
{IN_SW_DBA_INDEX, isc_spb_sts_idx_pages, "INDEX", 0,0,0, false, 25, 1, NULL}, // msg 25: -i analyze index leaf pages
// {IN_SW_DBA_LOG, isc_spb_sts_db_log, "LOG", 0,0,0, false, 26, 1, NULL}, // msg 26: -l analyze log page

Some files were not shown because too many files have changed in this diff Show More