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

Implemented CORE-4851: Apply methods, used for cross security database authentication, to the trace

This commit is contained in:
alexpeshkoff 2015-06-30 16:01:10 +00:00
parent 5a9ae4a65b
commit b692e85f56
16 changed files with 129 additions and 48 deletions

View File

@ -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 */

View File

@ -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);

View File

@ -79,6 +79,7 @@ class ExternalFileDirectoryList;
class MonitoringData;
class GarbageCollector;
class CryptoManager;
class JProvider;
// general purpose vector
template <class T, BlockType TYPE = type_vec>
@ -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

View File

@ -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();

View File

@ -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))

View File

@ -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<Config>, 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> 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

View File

@ -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

View File

@ -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)
{

View File

@ -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);
}

View File

@ -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

View File

@ -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 <process.h>
@ -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> 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

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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();

View File

@ -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};