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

Fixed CORE-5892: SQL SECURITY DEFINER context is not properly evaluated for monitoring tables (#196)

* Now we take into account the call hierarchy when use SQL SECURITY
option.
Added new context variable in SYSTEM namespace - EFFICIENT_USER which is
returns user name in which context a code works.
We change efficient user before call procedure and function, fetch a
record from selective procedure and before execute a trigger.

* Renamed new context variable to EFFECTIVE_USER. Fixed nested calls.

* Improved error messages to print effective user when there is no permission.

* Added description of new context variable EFFECTIVE_USER. Improved description of SQL SECURITY clause.
This commit is contained in:
Roman Simakov 2019-03-18 14:17:02 +03:00 committed by Alexander Peshkov
parent b200006ab8
commit bb3c2e94ec
29 changed files with 183 additions and 62 deletions

View File

@ -98,6 +98,9 @@ Usage:
CURRENT_USER | Current user for the connection. Returned value is the
| same as of CURRENT_USER pseudo-variable
|
EFFECTIVE_USER | Effective user for now. It indicates privileges of
| which user is currently used to execute function, procedure, trigger.
|
CURRENT_ROLE | Current role for the connection. Returned value is the
| same as of CURRENT_ROLE pseudo-variable
|

View File

@ -24,7 +24,8 @@ By default INVOKER is used to keep backward compatibility. You can change this b
with SQL STANDARD by using ALTER DATABASE SET DEFAULT SQL SECURITY statement.
If INVOKER is specified a current set of privileges of the current user will be used.
If DEFINER - a set of privileges of object owner will be used to check an access to database objects used by this object.
If DEFINER - a set of privileges of object owner will be used to check an access to database objects
used by this object.
Trigger inherits SQL SECURITY option from TABLE but can overwrite it by explicit specifying. If SQL SECURITY option
will be changed for table, existing triggers without explicitly specified option will not use new value immediately
@ -32,6 +33,19 @@ it will take effect next time trigger will be loaded into metadata cache.
For procedures and functions defined in package explicit SQL SECURITY clause is prohibit.
In stored procedures, functions or triggers you may check which user if really effective and which privileges
are applying to accessed objects by using the system context variable EFFECTIVE_USER from SYSTEM namespace.
select RDB$GET_CONTEXT('SYSTEM', 'EFFECTIVE_USER') from RDB$DATABASE;
Note: now the same object may be called in different security contexts and requires different privileges.
For example we have:
- a stored procedure INV with SQL SECURITY INVOKER which insert records in a table T
- a stored procedure DEF with SQL SECURITY DEFINER defined by SYSDBA
If a user U calls INV an access to T will require an INSERT privile to be granted to U (and EXECUTE on INV of course).
In this case U is EFFECTIVE_USER due INV running.
If user U calls DEF an access to T will require an INSERT privilege to be granted to SYSDBA (end EXECUTE on DEF).
In this case SYSDBA is EFFECTIVE_USER due INV running as well as due DEF running.
Example 1. It's enough to grant only SELECT privilege to user US for table T.
In case of INVOKER it will require also EXECUTE for function F.

View File

@ -1918,6 +1918,8 @@ C --
PARAMETER (GDS__tra_snapshot_does_not_exist = 335545252)
INTEGER*4 GDS__eds_input_prm_not_used
PARAMETER (GDS__eds_input_prm_not_used = 335545253)
INTEGER*4 GDS__effective_user
PARAMETER (GDS__effective_user = 335545254)
INTEGER*4 GDS__gfix_db_name
PARAMETER (GDS__gfix_db_name = 335740929)
INTEGER*4 GDS__gfix_invalid_sw

View File

@ -1913,6 +1913,8 @@ const
gds_tra_snapshot_does_not_exist = 335545252;
isc_eds_input_prm_not_used = 335545253;
gds_eds_input_prm_not_used = 335545253;
isc_effective_user = 335545254;
gds_effective_user = 335545254;
isc_gfix_db_name = 335740929;
gds_gfix_db_name = 335740929;
isc_gfix_invalid_sw = 335740930;

View File

@ -3149,6 +3149,9 @@ void ExecProcedureNode::executeProcedure(thread_db* tdbb, jrd_req* request) cons
Arg::Str(procedure->getName().identifier) << Arg::Str(procedure->getName().package));
}
UserId* invoker = procedure->invoker ? procedure->invoker : tdbb->getAttachment()->att_ss_user;
AutoSetRestore<UserId*> userIdHolder(&tdbb->getAttachment()->att_ss_user, invoker);
ULONG inMsgLength = 0;
UCHAR* inMsg = NULL;

