Open firebird-automations opened 8 years ago
Commented by: @romansimakov
When procedure is compiled fields use default security class, but after granting field level privileges their security classes are changed which cause to check relation security class instead of field security class. I suggest to make field security class permanent and generate them when field is defining like in patch:
Author: Roman Simakov <mailto:roman.simakov@gmail.com> Date: Fri Feb 5 16:43:56 2016 +0300
Fixed [CORE5108](https://github.com/FirebirdSQL/firebird/issues?q=CORE5108+in%3Atitle)\.
diff --git a/src/jrd/drq.h b/src/jrd/drq.h index f034ee9..f067998 100644 --- a/src/jrd/drq.h +++ b/src/jrd/drq.h @@ -219,6 +219,7 @@ const int drq_l_xcp_name = 165; // lookup exception name const int drq_l_gen_name = 166; // lookup generator name const int drq_e_grant3 = 167; // revoke all on all const int drq_s2_difference = 168; // Store backup difference file, DYN_mod's change_backup_mode -const int drq_MAX = 169; +const int drq_g_nxt_fsc_id = 169; // generate next field security class id +const int drq_MAX = 170;
diff --git a/src/jrd/dyn_def.epp b/src/jrd/dyn_def.epp index 39bfc12..3bbca45 100644 --- a/src/jrd/dyn_def.epp +++ b/src/jrd/dyn_def.epp @@ -2761,6 +2761,14 @@ void DYN_define_local_field(Global* gbl, DYN_execute(gbl, ptr, relation_name, &tmp, NULL, NULL, NULL); }
+ // If security class is not defined explicitly we generate it automatically + if (RFR.RDB$SECURITY_CLASS.NULL) + { + RFR.RDB$SECURITY_CLASS.NULL = FALSE; + sprintf(RFR.RDB$SECURITY_CLASS, "%s%" SQUADFORMAT, SQL_FLD_SECCLASS_PREFIX, + DYN_UTIL_gen_unique_id(tdbb, gbl, drq_g_nxt_fsc_id, "RDB$SECURITY_CLASS")); + } + if (has_default && DYN_UTIL_is_array(tdbb, gbl, RFR.RDB$FIELD_SOURCE)) { DYN_error_punt(false, 226, RFR.RDB$FIELD_SOURCE); @@ -4050,6 +4058,10 @@ void DYN_define_sql_field(Global* gbl, RFR.RDB$DEFAULT_VALUE.NULL = TRUE; RFR.RDB$COLLATION_ID.NULL = TRUE;
+ RFR.RDB$SECURITY_CLASS.NULL = FALSE; + sprintf(RFR.RDB$SECURITY_CLASS, "%s%" SQUADFORMAT, SQL_FLD_SECCLASS_PREFIX, + DYN_UTIL_gen_unique_id(tdbb, gbl, drq_g_nxt_fsc_id, "RDB$SECURITY_CLASS")); + old_request = request; const SSHORT old_id = id; request = CMP_find_request(tdbb, drq_s_sql_gfld, DYN_REQUESTS);
Commented by: @romansimakov
https://github.com/FirebirdSQL/firebird/pull/81
I implemented another way to fix. If field level permissions were changed we reset metadata cache. I did not implement selection of procedures to reset which depend on changed field since it overhead which may not be good and cost about the same as restore metadata cache.
Submitted by: @romansimakov
To reproduce it on SuperServer execute: ------------------------------------------------------- roman:bin$ ./isql Use CONNECT or CREATE DATABASE to specify a database SQL> connect 'localhost:/tmp/429.fdb'; Database: 'localhost:/tmp/429.fdb' SQL> create table t(i integer); SQL> insert into t values (1); SQL> commit; SQL> ^Droman:bin$ roman:bin$ ./gsec GSEC> add test -pw test GSEC> roman:bin$ roman:bin$ ./isql -user test -password test Use CONNECT or CREATE DATABASE to specify a database SQL> connect 'localhost:/tmp/429.fdb'; Database: 'localhost:/tmp/429.fdb', User: test SQL> set term ^; SQL> edit^ SQL> set term ;^ SQL> commit; SQL> show procedures; Procedure Name Invalid Dependency, Type ================================= ======= ===================================== P T, Table SQL> execute procedure p; Statement failed, SQLSTATE = 28000 no permission for update/write access to TABLE T SQL> ^Droman:bin$ roman:bin$ ./isql Use CONNECT or CREATE DATABASE to specify a database SQL> connect 'localhost:/tmp/429.fdb'; Database: 'localhost:/tmp/429.fdb' SQL> grant update(i) on t to test; SQL> commit; SQL> ^Droman:bin$ roman:bin$ ./isql -user test -password test Use CONNECT or CREATE DATABASE to specify a database SQL> connect 'localhost:/tmp/429.fdb'; Database: 'localhost:/tmp/429.fdb', User: test SQL> execute procedure p; Statement failed, SQLSTATE = 28000 no permission for update/write access to COLUMN T.I SQL> update t set i = 3; SQL> ^Droman:bin$ roman:bin$ ./isql Use CONNECT or CREATE DATABASE to specify a database SQL> connect 'localhost:/tmp/429.fdb'; Database: 'localhost:/tmp/429.fdb' SQL> select * from t;
============ 3 ------------------------------------------------------- Procedure which is used in test case declared as: create procedure p as begin update t set i = 2; end