Privilege fixes for TRAFODION-12, TRAFODION-1761, and TRAFODION-1773 TRAFODION-12 Grant Revoke Enhancements
-- Revoke: added code to verify that when column privileges are revoked then the remaining grants are is still intact. It does this by starting at the beginning of the privilege tree and rebuilding it from top to bottom with the requested privilege changes. If the revoke causes part of the tree to be unaccessible (a broken branch), the revoke operation fails. TRAFODION-1761 Grant and Revoke on table with referencing views does not work -- When granting INSERT, UPDATE, or DELETE object privilege(s) on a table that is referenced by one or more views, then the privilege should be granted on any updatable views that reference the table. The grant request to the these views should be executed as though the current user is _SYSTEM. Similarily for revokes. -- If the grant is performed that adds the WITH GRANT OPTION, then the WITH GRANT OPTION is to be added to the referencing views. The grant request should be executed as though the current user is _SYSTEM. Similarily for revokes. -- The problem was caused by the incorrect grantor being processed. So, added a new field to the ObjectUsage structure that tells grant/revoke that the grantor should be the system user. Also added change to not propagate update privileges on non updatable views. -- The checkin fixes object privileges; however, work is still needed to support column level privileges and a mix between column and object level. TRAFODION-1773 Internal error to revoke role with restrict option when there is dependent view -- There code (PrivMgrRoles) that determines if a specific user that owns objects whose existence depend upon a privilege granted to the specified role can be revoked. This code did not consider views as a referenced object type Cleaned up PrivMgrDesc.h & PrivMgrDesc.cpp: -- remove unused grantee field -- added columnOrdinal which will be used to fix column privs for TRAFODION 1761 -- replaced std::bitset<NBR_OF_PRIVS> with the define PrivMgrBitmap Project: http://git-wip-us.apache.org/repos/asf/incubator-trafodion/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-trafodion/commit/8652aeb8 Tree: http://git-wip-us.apache.org/repos/asf/incubator-trafodion/tree/8652aeb8 Diff: http://git-wip-us.apache.org/repos/asf/incubator-trafodion/diff/8652aeb8 Branch: refs/heads/master Commit: 8652aeb8294f525ca004ae872bd96d3c4158905b Parents: 3569255 Author: Roberta Marton <[email protected]> Authored: Sat Jan 23 00:12:12 2016 +0000 Committer: Roberta Marton <[email protected]> Committed: Sat Jan 23 00:12:12 2016 +0000 ---------------------------------------------------------------------- core/sql/regress/privs1/EXPECTED141 | Bin 78469 -> 92809 bytes core/sql/regress/privs1/TEST141 | 65 +++ core/sql/regress/privs2/EXPECTED135 | 84 ++- core/sql/regress/privs2/EXPECTED140 | 10 +- core/sql/regress/privs2/TEST135 | 54 +- core/sql/regress/tools/runregr_privs1.ksh | 3 - core/sql/regress/tools/runregr_privs2.ksh | 5 - core/sql/sqlcomp/PrivMgrDesc.h | 51 +- core/sql/sqlcomp/PrivMgrMD.cpp | 30 +- core/sql/sqlcomp/PrivMgrMD.h | 9 +- core/sql/sqlcomp/PrivMgrObjects.cpp | 52 ++ core/sql/sqlcomp/PrivMgrObjects.h | 4 + core/sql/sqlcomp/PrivMgrPrivileges.cpp | 685 +++++++++++++++++++------ core/sql/sqlcomp/PrivMgrPrivileges.h | 39 +- core/sql/sqlcomp/PrivMgrRoles.cpp | 1 + 15 files changed, 869 insertions(+), 223 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-trafodion/blob/8652aeb8/core/sql/regress/privs1/EXPECTED141 ---------------------------------------------------------------------- diff --git a/core/sql/regress/privs1/EXPECTED141 b/core/sql/regress/privs1/EXPECTED141 index 6c0717e..528f189 100644 Binary files a/core/sql/regress/privs1/EXPECTED141 and b/core/sql/regress/privs1/EXPECTED141 differ http://git-wip-us.apache.org/repos/asf/incubator-trafodion/blob/8652aeb8/core/sql/regress/privs1/TEST141 ---------------------------------------------------------------------- diff --git a/core/sql/regress/privs1/TEST141 b/core/sql/regress/privs1/TEST141 index 5c8c6da..8011c21 100755 --- a/core/sql/regress/privs1/TEST141 +++ b/core/sql/regress/privs1/TEST141 @@ -38,6 +38,7 @@ obey TEST141(test_private_user); obey TEST141(test_private_role); obey TEST141(test_shared_user); obey TEST141(test_shared_role); +obey TEST141(test_view_priv_propagation); log; obey TEST141(clean_up); exit; @@ -315,6 +316,57 @@ sh sqlci -i "TEST141(user2_objects)" -u sql_user2; execute get_obj_privs; -- ============================================================================ +?section test_view_priv_propagation +-- ============================================================================ +values (user); + +-- remove schemas +drop schema if exists t141_user1 cascade; +drop schema if exists t141_user2 cascade; +drop schema if exists t141_user3 cascade; + +-- setup database with private schemas owned by users +create schema t141_user1 authorization sql_user1; +create schema t141_user2 authorization sql_user2; + +-- create some tables owned by user1 +set schema t141_user1; +create table u1t1 (c1 int not null primary key, c2 int, c3 int); +insert into u1t1 values (1,1,1), (2,2,2), (3,3,3), (4,4,4), (5,5,5); +create table u1t2 (c1 int not null primary key, c2 int, c3 int); +insert into u1t2 values (1,1,1), (2,2,2), (3,3,3), (4,4,4), (5,5,5); + +-- grant privileges to sql_user2 on tables +grant select, delete on u1t1 to sql_user2; +grant select, delete on u1t2 to sql_user2 with grant option; + +execute get_obj_privs; + +-- user2 creates some views +sh sqlci -i "TEST141(user2_views)" -u sql_user2; + +execute get_obj_privs; + +-- user1 grants insert privilege on tables +grant insert on u1t1 to sql_user2; +grant insert on u1t2 to sql_user2 with grant option; + +execute get_obj_privs; + +-- remove with grant option for some privileges +revoke grant option for insert, delete on u1t2 from sql_user2; +execute get_obj_privs; + +-- Add back the with grant option for delete +grant delete on u1t2 to sql_user2 with grant option; +execute get_obj_privs; + +-- Remove insert, and delete entirely +revoke insert, delete on u1t1 from sql_user2; +revoke insert, delete on u1t2 from sql_user2; +execute get_obj_privs; + +-- ============================================================================ ?section user1_objects -- ============================================================================ -- executed by sql_user1 @@ -392,3 +444,16 @@ create view u3v4 as select c1, c3 from t141_user1.u1t4; create view u3v5 as select c1, c3 from t141_user1.u1t3; get tables; get views; + +-- ============================================================================ +?section user2_views +-- ============================================================================ +-- executed by sql_user2 +log LOG141; +cqd SHOWDDL_DISPLAY_PRIVILEGE_GRANTS 'ON'; +values (user); +set schema t141_user2; + +create view u2v1 as select * from t141_user1.u1t1; +create view u2v2 as select * from t141_user1.u1t2; + http://git-wip-us.apache.org/repos/asf/incubator-trafodion/blob/8652aeb8/core/sql/regress/privs2/EXPECTED135 ---------------------------------------------------------------------- diff --git a/core/sql/regress/privs2/EXPECTED135 b/core/sql/regress/privs2/EXPECTED135 index 13405a2..0d8b0f6 100644 --- a/core/sql/regress/privs2/EXPECTED135 +++ b/core/sql/regress/privs2/EXPECTED135 @@ -34,7 +34,7 @@ SCHEMA_PRIVILEGES +>from "_PRIVMGR_MD_".object_privileges +>where +> object_name in ('TRAFODION.T135SCH.T135_T1', 'TRAFODION.T135SCH.T135_T2', 'TRAFODION.T135SCH.T135_V1', 'TRAFODION.T135SCH.T135_V2', 'TRAFODION.T135SCH.T135_L1', 'TRAFODION.T135SCH.T135_L2', 'TRAFODION.T135SCH.T135_SESSIONIZE', 'TRAFODION.T135SCH.T135_ADD2') -+>for read uncommitted access; ++>order by 1,3,2 for read uncommitted access; --- SQL command prepared. >> @@ -161,8 +161,8 @@ OBJECT_NAME ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ----------------------------------------------------------------------------------------------------------------------------------------- ----------------------------------------------------------------------------------------------------------------------- TRAFODION.T135SCH.T135_T1 DB__ROOT _SYSTEM -TRAFODION.T135SCH.T135_V1 DB__ROOT _SYSTEM TRAFODION.T135SCH.T135_T2 DB__ROOT _SYSTEM +TRAFODION.T135SCH.T135_V1 DB__ROOT _SYSTEM --- 3 row(s) selected. >> @@ -569,6 +569,71 @@ End of MXCI Session End of MXCI Session >> +>>-- create some roles +>>create role t135_role1; + +--- SQL operation complete. +>>create role t135_role2; + +--- SQL operation complete. +>>grant role t135_role1, t135_role2 to sql_user4; + +--- SQL operation complete. +>>grant select on t135_t1 to t135_role1; + +--- SQL operation complete. +>>grant select on t135_v1_t1 to t135_role2; + +--- SQL operation complete. +>> +>>-- have sql_user4 create a view based on role privs +>>create schema if not exists t135sch_user4 authorization sql_user4; + +--- SQL operation complete. +>>sh sqlci -i "TEST135(user4_views)" -u sql_user4; +>>create view t135_v1_user4 as ++> select t135sch.t135_t1.c2, t135sch.t135_v1_t1.c1 ++> from t135sch.t135_t1, t135sch.t135_v1_t1; + +--- SQL operation complete. +>>showddl t135_v1_user4; + +CREATE VIEW TRAFODION.T135SCH_USER4.T135_V1_USER4 AS + SELECT TRAFODION.T135SCH.T135_T1.C2, TRAFODION.T135SCH.T135_V1_T1.C1 FROM + TRAFODION.T135SCH.T135_T1, TRAFODION.T135SCH.T135_V1_T1 ; + +-- GRANT SELECT ON TRAFODION.T135SCH_USER4.T135_V1_USER4 TO SQL_USER4; + +--- SQL operation complete. +>> +>>exit; + +End of MXCI Session + +>> +>>-- should not be able to revoke user4 from role +>>revoke role t135_role1 from sql_user4; + +*** ERROR[1364] Cannot revoke role T135_ROLE1. Object TRAFODION.T135SCH_USER4.T135_V1_USER4 depends on privileges on object TRAFODION.T135SCH.T135_T1. + +--- SQL operation failed with errors. +>>revoke role t135_role2 from sql_user4; + +*** ERROR[1364] Cannot revoke role T135_ROLE2. Object TRAFODION.T135SCH_USER4.T135_V1_USER4 depends on privileges on object TRAFODION.T135SCH.T135_V1_T1. + +--- SQL operation failed with errors. +>> +>>-- after droppping the view, revokes succeed +>>drop view t135sch_user4.t135_v1_user4; + +--- SQL operation complete. +>>revoke role t135_role1 from sql_user4; + +--- SQL operation complete. +>>revoke role t135_role2 from sql_user4; + +--- SQL operation complete. +>> >>drop table t135_t1 cascade; --- SQL operation complete. @@ -576,6 +641,13 @@ End of MXCI Session --- SQL operation complete. >> +>>drop role t135_role1; + +--- SQL operation complete. +>>drop role t135_role2; + +--- SQL operation complete. +>> >>obey TEST135(constraint_tests); >>-- >>============================================================================ >>set schema t135sch; @@ -647,6 +719,8 @@ CREATE TABLE TRAFODION.T135SCH_USER3.T135_T3 -- GRANT SELECT, INSERT, DELETE, UPDATE, REFERENCES ON TRAFODION.T135SCH_USER3.T135_T3 TO SQL_USER3 WITH GRANT OPTION; --- SQL operation complete. +>> +>>-- ============================================================================ >>exit; End of MXCI Session @@ -697,6 +771,8 @@ ALTER TABLE TRAFODION.T135SCH_USER3.T135_T3 ADD CONSTRAINT -- GRANT SELECT, INSERT, DELETE, UPDATE, REFERENCES ON TRAFODION.T135SCH_USER3.T135_T3 TO SQL_USER3 WITH GRANT OPTION; --- SQL operation complete. +>> +>>-- ============================================================================ >>exit; End of MXCI Session @@ -800,6 +876,8 @@ CREATE TABLE TRAFODION.T135SCH_USER3.T135_T3 -- GRANT SELECT, INSERT, DELETE, UPDATE, REFERENCES ON TRAFODION.T135SCH_USER3.T135_T3 TO SQL_USER3 WITH GRANT OPTION; --- SQL operation complete. +>> +>>-- ============================================================================ >>exit; End of MXCI Session @@ -851,6 +929,8 @@ ALTER TABLE TRAFODION.T135SCH_USER3.T135_T3 ADD CONSTRAINT -- GRANT SELECT, INSERT, DELETE, UPDATE, REFERENCES ON TRAFODION.T135SCH_USER3.T135_T3 TO SQL_USER3 WITH GRANT OPTION; --- SQL operation complete. +>> +>>-- ============================================================================ >>exit; End of MXCI Session http://git-wip-us.apache.org/repos/asf/incubator-trafodion/blob/8652aeb8/core/sql/regress/privs2/EXPECTED140 ---------------------------------------------------------------------- diff --git a/core/sql/regress/privs2/EXPECTED140 b/core/sql/regress/privs2/EXPECTED140 index a7ee967..052709f 100644 --- a/core/sql/regress/privs2/EXPECTED140 +++ b/core/sql/regress/privs2/EXPECTED140 @@ -4,12 +4,12 @@ Current Environment ---------------------------------- AUTHENTICATION disabled AUTHORIZATION enabled -CURRENT DIRECTORY /opt/home/rmarton/git_ws/core/sql/regress/rundir/catman1 +CURRENT DIRECTORY /mnt/rmarton/gitws/incubator-trafodion/core/sql/regress/rundir/privs2 LIST_COUNT 4294967295 LOG FILE LOG140 -MESSAGEFILE /opt/home/rmarton/git_ws/core/sqf/export/bin64d/mxcierr ... +MESSAGEFILE /mnt/rmarton/gitws/incubator-trafodion/core/sqf/export/ ... MESSAGEFILE LANG US English -MESSAGEFILE VRSN {2015-05-22 10:41 LINUX:G4T3035.HOUSTON.HP.COM/rmarton} +MESSAGEFILE VRSN {2016-01-21 17:33 LINUX:EDEV05/rmarton} SQL CATALOG TRAFODION SQL SCHEMA SCH SQL USER CONNECTED user not connected @@ -830,7 +830,7 @@ End of MXCI Session OBJECT_NAME TYPE GRANTOR GRANTEE GRANTED_PRIVS GRANTABLE_PRIVS ---------------------------------------------------------------------------------------------------------------------------------------------------------------- ---- ---------- ---------- -------------------- -------------------- -TRAFODION.T140_SHARED_VIEWS.GAMES_BY_PLA VI -2 SQL_USER2 SI----- SI----- +TRAFODION.T140_SHARED_VIEWS.GAMES_BY_PLA VI -2 SQL_USER2 S------ NONE TRAFODION.T140_SHARED_VIEWS.HOME_TEAM_GA VI -2 DB__ROOT S----R- S----R- TRAFODION.T140_SHARED_VIEWS.HOME_TEAM_GA VI DB__ROOT SQL_USER1 S------ S------ TRAFODION.T140_SHARED_VIEWS.HOME_TEAM_GA VI SQL_USER1 SQL_USER2 S------ NONE @@ -899,7 +899,7 @@ TRAFODION.T140_USER1_PRIVATE.TEAMS OBJECT_NAME TYPE GRANTOR GRANTEE GRANTED_PRIVS GRANTABLE_PRIVS ---------------------------------------------------------------------------------------------------------------------------------------------------------------- ---- ---------- ---------- -------------------- -------------------- -TRAFODION.T140_SHARED_VIEWS.GAMES_BY_PLA VI -2 SQL_USER2 SI----- SI----- +TRAFODION.T140_SHARED_VIEWS.GAMES_BY_PLA VI -2 SQL_USER2 S------ NONE TRAFODION.T140_SHARED_VIEWS.HOME_TEAM_GA VI -2 DB__ROOT S----R- S----R- TRAFODION.T140_SHARED_VIEWS.HOME_TEAM_GA VI DB__ROOT SQL_USER1 S------ S------ TRAFODION.T140_SHARED_VIEWS.HOME_TEAM_GA VI SQL_USER1 SQL_USER2 S------ NONE http://git-wip-us.apache.org/repos/asf/incubator-trafodion/blob/8652aeb8/core/sql/regress/privs2/TEST135 ---------------------------------------------------------------------- diff --git a/core/sql/regress/privs2/TEST135 b/core/sql/regress/privs2/TEST135 index d15e99d..fb71235 100755 --- a/core/sql/regress/privs2/TEST135 +++ b/core/sql/regress/privs2/TEST135 @@ -22,7 +22,7 @@ -- -- @@@ END COPYRIGHT @@@ -- --- This test uses users sql_user1, sql_user2, and sql_user3 +-- This test uses users sql_user1, sql_user2, sql_user3, and sql_user4 -- -- Makes sure privileges are granted correctly for new objects -- Makes sure privileges are revoked correctly for dropped objects @@ -34,17 +34,6 @@ -- ============================================================================ obey TEST135(clean_up); -set parserflags 64; -register user sql_user1; -register user sql_user2; -register user sql_user3; -register user sql_user4; -register user sql_user5; -register user sql_user6; -register user sql_user7; -register user sql_user8; -register user sql_user9; -register user sql_user10; cqd SHOWDDL_DISPLAY_PRIVILEGE_GRANTS 'ON'; log LOG135 clear; sh rm -f LOG135-SECONDARY; @@ -66,6 +55,10 @@ drop table_mapping function sessionize; -- drop database drop schema t135sch cascade; drop schema t135sch_user3 cascade; +drop schema t135sch_user4 cascade; + +drop role t135_role1; +drop role t135_role2; ?section set_up -- ============================================================================ @@ -87,7 +80,7 @@ select object_name, grantee_name, grantor_name from "_PRIVMGR_MD_".object_privileges where object_name in ('TRAFODION.T135SCH.T135_T1', 'TRAFODION.T135SCH.T135_T2', 'TRAFODION.T135SCH.T135_V1', 'TRAFODION.T135SCH.T135_V2', 'TRAFODION.T135SCH.T135_L1', 'TRAFODION.T135SCH.T135_L2', 'TRAFODION.T135SCH.T135_SESSIONIZE', 'TRAFODION.T135SCH.T135_ADD2') -for read uncommitted access; +order by 1,3,2 for read uncommitted access; ?section tbl_tests -- ============================================================================ @@ -219,9 +212,32 @@ revoke all on t135_t1 from sql_user3; sh sqlci -i "TEST135(user3_drops)" -u sql_user3; +-- create some roles +create role t135_role1; +create role t135_role2; +grant role t135_role1, t135_role2 to sql_user4; +grant select on t135_t1 to t135_role1; +grant select on t135_v1_t1 to t135_role2; + +-- have sql_user4 create a view based on role privs +create schema if not exists t135sch_user4 authorization sql_user4; +sh sqlci -i "TEST135(user4_views)" -u sql_user4; + +-- should not be able to revoke user4 from role +revoke role t135_role1 from sql_user4; +revoke role t135_role2 from sql_user4; + +-- after droppping the view, revokes succeed +drop view t135sch_user4.t135_v1_user4; +revoke role t135_role1 from sql_user4; +revoke role t135_role2 from sql_user4; + drop table t135_t1 cascade; drop table t135_t2 cascade; +drop role t135_role1; +drop role t135_role2; + ?section constraint_tests -- ============================================================================ set schema t135sch; @@ -463,3 +479,15 @@ set schema t135sch_user3; log LOG135; alter table t135_t3 add constraint t1_t3 foreign key (c1) references t135sch.t135_t1; showddl t135_t3; + +-- ============================================================================ +?section user4_views +-- ============================================================================ +cqd SHOWDDL_DISPLAY_PRIVILEGE_GRANTS 'ON'; +set schema t135sch_user4; +log LOG135; +create view t135_v1_user4 as + select t135sch.t135_t1.c2, t135sch.t135_v1_t1.c1 + from t135sch.t135_t1, t135sch.t135_v1_t1; +showddl t135_v1_user4; + http://git-wip-us.apache.org/repos/asf/incubator-trafodion/blob/8652aeb8/core/sql/regress/tools/runregr_privs1.ksh ---------------------------------------------------------------------- diff --git a/core/sql/regress/tools/runregr_privs1.ksh b/core/sql/regress/tools/runregr_privs1.ksh index 09eb9d2..7198c90 100755 --- a/core/sql/regress/tools/runregr_privs1.ksh +++ b/core/sql/regress/tools/runregr_privs1.ksh @@ -184,9 +184,6 @@ fi #------------------------------------------------------- skipTheseTests="TEST132" -#skip these tests for Seabase -skipTheseTests="$skipTheseTests" - testfiles="$prettyfiles" prettyfiles= skippedfiles= http://git-wip-us.apache.org/repos/asf/incubator-trafodion/blob/8652aeb8/core/sql/regress/tools/runregr_privs2.ksh ---------------------------------------------------------------------- diff --git a/core/sql/regress/tools/runregr_privs2.ksh b/core/sql/regress/tools/runregr_privs2.ksh index 5d9ea05..af75f3b 100755 --- a/core/sql/regress/tools/runregr_privs2.ksh +++ b/core/sql/regress/tools/runregr_privs2.ksh @@ -184,11 +184,6 @@ fi #------------------------------------------------------- skipTheseTests="" -#skip these tests for Seabase -if [ "$seabase" -ne 0 ]; then - skipTheseTests="$skipTheseTests" -fi - testfiles="$prettyfiles" prettyfiles= skippedfiles= http://git-wip-us.apache.org/repos/asf/incubator-trafodion/blob/8652aeb8/core/sql/sqlcomp/PrivMgrDesc.h ---------------------------------------------------------------------- diff --git a/core/sql/sqlcomp/PrivMgrDesc.h b/core/sql/sqlcomp/PrivMgrDesc.h index 53a3c38..ce325e1 100644 --- a/core/sql/sqlcomp/PrivMgrDesc.h +++ b/core/sql/sqlcomp/PrivMgrDesc.h @@ -26,6 +26,7 @@ #include <bitset> #include <string> +#include <vector> #include "PrivMgrMDDefs.h" #include "PrivMgrDefs.h" #include "ComSmallDefs.h" @@ -145,18 +146,30 @@ class PrivMgrCoreDesc { priv_.reset(); wgo_.reset(); + columnOrdinal_ = -1; } - PrivMgrCoreDesc(std::bitset<NBR_OF_PRIVS> privBits, - std::bitset<NBR_OF_PRIVS> wgoBits) + PrivMgrCoreDesc(PrivMgrBitmap privBits, + PrivMgrBitmap wgoBits) : priv_(privBits) , wgo_(wgoBits) + , columnOrdinal_ (-1) {} + PrivMgrCoreDesc(PrivMgrBitmap privBits, + PrivMgrBitmap wgoBits, + int32_t columnOrdinal) + : priv_(privBits) + , wgo_(wgoBits) + , columnOrdinal_ (columnOrdinal) + {} + + PrivMgrCoreDesc(const PrivMgrCoreDesc&other) // copy constructor { priv_ = other.priv_; wgo_ = other.wgo_; + columnOrdinal_ = other.columnOrdinal_; } virtual ~PrivMgrCoreDesc() // destructor @@ -245,12 +258,14 @@ class PrivMgrCoreDesc // ------------------------------------------------------------------- // Accessors: // ------------------------------------------------------------------- - std::bitset<NBR_OF_PRIVS> getPrivBitmap (void) const { return priv_; } + PrivMgrBitmap getPrivBitmap (void) const { return priv_; } bool getPriv(const PrivType which) const { return priv_.test(which); } - std::bitset<NBR_OF_PRIVS> getWgoBitmap (void) const { return wgo_; } + PrivMgrBitmap getWgoBitmap (void) const { return wgo_; } bool getWgo(const PrivType which) const { return wgo_.test(which); } + int32_t getColumnOrdinal (void) const { return columnOrdinal_; } + // ------------------------------------------------------------------- // Mutators: // ------------------------------------------------------------------- @@ -304,11 +319,18 @@ class PrivMgrCoreDesc setWgo(EXECUTE_PRIV, wgo); } + inline void setColumnOrdinal( const int32_t columnOrdinal ) { columnOrdinal_ = columnOrdinal; } + inline void setPrivBitmap (PrivMgrBitmap priv) { priv_ = priv; } + inline void setWgoBitmap (PrivMgrBitmap wgo) { wgo_ = wgo; } + + + private: - std::bitset<NBR_OF_PRIVS> priv_; // Bit == True if the privilege is held. + PrivMgrBitmap priv_; // Bit == True if the privilege is held. - std::bitset<NBR_OF_PRIVS> wgo_; // == True if the priv is held grantable. + PrivMgrBitmap wgo_; // == True if the priv is held grantable. + int32_t columnOrdinal_; // Private helper function to interpret changes to specified privs. void interpretChanges( const bool before, // in @@ -344,27 +366,23 @@ class PrivMgrDesc public: PrivMgrDesc(const PrivMgrDesc&other) // copy constructor - : tableLevel_(other.tableLevel_), - grantee_(other.grantee_) + : tableLevel_(other.tableLevel_) {} PrivMgrDesc(const int32_t grantee, const int32_t nbrCols = 0 // preset constructor ) : tableLevel_() - , grantee_ (grantee) {} //PrivMgrDesc(const int32_t nbrCols); // preset constructor PrivMgrDesc(const PrivMgrDesc &privs, // preset constructor const int32_t grantee) - : tableLevel_(privs.tableLevel_), - grantee_(grantee) + : tableLevel_(privs.tableLevel_) {} PrivMgrDesc(void) : tableLevel_() - , grantee_(0) {} virtual ~PrivMgrDesc() // destructor @@ -379,7 +397,6 @@ public: tableLevel_ = other.tableLevel_; //columnLevel_ = other.columnLevel_; - grantee_ = other.grantee_; return *this; } @@ -392,7 +409,7 @@ public: if ( this == &other ) return TRUE; - return ( ( grantee_ == other.grantee_) && + return ( // ( columnLevel_ == other.columnLevel_ ) && ( tableLevel_ == other.tableLevel_ ) ); } @@ -440,7 +457,6 @@ public: // Accessors - int32_t getGrantee() const { return grantee_; } PrivMgrCoreDesc getTablePrivs() const { return tableLevel_;} PrivMgrCoreDesc & fetchTablePrivs(); bool getOneTablePriv(const PrivType which) const; @@ -584,9 +600,8 @@ CatPrivs::PrivResult applyTableGrants(const int64_t objectUID, // Data members private: - PrivMgrCoreDesc tableLevel_; - //PrivMgrCoreDesc columnLevel_; - int32_t grantee_; + PrivMgrCoreDesc tableLevel_; + std::vector<PrivMgrCoreDesc> columnLevel_; }; http://git-wip-us.apache.org/repos/asf/incubator-trafodion/blob/8652aeb8/core/sql/sqlcomp/PrivMgrMD.cpp ---------------------------------------------------------------------- diff --git a/core/sql/sqlcomp/PrivMgrMD.cpp b/core/sql/sqlcomp/PrivMgrMD.cpp index c04c778..849a1fb 100644 --- a/core/sql/sqlcomp/PrivMgrMD.cpp +++ b/core/sql/sqlcomp/PrivMgrMD.cpp @@ -151,21 +151,19 @@ PrivStatus PrivMgrMDAdmin::initializeComponentPrivileges() { -// First, let's start with a clean slate. Drop all components as well as -// their respective operations and and any privileges granted. This should be -// a NOP unless PrivMgr metadata was damaged and reintialization is occurring. - -PrivMgrComponents components(metadataLocation_,pDiags_); - - components.dropAll(); - // Next, register the component. PrivStatus privStatus = STATUS_GOOD; + // First, let's start with a clean slate. Drop all components as well as + // their respective operations and and any privileges granted. This should be + // a NOP unless PrivMgr metadata was damaged and reintialization is occurring. + PrivMgrComponents components(metadataLocation_,pDiags_); + components.dropAll(); + privStatus = components.registerComponentInternal(SQL_OPERATION_NAME, - SQL_OPERATIONS_COMPONENT_UID, - true,"Component for SQL operations"); + SQL_OPERATIONS_COMPONENT_UID, + true, "Component for SQL operations"); if (privStatus != STATUS_GOOD) return STATUS_ERROR; @@ -525,7 +523,7 @@ bool PrivMgrMDAdmin::isAuthorized (void) // method: getViewsThatReferenceObject // // this method gets the list of views associated with the passed in -// objectUID that are owned by the objectOwner. +// objectUID that are owned by the granteeID. // **************************************************************************** PrivStatus PrivMgrMDAdmin::getViewsThatReferenceObject ( const ObjectUsage &objectUsage, @@ -536,7 +534,7 @@ PrivStatus PrivMgrMDAdmin::getViewsThatReferenceObject ( std::string viewsMDTable = trafMetadataLocation_ + ".VIEWS v"; std::string roleUsageMDTable = metadataLocation_ + ".ROLE_USAGE"; - // Select all the views that are referenced by the table or view owned by the objectOwner + // Select all the views that are referenced by the table or view owned by the granteeID std::string selectStmt = "select o.object_uid, o.object_owner, o.catalog_name, o.schema_name, o.object_name, v.is_insertable, v.is_updatable from "; selectStmt += objectMDTable; selectStmt += ", "; @@ -551,11 +549,11 @@ PrivStatus PrivMgrMDAdmin::getViewsThatReferenceObject ( // only return rows where user owns the view either directly or through one of // their granted roles selectStmt += " and (o.object_owner = "; - selectStmt += UIDToString(objectUsage.objectOwner); + selectStmt += UIDToString(objectUsage.granteeID); selectStmt += " or o.object_owner in (select role_id from "; selectStmt += roleUsageMDTable; selectStmt += " where grantee_id = "; - selectStmt += UIDToString(objectUsage.objectOwner); + selectStmt += UIDToString(objectUsage.granteeID); selectStmt += ")) order by o.create_time "; @@ -746,11 +744,11 @@ PrivStatus PrivMgrMDAdmin::getUdrsThatReferenceLibrary( selectStmt += UIDToString(objectUsage.objectUID); selectStmt += " and u.used_udr_uid = o.object_uid "; selectStmt += " and (o.object_owner = "; - selectStmt += UIDToString(objectUsage.objectOwner); + selectStmt += UIDToString(objectUsage.granteeID); selectStmt += " or o.object_owner in (select role_id from "; selectStmt += roleUsageMDTable; selectStmt += " where grantee_id = "; - selectStmt += UIDToString(objectUsage.objectOwner); + selectStmt += UIDToString(objectUsage.granteeID); selectStmt += ")) order by o.create_time "; ExeCliInterface cliInterface(STMTHEAP, NULL, NULL, http://git-wip-us.apache.org/repos/asf/incubator-trafodion/blob/8652aeb8/core/sql/sqlcomp/PrivMgrMD.h ---------------------------------------------------------------------- diff --git a/core/sql/sqlcomp/PrivMgrMD.h b/core/sql/sqlcomp/PrivMgrMD.h index 017dc9a..c765d7d 100644 --- a/core/sql/sqlcomp/PrivMgrMD.h +++ b/core/sql/sqlcomp/PrivMgrMD.h @@ -62,7 +62,8 @@ class PrivMgrMDAdmin; // ----------------------------------------------------------------------- typedef struct { int64_t objectUID; - int32_t objectOwner; + int32_t granteeID; + bool grantorIsSystem; std::string objectName; ComObjectType objectType; PrivMgrDesc originalPrivs; @@ -78,8 +79,10 @@ typedef struct { details += to_string((long long int) objectUID); details += ", name is "; details += objectName; - details += ", owner is "; - details += to_string((long long int) objectOwner); + details += ", grantee is "; + details += to_string((long long int) granteeID); + details += ", is owner "; + details += (grantorIsSystem) ? "true " : "false "; } } ObjectUsage; http://git-wip-us.apache.org/repos/asf/incubator-trafodion/blob/8652aeb8/core/sql/sqlcomp/PrivMgrObjects.cpp ---------------------------------------------------------------------- diff --git a/core/sql/sqlcomp/PrivMgrObjects.cpp b/core/sql/sqlcomp/PrivMgrObjects.cpp index 6fce715..ab7ea5d 100644 --- a/core/sql/sqlcomp/PrivMgrObjects.cpp +++ b/core/sql/sqlcomp/PrivMgrObjects.cpp @@ -344,6 +344,58 @@ std::string whereClause(" WHERE CATALOG_NAME = '"); +// ***************************************************************************** +// * * +// * Function: PrivMgrObjects::fetchObjectOwner * +// * * +// * Returns the object owner ID for the object that matches the unique ID * +// * * +// ***************************************************************************** +// * * +// * Parameters: * +// * * +// * * +// * <objectUID> const int64_t In * +// * is the unique ID representing the object. * +// * * +// * <objectOwner> int32_t & Out * +// * passes back the object owner ID. * +// * * +// ***************************************************************************** +// * * +// * Returns: PrivStatus * +// * * +// * STATUS_GOOD: The object owner was returned. * +// * STATUS_ERROR: Theo object owner was not returned. CLI error is put into * +// * the diags area. * +// * * +// ***************************************************************************** + +PrivStatus PrivMgrObjects::fetchObjectOwner( + const int64_t objectUID, + int32_t & objectOwner) + +{ + +MyTable &myTable = static_cast<MyTable &>(myTable_); +MyRow row(fullTableName_); + +std::string whereClause(" WHERE OBJECT_UID = "); + + whereClause += UIDToString(objectUID); + +PrivStatus privStatus = myTable.selectWhereUnique(whereClause,row); + + if (privStatus != STATUS_GOOD) + return STATUS_ERROR; + + objectOwner = row.objectOwner_; + + return STATUS_GOOD; + +} +//****************** End of PrivMgrObjects::fetchObjectOwner ***************** + // ***************************************************************************** // * * http://git-wip-us.apache.org/repos/asf/incubator-trafodion/blob/8652aeb8/core/sql/sqlcomp/PrivMgrObjects.h ---------------------------------------------------------------------- diff --git a/core/sql/sqlcomp/PrivMgrObjects.h b/core/sql/sqlcomp/PrivMgrObjects.h index 11e0863..33e7c3e 100644 --- a/core/sql/sqlcomp/PrivMgrObjects.h +++ b/core/sql/sqlcomp/PrivMgrObjects.h @@ -92,6 +92,10 @@ public: const std::string & schemaName, const std::string & objectName); + PrivStatus fetchObjectOwner( + const int64_t objectUID, + int_32 & objectOwner); + PrivStatus fetchQualifiedName( const int64_t objectUID, std::string & qualifiedObjectName); http://git-wip-us.apache.org/repos/asf/incubator-trafodion/blob/8652aeb8/core/sql/sqlcomp/PrivMgrPrivileges.cpp ---------------------------------------------------------------------- diff --git a/core/sql/sqlcomp/PrivMgrPrivileges.cpp b/core/sql/sqlcomp/PrivMgrPrivileges.cpp index e38317b..f3462b9 100644 --- a/core/sql/sqlcomp/PrivMgrPrivileges.cpp +++ b/core/sql/sqlcomp/PrivMgrPrivileges.cpp @@ -49,6 +49,7 @@ #include "ComUser.h" #include "CmpSeabaseDDLutil.h" #include "logmxevent_traf.h" +class ColPrivEntry; class ColPrivGrant; class ColumnPrivsMDTable; @@ -233,6 +234,29 @@ public: // Describe a row for tracing void describeRow (std::string &rowDetails); +// sets the privilege and grantable bitmaps to 0 + void clearVisited() + { + visited_.columnOrdinal = columnOrdinal_; + visited_.privsBitmap.reset(); + visited_.grantableBitmap.reset(); + } + +// sets the current entry to match the original privileges +// before they are adjusted by a revoke command + void setCurrentToOriginal() + { + current_.columnOrdinal = columnOrdinal_; + current_.privsBitmap = privsBitmap_; + current_.grantableBitmap = grantableBitmap_; + } + +// compares the current privileges with the regenerated grant tree to +// see if there are any broken branches + NABoolean anyNotVisited() + {return current_.privsBitmap != visited_.privsBitmap || + current_.grantableBitmap != visited_.grantableBitmap;} + // ------------------------------------------------------------------- // Data Members: @@ -248,6 +272,9 @@ public: PrivColumnBitmap privsBitmap_; PrivColumnBitmap grantableBitmap_; + ColPrivEntry visited_; + ColPrivEntry current_; + }; @@ -292,17 +319,6 @@ private: ColumnPrivsMDRow &rowOut); }; -class ColPrivEntry -{ -public: - int32_t columnOrdinal; - PrivColumnBitmap privsBitmap; - PrivColumnBitmap grantableBitmap; - bool isUpdate; - ColPrivEntry() - : columnOrdinal(0),isUpdate(false){}; -}; - class ColObjectGrants { public: @@ -395,6 +411,27 @@ static bool hasGrantedColumnPriv( static bool isDelimited( const std::string &identifier); // ***************************************************************************** +// ColPrivEntry constructors +// ***************************************************************************** +ColPrivEntry::ColPrivEntry ( const PrivMgrMDRow &row ) +{ + PrivMgrMDRow theRow = row; + ColumnPrivsMDRow &columnRow = static_cast<ColumnPrivsMDRow &> (theRow); + columnOrdinal = columnRow.columnOrdinal_; + privsBitmap = columnRow.privsBitmap_; + grantableBitmap = columnRow.grantableBitmap_; + isUpdate = false; +} + +ColPrivEntry::ColPrivEntry ( const ColPrivEntry &other) +{ + columnOrdinal = other.columnOrdinal; + privsBitmap = other.privsBitmap; + grantableBitmap = other.grantableBitmap; + isUpdate = other.isUpdate; +} + +// ***************************************************************************** // PrivMgrPrivileges methods // ***************************************************************************** @@ -571,11 +608,11 @@ PrivStatus PrivMgrPrivileges::getColPrivsForUser( { -std::vector<ColumnPrivsMDRow> rowList; + std::vector<ColumnPrivsMDRow> rowList; -// Get the privileges for the columns of the object granted to the grantee -PrivStatus privStatus = getColRowsForGrantee(columnRowList_,granteeID,roleIDs, - rowList,secKeySet); + // Get the privileges for the columns of the object granted to the grantee + PrivStatus privStatus = getColRowsForGrantee(columnRowList_,granteeID,roleIDs, + rowList,secKeySet); if (privStatus == STATUS_ERROR) return privStatus; @@ -998,71 +1035,70 @@ PrivStatus PrivMgrPrivileges::grantColumnPrivileges( const bool isWGOSpecified) { -PrivStatus privStatus = STATUS_GOOD; -std::vector<ColPrivSpec> &colPrivsArray = + std::string traceMsg; + + PrivStatus privStatus = STATUS_GOOD; + std::vector<ColPrivSpec> &colPrivsArray = const_cast<std::vector<ColPrivSpec> &>(colPrivsArrayIn); - log (__FILE__, "checking column privileges", -1); + log (__FILE__, "Checking column privileges", -1); -// generate the list of column privileges granted to the object and store in -// class (columnRowList_) + // generate the list of column privileges granted to the object and store in + // class (columnRowList_) if (generateColumnRowList() == STATUS_ERROR) - return STATUS_ERROR; + return STATUS_ERROR; -// get roleIDs for the grantor -std::vector<int_32> roleIDs; + // get roleIDs for the grantor + std::vector<int_32> roleIDs; privStatus = getRoleIDsForUserID(grantorID_,roleIDs); if (privStatus == STATUS_ERROR) return privStatus; -// Determine if the grantor has WITH GRANT OPTION (WGO) for all the -// columns to be granted. If not, return an error. -ObjectPrivsMDTable objectPrivsTable(objectTableName_,pDiags_); -ColumnPrivsMDTable columnPrivsTable(columnTableName_,pDiags_); + // Determine if the grantor has WITH GRANT OPTION (WGO) for all the + // columns to be granted. If not, return an error. + ObjectPrivsMDTable objectPrivsTable(objectTableName_,pDiags_); + ColumnPrivsMDTable columnPrivsTable(columnTableName_,pDiags_); -// Grantor may have WGO from two sources, object-level grants on the object, -// and column-level grants. First check the object-level grants. If there -// are privileges still to grant, check for requisite column-level grants. + // Grantor may have WGO from two sources, object-level grants on the object, + // and column-level grants. First check the object-level grants. If there + // are privileges still to grant, check for requisite column-level grants. -std::vector<ColPrivEntry> grantedColPrivs; - - if (!hasColumnWGO(colPrivsArrayIn,roleIDs,privStatus)) - { - if (privStatus == STATUS_NOTFOUND) - *pDiags_ << DgSqlCode(-CAT_PRIVILEGE_NOT_GRANTED); - else - PRIVMGR_INTERNAL_ERROR("Cannot fetch privileges"); - return STATUS_ERROR; - } + std::vector<ColPrivEntry> grantedColPrivs; + if (!hasColumnWGO(colPrivsArrayIn,roleIDs,privStatus)) + { + if (privStatus == STATUS_NOTFOUND) + *pDiags_ << DgSqlCode(-CAT_PRIVILEGE_NOT_GRANTED); + else + PRIVMGR_INTERNAL_ERROR("Cannot fetch privileges"); + return STATUS_ERROR; + } -// Grantor has authority to grant all privileges requested. See if some of -// the grants are already present. (may be adding WGO) + // Grantor has authority to grant all privileges requested. See if some of + // the grants are already present. (may be adding WGO) -// Get existing column grants from grantor to the specified grantee. + // Get existing column grants from grantor to the specified grantee. getColRowsForGranteeGrantor(columnRowList_, granteeID,grantorID_, grantedColPrivs); -// Merge the column-privilege-to-grant entries (colPrivArray) into one entry -// per column ordinal. -// -// Example: Given a commands such as -// -// GRANT SELECT(COL4),INSERT(COL2,COL4) ON TAB TO USER; -// -// three entries are generated by the parser, but only two rows are written; -// one for column 2 (insert) and one for column 4 (insert and select). -// -// Input may have same column ordinal in multiple entries, but the input is -// guaranteed not to contain same ordinal and privType more than once. - -std::vector<ColPrivEntry> colPrivsToGrant; - - for (size_t i = 0; i < colPrivsArray.size(); i++) - { - const ColPrivSpec &colPrivEntry = colPrivsArray[i]; + // Merge the column-privilege-to-grant entries (colPrivArray) into one entry + // per column ordinal. + // + // Example: Given a commands such as + // + // GRANT SELECT(COL4),INSERT(COL2,COL4) ON TAB TO USER; + // + // three entries are generated by the parser, but only two rows are written; + // one for column 2 (insert) and one for column 4 (insert and select). + // + // Input may have same column ordinal in multiple entries, but the input is + // guaranteed not to contain same ordinal and privType more than once. + std::vector<ColPrivEntry> colPrivsToGrant; + for (size_t i = 0; i < colPrivsArray.size(); i++) + { + const ColPrivSpec &colPrivEntry = colPrivsArray[i]; ColPrivEntry *existingEntry = findColumnEntry(colPrivsToGrant, colPrivEntry.columnOrdinal); @@ -1081,23 +1117,23 @@ std::vector<ColPrivEntry> colPrivsToGrant; if (isWGOSpecified) colPrivToGrant.grantableBitmap.set(colPrivEntry.privType); - colPrivsToGrant.push_back(colPrivToGrant); - } - } + colPrivsToGrant.push_back(colPrivToGrant); + } + } -// Walk the list of column privileges to grant, and either insert a new -// row in the COLUMN_PRIVILEGES table or update an existing row. + // Walk the list of column privileges to grant, and either insert a new + // row in the COLUMN_PRIVILEGES table or update an existing row. -bool rowWritten = false; + bool rowWritten = false; -std::string whereBase(" WHERE object_uid = "); + std::string whereBase(" WHERE object_uid = "); - whereBase += UIDToString(objectUID_); - whereBase += " AND grantor_id = "; - whereBase += authIDToString(grantorID_); - whereBase += " AND grantee_id = "; - whereBase += authIDToString(granteeID); - whereBase += " AND column_number = "; + whereBase += UIDToString(objectUID_); + whereBase += " AND grantor_id = "; + whereBase += authIDToString(grantorID_); + whereBase += " AND grantee_id = "; + whereBase += authIDToString(granteeID); + whereBase += " AND column_number = "; for (size_t i = 0; i < colPrivsToGrant.size(); i++) { @@ -1170,28 +1206,46 @@ std::string whereBase(" WHERE object_uid = "); if (skipOperation) continue; - ColumnPrivsMDRow row; + // TBD: need to get the list of referencing views that need to have this + // privilege progated. + // + // SQL ANSI general rules state + // + // - When granting INSERT, UPDATE, or DELETE object or column privilege to + // a table that is referenced by one or more views, then the privilege + // should be propagated to any updatable views that reference the table. + // The grant request to the these views should be executed as though the + // current user is _SYSTEM. + // + // - If the table already has SELECT privilege and a new grant is + // performed that adds the WITH GRANT OPTION, then the WITH GRANT OPTION + // is to be propagated to referencing views. The grant request should + // be executed as though the current user is _SYSTEM. + + + // Prepare for the insert or update request + ColumnPrivsMDRow row; - row.objectUID_ = objectUID_; - row.objectName_ = objectName_; - row.granteeID_ = granteeID; - row.granteeName_ = granteeName; - row.grantorID_ = grantorID_; - row.grantorName_ = grantorName; - row.privsBitmap_ = colPrivToGrant.privsBitmap; - row.grantableBitmap_ = colPrivToGrant.grantableBitmap; - row.columnOrdinal_ = colPrivToGrant.columnOrdinal; + row.objectUID_ = objectUID_; + row.objectName_ = objectName_; + row.granteeID_ = granteeID; + row.granteeName_ = granteeName; + row.grantorID_ = grantorID_; + row.grantorName_ = grantorName; + row.privsBitmap_ = colPrivToGrant.privsBitmap; + row.grantableBitmap_ = colPrivToGrant.grantableBitmap; + row.columnOrdinal_ = colPrivToGrant.columnOrdinal; - if (updateOperation) - privStatus = columnPrivsTable.updateColumnRow(row,whereBase); - else - privStatus = columnPrivsTable.insert(row); + if (updateOperation) + privStatus = columnPrivsTable.updateColumnRow(row,whereBase); + else + privStatus = columnPrivsTable.insert(row); - if (privStatus == STATUS_ERROR) - return privStatus; + if (privStatus == STATUS_ERROR) + return privStatus; - rowWritten = true; - } + rowWritten = true; + } //TODO: Could issue a warning if no privileges were granted; means all // requested grants already exist. @@ -1435,7 +1489,8 @@ PrivStatus PrivMgrPrivileges::grantObjectPriv( { ObjectUsage objectUsage; objectUsage.objectUID = objectUID_; - objectUsage.objectOwner = granteeID; + objectUsage.granteeID = granteeID; + objectUsage.grantorIsSystem = false; objectUsage.objectName = row.objectName_; objectUsage.objectType = row.objectType_; @@ -1467,8 +1522,24 @@ PrivStatus PrivMgrPrivileges::grantObjectPriv( pObj->describe(traceMsg); log (__FILE__, traceMsg, i); - int32_t theGrantor = (pObj->objectType == COM_VIEW_OBJECT) ? SYSTEM_USER : grantorID_; - int32_t theGrantee = pObj->objectOwner; + // Determine the grantor: + // SQL ANSI general rules state + // + // - When granting INSERT, UPDATE, or DELETE object or column privilege to + // a table that is referenced by one or more views, then the privilege + // should be propagated to any updatable views that reference the table. + // The grant request to the these views should be executed as though the + // current user is _SYSTEM. + // + // - If the table already has SELECT privilege and a new grant is + // performed that adds the WITH GRANT OPTION, then the WITH GRANT OPTION + // is to be propagated to referencing views. The grant request should + // be executed as though the current user is _SYSTEM. + // + // The listOfObjects contains referencing views that meet the above + // criteria. + int32_t theGrantor = (pObj->grantorIsSystem) ? SYSTEM_USER : grantorID_; + int32_t theGrantee = pObj->granteeID; int64_t theUID = pObj->objectUID; PrivMgrCoreDesc thePrivs = pObj->updatedPrivs.getTablePrivs(); @@ -1866,7 +1937,7 @@ PrivStatus PrivMgrPrivileges::dealWithUdrs( if (objectList.size() > 0) { std::vector<int32_t> roleIDs; - retcode = getRoleIDsForUserID(objectUsage.objectOwner,roleIDs); + retcode = getRoleIDsForUserID(objectUsage.granteeID,roleIDs); if (retcode == STATUS_ERROR) return retcode; @@ -1874,7 +1945,7 @@ PrivStatus PrivMgrPrivileges::dealWithUdrs( // privs for the library // current privs contains any adjustments retcode = summarizeCurrentAndOriginalPrivs(objectUsage.objectUID, - objectUsage.objectOwner, + objectUsage.granteeID, roleIDs, listOfAffectedObjects, originalPrivs, @@ -1975,22 +2046,28 @@ PrivStatus PrivMgrPrivileges::dealWithViews( { // this view is affected by the grant/revoke request, add to list // and check to see if anything down stream needs to change - ObjectUsage *pUsage = new (ObjectUsage); - pUsage->objectUID = viewUsage.viewUID; - pUsage->objectOwner = viewUsage.viewOwner; - pUsage->objectName = viewUsage.viewName; - pUsage->objectType = COM_VIEW_OBJECT; - pUsage->originalPrivs = viewUsage.originalPrivs; - pUsage->updatedPrivs = viewUsage.updatedPrivs; - listOfAffectedObjects.push_back(pUsage); - - traceMsg = "adding new objectUsage for "; - pUsage->describe(traceMsg); - log (__FILE__, traceMsg, i); - - retcode = dealWithViews(*pUsage, command, listOfAffectedObjects); - if (retcode != STATUS_GOOD && retcode != STATUS_WARNING) - return retcode; + // We already have select privilege on the view. So only adjust + // view for other privileges if it is updatable and insertable + if (viewUsage.isUpdatable && viewUsage.isInsertable) + { + ObjectUsage *pUsage = new (ObjectUsage); + pUsage->objectUID = viewUsage.viewUID; + pUsage->granteeID = viewUsage.viewOwner; + pUsage->grantorIsSystem = true; + pUsage->objectName = viewUsage.viewName; + pUsage->objectType = COM_VIEW_OBJECT; + pUsage->originalPrivs = viewUsage.originalPrivs; + pUsage->updatedPrivs = viewUsage.updatedPrivs; + listOfAffectedObjects.push_back(pUsage); + + traceMsg = "adding new objectUsage for "; + pUsage->describe(traceMsg); + log (__FILE__, traceMsg, i); + + retcode = dealWithViews(*pUsage, command, listOfAffectedObjects); + if (retcode != STATUS_GOOD && retcode != STATUS_WARNING) + return retcode; + } } } @@ -2202,7 +2279,8 @@ PrivStatus PrivMgrPrivileges::getAffectedObjects( // found an object whose privileges need to be updated ObjectUsage *pUsage = new (ObjectUsage); pUsage->objectUID = objectUsage.objectUID; - pUsage->objectOwner = objectUsage.objectOwner; + pUsage->granteeID = objectUsage.granteeID; + pUsage->grantorIsSystem = objectUsage.grantorIsSystem; pUsage->objectName = objectUsage.objectName; pUsage->objectType = objectUsage.objectType; pUsage->originalPrivs = objectUsage.originalPrivs; @@ -2452,56 +2530,79 @@ PrivStatus PrivMgrPrivileges::revokeColumnPrivileges( return privStatus; } -// Create a privsToRevoke array using the passed in revoke entries and the -// list of currently granted column privileges. Combine multiple privileges -// for the same column into one entry. - -std::vector<ColPrivEntry> colPrivsToRevoke; + // Create a privsToRevoke array using the passed in revoke entries and the + // list of currently granted column privileges. Combine multiple privileges + // for the same column into one entry. + std::vector<ColPrivEntry> colPrivsToRevoke; for (size_t i = 0; i < colPrivsArray.size(); i++) { const ColPrivSpec &colPrivSpecEntry = colPrivsArray[i]; + PrivType privType = colPrivSpecEntry.privType; + int32_t columnOrdinal = colPrivSpecEntry.columnOrdinal; + // Find the priv details from metadata + ColPrivEntry *metadataEntry = findColumnEntry(grantedColPrivs, + columnOrdinal); + if (metadataEntry == NULL) + { + PRIVMGR_INTERNAL_ERROR("Privilege to revoke not found"); + return STATUS_ERROR; + } + + // See if privilege entry has already been created ColPrivEntry *existingEntry = findColumnEntry(colPrivsToRevoke, - colPrivSpecEntry.columnOrdinal); + columnOrdinal); if (existingEntry != NULL) - existingEntry->privsBitmap.set(colPrivSpecEntry.privType); + { + existingEntry->privsBitmap.set(privType); + + // if revoking a privilege and auth ID has WGO, then revoke + // the WGO bit also + PrivColumnBitmap grantableBitmap = metadataEntry->grantableBitmap; + existingEntry->grantableBitmap.set(privType, grantableBitmap.test(privType)); + } else { ColPrivEntry colPrivToRevoke; - colPrivToRevoke.columnOrdinal = colPrivSpecEntry.columnOrdinal; - colPrivToRevoke.privsBitmap.set(colPrivSpecEntry.privType); - + colPrivToRevoke.columnOrdinal = columnOrdinal; + colPrivToRevoke.privsBitmap.set(privType); + + // if revoking a privilege and auth ID has WGO, then revoke + // the WGO bit also + colPrivToRevoke.grantableBitmap.set(privType, metadataEntry->grantableBitmap.test(privType)); + colPrivsToRevoke.push_back(colPrivToRevoke); } } -// At this point we have an array of privsToRevoke with column ordinal and -// priv bitmap. -// -// Three revoke column cases: -// -// Spec Spec Priv bitmap compare -// GOF Priv to granted priv bitmap Action -// T 1 NA Removing WGO only. Update operation. -// Reset privType bit in grantable bitmap, -// copy priv bitmap from granted privs. -// -// F 1 Equal Revoking all privs on this column, plus -// WGO. Delete operation. -// -// F 1 Not equal Revoking some privs on this column plus -// WGO for the revoked privs. Reset bits in -// both bitmaps. Update operation. - - -//TODO: When revoking WGO, need to check for dependent objects, e.g. views. - -bool rowRevoked = false; -PrivColumnBitmap revokedPrivs; + // Verify that the existing grant tree stays intact (i.e. no broken branches) + // if the requested privileges are revokew. + if (checkColumnRevokeRestrict (granteeID, colPrivsToRevoke, columnRowList_)) + return STATUS_ERROR; -std::string whereBase(" WHERE object_uid = "); + // At this point we have an array of privsToRevoke with column ordinal and + // priv bitmap. + // + // Three revoke column cases: + // + // Spec Spec Priv bitmap compare + // GOF Priv to granted priv bitmap Action + // T 1 NA Removing WGO only. Update operation. + // Reset privType bit in grantable bitmap, + // copy priv bitmap from granted privs. + // + // F 1 Equal Revoking all privs on this column, plus + // WGO. Delete operation. + // + // F 1 Not equal Revoking some privs on this column plus + // WGO for the revoked privs. Reset bits in + // both bitmaps. Update operation. + bool rowRevoked = false; + PrivColumnBitmap revokedPrivs; + + std::string whereBase(" WHERE object_uid = "); whereBase += UIDToString(objectUID_); whereBase += " AND grantor_id = "; @@ -2601,9 +2702,9 @@ std::string whereBase(" WHERE object_uid = "); rowRevoked = true; } -// Send revoked privs to RMS -SQL_QIKEY siKeyList[NBR_DML_COL_PRIVS]; -size_t siIndex = 0; + // Send revoked privs to RMS + SQL_QIKEY siKeyList[NBR_DML_COL_PRIVS]; + size_t siIndex = 0; for (size_t i = FIRST_DML_COL_PRIV; i <= LAST_DML_COL_PRIV; i++ ) { @@ -2807,7 +2908,8 @@ PrivStatus PrivMgrPrivileges::revokeObjectPriv (const ComObjectType objectType, // removing the privilege ObjectUsage objectUsage; objectUsage.objectUID = objectUID_; - objectUsage.objectOwner = granteeID; + objectUsage.granteeID = granteeID; + objectUsage.grantorIsSystem = false; objectUsage.objectName = row.objectName_; objectUsage.objectType = row.objectType_; @@ -2837,8 +2939,23 @@ PrivStatus PrivMgrPrivileges::revokeObjectPriv (const ComObjectType objectType, ObjectUsage *pObj = listOfObjects[i]; PrivMgrCoreDesc thePrivs = pObj->updatedPrivs.getTablePrivs(); - int32_t theGrantor = grantorID_; - int32_t theGrantee = pObj->objectOwner; + // Determine the grantor: + // SQL ANSI general rules state + // + // - When revoking INSERT, UPDATE, or DELETE object or column privilege from + // a table that is referenced by one or more views, then the privilege + // should be revoked on any updatable views that reference the table. + // The revoke request to the these views should be executed as though the + // current user is _SYSTEM. + // + // - If the revoke is performed that removes the WITH GRANT OPTION, then + // the WITH GRANT OPTION is to be removed frome referencing views. The + // revoke request should be executed as though the current user is _SYSTEM. + // + // The listOfObjects contains referencing views that meet the above + // criteria. + int32_t theGrantor = (pObj->grantorIsSystem) ? SYSTEM_USER : grantorID_; + int32_t theGrantee = pObj->granteeID; int64_t theUID = pObj->objectUID; sprintf(buf, "where grantee_id = %d and grantor_id = %d and object_uid = %ld", @@ -3151,6 +3268,264 @@ void PrivMgrPrivileges::scanPublic( const PrivType pType, // in } // end scan privsList over all Grantees/Grantors } // end scanPublic +// ---------------------------------------------------------------------------- +// method: checkColumnRevokeRestrict +// +// This method starts at the beginning of the privilege tree and rebuilds +// it from top to bottom. If the revoke causes part of the tree to be +// unaccessible (a broken branch), it returns true; otherwise, revoke can +// proceed - returns false. +// +// Params: +// granteeID - the target AuthID +// colPrivsToRevoke - the list of column entries containing proposed +// changes from the requested revoke statement. +// rowList - a list of all the rows associated with the object +// +// true - unable to perform revoke because of dependencies +// false - able to perform revoke.privileges +// +// The diags area is set up with where the tree was broken +// ---------------------------------------------------------------------------- +bool PrivMgrPrivileges::checkColumnRevokeRestrict ( + int32_t granteeID, + const std::vector<ColPrivEntry> &colPrivsToRevoke, + std::vector <PrivMgrMDRow *> &rowList ) +{ + std::string traceMsg; + log (__FILE__, "checking column grant tree for broken branches", -1); + + // Clear visited_ bitmaps and set current_ bitmaps to current priv values + // Search the list of privileges associated with the object and turn off + // the bitmaps in current_ that are no longer available when the revoke + // completes - based on colPrivsToRevoke. + for (int32_t i = 0; i < rowList.size(); i++) + { + ColumnPrivsMDRow ¤tRow = static_cast<ColumnPrivsMDRow &> (*rowList[i]); + currentRow.setCurrentToOriginal(); + currentRow.clearVisited(); + + // only look at rows for the current grantor and grantee + if (currentRow.grantorID_ == grantorID_ && + currentRow.granteeID_ == granteeID) + { + // Adjust rows that have had their privileges updated + for (int32_t j = 0; j < colPrivsToRevoke.size(); j++) + { + ColPrivEntry updatedEntry = (ColPrivEntry)colPrivsToRevoke[j]; + + if (updatedEntry.columnOrdinal == currentRow.columnOrdinal_) + { + PrivColumnBitmap newPrivsBitmap = updatedEntry.privsBitmap ^= currentRow.privsBitmap_; + PrivColumnBitmap newGrantableBitmap = updatedEntry.grantableBitmap ^= currentRow.grantableBitmap_; + currentRow.current_.privsBitmap = newPrivsBitmap; + currentRow.current_.grantableBitmap = newGrantableBitmap; + traceMsg = "Adjusted current_ to reflect revoked privileges"; + traceMsg += ", grantor is "; + traceMsg += to_string((long long int)currentRow.grantorID_); + traceMsg += ", grantee is "; + traceMsg += to_string((long long int) currentRow.granteeID_); + log (__FILE__, traceMsg, -1); + } + } + } + } + + // Reconstruct the privilege tree based on the adjusted privileges + // starting with the object owner - get the object owner. + PrivMgrObjects objects(trafMetadataLocation_,pDiags_); + int32_t objectOwner = 0; + PrivStatus privStatus = objects.fetchObjectOwner(objectUID_,objectOwner); + if (privStatus == STATUS_ERROR) + { + PRIVMGR_INTERNAL_ERROR("Could not fetch object owner"); + return true; + } + + // Create the list of columns that have been changed, during + // reconstruction, only look at rows that have changes. + // std::set does not add entries if they already exist. + std::set<int32_t> listOfColumnOrdinals; + for ( size_t i = 0; i < colPrivsToRevoke.size(); i++) + { + const ColPrivEntry colPrivToRevoke = colPrivsToRevoke[i]; + listOfColumnOrdinals.insert(colPrivToRevoke.columnOrdinal); + } + + // Reconstruct tree + for ( size_t i = 0; i < NBR_DML_COL_PRIVS; i++ ) + { + scanColumnBranch (PrivType(i), objectOwner, listOfColumnOrdinals, rowList); + } + + // If a branch of the tree was not visited, then we have a broken + // tree. Therefore, revoke restrict will leave abandoned privileges + // in the case, return true. + bool notVisited = false; + for (size_t i = 0; i < rowList.size(); i++) + { + ColumnPrivsMDRow ¤tRow = static_cast<ColumnPrivsMDRow &> (*rowList[i]); + + // Only look at rows that have been changed + for (std::set<int32_t>::iterator it = listOfColumnOrdinals.begin(); + it!= listOfColumnOrdinals.end(); ++it) + { + if (*it == currentRow.columnOrdinal_) + { + currentRow.describeRow(traceMsg); + log (__FILE__, traceMsg, i); + + if (currentRow.anyNotVisited()) + { + *pDiags_ << DgSqlCode(-CAT_DEPENDENT_PRIV_EXISTS) + << DgString0(currentRow.grantorName_.c_str()) + << DgString1(currentRow.granteeName_.c_str()); + + log (__FILE__, "found a branch that is not accessible", -1); + notVisited = true; + break; + } + } + } + } + return notVisited; +} + +// ---------------------------------------------------------------------------- +// method: scanObjectBranch +// +// scans the privsList entries for match on Grantor, +// keeping track of which priv/wgo entries have been encountered +// by setting "visited" flag in the entry. +// +// For each entry discovered, set visited flag to indicate that +// priv and wgo were seen. For wgo, if the wgo visited flag has not +// already been set, call scanObjectBranch recursively with this grantee +// as grantor. (By observing the state of the wgo visited flag +// we avoid redundantly exploring the sub-tree rooted in a grantor +// which has already been discovered as having wgo from some other +// ancestor grantor.) +// +// This algorithm produces a depth-first scan of all nodes of the +// directed graph of privilege settings which can currently be reached +// by an uninterrupted chain of wgo values. +// +// The implementation is dependent on the fact that rowList +// entries are ordered by Grantor, Grantee, columnOrdinal +// ----------------------------------------------------------------------------- +void PrivMgrPrivileges::scanColumnBranch( const PrivType pType, + const int32_t& grantor, + const std::set<int32_t> &listOfColumnOrdinals, + const std::vector<PrivMgrMDRow *> & rowList ) +{ + + // The PrivMgrMDRow <list> is maintained in order by + // columnOrdinal within Grantee within Grantor - through an order by clause. + + // Skip over Grantors lower than the specified one. + size_t i = 0; + while ( i < rowList.size() ) + { + ColumnPrivsMDRow ¤tRow = static_cast<ColumnPrivsMDRow &> (*rowList[i]); + if (currentRow.grantorID_ < grantor) + i++; + else + break; + } + + // For matching Grantor, process each Grantee. + while ( i < rowList.size() ) + { + ColumnPrivsMDRow ¤tRow = static_cast<ColumnPrivsMDRow &> (*rowList[i]); + if (currentRow.grantorID_ == grantor) + { + + // Just look at rows that have had privileges changed + // The listOfColumnOrdinals has this list + ColPrivEntry current = currentRow.current_; + std::set<int32_t>::iterator it; + it = std::find(listOfColumnOrdinals.begin(), listOfColumnOrdinals.end(), current.columnOrdinal); + if (it != listOfColumnOrdinals.end()) + { + if ( current.privsBitmap.test(pType) ) + { + // This grantee has priv. Set corresponding visited flag. + currentRow.visited_.privsBitmap.set(pType, true); + + if ( current.grantableBitmap.test(pType)) + { + // This grantee has wgo. + if ( currentRow.visited_.grantableBitmap.test(pType) ) + { // Already processed this subtree. + } + else + { + currentRow.visited_.grantableBitmap.set(pType, true); + + // To check: since column level privileges do not have + // an anchor, we choose the object owner as the root. + int32_t thisGrantee( currentRow.granteeID_ ); + if ( ComUser::isPublicUserID(thisGrantee) ) + scanPublic( pType, // Deal with PUBLIC grantee wgo. + rowList ); + else + { + int32_t granteeAsGrantor(thisGrantee); + scanColumnBranch( pType, // Scan for this grantee as grantor. + granteeAsGrantor, + listOfColumnOrdinals, + rowList ); + } + } + } // end this grantee has wgo + } // end this grantee has this priv + } // correct column ordinal + i++; // on to next rowList entry + } + else + break; // done with the grantor + } // end scan rowList over Grantees for this Grantor +} + +/* ******************************************************************* + scanColumnPublic -- a grant wgo to PUBLIC has been encountered for the + current privilege type, so *all* users are able to grant this privilege. + Scan the privsList for all grantees who have this priv from any grantor, + marking each such entry as visited. + +****************************************************************** */ + +void PrivMgrPrivileges::scanColumnPublic( + const PrivType pType, // in + const std::set<int32_t> &listOfColumnOrdinals, + const std::vector<PrivMgrMDRow *>& rowList ) // in +{ + // PUBLIC has a priv wgo. So *every* grant of this priv + // is allowed, by any Grantor. + for ( size_t i = 0; i < rowList.size(); i++ ) + { + ColumnPrivsMDRow ¤tRow = static_cast<ColumnPrivsMDRow &> (*rowList[i]); + + // Just look at rows that have had privileges changed + // The listOfColumnOrdinals has this list + ColPrivEntry current = currentRow.current_; + std::set<int32_t>::iterator it; + it = std::find(listOfColumnOrdinals.begin(), listOfColumnOrdinals.end(), current.columnOrdinal); + if (it != listOfColumnOrdinals.end()) + { + if ( current.privsBitmap.test(pType) ) + { + // This grantee has priv. Set corresponding visited flag. + currentRow.visited_.privsBitmap.set(pType, true); + + // This grantee has wgo. + if ( currentRow.visited_.grantableBitmap.test(pType) ) + currentRow.visited_.grantableBitmap.set(pType, true); + } + } + } // end scan privsList over all Grantees/Grantors +} // end scanPublic + // **************************************************************************** // method: sendSecurityKeysToRMS @@ -3765,7 +4140,7 @@ PrivStatus PrivMgrPrivileges::summarizeCurrentAndOriginalPrivs( ObjectUsage *pObj = listOfChangedPrivs[j]; if (pObj->objectUID == row.objectUID_ && grantorID_ == row.grantorID_ && - pObj->objectOwner == row.granteeID_ ) + pObj->granteeID == row.granteeID_ ) { current = pObj->updatedPrivs.getTablePrivs(); } http://git-wip-us.apache.org/repos/asf/incubator-trafodion/blob/8652aeb8/core/sql/sqlcomp/PrivMgrPrivileges.h ---------------------------------------------------------------------- diff --git a/core/sql/sqlcomp/PrivMgrPrivileges.h b/core/sql/sqlcomp/PrivMgrPrivileges.h index ce0ca55..473e2cd 100644 --- a/core/sql/sqlcomp/PrivMgrPrivileges.h +++ b/core/sql/sqlcomp/PrivMgrPrivileges.h @@ -57,6 +57,24 @@ public: }; // ***************************************************************************** +// * Class: ColPrivEntry +// * Description: This class represents the privileges and corresponding +// * WGO (with grant option) for a column +// ***************************************************************************** +class ColPrivEntry +{ +public: + int32_t columnOrdinal; + PrivColumnBitmap privsBitmap; + PrivColumnBitmap grantableBitmap; + bool isUpdate; + ColPrivEntry() + : columnOrdinal(0),isUpdate(false){}; + ColPrivEntry(const PrivMgrMDRow &row); + ColPrivEntry(const ColPrivEntry &other); +}; + +// ***************************************************************************** // * Class: PrivMgrPrivileges // * Description: This class represents the access rights for objects // ***************************************************************************** @@ -263,6 +281,11 @@ private: // Private functions: // ------------------------------------------------------------------- + bool checkColumnRevokeRestrict ( + int32_t granteeID, + const std::vector<ColPrivEntry> &colPrivsToRevoke, + std::vector <PrivMgrMDRow *> &rowList ); + bool checkRevokeRestrict ( PrivMgrMDRow &rowIn, std::vector<PrivMgrMDRow *> &rowList ); @@ -334,10 +357,20 @@ private: const std::vector<int32_t> &roleIDs, PrivStatus & privStatus); + void scanColumnBranch( const PrivType pType, + const int32_t& grantor, + const std::set<int32_t> &listOfColumnOrdinals, + const std::vector<PrivMgrMDRow *> & rowList ); + + void scanColumnPublic( + const PrivType pType, + const std::set<int32_t> &listOfColumnOrdinals, + const std::vector<PrivMgrMDRow *>& rowList ); + void scanObjectBranch( - const PrivType pType, // in - const int32_t& grantor, // in - const std::vector<PrivMgrMDRow *>& rowList ); // in + const PrivType pType, + const int32_t& grantor, + const std::vector<PrivMgrMDRow *>& rowList ); void scanPublic( const PrivType pType, // in http://git-wip-us.apache.org/repos/asf/incubator-trafodion/blob/8652aeb8/core/sql/sqlcomp/PrivMgrRoles.cpp ---------------------------------------------------------------------- diff --git a/core/sql/sqlcomp/PrivMgrRoles.cpp b/core/sql/sqlcomp/PrivMgrRoles.cpp index cc7abe8..8f47202 100644 --- a/core/sql/sqlcomp/PrivMgrRoles.cpp +++ b/core/sql/sqlcomp/PrivMgrRoles.cpp @@ -412,6 +412,7 @@ PrivMgrMDAdmin admin(trafMetadataLocation_,metadataLocation_,pDiags_); switch (referencedObjectsList[obj]->objectType) { case COM_BASE_TABLE_OBJECT: + case COM_VIEW_OBJECT: privType = SELECT_PRIV; break; case COM_USER_DEFINED_ROUTINE_OBJECT:
