mirror of
https://github.com/FirebirdSQL/firebird.git
synced 2025-01-22 20:03:02 +01:00
SQL SECURITY Feature (#42)
* Added SQL SECURITY clause to various DDL statements
This commit is contained in:
parent
d3a0723ae4
commit
9aab6ed8cc
162
doc/sql.extensions/README.sql_security.txt
Normal file
162
doc/sql.extensions/README.sql_security.txt
Normal file
@ -0,0 +1,162 @@
|
||||
SQL SECURITY.
|
||||
|
||||
Implements capability to run executable objects regarding SQL SECURITY clause.
|
||||
SQL Standard (2003, 2011) Feature.
|
||||
|
||||
Author:
|
||||
Red Soft, roman.simakov(at)red-soft.ru
|
||||
|
||||
Syntax is:
|
||||
|
||||
CREATE TABLE <TABLENAME> (...) [SQL SECURITY {DEFINER | INVOKER}]
|
||||
ALTER TABLE <TABLENAME> ... [{ALTER SQL SECURITY {DEFINER | INVOKER} | DROP SQL SECURITY}]
|
||||
CREATE [OR ALTER] FUNCTION <FUNCTIONNAME> ... [SQL SECURITY {DEFINER | INVOKER}] AS ...
|
||||
CREATE [OR ALTER] PROCEDURE <PROCEDURENAME> ... [SQL SECURITY {DEFINER | INVOKER}] AS ...
|
||||
CREATE [OR ALTER] TRIGGER <TRIGGERNAME> ... [SQL SECURITY {DEFINER | INVOKER} | DROP SQL SECURITY] [AS ...]
|
||||
CREATE [OR ALTER] PACKAGE <PACKAGENAME> [SQL SECURITY {DEFINER | INVOKER}] AS ...
|
||||
|
||||
Description:
|
||||
|
||||
Makes it possible to execute some objects with permissions of either definer or invoker.
|
||||
By default INVOKER is used to keep backword compatibility.
|
||||
|
||||
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.
|
||||
|
||||
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
|
||||
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.
|
||||
|
||||
|
||||
Example 1. It's enought to grant only SELECT privilege to user US for table T.
|
||||
In case of INVOKER it will require also EXECUTE for function F.
|
||||
|
||||
set term ^;
|
||||
create function f() returns int
|
||||
as
|
||||
begin
|
||||
return 3;
|
||||
end^
|
||||
set term ;^
|
||||
create table t (i integer, c computed by (i + f())) sql security definer;
|
||||
insert into t values (2);
|
||||
grant select on table t to user us;
|
||||
|
||||
commit;
|
||||
|
||||
connect 'localhost:/tmp/7.fdb' user us password 'pas';
|
||||
select * from t;
|
||||
|
||||
|
||||
Example 2. It's enough to grant EXECUTE privilege to user US for function F.
|
||||
In case of INVOKER it will require also INSERT for table T.
|
||||
|
||||
set term ^;
|
||||
create function f (i integer) returns int sql security definer
|
||||
as
|
||||
begin
|
||||
insert into t values (:i);
|
||||
return i + 1;
|
||||
end^
|
||||
set term ;^
|
||||
grant execute on function f to user us;
|
||||
|
||||
commit;
|
||||
|
||||
connect 'localhost:/tmp/59.fdb' user us password 'pas';
|
||||
select f(3) from rdb$database;
|
||||
|
||||
|
||||
Example 3. It's enought to grant only EXECUTE privilege to user US for procedure P.
|
||||
In case of INVOKER it will require also INSERT for table T to either user US or procedure P.
|
||||
|
||||
set term ^;
|
||||
create procedure p (i integer) sql security definer
|
||||
as
|
||||
begin
|
||||
insert into t values (:i);
|
||||
end^
|
||||
set term ;^
|
||||
|
||||
grant execute on procedure p to user us;
|
||||
commit;
|
||||
|
||||
connect 'localhost:/tmp/17.fdb' user us password 'pas';
|
||||
execute procedure p(1);
|
||||
|
||||
|
||||
Example 4. It's enought to grant only INSERT privilege to user US for table TR.
|
||||
In case of INVOKER it will require also INSERT for table T to user US.
|
||||
|
||||
create table tr (i integer);
|
||||
create table t (i integer);
|
||||
set term ^;
|
||||
create trigger tr_ins for tr after insert sql security definer
|
||||
as
|
||||
begin
|
||||
insert into t values (NEW.i);
|
||||
end^
|
||||
set term ;^
|
||||
grant insert on table tr to user us;
|
||||
|
||||
commit;
|
||||
|
||||
connect 'localhost:/tmp/29.fdb' user us password 'pas';
|
||||
insert into tr values(2);
|
||||
|
||||
the same result if specify SQL SECURITY DEFINER for table TR.
|
||||
|
||||
create table tr (i integer) sql security definer;
|
||||
create table t (i integer);
|
||||
set term ^;
|
||||
create trigger tr_ins for tr after insert
|
||||
as
|
||||
begin
|
||||
insert into t values (NEW.i);
|
||||
end^
|
||||
set term ;^
|
||||
grant insert on table tr to user us;
|
||||
|
||||
commit;
|
||||
|
||||
connect 'localhost:/tmp/29.fdb' user us password 'pas';
|
||||
insert into tr values(2);
|
||||
|
||||
|
||||
Example 5. It's enought to grant only EXECUTE privilege to user US for package PK.
|
||||
In case of INVOKER it will require also INSERT for table T to user US.
|
||||
|
||||
create table t (i integer);
|
||||
set term ^;
|
||||
create package pk sql security definer
|
||||
as
|
||||
begin
|
||||
function f(i integer) returns int;
|
||||
end^
|
||||
|
||||
create package body pk
|
||||
as
|
||||
begin
|
||||
function f(i integer) returns int
|
||||
as
|
||||
begin
|
||||
insert into t values (:i);
|
||||
return i + 1;
|
||||
end
|
||||
end^
|
||||
set term ;^
|
||||
grant execute on package pk to user us;
|
||||
|
||||
commit;
|
||||
|
||||
connect 'localhost:/tmp/69.fdb' user us password 'pas';
|
||||
select pk.f(3) from rdb$database;
|
||||
|
||||
Example 6. Altering explicit option SQL SECURITY for triggers.
|
||||
To remove explicit SQL SECURITY OPTION from trigger you can execute:
|
||||
alter trigger tr_ins drop sql security;
|
||||
|
||||
To set it again to SQL SECURITY INVOKER you can:
|
||||
alter trigger tr_ins sql security invoker;
|
2
extern/btyacc/defs.h
vendored
2
extern/btyacc/defs.h
vendored
@ -23,7 +23,7 @@
|
||||
#define MAXCHAR 255
|
||||
#define MAXSHORT ((int)0x7FFFFFFF)
|
||||
#define MINSHORT ((int)0x80000000)
|
||||
#define MAXTABLE 120000
|
||||
#define MAXTABLE 200000
|
||||
|
||||
#ifdef __MSDOS__
|
||||
#define BITS_PER_WORD 16
|
||||
|
@ -1792,6 +1792,8 @@ C --
|
||||
PARAMETER (GDS__dsql_no_output_sqlda = 336003110)
|
||||
INTEGER*4 GDS__dsql_wrong_param_num
|
||||
PARAMETER (GDS__dsql_wrong_param_num = 336003111)
|
||||
INTEGER*4 GDS__dsql_invalid_drop_ss_clause
|
||||
PARAMETER (GDS__dsql_invalid_drop_ss_clause = 336003112)
|
||||
INTEGER*4 GDS__dyn_filter_not_found
|
||||
PARAMETER (GDS__dyn_filter_not_found = 336068645)
|
||||
INTEGER*4 GDS__dyn_func_not_found
|
||||
|
@ -1787,6 +1787,8 @@ const
|
||||
gds_dsql_no_output_sqlda = 336003110;
|
||||
isc_dsql_wrong_param_num = 336003111;
|
||||
gds_dsql_wrong_param_num = 336003111;
|
||||
isc_dsql_invalid_drop_ss_clause = 336003112;
|
||||
gds_dsql_invalid_drop_ss_clause = 336003112;
|
||||
isc_dyn_filter_not_found = 336068645;
|
||||
gds_dyn_filter_not_found = 336068645;
|
||||
isc_dyn_func_not_found = 336068649;
|
||||
|
@ -118,6 +118,7 @@ void put_index(burp_rel*);
|
||||
int put_message(att_type, att_type, const TEXT*, const ULONG);
|
||||
void put_int32(att_type, SLONG);
|
||||
void put_int64(att_type attribute, SINT64 value);
|
||||
void put_boolean(att_type, FB_BOOLEAN value);
|
||||
void put_relation(burp_rel*);
|
||||
bool put_source_blob(att_type, att_type, ISC_QUAD&);
|
||||
int put_text(att_type, const TEXT*, SSHORT);
|
||||
@ -2009,6 +2010,24 @@ void put_int64( att_type attribute, SINT64 value)
|
||||
}
|
||||
|
||||
|
||||
void put_boolean(att_type attribute, const FB_BOOLEAN value)
|
||||
{
|
||||
/**************************************
|
||||
*
|
||||
* p u t _ b o o l e a n
|
||||
*
|
||||
**************************************
|
||||
*
|
||||
* Functional description
|
||||
* Write a FB_BOOLEAN value as an attribute.
|
||||
**************************************/
|
||||
BurpGlobals* tdgbl = BurpGlobals::getSpecific();
|
||||
|
||||
put(tdgbl, attribute);
|
||||
put(tdgbl, value ? 1u : 0u);
|
||||
}
|
||||
|
||||
|
||||
void put_relation( burp_rel* relation)
|
||||
{
|
||||
/**************************************
|
||||
@ -2946,6 +2965,8 @@ void write_functions()
|
||||
put_int32(att_function_legacy_flag, X.RDB$LEGACY_FLAG);
|
||||
if (!X.RDB$DETERMINISTIC_FLAG.NULL)
|
||||
put_int32(att_function_deterministic_flag, X.RDB$DETERMINISTIC_FLAG);
|
||||
if (!X.RDB$SQL_SECURITY.NULL)
|
||||
put_boolean(att_function_sql_security, X.RDB$SQL_SECURITY);
|
||||
|
||||
put(tdgbl, att_end);
|
||||
|
||||
@ -3523,6 +3544,9 @@ void write_packages()
|
||||
if (!X.RDB$DESCRIPTION.NULL)
|
||||
put_source_blob(att_package_description, att_package_description, X.RDB$DESCRIPTION);
|
||||
|
||||
if (!X.RDB$SQL_SECURITY.NULL)
|
||||
put_boolean(att_package_sql_security, X.RDB$SQL_SECURITY);
|
||||
|
||||
put(tdgbl, att_end);
|
||||
}
|
||||
END_FOR
|
||||
@ -3602,6 +3626,9 @@ void write_procedures()
|
||||
if (!X.RDB$PRIVATE_FLAG.NULL)
|
||||
put_int32(att_procedure_private_flag, X.RDB$PRIVATE_FLAG);
|
||||
|
||||
if (!X.RDB$SQL_SECURITY.NULL)
|
||||
put_boolean(att_procedure_sql_security, X.RDB$SQL_SECURITY);
|
||||
|
||||
put(tdgbl, att_end);
|
||||
COPY(X.RDB$PROCEDURE_NAME, proc);
|
||||
write_procedure_prms ((X.RDB$PACKAGE_NAME.NULL ? "" : X.RDB$PACKAGE_NAME), proc);
|
||||
@ -3872,6 +3899,9 @@ void write_relations()
|
||||
if (!X.RDB$RELATION_TYPE.NULL)
|
||||
put_int32 (att_relation_type, X.RDB$RELATION_TYPE);
|
||||
|
||||
if (!X.RDB$SQL_SECURITY.NULL)
|
||||
put_boolean(att_relation_sql_security, X.RDB$SQL_SECURITY);
|
||||
|
||||
put(tdgbl, att_end);
|
||||
burp_rel* relation = (burp_rel*) BURP_alloc_zero (sizeof(burp_rel));
|
||||
relation->rel_next = tdgbl->relations;
|
||||
@ -4226,6 +4256,9 @@ void write_triggers()
|
||||
if (!X.RDB$ENTRYPOINT.NULL)
|
||||
PUT_TEXT(att_trig_entrypoint, X.RDB$ENTRYPOINT);
|
||||
|
||||
if (!X.RDB$SQL_SECURITY.NULL)
|
||||
put_boolean(att_trig_sql_security, X.RDB$SQL_SECURITY);
|
||||
|
||||
put(tdgbl, att_end);
|
||||
|
||||
END_FOR;
|
||||
|
@ -197,9 +197,11 @@ Version 9: FB2.5.
|
||||
|
||||
Version 10: FB3.0.
|
||||
See backup_capabilities in OdsDetection.h.
|
||||
|
||||
Version 11: FB 4.0
|
||||
*/
|
||||
|
||||
const int ATT_BACKUP_FORMAT = 10;
|
||||
const int ATT_BACKUP_FORMAT = 11;
|
||||
|
||||
// format version number for ranges for arrays
|
||||
|
||||
@ -267,6 +269,7 @@ enum att_type {
|
||||
att_relation_flags,
|
||||
att_relation_ext_file_name, // name of file for external tables
|
||||
att_relation_type,
|
||||
att_relation_sql_security,
|
||||
|
||||
// Field attributes (used for both global and local fields)
|
||||
|
||||
@ -400,6 +403,7 @@ enum att_type {
|
||||
att_trig_engine_name,
|
||||
att_trig_entrypoint,
|
||||
att_trig_type2,
|
||||
att_trig_sql_security,
|
||||
|
||||
// Function attributes
|
||||
|
||||
@ -423,6 +427,7 @@ enum att_type {
|
||||
att_function_owner_name,
|
||||
att_function_legacy_flag,
|
||||
att_function_deterministic_flag,
|
||||
att_function_sql_security,
|
||||
|
||||
// Function argument attributes
|
||||
|
||||
@ -518,6 +523,7 @@ enum att_type {
|
||||
att_procedure_entrypoint,
|
||||
att_procedure_package_name,
|
||||
att_procedure_private_flag,
|
||||
att_procedure_sql_security,
|
||||
|
||||
// Stored procedure parameter attributes
|
||||
|
||||
@ -617,7 +623,8 @@ enum att_type {
|
||||
att_package_valid_body_flag,
|
||||
att_package_security_class,
|
||||
att_package_owner_name,
|
||||
att_package_description
|
||||
att_package_description,
|
||||
att_package_sql_security
|
||||
};
|
||||
|
||||
|
||||
|
@ -182,6 +182,11 @@ static inline int get(BurpGlobals* tdgbl)
|
||||
return MVOL_read(&tdgbl->io_cnt, &tdgbl->io_ptr);
|
||||
}
|
||||
|
||||
static inline FB_BOOLEAN get_boolean(BurpGlobals* tdgbl)
|
||||
{
|
||||
return get(tdgbl) ? FB_TRUE : FB_FALSE;
|
||||
}
|
||||
|
||||
static inline att_type get_attribute(att_type* att, BurpGlobals* tdgbl)
|
||||
{
|
||||
*att = (att_type) get(tdgbl);
|
||||
@ -4181,6 +4186,8 @@ bool get_function(BurpGlobals* tdgbl)
|
||||
X.RDB$LEGACY_FLAG.NULL = FALSE;
|
||||
X.RDB$LEGACY_FLAG = 1;
|
||||
|
||||
X.RDB$SQL_SECURITY.NULL = TRUE;
|
||||
|
||||
skip_init(&scan_next_attr);
|
||||
while (skip_scan(&scan_next_attr), get_attribute(&attribute, tdgbl) != att_end)
|
||||
{
|
||||
@ -4350,6 +4357,16 @@ bool get_function(BurpGlobals* tdgbl)
|
||||
bad_attribute(scan_next_attr, attribute, 89);
|
||||
break;
|
||||
|
||||
case att_function_sql_security:
|
||||
if (tdgbl->RESTORE_format >= 11)
|
||||
{
|
||||
X.RDB$SQL_SECURITY = get_boolean(tdgbl);
|
||||
X.RDB$SQL_SECURITY.NULL = FALSE;
|
||||
}
|
||||
else
|
||||
bad_attribute(scan_next_attr, attribute, 89);
|
||||
break;
|
||||
|
||||
default:
|
||||
bad_attribute(scan_next_attr, attribute, 89);
|
||||
// msg 89 function
|
||||
@ -4471,6 +4488,13 @@ bool get_function(BurpGlobals* tdgbl)
|
||||
bad_attribute(scan_next_attr, attribute, 89);
|
||||
break;
|
||||
|
||||
case att_function_sql_security:
|
||||
if (tdgbl->RESTORE_format >= 11)
|
||||
get_boolean(tdgbl);
|
||||
else
|
||||
bad_attribute(scan_next_attr, attribute, 89);
|
||||
break;
|
||||
|
||||
default:
|
||||
bad_attribute(scan_next_attr, attribute, 89);
|
||||
// msg 89 function
|
||||
@ -6551,6 +6575,7 @@ bool get_package(BurpGlobals* tdgbl)
|
||||
X.RDB$SYSTEM_FLAG = 0;
|
||||
X.RDB$SYSTEM_FLAG.NULL = FALSE;
|
||||
X.RDB$DESCRIPTION.NULL = TRUE;
|
||||
X.RDB$SQL_SECURITY.NULL = TRUE;
|
||||
|
||||
skip_init(&scan_next_attr);
|
||||
while (skip_scan(&scan_next_attr), get_attribute(&attribute, tdgbl) != att_end)
|
||||
@ -6594,6 +6619,16 @@ bool get_package(BurpGlobals* tdgbl)
|
||||
X.RDB$DESCRIPTION.NULL = FALSE;
|
||||
break;
|
||||
|
||||
case att_package_sql_security:
|
||||
if (tdgbl->RESTORE_format >= 11)
|
||||
{
|
||||
X.RDB$SQL_SECURITY = get_boolean(tdgbl);
|
||||
X.RDB$SQL_SECURITY.NULL = FALSE;
|
||||
}
|
||||
else
|
||||
bad_attribute(scan_next_attr, attribute, 338);
|
||||
break;
|
||||
|
||||
default:
|
||||
bad_attribute(scan_next_attr, attribute, 338); // msg 338 package
|
||||
break;
|
||||
@ -6656,6 +6691,7 @@ bool get_procedure(BurpGlobals* tdgbl)
|
||||
X.RDB$ENTRYPOINT.NULL = TRUE;
|
||||
X.RDB$PACKAGE_NAME.NULL = TRUE;
|
||||
X.RDB$PRIVATE_FLAG.NULL = TRUE;
|
||||
X.RDB$SQL_SECURITY.NULL = TRUE;
|
||||
|
||||
skip_init(&scan_next_attr);
|
||||
while (skip_scan(&scan_next_attr), get_attribute(&attribute, tdgbl) != att_end)
|
||||
@ -6800,6 +6836,16 @@ bool get_procedure(BurpGlobals* tdgbl)
|
||||
bad_attribute(scan_next_attr, attribute, 290);
|
||||
break;
|
||||
|
||||
case att_procedure_sql_security:
|
||||
if (tdgbl->RESTORE_format >= 11)
|
||||
{
|
||||
X.RDB$SQL_SECURITY = get_boolean(tdgbl);
|
||||
X.RDB$SQL_SECURITY.NULL = FALSE;
|
||||
}
|
||||
else
|
||||
bad_attribute(scan_next_attr, attribute, 290);
|
||||
break;
|
||||
|
||||
default:
|
||||
bad_attribute(scan_next_attr, attribute, 290);
|
||||
// msg 290 procedure
|
||||
@ -6915,6 +6961,13 @@ bool get_procedure(BurpGlobals* tdgbl)
|
||||
bad_attribute(scan_next_attr, attribute, 290);
|
||||
break;
|
||||
|
||||
case att_procedure_sql_security:
|
||||
if (tdgbl->RESTORE_format >= 11)
|
||||
get_boolean(tdgbl);
|
||||
else
|
||||
bad_attribute(scan_next_attr, attribute, 290);
|
||||
break;
|
||||
|
||||
default:
|
||||
bad_attribute(scan_next_attr, attribute, 290);
|
||||
// msg 290 procedure
|
||||
@ -7280,6 +7333,8 @@ bool get_relation(BurpGlobals* tdgbl)
|
||||
rel_desc = isc_blob_null, ext_desc = isc_blob_null;
|
||||
bool view_blr_null = true, view_src_null = true, rel_desc_null = true,
|
||||
ext_desc_null = true;
|
||||
FB_BOOLEAN sql_security = 0;
|
||||
bool sql_security_null = true;
|
||||
|
||||
BASED_ON RDB$RELATIONS.RDB$SECURITY_CLASS sec_class;
|
||||
sec_class[0] = '\0';
|
||||
@ -7399,6 +7454,11 @@ bool get_relation(BurpGlobals* tdgbl)
|
||||
bad_attribute(scan_next_attr, attribute, 111);
|
||||
break;
|
||||
|
||||
case att_relation_sql_security:
|
||||
sql_security_null = false;
|
||||
sql_security = get_boolean(tdgbl);
|
||||
break;
|
||||
|
||||
default:
|
||||
bad_attribute(scan_next_attr, attribute, 111);
|
||||
// msg 111 table
|
||||
@ -7429,6 +7489,7 @@ bool get_relation(BurpGlobals* tdgbl)
|
||||
X.RDB$EXTERNAL_DESCRIPTION.NULL = ext_desc_null;
|
||||
X.RDB$EXTERNAL_FILE.NULL = ext_file_name_null;
|
||||
X.RDB$RELATION_TYPE.NULL = type_null;
|
||||
X.RDB$SQL_SECURITY.NULL = sql_security_null;
|
||||
|
||||
X.RDB$SYSTEM_FLAG = (USHORT) sys_flag;
|
||||
X.RDB$FLAGS = (USHORT) rel_flags;
|
||||
@ -7442,6 +7503,7 @@ bool get_relation(BurpGlobals* tdgbl)
|
||||
strcpy(X.RDB$EXTERNAL_FILE, ext_file_name);
|
||||
|
||||
X.RDB$RELATION_TYPE = (USHORT) type;
|
||||
X.RDB$SQL_SECURITY = (FB_BOOLEAN) sql_security;
|
||||
|
||||
END_STORE;
|
||||
ON_ERROR
|
||||
@ -8482,6 +8544,7 @@ bool get_trigger(BurpGlobals* tdgbl)
|
||||
X.RDB$DEBUG_INFO.NULL = TRUE;
|
||||
X.RDB$ENGINE_NAME.NULL = TRUE;
|
||||
X.RDB$ENTRYPOINT.NULL = TRUE;
|
||||
X.RDB$SQL_SECURITY.NULL = TRUE;
|
||||
|
||||
skip_init(&scan_next_attr);
|
||||
while (skip_scan(&scan_next_attr), get_attribute(&attribute, tdgbl) != att_end)
|
||||
@ -8594,6 +8657,16 @@ bool get_trigger(BurpGlobals* tdgbl)
|
||||
bad_attribute(scan_next_attr, attribute, 134);
|
||||
break;
|
||||
|
||||
case att_trig_sql_security:
|
||||
if (tdgbl->RESTORE_format >= 11)
|
||||
{
|
||||
X.RDB$SQL_SECURITY = get_boolean(tdgbl);
|
||||
X.RDB$SQL_SECURITY.NULL = FALSE;
|
||||
}
|
||||
else
|
||||
bad_attribute(scan_next_attr, attribute, 134);
|
||||
break;
|
||||
|
||||
default:
|
||||
bad_attribute(scan_next_attr, attribute, 134);
|
||||
// msg 134 trigger
|
||||
@ -8712,6 +8785,13 @@ bool get_trigger(BurpGlobals* tdgbl)
|
||||
bad_attribute(scan_next_attr, attribute, 134);
|
||||
break;
|
||||
|
||||
case att_trig_sql_security:
|
||||
if (tdgbl->RESTORE_format >= 11)
|
||||
get_boolean(tdgbl);
|
||||
else
|
||||
bad_attribute(scan_next_attr, attribute, 134);
|
||||
break;
|
||||
|
||||
default:
|
||||
bad_attribute(scan_next_attr, attribute, 134);
|
||||
// msg 134 trigger
|
||||
|
@ -1612,6 +1612,14 @@ DdlNode* CreateAlterFunctionNode::dsqlPass(DsqlCompilerScratch* dsqlScratch)
|
||||
if (returnType && returnType->type)
|
||||
returnType->type->resolve(dsqlScratch);
|
||||
|
||||
// check SQL SECURITY is not set if function declared in package
|
||||
if (package.hasData() && ssDefiner.specified)
|
||||
{
|
||||
// parameter without default value after parameters with default
|
||||
ERRD_post(Arg::Gds(isc_sqlerr) << Arg::Num(-204) <<
|
||||
Arg::Gds(isc_invalid_clause) << Arg::Str("SQL SECURITY for functions is prohibit in packages"));
|
||||
}
|
||||
|
||||
return DdlNode::dsqlPass(dsqlScratch);
|
||||
}
|
||||
|
||||
@ -1803,6 +1811,14 @@ bool CreateAlterFunctionNode::executeAlter(thread_db* tdbb, DsqlCompilerScratch*
|
||||
FUN.RDB$DETERMINISTIC_FLAG.NULL = FALSE;
|
||||
FUN.RDB$DETERMINISTIC_FLAG = deterministic ? TRUE : FALSE;
|
||||
|
||||
if (ssDefiner.specified)
|
||||
{
|
||||
FUN.RDB$SQL_SECURITY.NULL = FALSE;
|
||||
FUN.RDB$SQL_SECURITY = ssDefiner.value ? 1 : 0;
|
||||
}
|
||||
else
|
||||
FUN.RDB$SQL_SECURITY.NULL = TRUE;
|
||||
|
||||
if (isUdf())
|
||||
{
|
||||
dsql_fld* field = returnType ? returnType->type : NULL;
|
||||
@ -2601,6 +2617,14 @@ DdlNode* CreateAlterProcedureNode::dsqlPass(DsqlCompilerScratch* dsqlScratch)
|
||||
for (unsigned i = 0; i < returns.getCount(); ++i)
|
||||
returns[i]->type->resolve(dsqlScratch);
|
||||
|
||||
// check SQL SECURITY is not set if function declared in package
|
||||
if (package.hasData() && ssDefiner.specified)
|
||||
{
|
||||
// parameter without default value after parameters with default
|
||||
ERRD_post(Arg::Gds(isc_sqlerr) << Arg::Num(-204) <<
|
||||
Arg::Gds(isc_invalid_clause) << Arg::Str("SQL SECURITY for procedures is prohibit in packages"));
|
||||
}
|
||||
|
||||
return DdlNode::dsqlPass(dsqlScratch);
|
||||
}
|
||||
|
||||
@ -2790,6 +2814,14 @@ bool CreateAlterProcedureNode::executeAlter(thread_db* tdbb, DsqlCompilerScratch
|
||||
}
|
||||
else
|
||||
P.RDB$PRIVATE_FLAG.NULL = TRUE;
|
||||
|
||||
if (ssDefiner.specified)
|
||||
{
|
||||
P.RDB$SQL_SECURITY.NULL = FALSE;
|
||||
P.RDB$SQL_SECURITY = ssDefiner.value ? 1 : 0;
|
||||
}
|
||||
else
|
||||
P.RDB$SQL_SECURITY.NULL = TRUE;
|
||||
}
|
||||
|
||||
if (external)
|
||||
@ -3403,6 +3435,17 @@ bool TriggerDefinition::modify(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch
|
||||
attachment->storeMetaDataBlob(tdbb, transaction, &TRG.RDB$TRIGGER_SOURCE, source);
|
||||
}
|
||||
|
||||
if (ssDefiner.specified)
|
||||
{
|
||||
if (ssDefiner.value != SS_DROP)
|
||||
{
|
||||
TRG.RDB$SQL_SECURITY.NULL = FALSE;
|
||||
TRG.RDB$SQL_SECURITY = ssDefiner.value == SS_DEFINER ? 1 : 0;
|
||||
}
|
||||
else
|
||||
TRG.RDB$SQL_SECURITY.NULL = TRUE;
|
||||
}
|
||||
|
||||
modified = true;
|
||||
END_MODIFY
|
||||
}
|
||||
@ -3451,6 +3494,9 @@ DdlNode* CreateAlterTriggerNode::dsqlPass(DsqlCompilerScratch* dsqlScratch)
|
||||
}
|
||||
}
|
||||
|
||||
if (create && ssDefiner.specified && ssDefiner.value == TriggerDefinition::SS_DROP)
|
||||
status_exception::raise(Arg::Gds(isc_dsql_command_err) << Arg::Gds(isc_dsql_invalid_drop_ss_clause));
|
||||
|
||||
return DdlNode::dsqlPass(dsqlScratch);
|
||||
}
|
||||
|
||||
@ -7207,6 +7253,14 @@ void CreateRelationNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScrat
|
||||
REL.RDB$FLAGS = REL_sql;
|
||||
REL.RDB$RELATION_TYPE = relationType;
|
||||
|
||||
if (ssDefiner.specified)
|
||||
{
|
||||
REL.RDB$SQL_SECURITY.NULL = FALSE;
|
||||
REL.RDB$SQL_SECURITY = ssDefiner.value ? 1 : 0;
|
||||
}
|
||||
else
|
||||
REL.RDB$SQL_SECURITY.NULL = TRUE;
|
||||
|
||||
REL.RDB$VIEW_BLR.NULL = TRUE;
|
||||
REL.RDB$VIEW_SOURCE.NULL = TRUE;
|
||||
REL.RDB$EXTERNAL_FILE.NULL = TRUE;
|
||||
@ -7528,6 +7582,36 @@ void AlterRelationNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratc
|
||||
break;
|
||||
}
|
||||
|
||||
case Clause::TYPE_ALTER_SQL_SECURITY:
|
||||
{
|
||||
AutoRequest request;
|
||||
bool found = false;
|
||||
|
||||
FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction)
|
||||
REL IN RDB$RELATIONS
|
||||
WITH REL.RDB$RELATION_NAME EQ name.c_str()
|
||||
{
|
||||
found = true;
|
||||
|
||||
MODIFY REL
|
||||
{
|
||||
const Nullable<bool> ssDefiner = static_cast<const AlterSqlSecurityClause*>(
|
||||
i->getObject())->ssDefiner;
|
||||
|
||||
if (ssDefiner.specified)
|
||||
{
|
||||
REL.RDB$SQL_SECURITY.NULL = FALSE;
|
||||
REL.RDB$SQL_SECURITY = ssDefiner.value ? TRUE : FALSE;
|
||||
}
|
||||
else
|
||||
REL.RDB$SQL_SECURITY.NULL = TRUE;
|
||||
}
|
||||
END_MODIFY
|
||||
}
|
||||
END_FOR
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
fb_assert(false);
|
||||
break;
|
||||
|
@ -409,6 +409,7 @@ public:
|
||||
bool privateScope;
|
||||
bool preserveDefaults;
|
||||
SLONG udfReturnPos;
|
||||
Nullable<bool> ssDefiner;
|
||||
};
|
||||
|
||||
|
||||
@ -542,6 +543,7 @@ public:
|
||||
Firebird::MetaName packageOwner;
|
||||
bool privateScope;
|
||||
bool preserveDefaults;
|
||||
Nullable<bool> ssDefiner;
|
||||
};
|
||||
|
||||
|
||||
@ -586,6 +588,13 @@ typedef RecreateNode<CreateAlterProcedureNode, DropProcedureNode, isc_dsql_recre
|
||||
class TriggerDefinition
|
||||
{
|
||||
public:
|
||||
enum SqlSecurity
|
||||
{
|
||||
SS_INVOKER,
|
||||
SS_DEFINER,
|
||||
SS_DROP
|
||||
};
|
||||
|
||||
explicit TriggerDefinition(MemoryPool& p)
|
||||
: name(p),
|
||||
relationName(p),
|
||||
@ -626,6 +635,7 @@ public:
|
||||
Firebird::ByteChunk debugData;
|
||||
USHORT systemFlag;
|
||||
bool fkTrigger;
|
||||
Nullable<SqlSecurity> ssDefiner;
|
||||
};
|
||||
|
||||
|
||||
@ -1230,7 +1240,8 @@ public:
|
||||
TYPE_ALTER_COL_POS,
|
||||
TYPE_ALTER_COL_TYPE,
|
||||
TYPE_DROP_COLUMN,
|
||||
TYPE_DROP_CONSTRAINT
|
||||
TYPE_DROP_CONSTRAINT,
|
||||
TYPE_ALTER_SQL_SECURITY
|
||||
};
|
||||
|
||||
explicit Clause(MemoryPool& p, Type aType)
|
||||
@ -1401,6 +1412,16 @@ public:
|
||||
Firebird::MetaName name;
|
||||
};
|
||||
|
||||
struct AlterSqlSecurityClause : public Clause
|
||||
{
|
||||
explicit AlterSqlSecurityClause(MemoryPool& p)
|
||||
: Clause(p, TYPE_ALTER_SQL_SECURITY)
|
||||
{
|
||||
}
|
||||
|
||||
Nullable<bool> ssDefiner;
|
||||
};
|
||||
|
||||
RelationNode(MemoryPool& p, RelationSourceNode* aDsqlNode);
|
||||
|
||||
static void deleteLocalField(thread_db* tdbb, jrd_tra* transaction,
|
||||
@ -1448,6 +1469,7 @@ public:
|
||||
NestConst<RelationSourceNode> dsqlNode;
|
||||
Firebird::MetaName name;
|
||||
Firebird::Array<NestConst<Clause> > clauses;
|
||||
Nullable<bool> ssDefiner;
|
||||
};
|
||||
|
||||
|
||||
@ -2299,4 +2321,14 @@ public:
|
||||
|
||||
} // namespace
|
||||
|
||||
template <>
|
||||
class NullableClear<Jrd::TriggerDefinition::SqlSecurity> // TriggerDefinition::SqlSecurity especialization for NullableClear
|
||||
{
|
||||
public:
|
||||
static void clear(Jrd::TriggerDefinition::SqlSecurity& v)
|
||||
{
|
||||
v = Jrd::TriggerDefinition::SS_INVOKER;
|
||||
}
|
||||
};
|
||||
|
||||
#endif // DSQL_DDL_NODES_H
|
||||
|
@ -5481,38 +5481,41 @@ ValueExprNode* FieldNode::pass1(thread_db* tdbb, CompilerScratch* csb)
|
||||
// the nodes in the subtree are involved in a validation
|
||||
// clause only, the subtree is a validate_subtree in our notation.
|
||||
|
||||
const SLONG viewId = tail->csb_view ?
|
||||
SLONG ssRelationId = tail->csb_view ?
|
||||
tail->csb_view->rel_id : (csb->csb_view ? csb->csb_view->rel_id : 0);
|
||||
|
||||
if (!ssRelationId && relation->rel_ss_definer.value)
|
||||
ssRelationId = relation->rel_id;
|
||||
|
||||
if (tail->csb_flags & csb_modify)
|
||||
{
|
||||
if (!csb->csb_validate_expr)
|
||||
{
|
||||
SecurityClass::flags_t priv = csb->csb_returning_expr ?
|
||||
SCL_select : SCL_update;
|
||||
CMP_post_access(tdbb, csb, relation->rel_security_name, viewId,
|
||||
CMP_post_access(tdbb, csb, relation->rel_security_name, ssRelationId,
|
||||
priv, SCL_object_table, relation->rel_name);
|
||||
CMP_post_access(tdbb, csb, field->fld_security_name, viewId,
|
||||
CMP_post_access(tdbb, csb, field->fld_security_name, ssRelationId,
|
||||
priv, SCL_object_column, field->fld_name, relation->rel_name);
|
||||
}
|
||||
}
|
||||
else if (tail->csb_flags & csb_erase)
|
||||
{
|
||||
CMP_post_access(tdbb, csb, relation->rel_security_name, viewId,
|
||||
CMP_post_access(tdbb, csb, relation->rel_security_name, ssRelationId,
|
||||
SCL_delete, SCL_object_table, relation->rel_name);
|
||||
}
|
||||
else if (tail->csb_flags & csb_store)
|
||||
{
|
||||
CMP_post_access(tdbb, csb, relation->rel_security_name, viewId,
|
||||
CMP_post_access(tdbb, csb, relation->rel_security_name, ssRelationId,
|
||||
SCL_insert, SCL_object_table, relation->rel_name);
|
||||
CMP_post_access(tdbb, csb, field->fld_security_name, viewId,
|
||||
CMP_post_access(tdbb, csb, field->fld_security_name, ssRelationId,
|
||||
SCL_insert, SCL_object_column, field->fld_name, relation->rel_name);
|
||||
}
|
||||
else
|
||||
{
|
||||
CMP_post_access(tdbb, csb, relation->rel_security_name, viewId,
|
||||
CMP_post_access(tdbb, csb, relation->rel_security_name, ssRelationId,
|
||||
SCL_select, SCL_object_table, relation->rel_name);
|
||||
CMP_post_access(tdbb, csb, field->fld_security_name, viewId,
|
||||
CMP_post_access(tdbb, csb, field->fld_security_name, ssRelationId,
|
||||
SCL_select, SCL_object_column, field->fld_name, relation->rel_name);
|
||||
}
|
||||
|
||||
@ -5578,6 +5581,8 @@ ValueExprNode* FieldNode::pass1(thread_db* tdbb, CompilerScratch* csb)
|
||||
sub = cast;
|
||||
}
|
||||
|
||||
AutoSetRestore<jrd_rel*> autoRelationStream(&csb->csb_parent_relation, relation->rel_ss_definer.value ? relation : 0);
|
||||
|
||||
if (relation->rel_view_rse)
|
||||
{
|
||||
// dimitr: if we reference view columns, we need to pass them
|
||||
@ -11191,8 +11196,15 @@ ValueExprNode* UdfCallNode::pass1(thread_db* tdbb, CompilerScratch* csb)
|
||||
{
|
||||
if (function->getName().package.isEmpty())
|
||||
{
|
||||
CMP_post_access(tdbb, csb, function->getSecurityName(),
|
||||
(csb->csb_view ? csb->csb_view->rel_id : 0),
|
||||
SLONG ssRelationId = csb->csb_view ? csb->csb_view->rel_id : 0;
|
||||
|
||||
if (!ssRelationId && csb->csb_parent_relation)
|
||||
{
|
||||
fb_assert(csb->csb_parent_relation->rel_ss_definer.value);
|
||||
ssRelationId = csb->csb_parent_relation->rel_id;
|
||||
}
|
||||
|
||||
CMP_post_access(tdbb, csb, function->getSecurityName(), ssRelationId,
|
||||
SCL_execute, SCL_object_function, function->getName().identifier);
|
||||
}
|
||||
else
|
||||
|
@ -512,6 +512,14 @@ void CreateAlterPackageNode::executeCreate(thread_db* tdbb, DsqlCompilerScratch*
|
||||
|
||||
PKG.RDB$PACKAGE_HEADER_SOURCE.NULL = FALSE;
|
||||
attachment->storeMetaDataBlob(tdbb, transaction, &PKG.RDB$PACKAGE_HEADER_SOURCE, source);
|
||||
|
||||
if (ssDefiner.specified)
|
||||
{
|
||||
PKG.RDB$SQL_SECURITY.NULL = FALSE;
|
||||
PKG.RDB$SQL_SECURITY = ssDefiner.value ? 1 : 0;
|
||||
}
|
||||
else
|
||||
PKG.RDB$SQL_SECURITY.NULL = TRUE;
|
||||
}
|
||||
END_STORE
|
||||
|
||||
@ -577,6 +585,15 @@ bool CreateAlterPackageNode::executeAlter(thread_db* tdbb, DsqlCompilerScratch*
|
||||
|
||||
if (!PKG.RDB$VALID_BODY_FLAG.NULL)
|
||||
PKG.RDB$VALID_BODY_FLAG = FALSE;
|
||||
|
||||
if (ssDefiner.specified)
|
||||
{
|
||||
PKG.RDB$SQL_SECURITY.NULL = FALSE;
|
||||
PKG.RDB$SQL_SECURITY = ssDefiner.value ? 1 : 0;
|
||||
}
|
||||
else
|
||||
PKG.RDB$SQL_SECURITY.NULL = TRUE;
|
||||
|
||||
END_MODIFY
|
||||
|
||||
owner = PKG.RDB$OWNER_NAME;
|
||||
|
@ -110,6 +110,7 @@ public:
|
||||
Firebird::Array<Item>* items;
|
||||
Firebird::SortedArray<Firebird::MetaName> functionNames;
|
||||
Firebird::SortedArray<Firebird::MetaName> procedureNames;
|
||||
Nullable<bool> ssDefiner;
|
||||
|
||||
private:
|
||||
Firebird::MetaName owner;
|
||||
|
150
src/dsql/parse.y
150
src/dsql/parse.y
@ -607,6 +607,10 @@ using namespace Firebird;
|
||||
%token <metaNamePtr> TIES
|
||||
%token <metaNamePtr> UNBOUNDED
|
||||
%token <metaNamePtr> WINDOW
|
||||
%token <metaNamePtr> SQL
|
||||
%token <metaNamePtr> SECURITY
|
||||
%token <metaNamePtr> INVOKER
|
||||
%token <metaNamePtr> DEFINER
|
||||
|
||||
// precedence declarations for expression evaluation
|
||||
|
||||
@ -638,6 +642,7 @@ using namespace Firebird;
|
||||
{
|
||||
BaseNullable<int> nullableIntVal;
|
||||
BaseNullable<bool> nullableBoolVal;
|
||||
BaseNullable<Jrd::TriggerDefinition::SqlSecurity> nullableSqlSecurityVal;
|
||||
bool boolVal;
|
||||
int intVal;
|
||||
unsigned uintVal;
|
||||
@ -2057,22 +2062,38 @@ page_noise
|
||||
%type <createRelationNode> table_clause
|
||||
table_clause
|
||||
: simple_table_name external_file
|
||||
{ $<createRelationNode>$ = newNode<CreateRelationNode>($1, $2); }
|
||||
'(' table_elements($3) ')'
|
||||
{ $$ = $3; }
|
||||
{
|
||||
$<createRelationNode>$ = newNode<CreateRelationNode>($1, $2);
|
||||
}
|
||||
'(' table_elements($3) ')' sql_security_clause
|
||||
{
|
||||
$$ = $3;
|
||||
$$->ssDefiner = $7;
|
||||
}
|
||||
;
|
||||
|
||||
%type <createRelationNode> gtt_table_clause
|
||||
gtt_table_clause
|
||||
: simple_table_name
|
||||
{ $<createRelationNode>$ = newNode<CreateRelationNode>($1); }
|
||||
'(' table_elements($2) ')' gtt_scope
|
||||
'(' table_elements($2) ')' gtt_ops($2)
|
||||
{
|
||||
$$ = $2;
|
||||
$$->relationType = static_cast<rel_t>($6);
|
||||
}
|
||||
;
|
||||
|
||||
%type gtt_ops(<createRelationNode>)
|
||||
gtt_ops($createRelationNode)
|
||||
: gtt_op($createRelationNode)
|
||||
| gtt_ops ',' gtt_op($createRelationNode)
|
||||
;
|
||||
|
||||
%type gtt_op(<createRelationNode>)
|
||||
gtt_op($createRelationNode)
|
||||
: sql_security_clause { $createRelationNode->ssDefiner = $1; }
|
||||
| gtt_scope { $createRelationNode->relationType = static_cast<rel_t>($1); }
|
||||
;
|
||||
|
||||
%type <intVal> gtt_scope
|
||||
gtt_scope
|
||||
: /* nothing */ { $$ = rel_global_temp_delete; }
|
||||
@ -2099,7 +2120,6 @@ table_element($createRelationNode)
|
||||
| table_constraint_definition($createRelationNode)
|
||||
;
|
||||
|
||||
|
||||
// column definition
|
||||
|
||||
%type column_def(<relationNode>)
|
||||
@ -2457,12 +2477,13 @@ procedure_clause
|
||||
|
||||
%type <createAlterProcedureNode> psql_procedure_clause
|
||||
psql_procedure_clause
|
||||
: procedure_clause_start AS local_declaration_list full_proc_block
|
||||
: procedure_clause_start sql_security_clause AS local_declaration_list full_proc_block
|
||||
{
|
||||
$$ = $1;
|
||||
$$->source = makeParseStr(YYPOSNARG(3), YYPOSNARG(4));
|
||||
$$->localDeclList = $3;
|
||||
$$->body = $4;
|
||||
$$->ssDefiner = $2;
|
||||
$$->source = makeParseStr(YYPOSNARG(4), YYPOSNARG(5));
|
||||
$$->localDeclList = $4;
|
||||
$$->body = $5;
|
||||
}
|
||||
;
|
||||
|
||||
@ -2480,11 +2501,23 @@ external_procedure_clause
|
||||
%type <createAlterProcedureNode> procedure_clause_start
|
||||
procedure_clause_start
|
||||
: symbol_procedure_name
|
||||
{ $$ = newNode<CreateAlterProcedureNode>(*$1); }
|
||||
{
|
||||
$$ = newNode<CreateAlterProcedureNode>(*$1);
|
||||
}
|
||||
input_parameters(NOTRIAL(&$2->parameters)) output_parameters(NOTRIAL(&$2->returns))
|
||||
{ $$ = $2; }
|
||||
;
|
||||
|
||||
%type <nullableBoolVal> sql_security_clause
|
||||
sql_security_clause
|
||||
: SQL SECURITY DEFINER
|
||||
{ $$ = Nullable<bool>::val(true); }
|
||||
| SQL SECURITY INVOKER
|
||||
{ $$ = Nullable<bool>::val(false); }
|
||||
| // nothing
|
||||
{ $$ = Nullable<bool>::empty(); }
|
||||
;
|
||||
|
||||
%type <createAlterProcedureNode> alter_procedure_clause
|
||||
alter_procedure_clause
|
||||
: procedure_clause
|
||||
@ -2580,12 +2613,13 @@ function_clause
|
||||
|
||||
%type <createAlterFunctionNode> psql_function_clause
|
||||
psql_function_clause
|
||||
: function_clause_start AS local_declaration_list full_proc_block
|
||||
: function_clause_start sql_security_clause AS local_declaration_list full_proc_block
|
||||
{
|
||||
$$ = $1;
|
||||
$$->source = makeParseStr(YYPOSNARG(3), YYPOSNARG(4));
|
||||
$$->localDeclList = $3;
|
||||
$$->body = $4;
|
||||
$$->ssDefiner = $2;
|
||||
$$->source = makeParseStr(YYPOSNARG(4), YYPOSNARG(5));
|
||||
$$->localDeclList = $4;
|
||||
$$->body = $5;
|
||||
}
|
||||
;
|
||||
|
||||
@ -2603,7 +2637,9 @@ external_function_clause
|
||||
%type <createAlterFunctionNode> function_clause_start
|
||||
function_clause_start
|
||||
: symbol_UDF_name
|
||||
{ $$ = newNode<CreateAlterFunctionNode>(*$1); }
|
||||
{
|
||||
$$ = newNode<CreateAlterFunctionNode>(*$1);
|
||||
}
|
||||
input_parameters(NOTRIAL(&$2->parameters))
|
||||
RETURNS domain_or_non_array_type collate_clause deterministic_opt
|
||||
{
|
||||
@ -2665,11 +2701,12 @@ replace_function_clause
|
||||
|
||||
%type <createAlterPackageNode> package_clause
|
||||
package_clause
|
||||
: symbol_package_name AS BEGIN package_items_opt END
|
||||
: symbol_package_name sql_security_clause AS BEGIN package_items_opt END
|
||||
{
|
||||
CreateAlterPackageNode* node = newNode<CreateAlterPackageNode>(*$1);
|
||||
node->source = makeParseStr(YYPOSNARG(3), YYPOSNARG(5));
|
||||
node->items = $4;
|
||||
node->ssDefiner = $2;
|
||||
node->source = makeParseStr(YYPOSNARG(4), YYPOSNARG(6));
|
||||
node->items = $5;
|
||||
$$ = node;
|
||||
}
|
||||
;
|
||||
@ -3505,16 +3542,17 @@ check_opt
|
||||
|
||||
%type <createAlterTriggerNode> trigger_clause
|
||||
trigger_clause
|
||||
: symbol_trigger_name trigger_active trigger_type trigger_position
|
||||
: symbol_trigger_name trigger_active trigger_type trigger_position trg_sql_security_clause
|
||||
AS local_declaration_list full_proc_block
|
||||
{
|
||||
$$ = newNode<CreateAlterTriggerNode>(*$1);
|
||||
$$->active = $2;
|
||||
$$->type = $3;
|
||||
$$->position = $4;
|
||||
$$->source = makeParseStr(YYPOSNARG(5), YYPOSNARG(7));
|
||||
$$->localDeclList = $6;
|
||||
$$->body = $7;
|
||||
$$->ssDefiner = $5;
|
||||
$$->source = makeParseStr(YYPOSNARG(6), YYPOSNARG(8));
|
||||
$$->localDeclList = $7;
|
||||
$$->body = $8;
|
||||
}
|
||||
| symbol_trigger_name trigger_active trigger_type trigger_position
|
||||
external_clause external_body_clause_opt
|
||||
@ -3527,7 +3565,7 @@ trigger_clause
|
||||
if ($6)
|
||||
$$->source = *$6;
|
||||
}
|
||||
| symbol_trigger_name trigger_active trigger_type trigger_position ON symbol_table_name
|
||||
| symbol_trigger_name trigger_active trigger_type trigger_position ON symbol_table_name trg_sql_security_clause
|
||||
AS local_declaration_list full_proc_block
|
||||
{
|
||||
$$ = newNode<CreateAlterTriggerNode>(*$1);
|
||||
@ -3535,9 +3573,10 @@ trigger_clause
|
||||
$$->type = $3;
|
||||
$$->position = $4;
|
||||
$$->relationName = *$6;
|
||||
$$->source = makeParseStr(YYPOSNARG(7), YYPOSNARG(9));
|
||||
$$->localDeclList = $8;
|
||||
$$->body = $9;
|
||||
$$->ssDefiner = $7;
|
||||
$$->source = makeParseStr(YYPOSNARG(8), YYPOSNARG(10));
|
||||
$$->localDeclList = $9;
|
||||
$$->body = $10;
|
||||
}
|
||||
| symbol_trigger_name trigger_active trigger_type trigger_position ON symbol_table_name
|
||||
external_clause external_body_clause_opt
|
||||
@ -3551,7 +3590,7 @@ trigger_clause
|
||||
if ($8)
|
||||
$$->source = *$8;
|
||||
}
|
||||
| symbol_trigger_name FOR symbol_table_name trigger_active trigger_type trigger_position
|
||||
| symbol_trigger_name FOR symbol_table_name trigger_active trigger_type trigger_position trg_sql_security_clause
|
||||
AS local_declaration_list full_proc_block
|
||||
{
|
||||
$$ = newNode<CreateAlterTriggerNode>(*$1);
|
||||
@ -3559,9 +3598,10 @@ trigger_clause
|
||||
$$->type = $5;
|
||||
$$->position = $6;
|
||||
$$->relationName = *$3;
|
||||
$$->source = makeParseStr(YYPOSNARG(7), YYPOSNARG(9));
|
||||
$$->localDeclList = $8;
|
||||
$$->body = $9;
|
||||
$$->ssDefiner = $7;
|
||||
$$->source = makeParseStr(YYPOSNARG(8), YYPOSNARG(10));
|
||||
$$->localDeclList = $9;
|
||||
$$->body = $10;
|
||||
}
|
||||
| symbol_trigger_name FOR symbol_table_name trigger_active trigger_type trigger_position
|
||||
external_clause external_body_clause_opt
|
||||
@ -3882,6 +3922,27 @@ alter_op($relationNode)
|
||||
clause->identityRestartValue = $4;
|
||||
$relationNode->clauses.add(clause);
|
||||
}
|
||||
| ALTER SQL SECURITY DEFINER
|
||||
{
|
||||
RelationNode::AlterSqlSecurityClause* clause =
|
||||
newNode<RelationNode::AlterSqlSecurityClause>();
|
||||
clause->ssDefiner = Nullable<bool>::val(true);
|
||||
$relationNode->clauses.add(clause);
|
||||
}
|
||||
| ALTER SQL SECURITY INVOKER
|
||||
{
|
||||
RelationNode::AlterSqlSecurityClause* clause =
|
||||
newNode<RelationNode::AlterSqlSecurityClause>();
|
||||
clause->ssDefiner = Nullable<bool>::val(false);
|
||||
$relationNode->clauses.add(clause);
|
||||
}
|
||||
| DROP SQL SECURITY
|
||||
{
|
||||
RelationNode::AlterSqlSecurityClause* clause =
|
||||
newNode<RelationNode::AlterSqlSecurityClause>();
|
||||
clause->ssDefiner = Nullable<bool>::empty();
|
||||
$relationNode->clauses.add(clause);
|
||||
}
|
||||
;
|
||||
|
||||
%type <metaNamePtr> alter_column_name
|
||||
@ -4105,7 +4166,7 @@ crypt_key_clause($alterDatabaseNode)
|
||||
|
||||
%type <createAlterTriggerNode> alter_trigger_clause
|
||||
alter_trigger_clause
|
||||
: symbol_trigger_name trigger_active trigger_type_opt trigger_position
|
||||
: symbol_trigger_name trigger_active trigger_type_opt trigger_position trg_sql_security_clause
|
||||
AS local_declaration_list full_proc_block
|
||||
{
|
||||
$$ = newNode<CreateAlterTriggerNode>(*$1);
|
||||
@ -4114,9 +4175,10 @@ alter_trigger_clause
|
||||
$$->active = $2;
|
||||
$$->type = $3;
|
||||
$$->position = $4;
|
||||
$$->source = makeParseStr(YYPOSNARG(5), YYPOSNARG(7));
|
||||
$$->localDeclList = $6;
|
||||
$$->body = $7;
|
||||
$$->ssDefiner = $5;
|
||||
$$->source = makeParseStr(YYPOSNARG(6), YYPOSNARG(8));
|
||||
$$->localDeclList = $7;
|
||||
$$->body = $8;
|
||||
}
|
||||
| symbol_trigger_name trigger_active trigger_type_opt trigger_position
|
||||
external_clause external_body_clause_opt
|
||||
@ -4131,7 +4193,7 @@ alter_trigger_clause
|
||||
if ($6)
|
||||
$$->source = *$6;
|
||||
}
|
||||
| symbol_trigger_name trigger_active trigger_type_opt trigger_position
|
||||
| symbol_trigger_name trigger_active trigger_type_opt trigger_position trg_sql_security_clause
|
||||
{
|
||||
$$ = newNode<CreateAlterTriggerNode>(*$1);
|
||||
$$->alter = true;
|
||||
@ -4139,6 +4201,7 @@ alter_trigger_clause
|
||||
$$->active = $2;
|
||||
$$->type = $3;
|
||||
$$->position = $4;
|
||||
$$->ssDefiner = $5;
|
||||
}
|
||||
;
|
||||
|
||||
@ -4150,6 +4213,17 @@ trigger_type_opt // we do not allow alter database triggers, hence we do not use
|
||||
{ $$ = Nullable<FB_UINT64>::empty(); }
|
||||
;
|
||||
|
||||
%type <nullableSqlSecurityVal> trg_sql_security_clause
|
||||
trg_sql_security_clause
|
||||
: SQL SECURITY DEFINER
|
||||
{ $$ = Nullable<TriggerDefinition::SqlSecurity>::val(TriggerDefinition::SS_DEFINER); }
|
||||
| SQL SECURITY INVOKER
|
||||
{ $$ = Nullable<TriggerDefinition::SqlSecurity>::val(TriggerDefinition::SS_INVOKER); }
|
||||
| DROP SQL SECURITY
|
||||
{ $$ = Nullable<TriggerDefinition::SqlSecurity>::val(TriggerDefinition::SS_DROP); }
|
||||
| // nothing
|
||||
{ $$ = Nullable<TriggerDefinition::SqlSecurity>::empty(); }
|
||||
;
|
||||
|
||||
// DROP metadata operations
|
||||
|
||||
@ -8029,6 +8103,10 @@ non_reserved_word
|
||||
| SYSTEM
|
||||
| ERROR_MESSAGE
|
||||
| TIES
|
||||
| SQL
|
||||
| SECURITY
|
||||
| INVOKER
|
||||
| DEFINER
|
||||
;
|
||||
|
||||
%%
|
||||
|
@ -892,6 +892,7 @@ static const struct {
|
||||
{"dsql_no_input_sqlda", 336003109},
|
||||
{"dsql_no_output_sqlda", 336003110},
|
||||
{"dsql_wrong_param_num", 336003111},
|
||||
{"dsql_invalid_drop_ss_clause", 336003112},
|
||||
{"dyn_filter_not_found", 336068645},
|
||||
{"dyn_func_not_found", 336068649},
|
||||
{"dyn_index_not_found", 336068656},
|
||||
|
@ -926,6 +926,7 @@ const ISC_STATUS isc_dsql_no_sqldata = 336003108L;
|
||||
const ISC_STATUS isc_dsql_no_input_sqlda = 336003109L;
|
||||
const ISC_STATUS isc_dsql_no_output_sqlda = 336003110L;
|
||||
const ISC_STATUS isc_dsql_wrong_param_num = 336003111L;
|
||||
const ISC_STATUS isc_dsql_invalid_drop_ss_clause = 336003112L;
|
||||
const ISC_STATUS isc_dyn_filter_not_found = 336068645L;
|
||||
const ISC_STATUS isc_dyn_func_not_found = 336068649L;
|
||||
const ISC_STATUS isc_dyn_index_not_found = 336068656L;
|
||||
@ -1332,7 +1333,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 = 1276;
|
||||
const ISC_STATUS isc_err_max = 1277;
|
||||
|
||||
#else /* c definitions */
|
||||
|
||||
@ -2228,6 +2229,7 @@ const ISC_STATUS isc_err_max = 1276;
|
||||
#define isc_dsql_no_input_sqlda 336003109L
|
||||
#define isc_dsql_no_output_sqlda 336003110L
|
||||
#define isc_dsql_wrong_param_num 336003111L
|
||||
#define isc_dsql_invalid_drop_ss_clause 336003112L
|
||||
#define isc_dyn_filter_not_found 336068645L
|
||||
#define isc_dyn_func_not_found 336068649L
|
||||
#define isc_dyn_index_not_found 336068656L
|
||||
@ -2634,7 +2636,7 @@ const ISC_STATUS isc_err_max = 1276;
|
||||
#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 1276
|
||||
#define isc_err_max 1277
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -145,6 +145,7 @@
|
||||
const USHORT f_rel_def_class = 14;
|
||||
const USHORT f_rel_flags = 15;
|
||||
const USHORT f_rel_type = 16;
|
||||
const USHORT f_rel_sql_security = 17;
|
||||
|
||||
|
||||
// Relation 7 (RDB$VIEW_RELATIONS)
|
||||
@ -206,6 +207,7 @@
|
||||
const USHORT f_trg_debug_info = 11;
|
||||
const USHORT f_trg_engine_name = 12;
|
||||
const USHORT f_trg_entry = 13;
|
||||
const USHORT f_trg_sql_security = 14;
|
||||
|
||||
|
||||
// Relation 13 (RDB$DEPENDENCIES)
|
||||
@ -240,6 +242,7 @@
|
||||
const USHORT f_fun_owner = 17;
|
||||
const USHORT f_fun_legacy_flag = 18;
|
||||
const USHORT f_fun_deterministic_flag = 19;
|
||||
const USHORT f_fun_sql_security = 20;
|
||||
|
||||
|
||||
// Relation 15 (RDB$FUNCTION_ARGUMENTS)
|
||||
@ -383,6 +386,7 @@
|
||||
const USHORT f_prc_entry = 15;
|
||||
const USHORT f_prc_pkg_name = 16;
|
||||
const USHORT f_prc_private_flag = 17;
|
||||
const USHORT f_prc_sql_security = 18;
|
||||
|
||||
|
||||
// Relation 27 (RDB$PROCEDURE_PARAMETERS)
|
||||
@ -616,6 +620,7 @@
|
||||
const USHORT f_pkg_owner = 5;
|
||||
const USHORT f_pkg_sys_flag = 6;
|
||||
const USHORT f_pkg_desc = 7;
|
||||
const USHORT f_pkg_sql_security = 8;
|
||||
|
||||
|
||||
// Relation 43 (SEC$USERS)
|
||||
|
@ -895,6 +895,7 @@ Data source : @4"}, /* eds_statement */
|
||||
{336003109, "No SQLDA for input values provided"}, /* dsql_no_input_sqlda */
|
||||
{336003110, "No SQLDA for output values provided"}, /* dsql_no_output_sqlda */
|
||||
{336003111, "Wrong number of parameters (expected @1, got @2)"}, /* dsql_wrong_param_num */
|
||||
{336003112, "Invalid DROP SQL SECURITY clause"}, /* dsql_invalid_drop_ss_clause */
|
||||
{336068645, "BLOB Filter @1 not found"}, /* dyn_filter_not_found */
|
||||
{336068649, "Function @1 not found"}, /* dyn_func_not_found */
|
||||
{336068656, "Index not found"}, /* dyn_index_not_found */
|
||||
|
@ -891,6 +891,7 @@ static const struct {
|
||||
{336003109, -802}, /* 37 dsql_no_input_sqlda */
|
||||
{336003110, -802}, /* 38 dsql_no_output_sqlda */
|
||||
{336003111, -313}, /* 39 dsql_wrong_param_num */
|
||||
{336003112, -817}, /* 40 dsql_invalid_drop_ss_clause */
|
||||
{336068645, -901}, /* 37 dyn_filter_not_found */
|
||||
{336068649, -901}, /* 41 dyn_func_not_found */
|
||||
{336068656, -901}, /* 48 dyn_index_not_found */
|
||||
|
@ -891,6 +891,7 @@ static const struct {
|
||||
{336003109, "07002"}, // 37 dsql_no_input_sqlda
|
||||
{336003110, "07002"}, // 38 dsql_no_output_sqlda
|
||||
{336003111, "07001"}, // 39 dsql_wrong_param_num
|
||||
{336003112, "42000"}, // 40 dsql_invalid_drop_ss_clause
|
||||
{336068645, "42000"}, // 37 dyn_filter_not_found
|
||||
{336068649, "42000"}, // 41 dyn_func_not_found
|
||||
{336068656, "42000"}, // 48 dyn_index_not_found
|
||||
|
@ -303,6 +303,7 @@ int EXTRACT_list_table(const SCHAR* relation_name,
|
||||
bool first = true;
|
||||
SCHAR char_sets[86];
|
||||
rel_t rel_type = rel_persistent;
|
||||
char ss[28] = "";
|
||||
|
||||
// Query to obtain relation detail information
|
||||
|
||||
@ -350,6 +351,12 @@ int EXTRACT_list_table(const SCHAR* relation_name,
|
||||
else
|
||||
isqlGlob.printf("%s ", new_name ? new_name : relation_name);
|
||||
|
||||
if (!REL.RDB$SQL_SECURITY.NULL)
|
||||
if (REL.RDB$SQL_SECURITY)
|
||||
strcpy(ss, "SQL SECURITY DEFINER");
|
||||
else
|
||||
strcpy(ss, "SQL SECURITY INVOKER");
|
||||
|
||||
if (!REL.RDB$EXTERNAL_FILE.NULL)
|
||||
{
|
||||
IUTILS_copy_SQL_id (REL.RDB$EXTERNAL_FILE, SQL_identifier2, SINGLE_QUOTE);
|
||||
@ -555,10 +562,11 @@ int EXTRACT_list_table(const SCHAR* relation_name,
|
||||
if (first) // we extracted nothing
|
||||
return FINI_ERROR;
|
||||
|
||||
if (rel_type == rel_global_temp_preserve)
|
||||
isqlGlob.printf(")%sON COMMIT PRESERVE ROWS", NEWLINE);
|
||||
else if (rel_type == rel_global_temp_delete)
|
||||
isqlGlob.printf(")%sON COMMIT DELETE ROWS", NEWLINE);
|
||||
const char* gtt_scope = (rel_type == rel_global_temp_preserve) ? "ON COMMIT PRESERVE ROWS" :
|
||||
((rel_type == rel_global_temp_delete) ? "ON COMMIT DELETE ROWS" : "");
|
||||
|
||||
if (*gtt_scope || *ss)
|
||||
isqlGlob.printf(")%s%s%s", NEWLINE, gtt_scope, ss);
|
||||
else
|
||||
isqlGlob.printf(")");
|
||||
|
||||
@ -1532,6 +1540,12 @@ static void list_procedure_bodies()
|
||||
isqlGlob.printf("EXTERNAL NAME %s%s", SQL_identifier2, NEWLINE);
|
||||
}
|
||||
|
||||
if (!PRC.RDB$SQL_SECURITY.NULL)
|
||||
{
|
||||
const char* ss = PRC.RDB$SQL_SECURITY ? "SQL SECURITY DEFINER" : "SQL SECURITY INVOKER";
|
||||
isqlGlob.printf("%s%s", ss, NEWLINE);
|
||||
}
|
||||
|
||||
if (!PRC.RDB$ENGINE_NAME.NULL)
|
||||
{
|
||||
fb_utils::exact_name(PRC.RDB$ENGINE_NAME);
|
||||
@ -1658,6 +1672,12 @@ static void list_all_triggers()
|
||||
SHOW_trigger_action(TRG.RDB$TRIGGER_TYPE).c_str(), TRG.RDB$TRIGGER_SEQUENCE,
|
||||
NEWLINE);
|
||||
|
||||
if (!TRG.RDB$SQL_SECURITY.NULL)
|
||||
{
|
||||
const char* ss = TRG.RDB$SQL_SECURITY ? "SQL SECURITY DEFINER" : "SQL SECURITY INVOKER";
|
||||
isqlGlob.printf("%s%s", ss, NEWLINE);
|
||||
}
|
||||
|
||||
if (!TRG.RDB$ENTRYPOINT.NULL)
|
||||
{
|
||||
fb_utils::exact_name(TRG.RDB$ENTRYPOINT);
|
||||
@ -1737,6 +1757,12 @@ static void list_all_triggers()
|
||||
SHOW_trigger_action(TRG.RDB$TRIGGER_TYPE).c_str(), TRG.RDB$TRIGGER_SEQUENCE,
|
||||
NEWLINE);
|
||||
|
||||
if (!TRG.RDB$SQL_SECURITY.NULL)
|
||||
{
|
||||
const char* ss = TRG.RDB$SQL_SECURITY ? "SQL SECURITY DEFINER" : "SQL SECURITY INVOKER";
|
||||
isqlGlob.printf("%s%s", ss, NEWLINE);
|
||||
}
|
||||
|
||||
if (!TRG.RDB$ENTRYPOINT.NULL)
|
||||
{
|
||||
fb_utils::exact_name(TRG.RDB$ENTRYPOINT);
|
||||
@ -3089,6 +3115,12 @@ static void list_functions_ods12_bodies()
|
||||
isqlGlob.printf("EXTERNAL NAME %s%s", SQL_identifier2, NEWLINE);
|
||||
}
|
||||
|
||||
if (!FUN.RDB$SQL_SECURITY.NULL)
|
||||
{
|
||||
const char* ss = FUN.RDB$SQL_SECURITY ? "SQL SECURITY DEFINER" : "SQL SECURITY INVOKER";
|
||||
isqlGlob.printf("%s%s", ss, NEWLINE);
|
||||
}
|
||||
|
||||
if (!FUN.RDB$ENGINE_NAME.NULL)
|
||||
{
|
||||
fb_utils::exact_name(FUN.RDB$ENGINE_NAME);
|
||||
@ -3372,7 +3404,11 @@ static void list_package_headers()
|
||||
PACK.RDB$PACKAGE_NAME,
|
||||
PACK.RDB$OWNER_NAME,
|
||||
NEWLINE);
|
||||
isqlGlob.printf("CREATE PACKAGE %s AS%s", SQL_identifier, NEWLINE);
|
||||
|
||||
const char* ss = PACK.RDB$SQL_SECURITY.NULL ? "" :
|
||||
(PACK.RDB$SQL_SECURITY ? " SQL SECURITY DEFINER" : " SQL SECURITY INVOKER");
|
||||
|
||||
isqlGlob.printf("CREATE PACKAGE %s%s AS%s", SQL_identifier, ss, NEWLINE);
|
||||
|
||||
if (!PACK.RDB$PACKAGE_HEADER_SOURCE.NULL)
|
||||
SHOW_print_metadata_text_blob(isqlGlob.Out, &PACK.RDB$PACKAGE_HEADER_SOURCE);
|
||||
|
@ -4265,6 +4265,12 @@ static processing_state show_func(const SCHAR* funcname)
|
||||
isqlGlob.printf("External name: %s%s", FUN.RDB$ENTRYPOINT, NEWLINE);
|
||||
}
|
||||
|
||||
if (!FUN.RDB$SQL_SECURITY.NULL)
|
||||
{
|
||||
const char* ss = FUN.RDB$SQL_SECURITY ? "DEFINER" : "INVOKER";
|
||||
isqlGlob.printf("SQL SECURITY: %s%s", ss, NEWLINE);
|
||||
}
|
||||
|
||||
if (!FUN.RDB$ENGINE_NAME.NULL)
|
||||
{
|
||||
fb_utils::exact_name(FUN.RDB$ENGINE_NAME);
|
||||
@ -4830,6 +4836,12 @@ static processing_state show_packages(const SCHAR* package_name)
|
||||
|
||||
isqlGlob.printf(NEWLINE);
|
||||
|
||||
if (!PACK.RDB$SQL_SECURITY.NULL)
|
||||
{
|
||||
const char* ss = PACK.RDB$SQL_SECURITY ? "DEFINER" : "INVOKER";
|
||||
isqlGlob.printf("SQL SECURITY: %s%s", ss, NEWLINE);
|
||||
}
|
||||
|
||||
if (!PACK.RDB$PACKAGE_HEADER_SOURCE.NULL)
|
||||
{
|
||||
isqlGlob.printf("%s%s", "Header source:", NEWLINE);
|
||||
@ -5124,6 +5136,12 @@ static processing_state show_proc(const SCHAR* procname)
|
||||
isqlGlob.printf("External name: %s%s", PRC.RDB$ENTRYPOINT, NEWLINE);
|
||||
}
|
||||
|
||||
if (!PRC.RDB$SQL_SECURITY.NULL)
|
||||
{
|
||||
const char* ss = PRC.RDB$SQL_SECURITY ? "DEFINER" : "INVOKER";
|
||||
isqlGlob.printf("SQL SECURITY: %s%s", ss, NEWLINE);
|
||||
}
|
||||
|
||||
if (!PRC.RDB$ENGINE_NAME.NULL)
|
||||
{
|
||||
fb_utils::exact_name(PRC.RDB$ENGINE_NAME);
|
||||
@ -5682,6 +5700,12 @@ static processing_state show_table(const SCHAR* relation_name, bool isView)
|
||||
WITH REL.RDB$RELATION_NAME EQ relation_name
|
||||
if (first)
|
||||
{
|
||||
if (!REL.RDB$SQL_SECURITY.NULL)
|
||||
{
|
||||
const char* ss = REL.RDB$SQL_SECURITY ? "DEFINER" : "INVOKER";
|
||||
isqlGlob.printf("SQL SECURITY: %s%s", ss, NEWLINE);
|
||||
}
|
||||
|
||||
if (!REL.RDB$EXTERNAL_FILE.NULL)
|
||||
isqlGlob.printf("External file: %s%s", REL.RDB$EXTERNAL_FILE, NEWLINE);
|
||||
}
|
||||
@ -6117,11 +6141,15 @@ static processing_state show_trigger(const SCHAR* object, bool show_source, bool
|
||||
first = false;
|
||||
}
|
||||
|
||||
isqlGlob.printf("%s, Sequence: %d, Type: %s, %s%s",
|
||||
const char* ss = TRG.RDB$SQL_SECURITY.NULL ? "" :
|
||||
(TRG.RDB$SQL_SECURITY ? ", SQL SECURITY DEFINER" : ", SQL SECURITY INVOKER");
|
||||
|
||||
isqlGlob.printf("%s, Sequence: %d, Type: %s, %s%s%s",
|
||||
TRG.RDB$TRIGGER_NAME,
|
||||
TRG.RDB$TRIGGER_SEQUENCE,
|
||||
SHOW_trigger_action(TRG.RDB$TRIGGER_TYPE).c_str(),
|
||||
(TRG.RDB$TRIGGER_INACTIVE ? "Inactive" : "Active"),
|
||||
ss,
|
||||
NEWLINE);
|
||||
|
||||
if (show_source)
|
||||
|
@ -722,10 +722,11 @@ 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 : "";
|
||||
ContextManager<IExternalFunction> ctxManager(tdbb, attInfo, function,
|
||||
(udf->getName().package.isEmpty() ?
|
||||
CallerName(obj_udf, udf->getName().identifier) :
|
||||
CallerName(obj_package_header, udf->getName().package)));
|
||||
CallerName(obj_udf, udf->getName().identifier, userName) :
|
||||
CallerName(obj_package_header, udf->getName().package, userName)));
|
||||
|
||||
EngineCheckout cout(tdbb, FB_FUNCTION);
|
||||
|
||||
@ -775,10 +776,11 @@ 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 : "";
|
||||
ContextManager<IExternalProcedure> ctxManager(tdbb, attInfo, procedure->procedure,
|
||||
(procedure->prc->getName().package.isEmpty() ?
|
||||
CallerName(obj_procedure, procedure->prc->getName().identifier) :
|
||||
CallerName(obj_package_header, procedure->prc->getName().package)));
|
||||
CallerName(obj_procedure, procedure->prc->getName().identifier, userName) :
|
||||
CallerName(obj_package_header, procedure->prc->getName().package, userName)));
|
||||
|
||||
charSet = attachment->att_charset;
|
||||
|
||||
@ -808,10 +810,11 @@ 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 : "";
|
||||
ContextManager<IExternalProcedure> ctxManager(tdbb, attInfo, charSet,
|
||||
(procedure->prc->getName().package.isEmpty() ?
|
||||
CallerName(obj_procedure, procedure->prc->getName().identifier) :
|
||||
CallerName(obj_package_header, procedure->prc->getName().package)));
|
||||
CallerName(obj_procedure, procedure->prc->getName().identifier, userName) :
|
||||
CallerName(obj_package_header, procedure->prc->getName().package, userName)));
|
||||
|
||||
EngineCheckout cout(tdbb, FB_FUNCTION);
|
||||
|
||||
@ -883,8 +886,10 @@ void ExtEngineManager::Trigger::execute(thread_db* tdbb, unsigned action,
|
||||
record_param* oldRpb, record_param* newRpb) const
|
||||
{
|
||||
EngineAttachmentInfo* attInfo = extManager->getEngineAttachment(tdbb, engine);
|
||||
const Nullable<bool>& ssDefiner = trg->ssDefiner.specified ? trg->ssDefiner : trg->relation->rel_ss_definer;
|
||||
const MetaName& userName = ssDefiner.specified && ssDefiner.value ? trg->relation->rel_owner_name : "";
|
||||
ContextManager<IExternalTrigger> ctxManager(tdbb, attInfo, trigger,
|
||||
CallerName(obj_trigger, trg->name));
|
||||
CallerName(obj_trigger, trg->name, userName));
|
||||
|
||||
// ASF: Using Array instead of HalfStaticArray to not need to do alignment hacks here.
|
||||
Array<UCHAR> oldMsg;
|
||||
@ -1047,10 +1052,11 @@ 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 : "";
|
||||
ContextManager<IExternalFunction> ctxManager(tdbb, attInfo, attInfo->adminCharSet,
|
||||
(udf->getName().package.isEmpty() ?
|
||||
CallerName(obj_udf, udf->getName().identifier) :
|
||||
CallerName(obj_package_header, udf->getName().package)));
|
||||
CallerName(obj_udf, udf->getName().identifier, userName) :
|
||||
CallerName(obj_package_header, udf->getName().package, userName)));
|
||||
|
||||
///MemoryPool& pool = *tdbb->getDefaultPool();
|
||||
MemoryPool& pool = *getDefaultMemoryPool();
|
||||
@ -1156,10 +1162,11 @@ 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 : "";
|
||||
ContextManager<IExternalProcedure> ctxManager(tdbb, attInfo, attInfo->adminCharSet,
|
||||
(prc->getName().package.isEmpty() ?
|
||||
CallerName(obj_procedure, prc->getName().identifier) :
|
||||
CallerName(obj_package_header, prc->getName().package)));
|
||||
CallerName(obj_procedure, prc->getName().identifier, userName) :
|
||||
CallerName(obj_package_header, prc->getName().package, userName)));
|
||||
|
||||
///MemoryPool& pool = *tdbb->getDefaultPool();
|
||||
MemoryPool& pool = *getDefaultMemoryPool();
|
||||
@ -1267,8 +1274,10 @@ void ExtEngineManager::makeTrigger(thread_db* tdbb, CompilerScratch* csb, Jrd::T
|
||||
entryPointTrimmed.trim();
|
||||
|
||||
EngineAttachmentInfo* attInfo = getEngineAttachment(tdbb, engine);
|
||||
Nullable<bool>& ssDefiner = trg->ssDefiner.specified ? trg->ssDefiner : trg->relation->rel_ss_definer;
|
||||
const MetaName& userName = ssDefiner.specified && ssDefiner.value ? trg->relation->rel_owner_name : "";
|
||||
ContextManager<IExternalTrigger> ctxManager(tdbb, attInfo, attInfo->adminCharSet,
|
||||
CallerName(obj_trigger, trg->name));
|
||||
CallerName(obj_trigger, trg->name, userName));
|
||||
|
||||
///MemoryPool& pool = *tdbb->getDefaultPool();
|
||||
MemoryPool& pool = *getDefaultMemoryPool();
|
||||
|
@ -220,6 +220,8 @@ Function* Function::loadMetadata(thread_db* tdbb, USHORT id, bool noscan, USHORT
|
||||
function->setName(QualifiedName(X.RDB$FUNCTION_NAME,
|
||||
(X.RDB$PACKAGE_NAME.NULL ? NULL : X.RDB$PACKAGE_NAME)));
|
||||
|
||||
function->owner = X.RDB$OWNER_NAME;
|
||||
|
||||
if (!X.RDB$SECURITY_CLASS.NULL)
|
||||
{
|
||||
function->setSecurityName(X.RDB$SECURITY_CLASS);
|
||||
@ -237,9 +239,16 @@ Function* Function::loadMetadata(thread_db* tdbb, USHORT id, bool noscan, USHORT
|
||||
function->setSecurityName(PKG.RDB$SECURITY_CLASS);
|
||||
}
|
||||
|
||||
// SQL SECURITY of function must be the same if it's defined in package
|
||||
if (!PKG.RDB$SQL_SECURITY.NULL)
|
||||
function->ssDefiner = Nullable<bool>::val(PKG.RDB$SQL_SECURITY);
|
||||
|
||||
END_FOR
|
||||
}
|
||||
|
||||
if (!function->ssDefiner.specified && !X.RDB$SQL_SECURITY.NULL)
|
||||
function->ssDefiner = Nullable<bool>::val(X.RDB$SQL_SECURITY);
|
||||
|
||||
size_t count = 0;
|
||||
ULONG length = 0;
|
||||
|
||||
|
@ -54,6 +54,7 @@ JrdStatement::JrdStatement(thread_db* tdbb, MemoryPool* p, CompilerScratch* csb)
|
||||
accessList(*p),
|
||||
resources(*p),
|
||||
triggerName(*p),
|
||||
triggerOwner(*p),
|
||||
parentStatement(NULL),
|
||||
subStatements(*p),
|
||||
fors(*p),
|
||||
@ -416,26 +417,31 @@ void JrdStatement::verifyAccess(thread_db* tdbb)
|
||||
else
|
||||
{
|
||||
jrd_rel* relation = MET_lookup_relation_id(tdbb, item->exa_rel_id, false);
|
||||
jrd_rel* view = NULL;
|
||||
if (item->exa_view_id)
|
||||
view = MET_lookup_relation_id(tdbb, item->exa_view_id, false);
|
||||
|
||||
if (!relation)
|
||||
continue;
|
||||
|
||||
MetaName userName;
|
||||
if (item->exa_view_id)
|
||||
{
|
||||
jrd_rel* view = MET_lookup_relation_id(tdbb, item->exa_view_id, false);
|
||||
if (view && (view->rel_flags & REL_sql_relation))
|
||||
userName = view->rel_owner_name;
|
||||
}
|
||||
|
||||
switch (item->exa_action)
|
||||
{
|
||||
case ExternalAccess::exa_insert:
|
||||
verifyTriggerAccess(tdbb, relation, relation->rel_pre_store, view);
|
||||
verifyTriggerAccess(tdbb, relation, relation->rel_post_store, view);
|
||||
verifyTriggerAccess(tdbb, relation, relation->rel_pre_store, userName);
|
||||
verifyTriggerAccess(tdbb, relation, relation->rel_post_store, userName);
|
||||
break;
|
||||
case ExternalAccess::exa_update:
|
||||
verifyTriggerAccess(tdbb, relation, relation->rel_pre_modify, view);
|
||||
verifyTriggerAccess(tdbb, relation, relation->rel_post_modify, view);
|
||||
verifyTriggerAccess(tdbb, relation, relation->rel_pre_modify, userName);
|
||||
verifyTriggerAccess(tdbb, relation, relation->rel_post_modify, userName);
|
||||
break;
|
||||
case ExternalAccess::exa_delete:
|
||||
verifyTriggerAccess(tdbb, relation, relation->rel_pre_erase, view);
|
||||
verifyTriggerAccess(tdbb, relation, relation->rel_post_erase, view);
|
||||
verifyTriggerAccess(tdbb, relation, relation->rel_pre_erase, userName);
|
||||
verifyTriggerAccess(tdbb, relation, relation->rel_post_erase, userName);
|
||||
break;
|
||||
default:
|
||||
fb_assert(false);
|
||||
@ -454,17 +460,28 @@ void JrdStatement::verifyAccess(thread_db* tdbb)
|
||||
{
|
||||
const SecurityClass* sec_class = SCL_get_class(tdbb, access->acc_security_name.c_str());
|
||||
|
||||
MetaName userName;
|
||||
|
||||
if (access->acc_ss_rel_id)
|
||||
{
|
||||
const jrd_rel* view = MET_lookup_relation_id(tdbb, access->acc_ss_rel_id, false);
|
||||
if (view && (view->rel_flags & REL_sql_relation))
|
||||
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, access->acc_view_id, aclType,
|
||||
SCL_check_access(tdbb, sec_class, userName, aclType,
|
||||
routine->getName().identifier, access->acc_mask, access->acc_type,
|
||||
true, access->acc_name, access->acc_r_name);
|
||||
}
|
||||
else
|
||||
{
|
||||
SCL_check_access(tdbb, sec_class, access->acc_view_id,
|
||||
id_package, routine->getName().package,
|
||||
access->acc_mask, access->acc_type,
|
||||
SCL_check_access(tdbb, sec_class, userName, id_package,
|
||||
routine->getName().package, access->acc_mask, access->acc_type,
|
||||
true, access->acc_name, access->acc_r_name);
|
||||
}
|
||||
}
|
||||
@ -485,6 +502,8 @@ void JrdStatement::verifyAccess(thread_db* tdbb)
|
||||
MetaName objName;
|
||||
SLONG objType = 0;
|
||||
|
||||
MetaName userName;
|
||||
|
||||
if (useCallerPrivs)
|
||||
{
|
||||
switch (transaction->tra_caller_name.type)
|
||||
@ -509,9 +528,18 @@ void JrdStatement::verifyAccess(thread_db* tdbb)
|
||||
}
|
||||
|
||||
objName = transaction->tra_caller_name.name;
|
||||
userName = transaction->tra_caller_name.userName;
|
||||
}
|
||||
|
||||
SCL_check_access(tdbb, sec_class, access->acc_view_id, objType, objName,
|
||||
|
||||
if (access->acc_ss_rel_id)
|
||||
{
|
||||
const jrd_rel* view = MET_lookup_relation_id(tdbb, access->acc_ss_rel_id, false);
|
||||
if (view && (view->rel_flags & REL_sql_relation))
|
||||
userName = view->rel_owner_name;
|
||||
}
|
||||
|
||||
SCL_check_access(tdbb, sec_class, userName, objType, objName,
|
||||
access->acc_mask, access->acc_type, true, access->acc_name, access->acc_r_name);
|
||||
}
|
||||
}
|
||||
@ -588,7 +616,7 @@ void JrdStatement::release(thread_db* tdbb)
|
||||
|
||||
// Check that we have enough rights to access all resources this list of triggers touches.
|
||||
void JrdStatement::verifyTriggerAccess(thread_db* tdbb, jrd_rel* ownerRelation,
|
||||
trig_vec* triggers, jrd_rel* view)
|
||||
trig_vec* triggers, MetaName userName)
|
||||
{
|
||||
if (!triggers)
|
||||
return;
|
||||
@ -629,10 +657,18 @@ void JrdStatement::verifyTriggerAccess(thread_db* tdbb, jrd_rel* ownerRelation,
|
||||
}
|
||||
|
||||
// a direct access to an object from this trigger
|
||||
if (access->acc_ss_rel_id)
|
||||
{
|
||||
const jrd_rel* view = MET_lookup_relation_id(tdbb, access->acc_ss_rel_id, false);
|
||||
if (view && (view->rel_flags & REL_sql_relation))
|
||||
userName = view->rel_owner_name;
|
||||
}
|
||||
else if (t.ssDefiner.specified && t.ssDefiner.value)
|
||||
userName = ownerRelation->rel_owner_name;
|
||||
|
||||
const SecurityClass* sec_class = SCL_get_class(tdbb, access->acc_security_name.c_str());
|
||||
SCL_check_access(tdbb, sec_class,
|
||||
(access->acc_view_id) ? access->acc_view_id : (view ? view->rel_id : 0),
|
||||
id_trigger, t.statement->triggerName, access->acc_mask,
|
||||
SCL_check_access(tdbb, sec_class, userName, id_trigger,
|
||||
t.statement->triggerName, access->acc_mask,
|
||||
access->acc_type, true, access->acc_name, access->acc_r_name);
|
||||
}
|
||||
}
|
||||
|
@ -58,7 +58,7 @@ public:
|
||||
|
||||
private:
|
||||
static void verifyTriggerAccess(thread_db* tdbb, jrd_rel* ownerRelation, trig_vec* triggers,
|
||||
jrd_rel* view);
|
||||
Firebird::MetaName userName);
|
||||
static void triggersExternalAccess(thread_db* tdbb, ExternalAccessList& list, trig_vec* tvec);
|
||||
|
||||
void buildExternalAccess(thread_db* tdbb, ExternalAccessList& list);
|
||||
@ -76,6 +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
|
||||
JrdStatement* parentStatement; // Sub routine's parent statement
|
||||
Firebird::Array<JrdStatement*> subStatements; // Array of subroutines' statements
|
||||
const StmtNode* topNode; // top of execution tree
|
||||
|
@ -667,9 +667,9 @@ RecordSourceNode* RelationSourceNode::pass1(thread_db* tdbb, CompilerScratch* cs
|
||||
|
||||
if (relation)
|
||||
{
|
||||
int viewId = tail->csb_view ? tail->csb_view->rel_id :
|
||||
SLONG ssRelationIdId = tail->csb_view ? tail->csb_view->rel_id :
|
||||
view ? view->rel_id : csb->csb_view ? csb->csb_view->rel_id : 0;
|
||||
CMP_post_access(tdbb, csb, relation->rel_security_name, viewId,
|
||||
CMP_post_access(tdbb, csb, relation->rel_security_name, ssRelationIdId,
|
||||
SCL_select, SCL_object_table, relation->rel_name);
|
||||
}
|
||||
|
||||
|
@ -178,6 +178,7 @@ public:
|
||||
trig_vec* rel_post_store; // Post-operation store trigger
|
||||
prim rel_primary_dpnds; // foreign dependencies on this relation's primary key
|
||||
frgn rel_foreign_refs; // foreign references to other relations' primary keys
|
||||
Nullable<bool> rel_ss_definer;
|
||||
|
||||
Firebird::Mutex rel_drop_mutex;
|
||||
|
||||
@ -319,7 +320,7 @@ const ULONG REL_gc_lockneed = 0x80000; // gc lock should be acquired
|
||||
inline jrd_rel::jrd_rel(MemoryPool& p)
|
||||
: rel_pool(&p), rel_flags(REL_gc_lockneed),
|
||||
rel_name(p), rel_owner_name(p), rel_security_name(p),
|
||||
rel_view_contexts(p), rel_gc_records(p)
|
||||
rel_view_contexts(p), rel_gc_records(p), rel_ss_definer(false)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -28,6 +28,7 @@
|
||||
#include "../common/classes/QualifiedName.h"
|
||||
#include "../common/classes/NestConst.h"
|
||||
#include "../common/MsgMetadata.h"
|
||||
#include "../common/classes/Nullable.h"
|
||||
|
||||
namespace Jrd
|
||||
{
|
||||
@ -177,6 +178,9 @@ namespace Jrd
|
||||
// (it will usually be 0)
|
||||
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;
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -355,7 +355,7 @@ ULONG CMP_impure(CompilerScratch* csb, ULONG size)
|
||||
void CMP_post_access(thread_db* tdbb,
|
||||
CompilerScratch* csb,
|
||||
const Firebird::MetaName& security_name,
|
||||
SLONG view_id,
|
||||
SLONG ssRelationId, // SQL SECURITY relation in which contex permissions should be check
|
||||
SecurityClass::flags_t mask,
|
||||
SLONG type_name,
|
||||
const Firebird::MetaName& name,
|
||||
@ -383,7 +383,7 @@ void CMP_post_access(thread_db* tdbb,
|
||||
|
||||
SET_TDBB(tdbb);
|
||||
|
||||
AccessItem access(security_name, view_id, name, type_name, mask, r_name);
|
||||
AccessItem access(security_name, ssRelationId, name, type_name, mask, r_name);
|
||||
|
||||
FB_SIZE_T i;
|
||||
|
||||
|
@ -49,7 +49,7 @@ Jrd::jrd_req* CMP_make_request(Jrd::thread_db*, Jrd::CompilerScratch*, bool);
|
||||
void CMP_mark_variant(Jrd::CompilerScratch*, StreamType stream);
|
||||
Jrd::ItemInfo* CMP_pass2_validation(Jrd::thread_db*, Jrd::CompilerScratch*, const Jrd::Item&);
|
||||
|
||||
void CMP_post_access(Jrd::thread_db*, Jrd::CompilerScratch*, const Firebird::MetaName&, SLONG,
|
||||
void CMP_post_access(Jrd::thread_db*, Jrd::CompilerScratch*, const Firebird::MetaName&, SLONG ssRelationId,
|
||||
Jrd::SecurityClass::flags_t, SLONG type_name, const Firebird::MetaName&,
|
||||
const Firebird::MetaName& = "");
|
||||
|
||||
|
@ -188,7 +188,7 @@ typedef Firebird::SortedArray<Resource, Firebird::EmptyStorage<Resource>,
|
||||
struct AccessItem
|
||||
{
|
||||
Firebird::MetaName acc_security_name;
|
||||
SLONG acc_view_id;
|
||||
SLONG acc_ss_rel_id; // Relation Id which owner will be used to check permissions
|
||||
Firebird::MetaName acc_name, acc_r_name;
|
||||
SLONG acc_type;
|
||||
SecurityClass::flags_t acc_mask;
|
||||
@ -209,8 +209,8 @@ struct AccessItem
|
||||
if ((v = i1.acc_security_name.compare(i2.acc_security_name)) != 0)
|
||||
return v > 0;
|
||||
|
||||
if (i1.acc_view_id != i2.acc_view_id)
|
||||
return i1.acc_view_id > i2.acc_view_id;
|
||||
if (i1.acc_ss_rel_id != i2.acc_ss_rel_id)
|
||||
return i1.acc_ss_rel_id > i2.acc_ss_rel_id;
|
||||
|
||||
if (i1.acc_mask != i2.acc_mask)
|
||||
return i1.acc_mask > i2.acc_mask;
|
||||
@ -227,7 +227,7 @@ struct AccessItem
|
||||
AccessItem(const Firebird::MetaName& security_name, SLONG view_id,
|
||||
const Firebird::MetaName& name, SLONG type,
|
||||
SecurityClass::flags_t mask, const Firebird::MetaName& relName)
|
||||
: acc_security_name(security_name), acc_view_id(view_id), acc_name(name),
|
||||
: acc_security_name(security_name), acc_ss_rel_id(view_id), acc_name(name),
|
||||
acc_r_name(relName), acc_type(type), acc_mask(mask)
|
||||
{}
|
||||
};
|
||||
@ -514,6 +514,7 @@ public:
|
||||
// used in cmp.cpp/pass1
|
||||
jrd_rel* csb_view;
|
||||
StreamType csb_view_stream;
|
||||
jrd_rel* csb_parent_relation;
|
||||
unsigned blrVersion;
|
||||
USHORT csb_remap_variable;
|
||||
bool csb_validate_expr;
|
||||
|
@ -406,19 +406,20 @@ void InternalStatement::doPrepare(thread_db* tdbb, const string& sql)
|
||||
statement = statement->parentStatement;
|
||||
|
||||
if (statement && statement->triggerName.hasData())
|
||||
tran->getHandle()->tra_caller_name = CallerName(obj_trigger, statement->triggerName);
|
||||
tran->getHandle()->tra_caller_name = CallerName(obj_trigger, statement->triggerName, statement->triggerOwner);
|
||||
else if (statement && (routine = statement->getRoutine()) &&
|
||||
routine->getName().identifier.hasData())
|
||||
{
|
||||
const MetaName& userName = routine->ssDefiner.specified && routine->ssDefiner.value ? routine->owner : "";
|
||||
if (routine->getName().package.isEmpty())
|
||||
{
|
||||
tran->getHandle()->tra_caller_name = CallerName(routine->getObjectType(),
|
||||
routine->getName().identifier);
|
||||
routine->getName().identifier, userName);
|
||||
}
|
||||
else
|
||||
{
|
||||
tran->getHandle()->tra_caller_name = CallerName(obj_package_header,
|
||||
routine->getName().package);
|
||||
routine->getName().package, userName);
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -194,3 +194,4 @@
|
||||
FIELD(fld_plan , nam_plan , dtype_blob , BLOB_SIZE , isc_blob_text , NULL , true)
|
||||
|
||||
FIELD(fld_system_privileges, nam_system_privileges, dtype_text, 8 , dsc_text_type_fixed , dflt_no_privs, true)
|
||||
FIELD(fld_b_sql_security, nam_sql_security , dtype_boolean , 1 , 0 , NULL , true)
|
||||
|
@ -844,6 +844,9 @@ void Trigger::compile(thread_db* tdbb)
|
||||
}
|
||||
|
||||
statement->triggerName = name;
|
||||
const Nullable<bool>& ss = ssDefiner.specified ? ssDefiner : relation->rel_ss_definer;
|
||||
if (ss.specified && ss.value)
|
||||
statement->triggerOwner = relation->rel_owner_name;
|
||||
|
||||
if (sys_trigger)
|
||||
statement->flags |= JrdStatement::FLAG_SYS_TRIGGER;
|
||||
|
@ -156,6 +156,7 @@ public:
|
||||
Firebird::string entryPoint; // External trigger entrypoint
|
||||
Firebird::string extBody; // External trigger body
|
||||
ExtEngineManager::Trigger* extTrigger; // External trigger
|
||||
Nullable<bool> ssDefiner;
|
||||
|
||||
void compile(thread_db*); // Ensure that trigger is compiled
|
||||
void release(thread_db*); // Try to free trigger request
|
||||
|
@ -114,7 +114,7 @@ static int partners_ast_relation(void*);
|
||||
static int rescan_ast_relation(void*);
|
||||
static ULONG get_rel_flags_from_FLAGS(USHORT);
|
||||
static void get_trigger(thread_db*, jrd_rel*, bid*, bid*, trig_vec**, const TEXT*, FB_UINT64, bool,
|
||||
USHORT, const MetaName&, const string&, const bid*);
|
||||
USHORT, const MetaName&, const string&, const bid*, Nullable<bool> ssDefiner);
|
||||
static bool get_type(thread_db*, USHORT*, const UCHAR*, const TEXT*);
|
||||
static void lookup_view_contexts(thread_db*, jrd_rel*);
|
||||
static void make_relation_scope_name(const TEXT*, const USHORT, string& str);
|
||||
@ -123,7 +123,7 @@ static BoolExprNode* parse_field_validation_blr(thread_db* tdbb, bid* blob_id, c
|
||||
static bool resolve_charset_and_collation(thread_db*, USHORT*, const UCHAR*, const UCHAR*);
|
||||
static void save_trigger_data(thread_db*, trig_vec**, jrd_rel*, JrdStatement*, blb*, blb*,
|
||||
const TEXT*, FB_UINT64, bool, USHORT, const MetaName&, const string&,
|
||||
const bid*);
|
||||
const bid*, Nullable<bool> ssDefiner);
|
||||
static void scan_partners(thread_db*, jrd_rel*);
|
||||
static void store_dependencies(thread_db*, CompilerScratch*, const jrd_rel*,
|
||||
const MetaName&, int, jrd_tra*);
|
||||
@ -1972,6 +1972,10 @@ void MET_load_trigger(thread_db* tdbb,
|
||||
if (!TRG.RDB$ENTRYPOINT.NULL) // ODS_12_0
|
||||
entryPoint = TRG.RDB$ENTRYPOINT;
|
||||
|
||||
|
||||
const Nullable<bool> ssDefiner = TRG.RDB$SQL_SECURITY.NULL ?
|
||||
relation->rel_ss_definer : Nullable<bool>(static_cast<bool>(TRG.RDB$SQL_SECURITY));
|
||||
|
||||
if (TRG.RDB$RELATION_NAME.NULL)
|
||||
{
|
||||
if ((TRG.RDB$TRIGGER_TYPE & TRIGGER_TYPE_MASK) == TRIGGER_TYPE_DB ||
|
||||
@ -1989,7 +1993,8 @@ void MET_load_trigger(thread_db* tdbb,
|
||||
trig_flags,
|
||||
engine,
|
||||
entryPoint,
|
||||
&extBodyId);
|
||||
&extBodyId,
|
||||
ssDefiner);
|
||||
}
|
||||
}
|
||||
else
|
||||
@ -2009,7 +2014,8 @@ void MET_load_trigger(thread_db* tdbb,
|
||||
trig_flags,
|
||||
engine,
|
||||
entryPoint,
|
||||
&extBodyId);
|
||||
&extBodyId,
|
||||
ssDefiner);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -3159,7 +3165,7 @@ void MET_parse_sys_trigger(thread_db* tdbb, jrd_rel* relation)
|
||||
statement->flags |= JrdStatement::FLAG_IGNORE_PERM;
|
||||
|
||||
save_trigger_data(tdbb, ptr, relation, statement, NULL, NULL, NULL, type, true, 0, "",
|
||||
"", NULL);
|
||||
"", NULL, Nullable<bool>());
|
||||
}
|
||||
}
|
||||
END_FOR
|
||||
@ -3327,10 +3333,15 @@ jrd_prc* MET_procedure(thread_db* tdbb, USHORT id, bool noscan, USHORT flags)
|
||||
{
|
||||
if (!PKG.RDB$SECURITY_CLASS.NULL)
|
||||
procedure->setSecurityName(PKG.RDB$SECURITY_CLASS);
|
||||
if (!PKG.RDB$SQL_SECURITY.NULL)
|
||||
procedure->ssDefiner = Nullable<bool>::val(PKG.RDB$SQL_SECURITY);
|
||||
}
|
||||
END_FOR
|
||||
}
|
||||
|
||||
if (!procedure->ssDefiner.specified && !P.RDB$SQL_SECURITY.NULL)
|
||||
procedure->ssDefiner = Nullable<bool>::val(P.RDB$SQL_SECURITY);
|
||||
procedure->owner = P.RDB$OWNER_NAME;
|
||||
procedure->setImplemented(true);
|
||||
procedure->getInputFields().resize(P.RDB$PROCEDURE_INPUTS);
|
||||
procedure->getOutputFields().resize(P.RDB$PROCEDURE_OUTPUTS);
|
||||
@ -3782,6 +3793,7 @@ void MET_scan_relation(thread_db* tdbb, jrd_rel* relation)
|
||||
|
||||
relation->rel_name = REL.RDB$RELATION_NAME;
|
||||
relation->rel_owner_name = REL.RDB$OWNER_NAME;
|
||||
relation->rel_ss_definer = REL.RDB$SQL_SECURITY;
|
||||
|
||||
if (!REL.RDB$VIEW_BLR.isEmpty())
|
||||
{
|
||||
@ -4431,7 +4443,7 @@ static void get_trigger(thread_db* tdbb, jrd_rel* relation,
|
||||
const TEXT* name, FB_UINT64 type,
|
||||
bool sys_trigger, USHORT flags,
|
||||
const MetaName& engine, const string& entryPoint,
|
||||
const bid* body)
|
||||
const bid* body, Nullable<bool> ssDefiner)
|
||||
{
|
||||
/**************************************
|
||||
*
|
||||
@ -4459,7 +4471,7 @@ static void get_trigger(thread_db* tdbb, jrd_rel* relation,
|
||||
debugInfoBlob = blb::open(tdbb, attachment->getSysTransaction(), debug_blob_id);
|
||||
|
||||
save_trigger_data(tdbb, ptr, relation, NULL, blrBlob, debugInfoBlob,
|
||||
name, type, sys_trigger, flags, engine, entryPoint, body);
|
||||
name, type, sys_trigger, flags, engine, entryPoint, body, ssDefiner);
|
||||
}
|
||||
|
||||
|
||||
@ -4822,7 +4834,7 @@ static void save_trigger_data(thread_db* tdbb, trig_vec** ptr, jrd_rel* relation
|
||||
const TEXT* name, FB_UINT64 type,
|
||||
bool sys_trigger, USHORT flags,
|
||||
const MetaName& engine, const string& entryPoint,
|
||||
const bid* body)
|
||||
const bid* body, Nullable<bool> ssDefiner)
|
||||
{
|
||||
/**************************************
|
||||
*
|
||||
@ -4882,6 +4894,7 @@ static void save_trigger_data(thread_db* tdbb, trig_vec** ptr, jrd_rel* relation
|
||||
t.relation = relation;
|
||||
t.engine = engine;
|
||||
t.entryPoint = entryPoint;
|
||||
t.ssDefiner = ssDefiner;
|
||||
}
|
||||
|
||||
|
||||
|
@ -407,3 +407,4 @@ NAME("SEC$USER", nam_sec_user)
|
||||
NAME("SEC$USER_TYPE", nam_sec_user_type)
|
||||
|
||||
NAME("RDB$SYSTEM_PRIVILEGES", nam_system_privileges)
|
||||
NAME("RDB$SQL_SECURITY", nam_sql_security)
|
||||
|
@ -144,6 +144,7 @@ RELATION(nam_relations, rel_relations, ODS_8_0, rel_persistent)
|
||||
FIELD(f_rel_def_class, nam_def_class, fld_class, 1, ODS_8_0)
|
||||
FIELD(f_rel_flags, nam_flags, fld_flag_nullable, 0, ODS_8_0)
|
||||
FIELD(f_rel_type, nam_r_type, fld_r_type, 0, ODS_11_1)
|
||||
FIELD(f_rel_sql_security, nam_sql_security, fld_b_sql_security, 1, ODS_13_0)
|
||||
END_RELATION
|
||||
|
||||
// Relation 7 (RDB$VIEW_RELATIONS)
|
||||
@ -205,6 +206,7 @@ RELATION(nam_trgs, rel_triggers, ODS_8_0, rel_persistent)
|
||||
FIELD(f_trg_debug_info, nam_debug_info, fld_debug_info, 1, ODS_11_1)
|
||||
FIELD(f_trg_engine_name, nam_engine_name, fld_engine_name, 1, ODS_12_0)
|
||||
FIELD(f_trg_entry, nam_entry, fld_ext_name, 1, ODS_12_0)
|
||||
FIELD(f_trg_sql_security, nam_sql_security, fld_b_sql_security, 1, ODS_13_0)
|
||||
END_RELATION
|
||||
|
||||
// Relation 13 (RDB$DEPENDENCIES)
|
||||
@ -239,6 +241,7 @@ RELATION(nam_funs, rel_funs, ODS_8_0, rel_persistent)
|
||||
FIELD(f_fun_owner, nam_owner, fld_user, 1, ODS_12_0)
|
||||
FIELD(f_fun_legacy_flag, nam_legacy_flag, fld_flag_nullable, 0, ODS_12_0)
|
||||
FIELD(f_fun_deterministic_flag, nam_deterministic_flag, fld_flag_nullable, 0, ODS_12_0)
|
||||
FIELD(f_fun_sql_security, nam_sql_security, fld_b_sql_security, 1, ODS_13_0)
|
||||
END_RELATION
|
||||
|
||||
// Relation 15 (RDB$FUNCTION_ARGUMENTS)
|
||||
@ -382,6 +385,7 @@ RELATION(nam_procedures, rel_procedures, ODS_8_0, rel_persistent)
|
||||
FIELD(f_prc_entry, nam_entry, fld_ext_name, 1, ODS_12_0)
|
||||
FIELD(f_prc_pkg_name, nam_pkg_name, fld_pkg_name, 1, ODS_12_0)
|
||||
FIELD(f_prc_private_flag, nam_private_flag, fld_flag_nullable, 1, ODS_12_0)
|
||||
FIELD(f_prc_sql_security, nam_sql_security, fld_b_sql_security, 1, ODS_13_0)
|
||||
END_RELATION
|
||||
|
||||
// Relation 27 (RDB$PROCEDURE_PARAMETERS)
|
||||
@ -615,6 +619,7 @@ RELATION(nam_packages, rel_packages, ODS_12_0, rel_persistent)
|
||||
FIELD(f_pkg_owner, nam_owner, fld_user, 1, ODS_12_0)
|
||||
FIELD(f_pkg_sys_flag, nam_sys_flag, fld_flag, 1, ODS_12_0)
|
||||
FIELD(f_pkg_desc, nam_description, fld_description, 1, ODS_12_0)
|
||||
FIELD(f_pkg_sql_security, nam_sql_security, fld_b_sql_security, 1, ODS_13_0)
|
||||
END_RELATION
|
||||
|
||||
// Relation 43 (SEC$USERS)
|
||||
|
@ -72,8 +72,8 @@ static bool check_number(const UCHAR*, USHORT);
|
||||
static bool check_user_group(thread_db* tdbb, const UCHAR*, USHORT);
|
||||
static bool check_string(const UCHAR*, const Firebird::MetaName&);
|
||||
static SecurityClass::flags_t compute_access(thread_db* tdbb, const SecurityClass*,
|
||||
const jrd_rel*, SLONG, const Firebird::MetaName&);
|
||||
static SecurityClass::flags_t walk_acl(thread_db* tdbb, const Acl&, const jrd_rel*,
|
||||
const MetaName &userName, SLONG, const Firebird::MetaName&);
|
||||
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);
|
||||
@ -198,7 +198,7 @@ static void raiseError(SecurityClass::flags_t mask, SLONG type, const Firebird::
|
||||
|
||||
void SCL_check_access(thread_db* tdbb,
|
||||
const SecurityClass* s_class,
|
||||
SLONG view_id,
|
||||
MetaName userName,
|
||||
SLONG obj_type,
|
||||
const Firebird::MetaName& obj_name,
|
||||
SecurityClass::flags_t mask,
|
||||
@ -215,6 +215,7 @@ void SCL_check_access(thread_db* tdbb,
|
||||
*
|
||||
* Functional description
|
||||
* Check security class for desired permission.
|
||||
* userName a name of user in which context permissions will be checked.
|
||||
*
|
||||
**************************************/
|
||||
SET_TDBB(tdbb);
|
||||
@ -230,20 +231,14 @@ void SCL_check_access(thread_db* tdbb,
|
||||
}
|
||||
|
||||
// Check global DDL permissions with ANY option which allow user to make changes non owned objects
|
||||
const SecurityClass::flags_t obj_mask = SCL_get_object_mask(type);
|
||||
if (mask & obj_mask)
|
||||
if ( (type > obj_last_non_ddl) && (mask & SCL_get_object_mask(type)))
|
||||
return;
|
||||
|
||||
if (!s_class || (mask & s_class->scl_flags))
|
||||
if (!s_class || (userName.isEmpty() && (mask & s_class->scl_flags)))
|
||||
return;
|
||||
|
||||
const jrd_rel* view = NULL;
|
||||
|
||||
if (view_id)
|
||||
view = MET_lookup_relation_id(tdbb, view_id, false);
|
||||
|
||||
if ((view || obj_name.hasData()) &&
|
||||
(compute_access(tdbb, s_class, view, obj_type, obj_name) & mask))
|
||||
if ((userName.hasData() || obj_name.hasData()) &&
|
||||
(compute_access(tdbb, s_class, userName, obj_type, obj_name) & mask))
|
||||
{
|
||||
return;
|
||||
}
|
||||
@ -1421,7 +1416,7 @@ static void get_string(const UCHAR* acl, Firebird::MetaName& string)
|
||||
|
||||
static SecurityClass::flags_t compute_access(thread_db* tdbb,
|
||||
const SecurityClass* s_class,
|
||||
const jrd_rel* view,
|
||||
const MetaName& userName,
|
||||
SLONG obj_type,
|
||||
const Firebird::MetaName& obj_name)
|
||||
{
|
||||
@ -1487,7 +1482,7 @@ static SecurityClass::flags_t compute_access(thread_db* tdbb,
|
||||
acl.shrink(end - buffer);
|
||||
|
||||
if (acl.getCount() > 0)
|
||||
privileges |= walk_acl(tdbb, acl, view, obj_type, obj_name);
|
||||
privileges |= walk_acl(tdbb, acl, userName, obj_type, obj_name);
|
||||
}
|
||||
END_FOR
|
||||
|
||||
@ -1497,7 +1492,7 @@ static SecurityClass::flags_t compute_access(thread_db* tdbb,
|
||||
|
||||
static SecurityClass::flags_t walk_acl(thread_db* tdbb,
|
||||
const Acl& acl,
|
||||
const jrd_rel* view,
|
||||
const MetaName& userName,
|
||||
SLONG obj_type,
|
||||
const Firebird::MetaName& obj_name)
|
||||
{
|
||||
@ -1510,6 +1505,7 @@ static SecurityClass::flags_t walk_acl(thread_db* tdbb,
|
||||
* Functional description
|
||||
* Walk an access control list looking for a hit. If a hit
|
||||
* is found, return privileges.
|
||||
* userName a name of user which privileges must be computed. NULL is current user (INVOKER)
|
||||
*
|
||||
**************************************/
|
||||
SET_TDBB(tdbb);
|
||||
@ -1517,18 +1513,12 @@ static SecurityClass::flags_t walk_acl(thread_db* tdbb,
|
||||
|
||||
// Munch ACL. If we find a hit, eat up privileges.
|
||||
|
||||
UserId user = *attachment->att_user;
|
||||
UserId user;
|
||||
|
||||
if (view && (view->rel_flags & REL_sql_relation))
|
||||
{
|
||||
// Use the owner of the view to perform the sql security
|
||||
// checks with: (1) The view user must have sufficient privileges
|
||||
// to the view, and (2a) the view owner must have sufficient
|
||||
// privileges to the base table or (2b) the view must have
|
||||
// sufficient privileges on the base table.
|
||||
|
||||
user.setUserName(view->rel_owner_name.c_str());
|
||||
}
|
||||
if (userName.hasData())
|
||||
user.setUserName(userName);
|
||||
else
|
||||
user = *attachment->att_user;
|
||||
|
||||
SecurityClass::flags_t privilege = 0;
|
||||
const UCHAR* a = acl.begin();
|
||||
@ -1582,10 +1572,6 @@ static SecurityClass::flags_t walk_acl(thread_db* tdbb,
|
||||
}
|
||||
|
||||
case id_view:
|
||||
if (!view || check_string(a, view->rel_name))
|
||||
hit = false;
|
||||
break;
|
||||
|
||||
case id_package:
|
||||
case id_procedure:
|
||||
case id_trigger:
|
||||
@ -1601,8 +1587,8 @@ static SecurityClass::flags_t walk_acl(thread_db* tdbb,
|
||||
// generated for SQL.
|
||||
|
||||
hit = false;
|
||||
if (!view)
|
||||
hit = false;
|
||||
// if (!view)
|
||||
// hit = false;
|
||||
break;
|
||||
|
||||
case id_user:
|
||||
|
@ -33,7 +33,7 @@
|
||||
|
||||
struct dsc;
|
||||
|
||||
void SCL_check_access(Jrd::thread_db*, const Jrd::SecurityClass*, SLONG, SLONG, const Firebird::MetaName&,
|
||||
void SCL_check_access(Jrd::thread_db*, const Jrd::SecurityClass*, Firebird::MetaName userName, SLONG, const Firebird::MetaName&,
|
||||
Jrd::SecurityClass::flags_t, SLONG type, bool recursive, const Firebird::MetaName&,
|
||||
const Firebird::MetaName& = "");
|
||||
void SCL_check_create_access(Jrd::thread_db*, int type);
|
||||
|
@ -108,9 +108,10 @@ typedef Firebird::BePlusTree<BlobIndex, ULONG, MemoryPool, BlobIndex> BlobIndexT
|
||||
|
||||
struct CallerName
|
||||
{
|
||||
CallerName(int aType, const Firebird::MetaName& aName)
|
||||
CallerName(int aType, const Firebird::MetaName& aName, const Firebird::MetaName& aUserName)
|
||||
: type(aType),
|
||||
name(aName)
|
||||
name(aName),
|
||||
userName(aUserName)
|
||||
{
|
||||
}
|
||||
|
||||
@ -121,7 +122,8 @@ struct CallerName
|
||||
|
||||
CallerName(const CallerName& o)
|
||||
: type(o.type),
|
||||
name(o.name)
|
||||
name(o.name),
|
||||
userName(o.userName)
|
||||
{
|
||||
}
|
||||
|
||||
@ -131,11 +133,13 @@ struct CallerName
|
||||
{
|
||||
type = o.type;
|
||||
name = o.name;
|
||||
userName = o.userName;
|
||||
}
|
||||
}
|
||||
|
||||
int type;
|
||||
Firebird::MetaName name;
|
||||
Firebird::MetaName userName;
|
||||
};
|
||||
|
||||
const int DEFAULT_LOCK_TIMEOUT = -1; // infinite
|
||||
|
@ -1699,6 +1699,7 @@ COMMIT WORK;
|
||||
('dsql_no_output_sqlda', NULL, NULL, NULL, 7, 38, NULL, 'No SQLDA for output values provided', NULL, NULL);
|
||||
('dsql_wrong_param_num', NULL, NULL, NULL, 7, 39, NULL, 'Wrong number of parameters (expected @1, got @2)', NULL, NULL);
|
||||
-- Do not change the arguments of the previous DSQL messages.
|
||||
('dsql_invalid_drop_ss_clause', 'CreateAlterTriggerNode::dsqlPass', 'DdlNodes.epp', NULL, 7, 40, NULL, 'Invalid DROP SQL SECURITY clause', NULL, NULL);
|
||||
-- Write the new DSQL messages here.
|
||||
-- DYN
|
||||
(NULL, NULL, 'dyn.c', NULL, 8, 1, NULL, 'ODS version not supported by DYN', NULL, NULL);
|
||||
|
@ -879,6 +879,7 @@ set bulk_insert INSERT INTO SYSTEM_ERRORS (SQL_CODE, SQL_CLASS, SQL_SUBCLASS, FA
|
||||
(-802, '07', '002', 7, 37, 'dsql_no_input_sqlda', NULL, NULL)
|
||||
(-802, '07', '002', 7, 38, 'dsql_no_output_sqlda', NULL, NULL)
|
||||
(-313, '07', '001', 7, 39, 'dsql_wrong_param_num', NULL, NULL)
|
||||
(-817, '42', '000', 7, 40, 'dsql_invalid_drop_ss_clause', NULL, NULL)
|
||||
-- DYN
|
||||
(-901, '42', '000', 8, 37, 'dyn_filter_not_found', NULL, NULL)
|
||||
(-901, '42', '000', 8, 41, 'dyn_func_not_found', NULL, NULL)
|
||||
|
@ -162,6 +162,7 @@ static const TOK tokens[] =
|
||||
{TOK_DECODE, "DECODE", false},
|
||||
{TOK_DECRYPT, "DECRYPT", true},
|
||||
{TOK_DEFAULT, "DEFAULT", false},
|
||||
{TOK_DEFINER, "DEFINER", true},
|
||||
{TOK_DELETE, "DELETE", false},
|
||||
{TOK_DELETING, "DELETING", true},
|
||||
{TOK_DENSE_RANK, "DENSE_RANK", false},
|
||||
@ -235,6 +236,7 @@ static const TOK tokens[] =
|
||||
{TOK_INT, "INT", false},
|
||||
{TOK_INTEGER, "INTEGER", false},
|
||||
{TOK_INTO, "INTO", false},
|
||||
{TOK_INVOKER, "INVOKER", true},
|
||||
{TOK_IS, "IS", false},
|
||||
{TOK_ISOLATION, "ISOLATION", false},
|
||||
{TOK_JOIN, "JOIN", false},
|
||||
@ -383,6 +385,8 @@ static const TOK tokens[] =
|
||||
{TOK_DATABASE, "SCHEMA", false}, // Alias of DATABASE
|
||||
{TOK_SCROLL, "SCROLL", false},
|
||||
{TOK_SECOND, "SECOND", false},
|
||||
{TOK_SQL, "SQL", true},
|
||||
{TOK_SECURITY, "SECURITY", true},
|
||||
{TOK_SEGMENT, "SEGMENT", false},
|
||||
{TOK_SELECT, "SELECT", false},
|
||||
{TOK_SENSITIVE, "SENSITIVE", false},
|
||||
|
Loading…
Reference in New Issue
Block a user