mirror of
https://github.com/FirebirdSQL/firebird.git
synced 2025-02-02 08:40:39 +01:00
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.
This commit is contained in:
parent
a1d0c2b52a
commit
573e93e5a6
35
doc/sql.extensions/README.ddl_access.txt
Normal file
35
doc/sql.extensions/README.ddl_access.txt
Normal file
@ -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;
|
@ -1598,6 +1598,10 @@ C --
|
||||
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
|
||||
|
@ -806,6 +806,8 @@ const
|
||||
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;
|
||||
|
@ -747,6 +747,15 @@ static void updateRdbFields(const TypeClause* type,
|
||||
|
||||
//----------------------
|
||||
|
||||
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,
|
||||
@ -962,6 +971,12 @@ void AlterCharSetNode::print(string& text) const
|
||||
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 @@ void CommentOnNode::print(string& text) const
|
||||
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 @@ DdlNode* CreateAlterFunctionNode::dsqlPass(DsqlCompilerScratch* dsqlScratch)
|
||||
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 @@ void AlterExternalFunctionNode::print(string& text) const
|
||||
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 @@ DdlNode* DropFunctionNode::dsqlPass(DsqlCompilerScratch* dsqlScratch)
|
||||
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 @@ DdlNode* CreateAlterProcedureNode::dsqlPass(DsqlCompilerScratch* dsqlScratch)
|
||||
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 @@ DdlNode* DropProcedureNode::dsqlPass(DsqlCompilerScratch* dsqlScratch)
|
||||
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 @@ DdlNode* CreateAlterTriggerNode::dsqlPass(DsqlCompilerScratch* dsqlScratch)
|
||||
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 @@ void CreateAlterTriggerNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlS
|
||||
|
||||
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 @@ DdlNode* DropTriggerNode::dsqlPass(DsqlCompilerScratch* dsqlScratch)
|
||||
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 @@ void CreateCollationNode::print(string& text) const
|
||||
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 @@ void DropCollationNode::print(string& text) const
|
||||
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 @@ void CreateDomainNode::print(string& text) const
|
||||
" " + 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 @@ void AlterDomainNode::print(string& text) const
|
||||
" %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 @@ void AlterDomainNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch,
|
||||
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 @@ void DropDomainNode::print(string& text) const
|
||||
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 @@ void CreateAlterExceptionNode::print(string& text) const
|
||||
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 @@ void CreateAlterExceptionNode::executeCreate(thread_db* tdbb, DsqlCompilerScratc
|
||||
{
|
||||
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 @@ void DropExceptionNode::print(string& text) const
|
||||
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 @@ void CreateAlterSequenceNode::print(string& text) const
|
||||
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 @@ void DropSequenceNode::print(string& text) const
|
||||
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 @@ void CreateRelationNode::print(string& text) const
|
||||
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 @@ void AlterRelationNode::print(string& text) const
|
||||
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 @@ void DropRelationNode::print(string& text) const
|
||||
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 @@ DdlNode* CreateAlterViewNode::dsqlPass(DsqlCompilerScratch* dsqlScratch)
|
||||
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 @@ void CreateAlterViewNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScra
|
||||
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 @@ void CreateIndexNode::print(string& text) const
|
||||
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 @@ void AlterIndexNode::print(string& text) const
|
||||
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 @@ void SetStatisticsNode::print(string& text) const
|
||||
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 @@ void DropIndexNode::print(string& text) const
|
||||
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 @@ void CreateFilterNode::print(string& text) const
|
||||
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 @@ void DropFilterNode::print(string& text) const
|
||||
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 @@ void CreateShadowNode::print(string& text) const
|
||||
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 @@ void DropShadowNode::print(string& text) const
|
||||
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 @@ void CreateRoleNode::print(string& text) const
|
||||
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 @@ void MappingNode::addItem(string& ddl, const char* text)
|
||||
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 @@ void DropRoleNode::print(string& text) const
|
||||
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 @@ void DropRoleNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, jr
|
||||
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,28 +10014,21 @@ void DropRoleNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, jr
|
||||
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;
|
||||
}
|
||||
@ -9759,6 +10080,13 @@ static void setCharField(Auth::CharField& field, const string* value)
|
||||
}
|
||||
|
||||
|
||||
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 @@ void DropUserNode::print(string& text) const
|
||||
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 @@ void GrantRevokeNode::print(string& text) const
|
||||
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 @@ void GrantRevokeNode::grantRevoke(thread_db* tdbb, jrd_tra* transaction, const G
|
||||
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 @@ void GrantRevokeNode::grantRevoke(thread_db* tdbb, jrd_tra* transaction, const G
|
||||
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 @@ void GrantRevokeNode::checkGrantorCanGrantRole(thread_db* tdbb, jrd_tra* transac
|
||||
}
|
||||
}
|
||||
|
||||
// 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 @@ void AlterDatabaseNode::print(string& text) const
|
||||
"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)
|
||||
{
|
||||
|
@ -153,6 +153,11 @@ public:
|
||||
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:
|
||||
|
||||
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:
|
||||
|
||||
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:
|
||||
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:
|
||||
|
||||
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:
|
||||
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:
|
||||
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:
|
||||
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:
|
||||
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:
|
||||
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:
|
||||
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:
|
||||
|
||||
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:
|
||||
|
||||
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 @@ public:
|
||||
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:
|
||||
|
||||
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:
|
||||
|
||||
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:
|
||||
|
||||
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:
|
||||
|
||||
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:
|
||||
|
||||
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:
|
||||
|
||||
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:
|
||||
|
||||
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:
|
||||
|
||||
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:
|
||||
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:
|
||||
|
||||
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:
|
||||
|
||||
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:
|
||||
|
||||
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:
|
||||
|
||||
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:
|
||||
|
||||
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:
|
||||
|
||||
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:
|
||||
|
||||
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:
|
||||
|
||||
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:
|
||||
|
||||
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:
|
||||
|
||||
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:
|
||||
|
||||
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:
|
||||
|
||||
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:
|
||||
|
||||
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 @@ public:
|
||||
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 @@ private:
|
||||
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 @@ private:
|
||||
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 @@ public:
|
||||
Firebird::Array<GranteeClause> users;
|
||||
bool grantAdminOption;
|
||||
NestConst<Firebird::MetaName> grantor;
|
||||
// ddl rights
|
||||
bool isDdl;
|
||||
};
|
||||
|
||||
|
||||
@ -2038,6 +2088,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:
|
||||
|
@ -152,6 +152,23 @@ public:
|
||||
};
|
||||
|
||||
|
||||
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 @@ public:
|
||||
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 @@ public:
|
||||
if (dsqlScratch)
|
||||
dsqlScratch->setTransaction(transaction);
|
||||
|
||||
execute(tdbb, dsqlScratch, transaction);
|
||||
SecureDdlNodeExecute(tdbb, this, dsqlScratch, transaction);
|
||||
}
|
||||
|
||||
virtual DdlNode* dsqlPass(DsqlCompilerScratch* dsqlScratch)
|
||||
|
@ -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 @@ DdlNode* CreateAlterPackageNode::dsqlPass(DsqlCompilerScratch* dsqlScratch)
|
||||
}
|
||||
|
||||
|
||||
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 @@ void DropPackageNode::print(string& text) const
|
||||
}
|
||||
|
||||
|
||||
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 @@ DdlNode* CreatePackageBodyNode::dsqlPass(DsqlCompilerScratch* dsqlScratch)
|
||||
}
|
||||
|
||||
|
||||
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 @@ void DropPackageBodyNode::print(string& text) const
|
||||
}
|
||||
|
||||
|
||||
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)
|
||||
{
|
||||
|
@ -84,6 +84,7 @@ public:
|
||||
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:
|
||||
|
||||
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:
|
||||
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:
|
||||
|
||||
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:
|
||||
|
@ -838,6 +838,14 @@ grant0($node)
|
||||
$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 @@ grant0($node)
|
||||
}
|
||||
;
|
||||
|
||||
%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 @@ execute_privilege($privilegeArray)
|
||||
%type usage_privilege(<privilegeArray>)
|
||||
usage_privilege($privilegeArray)
|
||||
: USAGE { $privilegeArray->add(PrivilegeClause('G', NULL)); }
|
||||
;
|
||||
|
||||
%type privilege(<privilegeArray>)
|
||||
privilege($privilegeArray)
|
||||
@ -883,6 +923,26 @@ privilege($privilegeArray)
|
||||
| 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 @@ revoke0($node)
|
||||
$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
|
||||
{
|
||||
|
@ -795,6 +795,8 @@ static const struct {
|
||||
{"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},
|
||||
|
@ -829,6 +829,8 @@ const ISC_STATUS isc_miss_trusted_role = 335545090L;
|
||||
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_user_only = 337182757L;
|
||||
const ISC_STATUS isc_trace_switch_param_miss = 337182758L;
|
||||
const ISC_STATUS isc_trace_param_act_notcompat = 337182759L;
|
||||
const ISC_STATUS isc_trace_mandatory_switch_miss = 337182760L;
|
||||
const ISC_STATUS isc_err_max = 1231;
|
||||
const ISC_STATUS isc_err_max = 1233;
|
||||
|
||||
#else /* c definitions */
|
||||
|
||||
@ -2086,6 +2088,8 @@ const ISC_STATUS isc_err_max = 1231;
|
||||
#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 @@ const ISC_STATUS isc_err_max = 1231;
|
||||
#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
|
||||
|
||||
|
@ -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)
|
||||
|
@ -798,6 +798,8 @@ Data source : @4"}, /* eds_statement */
|
||||
{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 */
|
||||
|
@ -794,6 +794,8 @@ static const struct {
|
||||
{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 */
|
||||
|
@ -794,6 +794,8 @@ static const struct {
|
||||
{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
|
||||
|
@ -411,7 +411,6 @@ public:
|
||||
|
||||
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 @@ private:
|
||||
dbb_modules(*p),
|
||||
dbb_extManager(*p),
|
||||
dbb_filename(*p),
|
||||
dbb_owner(*p),
|
||||
dbb_database_name(*p),
|
||||
dbb_pools(*p, 4),
|
||||
dbb_sort_buffers(*p),
|
||||
|
@ -50,7 +50,10 @@ const int priv_references = 10; // REFERENCES for foreign key
|
||||
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 @@ const int id_sql_role = 11; // SQL role
|
||||
// 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:
|
||||
|
||||
|
@ -132,6 +132,8 @@ const char* const SQL_SECCLASS_PREFIX = "SQL$";
|
||||
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_";
|
||||
|
@ -232,6 +232,9 @@ enum drq_type_t
|
||||
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
|
||||
};
|
||||
|
@ -94,7 +94,10 @@ static const TEXT* acl_privs[priv_max] =
|
||||
"update",
|
||||
"references",
|
||||
"execute",
|
||||
"usage"
|
||||
"usage",
|
||||
"create",
|
||||
"alter_any",
|
||||
"drop_any"
|
||||
};
|
||||
|
||||
static const TEXT* acl_ids[id_max] =
|
||||
|
@ -141,7 +141,11 @@ void GRANT_privileges(thread_db* tdbb, const Firebird::string& name, USHORT id,
|
||||
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 @@ static void get_object_info(thread_db* tdbb,
|
||||
}
|
||||
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 @@ static SecurityClass::flags_t trans_sql_priv(const TEXT* privileges)
|
||||
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;
|
||||
|
@ -72,6 +72,7 @@ const int FB_MAX_ACL_SIZE = 4096;
|
||||
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 @@ void INI_format(const MetaName& owner, const MetaName& charset)
|
||||
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 @@ static void add_security_to_sys_obj(thread_db* tdbb,
|
||||
}
|
||||
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 @@ static void add_security_to_sys_obj(thread_db* tdbb,
|
||||
}
|
||||
|
||||
|
||||
// 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(tdbb, attachment->getSysTransaction(), &blob_id,
|
||||
ByteChunk(acl, acl_length));
|
||||
|
||||
AutoRequest handle;
|
||||
|
||||
STORE(REQUEST_HANDLE handle)
|
||||
CLS IN RDB$SECURITY_CLASSES
|
||||
{
|
||||
PAD(class_name.c_str(), CLS.RDB$SECURITY_CLASS);
|
||||
CLS.RDB$ACL = blob_id;
|
||||
}
|
||||
END_STORE
|
||||
|
||||
handle.reset();
|
||||
}
|
||||
|
||||
|
||||
static void store_generator(thread_db* tdbb, const gen* generator, AutoRequest& handle,
|
||||
const MetaName& owner)
|
||||
{
|
||||
|
@ -70,6 +70,9 @@
|
||||
|
||||
#define COLLATE_NONE 0 // No special collation, use codepoint order
|
||||
|
||||
#define INTL_ASSIGN_DSC(dsc, cs, coll) \
|
||||
{ (dsc)->dsc_sub_type = (SSHORT) ((coll) << 8 | (cs)); }
|
||||
|
||||
#define INTL_GET_TTYPE(dsc) \
|
||||
((dsc)->dsc_sub_type)
|
||||
|
||||
|
@ -369,6 +369,7 @@ const USHORT TDBB_use_db_page_space = 256; // use database (not temporary) page
|
||||
const USHORT TDBB_detaching = 512; // detach is in progress
|
||||
const USHORT TDBB_wait_cancel_disable = 1024; // don't cancel current waiting operation
|
||||
const USHORT TDBB_cache_unwound = 2048; // page cache was unwound
|
||||
const USHORT TDBB_trusted_ddl = 4096; // skip DDL permission checks. set after DDL permission check and clear after DDL execution
|
||||
|
||||
class thread_db : public Firebird::ThreadData
|
||||
{
|
||||
|
@ -1043,7 +1043,7 @@ DeferredWork* MET_change_fields(thread_db* tdbb, jrd_tra* transaction, const dsc
|
||||
{
|
||||
relation_name.makeText(sizeof(X.RDB$RELATION_NAME), CS_METADATA,
|
||||
(UCHAR*) X.RDB$RELATION_NAME);
|
||||
SCL_check_relation(tdbb, &relation_name, SCL_control);
|
||||
SCL_check_relation(tdbb, &relation_name, SCL_alter);
|
||||
dw = DFW_post_work(transaction, dfw_update_format, &relation_name, 0);
|
||||
|
||||
AutoCacheRequest request2(tdbb, irq_m_fields4, IRQ_REQUESTS);
|
||||
|
@ -48,12 +48,62 @@ const int obj_collation = 17;
|
||||
const int obj_package_header = 18;
|
||||
const int obj_package_body = 19;
|
||||
|
||||
const int obj_type_MAX = 20; // keep this last!
|
||||
//objects types for ddl operations
|
||||
const int obj_database = 20;
|
||||
const int obj_relations = 21;
|
||||
const int obj_views = 22;
|
||||
const int obj_procedures = 23;
|
||||
const int obj_functions = 24;
|
||||
const int obj_packages = 25;
|
||||
const int obj_generators = 26;
|
||||
const int obj_domains = 27;
|
||||
const int obj_exceptions = 28;
|
||||
const int obj_roles = 29;
|
||||
const int obj_shadows = 30;
|
||||
const int obj_charsets = 31;
|
||||
const int obj_collations = 32;
|
||||
const int obj_filters = 33;
|
||||
|
||||
const int obj_type_MAX = 34; // keep this last!
|
||||
|
||||
// used in the parser only / no relation with obj_type_MAX
|
||||
const int obj_user_or_role = 20;
|
||||
const int obj_database = 21;
|
||||
const int obj_schema = 22;
|
||||
const int obj_parameter = 23;
|
||||
const int obj_user_or_role = 35;
|
||||
const int obj_schema = 36;
|
||||
const int obj_parameter = 37;
|
||||
|
||||
static char* get_object_name(int object_type)
|
||||
{
|
||||
switch (object_type)
|
||||
{
|
||||
case obj_relations:
|
||||
return "OBJ$TABLES";
|
||||
case obj_views:
|
||||
return "OBJ$VIEWS";
|
||||
case obj_procedures:
|
||||
return "OBJ$PROCEDURES";
|
||||
case obj_functions:
|
||||
return "OBJ$FUNCTIONS";
|
||||
case obj_packages:
|
||||
return "OBJ$PACKAGES";
|
||||
case obj_generators:
|
||||
return "OBJ$GENERATORS";
|
||||
case obj_filters:
|
||||
return "OBJ$FILTERS";
|
||||
case obj_domains:
|
||||
return "OBJ$DOMAINS";
|
||||
case obj_exceptions:
|
||||
return "OBJ$EXCEPTIONS";
|
||||
case obj_roles:
|
||||
return "OBJ$ROLES";
|
||||
case obj_shadows:
|
||||
return "OBJ$SHADOWS";
|
||||
case obj_charsets:
|
||||
return "OBJ$CHARSETS";
|
||||
case obj_collations:
|
||||
return "OBJ$COLLATIONS";
|
||||
default:
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
#endif // JRD_OBJ_H
|
||||
|
@ -276,6 +276,7 @@ RELATION(nam_filters, rel_filters, ODS_8_0, rel_persistent)
|
||||
FIELD(f_flt_input, nam_in_type, fld_sub_type, 1, ODS_8_0)
|
||||
FIELD(f_flt_output, nam_out_type, fld_sub_type, 1, ODS_8_0)
|
||||
FIELD(f_flt_sys_flag, nam_sys_flag, fld_flag, 0, ODS_8_0)
|
||||
FIELD(f_flt_class, nam_class, fld_class, 1, ODS_12_0)
|
||||
END_RELATION
|
||||
|
||||
// Relation 17 (RDB$TRIGGER_MESSAGES)
|
||||
@ -448,6 +449,7 @@ RELATION(nam_roles, rel_roles, ODS_9_0, rel_persistent)
|
||||
FIELD(f_rol_owner, nam_owner, fld_user, 1, ODS_9_0)
|
||||
FIELD(f_rol_desc, nam_description, fld_description, 1, ODS_11_0)
|
||||
FIELD(f_rol_sys_flag, nam_sys_flag, fld_flag, 1, ODS_11_0)
|
||||
FIELD(f_rol_class, nam_class, fld_class, 1, ODS_12_0)
|
||||
END_RELATION
|
||||
|
||||
// Relation 32 (RDB$BACKUP_HISTORY)
|
||||
|
291
src/jrd/scl.epp
291
src/jrd/scl.epp
@ -96,6 +96,7 @@ namespace
|
||||
{ SCL_references, priv_references, "REFERENCES" },
|
||||
{ SCL_execute, priv_execute, "EXECUTE" },
|
||||
{ SCL_usage, priv_usage, "USAGE" },
|
||||
{ SCL_create, priv_create, "CREATE" },
|
||||
{ 0, 0, "" }
|
||||
};
|
||||
|
||||
@ -113,6 +114,9 @@ namespace
|
||||
const char* const object_str_domain = "DOMAIN";
|
||||
const char* const object_str_exception = "EXCEPTION";
|
||||
const char* const object_str_generator = "GENERATOR";
|
||||
const char* const object_str_view = "VIEW";
|
||||
const char* const object_str_role = "ROLE";
|
||||
const char* const object_str_filter = "FILTER";
|
||||
|
||||
|
||||
struct SecObjectNamePriority
|
||||
@ -135,6 +139,9 @@ namespace
|
||||
{object_str_domain, SCL_object_domain},
|
||||
{object_str_exception, SCL_object_exception},
|
||||
{object_str_generator, SCL_object_generator},
|
||||
{object_str_view, SCL_object_view},
|
||||
{object_str_role, SCL_object_role},
|
||||
{object_str_filter, SCL_object_filter},
|
||||
{"", 0}
|
||||
};
|
||||
|
||||
@ -189,6 +196,9 @@ void SCL_check_access(thread_db* tdbb,
|
||||
**************************************/
|
||||
SET_TDBB(tdbb);
|
||||
|
||||
if (tdbb->tdbb_flags & TDBB_trusted_ddl)
|
||||
return;
|
||||
|
||||
if (s_class && (s_class->scl_flags & SCL_corrupt))
|
||||
{
|
||||
ERR_post(Arg::Gds(isc_no_priv) << Arg::Str("(ACL unrecognized)") <<
|
||||
@ -209,27 +219,22 @@ void SCL_check_access(thread_db* tdbb,
|
||||
if (attachment.locksmith())
|
||||
return;
|
||||
|
||||
bool denied_db = false;
|
||||
// Check global DDL permissions with ANY option which allow user to make changes non owned objects
|
||||
const SecurityClass::flags_t obj_mask = SCL_get_object_mask(type);
|
||||
if (mask & obj_mask)
|
||||
return;
|
||||
|
||||
const SecurityClass* const att_class = attachment.att_security_class;
|
||||
if (att_class && !(att_class->scl_flags & mask))
|
||||
{
|
||||
denied_db = true;
|
||||
if (!s_class || (mask & s_class->scl_flags)) {
|
||||
return;
|
||||
}
|
||||
else
|
||||
const jrd_rel* view = NULL;
|
||||
if (view_id) {
|
||||
view = MET_lookup_relation_id(tdbb, view_id, false);
|
||||
}
|
||||
if ((view || obj_name.hasData()) &&
|
||||
(compute_access(tdbb, s_class, view, obj_type, obj_name) & mask))
|
||||
{
|
||||
if (!s_class || (mask & s_class->scl_flags)) {
|
||||
return;
|
||||
}
|
||||
const jrd_rel* view = NULL;
|
||||
if (view_id) {
|
||||
view = MET_lookup_relation_id(tdbb, view_id, false);
|
||||
}
|
||||
if ((view || obj_name.hasData()) &&
|
||||
(compute_access(tdbb, s_class, view, obj_type, obj_name) & mask))
|
||||
{
|
||||
return;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Allow recursive procedure/function call
|
||||
@ -244,30 +249,37 @@ void SCL_check_access(thread_db* tdbb,
|
||||
|
||||
const P_NAMES* names;
|
||||
for (names = p_names; names->p_names_priv; names++)
|
||||
{
|
||||
if (names->p_names_priv & mask)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (denied_db)
|
||||
{
|
||||
fb_assert(type == SCL_object_database);
|
||||
ERR_post(Arg::Gds(isc_no_priv) << Arg::Str(names->p_names_string) <<
|
||||
Arg::Str(object_str_database) <<
|
||||
Arg::Str(""));
|
||||
}
|
||||
else
|
||||
{
|
||||
fb_assert(type != SCL_object_database);
|
||||
const char* const typeAsStr = accTypeNumToStr(type);
|
||||
const Firebird::string fullName = r_name.hasData() ?
|
||||
r_name.c_str() + Firebird::string(".") + name.c_str() : name.c_str();
|
||||
ERR_post(Arg::Gds(isc_no_priv) << Arg::Str(names->p_names_string) <<
|
||||
Arg::Str(typeAsStr) <<
|
||||
Arg::Str(fullName));
|
||||
}
|
||||
const char* const typeAsStr = accTypeNumToStr(type);
|
||||
const Firebird::string fullName = r_name.hasData() ?
|
||||
r_name.c_str() + Firebird::string(".") + name.c_str() : name.c_str();
|
||||
ERR_post(Arg::Gds(isc_no_priv) << Arg::Str(names->p_names_string) <<
|
||||
Arg::Str(typeAsStr) <<
|
||||
Arg::Str(fullName));
|
||||
}
|
||||
|
||||
|
||||
void SCL_check_create_access(thread_db* tdbb, int type)
|
||||
{
|
||||
/**************************************
|
||||
*
|
||||
* S C L _ c h e c k _ c r e a t e _ a c c e s s
|
||||
*
|
||||
**************************************
|
||||
*
|
||||
* Functional description
|
||||
* Check create access on a database object (DDL access)
|
||||
*
|
||||
**************************************/
|
||||
SET_TDBB(tdbb);
|
||||
|
||||
const SecurityClass::flags_t obj_mask = SCL_get_object_mask(type);
|
||||
if (SCL_create & obj_mask)
|
||||
return;
|
||||
|
||||
ERR_post(Arg::Gds(isc_dyn_no_priv));
|
||||
}
|
||||
|
||||
|
||||
@ -333,6 +345,43 @@ void SCL_check_collation(thread_db* tdbb, const MetaName& name, SecurityClass::f
|
||||
}
|
||||
|
||||
|
||||
void SCL_check_database(thread_db* tdbb, SecurityClass::flags_t mask)
|
||||
{
|
||||
/**************************************
|
||||
*
|
||||
* S C L _ c h e c k _ d a t a b a s e
|
||||
*
|
||||
**************************************
|
||||
*
|
||||
* Functional description
|
||||
* Check for a set of privileges of current database.
|
||||
*
|
||||
**************************************/
|
||||
SET_TDBB(tdbb);
|
||||
|
||||
Jrd::Attachment* const attachment = tdbb->getAttachment();
|
||||
|
||||
// Allow the locksmith any access to database
|
||||
if (attachment->locksmith())
|
||||
return;
|
||||
|
||||
const SecurityClass* const att_class = attachment->att_security_class;
|
||||
if (att_class && (att_class->scl_flags & mask))
|
||||
return;
|
||||
|
||||
const P_NAMES* names;
|
||||
for (names = p_names; names->p_names_priv; names++)
|
||||
{
|
||||
if (names->p_names_priv & mask)
|
||||
break;
|
||||
}
|
||||
|
||||
ERR_post(Arg::Gds(isc_no_priv) << Arg::Str(names->p_names_string) <<
|
||||
Arg::Str(object_str_database) <<
|
||||
Arg::Str(""));
|
||||
}
|
||||
|
||||
|
||||
void SCL_check_domain(thread_db* tdbb, const MetaName& name, SecurityClass::flags_t mask)
|
||||
{
|
||||
/**************************************
|
||||
@ -653,6 +702,40 @@ void SCL_check_function(thread_db* tdbb, const dsc* dsc_name, SecurityClass::fla
|
||||
}
|
||||
|
||||
|
||||
void SCL_check_filter(thread_db* tdbb, const MetaName &name, SecurityClass::flags_t mask)
|
||||
{
|
||||
/**************************************
|
||||
*
|
||||
* S C L _ c h e c k _ f i l t e r
|
||||
*
|
||||
**************************************
|
||||
*
|
||||
* Functional description
|
||||
* Given a filter name, check for a set of privileges. The
|
||||
* filter in question may or may not have been created, let alone
|
||||
* scanned. This is used exclusively for meta-data operations.
|
||||
*
|
||||
**************************************/
|
||||
SET_TDBB(tdbb);
|
||||
|
||||
Jrd::Attachment* const attachment = tdbb->getAttachment();
|
||||
|
||||
const SecurityClass* s_class = NULL;
|
||||
AutoCacheRequest request(tdbb, irq_f_security, IRQ_REQUESTS);
|
||||
|
||||
FOR (REQUEST_HANDLE request)
|
||||
F IN RDB$FILTERS
|
||||
WITH F.RDB$FUNCTION_NAME EQ name.c_str()
|
||||
{
|
||||
if (!F.RDB$SECURITY_CLASS.NULL)
|
||||
s_class = SCL_get_class(tdbb, F.RDB$SECURITY_CLASS);
|
||||
}
|
||||
END_FOR
|
||||
|
||||
SCL_check_access(tdbb, s_class, 0, id_filter, name, mask, SCL_object_filter, false, name);
|
||||
}
|
||||
|
||||
|
||||
void SCL_check_relation(thread_db* tdbb, const dsc* dsc_name, SecurityClass::flags_t mask)
|
||||
{
|
||||
/**************************************
|
||||
@ -683,13 +766,85 @@ void SCL_check_relation(thread_db* tdbb, const dsc* dsc_name, SecurityClass::fla
|
||||
WITH REL.RDB$RELATION_NAME EQ name.c_str()
|
||||
{
|
||||
if (!REL.RDB$SECURITY_CLASS.NULL)
|
||||
{
|
||||
s_class = SCL_get_class(tdbb, REL.RDB$SECURITY_CLASS);
|
||||
}
|
||||
}
|
||||
END_FOR
|
||||
|
||||
SCL_check_access(tdbb, s_class, 0, 0, NULL, mask, SCL_object_table, false, name);
|
||||
}
|
||||
|
||||
void SCL_check_view(thread_db* tdbb, const dsc* dsc_name, SecurityClass::flags_t mask)
|
||||
{
|
||||
/**************************************
|
||||
*
|
||||
* S C L _ c h e c k _ v i e w
|
||||
*
|
||||
**************************************
|
||||
*
|
||||
* Functional description
|
||||
* Given a view name, check for a set of privileges. The
|
||||
* relation in question may or may not have been created, let alone
|
||||
* scanned. This is used exclusively for meta-data operations.
|
||||
*
|
||||
**************************************/
|
||||
SET_TDBB(tdbb);
|
||||
|
||||
// Get the name in CSTRING format, ending on NULL or SPACE
|
||||
fb_assert(dsc_name->dsc_dtype == dtype_text);
|
||||
const Firebird::MetaName name(reinterpret_cast<TEXT*>(dsc_name->dsc_address),
|
||||
dsc_name->dsc_length);
|
||||
|
||||
Jrd::Attachment* const attachment = tdbb->getAttachment();
|
||||
|
||||
const SecurityClass* s_class = NULL;
|
||||
AutoCacheRequest request(tdbb, irq_v_security, IRQ_REQUESTS);
|
||||
|
||||
FOR(REQUEST_HANDLE request) REL IN RDB$RELATIONS
|
||||
WITH REL.RDB$RELATION_NAME EQ name.c_str()
|
||||
{
|
||||
if (!REL.RDB$SECURITY_CLASS.NULL)
|
||||
{
|
||||
s_class = SCL_get_class(tdbb, REL.RDB$SECURITY_CLASS);
|
||||
}
|
||||
}
|
||||
END_FOR
|
||||
|
||||
SCL_check_access(tdbb, s_class, 0, 0, NULL, mask, SCL_object_view, false, name);
|
||||
}
|
||||
|
||||
void SCL_check_role(thread_db* tdbb, const Firebird::MetaName& name, SecurityClass::flags_t mask)
|
||||
{
|
||||
/**************************************
|
||||
*
|
||||
* S C L _ c h e c k _ r o l e
|
||||
*
|
||||
**************************************
|
||||
*
|
||||
* Functional description
|
||||
* Given a role name, check for a set of privileges.
|
||||
*
|
||||
**************************************/
|
||||
SET_TDBB(tdbb);
|
||||
|
||||
Jrd::Attachment* const attachment = tdbb->getAttachment();
|
||||
|
||||
const SecurityClass* s_class = NULL;
|
||||
AutoCacheRequest request(tdbb, irq_v_security, IRQ_REQUESTS);
|
||||
|
||||
FOR(REQUEST_HANDLE request) R IN RDB$ROLES
|
||||
WITH R.RDB$ROLE_NAME EQ name.c_str()
|
||||
{
|
||||
if (!R.RDB$SECURITY_CLASS.NULL)
|
||||
{
|
||||
s_class = SCL_get_class(tdbb, R.RDB$SECURITY_CLASS);
|
||||
}
|
||||
}
|
||||
END_FOR
|
||||
|
||||
SCL_check_access(tdbb, s_class, 0, 0, NULL, mask, SCL_object_role, false, name);
|
||||
}
|
||||
|
||||
SecurityClass* SCL_get_class(thread_db* tdbb, const TEXT* par_string)
|
||||
{
|
||||
@ -1087,6 +1242,60 @@ void SCL_release_all(SecurityClassList*& list)
|
||||
}
|
||||
|
||||
|
||||
SecurityClass::flags_t SCL_get_object_mask(const int object_type)
|
||||
{
|
||||
/**************************************
|
||||
*
|
||||
* S C L _ g e t _ o b j e c t _ m a s k
|
||||
*
|
||||
**************************************
|
||||
*
|
||||
* Functional description
|
||||
* Get a protection mask for database object.
|
||||
*
|
||||
**************************************/
|
||||
thread_db* tdbb = JRD_get_thread_data();
|
||||
Database* dbb = tdbb->getDatabase();
|
||||
|
||||
UserId* user = tdbb->getAttachment()->att_user;
|
||||
|
||||
/*if (object_type == obj_roles)
|
||||
{
|
||||
if (user->isSecAdmin())
|
||||
return -1 & ~SCL_corrupt;
|
||||
}*/
|
||||
|
||||
const TEXT* object_name = get_object_name(object_type);
|
||||
const Jrd::SecurityClass* s_class = SCL_recompute_class(tdbb, object_name);
|
||||
|
||||
if (s_class)
|
||||
return s_class->scl_flags;
|
||||
|
||||
return -1 & ~SCL_corrupt;
|
||||
}
|
||||
|
||||
void SCL_set_user(const Firebird::MetaName& user_name, UserId& user)
|
||||
{
|
||||
/**************************************
|
||||
*
|
||||
* S C L _ s e t _ u s e r
|
||||
*
|
||||
**************************************
|
||||
*
|
||||
* Functional description
|
||||
* Set user attributes.
|
||||
*
|
||||
**************************************/
|
||||
thread_db* tdbb = JRD_get_thread_data();
|
||||
Database* dbb = tdbb->getDatabase();
|
||||
|
||||
user.usr_user_name = user_name.c_str();
|
||||
|
||||
if (!user.usr_user_name.compare(dbb->dbb_owner.c_str())) {
|
||||
user.usr_flags |= USR_owner;
|
||||
}
|
||||
}
|
||||
|
||||
static bool check_number(const UCHAR* acl, USHORT number)
|
||||
{
|
||||
/**************************************
|
||||
@ -1471,6 +1680,10 @@ static SecurityClass::flags_t walk_acl(thread_db* tdbb,
|
||||
// unused
|
||||
break;
|
||||
|
||||
case priv_create:
|
||||
privilege |= SCL_create;
|
||||
break;
|
||||
|
||||
default:
|
||||
return SCL_corrupt;
|
||||
}
|
||||
|
@ -27,6 +27,7 @@
|
||||
#include "../common/classes/MetaName.h"
|
||||
#include "../common/classes/tree.h"
|
||||
#include "../common/security.h"
|
||||
#include "../jrd/obj.h"
|
||||
|
||||
namespace Firebird {
|
||||
class ClumpletWriter;
|
||||
@ -41,7 +42,7 @@ const size_t ACL_BLOB_BUFFER_SIZE = MAX_USHORT; // used to read/write acl blob
|
||||
class SecurityClass
|
||||
{
|
||||
public:
|
||||
typedef USHORT flags_t;
|
||||
typedef ULONG flags_t;
|
||||
|
||||
SecurityClass(Firebird::MemoryPool &pool, const Firebird::MetaName& name)
|
||||
: scl_flags(0), scl_name(pool, name)
|
||||
@ -76,7 +77,7 @@ const SecurityClass::flags_t SCL_update = 256; // UPDATE access
|
||||
const SecurityClass::flags_t SCL_references = 512; // REFERENCES access
|
||||
const SecurityClass::flags_t SCL_execute = 1024; // EXECUTE access
|
||||
const SecurityClass::flags_t SCL_usage = 2048; // USAGE access
|
||||
|
||||
const SecurityClass::flags_t SCL_create = 4096;
|
||||
|
||||
|
||||
// information about the user
|
||||
@ -158,17 +159,20 @@ public:
|
||||
|
||||
// These numbers are arbitrary and only used at run-time. Can be changed if necessary at any moment.
|
||||
// We need to include here the new objects that accept ACLs.
|
||||
const SLONG SCL_object_database = 1;
|
||||
const SLONG SCL_object_table = 2;
|
||||
const SLONG SCL_object_package = 3;
|
||||
const SLONG SCL_object_procedure = 4;
|
||||
const SLONG SCL_object_function = 5;
|
||||
const SLONG SCL_object_column = 6;
|
||||
const SLONG SCL_object_collation = 7;
|
||||
const SLONG SCL_object_exception = 8;
|
||||
const SLONG SCL_object_generator = 9;
|
||||
const SLONG SCL_object_charset = 10;
|
||||
const SLONG SCL_object_domain = 11;
|
||||
const SLONG SCL_object_column = 1;
|
||||
const SLONG SCL_object_database = obj_database;
|
||||
const SLONG SCL_object_table = obj_relations;
|
||||
const SLONG SCL_object_package = obj_packages;
|
||||
const SLONG SCL_object_procedure = obj_procedures;
|
||||
const SLONG SCL_object_function = obj_functions;
|
||||
const SLONG SCL_object_collation = obj_collations;
|
||||
const SLONG SCL_object_exception = obj_exceptions;
|
||||
const SLONG SCL_object_generator = obj_generators;
|
||||
const SLONG SCL_object_charset = obj_charsets;
|
||||
const SLONG SCL_object_domain = obj_domains;
|
||||
const SLONG SCL_object_view = obj_views;
|
||||
const SLONG SCL_object_role = obj_roles;
|
||||
const SLONG SCL_object_filter = obj_filters;
|
||||
|
||||
} //namespace Jrd
|
||||
|
||||
|
@ -36,8 +36,10 @@ struct dsc;
|
||||
void SCL_check_access(Jrd::thread_db*, const Jrd::SecurityClass*, SLONG, SLONG, const Firebird::MetaName&,
|
||||
Jrd::SecurityClass::flags_t, SLONG type, bool recursive, const Firebird::MetaName&,
|
||||
const Firebird::MetaName& = "");
|
||||
void SCL_check_create_access(Jrd::thread_db*, int type);
|
||||
void SCL_check_charset(Jrd::thread_db* tdbb, const Firebird::MetaName&, Jrd::SecurityClass::flags_t);
|
||||
void SCL_check_collation(Jrd::thread_db* tdbb, const Firebird::MetaName&, Jrd::SecurityClass::flags_t);
|
||||
void SCL_check_database(Jrd::thread_db* tdbb, Jrd::SecurityClass::flags_t mask);
|
||||
void SCL_check_domain(Jrd::thread_db* tdbb, const Firebird::MetaName&, Jrd::SecurityClass::flags_t);
|
||||
void SCL_check_exception(Jrd::thread_db* tdbb, const Firebird::MetaName&, Jrd::SecurityClass::flags_t);
|
||||
void SCL_check_generator(Jrd::thread_db* tdbb, const Firebird::MetaName&, Jrd::SecurityClass::flags_t);
|
||||
@ -45,7 +47,10 @@ void SCL_check_index(Jrd::thread_db*, const Firebird::MetaName&, UCHAR, Jrd::Sec
|
||||
void SCL_check_package(Jrd::thread_db* tdbb, const dsc*, Jrd::SecurityClass::flags_t);
|
||||
void SCL_check_procedure(Jrd::thread_db* tdbb, const dsc*, Jrd::SecurityClass::flags_t);
|
||||
void SCL_check_function(Jrd::thread_db* tdbb, const dsc*, Jrd::SecurityClass::flags_t);
|
||||
void SCL_check_filter(Jrd::thread_db* tdbb, const Firebird::MetaName &name, Jrd::SecurityClass::flags_t);
|
||||
void SCL_check_relation(Jrd::thread_db* tdbb, const dsc*, Jrd::SecurityClass::flags_t);
|
||||
void SCL_check_view(Jrd::thread_db* tdbb, const dsc*, Jrd::SecurityClass::flags_t);
|
||||
void SCL_check_role(Jrd::thread_db* tdbb, const Firebird::MetaName&, Jrd::SecurityClass::flags_t);
|
||||
Jrd::SecurityClass* SCL_get_class(Jrd::thread_db*, const TEXT*);
|
||||
Jrd::SecurityClass::flags_t SCL_get_mask(Jrd::thread_db* tdbb, const TEXT*, const TEXT*);
|
||||
void SCL_init(Jrd::thread_db* tdbb, bool, const Jrd::UserId& tempId);
|
||||
@ -53,6 +58,7 @@ Jrd::SecurityClass* SCL_recompute_class(Jrd::thread_db*, const TEXT*);
|
||||
void SCL_release_all(Jrd::SecurityClassList*&);
|
||||
bool SCL_role_granted(Jrd::thread_db* tdbb, const Jrd::UserId& usr, const TEXT* sql_role);
|
||||
bool SCL_admin_role(Jrd::thread_db* tdbb, const TEXT* sql_role);
|
||||
Jrd::SecurityClass::flags_t SCL_get_object_mask(const int object_type);
|
||||
|
||||
namespace Jrd {
|
||||
typedef Firebird::Array<UCHAR> Acl;
|
||||
|
@ -1396,6 +1396,7 @@ void VIO_erase(thread_db* tdbb, record_param* rpb, jrd_tra* transaction)
|
||||
{
|
||||
SCL_check_relation(tdbb, &desc, SCL_drop);
|
||||
}
|
||||
|
||||
if (EVL_field(0, rpb->rpb_record, f_rel_id, &desc2))
|
||||
{
|
||||
id = MOV_get_long(&desc2, 0);
|
||||
@ -1577,6 +1578,7 @@ void VIO_erase(thread_db* tdbb, record_param* rpb, jrd_tra* transaction)
|
||||
EVL_field(0, rpb->rpb_record, f_arg_fun_name, &desc);
|
||||
SCL_check_function(tdbb, &desc, SCL_control);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case rel_prc_prms:
|
||||
@ -1621,6 +1623,7 @@ void VIO_erase(thread_db* tdbb, record_param* rpb, jrd_tra* transaction)
|
||||
case rel_files:
|
||||
protect_system_table_delupd(tdbb, relation, "DELETE");
|
||||
{
|
||||
SCL_check_database(tdbb, SCL_alter);
|
||||
const bool name_defined = EVL_field(0, rpb->rpb_record, f_file_name, &desc);
|
||||
const USHORT file_flags = EVL_field(0, rpb->rpb_record, f_file_flags, &desc2) ?
|
||||
MOV_get_long(&desc2, 0) : 0;
|
||||
@ -2677,6 +2680,7 @@ void VIO_modify(thread_db* tdbb, record_param* org_rpb, record_param* new_rpb, j
|
||||
case rel_files:
|
||||
protect_system_table_delupd(tdbb, relation, "UPDATE");
|
||||
{
|
||||
SCL_check_database(tdbb, SCL_alter);
|
||||
SSHORT new_rel_flags, old_rel_flags;
|
||||
EVL_field(0, new_rpb->rpb_record, f_file_name, &desc1);
|
||||
if (EVL_field(0, new_rpb->rpb_record, f_file_flags, &desc2) &&
|
||||
@ -3036,6 +3040,7 @@ void VIO_store(thread_db* tdbb, record_param* rpb, jrd_tra* transaction)
|
||||
DeferredWork* work = NULL;
|
||||
MetaName package_name;
|
||||
USHORT object_id;
|
||||
MetaName object_name;
|
||||
|
||||
#ifdef VIO_DEBUG
|
||||
VIO_trace(DEBUG_WRITES,
|
||||
@ -3055,7 +3060,6 @@ void VIO_store(thread_db* tdbb, record_param* rpb, jrd_tra* transaction)
|
||||
switch ((RIDS) relation->rel_id)
|
||||
{
|
||||
case rel_pages:
|
||||
case rel_database:
|
||||
case rel_formats:
|
||||
case rel_trans:
|
||||
case rel_rcon:
|
||||
@ -3083,6 +3087,10 @@ void VIO_store(thread_db* tdbb, record_param* rpb, jrd_tra* transaction)
|
||||
case rel_log:
|
||||
case rel_global_auth_mapping:
|
||||
protect_system_table_insert(tdbb, request, relation, true);
|
||||
|
||||
case rel_database:
|
||||
if (set_security_class(tdbb, rpb->rpb_record, f_dat_class))
|
||||
DFW_post_work(transaction, dfw_grant, &desc, obj_database);
|
||||
break;
|
||||
|
||||
case rel_relations:
|
||||
@ -3188,6 +3196,8 @@ void VIO_store(thread_db* tdbb, record_param* rpb, jrd_tra* transaction)
|
||||
|
||||
case rel_fields:
|
||||
EVL_field(0, rpb->rpb_record, f_fld_name, &desc);
|
||||
MOV_get_metaname(&desc, object_name);
|
||||
SCL_check_domain(tdbb, object_name, SCL_create);
|
||||
DFW_post_work(transaction, dfw_create_field, &desc, 0);
|
||||
set_system_flag(tdbb, rpb->rpb_record, f_fld_sys_flag);
|
||||
set_owner_name(tdbb, rpb->rpb_record, f_fld_owner);
|
||||
@ -3195,6 +3205,12 @@ void VIO_store(thread_db* tdbb, record_param* rpb, jrd_tra* transaction)
|
||||
DFW_post_work(transaction, dfw_grant, &desc, obj_field);
|
||||
break;
|
||||
|
||||
case rel_filters:
|
||||
EVL_field(0, rpb->rpb_record, f_flt_name, &desc);
|
||||
if (set_security_class(tdbb, rpb->rpb_record, f_flt_class))
|
||||
DFW_post_work(transaction, dfw_grant, &desc, obj_blob_filter);
|
||||
break;
|
||||
|
||||
case rel_files:
|
||||
{
|
||||
const bool name_defined = EVL_field(0, rpb->rpb_record, f_file_name, &desc);
|
||||
|
@ -1,7 +1,7 @@
|
||||
/* MAX_NUMBER is the next number to be used, always one more than the highest message number. */
|
||||
set bulk_insert INSERT INTO FACILITIES (LAST_CHANGE, FACILITY, FAC_CODE, MAX_NUMBER) VALUES (?, ?, ?, ?);
|
||||
--
|
||||
('2014-06-24 10:13:56', 'JRD', 0, 774)
|
||||
('2014-05-14 23:48:00', 'JRD', 0, 775)
|
||||
('2012-01-23 20:10:30', 'QLI', 1, 532)
|
||||
('2013-11-13 15:59:10', 'GFIX', 3, 122)
|
||||
('1996-11-07 13:39:40', 'GPRE', 4, 1)
|
||||
|
@ -881,6 +881,8 @@ Data source : @4', NULL, NULL)
|
||||
('set_invalid_role', 'SetRoleNode::execute', 'StmtNodes.cpp', NULL, 0, 771, NULL, 'Role @1 is invalid or unavailable', NULL, NULL);
|
||||
('cursor_not_positioned', NULL, NULL, NULL, 0, 772, NULL, 'Cursor @1 is not positioned in a valid record', NULL, NULL);
|
||||
('dup_attribute', 'UserManagement::execute', 'UserManagement.cpp', NULL, 0, 773, NULL, 'Duplicated user attribute @1', NULL, NULL);
|
||||
('dyn_no_priv', NULL, 'scl.epp', NULL, 0, 774, NULL, 'There is no privilege for this operation', NULL, NULL);
|
||||
('dsql_cant_grant_option', NULL, 'DdlNodes.epp', NULL, 0, 775, NULL, 'Using GRANT OPTION on @1 not allowed', NULL, NULL);
|
||||
-- QLI
|
||||
(NULL, NULL, NULL, NULL, 1, 0, NULL, 'expected type', NULL, NULL);
|
||||
(NULL, NULL, NULL, NULL, 1, 1, NULL, 'bad block type', NULL, NULL);
|
||||
|
@ -780,6 +780,8 @@ set bulk_insert INSERT INTO SYSTEM_ERRORS (SQL_CODE, SQL_CLASS, SQL_SUBCLASS, FA
|
||||
(-901, '0P', '000', 0, 771, 'set_invalid_role', NULL, NULL);
|
||||
(-596, 'HY', '109', 0, 772, 'cursor_not_positioned', NULL, NULL)
|
||||
(-901, '42', '702', 0, 773, 'dup_attribute', NULL, NULL);
|
||||
(-901, '42', '000', 0, 774, 'dyn_no_priv', NULL, NULL)
|
||||
(-901, '42', '000', 0, 775, 'dsql_cant_grant_option', NULL, NULL);
|
||||
-- GFIX
|
||||
(-901, '00', '000', 3, 1, 'gfix_db_name', NULL, NULL)
|
||||
(-901, '00', '000', 3, 2, 'gfix_invalid_sw', NULL, NULL)
|
||||
|
Loading…
Reference in New Issue
Block a user