Skip to content

Commit

Permalink
Fixed bug CORE-5995 : Creator user name is empty in user trace sessions
Browse files Browse the repository at this point in the history
  • Loading branch information
hvlad committed Jan 30, 2019
1 parent 2b3682c commit d8ad276
Show file tree
Hide file tree
Showing 7 changed files with 121 additions and 59 deletions.
6 changes: 6 additions & 0 deletions src/jrd/svc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -806,6 +806,7 @@ Service::Service(const TEXT* service_name, USHORT spb_length, const UCHAR* spb_d
mapping.needAuthBlock(svc_auth_block);

mapping.setAuthBlock(svc_auth_block);
mapping.setSqlRole(svc_sql_role);
mapping.setErrorMessagesContextName("services manager");
mapping.setSecurityDbAlias(config->getSecurityDatabase(), nullptr);

Expand Down Expand Up @@ -3217,3 +3218,8 @@ const char* Service::getServiceName() const
{
return svc_service_run ? svc_service_run->serv_name : NULL;
}

bool Service::getUserAdminFlag() const
{
return (svc_user_flag & SVC_user_dba);
}
9 changes: 9 additions & 0 deletions src/jrd/svc.h
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,15 @@ class Service : public Firebird::UtilSvc, public TypedHandle<type_svc>
return svc_username;
}

const Firebird::string& getRoleName() const
{
return svc_sql_role;
}

// return true if user have admin privileges in security database used
// for service user authentication
bool getUserAdminFlag() const;

const Firebird::string& getNetworkProtocol() const { return svc_network_protocol; }
const Firebird::string& getRemoteAddress() const { return svc_remote_address; }
const Firebird::string& getRemoteProcess() const { return svc_remote_process; }
Expand Down
16 changes: 3 additions & 13 deletions src/jrd/trace/TraceCmdLine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -263,7 +263,7 @@ void fbtrace(UtilSvc* uSvc, TraceSvcIntf* traceSvc)
const Switches authSwitches(trace_auth_in_sw_table, FB_NELEM(trace_auth_in_sw_table),
false, true);
string svc_name, user, role, pwd;
bool adminRole = false;
bool trusted = false;
for (int itr = 1; itr < argc; ++itr)
{
if (!argv[itr])
Expand Down Expand Up @@ -350,7 +350,7 @@ void fbtrace(UtilSvc* uSvc, TraceSvcIntf* traceSvc)
if (uSvc->isService())
usage(uSvc, isc_trace_switch_user_only, sw->in_sw_name);

adminRole = true;
trusted = true;
break;

case IN_SW_TRACE_SERVICE_NAME:
Expand Down Expand Up @@ -396,19 +396,9 @@ void fbtrace(UtilSvc* uSvc, TraceSvcIntf* traceSvc)
}
}

AuthReader::AuthBlock authBlock;
const unsigned char* bytes;
unsigned int authBlockSize = uSvc->getAuthBlock(&bytes);
if (authBlockSize)
{
authBlock.add(bytes, authBlockSize);

pwd = "";
user = "";
adminRole = false;
}

traceSvc->setAttachInfo(svc_name, user, role, pwd, authBlock, adminRole);
traceSvc->setAttachInfo(svc_name, user, role, pwd, trusted);

