From b692e85f567e18137a6e8d1e0189df75deb09457 Mon Sep 17 00:00:00 2001 From: alexpeshkoff Date: Tue, 30 Jun 2015 16:01:10 +0000 Subject: [PATCH] Implemented CORE-4851: Apply methods, used for cross security database authentication, to the trace --- src/include/consts_pub.h | 1 + src/jrd/Attachment.h | 1 + src/jrd/Database.h | 5 ++- src/jrd/EngineInterface.h | 7 ++- src/jrd/Mapping.cpp | 9 ++-- src/jrd/jrd.cpp | 30 ++++++++----- src/jrd/svc.h | 2 + src/jrd/trace/TraceCmdLine.cpp | 26 +++-------- src/jrd/trace/TraceConfigStorage.cpp | 8 ++++ src/jrd/trace/TraceConfigStorage.h | 1 + src/jrd/trace/TraceManager.cpp | 55 ++++++++++++++++++++++- src/jrd/trace/TraceService.cpp | 11 +++-- src/jrd/trace/TraceService.h | 5 ++- src/jrd/trace/TraceSession.h | 4 ++ src/remote/server/server.cpp | 4 ++ src/utilities/fbtracemgr/traceMgrMain.cpp | 8 ++-- 16 files changed, 129 insertions(+), 48 deletions(-) diff --git a/src/include/consts_pub.h b/src/include/consts_pub.h index 3b7c7b1fe0..683a8736b5 100644 --- a/src/include/consts_pub.h +++ b/src/include/consts_pub.h @@ -122,6 +122,7 @@ #define isc_dpb_config 87 #define isc_dpb_nolinger 88 #define isc_dpb_reset_icu 89 +#define isc_dpb_map_attach 90 /**************************************************/ /* clumplet tags used inside isc_dpb_address_path */ diff --git a/src/jrd/Attachment.h b/src/jrd/Attachment.h index 3353bc0c3f..ff2b9e3a5b 100644 --- a/src/jrd/Attachment.h +++ b/src/jrd/Attachment.h @@ -480,6 +480,7 @@ const ULONG ATT_system = 0x04000L; // Special system attachment const ULONG ATT_creator = 0x08000L; // This attachment created the DB const ULONG ATT_monitor_done = 0x10000L; // Monitoring data is refreshed const ULONG ATT_security_db = 0x20000L; // Attachment used for security purposes +const ULONG ATT_mapping = 0x40000L; // Attachment used for mapping auth block const ULONG ATT_NO_CLEANUP = (ATT_no_cleanup | ATT_notify_gc); diff --git a/src/jrd/Database.h b/src/jrd/Database.h index 41bae2a73b..1b26de177d 100644 --- a/src/jrd/Database.h +++ b/src/jrd/Database.h @@ -79,6 +79,7 @@ class ExternalFileDirectoryList; class MonitoringData; class GarbageCollector; class CryptoManager; +class JProvider; // general purpose vector template @@ -330,12 +331,13 @@ public: bool active; }; - static Database* create(Firebird::IPluginConfig* pConf, bool shared) + static Database* create(Firebird::IPluginConfig* pConf, JProvider* provider, bool shared) { Firebird::MemoryStats temp_stats; MemoryPool* const pool = MemoryPool::createPool(NULL, temp_stats); Database* const dbb = FB_NEW(*pool) Database(pool, pConf, shared); pool->setStatsGroup(dbb->dbb_memory_stats); + dbb->dbb_provider = provider; return dbb; } @@ -375,6 +377,7 @@ public: LockManager* dbb_lock_mgr; EventManager* dbb_event_mgr; + JProvider* dbb_provider; Database* dbb_next; // Next database block in system Attachment* dbb_attachments; // Active attachments Attachment* dbb_sys_attachments; // System attachments diff --git a/src/jrd/EngineInterface.h b/src/jrd/EngineInterface.h index e1a0573108..02e39b39a4 100644 --- a/src/jrd/EngineInterface.h +++ b/src/jrd/EngineInterface.h @@ -409,6 +409,11 @@ public: return p; } + Firebird::ICryptKeyCallback* getCryptCallback() + { + return cryptCallback; + } + // IProvider implementation JAttachment* attachDatabase(Firebird::CheckStatusWrapper* status, const char* fileName, unsigned int dpbLength, const unsigned char* dpb); @@ -418,7 +423,7 @@ public: unsigned int spbLength, const unsigned char* spb); void shutdown(Firebird::CheckStatusWrapper* status, unsigned int timeout, const int reason); void setDbCryptCallback(Firebird::CheckStatusWrapper* status, - Firebird::ICryptKeyCallback* cryptCallback); + Firebird::ICryptKeyCallback* cryptCb); int release(); diff --git a/src/jrd/Mapping.cpp b/src/jrd/Mapping.cpp index bcce51a438..8d48f586fc 100644 --- a/src/jrd/Mapping.cpp +++ b/src/jrd/Mapping.cpp @@ -921,6 +921,7 @@ void mapUser(string& name, string& trusted_role, Firebird::string* auth_method, embeddedSysdba.insertString(isc_dpb_user_name, SYSDBA_USER_NAME, fb_strlen(SYSDBA_USER_NAME)); embeddedSysdba.insertByte(isc_dpb_sec_attach, TRUE); + embeddedSysdba.insertByte(isc_dpb_map_attach, TRUE); embeddedSysdba.insertByte(isc_dpb_no_db_triggers, TRUE); if (!iSec) @@ -966,10 +967,12 @@ void mapUser(string& name, string& trusted_role, Firebird::string* auth_method, if (db) cDb = locate(alias, db); Cache* cSec = locate(securityAlias, securityDb); + if (cDb == cSec) + cDb = NULL; - SyncObject dummySync; - Sync sDb((!(flags & FLAG_DB)) ? &cDb->syncObject : &dummySync, FB_FUNCTION); - Sync sSec((!(flags & FLAG_SEC)) ? &cSec->syncObject : &dummySync, FB_FUNCTION); + SyncObject dummySync1, dummySync2; + Sync sDb(((!(flags & FLAG_DB)) && cDb) ? &cDb->syncObject : &dummySync1, FB_FUNCTION); + Sync sSec((!(flags & FLAG_SEC)) ? &cSec->syncObject : &dummySync2, FB_FUNCTION); sSec.lock(syncType); if (!sDb.lockConditional(syncType)) diff --git a/src/jrd/jrd.cpp b/src/jrd/jrd.cpp index 4fbc480734..1610cee816 100644 --- a/src/jrd/jrd.cpp +++ b/src/jrd/jrd.cpp @@ -747,7 +747,7 @@ namespace DefaultCallback defCallback; - ICryptKeyCallback* getCryptCallback(ICryptKeyCallback* callback) + ICryptKeyCallback* getDefCryptCallback(ICryptKeyCallback* callback) { return callback ? callback : &defCallback; } @@ -904,6 +904,7 @@ public: ULONG dpb_flags; // to OR'd with dbb_flags bool dpb_nolinger; bool dpb_reset_icu; + bool dpb_map_attach; // here begin compound objects // for constructor to work properly dpb_user_name @@ -1015,7 +1016,7 @@ static VdnResult verifyDatabaseName(const PathName&, FbStatusVector*, bool); static void unwindAttach(thread_db* tdbb, const Exception& ex, FbStatusVector* userStatus, Jrd::Attachment* attachment, Database* dbb, unsigned internalFlags); static JAttachment* initAttachment(thread_db*, const PathName&, const PathName&, RefPtr, bool, - const DatabaseOptions&, RefMutexUnlock&, IPluginConfig*); + const DatabaseOptions&, RefMutexUnlock&, IPluginConfig*, JProvider*); static JAttachment* create_attachment(const PathName&, Database*, const DatabaseOptions&, bool newDb); static void prepare_tra(thread_db*, jrd_tra*, USHORT, const UCHAR*); static void start_transaction(thread_db* tdbb, bool transliterate, jrd_tra** tra_handle, @@ -1467,7 +1468,7 @@ JAttachment* JProvider::internalAttach(CheckStatusWrapper* user_status, const ch RefMutexUnlock initGuard; JAttachment* jAtt = initAttachment(tdbb, expanded_name, is_alias ? org_filename : expanded_name, - config, true, options, initGuard, pluginConfig); + config, true, options, initGuard, pluginConfig, this); dbb = tdbb->getDatabase(); fb_assert(dbb); @@ -1483,13 +1484,15 @@ JAttachment* JProvider::internalAttach(CheckStatusWrapper* user_status, const ch EngineContextHolder tdbb(user_status, jAtt, FB_FUNCTION, AttachmentHolder::ATT_DONT_LOCK); - attachment->att_crypt_callback = getCryptCallback(cryptCallback); + attachment->att_crypt_callback = getDefCryptCallback(cryptCallback); attachment->att_client_charset = attachment->att_charset = options.dpb_interp; if (options.dpb_no_garbage) attachment->att_flags |= ATT_no_cleanup; if (options.dpb_sec_attach) attachment->att_flags |= ATT_security_db; + if (options.dpb_map_attach) + attachment->att_flags |= ATT_mapping; if (options.dpb_gbak_attach) attachment->att_utility = Attachment::UTIL_GBAK; @@ -2492,7 +2495,7 @@ JAttachment* JProvider::createDatabase(CheckStatusWrapper* user_status, const ch RefMutexUnlock initGuard; JAttachment* jAtt = initAttachment(tdbb, expanded_name, is_alias ? org_filename : expanded_name, - config, false, options, initGuard, pluginConfig); + config, false, options, initGuard, pluginConfig, this); dbb = tdbb->getDatabase(); fb_assert(dbb); @@ -2506,13 +2509,15 @@ JAttachment* JProvider::createDatabase(CheckStatusWrapper* user_status, const ch EngineContextHolder tdbb(user_status, jAtt, FB_FUNCTION, AttachmentHolder::ATT_DONT_LOCK); - attachment->att_crypt_callback = getCryptCallback(cryptCallback); + attachment->att_crypt_callback = getDefCryptCallback(cryptCallback); if (options.dpb_working_directory.hasData()) attachment->att_working_directory = options.dpb_working_directory; if (options.dpb_sec_attach) attachment->att_flags |= ATT_security_db; + if (options.dpb_map_attach) + attachment->att_flags |= ATT_mapping; if (options.dpb_gbak_attach) attachment->att_utility = Attachment::UTIL_GBAK; @@ -4120,10 +4125,10 @@ void JProvider::shutdown(CheckStatusWrapper* status, unsigned int timeout, const } -void JProvider::setDbCryptCallback(CheckStatusWrapper* status, ICryptKeyCallback* callback) +void JProvider::setDbCryptCallback(CheckStatusWrapper* status, ICryptKeyCallback* cryptCb) { status->init(); - cryptCallback = callback; + cryptCallback = cryptCb; } @@ -5843,6 +5848,10 @@ void DatabaseOptions::get(const UCHAR* dpb, USHORT dpb_length, bool& invalid_cli dpb_sec_attach = rdr.getInt() != 0; break; + case isc_dpb_map_attach: + dpb_map_attach = true; + break; + case isc_dpb_gbak_attach: { string gbakStr; @@ -5977,7 +5986,8 @@ void DatabaseOptions::get(const UCHAR* dpb, USHORT dpb_length, bool& invalid_cli static JAttachment* initAttachment(thread_db* tdbb, const PathName& expanded_name, const PathName& alias_name, RefPtr config, bool attach_flag, - const DatabaseOptions& options, RefMutexUnlock& initGuard, IPluginConfig* pConf) + const DatabaseOptions& options, RefMutexUnlock& initGuard, IPluginConfig* pConf, + JProvider* provider) { /************************************** * @@ -6100,7 +6110,7 @@ static JAttachment* initAttachment(thread_db* tdbb, const PathName& expanded_nam Config::merge(config, &options.dpb_config); - dbb = Database::create(pConf, shared); + dbb = Database::create(pConf, provider, shared); dbb->dbb_config = config; dbb->dbb_filename = expanded_name; #ifdef HAVE_ID_BY_NAME diff --git a/src/jrd/svc.h b/src/jrd/svc.h index 60eef11752..cc8f809f7b 100644 --- a/src/jrd/svc.h +++ b/src/jrd/svc.h @@ -194,6 +194,8 @@ public: // external interface with service const Firebird::string& getRemoteAddress() const { return svc_remote_address; } const Firebird::string& getRemoteProcess() const { return svc_remote_process; } int getRemotePID() const { return svc_remote_pid; } + const Firebird::PathName& getExpectedDb() const { return svc_expected_db; } + Firebird::ICryptKeyCallback* getCryptCallback() { return svc_crypt_callback; } private: // Service must have private destructor, called from finish diff --git a/src/jrd/trace/TraceCmdLine.cpp b/src/jrd/trace/TraceCmdLine.cpp index 3acd6f6195..9b50f09daa 100644 --- a/src/jrd/trace/TraceCmdLine.cpp +++ b/src/jrd/trace/TraceCmdLine.cpp @@ -399,35 +399,19 @@ void fbtrace(UtilSvc* uSvc, TraceSvcIntf* traceSvc) } } - // This is a temporal hack!!! - // AuthBlock should be passed inside trace and used on per-database basis - // to make sure which attachments may be traced. + AuthReader::AuthBlock authBlock; const unsigned char* bytes; unsigned int authBlockSize = uSvc->getAuthBlock(&bytes); if (authBlockSize) { - AuthReader::AuthBlock authBlock; authBlock.add(bytes, authBlockSize); - AuthReader auth(authBlock); - AuthReader::Info info; - - if (auth.getInfo(info)) - { - pwd = ""; - user = info.name.ToString(); - adminRole = false; - - if (!info.secDb.hasData()) - { - auth.moveNext(); - if (auth.getInfo(info)) - adminRole = true; - } - } + pwd = ""; + user = ""; + adminRole = false; } - traceSvc->setAttachInfo(svc_name, user, pwd, adminRole); + traceSvc->setAttachInfo(svc_name, user, pwd, authBlock, adminRole); switch (action_sw->in_sw) { diff --git a/src/jrd/trace/TraceConfigStorage.cpp b/src/jrd/trace/TraceConfigStorage.cpp index 28bf5aaf99..5e370d98ff 100644 --- a/src/jrd/trace/TraceConfigStorage.cpp +++ b/src/jrd/trace/TraceConfigStorage.cpp @@ -336,6 +336,9 @@ void ConfigStorage::addSession(TraceSession& session) if (!session.ses_name.empty()) { putItem(tagName, session.ses_name.length(), session.ses_name.c_str()); } + if (session.ses_auth.hasData()) { + putItem(tagAuthBlock, session.ses_auth.getCount(), session.ses_auth.begin()); + } putItem(tagUserName, session.ses_user.length(), session.ses_user.c_str()); putItem(tagFlags, sizeof(session.ses_flags), &session.ses_flags); putItem(tagConfig, session.ses_config.length(), session.ses_config.c_str()); @@ -409,6 +412,11 @@ bool ConfigStorage::getNextSession(TraceSession& session) p = session.ses_logfile.getBuffer(len); break; + case tagAuthBlock: + if (session.ses_id) + p = session.ses_auth.getBuffer(len); + break; + default: fb_assert(false); } diff --git a/src/jrd/trace/TraceConfigStorage.h b/src/jrd/trace/TraceConfigStorage.h index cf6e31771a..504774f564 100644 --- a/src/jrd/trace/TraceConfigStorage.h +++ b/src/jrd/trace/TraceConfigStorage.h @@ -109,6 +109,7 @@ private: { tagID = 1, // session ID tagName, // session Name + tagAuthBlock, // with which creator logged in tagUserName, // creator user name tagFlags, // session flags tagConfig, // configuration diff --git a/src/jrd/trace/TraceManager.cpp b/src/jrd/trace/TraceManager.cpp index 79f8080203..34efdec812 100644 --- a/src/jrd/trace/TraceManager.cpp +++ b/src/jrd/trace/TraceManager.cpp @@ -30,10 +30,12 @@ #include "../../jrd/trace/TraceManager.h" #include "../../jrd/trace/TraceObjects.h" +#include "../../jrd/Mapping.h" #include "../../common/os/path_utils.h" #include "../../common/ScanDir.h" #include "../../common/isc_proto.h" #include "../../common/classes/GetPlugins.h" +#include "../../common/db_alias.h" #ifdef WIN_NT #include @@ -223,12 +225,61 @@ void TraceManager::update_session(const TraceSession& session) { if (attachment) { - if (!attachment->att_user || attachment->att_user->usr_user_name != session.ses_user) + if ((!attachment->att_user) || (attachment->att_flags & ATT_mapping)) return; + + string s_user = session.ses_user; + string t_role; + if (session.ses_auth.hasData()) + { + Database* dbb = attachment->att_database; + fb_assert(dbb); + + try + { + mapUser(s_user, t_role, NULL, NULL, session.ses_auth, + attachment->att_filename.c_str(), dbb->dbb_filename.c_str(), + dbb->dbb_config->getSecurityDatabase(), + dbb->dbb_provider->getCryptCallback()); + } + catch(const Firebird::Exception&) + { + // Error in mapUser() means missing context, therefore... + return; + } + t_role.upper(); + } + + if (s_user != SYSDBA_USER_NAME && t_role != ADMIN_ROLE && + attachment->att_user->usr_user_name != s_user) + { + return; + } } else if (service) { - if (session.ses_user != service->getUserName()) + string s_user = session.ses_user; + string t_role; + if (session.ses_auth.hasData()) + { + PathName dummy; + RefPtr config; + expandDatabaseName(service->getExpectedDb(), dummy, &config); + + try + { + mapUser(s_user, t_role, NULL, NULL, session.ses_auth, "services manager", NULL, + config->getSecurityDatabase(), service->getCryptCallback()); + } + catch(const Firebird::Exception&) + { + // Error in mapUser() means missing context, therefore... + return; + } + t_role.upper(); + } + + if (s_user != SYSDBA_USER_NAME && t_role != ADMIN_ROLE && service->getUserName() != s_user) return; } else diff --git a/src/jrd/trace/TraceService.cpp b/src/jrd/trace/TraceService.cpp index 3bc0a1e5ca..8977864dc5 100644 --- a/src/jrd/trace/TraceService.cpp +++ b/src/jrd/trace/TraceService.cpp @@ -54,8 +54,8 @@ public: virtual ~TraceSvcJrd() {}; - virtual void setAttachInfo(const string& service_name, const string& user, - const string& pwd, bool isAdmin); + virtual void setAttachInfo(const string& service_name, const string& user, const string& pwd, + const AuthReader::AuthBlock& authBlock, bool isAdmin); virtual void startSession(TraceSession& session, bool interactive); virtual void stopSession(ULONG id); @@ -69,13 +69,15 @@ private: Service& m_svc; string m_user; + AuthReader::AuthBlock m_authBlock; bool m_admin; ULONG m_chg_number; }; -void TraceSvcJrd::setAttachInfo(const string& /*service_name*/, const string& user, - const string& /*pwd*/, bool isAdmin) +void TraceSvcJrd::setAttachInfo(const string& /*svc_name*/, const string& user, const string& pwd, + const AuthReader::AuthBlock& authBlock, bool isAdmin) { + m_authBlock = authBlock; m_user = user; m_admin = isAdmin || (m_user == SYSDBA_USER_NAME); } @@ -93,6 +95,7 @@ void TraceSvcJrd::startSession(TraceSession& session, bool interactive) { // scope StorageGuard guard(storage); + session.ses_auth = m_authBlock; session.ses_user = m_user; session.ses_flags = trs_active; diff --git a/src/jrd/trace/TraceService.h b/src/jrd/trace/TraceService.h index 504e6ecaf1..1582909917 100644 --- a/src/jrd/trace/TraceService.h +++ b/src/jrd/trace/TraceService.h @@ -32,6 +32,7 @@ #include "fb_exception.h" #include "iberror.h" #include "../../common/classes/fb_string.h" +#include "../../common/classes/ClumpletReader.h" #include "../../common/StatusArg.h" #include "../../common/UtilSvc.h" #include "../../jrd/constants.h" @@ -47,8 +48,8 @@ namespace Firebird { class TraceSvcIntf { public: - virtual void setAttachInfo(const string& service_name, const string& user, - const string& pwd, bool isAdmin) = 0; + virtual void setAttachInfo(const string& service_name, const string& user, const string& pwd, + const AuthReader::AuthBlock& authBlock, bool isAdmin) = 0; virtual void startSession(TraceSession& session, bool interactive) = 0; virtual void stopSession(ULONG id) = 0; diff --git a/src/jrd/trace/TraceSession.h b/src/jrd/trace/TraceSession.h index d0f3412d47..bc4116f9fe 100644 --- a/src/jrd/trace/TraceSession.h +++ b/src/jrd/trace/TraceSession.h @@ -31,6 +31,7 @@ #include "firebird.h" #include "../../common/classes/fb_string.h" +#include "../../common/classes/ClumpletReader.h" namespace Firebird { @@ -46,6 +47,7 @@ public: explicit TraceSession(MemoryPool& pool) : ses_id(0), ses_name(pool), + ses_auth(pool), ses_user(pool), ses_config(pool), ses_start(0), @@ -59,6 +61,7 @@ public: { ses_id = 0; ses_name = ""; + ses_auth.clear(); ses_user = ""; ses_config = ""; ses_start = 0; @@ -68,6 +71,7 @@ public: ULONG ses_id; string ses_name; + AuthReader::AuthBlock ses_auth; string ses_user; string ses_config; time_t ses_start; diff --git a/src/remote/server/server.cpp b/src/remote/server/server.cpp index bc1dff85a6..bb51348f1e 100644 --- a/src/remote/server/server.cpp +++ b/src/remote/server/server.cpp @@ -2167,6 +2167,10 @@ void DatabaseAuth::accept(PACKET* send, Auth::WriterImplementation* authBlock) case isc_dpb_password: case isc_dpb_password_enc: + // remove tags for specific internal attaches + case isc_dpb_map_attach: + case isc_dpb_sec_attach: + // remove client's config information case isc_dpb_config: pb->deleteClumplet(); diff --git a/src/utilities/fbtracemgr/traceMgrMain.cpp b/src/utilities/fbtracemgr/traceMgrMain.cpp index b573aa9250..8a53794b8c 100644 --- a/src/utilities/fbtracemgr/traceMgrMain.cpp +++ b/src/utilities/fbtracemgr/traceMgrMain.cpp @@ -47,8 +47,8 @@ public: TraceSvcUtil(); virtual ~TraceSvcUtil(); - virtual void setAttachInfo(const string& service_name, const string& user, - const string& pwd, bool isAdmin); + virtual void setAttachInfo(const string& service_name, const string& user, const string& pwd, + const AuthReader::AuthBlock& authBlock, bool isAdmin); virtual void startSession(TraceSession& session, bool interactive); virtual void stopSession(ULONG id); @@ -83,8 +83,8 @@ TraceSvcUtil::~TraceSvcUtil() } } -void TraceSvcUtil::setAttachInfo(const string& service_name, const string& user, - const string& pwd, bool isAdmin) +void TraceSvcUtil::setAttachInfo(const string& service_name, const string& user, const string& pwd, + const AuthReader::AuthBlock& /*authBlock*/, bool isAdmin) { ISC_STATUS_ARRAY status = {0};