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:
parent
ed2cf92cb0
commit
2a01e4bcf9
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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=
|
||||
|
@ -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
|
||||
|
217
examples/dbcrypt/CryptApplication.cpp
Normal file
217
examples/dbcrypt/CryptApplication.cpp
Normal 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;
|
||||
}
|
278
examples/dbcrypt/CryptKeyHolder.cpp
Normal file
278
examples/dbcrypt/CryptKeyHolder.cpp
Normal 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);
|
||||
}
|
266
examples/dbcrypt/DbCrypt.cpp
Normal file
266
examples/dbcrypt/DbCrypt.cpp
Normal 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);
|
||||
}
|
2
examples/dbcrypt/ReadMe.txt
Normal file
2
examples/dbcrypt/ReadMe.txt
Normal 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!
|
@ -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())
|
||||
{
|
||||
|
@ -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())
|
||||
|
@ -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"
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
|
@ -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.
|
||||
|
@ -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();
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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"
|
||||
|
@ -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)
|
||||
|
@ -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"
|
||||
|
@ -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"
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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;
|
||||
};
|
||||
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -744,6 +744,11 @@ public:
|
||||
fb_assert(false);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
virtual int FB_CARG same(IVersioned* /*first*/, IVersioned* /*second*/)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
@ -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 */
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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"
|
||||
|
@ -36,6 +36,7 @@
|
||||
namespace Jrd {
|
||||
|
||||
class Lock;
|
||||
class BaseSubstringSimilarMatcher;
|
||||
|
||||
class Collation : public TextType
|
||||
{
|
||||
|
728
src/jrd/CryptoManager.cpp
Normal file
728
src/jrd/CryptoManager.cpp
Normal 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
147
src/jrd/CryptoManager.h
Normal 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
|
@ -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;
|
||||
|
@ -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()),
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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"
|
||||
|
@ -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;
|
||||
|
@ -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"
|
||||
|
@ -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
|
||||
|
@ -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>
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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>
|
||||
|
@ -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()
|
||||
|
@ -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))
|
||||
{
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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"
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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*);
|
||||
|
@ -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());
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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
|
||||
|
@ -29,6 +29,7 @@
|
||||
namespace Jrd {
|
||||
class thread_db;
|
||||
class Lock;
|
||||
class Collation;
|
||||
}
|
||||
|
||||
struct dsc;
|
||||
|
134
src/jrd/jrd.cpp
134
src/jrd/jrd.cpp
@ -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);
|
||||
|
||||
|
144
src/jrd/lck.cpp
144
src/jrd/lck.cpp
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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))
|
||||
{
|
||||
|
@ -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;
|
||||
|
@ -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"
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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"
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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();
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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"
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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());
|
||||
|
@ -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
|
||||
|
@ -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()
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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();
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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}
|
||||
};
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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
Loading…
Reference in New Issue
Block a user