switch (action_sw->in_sw)
{
Expand Down
56 changes: 25 additions & 31 deletions src/jrd/trace/TraceManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -243,18 +243,22 @@ void TraceManager::update_session(const TraceSession& session)

// if this session is not from administrator, it may trace connections
// only created by the same user
if (!(session.ses_flags & trs_admin))
if (!(session.ses_flags & (trs_admin | trs_system)))
{
const char* curr_user = nullptr;
string s_user = session.ses_user;
string t_role;
UserId::Privileges priv;
ULONG mapResult = 0;

if (attachment)
{
if ((!attachment->att_user) || (attachment->att_flags & ATT_mapping))
return;

string s_user = session.ses_user;
string t_role;
UserId::Privileges priv;
ULONG mapResult;
curr_user = attachment->att_user->getUserName().c_str();

if (session.ses_auth.hasData())
{ // scope
AutoSetRestoreFlag<ULONG> autoRestore(&attachment->att_flags, ATT_mapping, true);

Expand All @@ -269,25 +273,10 @@ void TraceManager::update_session(const TraceSession& session)
attachment->getInterface());
mapResult = mapping.mapUser(s_user, t_role);
}

if (session.ses_auth.hasData())
{
if (mapResult & Mapping::MAP_ERROR_NOT_THROWN)
return; // Error in mapUser() means missing context

t_role.upper();
}

if (s_user != DBA_USER_NAME && t_role != ADMIN_ROLE &&
attachment->att_user->getUserName() != s_user && (!priv.test(TRACE_ANY_ATTACHMENT)))
{
return;
}
}
else if (service)
{
string s_user = session.ses_user;
string t_role;
curr_user = service->getUserName().c_str();

if (session.ses_auth.hasData())
{
Expand All @@ -296,28 +285,33 @@ void TraceManager::update_session(const TraceSession& session)
expandDatabaseName(service->getExpectedDb(), dummy, &config);

Mapping mapping(Mapping::MAP_NO_FLAGS, service->getCryptCallback());
mapping.needSystemPrivileges(priv);
mapping.setAuthBlock(session.ses_auth);
mapping.setErrorMessagesContextName("services manager");
mapping.setSqlRole(session.ses_role);
mapping.setSecurityDbAlias(config->getSecurityDatabase(), nullptr);

if (mapping.mapUser(s_user, t_role) & Mapping::MAP_ERROR_NOT_THROWN)
{
// Error in mapUser() means missing context, therefore...
return;
}

t_role.upper();
mapResult = mapping.mapUser(s_user, t_role);
}

if (s_user != DBA_USER_NAME && t_role != ADMIN_ROLE && service->getUserName() != s_user)
return;
}
else
{
// failed attachment attempts traced by admin trace only
return;
}

if (mapResult & Mapping::MAP_ERROR_NOT_THROWN)
{
// Error in mapUser() means missing context, therefore...
return;
}

t_role.upper();
if (s_user != DBA_USER_NAME && t_role != ADMIN_ROLE &&
s_user != curr_user && (!priv.test(TRACE_ANY_ATTACHMENT)))
{
return;
}
}

for (FactoryInfo* info = factories->begin(); info != factories->end(); ++info)
Expand Down
85 changes: 74 additions & 11 deletions src/jrd/trace/TraceService.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,14 @@
#include "../../common/config/config.h"
#include "../../common/StatusArg.h"
#include "../../common/ThreadStart.h"
#include "../../common/db_alias.h"
#include "../../jrd/svc.h"
#include "../../common/os/guid.h"
#include "../../jrd/trace/TraceLog.h"
#include "../../jrd/trace/TraceManager.h"
#include "../../jrd/trace/TraceService.h"
#include "../../jrd/scl.h"
#include "../../jrd/Mapping.h"

using namespace Firebird;
using namespace Jrd;
Expand All @@ -56,7 +58,7 @@ class TraceSvcJrd : public TraceSvcIntf
virtual ~TraceSvcJrd() {};

virtual void setAttachInfo(const string& service_name, const string& user, const string& role,
const string& pwd, const AuthReader::AuthBlock& authBlock, bool isAdmin);
const string& pwd, bool trusted);

virtual void startSession(TraceSession& session, bool interactive);
virtual void stopSession(ULONG id);
Expand All @@ -68,6 +70,9 @@ class TraceSvcJrd : public TraceSvcIntf
bool changeFlags(ULONG id, int setFlags, int clearFlags);
bool checkAliveAndFlags(ULONG sesId, int& flags);

// Check if current service is allowed to list\stop given other session
bool checkPrivileges(TraceSession& session);

Service& m_svc;
string m_user;
string m_role;
Expand All @@ -77,12 +82,23 @@ class TraceSvcJrd : public TraceSvcIntf
};

void TraceSvcJrd::setAttachInfo(const string& /*svc_name*/, const string& user, const string& role,
const string& pwd, const AuthReader::AuthBlock& authBlock, bool isAdmin)
const string& /*pwd*/, bool /*trusted*/)
{
m_authBlock = authBlock;
m_user = user;
m_role = role;
m_admin = isAdmin || (m_user == DBA_USER_NAME);
const unsigned char* bytes;
unsigned int authBlockSize = m_svc.getAuthBlock(&bytes);
if (authBlockSize)
{
m_authBlock.add(bytes, authBlockSize);
m_user = "";
m_role = "";
m_admin = false;
}
else
{
m_user = user;
m_role = role;
m_admin = (m_user == DBA_USER_NAME) || (m_role == ADMIN_ROLE);
}
}

void TraceSvcJrd::startSession(TraceSession& session, bool interactive)
Expand All @@ -99,8 +115,8 @@ void TraceSvcJrd::startSession(TraceSession& session, bool interactive)
StorageGuard guard(storage);

session.ses_auth = m_authBlock;
session.ses_user = m_user;
MetaName role = m_role;
session.ses_user = m_user.hasData() ? m_user : m_svc.getUserName();
MetaName role = m_role.hasData() ? m_role : m_svc.getRoleName();
UserId::makeRoleName(role, SQL_DIALECT_V6);
session.ses_role = role.c_str();

