mirror of
https://github.com/FirebirdSQL/firebird.git
synced 2025-01-22 16:43: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:
parent
b200006ab8
commit
bb3c2e94ec
@ -98,6 +98,9 @@ Usage:
|
|||||||
CURRENT_USER | Current user for the connection. Returned value is the
|
CURRENT_USER | Current user for the connection. Returned value is the
|
||||||
| same as of CURRENT_USER pseudo-variable
|
| 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
|
CURRENT_ROLE | Current role for the connection. Returned value is the
|
||||||
| same as of CURRENT_ROLE pseudo-variable
|
| same as of CURRENT_ROLE pseudo-variable
|
||||||
|
|
|
|
||||||
|
@ -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.
|
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 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
|
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
|
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.
|
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.
|
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.
|
In case of INVOKER it will require also EXECUTE for function F.
|
||||||
|
@ -1918,6 +1918,8 @@ C --
|
|||||||
PARAMETER (GDS__tra_snapshot_does_not_exist = 335545252)
|
PARAMETER (GDS__tra_snapshot_does_not_exist = 335545252)
|
||||||
INTEGER*4 GDS__eds_input_prm_not_used
|
INTEGER*4 GDS__eds_input_prm_not_used
|
||||||
PARAMETER (GDS__eds_input_prm_not_used = 335545253)
|
PARAMETER (GDS__eds_input_prm_not_used = 335545253)
|
||||||
|
INTEGER*4 GDS__effective_user
|
||||||
|
PARAMETER (GDS__effective_user = 335545254)
|
||||||
INTEGER*4 GDS__gfix_db_name
|
INTEGER*4 GDS__gfix_db_name
|
||||||
PARAMETER (GDS__gfix_db_name = 335740929)
|
PARAMETER (GDS__gfix_db_name = 335740929)
|
||||||
INTEGER*4 GDS__gfix_invalid_sw
|
INTEGER*4 GDS__gfix_invalid_sw
|
||||||
|
@ -1913,6 +1913,8 @@ const
|
|||||||
gds_tra_snapshot_does_not_exist = 335545252;
|
gds_tra_snapshot_does_not_exist = 335545252;
|
||||||
isc_eds_input_prm_not_used = 335545253;
|
isc_eds_input_prm_not_used = 335545253;
|
||||||
gds_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;
|
isc_gfix_db_name = 335740929;
|
||||||
gds_gfix_db_name = 335740929;
|
gds_gfix_db_name = 335740929;
|
||||||
isc_gfix_invalid_sw = 335740930;
|
isc_gfix_invalid_sw = 335740930;
|
||||||
|
@ -3149,6 +3149,9 @@ void ExecProcedureNode::executeProcedure(thread_db* tdbb, jrd_req* request) cons
|
|||||||
Arg::Str(procedure->getName().identifier) << Arg::Str(procedure->getName().package));
|
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;
|
ULONG inMsgLength = 0;
|
||||||
UCHAR* inMsg = NULL;
|
UCHAR* inMsg = NULL;
|
||||||
|
|
||||||
|
@ -955,6 +955,7 @@ static const struct {
|
|||||||
{"bad_repl_handle", 335545251},
|
{"bad_repl_handle", 335545251},
|
||||||
{"tra_snapshot_does_not_exist", 335545252},
|
{"tra_snapshot_does_not_exist", 335545252},
|
||||||
{"eds_input_prm_not_used", 335545253},
|
{"eds_input_prm_not_used", 335545253},
|
||||||
|
{"effective_user", 335545254},
|
||||||
{"gfix_db_name", 335740929},
|
{"gfix_db_name", 335740929},
|
||||||
{"gfix_invalid_sw", 335740930},
|
{"gfix_invalid_sw", 335740930},
|
||||||
{"gfix_incmp_sw", 335740932},
|
{"gfix_incmp_sw", 335740932},
|
||||||
|
@ -989,6 +989,7 @@ const ISC_STATUS isc_tom_chacha_key = 335545250L;
|
|||||||
const ISC_STATUS isc_bad_repl_handle = 335545251L;
|
const ISC_STATUS isc_bad_repl_handle = 335545251L;
|
||||||
const ISC_STATUS isc_tra_snapshot_does_not_exist = 335545252L;
|
const ISC_STATUS isc_tra_snapshot_does_not_exist = 335545252L;
|
||||||
const ISC_STATUS isc_eds_input_prm_not_used = 335545253L;
|
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_db_name = 335740929L;
|
||||||
const ISC_STATUS isc_gfix_invalid_sw = 335740930L;
|
const ISC_STATUS isc_gfix_invalid_sw = 335740930L;
|
||||||
const ISC_STATUS isc_gfix_incmp_sw = 335740932L;
|
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_switch_param_miss = 337182758L;
|
||||||
const ISC_STATUS isc_trace_param_act_notcompat = 337182759L;
|
const ISC_STATUS isc_trace_param_act_notcompat = 337182759L;
|
||||||
const ISC_STATUS isc_trace_mandatory_switch_miss = 337182760L;
|
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 */
|
#else /* c definitions */
|
||||||
|
|
||||||
@ -2422,6 +2423,7 @@ const ISC_STATUS isc_err_max = 1407;
|
|||||||
#define isc_bad_repl_handle 335545251L
|
#define isc_bad_repl_handle 335545251L
|
||||||
#define isc_tra_snapshot_does_not_exist 335545252L
|
#define isc_tra_snapshot_does_not_exist 335545252L
|
||||||
#define isc_eds_input_prm_not_used 335545253L
|
#define isc_eds_input_prm_not_used 335545253L
|
||||||
|
#define isc_effective_user 335545254L
|
||||||
#define isc_gfix_db_name 335740929L
|
#define isc_gfix_db_name 335740929L
|
||||||
#define isc_gfix_invalid_sw 335740930L
|
#define isc_gfix_invalid_sw 335740930L
|
||||||
#define isc_gfix_incmp_sw 335740932L
|
#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_switch_param_miss 337182758L
|
||||||
#define isc_trace_param_act_notcompat 337182759L
|
#define isc_trace_param_act_notcompat 337182759L
|
||||||
#define isc_trace_mandatory_switch_miss 337182760L
|
#define isc_trace_mandatory_switch_miss 337182760L
|
||||||
#define isc_err_max 1407
|
#define isc_err_max 1408
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -958,6 +958,7 @@ Data source : @4"}, /* eds_statement */
|
|||||||
{335545251, "invalid replicator handle"}, /* bad_repl_handle */
|
{335545251, "invalid replicator handle"}, /* bad_repl_handle */
|
||||||
{335545252, "Transaction's base snapshot number does not exist"}, /* tra_snapshot_does_not_exist */
|
{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 */
|
{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 */
|
{335740929, "data base file name (@1) already given"}, /* gfix_db_name */
|
||||||
{335740930, "invalid switch @1"}, /* gfix_invalid_sw */
|
{335740930, "invalid switch @1"}, /* gfix_invalid_sw */
|
||||||
{335740932, "incompatible switch combination"}, /* gfix_incmp_sw */
|
{335740932, "incompatible switch combination"}, /* gfix_incmp_sw */
|
||||||
|
@ -954,6 +954,7 @@ static const struct {
|
|||||||
{335545251, -901}, /* 931 bad_repl_handle */
|
{335545251, -901}, /* 931 bad_repl_handle */
|
||||||
{335545252, -901}, /* 932 tra_snapshot_does_not_exist */
|
{335545252, -901}, /* 932 tra_snapshot_does_not_exist */
|
||||||
{335545253, -901}, /* 933 eds_input_prm_not_used */
|
{335545253, -901}, /* 933 eds_input_prm_not_used */
|
||||||
|
{335545254, -551}, /* 934 effective_user */
|
||||||
{335740929, -901}, /* 1 gfix_db_name */
|
{335740929, -901}, /* 1 gfix_db_name */
|
||||||
{335740930, -901}, /* 2 gfix_invalid_sw */
|
{335740930, -901}, /* 2 gfix_invalid_sw */
|
||||||
{335740932, -901}, /* 4 gfix_incmp_sw */
|
{335740932, -901}, /* 4 gfix_incmp_sw */
|
||||||
|
@ -954,6 +954,7 @@ static const struct {
|
|||||||
{335545251, "08003"}, // 931 bad_repl_handle
|
{335545251, "08003"}, // 931 bad_repl_handle
|
||||||
{335545252, "0B000"}, // 932 tra_snapshot_does_not_exist
|
{335545252, "0B000"}, // 932 tra_snapshot_does_not_exist
|
||||||
{335545253, "42000"}, // 933 eds_input_prm_not_used
|
{335545253, "42000"}, // 933 eds_input_prm_not_used
|
||||||
|
{335545254, "28000"}, // 934 effective_user
|
||||||
{335740929, "00000"}, // 1 gfix_db_name
|
{335740929, "00000"}, // 1 gfix_db_name
|
||||||
{335740930, "00000"}, // 2 gfix_invalid_sw
|
{335740930, "00000"}, // 2 gfix_invalid_sw
|
||||||
{335740932, "00000"}, // 4 gfix_incmp_sw
|
{335740932, "00000"}, // 4 gfix_incmp_sw
|
||||||
|
@ -207,6 +207,8 @@ Jrd::Attachment::Attachment(MemoryPool* pool, Database* dbb)
|
|||||||
: att_pool(pool),
|
: att_pool(pool),
|
||||||
att_memory_stats(&dbb->dbb_memory_stats),
|
att_memory_stats(&dbb->dbb_memory_stats),
|
||||||
att_database(dbb),
|
att_database(dbb),
|
||||||
|
att_ss_user(NULL),
|
||||||
|
att_user_ids(*pool),
|
||||||
att_active_snapshots(*pool),
|
att_active_snapshots(*pool),
|
||||||
att_requests(*pool),
|
att_requests(*pool),
|
||||||
att_lock_owner_id(Database::getLockOwnerId()),
|
att_lock_owner_id(Database::getLockOwnerId()),
|
||||||
@ -986,6 +988,18 @@ bool Attachment::getIdleTimerTimestamp(ISC_TIMESTAMP_TZ& ts) const
|
|||||||
return true;
|
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
|
/// Attachment::IdleTimer
|
||||||
|
|
||||||
void Attachment::IdleTimer::handler()
|
void Attachment::IdleTimer::handler()
|
||||||
|
@ -359,6 +359,9 @@ public:
|
|||||||
Database* att_database; // Parent database block
|
Database* att_database; // Parent database block
|
||||||
Attachment* att_next; // Next attachment to database
|
Attachment* att_next; // Next attachment to database
|
||||||
UserId* att_user; // User identification
|
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_transactions; // Transactions belonging to attachment
|
||||||
jrd_tra* att_dbkey_trans; // transaction to control db-key scope
|
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
|
TraNumber att_oldest_snapshot; // GTT's record versions older than this can be garbage-collected
|
||||||
@ -566,6 +569,8 @@ public:
|
|||||||
att_batches.findAndRemove(b);
|
att_batches.findAndRemove(b);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
UserId* getUserId(const Firebird::MetaName &userName);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Attachment(MemoryPool* pool, Database* dbb);
|
Attachment(MemoryPool* pool, Database* dbb);
|
||||||
~Attachment();
|
~Attachment();
|
||||||
@ -608,7 +613,8 @@ private:
|
|||||||
|
|
||||||
inline bool Attachment::locksmith(thread_db* tdbb, SystemPrivilege sp) const
|
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()
|
inline jrd_tra* Attachment::getSysTransaction()
|
||||||
|
@ -732,7 +732,7 @@ ExtEngineManager::Function::~Function()
|
|||||||
void ExtEngineManager::Function::execute(thread_db* tdbb, UCHAR* inMsg, UCHAR* outMsg) const
|
void ExtEngineManager::Function::execute(thread_db* tdbb, UCHAR* inMsg, UCHAR* outMsg) const
|
||||||
{
|
{
|
||||||
EngineAttachmentInfo* attInfo = extManager->getEngineAttachment(tdbb, engine);
|
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,
|
ContextManager<IExternalFunction> ctxManager(tdbb, attInfo, function,
|
||||||
(udf->getName().package.isEmpty() ?
|
(udf->getName().package.isEmpty() ?
|
||||||
CallerName(obj_udf, udf->getName().identifier, userName) :
|
CallerName(obj_udf, udf->getName().identifier, userName) :
|
||||||
@ -786,8 +786,7 @@ ExtEngineManager::ResultSet::ResultSet(thread_db* tdbb, UCHAR* inMsg, UCHAR* out
|
|||||||
firstFetch(true)
|
firstFetch(true)
|
||||||
{
|
{
|
||||||
attInfo = procedure->extManager->getEngineAttachment(tdbb, procedure->engine);
|
attInfo = procedure->extManager->getEngineAttachment(tdbb, procedure->engine);
|
||||||
const MetaName& userName = procedure->prc->ssDefiner.specified && procedure->prc->ssDefiner.value ?
|
const MetaName& userName = procedure->prc->invoker ? procedure->prc->invoker->getUserName() : "";
|
||||||
procedure->prc->owner : "";
|
|
||||||
ContextManager<IExternalProcedure> ctxManager(tdbb, attInfo, procedure->procedure,
|
ContextManager<IExternalProcedure> ctxManager(tdbb, attInfo, procedure->procedure,
|
||||||
(procedure->prc->getName().package.isEmpty() ?
|
(procedure->prc->getName().package.isEmpty() ?
|
||||||
CallerName(obj_procedure, procedure->prc->getName().identifier, userName) :
|
CallerName(obj_procedure, procedure->prc->getName().identifier, userName) :
|
||||||
@ -821,8 +820,7 @@ bool ExtEngineManager::ResultSet::fetch(thread_db* tdbb)
|
|||||||
if (!resultSet)
|
if (!resultSet)
|
||||||
return wasFirstFetch;
|
return wasFirstFetch;
|
||||||
|
|
||||||
const MetaName& userName = procedure->prc->ssDefiner.specified && procedure->prc->ssDefiner.value ?
|
const MetaName& userName = procedure->prc->invoker ? procedure->prc->invoker->getUserName() : "";
|
||||||
procedure->prc->owner : "";
|
|
||||||
ContextManager<IExternalProcedure> ctxManager(tdbb, attInfo, charSet,
|
ContextManager<IExternalProcedure> ctxManager(tdbb, attInfo, charSet,
|
||||||
(procedure->prc->getName().package.isEmpty() ?
|
(procedure->prc->getName().package.isEmpty() ?
|
||||||
CallerName(obj_procedure, procedure->prc->getName().identifier, userName) :
|
CallerName(obj_procedure, procedure->prc->getName().identifier, userName) :
|
||||||
@ -1286,7 +1284,7 @@ void ExtEngineManager::makeFunction(thread_db* tdbb, CompilerScratch* csb, Jrd::
|
|||||||
entryPointTrimmed.trim();
|
entryPointTrimmed.trim();
|
||||||
|
|
||||||
EngineAttachmentInfo* attInfo = getEngineAttachment(tdbb, engine);
|
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,
|
ContextManager<IExternalFunction> ctxManager(tdbb, attInfo, attInfo->adminCharSet,
|
||||||
(udf->getName().package.isEmpty() ?
|
(udf->getName().package.isEmpty() ?
|
||||||
CallerName(obj_udf, udf->getName().identifier, userName) :
|
CallerName(obj_udf, udf->getName().identifier, userName) :
|
||||||
@ -1410,7 +1408,7 @@ void ExtEngineManager::makeProcedure(thread_db* tdbb, CompilerScratch* csb, jrd_
|
|||||||
entryPointTrimmed.trim();
|
entryPointTrimmed.trim();
|
||||||
|
|
||||||
EngineAttachmentInfo* attInfo = getEngineAttachment(tdbb, engine);
|
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,
|
ContextManager<IExternalProcedure> ctxManager(tdbb, attInfo, attInfo->adminCharSet,
|
||||||
(prc->getName().package.isEmpty() ?
|
(prc->getName().package.isEmpty() ?
|
||||||
CallerName(obj_procedure, prc->getName().identifier, userName) :
|
CallerName(obj_procedure, prc->getName().identifier, userName) :
|
||||||
|
@ -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)));
|
(X.RDB$PACKAGE_NAME.NULL ? NULL : X.RDB$PACKAGE_NAME)));
|
||||||
|
|
||||||
function->owner = X.RDB$OWNER_NAME;
|
function->owner = X.RDB$OWNER_NAME;
|
||||||
|
Nullable<bool> ssDefiner;
|
||||||
|
|
||||||
if (!X.RDB$SECURITY_CLASS.NULL)
|
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
|
// SQL SECURITY of function must be the same if it's defined in package
|
||||||
if (!PKG.RDB$SQL_SECURITY.NULL)
|
if (!PKG.RDB$SQL_SECURITY.NULL)
|
||||||
function->ssDefiner = (bool) PKG.RDB$SQL_SECURITY;
|
ssDefiner = (bool) PKG.RDB$SQL_SECURITY;
|
||||||
|
|
||||||
END_FOR
|
END_FOR
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!function->ssDefiner.specified)
|
if (!ssDefiner.specified)
|
||||||
{
|
{
|
||||||
if (!X.RDB$SQL_SECURITY.NULL)
|
if (!X.RDB$SQL_SECURITY.NULL)
|
||||||
function->ssDefiner = (bool) X.RDB$SQL_SECURITY;
|
ssDefiner = (bool) X.RDB$SQL_SECURITY;
|
||||||
else
|
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;
|
size_t count = 0;
|
||||||
ULONG length = 0;
|
ULONG length = 0;
|
||||||
|
|
||||||
|
@ -54,7 +54,7 @@ JrdStatement::JrdStatement(thread_db* tdbb, MemoryPool* p, CompilerScratch* csb)
|
|||||||
accessList(*p),
|
accessList(*p),
|
||||||
resources(*p),
|
resources(*p),
|
||||||
triggerName(*p),
|
triggerName(*p),
|
||||||
triggerOwner(*p),
|
triggerInvoker(NULL),
|
||||||
parentStatement(NULL),
|
parentStatement(NULL),
|
||||||
subStatements(*p),
|
subStatements(*p),
|
||||||
fors(*p),
|
fors(*p),
|
||||||
@ -402,7 +402,8 @@ void JrdStatement::verifyAccess(thread_db* tdbb)
|
|||||||
SET_TDBB(tdbb);
|
SET_TDBB(tdbb);
|
||||||
|
|
||||||
ExternalAccessList external;
|
ExternalAccessList external;
|
||||||
buildExternalAccess(tdbb, external);
|
const MetaName defaultUser;
|
||||||
|
buildExternalAccess(tdbb, external, defaultUser);
|
||||||
|
|
||||||
for (ExternalAccess* item = external.begin(); item != external.end(); ++item)
|
for (ExternalAccess* item = external.begin(); item != external.end(); ++item)
|
||||||
{
|
{
|
||||||
@ -440,7 +441,7 @@ void JrdStatement::verifyAccess(thread_db* tdbb)
|
|||||||
if (!relation)
|
if (!relation)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
MetaName userName;
|
MetaName userName = item->user;
|
||||||
if (item->exa_view_id)
|
if (item->exa_view_id)
|
||||||
{
|
{
|
||||||
jrd_rel* view = MET_lookup_relation_id(tdbb, item->exa_view_id, false);
|
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());
|
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)
|
if (access->acc_ss_rel_id)
|
||||||
{
|
{
|
||||||
@ -488,9 +489,6 @@ void JrdStatement::verifyAccess(thread_db* tdbb)
|
|||||||
userName = view->rel_owner_name;
|
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())
|
if (routine->getName().package.isEmpty())
|
||||||
{
|
{
|
||||||
SCL_check_access(tdbb, sec_class, userName, aclType,
|
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
|
// Invoke buildExternalAccess for triggers in vector
|
||||||
inline void JrdStatement::triggersExternalAccess(thread_db* tdbb, ExternalAccessList& list,
|
inline void JrdStatement::triggersExternalAccess(thread_db* tdbb, ExternalAccessList& list,
|
||||||
TrigVector* tvec)
|
TrigVector* tvec, const MetaName& user)
|
||||||
{
|
{
|
||||||
if (!tvec)
|
if (!tvec)
|
||||||
return;
|
return;
|
||||||
@ -706,34 +704,39 @@ inline void JrdStatement::triggersExternalAccess(thread_db* tdbb, ExternalAccess
|
|||||||
t.compile(tdbb);
|
t.compile(tdbb);
|
||||||
|
|
||||||
if (t.statement)
|
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
|
// Recursively walk external dependencies (procedures, triggers) for request to assemble full
|
||||||
// list of requests it depends on.
|
// 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)
|
for (ExternalAccess* item = externalList.begin(); item != externalList.end(); ++item)
|
||||||
{
|
{
|
||||||
FB_SIZE_T i;
|
FB_SIZE_T i;
|
||||||
if (list.find(*item, i))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
list.insert(i, *item);
|
|
||||||
|
|
||||||
// Add externals recursively
|
// Add externals recursively
|
||||||
if (item->exa_action == ExternalAccess::exa_procedure)
|
if (item->exa_action == ExternalAccess::exa_procedure)
|
||||||
{
|
{
|
||||||
jrd_prc* const procedure = MET_lookup_procedure_id(tdbb, item->exa_prc_id, false, false, 0);
|
jrd_prc* const procedure = MET_lookup_procedure_id(tdbb, item->exa_prc_id, false, false, 0);
|
||||||
if (procedure && procedure->getStatement())
|
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)
|
else if (item->exa_action == ExternalAccess::exa_function)
|
||||||
{
|
{
|
||||||
Function* const function = Function::lookup(tdbb, item->exa_fun_id, false, false, 0);
|
Function* const function = Function::lookup(tdbb, item->exa_fun_id, false, false, 0);
|
||||||
if (function && function->getStatement())
|
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
|
else
|
||||||
{
|
{
|
||||||
@ -762,9 +765,13 @@ void JrdStatement::buildExternalAccess(thread_db* tdbb, ExternalAccessList& list
|
|||||||
continue; // should never happen, silence the compiler
|
continue; // should never happen, silence the compiler
|
||||||
}
|
}
|
||||||
|
|
||||||
triggersExternalAccess(tdbb, list, vec1);
|
item->user = relation->rel_ss_definer.orElse(false) ? relation->rel_owner_name : user;
|
||||||
triggersExternalAccess(tdbb, list, vec2);
|
triggersExternalAccess(tdbb, list, vec1, item->user);
|
||||||
|
triggersExternalAccess(tdbb, list, vec2, item->user);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!list.find(*item, i))
|
||||||
|
list.insert(i, *item);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -59,9 +59,9 @@ public:
|
|||||||
private:
|
private:
|
||||||
static void verifyTriggerAccess(thread_db* tdbb, jrd_rel* ownerRelation, TrigVector* triggers,
|
static void verifyTriggerAccess(thread_db* tdbb, jrd_rel* ownerRelation, TrigVector* triggers,
|
||||||
Firebird::MetaName userName);
|
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:
|
public:
|
||||||
MemoryPool* pool;
|
MemoryPool* pool;
|
||||||
@ -76,7 +76,7 @@ public:
|
|||||||
const jrd_prc* procedure; // procedure, if any
|
const jrd_prc* procedure; // procedure, if any
|
||||||
const Function* function; // function, if any
|
const Function* function; // function, if any
|
||||||
Firebird::MetaName triggerName; // name of request (trigger), 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
|
JrdStatement* parentStatement; // Sub routine's parent statement
|
||||||
Firebird::Array<JrdStatement*> subStatements; // Array of subroutines' statements
|
Firebird::Array<JrdStatement*> subStatements; // Array of subroutines' statements
|
||||||
const StmtNode* topNode; // top of execution tree
|
const StmtNode* topNode; // top of execution tree
|
||||||
|
@ -38,6 +38,7 @@ namespace Jrd
|
|||||||
class Lock;
|
class Lock;
|
||||||
class Format;
|
class Format;
|
||||||
class Parameter;
|
class Parameter;
|
||||||
|
class UserId;
|
||||||
|
|
||||||
class Routine : public Firebird::PermanentStorage
|
class Routine : public Firebird::PermanentStorage
|
||||||
{
|
{
|
||||||
@ -60,7 +61,8 @@ namespace Jrd
|
|||||||
useCount(0),
|
useCount(0),
|
||||||
intUseCount(0),
|
intUseCount(0),
|
||||||
alterCount(0),
|
alterCount(0),
|
||||||
existenceLock(NULL)
|
existenceLock(NULL),
|
||||||
|
invoker(NULL)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -180,8 +182,8 @@ namespace Jrd
|
|||||||
USHORT alterCount; // No. of times the routine was altered
|
USHORT alterCount; // No. of times the routine was altered
|
||||||
Lock* existenceLock; // existence lock, if any
|
Lock* existenceLock; // existence lock, if any
|
||||||
|
|
||||||
Nullable<bool> ssDefiner; // true ? SQL DEFINER : SQL INVOKER
|
|
||||||
Firebird::MetaName owner;
|
Firebird::MetaName owner;
|
||||||
|
Jrd::UserId* invoker; // Invoker ID
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -335,6 +335,7 @@ const char
|
|||||||
CURRENT_ROLE_NAME[] = "CURRENT_ROLE",
|
CURRENT_ROLE_NAME[] = "CURRENT_ROLE",
|
||||||
SESSION_IDLE_TIMEOUT[] = "SESSION_IDLE_TIMEOUT",
|
SESSION_IDLE_TIMEOUT[] = "SESSION_IDLE_TIMEOUT",
|
||||||
STATEMENT_TIMEOUT[] = "STATEMENT_TIMEOUT",
|
STATEMENT_TIMEOUT[] = "STATEMENT_TIMEOUT",
|
||||||
|
EFFECTIVE_USER_NAME[] = "EFFECTIVE_USER",
|
||||||
// SYSTEM namespace: transaction wise items
|
// SYSTEM namespace: transaction wise items
|
||||||
TRANSACTION_ID_NAME[] = "TRANSACTION_ID",
|
TRANSACTION_ID_NAME[] = "TRANSACTION_ID",
|
||||||
ISOLATION_LEVEL_NAME[] = "ISOLATION_LEVEL",
|
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());
|
resultStr.printf("%d", EDS::Manager::getConnPool()->getLifeTime());
|
||||||
else if (nameStr == REPLICATION_SEQ_NAME)
|
else if (nameStr == REPLICATION_SEQ_NAME)
|
||||||
resultStr.printf("%" UQUADFORMAT, dbb->getReplSequence(tdbb));
|
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
|
else
|
||||||
{
|
{
|
||||||
// "Context variable %s is not found in namespace %s"
|
// "Context variable %s is not found in namespace %s"
|
||||||
|
@ -1158,7 +1158,13 @@ void EXE_execute_triggers(thread_db* tdbb,
|
|||||||
|
|
||||||
TraceTrigExecute trace(tdbb, trigger, which_trig);
|
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);
|
const bool ok = (trigger->req_operation != jrd_req::req_unwind);
|
||||||
trace.finish(ok ? ITracePlugin::RESULT_SUCCESS : ITracePlugin::RESULT_FAILED);
|
trace.finish(ok ? ITracePlugin::RESULT_SUCCESS : ITracePlugin::RESULT_FAILED);
|
||||||
|
@ -252,6 +252,7 @@ struct ExternalAccess
|
|||||||
USHORT exa_fun_id;
|
USHORT exa_fun_id;
|
||||||
USHORT exa_rel_id;
|
USHORT exa_rel_id;
|
||||||
USHORT exa_view_id;
|
USHORT exa_view_id;
|
||||||
|
Firebird::MetaName user; // User which touch the recources.
|
||||||
|
|
||||||
// Procedure
|
// Procedure
|
||||||
ExternalAccess(exa_act action, USHORT id) :
|
ExternalAccess(exa_act action, USHORT id) :
|
||||||
@ -279,6 +280,8 @@ struct ExternalAccess
|
|||||||
return i1.exa_rel_id > i2.exa_rel_id;
|
return i1.exa_rel_id > i2.exa_rel_id;
|
||||||
if (i1.exa_view_id != i2.exa_view_id)
|
if (i1.exa_view_id != i2.exa_view_id)
|
||||||
return 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
|
return false; // Equal
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -461,12 +461,14 @@ void InternalStatement::doPrepare(thread_db* tdbb, const string& sql)
|
|||||||
if (statement && statement->parentStatement)
|
if (statement && statement->parentStatement)
|
||||||
statement = statement->parentStatement;
|
statement = statement->parentStatement;
|
||||||
|
|
||||||
if (statement && statement->triggerName.hasData())
|
if (statement && statement->triggerInvoker)
|
||||||
tran->getHandle()->tra_caller_name = CallerName(obj_trigger, statement->triggerName, statement->triggerOwner);
|
tran->getHandle()->tra_caller_name = CallerName(obj_trigger,
|
||||||
|
statement->triggerName,
|
||||||
|
statement->triggerInvoker->getUserName());
|
||||||
else if (statement && (routine = statement->getRoutine()) &&
|
else if (statement && (routine = statement->getRoutine()) &&
|
||||||
routine->getName().identifier.hasData())
|
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())
|
if (routine->getName().package.isEmpty())
|
||||||
{
|
{
|
||||||
tran->getHandle()->tra_caller_name = CallerName(routine->getObjectType(),
|
tran->getHandle()->tra_caller_name = CallerName(routine->getObjectType(),
|
||||||
|
@ -915,8 +915,8 @@ void Trigger::compile(thread_db* tdbb)
|
|||||||
}
|
}
|
||||||
|
|
||||||
statement->triggerName = name;
|
statement->triggerName = name;
|
||||||
if (ssDefiner.specified && ssDefiner.value)
|
if (ssDefiner.orElse(false))
|
||||||
statement->triggerOwner = owner;
|
statement->triggerInvoker = att->getUserId(owner);
|
||||||
|
|
||||||
if (sys_trigger)
|
if (sys_trigger)
|
||||||
statement->flags |= JrdStatement::FLAG_SYS_TRIGGER;
|
statement->flags |= JrdStatement::FLAG_SYS_TRIGGER;
|
||||||
|
@ -3325,6 +3325,7 @@ jrd_prc* MET_procedure(thread_db* tdbb, USHORT id, bool noscan, USHORT flags)
|
|||||||
}
|
}
|
||||||
|
|
||||||
procedure->setId(P.RDB$PROCEDURE_ID);
|
procedure->setId(P.RDB$PROCEDURE_ID);
|
||||||
|
Nullable<bool> ssDefiner;
|
||||||
|
|
||||||
if (!P.RDB$SECURITY_CLASS.NULL)
|
if (!P.RDB$SECURITY_CLASS.NULL)
|
||||||
procedure->setSecurityName(P.RDB$SECURITY_CLASS);
|
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);
|
procedure->setSecurityName(PKG.RDB$SECURITY_CLASS);
|
||||||
|
|
||||||
if (!PKG.RDB$SQL_SECURITY.NULL)
|
if (!PKG.RDB$SQL_SECURITY.NULL)
|
||||||
procedure->ssDefiner = (bool) PKG.RDB$SQL_SECURITY;
|
ssDefiner = (bool) PKG.RDB$SQL_SECURITY;
|
||||||
}
|
}
|
||||||
END_FOR
|
END_FOR
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!procedure->ssDefiner.specified)
|
if (!ssDefiner.specified)
|
||||||
{
|
{
|
||||||
if (!P.RDB$SQL_SECURITY.NULL)
|
if (!P.RDB$SQL_SECURITY.NULL)
|
||||||
procedure->ssDefiner = (bool) P.RDB$SQL_SECURITY;
|
ssDefiner = (bool) P.RDB$SQL_SECURITY;
|
||||||
else
|
else
|
||||||
procedure->ssDefiner = MET_get_ss_definer(tdbb);
|
ssDefiner = MET_get_ss_definer(tdbb);
|
||||||
}
|
}
|
||||||
|
|
||||||
procedure->owner = P.RDB$OWNER_NAME;
|
procedure->owner = P.RDB$OWNER_NAME;
|
||||||
|
|
||||||
|
if (ssDefiner.orElse(false))
|
||||||
|
procedure->invoker = attachment->getUserId(procedure->owner);
|
||||||
|
|
||||||
procedure->setImplemented(true);
|
procedure->setImplemented(true);
|
||||||
procedure->getInputFields().resize(P.RDB$PROCEDURE_INPUTS);
|
procedure->getInputFields().resize(P.RDB$PROCEDURE_INPUTS);
|
||||||
procedure->getOutputFields().resize(P.RDB$PROCEDURE_OUTPUTS);
|
procedure->getOutputFields().resize(P.RDB$PROCEDURE_OUTPUTS);
|
||||||
|
@ -158,6 +158,9 @@ bool ProcedureScan::getRecord(thread_db* tdbb) const
|
|||||||
if (--tdbb->tdbb_quantum < 0)
|
if (--tdbb->tdbb_quantum < 0)
|
||||||
JRD_reschedule(tdbb, 0, true);
|
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();
|
jrd_req* const request = tdbb->getRequest();
|
||||||
record_param* const rpb = &request->req_rpb[m_stream];
|
record_param* const rpb = &request->req_rpb[m_stream];
|
||||||
Impure* const impure = request->getImpure<Impure>(m_impure);
|
Impure* const impure = request->getImpure<Impure>(m_impure);
|
||||||
|
@ -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 get_sys_privileges(thread_db* tdbb);
|
||||||
static SecurityClass::flags_t walk_acl(thread_db* tdbb, const Acl&, const MetaName&,
|
static SecurityClass::flags_t walk_acl(thread_db* tdbb, const Acl&, const MetaName&,
|
||||||
SLONG, const Firebird::MetaName&);
|
SLONG, const Firebird::MetaName&);
|
||||||
static void raiseError(SecurityClass::flags_t mask, SLONG type, const Firebird::MetaName& 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& r_name, const MetaName &invoker);
|
||||||
|
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
@ -176,8 +176,8 @@ namespace
|
|||||||
} // anonymous namespace
|
} // anonymous namespace
|
||||||
|
|
||||||
|
|
||||||
static void raiseError(SecurityClass::flags_t mask, SLONG type, const Firebird::MetaName& 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& r_name, const Firebird::MetaName& invoker)
|
||||||
{
|
{
|
||||||
const P_NAMES* names;
|
const P_NAMES* names;
|
||||||
for (names = p_names; names->p_names_priv; 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() ?
|
const Firebird::string fullName = r_name.hasData() ?
|
||||||
r_name.c_str() + Firebird::string(".") + name.c_str() : name.c_str();
|
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::StatusVector status;
|
||||||
Arg::Str(typeAsStr) <<
|
status << Arg::Gds(isc_no_priv) << Arg::Str(names->p_names_string) <<
|
||||||
Arg::Str(fullName));
|
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))
|
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("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
|
// Make fast check first
|
||||||
@ -263,7 +276,7 @@ void SCL_check_access(thread_db* tdbb,
|
|||||||
return;
|
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
|
// Someone is going to reference system table in FK
|
||||||
// Usually it's not good idea
|
// 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.
|
// 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
|
// Someone is going to modify system table layout
|
||||||
// Usually it's not good idea
|
// 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)
|
if (!REL.RDB$SECURITY_CLASS.NULL)
|
||||||
|
@ -261,6 +261,19 @@ public:
|
|||||||
usr_granted_roles = ui.usr_granted_roles;
|
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)
|
UserId(const UserId& ui)
|
||||||
: usr_user_name(ui.usr_user_name),
|
: usr_user_name(ui.usr_user_name),
|
||||||
usr_sql_role_name(ui.usr_sql_role_name),
|
usr_sql_role_name(ui.usr_sql_role_name),
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/* MAX_NUMBER is the next number to be used, always one more than the highest message number. */
|
/* 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 (?, ?, ?, ?);
|
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)
|
('2015-03-17 18:33:00', 'QLI', 1, 533)
|
||||||
('2018-03-17 12:00:00', 'GFIX', 3, 136)
|
('2018-03-17 12:00:00', 'GFIX', 3, 136)
|
||||||
('1996-11-07 13:39:40', 'GPRE', 4, 1)
|
('1996-11-07 13:39:40', 'GPRE', 4, 1)
|
||||||
|
@ -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);
|
('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);
|
('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);
|
('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
|
-- QLI
|
||||||
(NULL, NULL, NULL, NULL, 1, 0, NULL, 'expected type', NULL, NULL);
|
(NULL, NULL, NULL, NULL, 1, 0, NULL, 'expected type', NULL, NULL);
|
||||||
(NULL, NULL, NULL, NULL, 1, 1, NULL, 'bad block type', NULL, NULL);
|
(NULL, NULL, NULL, NULL, 1, 1, NULL, 'bad block type', NULL, NULL);
|
||||||
|
@ -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, '08', '003', 0, 931, 'bad_repl_handle', NULL, NULL)
|
||||||
(-901, '0B', '000', 0, 932, 'tra_snapshot_does_not_exist', 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)
|
(-901, '42', '000', 0, 933, 'eds_input_prm_not_used', NULL, NULL)
|
||||||
|
(-551, '28', '000', 0, 934, 'effective_user', NULL, 'ERROR')
|
||||||
-- GFIX
|
-- GFIX
|
||||||
(-901, '00', '000', 3, 1, 'gfix_db_name', NULL, NULL)
|
(-901, '00', '000', 3, 1, 'gfix_db_name', NULL, NULL)
|
||||||
(-901, '00', '000', 3, 2, 'gfix_invalid_sw', NULL, NULL)
|
(-901, '00', '000', 3, 2, 'gfix_invalid_sw', NULL, NULL)
|
||||||
|
Loading…
Reference in New Issue
Block a user