8
0
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:
roman-simakov 2014-07-08 07:35:27 +00:00
parent a1d0c2b52a
commit 573e93e5a6
34 changed files with 1119 additions and 101 deletions

View 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;

View File

@ -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

View File

@ -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;

View File

@ -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)
{

View File

@ -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:

View File

@ -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)

View File

@ -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)
{

View File

@ -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:

View File

@ -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
{

View File

@ -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},

View File

@ -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

View File

@ -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)

View File

@ -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 */

View File

@ -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 */

View File

@ -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

View File

@ -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),

View File

@ -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:

View File

@ -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_";

View File

@ -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
};

View File

@ -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] =

View File

@ -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;

View File

@ -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)
{

View File

@ -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)

View File

@ -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
{

View File

@ -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);

View File

@ -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

View File

@ -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)

View File

@ -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;
}

View File

@ -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

View File

@ -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;

View File

@ -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);

View File

@ -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)

View File

@ -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);

View File

@ -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)