Expand Down Expand Up @@ -152,7 +168,7 @@ void TraceSvcJrd::stopSession(ULONG id)
if (id != session.ses_id)
continue;

if (m_admin || m_user == session.ses_user)
if (checkPrivileges(session))
{
storage->removeSession(id);
m_svc.printf(false, "Trace session ID %ld stopped\n", id);
Expand Down Expand Up @@ -195,7 +211,7 @@ bool TraceSvcJrd::changeFlags(ULONG id, int setFlags, int clearFlags)
if (id != session.ses_id)
continue;

if (m_admin || m_user == session.ses_user)
if (checkPrivileges(session))
{
const int saveFlags = session.ses_flags;

Expand Down Expand Up @@ -229,7 +245,7 @@ void TraceSvcJrd::listSessions()
TraceSession session(*getDefaultMemoryPool());
while (storage->getNextSession(session))
{
if (m_admin || m_user == session.ses_user)
if (checkPrivileges(session))
{
m_svc.printf(false, "\nSession ID: %d\n", session.ses_id);
if (!session.ses_name.empty()) {
Expand Down Expand Up @@ -337,6 +353,53 @@ bool TraceSvcJrd::checkAliveAndFlags(ULONG sesId, int& flags)
return alive;
}

bool TraceSvcJrd::checkPrivileges(TraceSession& session)
{
// Our service run in embedded mode and have no auth info - trust user name as is
if (m_admin || m_user.hasData() && (m_user == session.ses_user))
return true;

// Other session is fully authorized - try to map our auth info using other's
// security database
if (session.ses_auth.hasData())
{
AuthReader::Info info;
for (AuthReader rdr(session.ses_auth); rdr.getInfo(info); rdr.moveNext())
{
string s_user, t_role;

PathName dummy;
RefPtr<const Config> config;
expandDatabaseName(info.secDb.hasData() ?
info.secDb.ToPathName() : m_svc.getExpectedDb(), dummy, &config);

Mapping mapping(Mapping::MAP_NO_FLAGS, m_svc.getCryptCallback());
UserId::Privileges priv;
mapping.needSystemPrivileges(priv);
mapping.setAuthBlock(m_authBlock);
mapping.setErrorMessagesContextName("services manager");
mapping.setSqlRole(m_svc.getRoleName());
mapping.setSecurityDbAlias(config->getSecurityDatabase(), nullptr);

if (mapping.mapUser(s_user, t_role) & Mapping::MAP_ERROR_NOT_THROWN)
{
// Error in mapUser() means missing context, therefore...
continue;
}

t_role.upper();

// TODO: add privileges for list\manage sessions and check it here
if (s_user == DBA_USER_NAME || t_role == ADMIN_ROLE || s_user == session.ses_user)
return true;
}
}
// Other session's service run in embedded mode - check our user name as is
else if (m_svc.getUserName() == session.ses_user || m_svc.getUserAdminFlag())
return true;

return false;
}

// service entrypoint
int TRACE_main(UtilSvc* arg)
Expand Down
2 changes: 1 addition & 1 deletion src/jrd/trace/TraceService.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ class TraceSvcIntf
{
public:
virtual void setAttachInfo(const string& service_name, const string& user, const string& role,
const string& pwd, const AuthReader::AuthBlock& authBlock, bool isAdmin) = 0;
const string& pwd, bool trusted) = 0;

virtual void startSession(TraceSession& session, bool interactive) = 0;
virtual void stopSession(ULONG id) = 0;
Expand Down
6 changes: 3 additions & 3 deletions src/utilities/fbtracemgr/traceMgrMain.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ class TraceSvcUtil : public TraceSvcIntf
virtual ~TraceSvcUtil();

virtual void setAttachInfo(const string& service_name, const string& user, const string& role,
const string& pwd, const AuthReader::AuthBlock& authBlock, bool isAdmin);
const string& pwd, bool trusted);

virtual void startSession(TraceSession& session, bool interactive);
virtual void stopSession(ULONG id);
Expand Down Expand Up @@ -85,7 +85,7 @@ TraceSvcUtil::~TraceSvcUtil()
}

void TraceSvcUtil::setAttachInfo(const string& service_name, const string& user, const string& role,
const string& pwd, const AuthReader::AuthBlock& /*authBlock*/, bool isAdmin)
const string& pwd, bool trusted)
{
ISC_STATUS_ARRAY status = {0};

Expand All @@ -100,7 +100,7 @@ void TraceSvcUtil::setAttachInfo(const string& service_name, const string& user,
if (role.hasData()) {
spb.insertString(isc_spb_sql_role_name, role);
}
if (isAdmin) {
if (trusted) {
spb.insertTag(isc_spb_trusted_auth);
}

Expand Down

0 comments on commit d8ad276

Please sign in to comment.