|
From: <ale...@us...> - 2012-05-31 16:53:57
|
Revision: 54574
http://firebird.svn.sourceforge.net/firebird/?rev=54574&view=rev
Author: alexpeshkoff
Date: 2012-05-31 16:53:42 +0000 (Thu, 31 May 2012)
Log Message:
-----------
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
Modified Paths:
--------------
firebird/trunk/builds/posix/Makefile.in
firebird/trunk/builds/posix/Makefile.in.plugins_examples
firebird/trunk/builds/posix/firebird.vers
firebird/trunk/builds/posix/make.defaults
firebird/trunk/builds/posix/make.shared.variables
firebird/trunk/builds/win32/defs/firebird.def
firebird/trunk/src/auth/SecureRemotePassword/manage/SrpManagement.cpp
firebird/trunk/src/auth/SecureRemotePassword/server/SrpServer.cpp
firebird/trunk/src/common/IntlUtil.cpp
firebird/trunk/src/common/TextType.cpp
firebird/trunk/src/common/TextType.h
firebird/trunk/src/common/classes/GetPlugins.h
firebird/trunk/src/common/classes/ImplementHelper.h
firebird/trunk/src/common/config/config.cpp
firebird/trunk/src/common/config/config.h
firebird/trunk/src/common/isc.cpp
firebird/trunk/src/common/isc_file.cpp
firebird/trunk/src/common/sdl.cpp
firebird/trunk/src/dsql/BoolNodes.cpp
firebird/trunk/src/dsql/DdlNodes.epp
firebird/trunk/src/dsql/DdlNodes.h
firebird/trunk/src/dsql/ExprNodes.cpp
firebird/trunk/src/dsql/parse.y
firebird/trunk/src/gpre/boot/gpre_meta_boot.cpp
firebird/trunk/src/include/consts_pub.h
firebird/trunk/src/include/firebird/Crypt.h
firebird/trunk/src/include/firebird/Interface.h
firebird/trunk/src/include/firebird/Plugin.h
firebird/trunk/src/include/firebird/Provider.h
firebird/trunk/src/include/gen/ids.h
firebird/trunk/src/jrd/Attachment.cpp
firebird/trunk/src/jrd/Attachment.h
firebird/trunk/src/jrd/Collation.cpp
firebird/trunk/src/jrd/Collation.h
firebird/trunk/src/jrd/Database.cpp
firebird/trunk/src/jrd/Database.h
firebird/trunk/src/jrd/DatabaseSnapshot.cpp
firebird/trunk/src/jrd/EngineInterface.h
firebird/trunk/src/jrd/Function.epp
firebird/trunk/src/jrd/GlobalRWLock.cpp
firebird/trunk/src/jrd/GlobalRWLock.h
firebird/trunk/src/jrd/IntlManager.cpp
firebird/trunk/src/jrd/JrdStatement.cpp
firebird/trunk/src/jrd/Optimizer.cpp
firebird/trunk/src/jrd/RecordNumber.h
firebird/trunk/src/jrd/SysFunction.cpp
firebird/trunk/src/jrd/VirtualTable.cpp
firebird/trunk/src/jrd/blb.h
firebird/trunk/src/jrd/btr.cpp
firebird/trunk/src/jrd/cch.cpp
firebird/trunk/src/jrd/cmp.cpp
firebird/trunk/src/jrd/cvt2.cpp
firebird/trunk/src/jrd/dfw.epp
firebird/trunk/src/jrd/dfw_proto.h
firebird/trunk/src/jrd/extds/InternalDS.cpp
firebird/trunk/src/jrd/ibase.h
firebird/trunk/src/jrd/idx.cpp
firebird/trunk/src/jrd/intl.cpp
firebird/trunk/src/jrd/intl_classes.h
firebird/trunk/src/jrd/intl_proto.h
firebird/trunk/src/jrd/jrd.cpp
firebird/trunk/src/jrd/lck.cpp
firebird/trunk/src/jrd/lck.h
firebird/trunk/src/jrd/lck_proto.h
firebird/trunk/src/jrd/met.epp
firebird/trunk/src/jrd/names.h
firebird/trunk/src/jrd/nbak.cpp
firebird/trunk/src/jrd/ods.h
firebird/trunk/src/jrd/opt.cpp
firebird/trunk/src/jrd/os/posix/unix.cpp
firebird/trunk/src/jrd/pag.cpp
firebird/trunk/src/jrd/recsrc/HashJoin.cpp
firebird/trunk/src/jrd/relations.h
firebird/trunk/src/jrd/rlck.cpp
firebird/trunk/src/jrd/sdw.cpp
firebird/trunk/src/jrd/svc.cpp
firebird/trunk/src/jrd/svc.h
firebird/trunk/src/jrd/tpc.cpp
firebird/trunk/src/jrd/tra.cpp
firebird/trunk/src/jrd/tra.h
firebird/trunk/src/jrd/val.h
firebird/trunk/src/msgs/facilities2.sql
firebird/trunk/src/msgs/messages2.sql
firebird/trunk/src/plugins/crypt/arc4/Arc4.cpp
firebird/trunk/src/remote/client/interface.cpp
firebird/trunk/src/remote/inet.cpp
firebird/trunk/src/remote/protocol.cpp
firebird/trunk/src/remote/protocol.h
firebird/trunk/src/remote/remote.cpp
firebird/trunk/src/remote/remote.h
firebird/trunk/src/remote/server/server.cpp
firebird/trunk/src/utilities/fbsvcmgr/fbsvcmgr.cpp
firebird/trunk/src/utilities/gstat/dba.epp
firebird/trunk/src/utilities/gstat/dbaswi.h
firebird/trunk/src/utilities/gstat/ppg.cpp
firebird/trunk/src/utilities/ntrace/TracePluginImpl.h
firebird/trunk/src/yvalve/MasterImplementation.cpp
firebird/trunk/src/yvalve/MasterImplementation.h
firebird/trunk/src/yvalve/YObjects.h
firebird/trunk/src/yvalve/gds.cpp
firebird/trunk/src/yvalve/keywords.cpp
firebird/trunk/src/yvalve/why.cpp
firebird/trunk/src/yvalve/why_proto.h
Added Paths:
-----------
firebird/trunk/examples/dbcrypt/
firebird/trunk/examples/dbcrypt/CryptApplication.cpp
firebird/trunk/examples/dbcrypt/CryptKeyHolder.cpp
firebird/trunk/examples/dbcrypt/DbCrypt.cpp
firebird/trunk/examples/dbcrypt/ReadMe.txt
firebird/trunk/src/jrd/CryptoManager.cpp
firebird/trunk/src/jrd/CryptoManager.h
Modified: firebird/trunk/builds/posix/Makefile.in
===================================================================
--- firebird/trunk/builds/posix/Makefile.in 2012-05-31 12:55:40 UTC (rev 54573)
+++ firebird/trunk/builds/posix/Makefile.in 2012-05-31 16:53:42 UTC (rev 54574)
@@ -359,10 +359,10 @@
#
.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 @@
$(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
Modified: firebird/trunk/builds/posix/Makefile.in.plugins_examples
===================================================================
--- firebird/trunk/builds/posix/Makefile.in.plugins_examples 2012-05-31 12:55:40 UTC (rev 54573)
+++ firebird/trunk/builds/posix/Makefile.in.plugins_examples 2012-05-31 16:53:42 UTC (rev 54574)
@@ -27,8 +27,15 @@
# Contributor(s):
# Adriano dos Santos Fernandes
#
-ROOT=../..
+ROOT=$(shell cd ../..; pwd)
+
+ifeq ($(IsDeveloper), Y)
+ DefaultTarget := Debug
+else
+ DefaultTarget := Release
+endif
+
CPPFLAGS+= -I$(FIREBIRD)/include
include $(ROOT)/gen/make.defaults
@@ -38,26 +45,23 @@
@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
-AllObjects = $(UDR_Objects)
-Dependencies = $(AllObjects:.o=.d)
+all: udrcpp_example dc_example kh_example
-.PHONY: all udrcpp_example
+UDR_Objects = $(call makeObjects,../examples/udr,UdrCppExample.cpp)
+UDR_Plugin = $(PLUGINS)/udr/$(LIB_PREFIX)udrcpp_example.$(SHRLIB_EXT)
+AllObjects = $(UDR_Objects)
-all: udrcpp_example
+udrcpp_example: $(UDR_Plugin)
-
-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 @@
$(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)
Modified: firebird/trunk/builds/posix/firebird.vers
===================================================================
--- firebird/trunk/builds/posix/firebird.vers 2012-05-31 12:55:40 UTC (rev 54573)
+++ firebird/trunk/builds/posix/firebird.vers 2012-05-31 16:53:42 UTC (rev 54574)
@@ -345,6 +345,8 @@
fb_get_database_handle
fb_get_transaction_handle
+fb_database_crypt_callback
+
# Other misc functions
isc_ftof
Modified: firebird/trunk/builds/posix/make.defaults
===================================================================
--- firebird/trunk/builds/posix/make.defaults 2012-05-31 12:55:40 UTC (rev 54573)
+++ firebird/trunk/builds/posix/make.defaults 2012-05-31 16:53:42 UTC (rev 54574)
@@ -336,7 +336,6 @@
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)
Modified: firebird/trunk/builds/posix/make.shared.variables
===================================================================
--- firebird/trunk/builds/posix/make.shared.variables 2012-05-31 12:55:40 UTC (rev 54573)
+++ firebird/trunk/builds/posix/make.shared.variables 2012-05-31 16:53:42 UTC (rev 54574)
@@ -15,7 +15,9 @@
dirObjects= $(call dirMaster,$(1)) $(call dirOs,$(1)) $(call dirFallBack,$(1))
+makePluginName= $(PLUGINS)/$(LIB_PREFIX)$(1).$(SHRLIB_EXT)
+
# Collect all object files here
AllObjects=
Modified: firebird/trunk/builds/win32/defs/firebird.def
===================================================================
--- firebird/trunk/builds/win32/defs/firebird.def 2012-05-31 12:55:40 UTC (rev 54573)
+++ firebird/trunk/builds/win32/defs/firebird.def 2012-05-31 16:53:42 UTC (rev 54574)
@@ -354,6 +354,7 @@
fb_get_master_interface
fb_get_database_handle
fb_get_transaction_handle
+ fb_database_crypt_callback
gds__trace
gds__trace_raw
Added: firebird/trunk/examples/dbcrypt/CryptApplication.cpp
===================================================================
--- firebird/trunk/examples/dbcrypt/CryptApplication.cpp (rev 0)
+++ firebird/trunk/examples/dbcrypt/CryptApplication.cpp 2012-05-31 16:53:42 UTC (rev 54574)
@@ -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;
+}
Property changes on: firebird/trunk/examples/dbcrypt/CryptApplication.cpp
___________________________________________________________________
Added: svn:mime-type
+ text/x-c++src
Added: svn:eol-style
+ native
Added: firebird/trunk/examples/dbcrypt/CryptKeyHolder.cpp
===================================================================
--- firebird/trunk/examples/dbcrypt/CryptKeyHolder.cpp (rev 0)
+++ firebird/trunk/examples/dbcrypt/CryptKeyHolder.cpp 2012-05-31 16:53:42 UTC (rev 54574)
@@ -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);
+}
Property changes on: firebird/trunk/examples/dbcrypt/CryptKeyHolder.cpp
___________________________________________________________________
Added: svn:mime-type
+ text/x-c++src
Added: svn:eol-style
+ native
Added: firebird/trunk/examples/dbcrypt/DbCrypt.cpp
===================================================================
--- firebird/trunk/examples/dbcrypt/DbCrypt.cpp (rev 0)
+++ firebird/trunk/examples/dbcrypt/DbCrypt.cpp 2012-05-31 16:53:42 UTC (rev 54574)
@@ -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);
+}
Property changes on: firebird/trunk/examples/dbcrypt/DbCrypt.cpp
___________________________________________________________________
Added: svn:mime-type
+ text/x-c++src
Added: svn:eol-style
+ native
Added: firebird/trunk/examples/dbcrypt/ReadMe.txt
===================================================================
--- firebird/trunk/examples/dbcrypt/ReadMe.txt (rev 0)
+++ firebird/trunk/examples/dbcrypt/ReadMe.txt 2012-05-31 16:53:42 UTC (rev 54574)
@@ -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!
Property changes on: firebird/trunk/examples/dbcrypt/ReadMe.txt
___________________________________________________________________
Added: svn:mime-type
+ text/plain
Added: svn:eol-style
+ native
Modified: firebird/trunk/src/auth/SecureRemotePassword/manage/SrpManagement.cpp
===================================================================
--- firebird/trunk/src/auth/SecureRemotePassword/manage/SrpManagement.cpp 2012-05-31 12:55:40 UTC (rev 54573)
+++ firebird/trunk/src/auth/SecureRemotePassword/manage/SrpManagement.cpp 2012-05-31 16:53:42 UTC (rev 54574)
@@ -216,8 +216,7 @@
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())
{
Modified: firebird/trunk/src/auth/SecureRemotePassword/server/SrpServer.cpp
===================================================================
--- firebird/trunk/src/auth/SecureRemotePassword/server/SrpServer.cpp 2012-05-31 12:55:40 UTC (rev 54573)
+++ firebird/trunk/src/auth/SecureRemotePassword/server/SrpServer.cpp 2012-05-31 16:53:42 UTC (rev 54574)
@@ -123,8 +123,7 @@
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())
Modified: firebird/trunk/src/common/IntlUtil.cpp
===================================================================
--- firebird/trunk/src/common/IntlUtil.cpp 2012-05-31 12:55:40 UTC (rev 54573)
+++ firebird/trunk/src/common/IntlUtil.cpp 2012-05-31 16:53:42 UTC (rev 54574)
@@ -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"
Modified: firebird/trunk/src/common/TextType.cpp
===================================================================
--- firebird/trunk/src/common/TextType.cpp 2012-05-31 12:55:40 UTC (rev 54573)
+++ firebird/trunk/src/common/TextType.cpp 2012-05-31 16:53:42 UTC (rev 54574)
@@ -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 @@
return srcLen / getCharSet()->minBytesPerChar();
}
+BYTE TextType::getCanonicalWidth() const
+{
+ return tt->texttype_canonical_width;
+}
+USHORT TextType::getFlags() const
+{
+ return tt->texttype_flags;
+}
+
} // namespace Jrd
Modified: firebird/trunk/src/common/TextType.h
===================================================================
--- firebird/trunk/src/common/TextType.h 2012-05-31 12:55:40 UTC (rev 54573)
+++ firebird/trunk/src/common/TextType.h 2012-05-31 16:53:42 UTC (rev 54574)
@@ -30,6 +30,8 @@
#ifndef JRD_TEXTTYPE_H
#define JRD_TEXTTYPE_H
+#include "../common/classes/MetaName.h"
+
struct texttype;
namespace Jrd {
@@ -85,16 +87,9 @@
return cs;
}
- BYTE getCanonicalWidth() const
- {
- return tt->texttype_canonical_width;
- }
+ BYTE getCanonicalWidth() const;
+ USHORT getFlags() const;
- USHORT getFlags() const
- {
- return tt->texttype_flags;
- }
-
public:
Firebird::MetaName name;
Modified: firebird/trunk/src/common/classes/GetPlugins.h
===================================================================
--- firebird/trunk/src/common/classes/GetPlugins.h 2012-05-31 12:55:40 UTC (rev 54573)
+++ firebird/trunk/src/common/classes/GetPlugins.h 2012-05-31 16:53:42 UTC (rev 54574)
@@ -47,7 +47,7 @@
{
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 @@
{
LocalStatus status;
pluginSet = pluginInterface->getPlugins(&status, interfaceType,
- (namesList ? namesList : Config::getPlugins(interfaceType)),
+ (namesList ? namesList : knownConfig->getPlugins(interfaceType)),
desiredVersion, ui, new FirebirdConf(knownConfig));
if (!pluginSet)
Modified: firebird/trunk/src/common/classes/ImplementHelper.h
===================================================================
--- firebird/trunk/src/common/classes/ImplementHelper.h 2012-05-31 12:55:40 UTC (rev 54573)
+++ firebird/trunk/src/common/classes/ImplementHelper.h 2012-05-31 16:53:42 UTC (rev 54574)
@@ -232,6 +232,21 @@
};
+// 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.
Modified: firebird/trunk/src/common/config/config.cpp
===================================================================
--- firebird/trunk/src/common/config/config.cpp 2012-05-31 12:55:40 UTC (rev 54573)
+++ firebird/trunk/src/common/config/config.cpp 2012-05-31 16:53:42 UTC (rev 54574)
@@ -175,7 +175,9 @@
{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 @@
#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();
Modified: firebird/trunk/src/common/config/config.h
===================================================================
--- firebird/trunk/src/common/config/config.h 2012-05-31 12:55:40 UTC (rev 54573)
+++ firebird/trunk/src/common/config/config.h 2012-05-31 16:53:42 UTC (rev 54574)
@@ -140,7 +140,9 @@
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 @@
static bool getMultiClientServer();
- static const char* getPlugins(unsigned int type);
+ const char* getPlugins(unsigned int type) const;
const char* getSecurityDatabase() const;
Modified: firebird/trunk/src/common/isc.cpp
===================================================================
--- firebird/trunk/src/common/isc.cpp 2012-05-31 12:55:40 UTC (rev 54573)
+++ firebird/trunk/src/common/isc.cpp 2012-05-31 16:53:42 UTC (rev 54574)
@@ -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"
Modified: firebird/trunk/src/common/isc_file.cpp
===================================================================
--- firebird/trunk/src/common/isc_file.cpp 2012-05-31 12:55:40 UTC (rev 54573)
+++ firebird/trunk/src/common/isc_file.cpp 2012-05-31 16:53:42 UTC (rev 54574)
@@ -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 @@
/**************************************
*
* 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 @@
const char* start = device;
if (n<5)
- return false;
+ {
+ return false;
+ }
const char* iflag = strchr(device, ':');
if (iflag)
Modified: firebird/trunk/src/common/sdl.cpp
===================================================================
--- firebird/trunk/src/common/sdl.cpp 2012-05-31 12:55:40 UTC (rev 54573)
+++ firebird/trunk/src/common/sdl.cpp 2012-05-31 16:53:42 UTC (rev 54574)
@@ -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"
Modified: firebird/trunk/src/dsql/BoolNodes.cpp
===================================================================
--- firebird/trunk/src/dsql/BoolNodes.cpp 2012-05-31 12:55:40 UTC (rev 54573)
+++ firebird/trunk/src/dsql/BoolNodes.cpp 2012-05-31 16:53:42 UTC (rev 54574)
@@ -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"
Modified: firebird/trunk/src/dsql/DdlNodes.epp
===================================================================
--- firebird/trunk/src/dsql/DdlNodes.epp 2012-05-31 12:55:40 UTC (rev 54573)
+++ firebird/trunk/src/dsql/DdlNodes.epp 2012-05-31 16:53:42 UTC (rev 54574)
@@ -9946,6 +9946,22 @@
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);
Modified: firebird/trunk/src/dsql/DdlNodes.h
===================================================================
--- firebird/trunk/src/dsql/DdlNodes.h 2012-05-31 12:55:40 UTC (rev 54573)
+++ firebird/trunk/src/dsql/DdlNodes.h 2012-05-31 16:53:42 UTC (rev 54574)
@@ -1950,10 +1950,13 @@
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)
: DdlNode(p),
@@ -1963,7 +1966,8 @@
differenceFile(p),
setDefaultCharSet(p),
setDefaultCollation(p),
- files(p)
+ files(p),
+ cryptPlugin(p)
{
}
@@ -1996,6 +2000,7 @@
Firebird::MetaName setDefaultCharSet;
Firebird::MetaName setDefaultCollation;
Firebird::Array<NestConst<DbFileClause> > files;
+ Firebird::MetaName cryptPlugin;
};
Modified: firebird/trunk/src/dsql/ExprNodes.cpp
===================================================================
--- firebird/trunk/src/dsql/ExprNodes.cpp 2012-05-31 12:55:40 UTC (rev 54573)
+++ firebird/trunk/src/dsql/ExprNodes.cpp 2012-05-31 16:53:42 UTC (rev 54574)
@@ -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;
Modified: firebird/trunk/src/dsql/parse.y
===================================================================
--- firebird/trunk/src/dsql/parse.y 2012-05-31 12:55:40 UTC (rev 54573)
+++ firebird/trunk/src/dsql/parse.y 2012-05-31 16:53:42 UTC (rev 54574)
@@ -547,6 +547,8 @@
%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 @@
{ $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 @@
| BODY
| CONTINUE
| DDL
+ | DECRYPT
+ | ENCRYPT
| ENGINE
| IDENTITY
| NAME
Modified: firebird/trunk/src/gpre/boot/gpre_meta_boot.cpp
===================================================================
--- firebird/trunk/src/gpre/boot/gpre_meta_boot.cpp 2012-05-31 12:55:40 UTC (rev 54573)
+++ firebird/trunk/src/gpre/boot/gpre_meta_boot.cpp 2012-05-31 16:53:42 UTC (rev 54574)
@@ -744,6 +744,11 @@
fb_assert(false);
return NULL;
}
+
+ virtual int FB_CARG same(IVersioned* /*first*/, IVersioned* /*second*/)
+ {
+ return 0;
+ }
};
Modified: firebird/trunk/src/include/consts_pub.h
===================================================================
--- firebird/trunk/src/include/consts_pub.h 2012-05-31 12:55:40 UTC (rev 54573)
+++ firebird/trunk/src/include/consts_pub.h 2012-05-31 16:53:42 UTC (rev 54574)
@@ -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 */
Modified: firebird/trunk/src/include/firebird/Crypt.h
===================================================================
--- firebird/trunk/src/include/firebird/Crypt.h 2012-05-31 12:55:40 UTC (rev 54573)
+++ firebird/trunk/src/include/firebird/Crypt.h 2012-05-31 16:53:42 UTC (rev 54574)
@@ -27,26 +27,71 @@
namespace Firebird {
-class ICrypt : public IRefCounted
+// Part 1. Network crypt.
+
+// 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:
- virtual void FB_CARG transform(IStatus* status, unsigned int length, const void* from, void* to) = 0;
+ // 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 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_VERSION (FB_REFCOUNTED_VERSION + 1)
+#define FB_WIRECRYPT_PLUGIN_VERSION (FB_PLUGIN_VERSION + 4)
-class ICryptPlugin : public IPluginBase
+// 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:
- // 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 unsigned int FB_CARG callback(unsigned int dataLength, const void* data,
+ unsigned int bufferLength, void* buffer) = 0;
};
-#define FB_CRYPT_PLUGIN_VERSION (FB_PLUGIN_VERSION + 3)
+#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
Modified: firebird/trunk/src/include/firebird/Interface.h
===================================================================
--- firebird/trunk/src/include/firebird/Interface.h 2012-05-31 12:55:40 UTC (rev 54573)
+++ firebird/trunk/src/include/firebird/Interface.h 2012-05-31 16:53:42 UTC (rev 54574)
@@ -113,8 +113,11 @@
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
Modified: firebird/trunk/src/include/firebird/Plugin.h
===================================================================
--- firebird/trunk/src/include/firebird/Plugin.h 2012-05-31 12:55:40 UTC (rev 54573)
+++ firebird/trunk/src/include/firebird/Plugin.h 2012-05-31 16:53:42 UTC (rev 54574)
@@ -220,9 +220,11 @@
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
Modified: firebird/trunk/src/include/firebird/Provider.h
===================================================================
--- firebird/trunk/src/include/firebird/Provider.h 2012-05-31 12:55:40 UTC (rev 54573)
+++ firebird/trunk/src/include/firebird/Provider.h 2012-05-31 16:53:42 UTC (rev 54574)
@@ -36,6 +36,7 @@
// 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 @@
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
Modified: firebird/trunk/src/include/gen/ids.h
===================================================================
--- firebird/trunk/src/include/gen/ids.h 2012-05-31 12:55:40 UTC (rev 54573)
+++ firebird/trunk/src/include/gen/ids.h 2012-05-31 16:53:42 UTC (rev 54574)
@@ -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)
Modified: firebird/trunk/src/jrd/Attachment.cpp
===================================================================
--- firebird/trunk/src/jrd/Attachment.cpp 2012-05-31 12:55:40 UTC (rev 54573)
+++ firebird/trunk/src/jrd/Attachment.cpp 2012-05-31 16:53:42 UTC (rev 54574)
@@ -368,11 +368,7 @@
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;
}
Modified: firebird/trunk/src/jrd/Attachment.h
===================================================================
--- firebird/trunk/src/jrd/Attachment.h 2012-05-31 12:55:40 UTC (rev 54573)
+++ firebird/trunk/src/jrd/Attachment.h 2012-05-31 16:53:42 UTC (rev 54574)
@@ -44,6 +44,10 @@
class Connection;
}
+namespace Firebird {
+ class ICryptKeyCallback;
+}
+
class CharSetContainer;
namespace Jrd
@@ -273,6 +277,7 @@
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);
Modified: firebird/trunk/src/jrd/Collation.cpp
===================================================================
--- firebird/trunk/src/jrd/Collation.cpp 2012-05-31 12:55:40 UTC (rev 54573)
+++ firebird/trunk/src/jrd/Collation.cpp 2012-05-31 16:53:42 UTC (rev 54574)
@@ -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"
Modified: firebird/trunk/src/jrd/Collation.h
===================================================================
--- firebird/trunk/src/jrd/Collation.h 2012-05-31 12:55:40 UTC (rev 54573)
+++ firebird/trunk/src/jrd/Collation.h 2012-05-31 16:53:42 UTC (rev 54574)
@@ -36,6 +36,7 @@
namespace Jrd {
class Lock;
+class BaseSubstringSimilarMatcher;
class Collation : public TextType
{
Added: firebird/trunk/src/jrd/CryptoManager.cpp
===================================================================
--- firebird/trunk/src/jrd/CryptoManager.cpp (rev 0)
+++ firebird/trunk/src/jrd/CryptoManager.cpp 2012-05-31 16:53:42 UTC (rev 54574)
@@ -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::h...
[truncated message content] |