From: <rom...@us...> - 2014-07-08 07:35:38
|
Revision: 59840 http://sourceforge.net/p/firebird/code/59840 Author: roman-simakov Date: 2014-07-08 07:35:27 +0000 (Tue, 08 Jul 2014) Log Message: ----------- Fixed CORE-735: User rights for metadata changes. We check DDL in DDL nodes and skip at vio level. vio level still exists for direct metadata editing. Modified Paths: -------------- firebird/trunk/lang_helpers/gds_codes.ftn firebird/trunk/lang_helpers/gds_codes.pas firebird/trunk/src/dsql/DdlNodes.epp firebird/trunk/src/dsql/DdlNodes.h firebird/trunk/src/dsql/Nodes.h firebird/trunk/src/dsql/PackageNodes.epp firebird/trunk/src/dsql/PackageNodes.h firebird/trunk/src/dsql/parse.y firebird/trunk/src/include/gen/codetext.h firebird/trunk/src/include/gen/iberror.h firebird/trunk/src/include/gen/ids.h firebird/trunk/src/include/gen/msgs.h firebird/trunk/src/include/gen/sql_code.h firebird/trunk/src/include/gen/sql_state.h firebird/trunk/src/jrd/Database.h firebird/trunk/src/jrd/acl.h firebird/trunk/src/jrd/constants.h firebird/trunk/src/jrd/drq.h firebird/trunk/src/jrd/filters.cpp firebird/trunk/src/jrd/grant.epp firebird/trunk/src/jrd/ini.epp firebird/trunk/src/jrd/intl.h firebird/trunk/src/jrd/jrd.h firebird/trunk/src/jrd/met.epp firebird/trunk/src/jrd/obj.h firebird/trunk/src/jrd/relations.h firebird/trunk/src/jrd/scl.epp firebird/trunk/src/jrd/scl.h firebird/trunk/src/jrd/scl_proto.h firebird/trunk/src/jrd/vio.cpp firebird/trunk/src/msgs/facilities2.sql firebird/trunk/src/msgs/messages2.sql firebird/trunk/src/msgs/system_errors2.sql Added Paths: ----------- firebird/trunk/doc/sql.extensions/README.ddl_access.txt Added: firebird/trunk/doc/sql.extensions/README.ddl_access.txt =================================================================== --- firebird/trunk/doc/sql.extensions/README.ddl_access.txt (rev 0) +++ firebird/trunk/doc/sql.extensions/README.ddl_access.txt 2014-07-08 07:35:27 UTC (rev 59840) @@ -0,0 +1,35 @@ +SQL Language Extension: GRANT/REVOKE permissions on DDL operations + + Implements capability to manage permissions on DDL operations. + +Author: + Red Soft Corporation, roman.simakov(at)red-soft.biz + +Syntax is: + +GRANT CREATE <OBJECT> TO USER|ROLE [with grant option]; +GRANT ALTER ANY <OBJECT> TO USER|ROLE [with grant option]; +GRANT DROP ANY <OBJECT> TO USER|ROLE [with grant option]; + +REVOKE [grant option for] CREATE <OBJECT> FROM USER|ROLE; +REVOKE [grant option for] ALTER ANY <OBJECT> FROM USER|ROLE; +REVOKE [grant option for] DROP ANY <OBJECT> FROM USER|ROLE; + +Where <OBJECT> could be: +TABLE, VIEW, PROCEDURE, FUNCTION, PACKAGE, GENERATOR, SEQUENCE, DOMAIN, +EXCEPTION, ROLE, SHADOW, DATABASE, CHARACTER SET, COLLATION, FILTER + +Description: + +Makes it possible to grant and revoke privileges on DDL operations. + +DDL operations for managing triggers and indices re-use table privileges. + +If ANY keyword is used a user will be able to perform operation on any object. Otherwise only on object which he owns. +If ANY keyword was used due GRANT operation it also must be used in according REVOKE operation. + +Sample: + +GRANT CREATE TABLE TO Joe; +GRANT ALTER ANY TABLE TO Joe; +REVOKE CREATE TABLE FROM Joe; Property changes on: firebird/trunk/doc/sql.extensions/README.ddl_access.txt ___________________________________________________________________ Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +Author Date Id Rev URL \ No newline at end of property Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Modified: firebird/trunk/lang_helpers/gds_codes.ftn =================================================================== --- firebird/trunk/lang_helpers/gds_codes.ftn 2014-07-08 00:52:54 UTC (rev 59839) +++ firebird/trunk/lang_helpers/gds_codes.ftn 2014-07-08 07:35:27 UTC (rev 59840) @@ -1598,6 +1598,10 @@ PARAMETER (GDS__cursor_not_positioned = 335545092) INTEGER*4 GDS__dup_attribute PARAMETER (GDS__dup_attribute = 335545093) + INTEGER*4 GDS__dyn_no_priv + PARAMETER (GDS__dyn_no_priv = 335545094) + INTEGER*4 GDS__dsql_cant_grant_option + PARAMETER (GDS__dsql_cant_grant_option = 335545095) INTEGER*4 GDS__gfix_db_name PARAMETER (GDS__gfix_db_name = 335740929) INTEGER*4 GDS__gfix_invalid_sw Modified: firebird/trunk/lang_helpers/gds_codes.pas =================================================================== --- firebird/trunk/lang_helpers/gds_codes.pas 2014-07-08 00:52:54 UTC (rev 59839) +++ firebird/trunk/lang_helpers/gds_codes.pas 2014-07-08 07:35:27 UTC (rev 59840) @@ -806,6 +806,8 @@ gds_set_invalid_role = 335545091; gds_cursor_not_positioned = 335545092; gds_dup_attribute = 335545093; + gds_dyn_no_priv = 335545094; + gds_dsql_cant_grant_option = 335545095; gds_gfix_db_name = 335740929; gds_gfix_invalid_sw = 335740930; gds_gfix_incmp_sw = 335740932; Modified: firebird/trunk/src/dsql/DdlNodes.epp =================================================================== --- firebird/trunk/src/dsql/DdlNodes.epp 2014-07-08 00:52:54 UTC (rev 59839) +++ firebird/trunk/src/dsql/DdlNodes.epp 2014-07-08 07:35:27 UTC (rev 59840) @@ -747,7 +747,16 @@ //---------------------- +SecureDdlNodeExecute::SecureDdlNodeExecute(thread_db* tdbb, DdlNode* ddlNode, + DsqlCompilerScratch* dsqlScratch, jrd_tra* transaction): _tdbb(tdbb) +{ + if (ddlNode->checkPermission(tdbb, transaction)) + tdbb->tdbb_flags |= TDBB_trusted_ddl; + ddlNode->execute(tdbb, dsqlScratch, transaction); +} + + // Delete a security class. bool DdlNode::deleteSecurityClass(thread_db* tdbb, jrd_tra* transaction, const MetaName& secClass) @@ -962,6 +971,12 @@ charSet.c_str(), defaultCollation.c_str()); } +bool AlterCharSetNode::checkPermission(thread_db* tdbb, jrd_tra* transaction) +{ + SCL_check_charset(tdbb, charSet, SCL_alter); + return true; +} + void AlterCharSetNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, jrd_tra* transaction) { @@ -1030,6 +1045,13 @@ objType, objName.c_str(), this->text.c_str()); } +bool CommentOnNode::checkPermission(thread_db* tdbb, jrd_tra* transaction) +{ + //DDL_TODO + // Probably requires migration code from execute with caching some query results for reuse in execute later. + return false; +} + // select rdb$relation_name from rdb$relation_fields where rdb$field_name = 'RDB$DESCRIPTION'; // gives the list of objects that accept descriptions. At FB2 time, the only // subobjects with descriptions are relation's fields and procedure's parameters. @@ -1357,6 +1379,17 @@ return DdlNode::dsqlPass(dsqlScratch); } +bool CreateAlterFunctionNode::checkPermission(thread_db* tdbb, jrd_tra* transaction) +{ + dsc dscName; + dscName.makeText(name.length(), CS_METADATA, (UCHAR*)name.c_str()); + if (alter) + SCL_check_function(tdbb, &dscName, SCL_alter); + else + SCL_check_create_access(tdbb, SCL_object_function); + return true; +} + void CreateAlterFunctionNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, jrd_tra* transaction) { @@ -1975,6 +2008,14 @@ name.c_str(), clauses.name.c_str(), clauses.udfModule.c_str()); } +bool AlterExternalFunctionNode::checkPermission(thread_db* tdbb, jrd_tra* transaction) +{ + dsc dscName; + dscName.makeText(name.length(), CS_METADATA, (UCHAR*)name.c_str()); + SCL_check_function(tdbb, &dscName, SCL_alter); + return true; +} + // Allow changing the entry point and/or the module name of a UDF. void AlterExternalFunctionNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, jrd_tra* transaction) @@ -2092,6 +2133,14 @@ return DdlNode::dsqlPass(dsqlScratch); } +bool DropFunctionNode::checkPermission(thread_db* tdbb, jrd_tra* transaction) +{ + dsc dscName; + dscName.makeText(name.length(), CS_METADATA, (UCHAR*)name.c_str()); + SCL_check_function(tdbb, &dscName, SCL_drop); + return true; +} + void DropFunctionNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, jrd_tra* transaction) { @@ -2277,6 +2326,17 @@ return DdlNode::dsqlPass(dsqlScratch); } +bool CreateAlterProcedureNode::checkPermission(thread_db* tdbb, jrd_tra* transaction) +{ + dsc dscName; + dscName.makeText(name.length(), CS_METADATA, (UCHAR*)name.c_str()); + if (alter) + SCL_check_procedure(tdbb, &dscName, SCL_alter); + else + SCL_check_create_access(tdbb, SCL_object_procedure); + return true; +} + void CreateAlterProcedureNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, jrd_tra* transaction) { @@ -2820,6 +2880,14 @@ return DdlNode::dsqlPass(dsqlScratch); } +bool DropProcedureNode::checkPermission(thread_db* tdbb, jrd_tra* transaction) +{ + dsc dscName; + dscName.makeText(name.length(), CS_METADATA, (UCHAR*)name.c_str()); + SCL_check_procedure(tdbb, &dscName, SCL_drop); + return true; +} + void DropProcedureNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, jrd_tra* transaction) { @@ -3075,6 +3143,14 @@ return DdlNode::dsqlPass(dsqlScratch); } +bool CreateAlterTriggerNode::checkPermission(thread_db* tdbb, jrd_tra* transaction) +{ + dsc dscName; + dscName.makeText(relationName.length(), CS_METADATA, (UCHAR*)relationName.c_str()); + SCL_check_relation(tdbb, &dscName, SCL_alter); + return true; +} + void CreateAlterTriggerNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, jrd_tra* transaction) { @@ -3082,9 +3158,6 @@ Attachment* const attachment = transaction->getAttachment(); - if (relationName.isEmpty() && !attachment->locksmith()) - status_exception::raise(Arg::Gds(isc_adm_task_denied)); - source.ltrim("\n\r\t "); // run all statements under savepoint control @@ -3248,6 +3321,32 @@ return DdlNode::dsqlPass(dsqlScratch); } +bool DropTriggerNode::checkPermission(thread_db* tdbb, jrd_tra* transaction) +{ + dsc dscName; + MetaName relationName; + + AutoCacheRequest request(tdbb, drq_l_trigger_relname, DYN_REQUESTS); + + FOR (REQUEST_HANDLE request TRANSACTION_HANDLE transaction) + X IN RDB$TRIGGERS + WITH X.RDB$TRIGGER_NAME EQ name.c_str() + { + relationName = X.RDB$RELATION_NAME; + } + END_FOR + + if (relationName.isEmpty()) + { + // msg 48: "Index not found" + status_exception::raise(Arg::PrivateDyn(48)); + } + + dscName.makeText(relationName.length(), CS_METADATA, (UCHAR*)relationName.c_str()); + SCL_check_relation(tdbb, &dscName, SCL_alter); + return true; +} + void DropTriggerNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, jrd_tra* transaction) { @@ -3371,6 +3470,12 @@ attributesOn, attributesOff); } +bool CreateCollationNode::checkPermission(thread_db* tdbb, jrd_tra* transaction) +{ + SCL_check_create_access(tdbb, SCL_object_collation); + return true; +} + void CreateCollationNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, jrd_tra* transaction) { @@ -3583,6 +3688,12 @@ name.c_str()); } +bool DropCollationNode::checkPermission(thread_db* tdbb, jrd_tra* transaction) +{ + SCL_check_collation(tdbb, name, SCL_drop); + return true; +} + void DropCollationNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, jrd_tra* transaction) { @@ -3732,6 +3843,12 @@ " " + nameTypeStr + "\n"; } +bool CreateDomainNode::checkPermission(thread_db* tdbb, jrd_tra* transaction) +{ + SCL_check_create_access(tdbb, SCL_object_domain); + return true; +} + void CreateDomainNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, jrd_tra* transaction) { @@ -4250,6 +4367,12 @@ " %s\n", name.c_str()); } +bool AlterDomainNode::checkPermission(thread_db* tdbb, jrd_tra* transaction) +{ + SCL_check_domain(tdbb, name, SCL_alter); + return true; +} + void AlterDomainNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, jrd_tra* transaction) { @@ -4266,6 +4389,7 @@ WITH FLD.RDB$FIELD_NAME EQ name.c_str() { found = true; + executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_BEFORE, DDL_TRIGGER_ALTER_DOMAIN, name); @@ -4565,6 +4689,12 @@ name.c_str()); } +bool DropDomainNode::checkPermission(thread_db* tdbb, jrd_tra* transaction) +{ + SCL_check_domain(tdbb, name, SCL_drop); + return true; +} + void DropDomainNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, jrd_tra* transaction) { @@ -4685,6 +4815,15 @@ name.c_str(), create, alter, message.c_str()); } +bool CreateAlterExceptionNode::checkPermission(thread_db* tdbb, jrd_tra* transaction) +{ + if (alter) + SCL_check_exception(tdbb, name, SCL_alter); + else + SCL_check_create_access(tdbb, SCL_object_exception); + return true; +} + void CreateAlterExceptionNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, jrd_tra* transaction) { @@ -4720,7 +4859,6 @@ { Attachment* const attachment = transaction->getAttachment(); const string& userName = attachment->att_user->usr_user_name; - executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_BEFORE, DDL_TRIGGER_CREATE_EXCEPTION, name); @@ -4811,6 +4949,12 @@ name.c_str()); } +bool DropExceptionNode::checkPermission(thread_db* tdbb, jrd_tra* transaction) +{ + SCL_check_exception(tdbb, name, SCL_drop); + return true; +} + void DropExceptionNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, jrd_tra* transaction) { @@ -4869,6 +5013,15 @@ name.c_str()); } +bool CreateAlterSequenceNode::checkPermission(thread_db* tdbb, jrd_tra* transaction) +{ + if (alter) + SCL_check_generator(tdbb, name, SCL_alter); + else + SCL_check_create_access(tdbb, SCL_object_generator); + return true; +} + void CreateAlterSequenceNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, jrd_tra* transaction) { @@ -5116,6 +5269,12 @@ name.c_str()); } +bool DropSequenceNode::checkPermission(thread_db* tdbb, jrd_tra* transaction) +{ + SCL_check_generator(tdbb, name, SCL_drop); + return true; +} + void DropSequenceNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, jrd_tra* transaction) { // run all statements under savepoint control @@ -6552,6 +6711,12 @@ name.c_str()); } +bool CreateRelationNode::checkPermission(thread_db* tdbb, jrd_tra* transaction) +{ + SCL_check_create_access(tdbb, SCL_object_table); + return true; +} + void CreateRelationNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, jrd_tra* transaction) { @@ -6676,11 +6841,30 @@ name.c_str()); } +bool AlterRelationNode::checkPermission(thread_db* tdbb, jrd_tra* transaction) +{ + dsc dscName; + dscName.makeText(name.length(), CS_METADATA, (UCHAR*)name.c_str()); + SCL_check_relation(tdbb, &dscName, SCL_alter); + return true; +} + void AlterRelationNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, jrd_tra* transaction) { saveRelation(tdbb, dsqlScratch, name, false, false); + dsql_rel* relation; + relation = METD_get_relation(dsqlScratch->getTransaction(), dsqlScratch, name); + + if (!relation || (relation && (relation->rel_flags & REL_view))) + { + status_exception::raise( + Arg::Gds(isc_sqlerr) << Arg::Num(-607) << + Arg::Gds(isc_dsql_command_err) << + Arg::Gds(isc_dsql_table_not_found) << name); + } + if (!dsqlScratch->relation) { //// TODO: <Missing arg #1 - possibly status vector overflow> @@ -7353,6 +7537,17 @@ name.c_str()); } +bool DropRelationNode::checkPermission(thread_db* tdbb, jrd_tra* transaction) +{ + dsc dscName; + dscName.makeText(name.length(), CS_METADATA, (UCHAR*)name.c_str()); + if (view) + SCL_check_view(tdbb, &dscName, SCL_drop); + else + SCL_check_relation(tdbb, &dscName, SCL_drop); + return true; +} + void DropRelationNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, jrd_tra* transaction) { @@ -7587,6 +7782,17 @@ return DdlNode::dsqlPass(dsqlScratch); } +bool CreateAlterViewNode::checkPermission(thread_db* tdbb, jrd_tra* transaction) +{ + dsc dscName; + dscName.makeText(name.length(), CS_METADATA, (UCHAR*)name.c_str()); + if (alter) + SCL_check_view(tdbb, &dscName, SCL_alter); + else + SCL_check_create_access(tdbb, SCL_object_view); + return true; +} + void CreateAlterViewNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, jrd_tra* transaction) { @@ -7642,7 +7848,6 @@ REL.RDB$VIEW_BLR NOT MISSING { found = true; - MODIFY REL attachment->storeMetaDataBlob(tdbb, transaction, &REL.RDB$VIEW_SOURCE, source); attachment->storeBinaryBlob(tdbb, transaction, &REL.RDB$VIEW_BLR, @@ -8709,6 +8914,15 @@ name.c_str()); } +bool CreateIndexNode::checkPermission(thread_db* tdbb, jrd_tra* transaction) +{ + dsc dscName; + const MetaName &relationName = relation->dsqlName; + dscName.makeText(relationName.length(), CS_METADATA, (UCHAR*)relationName.c_str()); + SCL_check_relation(tdbb, &dscName, SCL_alter); + return true; +} + // Define an index. void CreateIndexNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, jrd_tra* transaction) { @@ -8768,6 +8982,32 @@ name.c_str(), active); } +bool AlterIndexNode::checkPermission(thread_db* tdbb, jrd_tra* transaction) +{ + dsc dscName; + MetaName relationName; + + AutoCacheRequest request(tdbb, drq_l_index_relname, DYN_REQUESTS); + + FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction) + IDX IN RDB$INDICES + WITH IDX.RDB$INDEX_NAME EQ name.c_str() + { + relationName = IDX.RDB$RELATION_NAME; + } + END_FOR + + if (relationName.isEmpty()) + { + // msg 48: "Index not found" + status_exception::raise(Arg::PrivateDyn(48)); + } + + dscName.makeText(relationName.length(), CS_METADATA, (UCHAR*)relationName.c_str()); + SCL_check_relation(tdbb, &dscName, SCL_alter); + return true; +} + void AlterIndexNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, jrd_tra* transaction) { // run all statements under savepoint control @@ -8814,6 +9054,32 @@ name.c_str()); } +bool SetStatisticsNode::checkPermission(thread_db* tdbb, jrd_tra* transaction) +{ + dsc dscName; + MetaName relationName; + + AutoCacheRequest request(tdbb, drq_l_index_relname, DYN_REQUESTS); + + FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction) + IDX IN RDB$INDICES + WITH IDX.RDB$INDEX_NAME EQ name.c_str() + { + relationName = IDX.RDB$RELATION_NAME; + } + END_FOR + + if (relationName.isEmpty()) + { + // msg 48: "Index not found" + status_exception::raise(Arg::PrivateDyn(48)); + } + + dscName.makeText(relationName.length(), CS_METADATA, (UCHAR*)relationName.c_str()); + SCL_check_relation(tdbb, &dscName, SCL_alter); + return true; +} + void SetStatisticsNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, jrd_tra* transaction) { // run all statements under savepoint control @@ -8879,6 +9145,32 @@ name.c_str()); } +bool DropIndexNode::checkPermission(thread_db* tdbb, jrd_tra* transaction) +{ + dsc dscName; + MetaName relationName; + + AutoCacheRequest request(tdbb, drq_l_index_relname, DYN_REQUESTS); + + FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction) + IDX IN RDB$INDICES + WITH IDX.RDB$INDEX_NAME EQ name.c_str() + { + relationName = IDX.RDB$RELATION_NAME; + } + END_FOR + + if (relationName.isEmpty()) + { + // msg 48: "Index not found" + status_exception::raise(Arg::PrivateDyn(48)); + } + + dscName.makeText(relationName.length(), CS_METADATA, (UCHAR*)relationName.c_str()); + SCL_check_relation(tdbb, &dscName, SCL_alter); + return true; +} + void DropIndexNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, jrd_tra* transaction) { // run all statements under savepoint control @@ -8929,6 +9221,12 @@ name.c_str()); } +bool CreateFilterNode::checkPermission(thread_db* tdbb, jrd_tra* transaction) +{ + SCL_check_create_access(tdbb, SCL_object_filter); + return true; +} + // Define a blob filter. void CreateFilterNode::execute(thread_db* tdbb, DsqlCompilerScratch* /*dsqlScratch*/, jrd_tra* transaction) { @@ -8994,6 +9292,12 @@ name.c_str()); } +bool DropFilterNode::checkPermission(thread_db* tdbb, jrd_tra* transaction) +{ + SCL_check_filter(tdbb, name, SCL_drop); + return true; +} + void DropFilterNode::execute(thread_db* tdbb, DsqlCompilerScratch* /*dsqlScratch*/, jrd_tra* transaction) { // run all statements under savepoint control @@ -9032,11 +9336,14 @@ number); } +bool CreateShadowNode::checkPermission(thread_db* tdbb, jrd_tra* transaction) +{ + SCL_check_database(tdbb, SCL_alter); + return true; +} + void CreateShadowNode::execute(thread_db* tdbb, DsqlCompilerScratch* /*dsqlScratch*/, jrd_tra* transaction) { - if (!tdbb->getAttachment()->locksmith()) - status_exception::raise(Arg::Gds(isc_adm_task_denied)); - // Should be caught by the parser. if (number == 0) { @@ -9097,11 +9404,14 @@ number); } +bool DropShadowNode::checkPermission(thread_db* tdbb, jrd_tra* transaction) +{ + SCL_check_database(tdbb, SCL_alter); + return true; +} + void DropShadowNode::execute(thread_db* tdbb, DsqlCompilerScratch* /*dsqlScratch*/, jrd_tra* transaction) { - if (!tdbb->getAttachment()->locksmith()) - status_exception::raise(Arg::Gds(isc_adm_task_denied)); - // run all statements under savepoint control AutoSavePoint savePoint(tdbb, transaction); @@ -9132,6 +9442,12 @@ name.c_str()); } +bool CreateRoleNode::checkPermission(thread_db* tdbb, jrd_tra* transaction) +{ + SCL_check_create_access(tdbb, SCL_object_role); + return true; +} + void CreateRoleNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, jrd_tra* transaction) { MetaName ownerName(tdbb->getAttachment()->att_user->usr_user_name); @@ -9269,6 +9585,12 @@ ddl += '"'; } +bool MappingNode::checkPermission(thread_db* tdbb, jrd_tra* transaction) +{ + //DDL_TODO + return false; +} + // It's purpose is to add/drop mapping from any security name to DB security object. void MappingNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, jrd_tra* transaction) { @@ -9660,6 +9982,12 @@ name.c_str()); } +bool DropRoleNode::checkPermission(thread_db* tdbb, jrd_tra* transaction) +{ + SCL_check_role(tdbb, name, SCL_drop); + return true; +} + void DropRoleNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, jrd_tra* transaction) { MetaName user(tdbb->getAttachment()->att_user->usr_user_name); @@ -9678,7 +10006,7 @@ executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_BEFORE, DDL_TRIGGER_DROP_ROLE, name); - const MetaName roleOwner(ROL.RDB$OWNER_NAME); + if (ROL.RDB$SYSTEM_FLAG != 0) { @@ -9686,29 +10014,22 @@ status_exception::raise(Arg::PrivateDyn(284) << name); } - if (tdbb->getAttachment()->locksmith() || roleOwner == user) - { - AutoCacheRequest request2(tdbb, drq_del_role_1, DYN_REQUESTS); + + AutoCacheRequest request2(tdbb, drq_del_role_1, DYN_REQUESTS); - // The first OR clause finds all members of the role. - // The 2nd OR clause finds all privileges granted to the role - FOR(REQUEST_HANDLE request2 TRANSACTION_HANDLE transaction) - PRIV IN RDB$USER_PRIVILEGES - WITH (PRIV.RDB$RELATION_NAME EQ name.c_str() AND PRIV.RDB$OBJECT_TYPE = obj_sql_role) OR - (PRIV.RDB$USER EQ name.c_str() AND PRIV.RDB$USER_TYPE = obj_sql_role) - { - ERASE PRIV; - } - END_FOR - - ERASE ROL; - } - else + // The first OR clause finds all members of the role. + // The 2nd OR clause finds all privileges granted to the role + FOR(REQUEST_HANDLE request2 TRANSACTION_HANDLE transaction) + PRIV IN RDB$USER_PRIVILEGES + WITH (PRIV.RDB$RELATION_NAME EQ name.c_str() AND PRIV.RDB$OBJECT_TYPE = obj_sql_role) OR + (PRIV.RDB$USER EQ name.c_str() AND PRIV.RDB$USER_TYPE = obj_sql_role) { - // msg 191: "only owner of SQL role or USR_locksmith could drop SQL role" - status_exception::raise(Arg::PrivateDyn(191)); + ERASE PRIV; } + END_FOR + ERASE ROL; + found = true; } END_FOR @@ -9759,6 +10080,13 @@ } +bool CreateAlterUserNode::checkPermission(thread_db* tdbb, jrd_tra* transaction) +{ + //DDL_TODO + return false; +} + + void CreateAlterUserNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, jrd_tra* transaction) { if (mode != USER_ADD && !password && !firstName && !middleName && !lastName && @@ -9872,6 +10200,12 @@ name.c_str()); } +bool DropUserNode::checkPermission(thread_db* tdbb, jrd_tra* transaction) +{ + //DDL_TODO + return false; +} + void DropUserNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, jrd_tra* transaction) { // run all statements under savepoint control @@ -9912,6 +10246,12 @@ isGrant); } +bool GrantRevokeNode::checkPermission(thread_db* tdbb, jrd_tra* transaction) +{ + // GRANT OPTION will be checked in grantRevoke method + return false; +} + void GrantRevokeNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, jrd_tra* transaction) { // run all statements under savepoint control @@ -10033,6 +10373,26 @@ break; } + if (options == 1) { // with grant option + switch (userType) { + case obj_procedure: { + ERRD_post(Arg::Gds(isc_dsql_cant_grant_option) << Arg::Str("procedures")); + break; + } + case obj_trigger: { + ERRD_post(Arg::Gds(isc_dsql_cant_grant_option) << Arg::Str("triggers")); + break; + } + case obj_view: { + ERRD_post(Arg::Gds(isc_dsql_cant_grant_option) << Arg::Str("views")); + break; + } + default: { + break; + } + } + } + MetaName grantorRevoker(grantor ? *grantor : tdbb->getAttachment()->att_user->usr_user_name); @@ -10171,6 +10531,10 @@ tdbb->getAttachment()->att_user->usr_user_name.c_str(), priv, objName, field, true); } + else if (objType >= obj_database) { + checkGrantorCanGrantDdl(tdbb, transaction, + tdbb->getAttachment()->att_user->usr_user_name.c_str(), priv, objName); + } } storePrivilege(tdbb, transaction, objName, user, field, pr, userType, objType, @@ -10506,6 +10870,35 @@ } } +// Check if the grantor has grant option on DDL privilege +void GrantRevokeNode::checkGrantorCanGrantDdl(thread_db* tdbb, jrd_tra* transaction, + const Firebird::MetaName& grantor, const char* privilege, const Firebird::MetaName& objName) +{ + if (tdbb->getAttachment()->locksmith()) + return; + + AutoCacheRequest request(tdbb, drq_l_grant_option, DYN_REQUESTS); + bool grantable = false; + + FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction) + PRV IN RDB$USER_PRIVILEGES WITH + PRV.RDB$USER = UPPERCASE(grantor.c_str()) AND + PRV.RDB$USER_TYPE = obj_user AND + PRV.RDB$RELATION_NAME EQ objName.c_str() AND + PRV.RDB$OBJECT_TYPE >= obj_database AND + PRV.RDB$PRIVILEGE EQ privilege + { + grantable = PRV.RDB$GRANT_OPTION == 1; + } + END_FOR + + if (!grantable) + { + // no .. privilege with grant option on DDL .. + status_exception::raise(Arg::PrivateDyn(174) << privilege << objName.c_str()); + } +} + void GrantRevokeNode::storePrivilege(thread_db* tdbb, jrd_tra* transaction, const MetaName& object, const MetaName& user, const MetaName& field, const TEXT* privilege, SSHORT userType, SSHORT objType, int option, const MetaName& grantor) @@ -10582,6 +10975,12 @@ "AlterDatabaseNode\n"); } +bool AlterDatabaseNode::checkPermission(thread_db* tdbb, jrd_tra* transaction) +{ + SCL_check_database(tdbb, SCL_alter); + return true; +} + void AlterDatabaseNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, jrd_tra* transaction) { Modified: firebird/trunk/src/dsql/DdlNodes.h =================================================================== --- firebird/trunk/src/dsql/DdlNodes.h 2014-07-08 00:52:54 UTC (rev 59839) +++ firebird/trunk/src/dsql/DdlNodes.h 2014-07-08 07:35:27 UTC (rev 59840) @@ -153,6 +153,11 @@ text.printf("RecreateNode\n"); } + virtual bool checkPermission(thread_db* tdbb, jrd_tra* transaction) + { + return dropNode.checkPermission(tdbb, transaction) && createNode->checkPermission(tdbb, transaction); + } + virtual void execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, jrd_tra* transaction) { // run all statements under savepoint control @@ -196,6 +201,7 @@ public: virtual void print(Firebird::string& text) const; + virtual bool checkPermission(thread_db* tdbb, jrd_tra* transaction); virtual void execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, jrd_tra* transaction); protected: @@ -226,6 +232,7 @@ public: virtual void print(Firebird::string& text) const; + virtual bool checkPermission(thread_db* tdbb, jrd_tra* transaction); virtual void execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, jrd_tra* transaction); protected: @@ -275,6 +282,7 @@ public: virtual void print(Firebird::string& text) const; virtual DdlNode* dsqlPass(DsqlCompilerScratch* dsqlScratch); + virtual bool checkPermission(thread_db* tdbb, jrd_tra* transaction); virtual void execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, jrd_tra* transaction); protected: @@ -334,6 +342,7 @@ public: virtual void print(Firebird::string& text) const; + virtual bool checkPermission(thread_db* tdbb, jrd_tra* transaction); virtual void execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, jrd_tra* transaction); protected: @@ -366,6 +375,7 @@ public: virtual void print(Firebird::string& text) const; virtual DdlNode* dsqlPass(DsqlCompilerScratch* dsqlScratch); + virtual bool checkPermission(thread_db* tdbb, jrd_tra* transaction); virtual void execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, jrd_tra* transaction); protected: @@ -410,6 +420,7 @@ public: virtual void print(Firebird::string& text) const; virtual DdlNode* dsqlPass(DsqlCompilerScratch* dsqlScratch); + virtual bool checkPermission(thread_db* tdbb, jrd_tra* transaction); virtual void execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, jrd_tra* transaction); protected: @@ -467,6 +478,7 @@ public: virtual void print(Firebird::string& text) const; virtual DdlNode* dsqlPass(DsqlCompilerScratch* dsqlScratch); + virtual bool checkPermission(thread_db* tdbb, jrd_tra* transaction); virtual void execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, jrd_tra* transaction); protected: @@ -551,6 +563,7 @@ public: virtual void print(Firebird::string& text) const; virtual DdlNode* dsqlPass(DsqlCompilerScratch* dsqlScratch); + virtual bool checkPermission(thread_db* tdbb, jrd_tra* transaction); virtual void execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, jrd_tra* transaction); protected: @@ -624,6 +637,7 @@ public: virtual void print(Firebird::string& text) const; virtual DdlNode* dsqlPass(DsqlCompilerScratch* dsqlScratch); + virtual bool checkPermission(thread_db* tdbb, jrd_tra* transaction); virtual void execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, jrd_tra* transaction); protected: @@ -663,6 +677,7 @@ public: virtual void print(Firebird::string& text) const; virtual DdlNode* dsqlPass(DsqlCompilerScratch* dsqlScratch); + virtual bool checkPermission(thread_db* tdbb, jrd_tra* transaction); virtual void execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, jrd_tra* transaction); void setAttribute(USHORT attribute) @@ -721,6 +736,7 @@ public: virtual void print(Firebird::string& text) const; + virtual bool checkPermission(thread_db* tdbb, jrd_tra* transaction); virtual void execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, jrd_tra* transaction); protected: @@ -747,6 +763,7 @@ public: virtual void print(Firebird::string& text) const; + virtual bool checkPermission(thread_db* tdbb, jrd_tra* transaction); virtual void execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, jrd_tra* transaction); protected: @@ -785,6 +802,7 @@ const Firebird::MetaName& newFieldName); virtual void print(Firebird::string& text) const; + virtual bool checkPermission(thread_db* tdbb, jrd_tra* transaction); virtual void execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, jrd_tra* transaction); protected: @@ -822,6 +840,7 @@ public: virtual void print(Firebird::string& text) const; + virtual bool checkPermission(thread_db* tdbb, jrd_tra* transaction); virtual void execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, jrd_tra* transaction); protected: @@ -853,6 +872,7 @@ public: virtual void print(Firebird::string& text) const; + virtual bool checkPermission(thread_db* tdbb, jrd_tra* transaction); virtual void execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, jrd_tra* transaction); protected: @@ -889,6 +909,7 @@ public: virtual void print(Firebird::string& text) const; + virtual bool checkPermission(thread_db* tdbb, jrd_tra* transaction); virtual void execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, jrd_tra* transaction); protected: @@ -940,6 +961,7 @@ public: virtual void print(Firebird::string& text) const; + virtual bool checkPermission(thread_db* tdbb, jrd_tra* transaction); virtual void execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, jrd_tra* transaction); virtual DdlNode* dsqlPass(DsqlCompilerScratch* dsqlScratch) @@ -982,6 +1004,7 @@ public: virtual void print(Firebird::string& text) const; + virtual bool checkPermission(thread_db* tdbb, jrd_tra* transaction); virtual void execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, jrd_tra* transaction); protected: @@ -1335,6 +1358,7 @@ public: virtual void print(Firebird::string& text) const; + virtual bool checkPermission(thread_db* tdbb, jrd_tra* transaction); virtual void execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, jrd_tra* transaction); protected: @@ -1362,6 +1386,7 @@ public: virtual void print(Firebird::string& text) const; + virtual bool checkPermission(thread_db* tdbb, jrd_tra* transaction); virtual void execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, jrd_tra* transaction); protected: @@ -1392,6 +1417,7 @@ public: virtual void print(Firebird::string& text) const; + virtual bool checkPermission(thread_db* tdbb, jrd_tra* transaction); virtual void execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, jrd_tra* transaction); protected: @@ -1429,6 +1455,7 @@ public: virtual void print(Firebird::string& text) const; virtual DdlNode* dsqlPass(DsqlCompilerScratch* dsqlScratch); + virtual bool checkPermission(thread_db* tdbb, jrd_tra* transaction); virtual void execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, jrd_tra* transaction); protected: @@ -1510,6 +1537,7 @@ public: virtual void print(Firebird::string& text) const; + virtual bool checkPermission(thread_db* tdbb, jrd_tra* transaction); virtual void execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, jrd_tra* transaction); protected: @@ -1540,6 +1568,7 @@ public: virtual void print(Firebird::string& text) const; + virtual bool checkPermission(thread_db* tdbb, jrd_tra* transaction); virtual void execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, jrd_tra* transaction); protected: @@ -1565,6 +1594,7 @@ public: virtual void print(Firebird::string& text) const; + virtual bool checkPermission(thread_db* tdbb, jrd_tra* transaction); virtual void execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, jrd_tra* transaction); protected: @@ -1593,6 +1623,7 @@ public: virtual void print(Firebird::string& text) const; + virtual bool checkPermission(thread_db* tdbb, jrd_tra* transaction); virtual void execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, jrd_tra* transaction); protected: @@ -1640,6 +1671,7 @@ public: virtual void print(Firebird::string& text) const; + virtual bool checkPermission(thread_db* tdbb, jrd_tra* transaction); virtual void execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, jrd_tra* transaction); protected: @@ -1668,6 +1700,7 @@ public: virtual void print(Firebird::string& text) const; + virtual bool checkPermission(thread_db* tdbb, jrd_tra* transaction); virtual void execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, jrd_tra* transaction); protected: @@ -1695,6 +1728,7 @@ public: virtual void print(Firebird::string& text) const; + virtual bool checkPermission(thread_db* tdbb, jrd_tra* transaction); virtual void execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, jrd_tra* transaction); protected: @@ -1723,6 +1757,7 @@ public: virtual void print(Firebird::string& text) const; + virtual bool checkPermission(thread_db* tdbb, jrd_tra* transaction); virtual void execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, jrd_tra* transaction); protected: @@ -1747,6 +1782,7 @@ public: virtual void print(Firebird::string& text) const; + virtual bool checkPermission(thread_db* tdbb, jrd_tra* transaction); virtual void execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, jrd_tra* transaction); protected: @@ -1787,6 +1823,7 @@ public: virtual void print(Firebird::string& text) const; + virtual bool checkPermission(thread_db* tdbb, jrd_tra* transaction); virtual void execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, jrd_tra* transaction); protected: @@ -1825,6 +1862,7 @@ public: virtual void print(Firebird::string& text) const; + virtual bool checkPermission(thread_db* tdbb, jrd_tra* transaction); virtual void execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, jrd_tra* transaction); protected: @@ -1857,6 +1895,7 @@ public: virtual void print(Firebird::string& text) const; + virtual bool checkPermission(thread_db* tdbb, jrd_tra* transaction); virtual void execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, jrd_tra* transaction); protected: @@ -1915,6 +1954,7 @@ public: virtual void print(Firebird::string& text) const; + virtual bool checkPermission(thread_db* tdbb, jrd_tra* transaction); virtual void execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, jrd_tra* transaction); protected: @@ -1942,12 +1982,14 @@ object(NULL), users(p), grantAdminOption(false), - grantor(NULL) + grantor(NULL), + isDdl(false) { } public: virtual void print(Firebird::string& text) const; + virtual bool checkPermission(thread_db* tdbb, jrd_tra* transaction); virtual void execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, jrd_tra* transaction); protected: @@ -1966,6 +2008,8 @@ const Firebird::MetaName& fieldName, bool topLevel); static void checkGrantorCanGrantRole(thread_db* tdbb, jrd_tra* transaction, const Firebird::MetaName& grantor, const Firebird::MetaName& roleName); + static void checkGrantorCanGrantDdl(thread_db* tdbb, jrd_tra* transaction, + const Firebird::MetaName& grantor, const char* privilege, const Firebird::MetaName& objName); static void storePrivilege(thread_db* tdbb, jrd_tra* transaction, const Firebird::MetaName& object, const Firebird::MetaName& user, const Firebird::MetaName& field, const TEXT* privilege, SSHORT userType, @@ -1987,6 +2031,10 @@ case 'G': return "Usage"; case 'M': return "Role"; case 'R': return "Reference"; + //ddl + case 'C': return "Create"; + case 'L': return "Alter"; + case 'O': return "DROP"; } return "<Unknown>"; @@ -2000,6 +2048,8 @@ Firebird::Array<GranteeClause> users; bool grantAdminOption; NestConst<Firebird::MetaName> grantor; + // ddl rights + bool isDdl; }; @@ -2038,6 +2088,7 @@ } virtual void print(Firebird::string& text) const; + virtual bool checkPermission(thread_db* tdbb, jrd_tra* transaction); virtual void execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, jrd_tra* transaction); protected: Modified: firebird/trunk/src/dsql/Nodes.h =================================================================== --- firebird/trunk/src/dsql/Nodes.h 2014-07-08 00:52:54 UTC (rev 59839) +++ firebird/trunk/src/dsql/Nodes.h 2014-07-08 07:35:27 UTC (rev 59840) @@ -152,6 +152,23 @@ }; +class DdlNode; + +class SecureDdlNodeExecute +{ +public: + explicit SecureDdlNodeExecute(thread_db* tdbb, DdlNode* ddlNode, + DsqlCompilerScratch* dsqlScratch, jrd_tra* transaction); + + ~SecureDdlNodeExecute() + { + _tdbb->tdbb_flags &= ~TDBB_trusted_ddl; + } + +private: + thread_db* _tdbb; +}; + class DdlNode : public Node { public: @@ -167,6 +184,11 @@ const Firebird::MetaName& name, int type, const char* privileges); public: + // Check permission on DDL operation. Return true if everything is OK. + // Raise an exception for bad permission. + // If returns false permissions will be check in old style at vio level as well as while direct RDB$ tables modify. + virtual bool checkPermission(thread_db* tdbb, jrd_tra* transaction) = 0; + // Set the scratch's transaction when executing a node. Fact of accessing the scratch during // execution is a hack. void executeDdl(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, jrd_tra* transaction) @@ -175,7 +197,7 @@ if (dsqlScratch) dsqlScratch->setTransaction(transaction); - execute(tdbb, dsqlScratch, transaction); + SecureDdlNodeExecute(tdbb, this, dsqlScratch, transaction); } virtual DdlNode* dsqlPass(DsqlCompilerScratch* dsqlScratch) Modified: firebird/trunk/src/dsql/PackageNodes.epp =================================================================== --- firebird/trunk/src/dsql/PackageNodes.epp 2014-07-08 00:52:54 UTC (rev 59839) +++ firebird/trunk/src/dsql/PackageNodes.epp 2014-07-08 07:35:27 UTC (rev 59840) @@ -34,6 +34,7 @@ #include "../dsql/pass1_proto.h" #include "../common/StatusArg.h" #include "../jrd/Attachment.h" +#include "../jrd/scl_proto.h" using namespace Firebird; @@ -458,6 +459,18 @@ } +bool CreateAlterPackageNode::checkPermission(thread_db* tdbb, jrd_tra* transaction) +{ + dsc dscName; + dscName.makeText(name.length(), CS_METADATA, (UCHAR*)name.c_str()); + if (alter) + SCL_check_package(tdbb, &dscName, SCL_alter); + else + SCL_check_create_access(tdbb, SCL_object_package); + return true; +} + + void CreateAlterPackageNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, jrd_tra* transaction) { @@ -619,6 +632,15 @@ } +bool DropPackageNode::checkPermission(thread_db* tdbb, jrd_tra* transaction) +{ + dsc dscName; + dscName.makeText(name.length(), CS_METADATA, (UCHAR*)name.c_str()); + SCL_check_package(tdbb, &dscName, SCL_drop); + return true; +} + + void DropPackageNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, jrd_tra* transaction) { @@ -838,6 +860,13 @@ } +bool CreatePackageBodyNode::checkPermission(thread_db* tdbb, jrd_tra* transaction) +{ + SCL_check_create_access(tdbb, SCL_object_package); + return true; +} + + void CreatePackageBodyNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, jrd_tra* transaction) { @@ -1063,6 +1092,15 @@ } +bool DropPackageBodyNode::checkPermission(thread_db* tdbb, jrd_tra* transaction) +{ + dsc dscName; + dscName.makeText(name.length(), CS_METADATA, (UCHAR*)name.c_str()); + SCL_check_package(tdbb, &dscName, SCL_drop); + return true; +} + + void DropPackageBodyNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, jrd_tra* transaction) { Modified: firebird/trunk/src/dsql/PackageNodes.h =================================================================== --- firebird/trunk/src/dsql/PackageNodes.h 2014-07-08 00:52:54 UTC (rev 59839) +++ firebird/trunk/src/dsql/PackageNodes.h 2014-07-08 07:35:27 UTC (rev 59840) @@ -84,6 +84,7 @@ public: virtual DdlNode* dsqlPass(DsqlCompilerScratch* dsqlScratch); virtual void print(Firebird::string& text) const; + virtual bool checkPermission(thread_db* tdbb, jrd_tra* transaction); virtual void execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, jrd_tra* transaction); protected: @@ -126,6 +127,7 @@ public: virtual void print(Firebird::string& text) const; + virtual bool checkPermission(thread_db* tdbb, jrd_tra* transaction); virtual void execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, jrd_tra* transaction); protected: @@ -160,6 +162,7 @@ public: virtual DdlNode* dsqlPass(DsqlCompilerScratch* dsqlScratch); virtual void print(Firebird::string& text) const; + virtual bool checkPermission(thread_db* tdbb, jrd_tra* transaction); virtual void execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, jrd_tra* transaction); protected: @@ -191,6 +194,7 @@ public: virtual void print(Firebird::string& text) const; + virtual bool checkPermission(thread_db* tdbb, jrd_tra* transaction); virtual void execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, jrd_tra* transaction); protected: Modified: firebird/trunk/src/dsql/parse.y =================================================================== --- firebird/trunk/src/dsql/parse.y 2014-07-08 00:52:54 UTC (rev 59839) +++ firebird/trunk/src/dsql/parse.y 2014-07-08 07:35:27 UTC (rev 59840) @@ -838,6 +838,14 @@ $node->grantAdminOption = $7; $node->grantor = $8; } + | ddl_privileges(NOTRIAL(&$node->privileges)) object + TO non_role_grantee_list(NOTRIAL(&$node->users)) grant_option granted_by + { + $node->object = $2; + $node->grantAdminOption = $5; + $node->grantor = $6; + $node->isDdl = true; + } | role_name_list(NOTRIAL(&$node->roles)) TO role_grantee_list(NOTRIAL(&$node->users)) role_admin_option granted_by { @@ -846,6 +854,39 @@ } ; +%type <granteeClause> object +object : TABLE + { $$ = newNode<GranteeClause>(obj_relations, get_object_name(obj_relations)); } + | VIEW + { $$ = newNode<GranteeClause>(obj_views, get_object_name(obj_views)); } + | PROCEDURE + { $$ = newNode<GranteeClause>(obj_procedures, get_object_name(obj_procedures)); } + | FUNCTION + { $$ = newNode<GranteeClause>(obj_functions, get_object_name(obj_functions)); } + | PACKAGE + { $$ = newNode<GranteeClause>(obj_packages, get_object_name(obj_packages)); } + | GENERATOR + { $$ = newNode<GranteeClause>(obj_generators, get_object_name(obj_generators)); } + | SEQUENCE + { $$ = newNode<GranteeClause>(obj_generators, get_object_name(obj_generators)); } + | KW_DOMAIN + { $$ = newNode<GranteeClause>(obj_domains, get_object_name(obj_domains)); } + | EXCEPTION + { $$ = newNode<GranteeClause>(obj_exceptions, get_object_name(obj_exceptions)); } + | ROLE + { $$ = newNode<GranteeClause>(obj_roles, get_object_name(obj_roles)); } + | SHADOW + { $$ = newNode<GranteeClause>(obj_shadows, get_object_name(obj_shadows)); } + | DATABASE + { $$ = newNode<GranteeClause>(obj_database, get_object_name(obj_database)); } + | CHARACTER SET + { $$ = newNode<GranteeClause>(obj_charsets, get_object_name(obj_charsets)); } + | COLLATION + { $$ = newNode<GranteeClause>(obj_collations, get_object_name(obj_collations)); } + | FILTER + { $$ = newNode<GranteeClause>(obj_filters, get_object_name(obj_filters)); } + ; + table_noise : // nothing | TABLE @@ -872,7 +913,6 @@ %type usage_privilege(<privilegeArray>) usage_privilege($privilegeArray) : USAGE { $privilegeArray->add(PrivilegeClause('G', NULL)); } - ; %type privilege(<privilegeArray>) privilege($privilegeArray) @@ -883,6 +923,26 @@ | REFERENCES column_parens_opt { $privilegeArray->add(PrivilegeClause('R', $2)); } ; +%type ddl_privileges(<privilegeArray>) +ddl_privileges($privilegeArray) + : ALL { $privilegeArray->add(PrivilegeClause('C', NULL)); $privilegeArray->add(PrivilegeClause('L', NULL)); $privilegeArray->add(PrivilegeClause('O', NULL)); } + | ALL PRIVILEGES { $privilegeArray->add(PrivilegeClause('C', NULL)); $privilegeArray->add(PrivilegeClause('L', NULL)); $privilegeArray->add(PrivilegeClause('O', NULL)); } + | ddl_privilege_list($privilegeArray) + ; + +%type ddl_privilege_list(<privilegeArray>) +ddl_privilege_list($privilegeArray) + : ddl_privilege($privilegeArray) + | ddl_privilege_list ',' ddl_privilege($privilegeArray) + ; + +%type ddl_privilege(<privilegeArray>) +ddl_privilege($privilegeArray) + : CREATE { $privilegeArray->add(PrivilegeClause('C', NULL)); } + | ALTER ANY { $privilegeArray->add(PrivilegeClause('L', NULL)); } + | DROP ANY { $privilegeArray->add(PrivilegeClause('O', NULL)); } + ; + %type <boolVal> grant_option grant_option : /* nothing */ { $$ = false; } @@ -996,6 +1056,14 @@ $node->grantAdminOption = $1; $node->grantor = $8; } + | rev_grant_option ddl_privileges(NOTRIAL(&$node->privileges)) object + FROM non_role_grantee_list(NOTRIAL(&$node->users)) granted_by + { + $node->object = $3; + $node->grantAdminOption = $1; + $node->grantor = $6; + $node->isDdl = true; + } | rev_admin_option role_name_list(NOTRIAL(&$node->roles)) FROM role_grantee_list(NOTRIAL(&$node->users)) granted_by { Modified: firebird/trunk/src/include/gen/codetext.h =================================================================== --- firebird/trunk/src/include/gen/codetext.h 2014-07-08 00:52:54 UTC (rev 59839) +++ firebird/trunk/src/include/gen/codetext.h 2014-07-08 07:35:27 UTC (rev 59840) @@ -795,6 +795,8 @@ {"set_invalid_role", 335545091}, {"cursor_not_positioned", 335545092}, {"dup_attribute", 335545093}, + {"dyn_no_priv", 335545094}, + {"dsql_cant_grant_option", 335545095}, {"gfix_db_name", 335740929}, {"gfix_invalid_sw", 335740930}, {"gfix_incmp_sw", 335740932}, Modified: firebird/trunk/src/include/gen/iberror.h =================================================================== --- firebird/trunk/src/include/gen/iberror.h 2014-07-08 00:52:54 UTC (rev 59839) +++ firebird/trunk/src/include/gen/iberror.h 2014-07-08 07:35:27 UTC (rev 59840) @@ -829,6 +829,8 @@ const ISC_STATUS isc_set_invalid_role = 335545091L; const ISC_STATUS isc_cursor_not_positioned = 335545092L; const ISC_STATUS isc_dup_attribute = 335545093L; +const ISC_STATUS isc_dyn_no_priv = 335545094L; +const ISC_STATUS isc_dsql_cant_grant_option = 335545095L; const ISC_STATUS isc_gfix_db_name = 335740929L; const ISC_STATUS isc_gfix_invalid_sw = 335740930L; const ISC_STATUS isc_gfix_incmp_sw = 335740932L; @@ -1287,7 +1289,7 @@ 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 = 1231; +const ISC_STATUS isc_err_max = 1233; #else /* c definitions */ @@ -2086,6 +2088,8 @@ #define isc_set_invalid_role 335545091L #define isc_cursor_not_positioned 335545092L #define isc_dup_attribute 335545093L +#define isc_dyn_no_priv 335545094L +#define isc_dsql_cant_grant_option 335545095L #define isc_gfix_db_name 335740929L #define isc_gfix_invalid_sw 335740930L #define isc_gfix_incmp_sw 335740932L @@ -2544,7 +2548,7 @@ #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 1231 +#define isc_err_max 1233 #endif Modified: firebird/trunk/src/include/gen/ids.h =================================================================== --- firebird/trunk/src/include/gen/ids.h 2014-07-08 00:52:54 UTC (rev 59839) +++ firebird/trunk/src/include/gen/ids.h 2014-07-08 07:35:27 UTC (rev 59840) @@ -277,6 +277,7 @@ const USHORT f_flt_input = 4; const USHORT f_flt_output = 5; const USHORT f_flt_sys_flag = 6; + const USHORT f_flt_class = 7; // Relation 17 (RDB$TRIGGER_MESSAGES) @@ -449,6 +450,7 @@ const USHORT f_rol_owner = 1; const USHORT f_rol_desc = 2; const USHORT f_rol_sys_flag = 3; + const USHORT f_rol_class = 4; // Relation 32 (RDB$BACKUP_HISTORY) Modified: firebird/trunk/src/include/gen/msgs.h =================================================================== --- firebird/trunk/src/include/gen/msgs.h 2014-07-08 00:52:54 UTC (rev 59839) +++ firebird/trunk/src/include/gen/msgs.h 2014-07-08 07:35:27 UTC (rev 59840) @@ -798,6 +798,8 @@ {335545091, "Role @1 is invalid or unavailable"}, /* set_invalid_role */ {335545092, "Cursor @1 is not positioned in a valid record"}, /* cursor_not_positioned */ {335545093, "Duplicated user attribute @1"}, /* dup_attribute */ + {335545094, "There is no privilege for this operation"}, /* dyn_no_priv */ + {335545095, "Using GRANT OPTION on @1 not allowed"}, /* dsql_cant_grant_option */ {335740929, "data base file name (@1) already given"}, /* gfix_db_name */ {335740930, "invalid switch @1"}, /* gfix_invalid_sw */ {335740932, "incompatible switch combination"}, /* gfix_incmp_sw */ Modified: firebird/trunk/src/include/gen/sql_code.h =================================================================== --- firebird/trunk/src/include/gen/sql_code.h 2014-07-08 00:52:54 UTC (rev 59839) +++ firebird/trunk/src/include/gen/sql_code.h 2014-07-08 07:35:27 UTC (rev 59840) @@ -794,6 +794,8 @@ {335545091, -901}, /* 771 set_invalid_role */ {335545092, -596}, /* 772 cursor_not_positioned */ {335545093, -901}, /* 773 dup_attribute */ + {335545094, -901}, /* 774 dyn_no_priv */ + {335545095, -901}, /* 775 dsql_cant_grant_option */ {335740929, -901}, /* 1 gfix_db_name */ {335740930, -901}, /* 2 gfix_invalid_sw */ {335740932, -901}, /* 4 gfix_incmp_sw */ Modified: firebird/trunk/src/include/gen/sql_state.h =================================================================== --- firebird/trunk/src/include/gen/sql_state.h 2014-07-08 00:52:54 UTC (rev 59839) +++ firebird/trunk/src/include/gen/sql_state.h 2014-07-08 07:35:27 UTC (rev 59840) @@ -794,6 +794,8 @@ {335545091, "0P000"}, // 771 set_invalid_role {335545092, "HY109"}, // 772 cursor_not_positioned {335545093, "42702"}, // 773 dup_attribute + {335545094, "42000"}, // 774 dyn_no_priv + {335545095, "42000"}, // 775 dsql_cant_grant_option {335740929, "00000"}, // 1 gfix_db_name {335740930, "00000"}, // 2 gfix_invalid_sw {335740932, "00000"}, // 4 gfix_incmp_sw Modified: firebird/trunk/src/jrd/Database.h =================================================================== --- firebird/trunk/src/jrd/Database.h 2014-07-08 00:52:54 UTC (rev 59839) +++ firebird/trunk/src/jrd/Database.h 2014-07-08 07:35:27 UTC (rev 59840) @@ -411,7 +411,6 @@ Firebird::PathName dbb_filename; // filename string Firebird::PathName dbb_database_name; // database ID (file name or alias) - Firebird::MetaName dbb_owner; // database owner Firebird::SyncObject dbb_pools_sync; @@ -494,6 +493,7 @@ dbb_modules(*p), dbb_extManager(*p), dbb_filename(*p), + dbb_owner(*p), dbb_database_name(*p), dbb_pools(*p, 4), dbb_sort_buffers(*p), Modified: firebird/trunk/src/jrd/acl.h =================================================================== --- firebird/trunk/src/jrd/acl.h 2014-07-08 00:52:54 UTC (rev 59839) +++ firebird/trunk/src/jrd/acl.h 2014-07-08 07:35:27 UTC (rev 59840) @@ -50,7 +50,10 @@ const int priv_execute = 11; // EXECUTE (procedure, function, package) // New in FB3 const int priv_usage = 12; // USAGE (domain, exception, sequence, collation) -const int priv_max = 13; +const int priv_create = 13; // Create object +const int priv_alter_any = 14; // Alter any object +const int priv_drop_any = 15; // Drop any object +const int priv_max = 16; // Identification criterias @@ -69,7 +72,8 @@ // New in FB3 const int id_package = 12; // Package name const int id_function = 13; // Function name -const int id_max = 14; +const int id_filter = 14; // Filter name +const int id_max = 15; /* Format of access control list: Modified: firebird/trunk/src/jrd/constants.h =================================================================== --- firebird/trunk/src/jrd/constants.h 2014-07-08 00:52:54 UTC (rev 59839) +++ firebird/trunk/src/jrd/constants.h 2014-07-08 07:35:27 UTC (rev 59840) @@ -132,6 +132,8 @@ const int SQL_SECCLASS_PREFIX_LEN = 4; const char* const SQL_FLD_SECCLASS_PREFIX = "SQL$GRANT"; const int SQL_FLD_SECCLASS_PREFIX_LEN = 9; +const char* const GEN_SECCLASS_PREFIX = "GEN$"; +const int GEN_SECCLASS_PREFIX_LEN = 4; // Automatically created check constraints for unnamed PRIMARY and UNIQUE declarations. const char* const IMPLICIT_INTEGRITY_PREFIX = "INTEG_"; Modified: firebird/trunk/src/jrd/drq.h =================================================================== --- firebird/trunk/src/jrd/drq.h 2014-07-08 00:52:54 UTC (rev 59839) +++ firebird/trunk/src/jrd/drq.h 2014-07-08 07:35:27 UTC (rev 59840) @@ -232,6 +232,9 @@ drq_e_gen_prvs, // erase generator privileges drq_e_gfld_prvs, // erase domain privileges drq_g_nxt_nbakhist_id, // generate next history ID for nbackup + drq_l_index_relname, // lookup relation name for index + drq_l_trigger_relname, // loopup relation name for trigger + drq_l_grant_option, // loopup grant option for privilege drq_MAX }; Modified: firebird/trunk/src/jrd/filters.cpp =================================================================== --- firebird/trunk/src/jrd/filters.cpp 2014-07-08 00:52:54 UTC (rev 59839) +++ firebird/trunk/src/jrd/filters.cpp 2014-07-08 07:35:27 UTC (rev 59840) @@ -94,7 +94,10 @@ "update", "references", "execute", - "usage" + "usage", + "create", + "alter_any", + "drop_any" }; static const TEXT* acl_ids[id_max] = Modified: firebird/trunk/src/jrd/grant.epp =================================================================== --- firebird/trunk/src/jrd/grant.epp 2014-07-08 00:52:54 UTC (rev 59839) +++ firebird/trunk/src/jrd/grant.epp 2014-07-08 07:35:27 UTC (rev 59840) @@ -141,7 +141,11 @@ break; default: - break; + if (id >= obj_database && + id < obj_type_MAX) + { + priv = OWNER_PRIVS; + } } grant_user(acl, owner, obj_user, priv); @@ -472,6 +476,20 @@ } END_FOR } + else if (obj_type == obj_database) + { + s_class = attachment->att_security_class->scl_name; + default_class = ""; + owner = tdbb->getDatabase()->dbb_owner; + view = false; + } + else + { + s_class = get_object_name(obj_type); + default_class = ""; + owner = tdbb->getDatabase()->dbb_owner; + view = false; + } } @@ -882,6 +900,15 @@ case 'G': priv |= SCL_usage; break; + case 'C': + priv |= SCL_create; + break; + case 'L': + priv |= SCL_alter; + break; + case 'O': + priv |= SCL_drop; + break; } return priv; Modified: firebird/trunk/src/jrd/ini.epp =================================================================== --- firebird/trunk/src/jrd/ini.epp 2014-07-08 00:52:54 UTC (rev 59839) +++ firebird/trunk/src/jrd/ini.epp 2014-07-08 07:35:27 UTC (rev 59840) @@ -72,6 +72,7 @@ static void add_index_set(thread_db*); static void add_security_to_sys_obj(thread_db*, const MetaName&, USHORT, const MetaName&, USHORT = 0, const UCHAR* = NULL); +static void add_security_class(thread_db* tdbb, const MetaName& class_name, USHORT acl_length, const UCHAR* acl); static void add_security_to_sys_rel(thread_db*, const MetaName&, const TEXT*, const USHORT, const UCHAR*); static void store_generator(thread_db*, const gen*, AutoRequest&, const MetaName&); @@ -477,6 +478,13 @@ add_security_to_sys_obj(tdbb, ownerName, obj_collation, collation->name, length, buffer); } + for (int ddl_obj = obj_database + 1; ddl_obj < obj_type_MAX; ddl_obj++) + { + add_security_class(tdbb, get_object_name(ddl_obj), length, buffer); + } + + add_security_to_sys_obj(tdbb, ownerName, obj_database, "", length, buffer); + // Add security on system tables const UCHAR REL_OWNER_ACL[] = @@ -1137,6 +1145,17 @@ } END_FOR } + else if (obj_type == obj_database) + { + FOR(REQUEST_HANDLE handle) DB IN RDB$DATABASE + { + MODIFY DB USING + DB.RDB$SECURITY_CLASS.NULL = FALSE; + PAD(security_class.c_str(), DB.RDB$SECURITY_CLASS); + END_MODIFY + } + END_FOR + } handle.reset(); @@ -1155,6 +1174,30 @@ } +// Add security class. +static void add_security_class(thread_db* tdbb, const MetaName& class_name, USHORT acl_length, const UCHAR* acl) +{ + SET_TDBB(tdbb); + Jrd::Attachment* const attachment = tdbb->getAttachment(); + + bid blob_id; + attachment->storeBinaryBlob(td... [truncated message content] |