View File

@ -955,6 +955,7 @@ static const struct {
{"bad_repl_handle", 335545251},
{"tra_snapshot_does_not_exist", 335545252},
{"eds_input_prm_not_used", 335545253},
{"effective_user", 335545254},
{"gfix_db_name", 335740929},
{"gfix_invalid_sw", 335740930},
{"gfix_incmp_sw", 335740932},

View File

@ -989,6 +989,7 @@ const ISC_STATUS isc_tom_chacha_key = 335545250L;
const ISC_STATUS isc_bad_repl_handle = 335545251L;
const ISC_STATUS isc_tra_snapshot_does_not_exist = 335545252L;
const ISC_STATUS isc_eds_input_prm_not_used = 335545253L;
const ISC_STATUS isc_effective_user = 335545254L;
const ISC_STATUS isc_gfix_db_name = 335740929L;
const ISC_STATUS isc_gfix_invalid_sw = 335740930L;
const ISC_STATUS isc_gfix_incmp_sw = 335740932L;
@ -1463,7 +1464,7 @@ const ISC_STATUS isc_trace_switch_user_only = 337182757L;
const ISC_STATUS isc_trace_switch_param_miss = 337182758L;
const ISC_STATUS isc_trace_param_act_notcompat = 337182759L;
const ISC_STATUS isc_trace_mandatory_switch_miss = 337182760L;
const ISC_STATUS isc_err_max = 1407;
const ISC_STATUS isc_err_max = 1408;
#else /* c definitions */
@ -2422,6 +2423,7 @@ const ISC_STATUS isc_err_max = 1407;
#define isc_bad_repl_handle 335545251L
#define isc_tra_snapshot_does_not_exist 335545252L
#define isc_eds_input_prm_not_used 335545253L
#define isc_effective_user 335545254L
#define isc_gfix_db_name 335740929L
#define isc_gfix_invalid_sw 335740930L
#define isc_gfix_incmp_sw 335740932L
@ -2896,7 +2898,7 @@ const ISC_STATUS isc_err_max = 1407;
#define isc_trace_switch_param_miss 337182758L
#define isc_trace_param_act_notcompat 337182759L
#define isc_trace_mandatory_switch_miss 337182760L
#define isc_err_max 1407
#define isc_err_max 1408
#endif

View File

@ -958,6 +958,7 @@ Data source : @4"}, /* eds_statement */
{335545251, "invalid replicator handle"}, /* bad_repl_handle */
{335545252, "Transaction's base snapshot number does not exist"}, /* tra_snapshot_does_not_exist */
{335545253, "Input parameter '@1' is not used in SQL query text"}, /* eds_input_prm_not_used */
{335545254, "Effective user is @1"}, /* effective_user */
{335740929, "data base file name (@1) already given"}, /* gfix_db_name */
{335740930, "invalid switch @1"}, /* gfix_invalid_sw */
{335740932, "incompatible switch combination"}, /* gfix_incmp_sw */

View File

@ -954,6 +954,7 @@ static const struct {
{335545251, -901}, /* 931 bad_repl_handle */
{335545252, -901}, /* 932 tra_snapshot_does_not_exist */
{335545253, -901}, /* 933 eds_input_prm_not_used */
{335545254, -551}, /* 934 effective_user */
{335740929, -901}, /* 1 gfix_db_name */
{335740930, -901}, /* 2 gfix_invalid_sw */
{335740932, -901}, /* 4 gfix_incmp_sw */

View File

@ -954,6 +954,7 @@ static const struct {
{335545251, "08003"}, // 931 bad_repl_handle
{335545252, "0B000"}, // 932 tra_snapshot_does_not_exist
{335545253, "42000"}, // 933 eds_input_prm_not_used
{335545254, "28000"}, // 934 effective_user
{335740929, "00000"}, // 1 gfix_db_name
{335740930, "00000"}, // 2 gfix_invalid_sw
{335740932, "00000"}, // 4 gfix_incmp_sw

View File

@ -207,6 +207,8 @@ Jrd::Attachment::Attachment(MemoryPool* pool, Database* dbb)
: att_pool(pool),
att_memory_stats(&dbb->dbb_memory_stats),
att_database(dbb),
att_ss_user(NULL),
att_user_ids(*pool),
att_active_snapshots(*pool),
att_requests(*pool),
att_lock_owner_id(Database::getLockOwnerId()),
@ -986,6 +988,18 @@ bool Attachment::getIdleTimerTimestamp(ISC_TIMESTAMP_TZ& ts) const
return true;
}
UserId* Attachment::getUserId(const MetaName& userName)
{
UserId* result = NULL;
if (!att_user_ids.get(userName, result))
{
result = FB_NEW_POOL(*att_pool) UserId(*att_pool);
result->setUserName(userName);
att_user_ids.put(userName, result);
}
return result;
}
/// Attachment::IdleTimer
void Attachment::IdleTimer::handler()

View File

@ -359,6 +359,9 @@ public:
Database* att_database; // Parent database block
Attachment* att_next; // Next attachment to database
UserId* att_user; // User identification
UserId* att_ss_user; // User identification for SQL SECURITY actual user
Firebird::GenericMap<Firebird::Pair<Firebird::Left<
Firebird::MetaName, UserId*> > > att_user_ids; // set of used UserIds
jrd_tra* att_transactions; // Transactions belonging to attachment
jrd_tra* att_dbkey_trans; // transaction to control db-key scope
TraNumber att_oldest_snapshot; // GTT's record versions older than this can be garbage-collected
@ -566,6 +569,8 @@ public:
att_batches.findAndRemove(b);
}
UserId* getUserId(const Firebird::MetaName &userName);
private:
Attachment(MemoryPool* pool, Database* dbb);
~Attachment();
@ -608,7 +613,8 @@ private:
inline bool Attachment::locksmith(thread_db* tdbb, SystemPrivilege sp) const
{
return att_user && att_user->locksmith(tdbb, sp);
return att_user && att_user->locksmith(tdbb, sp) ||
att_ss_user && att_ss_user->locksmith(tdbb, sp);
}
inline jrd_tra* Attachment::getSysTransaction()

View File

@ -732,7 +732,7 @@ ExtEngineManager::Function::~Function()
void ExtEngineManager::Function::execute(thread_db* tdbb, UCHAR* inMsg, UCHAR* outMsg) const
{
EngineAttachmentInfo* attInfo = extManager->getEngineAttachment(tdbb, engine);
const MetaName& userName = udf->ssDefiner.specified && udf->ssDefiner.value ? udf->owner : "";
const MetaName& userName = udf->invoker ? udf->invoker->getUserName() : "";
ContextManager<IExternalFunction> ctxManager(tdbb, attInfo, function,
(udf->getName().package.isEmpty() ?
CallerName(obj_udf, udf->getName().identifier, userName) :
@ -786,8 +786,7 @@ ExtEngineManager::ResultSet::ResultSet(thread_db* tdbb, UCHAR* inMsg, UCHAR* out
firstFetch(true)
{
attInfo = procedure->extManager->getEngineAttachment(tdbb, procedure->engine);
const MetaName& userName = procedure->prc->ssDefiner.specified && procedure->prc->ssDefiner.value ?
procedure->prc->owner : "";
const MetaName& userName = procedure->prc->invoker ? procedure->prc->invoker->getUserName() : "";
ContextManager<IExternalProcedure> ctxManager(tdbb, attInfo, procedure->procedure,
(procedure->prc->getName().package.isEmpty() ?
CallerName(obj_procedure, procedure->prc->getName().identifier, userName) :
@ -821,8 +820,7 @@ bool ExtEngineManager::ResultSet::fetch(thread_db* tdbb)
if (!resultSet)
return wasFirstFetch;
const MetaName& userName = procedure->prc->ssDefiner.specified && procedure->prc->ssDefiner.value ?
procedure->prc->owner : "";
const MetaName& userName = procedure->prc->invoker ? procedure->prc->invoker->getUserName() : "";
ContextManager<IExternalProcedure> ctxManager(tdbb, attInfo, charSet,
(procedure->prc->getName().package.isEmpty() ?
CallerName(obj_procedure, procedure->prc->getName().identifier, userName) :
@ -1286,7 +1284,7 @@ void ExtEngineManager::makeFunction(thread_db* tdbb, CompilerScratch* csb, Jrd::
entryPointTrimmed.trim();
EngineAttachmentInfo* attInfo = getEngineAttachment(tdbb, engine);
const MetaName& userName = udf->ssDefiner.specified && udf->ssDefiner.value ? udf->owner : "";
const MetaName& userName = udf->invoker ? udf->invoker->getUserName() : "";
ContextManager<IExternalFunction> ctxManager(tdbb, attInfo, attInfo->adminCharSet,
(udf->getName().package.isEmpty() ?
CallerName(obj_udf, udf->getName().identifier, userName) :
@ -1410,7 +1408,7 @@ void ExtEngineManager::makeProcedure(thread_db* tdbb, CompilerScratch* csb, jrd_
entryPointTrimmed.trim();
EngineAttachmentInfo* attInfo = getEngineAttachment(tdbb, engine);
const MetaName& userName = prc->ssDefiner.specified && prc->ssDefiner.value ? prc->owner : "";
const MetaName& userName = prc->invoker ? prc->invoker->getUserName() : "";
ContextManager<IExternalProcedure> ctxManager(tdbb, attInfo, attInfo->adminCharSet,
(prc->getName().package.isEmpty() ?
CallerName(obj_procedure, prc->getName().identifier, userName) :

View File

@ -221,6 +221,7 @@ Function* Function::loadMetadata(thread_db* tdbb, USHORT id, bool noscan, USHORT
(X.RDB$PACKAGE_NAME.NULL ? NULL : X.RDB$PACKAGE_NAME)));
function->owner = X.RDB$OWNER_NAME;
Nullable<bool> ssDefiner;
if (!X.RDB$SECURITY_CLASS.NULL)
{
@ -241,19 +242,22 @@ Function* Function::loadMetadata(thread_db* tdbb, USHORT id, bool noscan, USHORT
// SQL SECURITY of function must be the same if it's defined in package
if (!PKG.RDB$SQL_SECURITY.NULL)
function->ssDefiner = (bool) PKG.RDB$SQL_SECURITY;
ssDefiner = (bool) PKG.RDB$SQL_SECURITY;
END_FOR
}
if (!function->ssDefiner.specified)
if (!ssDefiner.specified)
{
if (!X.RDB$SQL_SECURITY.NULL)
function->ssDefiner = (bool) X.RDB$SQL_SECURITY;
ssDefiner = (bool) X.RDB$SQL_SECURITY;
else
function->ssDefiner = MET_get_ss_definer(tdbb);
ssDefiner = MET_get_ss_definer(tdbb);
}
if (ssDefiner.orElse(false))
function->invoker = attachment->getUserId(function->owner);
size_t count = 0;
ULONG length = 0;

View File

@ -54,7 +54,7 @@ JrdStatement::JrdStatement(thread_db* tdbb, MemoryPool* p, CompilerScratch* csb)
accessList(*p),
resources(*p),
triggerName(*p),
triggerOwner(*p),
triggerInvoker(NULL),
parentStatement(NULL),
subStatements(*p),
fors(*p),
@ -402,7 +402,8 @@ void JrdStatement::verifyAccess(thread_db* tdbb)
SET_TDBB(tdbb);
ExternalAccessList external;
buildExternalAccess(tdbb, external);
const MetaName defaultUser;
buildExternalAccess(tdbb, external, defaultUser);
for (ExternalAccess* item = external.begin(); item != external.end(); ++item)
{
@ -440,7 +441,7 @@ void JrdStatement::verifyAccess(thread_db* tdbb)
if (!relation)
continue;
MetaName userName;
MetaName userName = item->user;
if (item->exa_view_id)
{
jrd_rel* view = MET_lookup_relation_id(tdbb, item->exa_view_id, false);
@ -479,7 +480,7 @@ void JrdStatement::verifyAccess(thread_db* tdbb)
{
const SecurityClass* sec_class = SCL_get_class(tdbb, access->acc_security_name.c_str());
MetaName userName;
MetaName userName = item->user;
if (access->acc_ss_rel_id)
{
@ -488,9 +489,6 @@ void JrdStatement::verifyAccess(thread_db* tdbb)
userName = view->rel_owner_name;
}
if (userName.isEmpty() && routine->ssDefiner.specified && routine->ssDefiner.value && routine->owner.hasData())
userName = routine->owner;
if (routine->getName().package.isEmpty())
{
SCL_check_access(tdbb, sec_class, userName, aclType,
@ -695,7 +693,7 @@ void JrdStatement::verifyTriggerAccess(thread_db* tdbb, jrd_rel* ownerRelation,
// Invoke buildExternalAccess for triggers in vector
inline void JrdStatement::triggersExternalAccess(thread_db* tdbb, ExternalAccessList& list,
TrigVector* tvec)
TrigVector* tvec, const MetaName& user)
{
if (!tvec)
return;
@ -706,34 +704,39 @@ inline void JrdStatement::triggersExternalAccess(thread_db* tdbb, ExternalAccess
t.compile(tdbb);
if (t.statement)
t.statement->buildExternalAccess(tdbb, list);
{
const MetaName& userName = (t.ssDefiner.specified && t.ssDefiner.value) ? t.owner : user;
t.statement->buildExternalAccess(tdbb, list, userName);
}
}
}
// Recursively walk external dependencies (procedures, triggers) for request to assemble full
// list of requests it depends on.
void JrdStatement::buildExternalAccess(thread_db* tdbb, ExternalAccessList& list)
void JrdStatement::buildExternalAccess(thread_db* tdbb, ExternalAccessList& list, const MetaName &user)
{
for (ExternalAccess* item = externalList.begin(); item != externalList.end(); ++item)
{
FB_SIZE_T i;
if (list.find(*item, i))
continue;
list.insert(i, *item);
// Add externals recursively
if (item->exa_action == ExternalAccess::exa_procedure)
{
jrd_prc* const procedure = MET_lookup_procedure_id(tdbb, item->exa_prc_id, false, false, 0);
if (procedure && procedure->getStatement())
procedure->getStatement()->buildExternalAccess(tdbb, list);
{
item->user = procedure->invoker ? procedure->invoker->getUserName() : user;
procedure->getStatement()->buildExternalAccess(tdbb, list, item->user);
}
}
else if (item->exa_action == ExternalAccess::exa_function)
{
Function* const function = Function::lookup(tdbb, item->exa_fun_id, false, false, 0);
if (function && function->getStatement())
function->getStatement()->buildExternalAccess(tdbb, list);
{
item->user = function->invoker ? function->invoker->getUserName() : user;
function->getStatement()->buildExternalAccess(tdbb, list, item->user);
}
}
else
{
@ -762,9 +765,13 @@ void JrdStatement::buildExternalAccess(thread_db* tdbb, ExternalAccessList& list
continue; // should never happen, silence the compiler
}
triggersExternalAccess(tdbb, list, vec1);
triggersExternalAccess(tdbb, list, vec2);
item->user = relation->rel_ss_definer.orElse(false) ? relation->rel_owner_name : user;
triggersExternalAccess(tdbb, list, vec1, item->user);
triggersExternalAccess(tdbb, list, vec2, item->user);
}
if (!list.find(*item, i))
list.insert(i, *item);
}
}

View File

@ -59,9 +59,9 @@ public:
private:
static void verifyTriggerAccess(thread_db* tdbb, jrd_rel* ownerRelation, TrigVector* triggers,
Firebird::MetaName userName);
static void triggersExternalAccess(thread_db* tdbb, ExternalAccessList& list, TrigVector* tvec);
static void triggersExternalAccess(thread_db* tdbb, ExternalAccessList& list, TrigVector* tvec, const Firebird::MetaName &user);
void buildExternalAccess(thread_db* tdbb, ExternalAccessList& list);
void buildExternalAccess(thread_db* tdbb, ExternalAccessList& list, const Firebird::MetaName& user);
public:
MemoryPool* pool;
@ -76,7 +76,7 @@ public:
const jrd_prc* procedure; // procedure, if any
const Function* function; // function, if any
Firebird::MetaName triggerName; // name of request (trigger), if any
Firebird::MetaName triggerOwner; // user name if trigger run with SQL SECURITY DEFINER
Jrd::UserId* triggerInvoker; // user name if trigger run with SQL SECURITY DEFINER
JrdStatement* parentStatement; // Sub routine's parent statement
Firebird::Array<JrdStatement*> subStatements; // Array of subroutines' statements
const StmtNode* topNode; // top of execution tree

View File

@ -38,6 +38,7 @@ namespace Jrd
class Lock;
class Format;
class Parameter;
class UserId;
class Routine : public Firebird::PermanentStorage
{
@ -60,7 +61,8 @@ namespace Jrd
useCount(0),
intUseCount(0),
alterCount(0),
existenceLock(NULL)
existenceLock(NULL),
invoker(NULL)
{
}
@ -180,8 +182,8 @@ namespace Jrd
USHORT alterCount; // No. of times the routine was altered
Lock* existenceLock; // existence lock, if any
Nullable<bool> ssDefiner; // true ? SQL DEFINER : SQL INVOKER
Firebird::MetaName owner;
Jrd::UserId* invoker; // Invoker ID
};
}

View File

@ -335,6 +335,7 @@ const char
CURRENT_ROLE_NAME[] = "CURRENT_ROLE",
SESSION_IDLE_TIMEOUT[] = "SESSION_IDLE_TIMEOUT",
STATEMENT_TIMEOUT[] = "STATEMENT_TIMEOUT",
EFFECTIVE_USER_NAME[] = "EFFECTIVE_USER",
// SYSTEM namespace: transaction wise items
TRANSACTION_ID_NAME[] = "TRANSACTION_ID",
ISOLATION_LEVEL_NAME[] = "ISOLATION_LEVEL",
@ -3976,6 +3977,18 @@ dsc* evlGetContext(thread_db* tdbb, const SysFunction*, const NestValueArray& ar
resultStr.printf("%d", EDS::Manager::getConnPool()->getLifeTime());
else if (nameStr == REPLICATION_SEQ_NAME)
resultStr.printf("%" UQUADFORMAT, dbb->getReplSequence(tdbb));
else if (nameStr == EFFECTIVE_USER_NAME)
{
MetaName user;
if (attachment->att_ss_user)
user = attachment->att_ss_user->getUserName();
else if (attachment->att_user)
user = attachment->att_user->getUserName();
if (user.isEmpty())
return NULL;
resultStr = user.c_str();
}
else
{
// "Context variable %s is not found in namespace %s"

View File

@ -1158,7 +1158,13 @@ void EXE_execute_triggers(thread_db* tdbb,
TraceTrigExecute trace(tdbb, trigger, which_trig);
EXE_start(tdbb, trigger, transaction);
{ // Scope to replace att_ss_user
const JrdStatement* s = trigger->getStatement();
UserId* invoker = s->triggerInvoker ? s->triggerInvoker : tdbb->getAttachment()->att_ss_user;
AutoSetRestore<UserId*> userIdHolder(&tdbb->getAttachment()->att_ss_user, invoker);
EXE_start(tdbb, trigger, transaction);
}
const bool ok = (trigger->req_operation != jrd_req::req_unwind);
trace.finish(ok ? ITracePlugin::RESULT_SUCCESS : ITracePlugin::RESULT_FAILED);

View File

@ -252,6 +252,7 @@ struct ExternalAccess
USHORT exa_fun_id;
USHORT exa_rel_id;
USHORT exa_view_id;
Firebird::MetaName user; // User which touch the recources.
// Procedure
ExternalAccess(exa_act action, USHORT id) :
@ -279,6 +280,8 @@ struct ExternalAccess
return i1.exa_rel_id > i2.exa_rel_id;
if (i1.exa_view_id != i2.exa_view_id)
return i1.exa_view_id > i2.exa_view_id;
if (i1.user != i2.user)
return i1.user > i2.user;
return false; // Equal
}
};

View File

@ -461,12 +461,14 @@ void InternalStatement::doPrepare(thread_db* tdbb, const string& sql)
if (statement && statement->parentStatement)
statement = statement->parentStatement;
if (statement && statement->triggerName.hasData())
tran->getHandle()->tra_caller_name = CallerName(obj_trigger, statement->triggerName, statement->triggerOwner);
if (statement && statement->triggerInvoker)
tran->getHandle()->tra_caller_name = CallerName(obj_trigger,
statement->triggerName,
statement->triggerInvoker->getUserName());
else if (statement && (routine = statement->getRoutine()) &&
routine->getName().identifier.hasData())
{
const MetaName& userName = routine->ssDefiner.specified && routine->ssDefiner.value ? routine->owner : "";
const MetaName& userName = routine->invoker ? routine->invoker->getUserName() : "";
if (routine->getName().package.isEmpty())
{
tran->getHandle()->tra_caller_name = CallerName(routine->getObjectType(),

View File

@ -915,8 +915,8 @@ void Trigger::compile(thread_db* tdbb)
}
statement->triggerName = name;
if (ssDefiner.specified && ssDefiner.value)
statement->triggerOwner = owner;
if (ssDefiner.orElse(false))
statement->triggerInvoker = att->getUserId(owner);
if (sys_trigger)
statement->flags |= JrdStatement::FLAG_SYS_TRIGGER;

View File

@ -3325,6 +3325,7 @@ jrd_prc* MET_procedure(thread_db* tdbb, USHORT id, bool noscan, USHORT flags)
}
procedure->setId(P.RDB$PROCEDURE_ID);
Nullable<bool> ssDefiner;
if (!P.RDB$SECURITY_CLASS.NULL)
procedure->setSecurityName(P.RDB$SECURITY_CLASS);
@ -3340,20 +3341,24 @@ jrd_prc* MET_procedure(thread_db* tdbb, USHORT id, bool noscan, USHORT flags)
procedure->setSecurityName(PKG.RDB$SECURITY_CLASS);
if (!PKG.RDB$SQL_SECURITY.NULL)
procedure->ssDefiner = (bool) PKG.RDB$SQL_SECURITY;
ssDefiner = (bool) PKG.RDB$SQL_SECURITY;
}
END_FOR
}
if (!procedure->ssDefiner.specified)
if (!ssDefiner.specified)
{
if (!P.RDB$SQL_SECURITY.NULL)
procedure->ssDefiner = (bool) P.RDB$SQL_SECURITY;
ssDefiner = (bool) P.RDB$SQL_SECURITY;
else
procedure->ssDefiner = MET_get_ss_definer(tdbb);
ssDefiner = MET_get_ss_definer(tdbb);
}
procedure->owner = P.RDB$OWNER_NAME;
if (ssDefiner.orElse(false))
procedure->invoker = attachment->getUserId(procedure->owner);
procedure->setImplemented(true);
procedure->getInputFields().resize(P.RDB$PROCEDURE_INPUTS);
procedure->getOutputFields().resize(P.RDB$PROCEDURE_OUTPUTS);

View File

@ -158,6 +158,9 @@ bool ProcedureScan::getRecord(thread_db* tdbb) const
if (--tdbb->tdbb_quantum < 0)
JRD_reschedule(tdbb, 0, true);
UserId* invoker = m_procedure->invoker ? m_procedure->invoker : tdbb->getAttachment()->att_ss_user;
AutoSetRestore<UserId*> userIdHolder(&tdbb->getAttachment()->att_ss_user, invoker);
jrd_req* const request = tdbb->getRequest();
record_param* const rpb = &request->req_rpb[m_stream];
Impure* const impure = request->getImpure<Impure>(m_impure);

View File

@ -76,8 +76,8 @@ static SecurityClass::flags_t compute_access(thread_db* tdbb, const SecurityClas
static SecurityClass::flags_t get_sys_privileges(thread_db* tdbb);
static SecurityClass::flags_t walk_acl(thread_db* tdbb, const Acl&, const MetaName&,
SLONG, const Firebird::MetaName&);
static void raiseError(SecurityClass::flags_t mask, SLONG type, const Firebird::MetaName& name,
const Firebird::MetaName& r_name);
static void raiseError(thread_db* tdbb, SecurityClass::flags_t mask, SLONG type, const Firebird::MetaName& name,
const Firebird::MetaName& r_name, const MetaName &invoker);
namespace
@ -176,8 +176,8 @@ namespace
} // anonymous namespace
static void raiseError(SecurityClass::flags_t mask, SLONG type, const Firebird::MetaName& name,
const Firebird::MetaName& r_name)
static void raiseError(thread_db* tdbb, SecurityClass::flags_t mask, SLONG type, const Firebird::MetaName& name,
const Firebird::MetaName& r_name, const Firebird::MetaName& invoker)
{
const P_NAMES* names;
for (names = p_names; names->p_names_priv; names++)
@ -190,9 +190,16 @@ static void raiseError(SecurityClass::flags_t mask, SLONG type, const Firebird::
const Firebird::string fullName = r_name.hasData() ?
r_name.c_str() + Firebird::string(".") + name.c_str() : name.c_str();
ERR_post(Arg::Gds(isc_no_priv) << Arg::Str(names->p_names_string) <<
Arg::Str(typeAsStr) <<
Arg::Str(fullName));
Arg::StatusVector status;
status << Arg::Gds(isc_no_priv) << Arg::Str(names->p_names_string) <<
Arg::Str(typeAsStr) <<
Arg::Str(fullName);
if (invoker.hasData())
{
status << Arg::Gds(isc_effective_user) << Arg::Str(invoker);
}
ERR_post(status);
}
@ -231,9 +238,15 @@ void SCL_check_access(thread_db* tdbb,
if (s_class && (s_class->scl_flags & SCL_corrupt))
{
ERR_post(Arg::Gds(isc_no_priv) << Arg::Str("(ACL unrecognized)") <<
Arg::StatusVector status;
status << Arg::Gds(isc_no_priv) << Arg::Str("(ACL unrecognized)") <<
Arg::Str("security_class") <<
Arg::Str(s_class->scl_name));
Arg::Str(s_class->scl_name);
if (userName.hasData())
{
status << Arg::Gds(isc_effective_user) << Arg::Str(userName);
}
ERR_post(status);
}
// Make fast check first
@ -263,7 +276,7 @@ void SCL_check_access(thread_db* tdbb,
return;
}
raiseError(mask, type, name, r_name);
raiseError(tdbb, mask, type, name, r_name, userName);
}
@ -568,7 +581,7 @@ void SCL_check_index(thread_db* tdbb, const Firebird::MetaName& index_name, UCHA
{
// Someone is going to reference system table in FK
// Usually it's not good idea
raiseError(mask, SCL_object_table, reln_name, "");
raiseError(tdbb, mask, SCL_object_table, reln_name, "", NULL);
}
// Check if the relation exists. It may not have been created yet.
@ -791,7 +804,7 @@ void SCL_check_relation(thread_db* tdbb, const dsc* dsc_name, SecurityClass::fla
{
// Someone is going to modify system table layout
// Usually it's not good idea
raiseError(mask, SCL_object_table, name, "");
raiseError(tdbb, mask, SCL_object_table, name, "", NULL);
}
if (!REL.RDB$SECURITY_CLASS.NULL)

View File

@ -261,6 +261,19 @@ public:
usr_granted_roles = ui.usr_granted_roles;
}
UserId(Firebird::MemoryPool& p)
: usr_user_name(p),
usr_sql_role_name(p),
usr_granted_roles(p),
usr_trusted_role(p),
usr_init_role(p),
usr_project_name(p),
usr_org_name(p),
usr_auth_method(p),
usr_auth_block(p)
{
}
UserId(const UserId& ui)
: usr_user_name(ui.usr_user_name),
usr_sql_role_name(ui.usr_sql_role_name),

View File

@ -1,7 +1,7 @@
/* MAX_NUMBER is the next number to be used, always one more than the highest message number. */
set bulk_insert INSERT INTO FACILITIES (LAST_CHANGE, FACILITY, FAC_CODE, MAX_NUMBER) VALUES (?, ?, ?, ?);
--
('2019-03-04 19:40:00', 'JRD', 0, 934)
('2019-03-04 19:40:00', 'JRD', 0, 935)
('2015-03-17 18:33:00', 'QLI', 1, 533)
('2018-03-17 12:00:00', 'GFIX', 3, 136)
('1996-11-07 13:39:40', 'GPRE', 4, 1)

View File

@ -1040,7 +1040,8 @@ Data source : @4', NULL, NULL)
('tom_chacha_key', NULL, 'SysFunction.cpp', NULL, 0, 930, NULL, 'Invalid key length @1, need 16 or 32', NULL, NULL);
('bad_repl_handle', NULL, 'jrd.cpp', NULL, 0, 931, NULL, 'invalid replicator handle', NULL, NULL);
('tra_snapshot_does_not_exist', NULL, 'tpc.cpp', NULL, 0, 932, NULL, 'Transaction''s base snapshot number does not exist', NULL, NULL);
('eds_input_prm_not_used', NULL, 'ExtDS.cpp', NULL, 0, 933, NULL, 'Input parameter ''@1'' is not used in SQL query text', NULL, NULL)
('eds_input_prm_not_used', NULL, 'ExtDS.cpp', NULL, 0, 933, NULL, 'Input parameter ''@1'' is not used in SQL query text', NULL, NULL);
('effective_user', NULL, NULL, NULL, 0, 934, NULL, 'Effective user is @1', NULL, NULL);
-- QLI
(NULL, NULL, NULL, NULL, 1, 0, NULL, 'expected type', NULL, NULL);
(NULL, NULL, NULL, NULL, 1, 1, NULL, 'bad block type', NULL, NULL);

View File

@ -940,6 +940,7 @@ set bulk_insert INSERT INTO SYSTEM_ERRORS (SQL_CODE, SQL_CLASS, SQL_SUBCLASS, FA
(-901, '08', '003', 0, 931, 'bad_repl_handle', NULL, NULL)
(-901, '0B', '000', 0, 932, 'tra_snapshot_does_not_exist', NULL, NULL)
(-901, '42', '000', 0, 933, 'eds_input_prm_not_used', NULL, NULL)
(-551, '28', '000', 0, 934, 'effective_user', NULL, 'ERROR')
-- GFIX
(-901, '00', '000', 3, 1, 'gfix_db_name', NULL, NULL)
(-901, '00', '000', 3, 2, 'gfix_invalid_sw', NULL, NULL)