8
0
mirror of https://github.com/FirebirdSQL/firebird.git synced 2025-01-22 20:43:02 +01:00

Added support for system privileges

This commit is contained in:
Alexander Peshkov 2016-05-31 20:07:08 +03:00
parent 70e3848eeb
commit 7ad99b795e
80 changed files with 1813 additions and 789 deletions

View File

@ -681,6 +681,21 @@ Example:
select * from x order by rand();
--------------------
RDB$SYSTEM_PRIVILEGE
--------------------
(FB4 extension)
Function:
Returns true if current attachment has given system privilege.
Format:
RDB$SYSTEM_PRIVILEGE( <privilege> )
Example:
select rdb$system_privilege(user_management) from rdb$database;
-------
REPLACE
-------

View File

@ -509,3 +509,61 @@ ignoring it).
ALTER DATABASE DECRYPT
Decrypts database.
21) New clauses in CREATE and ALTER role operators.
(Alex Peshkov)
Provide support for system privileges. One can:
CREATE ROLE <name> SET SYSTEM PRIVILEGES TO <privilege1> {, <privilege2> {, ... <privilegeN> }}
ALTER ROLE <name> SET SYSTEM PRIVILEGES TO <privilege1> {, <privilege2> {, ... <privilegeN> }}
This forms assign non-empty list of system privileges to role <name>. Privileges previously assigned
to role <name> are cleared when using second form.
ALTER ROLE <name> DROP SYSTEM PRIVILEGES
This form clears list of system privileges in role <name>.
System privileges make it possible to delegate part of DBO rights to other users.
Pay attention taht system privileges provide very thin level of control, therefore sometimes
you will need to give user >1 privilege to perform some task (for example add
IGNORE_DB_TRIGGERS to USE_GSTAT_UTILITY cause gstat wants to ignore database triggers).
List of valid system privileges for FB4 is as follows:
USER_MANAGEMENT Manage users
READ_RAW_PAGES Read pages in raw format using Attachment::getInfo()
CREATE_USER_TYPES Add/change/delete non-system records in RDB$TYPES
USE_NBACKUP_UTILITY Use nbackup to create database's copies
CHANGE_SHUTDOWN_MODE Shutdown DB and bring online
TRACE_ANY_ATTACHMENT Trace other users' attachments
MONITOR_ANY_ATTACHMENT Monitor (tables MON$) other users' attachments
ACCESS_SHUTDOWN_DATABASE Access database when it's shut down
CREATE_DATABASE Create new databases (given in security.db)
DROP_DATABASE Drop this database
USE_GBAK_UTILITY Use appropriate utility
USE_GSTAT_UTILITY ...
USE_GFIX_UTILITY ...
IGNORE_DB_TRIGGERS Insruct engine not to run DB-level triggers
CHANGE_HEADER_SETTINGS Modify parameters in DB header page
SELECT_ANY_OBJECT_IN_DATABASE Use SELECT for any selectable object
ACCESS_ANY_OBJECT_IN_DATABASE Access (in any possible way) any object
MODIFY_ANY_OBJECT_IN_DATABASE Modify (up to drop) any object
CHANGE_MAPPING_RULES Change authentication mappings
USE_GRANTED_BY_CLAUSE Use GRANTED BY in GRANT and REVOKE operators
GRANT_REVOKE_ON_ANY_OBJECT GRANT and REVOKE rights on any object in database
GRANT_REVOKE_ANY_DDL_RIGHT GRANT and REVOKE any DDL rights
CREATE_PRIVILEGED_ROLES Use SET SYSTEM PRIVILEGES in roles
22) New grantee type in GRANT and REVOKE operators - SYSTEM PRIVILEGE.
(Alex Peshkov)
With support for various system privileges in engine it's getting very convenient to grant some
rights to users already having specific system privilege. Therefore appropriate grantee type is
suppoprted now. Example:
GRANT ALL ON PLG$SRP_VIEW TO SYSTEM PRIVILEGE USER_MANAGEMENT
Grants all rights to view (used in SRP management plugin) to users having USER_MANAGEMENT privilege.

View File

@ -1632,6 +1632,10 @@ C --
PARAMETER (GDS__encrypt_error = 335545109)
INTEGER*4 GDS__max_idx_depth
PARAMETER (GDS__max_idx_depth = 335545110)
INTEGER*4 GDS__wrong_prvlg
PARAMETER (GDS__wrong_prvlg = 335545111)
INTEGER*4 GDS__miss_prvlg
PARAMETER (GDS__miss_prvlg = 335545112)
INTEGER*4 GDS__gfix_db_name
PARAMETER (GDS__gfix_db_name = 335740929)
INTEGER*4 GDS__gfix_invalid_sw

View File

@ -1627,6 +1627,10 @@ const
gds_encrypt_error = 335545109;
isc_max_idx_depth = 335545110;
gds_max_idx_depth = 335545110;
isc_wrong_prvlg = 335545111;
gds_wrong_prvlg = 335545111;
isc_miss_prvlg = 335545112;
gds_miss_prvlg = 335545112;
isc_gfix_db_name = 335740929;
gds_gfix_db_name = 335740929;
isc_gfix_invalid_sw = 335740930;

View File

@ -87,16 +87,18 @@ private:
"CREATE VIEW PLG$SRP_VIEW AS "
"SELECT PLG$USER_NAME, PLG$VERIFIER, PLG$SALT, PLG$COMMENT, "
" PLG$FIRST, PLG$MIDDLE, PLG$LAST, PLG$ATTRIBUTES, PLG$ACTIVE "
"FROM PLG$SRP WHERE CURRENT_USER = 'SYSDBA' "
" OR CURRENT_ROLE = '" ADMIN_ROLE "' OR CURRENT_USER = PLG$SRP.PLG$USER_NAME"
"FROM PLG$SRP WHERE RDB$SYSTEM_PRIVILEGE(USER_MANAGEMENT) "
" OR CURRENT_USER = PLG$SRP.PLG$USER_NAME"
,
"GRANT ALL ON PLG$SRP to VIEW PLG$SRP_VIEW"
"GRANT ALL ON PLG$SRP TO VIEW PLG$SRP_VIEW"
,
"GRANT SELECT ON PLG$SRP_VIEW to PUBLIC"
"GRANT SELECT ON PLG$SRP_VIEW TO PUBLIC"
,
"GRANT UPDATE(PLG$VERIFIER, PLG$SALT, PLG$FIRST, PLG$MIDDLE, PLG$LAST, "
" PLG$COMMENT, PLG$ATTRIBUTES) ON PLG$SRP_VIEW TO PUBLIC"
,
"GRANT ALL ON PLG$SRP_VIEW TO SYSTEM PRIVILEGE USER_MANAGEMENT"
,
NULL
};
@ -106,9 +108,17 @@ private:
try
{
for (const char** sql = script; *sql; ++sql)
for (const char** s = script; *s; ++s)
{
att->execute(&statusWrapper, ddlTran, 0, *sql, SQL_DIALECT_V6, NULL, NULL, NULL, NULL);
const char* sql = *s;
bool err = false;
if (sql[0] == '*')
{
++sql;
err = true;
}
att->execute(&statusWrapper, ddlTran, 0, sql, SQL_DIALECT_V6, NULL, NULL, NULL, NULL);
if (!err)
check(&statusWrapper);
}

View File

@ -132,7 +132,7 @@ int SrpServer::authenticate(CheckStatusWrapper* status, IServerBlock* sb, IWrite
{
ClumpletWriter dpb(ClumpletReader::dpbList, MAX_DPB_SIZE);
dpb.insertByte(isc_dpb_sec_attach, TRUE);
dpb.insertString(isc_dpb_user_name, SYSDBA_USER_NAME, fb_strlen(SYSDBA_USER_NAME));
dpb.insertString(isc_dpb_user_name, DBA_USER_NAME, fb_strlen(DBA_USER_NAME));
const char* providers = "Providers=" CURRENT_ENGINE;
dpb.insertString(isc_dpb_config, providers, fb_strlen(providers));
att = p->attachDatabase(status, secDbName, dpb.getBufferLength(), dpb.getBuffer());

View File

@ -508,7 +508,7 @@ int SecurityDatabaseManagement::execute(Firebird::CheckStatusWrapper* st, Firebi
found = false;
// Do not allow SYSDBA user to be deleted
if (!fb_utils::stricmp(user->userName()->get(), SYSDBA_USER_NAME))
if (!fb_utils::stricmp(user->userName()->get(), DBA_USER_NAME))
ret = GsecMsg23;
else
{

View File

@ -289,7 +289,7 @@ void SecurityDatabase::prepare()
dpb.insertByte(isc_dpb_sec_attach, TRUE);
// Attach as SYSDBA
dpb.insertString(isc_dpb_trusted_auth, SYSDBA_USER_NAME, fb_strlen(SYSDBA_USER_NAME));
dpb.insertString(isc_dpb_trusted_auth, DBA_USER_NAME, fb_strlen(DBA_USER_NAME));
// Do not use other providers except current engine
const char* providers = "Providers=" CURRENT_ENGINE;

View File

@ -4037,6 +4037,12 @@ void write_sql_roles()
if (!X.RDB$DESCRIPTION.NULL) {
put_source_blob (att_role_description, att_role_description, X.RDB$DESCRIPTION);
}
const UCHAR ll = sizeof(X.RDB$SYSTEM_PRIVILEGES);
put(tdgbl, att_role_sys_priveleges);
put(tdgbl, ll);
put_block(tdgbl, (const UCHAR*) (X.RDB$SYSTEM_PRIVILEGES), ll);
put(tdgbl, att_end);
MISC_terminate (X.RDB$ROLE_NAME, temp, l, sizeof(temp));
BURP_verbose (249, temp);

View File

@ -566,6 +566,7 @@ enum att_type {
att_role_name = SERIES,
att_role_owner_name,
att_role_description,
att_role_sys_priveleges,
// Check constraints attributes
att_chk_constraint_name = SERIES,

View File

@ -7769,6 +7769,18 @@ bool get_sql_roles(BurpGlobals* tdgbl)
bad_attribute(scan_next_attr, attribute, 250);
break;
case att_role_sys_priveleges:
{
const ULONG l = get(tdgbl);
if (l > sizeof(X.RDB$SYSTEM_PRIVILEGES))
BURP_error_redirect (NULL, 46);
// msg 46 string truncated
if (l)
get_block(tdgbl, (UCHAR*) (X.RDB$SYSTEM_PRIVILEGES), l);
}
break;
default:
// msg 250 SQL role
bad_attribute(scan_next_attr, attribute, 250);

View File

@ -81,6 +81,9 @@ public:
bool isEmpty() const { return count == 0; }
bool hasData() const { return count != 0; }
char& operator[](unsigned n) { return data[n]; }
char operator[](unsigned n) const { return data[n]; }
const char* begin() const { return data; }
const char* end() const { return data + count; }

View File

@ -61,6 +61,7 @@
#include "../common/dsc_proto.h"
#include "../common/StatusArg.h"
#include "../auth/SecureRemotePassword/Message.h"
#include "../jrd/Mapping.h"
namespace Jrd {
@ -903,7 +904,7 @@ void DdlNode::storePrivileges(thread_db* tdbb, jrd_tra* transaction,
const char* privileges)
{
Attachment* const attachment = transaction->tra_attachment;
const MetaName& userName = attachment->att_user->usr_user_name;
const MetaName& userName = attachment->att_user->getUserName();
AutoCacheRequest request(tdbb, drq_s_usr_prvs, DYN_REQUESTS);
@ -966,7 +967,7 @@ void DdlNode::storeGlobalField(thread_db* tdbb, jrd_tra* transaction, MetaName&
const TypeClause* field, const string& computedSource, const BlrDebugWriter::BlrData& computedValue)
{
Attachment* const attachment = transaction->tra_attachment;
const MetaName& userName = attachment->att_user->usr_user_name;
const MetaName& userName = attachment->att_user->getUserName();
const ValueListNode* elements = field->ranges;
const USHORT dims = elements ? elements->items.getCount() / 2 : 0;
@ -1674,7 +1675,7 @@ void CreateAlterFunctionNode::executeCreate(thread_db* tdbb, DsqlCompilerScratch
jrd_tra* transaction)
{
Attachment* const attachment = transaction->getAttachment();
const MetaName& userName = attachment->att_user->usr_user_name;
const MetaName& userName = attachment->att_user->getUserName();
if (package.isEmpty())
{
@ -2661,7 +2662,7 @@ void CreateAlterProcedureNode::executeCreate(thread_db* tdbb, DsqlCompilerScratc
jrd_tra* transaction)
{
Attachment* const attachment = transaction->getAttachment();
const MetaName& userName = attachment->att_user->usr_user_name;
const MetaName& userName = attachment->att_user->getUserName();
if (package.isEmpty())
{
@ -3801,7 +3802,7 @@ void CreateCollationNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScra
jrd_tra* transaction)
{
Attachment* const attachment = transaction->tra_attachment;
const MetaName& userName = attachment->att_user->usr_user_name;
const MetaName& userName = attachment->att_user->getUserName();
// run all statements under savepoint control
AutoSavePoint savePoint(tdbb, transaction);
@ -5264,7 +5265,7 @@ void CreateAlterExceptionNode::executeCreate(thread_db* tdbb, DsqlCompilerScratc
jrd_tra* transaction)
{
Attachment* const attachment = transaction->getAttachment();
const MetaName& userName = attachment->att_user->usr_user_name;
const MetaName& userName = attachment->att_user->getUserName();
executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_BEFORE,
DDL_TRIGGER_CREATE_EXCEPTION, name, NULL);
@ -5637,7 +5638,7 @@ SSHORT CreateAlterSequenceNode::store(thread_db* tdbb, jrd_tra* transaction, con
fb_sysflag sysFlag, SINT64 val, SLONG step)
{
Attachment* const attachment = transaction->tra_attachment;
const MetaName& userName = attachment->att_user->usr_user_name;
const MetaName& userName = attachment->att_user->getUserName();
DYN_UTIL_check_unique_name(tdbb, transaction, name, obj_generator);
@ -8304,7 +8305,7 @@ void CreateAlterViewNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScra
jrd_tra* transaction)
{
Attachment* const attachment = transaction->tra_attachment;
const MetaName& userName = attachment->att_user->usr_user_name;
const MetaName& userName = attachment->att_user->getUserName();
const dsql_rel* modifyingView = NULL;
@ -9725,7 +9726,7 @@ bool CreateFilterNode::checkPermission(thread_db* tdbb, jrd_tra* transaction)
// Define a blob filter.
void CreateFilterNode::execute(thread_db* tdbb, DsqlCompilerScratch* /*dsqlScratch*/, jrd_tra* transaction)
{
MetaName ownerName(tdbb->getAttachment()->att_user->usr_user_name);
MetaName ownerName(tdbb->getAttachment()->att_user->getUserName());
// run all statements under savepoint control
AutoSavePoint savePoint(tdbb, transaction);
@ -9953,30 +9954,52 @@ void DropShadowNode::execute(thread_db* tdbb, DsqlCompilerScratch* /*dsqlScratch
//----------------------
string CreateRoleNode::internalPrint(NodePrinter& printer) const
USHORT PrivilegesNode::convertPrivilegeFromString(thread_db* tdbb, jrd_tra* transaction, Firebird::MetaName privilege)
{
string priv(privilege.c_str());
priv.upper();
return SCL_convert_privilege(tdbb, transaction, priv);
}
//----------------------
string CreateAlterRoleNode::internalPrint(NodePrinter& printer) const
{
DdlNode::internalPrint(printer);
NODE_PRINT(printer, name);
return "CreateRoleNode";
return "CreateAlterRoleNode";
}
bool CreateRoleNode::checkPermission(thread_db* tdbb, jrd_tra* transaction)
bool CreateAlterRoleNode::checkPermission(thread_db* tdbb, jrd_tra* transaction)
{
if (createFlag)
SCL_check_create_access(tdbb, SCL_object_role);
else
SCL_check_role(tdbb, name, SCL_alter);
return true;
}
void CreateRoleNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, jrd_tra* transaction)
void CreateAlterRoleNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, jrd_tra* transaction)
{
MetaName ownerName(tdbb->getAttachment()->att_user->usr_user_name);
if (createFlag && sysPrivDrop)
{
// msg 293: DROP SYSTEM PRIVILEGES should not be used in CREATE ROLE
Arg::PrivateDyn(293).raise();
}
MetaName ownerName(tdbb->getAttachment()->att_user->getUserName());
// run all statements under savepoint control
AutoSavePoint savePoint(tdbb, transaction);
executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_BEFORE,
DDL_TRIGGER_CREATE_ROLE, name, NULL);
createFlag ? DDL_TRIGGER_CREATE_ROLE : DDL_TRIGGER_ALTER_ROLE, name, NULL);
if (name == ownerName)
{
@ -9997,31 +10020,64 @@ void CreateRoleNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch,
}
MetaName dummyName;
if (isItSqlRole(tdbb, transaction, name, dummyName))
if (createFlag && isItSqlRole(tdbb, transaction, name, dummyName))
{
// msg 194: "SQL role @1 already exists"
status_exception::raise(Arg::PrivateDyn(194) << name);
}
AutoCacheRequest request(tdbb, drq_role_gens, DYN_REQUESTS);
STORE(REQUEST_HANDLE request TRANSACTION_HANDLE transaction)
X IN RDB$ROLES
if (privileges.hasData() || sysPrivDrop)
{
strcpy(X.RDB$ROLE_NAME, name.c_str());
strcpy(X.RDB$OWNER_NAME, ownerName.c_str());
X.RDB$SYSTEM_FLAG = 0;
if (!tdbb->getAttachment()->locksmith(tdbb, CREATE_PRIVILEGED_ROLES))
{
// msg 294: Access to SYSTEM PRIVILEGES in ROLES denied to @1
(Arg::PrivateDyn(294) << ownerName).raise();
}
}
UserId::Privileges newPrivileges;
if (privileges.hasData() && !sysPrivDrop)
{
const MetaName* const end = privileges.end();
for (const MetaName* privName = privileges.begin(); privName < end; ++privName)
newPrivileges.set(convertPrivilegeFromString(tdbb, transaction, *privName));
}
Attachment* attachment = tdbb->getAttachment();
string p;
newPrivileges.store(p.getBuffer(newPrivileges.BYTES_COUNT));
if (createFlag)
{
PreparedStatement::Builder sql;
sql << "insert into rdb$roles(rdb$role_name, rdb$owner_name, rdb$system_privileges, rdb$system_flag)"
<< "values(" << name << "," << ownerName << "," << p << ", 0)";
AutoPreparedStatement ps(attachment->prepareStatement(tdbb, transaction, sql));
ps->execute(tdbb, transaction);
}
else if (privileges.hasData() || sysPrivDrop)
{
PreparedStatement::Builder sql;
sql << "update rdb$roles set rdb$system_privileges =" << p << "where rdb$role_name =" << name;
AutoPreparedStatement ps(attachment->prepareStatement(tdbb, transaction, sql));
if (ps->executeUpdate(tdbb, transaction) == 0)
{
// msg 155: "Role %s not found"
(Arg::PrivateDyn(155) << name).raise();
}
}
END_STORE
executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_AFTER,
DDL_TRIGGER_CREATE_ROLE, name, NULL);
createFlag ? DDL_TRIGGER_CREATE_ROLE : DDL_TRIGGER_ALTER_ROLE, name, NULL);
savePoint.release(); // everything is ok
}
// If role name is user name returns true. Otherwise returns false.
bool CreateRoleNode::isItUserName(thread_db* tdbb, jrd_tra* transaction)
bool CreateAlterRoleNode::isItUserName(thread_db* tdbb, jrd_tra* transaction)
{
bool found = false;
@ -10308,8 +10364,8 @@ void MappingNode::runInSecurityDb(SecDbContext* secDbContext)
// 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)
{
if (!(tdbb->getAttachment() && tdbb->getAttachment()->locksmith()))
status_exception::raise(Arg::Gds(isc_adm_task_denied));
if (!(tdbb->getAttachment() && tdbb->getAttachment()->locksmith(tdbb, CHANGE_MAPPING_RULES)))
(Arg::Gds(isc_miss_prvlg) << "CHANGE_MAPPING_RULES").raise();
if (global)
{
@ -10448,7 +10504,7 @@ void MappingNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, jrd
if (ddlTriggerAction > 0)
executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_AFTER, ddlTriggerAction, name, NULL);
DFW_post_work(transaction, dfw_clear_mapping, NULL, 0);
DFW_post_work(transaction, dfw_clear_cache, NULL, MAPPING_CACHE);
savePoint.release(); // everything is ok
}
@ -10473,7 +10529,7 @@ bool DropRoleNode::checkPermission(thread_db* tdbb, jrd_tra* transaction)
void DropRoleNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, jrd_tra* transaction)
{
MetaName user(tdbb->getAttachment()->att_user->usr_user_name);
MetaName user(tdbb->getAttachment()->att_user->getUserName());
// run all statements under savepoint control
AutoSavePoint savePoint(tdbb, transaction);
@ -10634,7 +10690,7 @@ void CreateAlterUserNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScra
if (!usr)
(Arg::Gds(isc_random) << "Missing user name for ALTER CURRENT USER").raise();
text = usr->usr_user_name;
text = usr->getUserName();
}
Firebird::LocalStatus s;
@ -10835,6 +10891,9 @@ void GrantRevokeNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch,
for (usersPtr = users.begin(); usersPtr != usersEnd; ++usersPtr)
grantRevoke(tdbb, transaction, rolesPtr, usersPtr, "M", defaultRole ? "D" : NULL, option);
}
// Invalidate system privileges cache
DFW_post_work(transaction, dfw_clear_cache, NULL, SYSTEM_PRIVILEGES_CACHE);
}
}
@ -11035,6 +11094,14 @@ void GrantRevokeNode::grantRevoke(thread_db* tdbb, jrd_tra* transaction, const G
status_exception::raise(Arg::PrivateDyn(195) << user.c_str());
}
break;
case obj_privilege: // Should convert symbolic privilege name to bit number
{
USHORT p = convertPrivilegeFromString(tdbb, transaction, user);
user.printf("%d", p);
}
break;
}
if (options == 1) // with grant option
@ -11053,16 +11120,26 @@ void GrantRevokeNode::grantRevoke(thread_db* tdbb, jrd_tra* transaction, const G
ERRD_post(Arg::Gds(isc_dsql_cant_grant_option) << Arg::Str("views"));
break;
case obj_privilege:
ERRD_post(Arg::Gds(isc_dsql_cant_grant_option) << Arg::Str("system privileges"));
break;
default:
break;
}
}
MetaName grantorRevoker(grantor ?
*grantor : tdbb->getAttachment()->att_user->usr_user_name);
*grantor : tdbb->getAttachment()->att_user->getUserName());
if (grantor && !tdbb->getAttachment()->locksmith())
status_exception::raise(Arg::PrivateDyn(252) << SYSDBA_USER_NAME);
if (grantor && !tdbb->getAttachment()->locksmith(tdbb, USE_GRANTED_BY_CLAUSE))
{
const Firebird::MetaName& owner(tdbb->getDatabase()->dbb_owner);
if (owner == DBA_USER_NAME)
(Arg::PrivateDyn(252) << DBA_USER_NAME).raise();
else
(Arg::PrivateDyn(295) << DBA_USER_NAME << owner).raise();
}
if (!isGrant && !privs) // REVOKE ALL ON ALL
{
@ -11077,7 +11154,8 @@ void GrantRevokeNode::grantRevoke(thread_db* tdbb, jrd_tra* transaction, const G
PRIV.RDB$USER_TYPE = userType AND
PRIV.RDB$GRANTOR NOT MISSING
{
if (tdbb->getAttachment()->att_user->locksmith() || grantorRevoker == PRIV.RDB$GRANTOR)
if (tdbb->getAttachment()->att_user->locksmith(tdbb, GRANT_REVOKE_ON_ANY_OBJECT) ||
grantorRevoker == PRIV.RDB$GRANTOR)
{
ERASE PRIV;
all.grantErased = true;
@ -11175,13 +11253,15 @@ void GrantRevokeNode::grantRevoke(thread_db* tdbb, jrd_tra* transaction, const G
if (userType == obj_sql_role)
{
// Check for blocking cycles of role grants.
Firebird::SortedArray<Firebird::MetaName> grantedRoles;
SCL_find_granted_roles(tdbb, objName, true, grantedRoles, false);
UserId grantedRoles;
grantedRoles.setSqlRole(objName);
if (grantedRoles.roleInUse(tdbb, user))
{
// 292: role @1 can not be granted to role @2
if (grantedRoles.exist(user.c_str()))
status_exception::raise(Arg::PrivateDyn(292) << objName.c_str() << user.c_str());
}
}
}
else
{
// In the case where the object is a view, then the grantor must have
@ -11199,13 +11279,13 @@ void GrantRevokeNode::grantRevoke(thread_db* tdbb, jrd_tra* transaction, const G
{
// Relation or view because we cannot distinguish at this point.
checkGrantorCanGrant(tdbb, transaction,
tdbb->getAttachment()->att_user->usr_user_name.c_str(), priv, objName,
tdbb->getAttachment()->att_user->getUserName().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);
tdbb->getAttachment()->att_user->getUserName().c_str(), priv, objName);
}
}
@ -11368,7 +11448,7 @@ void GrantRevokeNode::checkGrantorCanGrant(thread_db* tdbb, jrd_tra* transaction
// If the current user is locksmith - allow all grants to occur
if (tdbb->getAttachment()->locksmith())
if (tdbb->getAttachment()->locksmith(tdbb, GRANT_REVOKE_ON_ANY_OBJECT))
return;
// If this is a non-sql table, then the owner will probably not have any
@ -11569,7 +11649,7 @@ void GrantRevokeNode::checkGrantorCanGrantRole(thread_db* tdbb, jrd_tra* transac
if (isItSqlRole(tdbb, transaction, roleName, owner))
{
// Both SYSDBA and the owner of this ROLE can grant membership
if (tdbb->getAttachment()->locksmith() || owner == grantor)
if (tdbb->getAttachment()->locksmith(tdbb, GRANT_REVOKE_ON_ANY_OBJECT) || owner == grantor)
return;
}
else
@ -11592,7 +11672,7 @@ void GrantRevokeNode::checkGrantorCanGrantRole(thread_db* tdbb, jrd_tra* transac
void GrantRevokeNode::checkGrantorCanGrantDdl(thread_db* tdbb, jrd_tra* transaction,
const MetaName& grantor, const char* privilege, const MetaName& objName)
{
if (tdbb->getAttachment()->locksmith())
if (tdbb->getAttachment()->locksmith(tdbb, GRANT_REVOKE_ANY_DDL_RIGHT))
return;
AutoCacheRequest request(tdbb, drq_l_grant_option, DYN_REQUESTS);

View File

@ -1890,12 +1890,27 @@ public:
};
class CreateRoleNode : public DdlNode
class PrivilegesNode : public DdlNode
{
public:
CreateRoleNode(MemoryPool& p, const Firebird::MetaName& aName)
: DdlNode(p),
name(p, aName)
PrivilegesNode(MemoryPool& p)
: DdlNode(p)
{
}
protected:
USHORT convertPrivilegeFromString(thread_db* tdbb, jrd_tra* transaction, Firebird::MetaName privilege);
};
class CreateAlterRoleNode : public PrivilegesNode
{
public:
CreateAlterRoleNode(MemoryPool& p, const Firebird::MetaName& aName)
: PrivilegesNode(p),
name(p, aName),
createFlag(false),
sysPrivDrop(false),
privileges(p)
{
}
@ -1907,7 +1922,8 @@ public:
protected:
virtual void putErrorPrefix(Firebird::Arg::StatusVector& statusVector)
{
statusVector << Firebird::Arg::Gds(isc_dsql_create_role_failed) << name;
statusVector << Firebird::Arg::Gds(createFlag ? isc_dsql_create_role_failed :
isc_dsql_alter_role_failed) << name;
}
private:
@ -1915,6 +1931,15 @@ private:
public:
Firebird::MetaName name;
bool createFlag, sysPrivDrop;
void addPrivilege(const Firebird::MetaName* privName)
{
fb_assert(privName);
privileges.push(*privName);
}
private:
Firebird::HalfStaticArray<Firebird::MetaName, 4> privileges;
};
@ -2109,11 +2134,11 @@ public:
typedef Firebird::Pair<Firebird::NonPooled<char, ValueListNode*> > PrivilegeClause;
typedef Firebird::Pair<Firebird::NonPooled<SSHORT, Firebird::MetaName> > GranteeClause;
class GrantRevokeNode : public DdlNode, private ExecInSecurityDb
class GrantRevokeNode : public PrivilegesNode, private ExecInSecurityDb
{
public:
GrantRevokeNode(MemoryPool& p, bool aIsGrant)
: DdlNode(p),
: PrivilegesNode(p),
createDbJobs(p),
isGrant(aIsGrant),
privileges(p),

View File

@ -3661,7 +3661,7 @@ dsc* CurrentRoleNode::execute(thread_db* tdbb, jrd_req* request) const
if (tdbb->getAttachment()->att_user)
{
curRole = tdbb->getAttachment()->att_user->usr_sql_role_name.c_str();
curRole = tdbb->getAttachment()->att_user->getSqlRole().c_str();
impure->vlu_desc.dsc_address = reinterpret_cast<UCHAR*>(const_cast<char*>(curRole));
}
@ -3756,7 +3756,7 @@ dsc* CurrentUserNode::execute(thread_db* tdbb, jrd_req* request) const
if (tdbb->getAttachment()->att_user)
{
curUser = tdbb->getAttachment()->att_user->usr_user_name.c_str();
curUser = tdbb->getAttachment()->att_user->getUserName().c_str();
impure->vlu_desc.dsc_address = reinterpret_cast<UCHAR*>(const_cast<char*>(curUser));
}

View File

@ -491,7 +491,7 @@ void CreateAlterPackageNode::executeCreate(thread_db* tdbb, DsqlCompilerScratch*
jrd_tra* transaction)
{
Attachment* attachment = transaction->getAttachment();
const MetaName& userName = attachment->att_user->usr_user_name;
const MetaName& userName = attachment->att_user->getUserName();
executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_BEFORE,
DDL_TRIGGER_CREATE_PACKAGE, name, NULL);

View File

@ -7916,36 +7916,15 @@ void SetRoleNode::execute(thread_db* tdbb, dsql_req* request, jrd_tra** transact
UserId* user = attachment->att_user;
fb_assert(user);
user->usr_granted_roles.clear();
if (trusted)
{
if (!user->usr_trusted_role.hasData())
Arg::Gds(isc_miss_trusted_role).raise();
user->usr_sql_role_name = user->usr_trusted_role;
}
user->setRoleTrusted();
else
{
if (!SCL_role_granted(tdbb, *user, roleName.c_str()))
(Arg::Gds(isc_set_invalid_role) << roleName).raise();
user->usr_sql_role_name = roleName.c_str();
user->setSqlRole(roleName.c_str());
}
if (!user->usr_sql_role_name.isEmpty() || user->usr_sql_role_name != NULL_ROLE)
{
// Add role itself and all roles cumulatively granted to it. Not only default.
user->usr_granted_roles.add(user->usr_sql_role_name);
SCL_find_granted_roles(tdbb, user->usr_sql_role_name, true, user->usr_granted_roles, false);
}
// Add all default roles granted to user
SCL_find_granted_roles(tdbb, user->usr_user_name, false, user->usr_granted_roles, true);
if (SCL_admin_role(tdbb, user->usr_granted_roles))
user->usr_flags |= USR_dba;
else
user->usr_flags &= ~USR_dba;
SCL_release_all(attachment->att_security_classes);
}

View File

@ -591,7 +591,10 @@ using namespace Firebird;
// tokens added for Firebird 4.0
%token <metaNamePtr> PRIVILEGE
%token <metaNamePtr> RDB_ROLE_IN_USE
%token <metaNamePtr> RDB_SYSTEM_PRIVILEGE
%token <metaNamePtr> SYSTEM
// precedence declarations for expression evaluation
@ -724,6 +727,7 @@ using namespace Firebird;
Jrd::MappingNode* mappingNode;
Jrd::MappingNode::OP mappingOp;
Jrd::SetRoleNode* setRoleNode;
Jrd::CreateAlterRoleNode* createAlterRoleNode;
}
%include types.y
@ -1180,6 +1184,8 @@ grantee($granteeArray)
{ $granteeArray->add(GranteeClause(obj_view, *$2)); }
| ROLE symbol_role_name
{ $granteeArray->add(GranteeClause(obj_sql_role, *$2)); }
| SYSTEM PRIVILEGE valid_symbol_name
{ $granteeArray->add(GranteeClause(obj_privilege, *$3)); }
;
// CVC: In the future we can deprecate the first implicit form since we'll support
@ -1390,7 +1396,7 @@ create_clause
| DATABASE db_clause { $$ = $2; }
| KW_DOMAIN domain_clause { $$ = $2; }
| SHADOW shadow_clause { $$ = $2; }
| ROLE role_clause { $$ = $2; }
| ROLE role_clause { $2->createFlag = true; $$ = $2; }
| COLLATION collation_clause { $$ = $2; }
| USER create_user_clause { $$ = $2; }
| PACKAGE package_clause { $$ = $2; }
@ -1788,11 +1794,40 @@ sequence_value
;
// CREATE ROLE
// CREATE / ALTER ROLE
%type <ddlNode> role_clause
%type <createAlterRoleNode> role_clause
role_clause
: symbol_role_name { $$ = newNode<CreateRoleNode>(*$1); }
: symbol_role_name
{ $$ = newNode<CreateAlterRoleNode>(*$1); }
opt_system_privileges($2)
{ $$ = $2; }
;
%type opt_system_privileges(<createAlterRoleNode>)
opt_system_privileges($createAlterRole)
: // nothing
| set_system_privileges($createAlterRole)
| drop_system_privileges($createAlterRole)
;
%type set_system_privileges(<createAlterRoleNode>)
set_system_privileges($createAlterRole)
: SET SYSTEM PRIVILEGES TO system_privileges_list($createAlterRole)
%type drop_system_privileges(<createAlterRoleNode>)
drop_system_privileges($createAlterRole)
: DROP SYSTEM PRIVILEGES { $createAlterRole->sysPrivDrop = true; }
%type system_privileges_list(<createAlterRoleNode>)
system_privileges_list($createAlterRole)
: system_privilege($createAlterRole)
| system_privileges_list ',' system_privilege($createAlterRole)
;
%type system_privilege(<createAlterRoleNode>)
system_privilege($createAlterRole)
: valid_symbol_name { $createAlterRole->addPrivilege($1); }
;
@ -3976,22 +4011,29 @@ module_op
| MODULE_NAME utf_string { $$ = $2; }
;
%type <mappingNode> alter_role_clause
alter_role_clause
%type <ddlNode> alter_role_2X_compatibility
alter_role_2X_compatibility
: symbol_role_name alter_role_enable AUTO ADMIN MAPPING
{
$$ = newNode<MappingNode>(MappingNode::MAP_RPL, "AutoAdminImplementationMapping");
$$->op = $2 ? MappingNode::MAP_RPL : MappingNode::MAP_DROP;
$$->from = newNode<IntlString>(FB_DOMAIN_ANY_RID_ADMINS);
$$->fromType = newNode<MetaName>(FB_PREDEFINED_GROUP);
$$->mode = 'P';
$$->plugin = newNode<MetaName>("Win_Sspi");
$$->role = true;
$$->to = $1;
$$->validateAdmin();
MappingNode* mn = newNode<MappingNode>(MappingNode::MAP_RPL, "AutoAdminImplementationMapping");
mn->op = $2 ? MappingNode::MAP_RPL : MappingNode::MAP_DROP;
mn->from = newNode<IntlString>(FB_DOMAIN_ANY_RID_ADMINS);
mn->fromType = newNode<MetaName>(FB_PREDEFINED_GROUP);
mn->mode = 'P';
mn->plugin = newNode<MetaName>("Win_Sspi");
mn->role = true;
mn->to = $1;
mn->validateAdmin();
$$ = mn;
}
;
%type <ddlNode> alter_role_clause
alter_role_clause
: role_clause { $$ = $1; }
| alter_role_2X_compatibility { $$ = $1; }
;
%type <boolVal> alter_role_enable
alter_role_enable
: SET { $$ = true; }
@ -7154,6 +7196,11 @@ system_function_special_syntax
}
| POSITION '(' value_list_opt ')'
{ $$ = newNode<SysFuncCallNode>(*$1, $3); }
| RDB_SYSTEM_PRIVILEGE '(' valid_symbol_name ')'
{
ValueExprNode* v = MAKE_str_constant(newIntlString($3->c_str()), CS_ASCII);
$$ = newNode<SysFuncCallNode>(*$1, newNode<ValueListNode>(v));
}
;
%type <valueExprNode> string_value_function
@ -7736,6 +7783,7 @@ non_reserved_word
| PASSWORD
// | PLAN
// | POST_EVENT
| PRIVILEGE
| PRIVILEGES
| PROTECTED
| READ
@ -7755,6 +7803,7 @@ non_reserved_word
| STATISTICS
| SUB_TYPE
| SUSPEND
| SYSTEM
| TRANSACTION
| UNCOMMITTED
// | VARIABLE
@ -7798,6 +7847,7 @@ non_reserved_word
| INCREMENT
| TRUSTED
| RDB_ROLE_IN_USE // added in FB 4.0
| RDB_SYSTEM_PRIVILEGE
;
%%

View File

@ -99,7 +99,7 @@ void JRDMET_init( gpre_dbb* db)
field->fld_charset_id = CS_NONE;
field->fld_collate_id = COLLATE_NONE;
field->fld_ttype = ttype_none;
field->fld_ttype = gfield->gfld_sub_type == dsc_text_type_fixed ? ttype_binary : ttype_none;
}
++field->fld_length;

View File

@ -812,6 +812,8 @@ static const struct {
{"bad_crypt_key", 335545108},
{"encrypt_error", 335545109},
{"max_idx_depth", 335545110},
{"wrong_prvlg", 335545111},
{"miss_prvlg", 335545112},
{"gfix_db_name", 335740929},
{"gfix_invalid_sw", 335740930},
{"gfix_incmp_sw", 335740932},

View File

@ -846,6 +846,8 @@ const ISC_STATUS isc_already_opened = 335545107L;
const ISC_STATUS isc_bad_crypt_key = 335545108L;
const ISC_STATUS isc_encrypt_error = 335545109L;
const ISC_STATUS isc_max_idx_depth = 335545110L;
const ISC_STATUS isc_wrong_prvlg = 335545111L;
const ISC_STATUS isc_miss_prvlg = 335545112L;
const ISC_STATUS isc_gfix_db_name = 335740929L;
const ISC_STATUS isc_gfix_invalid_sw = 335740930L;
const ISC_STATUS isc_gfix_incmp_sw = 335740932L;
@ -1317,7 +1319,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 = 1261;
const ISC_STATUS isc_err_max = 1263;
#else /* c definitions */
@ -2133,6 +2135,8 @@ const ISC_STATUS isc_err_max = 1261;
#define isc_bad_crypt_key 335545108L
#define isc_encrypt_error 335545109L
#define isc_max_idx_depth 335545110L
#define isc_wrong_prvlg 335545111L
#define isc_miss_prvlg 335545112L
#define isc_gfix_db_name 335740929L
#define isc_gfix_invalid_sw 335740930L
#define isc_gfix_incmp_sw 335740932L
@ -2604,7 +2608,7 @@ const ISC_STATUS isc_err_max = 1261;
#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 1261
#define isc_err_max 1263
#endif

View File

@ -452,6 +452,7 @@
const USHORT f_rol_desc = 2;
const USHORT f_rol_sys_flag = 3;
const USHORT f_rol_class = 4;
const USHORT f_rol_sys_priv = 5;
// Relation 32 (RDB$BACKUP_HISTORY)

View File

@ -815,6 +815,8 @@ Data source : @4"}, /* eds_statement */
{335545108, "Invalid crypt key @1"}, /* bad_crypt_key */
{335545109, "Page requires encyption but crypt plugin is missing"}, /* encrypt_error */
{335545110, "Maximum index depth (@1 levels) is reached"}, /* max_idx_depth */
{335545111, "System privilege @1 does not exist"}, /* wrong_prvlg */
{335545112, "Unable to perform operation: system privilege @1 is missing"}, /* miss_prvlg */
{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

@ -811,6 +811,8 @@ static const struct {
{335545108, -902}, /* 788 bad_crypt_key */
{335545109, -901}, /* 789 encrypt_error */
{335545110, -904}, /* 790 max_idx_depth */
{335545111, -901}, /* 791 wrong_prvlg */
{335545112, -902}, /* 792 miss_prvlg */
{335740929, -901}, /* 1 gfix_db_name */
{335740930, -901}, /* 2 gfix_invalid_sw */
{335740932, -901}, /* 4 gfix_incmp_sw */

View File

@ -811,6 +811,8 @@ static const struct {
{335545108, "08006"}, // 788 bad_crypt_key
{335545109, "XX000"}, // 789 encrypt_error
{335545110, "54000"}, // 790 max_idx_depth
{335545111, "0A000"}, // 791 wrong_prvlg
{335545112, "28000"}, // 792 miss_prvlg
{335740929, "00000"}, // 1 gfix_db_name
{335740930, "00000"}, // 2 gfix_invalid_sw
{335740932, "00000"}, // 4 gfix_incmp_sw

View File

@ -1150,10 +1150,13 @@ static processing_state list_all_grants2(bool show_role_list, const SCHAR* termi
if (isqlGlob.db_SQL_dialect > SQL_DIALECT_V6_TRANSITION)
{
IUTILS_copy_SQL_id (XX.RDB$ROLE_NAME, SQL_identifier, DBL_QUOTE);
isqlGlob.printf("CREATE ROLE %s;%s", SQL_identifier, NEWLINE);
isqlGlob.printf("CREATE ROLE %s", SQL_identifier);
}
else
isqlGlob.printf("CREATE ROLE %s;%s", XX.RDB$ROLE_NAME, NEWLINE);
isqlGlob.printf("CREATE ROLE %s", XX.RDB$ROLE_NAME);
SHOW_system_privileges(XX.RDB$ROLE_NAME, " SET SYSTEM PRIVILEGES TO", false);
isqlGlob.printf(";%s", NEWLINE);
}
END_FOR

View File

@ -3639,7 +3639,7 @@ static processing_state create_db(const TEXT* statement, TEXT* d_name)
* Parameters: statement == the entire statement for processing.
*
* Note: SQL ROLE setting must be taken into an account no matter
* that the newly created database will not have any roles defined
* that the newly created database will not have any user roles defined
* in it. Role may affect right to create new database.
*
**************************************/

View File

@ -265,6 +265,7 @@ const int NUMBER_FREE_PAGES = 191; // Number of free DB pages = @1
const int DATABASE_CRYPTED = 192; // DB encrypted
const int DATABASE_NOT_CRYPTED = 193; // DB not encrypted
const int DATABASE_CRYPT_PROCESS = 194; // crypt thread not complete
const int MSG_ROLES = 195; // Roles:
// Initialize types

View File

@ -104,7 +104,7 @@ static void show_index(SCHAR*, SCHAR*, const SSHORT, const SSHORT, const SSHORT)
static processing_state show_indices(const SCHAR* const*);
static processing_state show_proc(const SCHAR*);
static processing_state show_packages(const SCHAR* package_name);
static processing_state show_role(const SCHAR*);
static processing_state show_role(const SCHAR*, bool, const char* msg = 0);
static processing_state show_secclass(const char* object, const char* opt);
static processing_state show_table(const SCHAR*, bool);
static processing_state show_trigger(const SCHAR*, bool, bool);
@ -636,7 +636,7 @@ static const char* granted_by(char* buffer, const char* grantor, bool nullGranto
if (reReadDbOwner)
{
// Get the owner name
strcpy(owner, SYSDBA_USER_NAME);
strcpy(owner, DBA_USER_NAME);
FOR REL IN RDB$RELATIONS WITH
REL.RDB$RELATION_NAME = "RDB$DATABASE"
@ -700,6 +700,15 @@ static void set_grantee(int user_type, const char* SQL_identifier, char* user_st
case obj_package_header:
sprintf(user_string, "PACKAGE %s", SQL_identifier);
break;
case obj_privilege:
FOR T IN RDB$TYPES
WITH T.RDB$FIELD_NAME EQ 'RDB$SYSTEM_PRIVILEGES'
AND T.RDB$TYPE EQ atoi(SQL_identifier)
{
sprintf(user_string, "SYSTEM PRIVILEGE %s", fb_utils::exact_name(T.RDB$TYPE_NAME));
}
END_FOR
break;
default:
strcpy(user_string, SQL_identifier);
break;
@ -770,6 +779,7 @@ processing_state SHOW_grants2 (const SCHAR* object,
FOR PRV IN RDB$USER_PRIVILEGES CROSS
REL IN RDB$RELATIONS WITH
PRV.RDB$GRANTOR NOT MISSING AND
PRV.RDB$RELATION_NAME EQ object AND
REL.RDB$RELATION_NAME EQ object AND
PRV.RDB$PRIVILEGE NE 'M' AND
@ -952,6 +962,7 @@ processing_state SHOW_grants2 (const SCHAR* object,
FOR PRV IN RDB$USER_PRIVILEGES CROSS
PRC IN RDB$PROCEDURES WITH
PRV.RDB$GRANTOR NOT MISSING AND
PRV.RDB$OBJECT_TYPE = obj_procedure AND
PRV.RDB$RELATION_NAME EQ object AND
PRC.RDB$PROCEDURE_NAME EQ object AND
@ -1031,6 +1042,7 @@ processing_state SHOW_grants2 (const SCHAR* object,
FOR FIRST 1 R IN RDB$ROLES WITH R.RDB$ROLE_NAME EQ object
FOR PRV IN RDB$USER_PRIVILEGES WITH
PRV.RDB$GRANTOR NOT MISSING AND
PRV.RDB$OBJECT_TYPE EQ obj_sql_role AND
(PRV.RDB$USER_TYPE EQ obj_user OR
PRV.RDB$USER_TYPE EQ obj_sql_role) AND
@ -1090,6 +1102,7 @@ processing_state SHOW_grants2 (const SCHAR* object,
FOR FIRST 1 P IN RDB$PACKAGES WITH P.RDB$PACKAGE_NAME EQ object
FOR PRV IN RDB$USER_PRIVILEGES CROSS
PACK IN RDB$PACKAGES WITH
PRV.RDB$GRANTOR NOT MISSING AND
PRV.RDB$OBJECT_TYPE = obj_package_header AND
PRV.RDB$RELATION_NAME EQ object AND
PACK.RDB$PACKAGE_NAME EQ object AND
@ -1166,6 +1179,7 @@ processing_state SHOW_grants2 (const SCHAR* object,
FOR PRV IN RDB$USER_PRIVILEGES CROSS
FUN IN RDB$FUNCTIONS WITH
PRV.RDB$GRANTOR NOT MISSING AND
PRV.RDB$OBJECT_TYPE = obj_udf AND
PRV.RDB$RELATION_NAME EQ object AND
FUN.RDB$FUNCTION_NAME EQ object AND
@ -1240,6 +1254,7 @@ processing_state SHOW_grants2 (const SCHAR* object,
FOR FIRST 1 G IN RDB$GENERATORS WITH G.RDB$GENERATOR_NAME EQ object
FOR PRV IN RDB$USER_PRIVILEGES CROSS
GEN IN RDB$GENERATORS WITH
PRV.RDB$GRANTOR NOT MISSING AND
PRV.RDB$OBJECT_TYPE = obj_generator AND
PRV.RDB$RELATION_NAME EQ object AND
GEN.RDB$GENERATOR_NAME EQ object AND
@ -1313,6 +1328,7 @@ processing_state SHOW_grants2 (const SCHAR* object,
FOR FIRST 1 E IN RDB$EXCEPTIONS WITH E.RDB$EXCEPTION_NAME EQ object
FOR PRV IN RDB$USER_PRIVILEGES CROSS
XCP IN RDB$EXCEPTIONS WITH
PRV.RDB$GRANTOR NOT MISSING AND
PRV.RDB$OBJECT_TYPE = obj_exception AND
PRV.RDB$RELATION_NAME EQ object AND
XCP.RDB$EXCEPTION_NAME EQ object AND
@ -1387,6 +1403,7 @@ processing_state SHOW_grants2 (const SCHAR* object,
FOR FIRST 1 F IN RDB$FIELDS WITH F.RDB$FIELD_NAME EQ object
FOR PRV IN RDB$USER_PRIVILEGES CROSS
FLD IN RDB$FIELDS WITH
PRV.RDB$GRANTOR NOT MISSING AND
PRV.RDB$OBJECT_TYPE = obj_field AND
PRV.RDB$RELATION_NAME EQ object AND
FLD.RDB$FIELD_NAME EQ object AND
@ -1460,6 +1477,7 @@ processing_state SHOW_grants2 (const SCHAR* object,
FOR FIRST 1 C IN RDB$CHARACTER_SETS WITH C.RDB$CHARACTER_SET_NAME EQ object
FOR PRV IN RDB$USER_PRIVILEGES CROSS
CS IN RDB$CHARACTER_SETS WITH
PRV.RDB$GRANTOR NOT MISSING AND
PRV.RDB$OBJECT_TYPE = obj_charset AND
PRV.RDB$RELATION_NAME EQ object AND
CS.RDB$CHARACTER_SET_NAME EQ object AND
@ -1533,6 +1551,7 @@ processing_state SHOW_grants2 (const SCHAR* object,
FOR FIRST 1 C IN RDB$COLLATIONS WITH C.RDB$COLLATION_NAME EQ object
FOR PRV IN RDB$USER_PRIVILEGES CROSS
COL IN RDB$COLLATIONS WITH
PRV.RDB$GRANTOR NOT MISSING AND
PRV.RDB$OBJECT_TYPE = obj_collation AND
PRV.RDB$RELATION_NAME EQ object AND
COL.RDB$COLLATION_NAME EQ object AND
@ -1605,6 +1624,7 @@ processing_state SHOW_grants2 (const SCHAR* object,
if (isqlGlob.major_ods >= ODS_VERSION12)
{
FOR PRV IN RDB$USER_PRIVILEGES WITH
PRV.RDB$GRANTOR NOT MISSING AND
PRV.RDB$OBJECT_TYPE >= obj_database AND
PRV.RDB$RELATION_NAME EQ object
SORTED BY PRV.RDB$USER, PRV.RDB$GRANT_OPTION
@ -1822,6 +1842,7 @@ void SHOW_grant_roles2 (const SCHAR* terminator,
// process role "object"
FOR PRV IN RDB$USER_PRIVILEGES WITH
PRV.RDB$GRANTOR NOT MISSING AND
PRV.RDB$OBJECT_TYPE EQ obj_sql_role AND
(PRV.RDB$USER_TYPE EQ obj_user OR
PRV.RDB$USER_TYPE EQ obj_sql_role) AND
@ -2090,11 +2111,11 @@ processing_state SHOW_metadata(const SCHAR* const* cmd, SCHAR** lcmd)
if (*cmd[2] == '"')
{
remove_delimited_double_quotes(lcmd[2]);
ret = show_role(lcmd[2]);
ret = show_role(lcmd[2], false);
}
else
{
ret = show_role(cmd[2]);
ret = show_role(cmd[2], false);
}
if (ret == OBJECT_NOT_FOUND)
@ -2102,7 +2123,7 @@ processing_state SHOW_metadata(const SCHAR* const* cmd, SCHAR** lcmd)
}
else
{
ret = show_role(NULL);
ret = show_role(NULL, false);
if (ret == OBJECT_NOT_FOUND)
key = NO_ROLES;
}
@ -2179,6 +2200,10 @@ processing_state SHOW_metadata(const SCHAR* const* cmd, SCHAR** lcmd)
show_all_tables(1);
break;
case ShowOptions::role:
show_role(NULL, true);
break;
default:
return ps_ERR;
}
@ -2193,6 +2218,8 @@ processing_state SHOW_metadata(const SCHAR* const* cmd, SCHAR** lcmd)
show_sys_functions(msg);
IUTILS_msg_get(MSG_COLLATIONS, msg);
show_collations("", 1, msg, true);
IUTILS_msg_get(MSG_ROLES, msg);
show_role(NULL, true, msg);
}
break;
@ -5300,7 +5327,55 @@ static processing_state show_proc(const SCHAR* procname)
}
static processing_state show_role(const SCHAR* object)
bool SHOW_system_privileges(const char* role, const char* prefix, bool lf)
{
bool first = true;
FOR X IN RDB$ROLES WITH
X.RDB$ROLE_NAME EQ role
{
if (!X.RDB$SYSTEM_PRIVILEGES.NULL)
{
for (unsigned byte = 0; byte < sizeof(X.RDB$SYSTEM_PRIVILEGES); ++byte)
{
char b = X.RDB$SYSTEM_PRIVILEGES[byte];
for (int bit = 0; bit < 8; ++bit)
{
if (b & (1 << bit))
{
FOR T IN RDB$TYPES
WITH T.RDB$FIELD_NAME EQ 'RDB$SYSTEM_PRIVILEGES'
AND T.RDB$TYPE EQ (byte * 8 + bit)
{
if (first)
{
if (lf)
isqlGlob.printf("%s", NEWLINE);
isqlGlob.printf("%s", prefix);
}
else
isqlGlob.printf(",");
first = false;
isqlGlob.printf(" %s", fb_utils::exact_name(T.RDB$TYPE_NAME));
}
END_FOR
}
}
}
}
}
END_FOR
ON_ERROR
ISQL_errmsg(fbStatus);
return false;
END_ERROR;
return !first;
}
static processing_state show_role(const SCHAR* object, bool system, const char* msg)
{
if (isqlGlob.major_ods < ODS_VERSION9)
return OBJECT_NOT_FOUND;
@ -5323,13 +5398,21 @@ static processing_state show_role(const SCHAR* object)
bool system_flag = !X.RDB$SYSTEM_FLAG.NULL && X.RDB$SYSTEM_FLAG > 0;
if (!system_flag)
if (system_flag == system)
{
if (first && msg)
isqlGlob.printf("%s%s", msg, NEWLINE);
first = false;
isqlGlob.printf("%38s%s", X.RDB$ROLE_NAME, (odd ? " " : NEWLINE));
odd = !odd;
/*
if (SHOW_system_privileges(X.RDB$ROLE_NAME, "System privileges:", !odd))
{
isqlGlob.printf("%s", NEWLINE);
odd = true;
} */
}
END_FOR
ON_ERROR
ISQL_errmsg(fbStatus);
@ -5402,6 +5485,8 @@ static processing_state show_role(const SCHAR* object)
if (first)
return (OBJECT_NOT_FOUND);
else if (SHOW_system_privileges(object, "System privileges:", false))
isqlGlob.printf("%s", NEWLINE);
return (SKIP);
}

View File

@ -38,5 +38,6 @@ processing_state SHOW_metadata(const SCHAR* const*, SCHAR**);
void SHOW_read_owner();
const Firebird::string SHOW_trigger_action(SINT64);
processing_state SHOW_maps(bool extract, const SCHAR* map_name);
bool SHOW_system_privileges(const char* role, const char* prfx, bool lf);
#endif // ISQL_SHOW_PROTO_H

View File

@ -326,7 +326,7 @@ public:
/// former Database members - end
bool locksmith() const;
bool locksmith(thread_db* tdbb, SystemPrivilege sp) const;
jrd_tra* getSysTransaction();
void setSysTransaction(jrd_tra* trans); // used only by TRA_init
@ -406,9 +406,9 @@ const ULONG ATT_mapping = 0x40000L; // Attachment used for mapping auth block
const ULONG ATT_NO_CLEANUP = (ATT_no_cleanup | ATT_notify_gc);
inline bool Attachment::locksmith() const
inline bool Attachment::locksmith(thread_db* tdbb, SystemPrivilege sp) const
{
return att_user && att_user->locksmith();
return att_user && att_user->locksmith(tdbb, sp);
}
inline jrd_tra* Attachment::getSysTransaction()

View File

@ -677,7 +677,7 @@ namespace Jrd {
// Establish temp context
// Needed to take crypt thread lock
UserId user;
user.usr_user_name = "(Crypt thread)";
user.setUserName("(Crypt thread)");
Jrd::Attachment* const attachment = Jrd::Attachment::create(&dbb);
RefPtr<SysStableAttachment> sAtt(FB_NEW SysStableAttachment(attachment));
@ -707,7 +707,7 @@ namespace Jrd {
// Establish context
// Need real attachment in order to make classic mode happy
ClumpletWriter writer(ClumpletReader::Tagged, MAX_DPB_SIZE, isc_dpb_version1);
writer.insertString(isc_dpb_user_name, SYSDBA_USER_NAME);
writer.insertString(isc_dpb_user_name, DBA_USER_NAME);
writer.insertByte(isc_dpb_no_db_triggers, TRUE);
RefPtr<JAttachment> jAtt(REF_NO_INCR, dbb.dbb_provider->attachDatabase(&status_vector,

View File

@ -54,6 +54,7 @@
using namespace Firebird;
using namespace Jrd;
using namespace Auth;
namespace {
@ -69,16 +70,15 @@ void check(const char* s, IStatus* st)
bool openDb(const char* securityDb, RefPtr<IAttachment>& att, RefPtr<ITransaction>& tra)
{
DispatcherPtr prov;
ClumpletWriter embeddedSysdba(ClumpletWriter::Tagged, MAX_DPB_SIZE, isc_dpb_version1);
embeddedSysdba.insertString(isc_dpb_user_name, SYSDBA_USER_NAME, fb_strlen(SYSDBA_USER_NAME));
embeddedSysdba.insertByte(isc_dpb_sec_attach, TRUE);
embeddedSysdba.insertByte(isc_dpb_no_db_triggers, TRUE);
ClumpletWriter embeddedAttach(ClumpletWriter::Tagged, MAX_DPB_SIZE, isc_dpb_version1);
embeddedAttach.insertString(isc_dpb_user_name, DBA_USER_NAME, fb_strlen(DBA_USER_NAME));
embeddedAttach.insertByte(isc_dpb_sec_attach, TRUE);
embeddedAttach.insertByte(isc_dpb_no_db_triggers, TRUE);
FbLocalStatus st;
DispatcherPtr prov;
att = prov->attachDatabase(&st, securityDb,
embeddedSysdba.getBufferLength(), embeddedSysdba.getBuffer());
embeddedAttach.getBufferLength(), embeddedAttach.getBuffer());
if (st->getState() & IStatus::STATE_ERRORS)
{
if (!fb_utils::containsErrorCode(st->getErrors(), isc_io_error))
@ -105,17 +105,16 @@ namespace Jrd {
bool checkCreateDatabaseGrant(const MetaName& userName, const MetaName& trustedRole,
const MetaName& sqlRole, const char* securityDb)
{
if (userName == SYSDBA_USER_NAME)
if (userName == DBA_USER_NAME)
return true;
RefPtr<IAttachment> att;
RefPtr<ITransaction> tra;
if (!openDb(securityDb, att, tra))
return false;
bool hasDb = openDb(securityDb, att, tra);
FbLocalStatus st;
MetaName role(sqlRole);
if (role.hasData())
if (hasDb && role.hasData())
{
const UCHAR info[] = { isc_info_db_sql_dialect, isc_info_end };
UCHAR buffer[BUFFER_TINY];
@ -140,9 +139,9 @@ bool checkCreateDatabaseGrant(const MetaName& userName, const MetaName& trustedR
p += length;
}
JRD_make_role_name(role, dialect);
UserId::makeRoleName(role, dialect);
// We need to check is admin role granted to userName in security DB
// We need to check is role granted to userName in security DB
const char* sql = "select count(*) from RDB$USER_PRIVILEGES "
"where RDB$USER = ? and RDB$RELATION_NAME = ? and RDB$PRIVILEGE = 'M'";
@ -176,6 +175,10 @@ bool checkCreateDatabaseGrant(const MetaName& userName, const MetaName& trustedR
if (role == ADMIN_ROLE)
return true;
if (!hasDb)
return false;
// check db creators table
Message gr;
Field<ISC_SHORT> uType(gr);
Field<Varying> u(gr, MAX_SQL_IDENTIFIER_LEN);
@ -204,7 +207,49 @@ bool checkCreateDatabaseGrant(const MetaName& userName, const MetaName& trustedR
check("IAttachment::execute", &st);
}
return cnt > 0;
if (cnt > 0)
return true;
if (!role.hasData())
role = "NONE";
Message par2;
Field<ISC_SHORT> uType2(par2);
Field<Varying> u2(par2, MAX_SQL_IDENTIFIER_LEN);
Field<Varying> r2(par2, MAX_SQL_IDENTIFIER_LEN);
uType2 = obj_user;
u2 = userName.c_str();
r2 = role.c_str();
Message res2;
Field<Text> priv(res2, 8);
const char* sql =
"with recursive role_tree as ( "
" select rdb$relation_name as nm, 0 as ur from rdb$user_privileges "
" where rdb$privilege = 'M' and rdb$field_name = 'D' and rdb$user_type = ? and rdb$user = ? "
" union all "
" select rdb$role_name as nm, 1 as ur from rdb$roles "
" where rdb$role_name = ? "
" union all "
" select p.rdb$relation_name as nm, t.ur from rdb$user_privileges p "
" join role_tree t on t.nm = p.rdb$user "
" where p.rdb$privilege = 'M' and (p.rdb$field_name = 'D' or t.ur = 1)) "
"select r.rdb$system_privileges "
" from role_tree t join rdb$roles r on t.nm = r.rdb$role_name ";
RefPtr<IResultSet> rs(att->openCursor(&st, tra, 0, sql,
SQL_DIALECT_V6, par2.getMetadata(), par2.getBuffer(), res2.getMetadata(), NULL, 0));
check("IAttachment::execute", &st);
UserId::Privileges privileges, wrk;
while (rs->fetchNext(&st, res2.getBuffer()) == IStatus::RESULT_OK)
{
wrk.load(&priv);
privileges |= wrk;
}
check("IResultSet::fetchNext", &st);
return wrk.test(CREATE_DATABASE);
}

View File

@ -662,7 +662,7 @@ Firebird::ITransaction* ExtEngineManager::ExternalContextImpl::getTransaction(
const char* ExtEngineManager::ExternalContextImpl::getUserName()
{
return internalAttachment->att_user->usr_user_name.c_str();
return internalAttachment->att_user->getUserName().c_str();
}
const char* ExtEngineManager::ExternalContextImpl::getDatabaseName()

View File

@ -551,6 +551,8 @@ void resetMap(const char* securityDb)
MAP_DEBUG(fprintf(stderr, "Empty cache for %s\n", securityDb));
}
void resetMap(const char* securityDb, ULONG index);
// ----------------------------------------------------
@ -559,7 +561,8 @@ class MappingHeader : public Firebird::MemoryHeader
public:
SLONG currentProcess;
ULONG processes;
char databaseForReset[1024];
char databaseForReset[1024]; // database for which cache to be reset
ULONG resetIndex; // what cache to reset
struct Process
{
@ -617,7 +620,7 @@ public:
sharedMemory->removeMapFile();
}
void clearMap(const char* dbName)
void clearCache(const char* dbName, USHORT index)
{
PathName target;
expandDatabaseName(dbName, target, NULL);
@ -628,6 +631,7 @@ public:
MappingHeader* sMem = sharedMemory->getHeader();
target.copyTo(sMem->databaseForReset, sizeof(sMem->databaseForReset));
sMem->resetIndex = index;
// Set currentProcess
sMem->currentProcess = -1;
@ -648,7 +652,7 @@ public:
{
// did not find current process
// better ignore delivery than fail in it
gds__log("MappingIpc::clearMap() failed to find current process %d in shared memory", processId);
gds__log("MappingIpc::clearCache() failed to find current process %d in shared memory", processId);
return;
}
MappingHeader::Process* current = &sMem->process[sMem->currentProcess];
@ -662,8 +666,8 @@ public:
if (p->id == processId)
{
MAP_DEBUG(fprintf(stderr, "Internal resetMap(%s)\n", sMem->databaseForReset));
resetMap(sMem->databaseForReset);
MAP_DEBUG(fprintf(stderr, "Internal resetMap(%s, %d)\n", sMem->databaseForReset, sMem->resetIndex));
resetMap(sMem->databaseForReset, sMem->resetIndex);
continue;
}
@ -770,9 +774,9 @@ private:
if (p->flags & MappingHeader::FLAG_DELIVER)
{
resetMap(sharedMemory->getHeader()->databaseForReset);
MappingHeader* sMem = sharedMemory->getHeader();
resetMap(sMem->databaseForReset, sMem->resetIndex);
MappingHeader::Process* cur = &sMem->process[sMem->currentProcess];
if (sharedMemory->eventPost(&cur->callbackEvent) != FB_SUCCESS)
{
@ -877,14 +881,246 @@ void setupIpc()
mappingIpc->setup();
}
class DbHandle : public AutoPtr<IAttachment, SimpleRelease<IAttachment> >
{
public:
DbHandle()
: AutoPtr()
{ }
DbHandle(IAttachment* att)
: AutoPtr(att)
{
if (att)
att->addRef();
}
bool attach(FbLocalStatus& st, const char* aliasDb, ICryptKeyCallback* cryptCb)
{
bool down = false; // true if on attach db is shutdown
if (hasData())
return down;
DispatcherPtr prov;
if (cryptCb)
{
prov->setDbCryptCallback(&st, cryptCb);
check("IProvider::setDbCryptCallback", &st);
}
ClumpletWriter embeddedSysdba(ClumpletWriter::Tagged, 1024, isc_dpb_version1);
embeddedSysdba.insertString(isc_dpb_user_name, DBA_USER_NAME, fb_strlen(DBA_USER_NAME));
embeddedSysdba.insertByte(isc_dpb_sec_attach, TRUE);
embeddedSysdba.insertByte(isc_dpb_map_attach, TRUE);
embeddedSysdba.insertByte(isc_dpb_no_db_triggers, TRUE);
IAttachment* att = prov->attachDatabase(&st, aliasDb,
embeddedSysdba.getBufferLength(), embeddedSysdba.getBuffer());
if (st->getState() & IStatus::STATE_ERRORS)
{
const ISC_STATUS* s = st->getErrors();
bool missing = fb_utils::containsErrorCode(s, isc_io_error);
down = fb_utils::containsErrorCode(s, isc_shutdown);
if (!(missing || down))
check("IProvider::attachDatabase", &st);
// down/missing security DB is not a reason to fail mapping
}
else
reset(att);
return down;
}
};
const char* roleSql =
"with recursive role_tree as ( "
" select rdb$role_name as nm from rdb$roles "
" where rdb$role_name = ? "
" union all "
" select p.rdb$relation_name as nm from rdb$user_privileges p "
" join role_tree t on t.nm = p.rdb$user "
" where p.rdb$privilege = 'M') "
"select r.rdb$system_privileges from role_tree t "
" join rdb$roles r on t.nm = r.rdb$role_name "
;
const char* userSql =
"with recursive role_tree as ( "
" select rdb$relation_name as nm from rdb$user_privileges "
" where rdb$privilege = 'M' and rdb$field_name = 'D' and rdb$user = ? and rdb$user_type = 8 "
" union all "
" select p.rdb$relation_name as nm from rdb$user_privileges p "
" join role_tree t on t.nm = p.rdb$user "
" where p.rdb$privilege = 'M' and p.rdb$field_name = 'D') "
"select r.rdb$system_privileges from role_tree t "
" join rdb$roles r on t.nm = r.rdb$role_name "
;
class SysPrivCache : public PermanentStorage
{
public:
SysPrivCache(MemoryPool& p)
: PermanentStorage(p),
databases(getPool())
{ }
SyncObject* getSync()
{
return &sync;
}
bool getPrivileges(const PathName& db, const string& name, const string& trusted_role, UserId::Privileges& system_privileges)
{
DbCache* c;
return databases.get(db, c) && c->getPrivileges(name, trusted_role, system_privileges);
}
void populate(const PathName& db, DbHandle& iDb, const string& name, const string& trusted_role)
{
DbCache* c;
if (!databases.get(db, c))
{
c = FB_NEW_POOL(getPool()) DbCache(getPool());
*(databases.put(db)) = c;
}
c->populate(iDb, name, trusted_role);
setupIpc();
}
void invalidate(const PathName& db)
{
DbCache* c;
if (databases.get(db, c))
c->invalidate();
}
private:
class DbCache
{
public:
DbCache(MemoryPool& p)
: logins(p, userSql),
roles(p, roleSql)
{ }
bool getPrivileges(const string& name, const string& trusted_role, UserId::Privileges& system_privileges)
{
system_privileges.clearAll();
return logins.getPrivileges(name, system_privileges) &&
roles.getPrivileges(trusted_role, system_privileges);
}
void populate(DbHandle& iDb, const string& name, const string& trusted_role)
{
logins.populate(name, iDb);
roles.populate(trusted_role, iDb);
}
void invalidate()
{
logins.invalidate();
roles.invalidate();
}
private:
class NameCache : private GenericMap<Pair<Left<string, UserId::Privileges> > >
{
public:
NameCache(MemoryPool& p, const char* s)
: GenericMap(p),
sql(s)
{ }
bool getPrivileges(const string& key, UserId::Privileges& system_privileges)
{
if (!key.hasData())
return false;
UserId::Privileges p;
if (!get(key, p))
return false;
system_privileges |= p;
return true;
}
void populate(const string& key, DbHandle& iDb)
{
if (!key.hasData())
return;
ThrowLocalStatus st;
RefPtr<ITransaction> tra(REF_NO_INCR, iDb->startTransaction(&st, 0, NULL));
Message par;
Field<Varying> user(par, MAX_SQL_IDENTIFIER_SIZE);
user = key.c_str();
RefPtr<IResultSet> curs(REF_NO_INCR, iDb->openCursor(&st, tra, 0, sql, 3,
par.getMetadata(), par.getBuffer(), NULL, NULL, 0));
RefPtr<IMessageMetadata> meta(curs->getMetadata(&st));
AutoPtr<UCHAR, ArrayDelete<UCHAR> > buffer(FB_NEW UCHAR[meta->getMessageLength(&st)]);
UCHAR* bits = buffer + meta->getOffset(&st, 0);
UserId::Privileges g, l;
while(curs->fetchNext(&st, buffer) == IStatus::RESULT_OK)
{
l.load(bits);
g |= l;
}
put(key, g);
}
void invalidate()
{
clear();
}
private:
const char* sql;
};
NameCache logins, roles;
};
SyncObject sync;
GenericMap<Pair<Left<PathName, DbCache*> > > databases;
};
InitInstance<SysPrivCache> spCache;
void resetMap(const char* db, ULONG index)
{
switch(index)
{
case MAPPING_CACHE:
resetMap(db);
break;
case SYSTEM_PRIVILEGES_CACHE:
spCache().invalidate(db);
break;
default:
fb_assert(false);
break;
}
}
} // anonymous namespace
namespace Jrd {
bool mapUser(string& name, string& trusted_role, Firebird::string* auth_method,
AuthReader::AuthBlock* newAuthBlock, const AuthReader::AuthBlock& authBlock,
const char* alias, const char* db, const char* securityAlias,
ICryptKeyCallback* cryptCb)
ULONG mapUser(const bool throwNotFoundError,
string& name, string& trusted_role, Firebird::string* auth_method,
AuthReader::AuthBlock* newAuthBlock, UserId::Privileges* system_privileges,
const AuthReader::AuthBlock& authBlock, const char* alias, const char* db,
const char* securityAlias, ICryptKeyCallback* cryptCb, Firebird::IAttachment* att)
{
AuthReader::Info info;
@ -903,7 +1139,7 @@ bool mapUser(string& name, string& trusted_role, Firebird::string* auth_method,
}
}
return false;
return 0;
}
// expand security database name (db is expected to be expanded, alias - original)
@ -912,6 +1148,8 @@ bool mapUser(string& name, string& trusted_role, Firebird::string* auth_method,
const char* securityDb = secExpanded.c_str();
bool secDown = false;
bool dbDown = false;
DbHandle iDb(att);
FbLocalStatus st;
// Create new writer
AuthWriter newBlock;
@ -928,69 +1166,21 @@ bool mapUser(string& name, string& trusted_role, Firebird::string* auth_method,
}
// Perform lock & map only when needed
if (flags != (FLAG_DB | FLAG_SEC))
if ((flags != (FLAG_DB | FLAG_SEC)) && authBlock.hasData())
{
AuthReader::Info info;
SyncType syncType = SYNC_SHARED;
IAttachment* iDb = NULL;
IAttachment* iSec = NULL;
FbLocalStatus st;
DbHandle iSec;
try
{
for (;;)
{
if (syncType == SYNC_EXCLUSIVE)
{
DispatcherPtr prov;
if (cryptCb)
{
prov->setDbCryptCallback(&st, cryptCb);
check("IProvider::setDbCryptCallback", &st);
}
ClumpletWriter embeddedSysdba(ClumpletWriter::Tagged,
MAX_DPB_SIZE, isc_dpb_version1);
embeddedSysdba.insertString(isc_dpb_user_name, SYSDBA_USER_NAME,
fb_strlen(SYSDBA_USER_NAME));
embeddedSysdba.insertByte(isc_dpb_sec_attach, TRUE);
embeddedSysdba.insertByte(isc_dpb_map_attach, TRUE);
embeddedSysdba.insertByte(isc_dpb_no_db_triggers, TRUE);
if (!iSec)
{
iSec = prov->attachDatabase(&st, securityAlias,
embeddedSysdba.getBufferLength(), embeddedSysdba.getBuffer());
if (st->getState() & IStatus::STATE_ERRORS)
{
const ISC_STATUS* s = st->getErrors();
bool missing = fb_utils::containsErrorCode(s, isc_io_error);
secDown = fb_utils::containsErrorCode(s, isc_shutdown);
if (!(missing || secDown))
check("IProvider::attachDatabase", &st);
// down/missing security DB is not a reason to fail mapping
iSec = NULL;
}
}
iSec.attach(st, securityAlias, cryptCb);
if (db && !iDb)
{
iDb = prov->attachDatabase(&st, alias,
embeddedSysdba.getBufferLength(), embeddedSysdba.getBuffer());
if (st->getState() & IStatus::STATE_ERRORS)
{
const ISC_STATUS* s = st->getErrors();
bool missing = fb_utils::containsErrorCode(s, isc_io_error);
dbDown = fb_utils::containsErrorCode(s, isc_shutdown);
if (!(missing || dbDown))
check("IProvider::attachDatabase", &st);
// down/missing DB is not a reason to fail mapping
iDb = NULL;
}
}
iDb.attach(st, alias, cryptCb);
}
MutexEnsureUnlock g(treeMutex, FB_FUNCTION);
@ -1063,28 +1253,6 @@ bool mapUser(string& name, string& trusted_role, Firebird::string* auth_method,
break;
}
if (iDb)
{
iDb->detach(&st);
check("IAttachment::detach", &st);
iDb = NULL;
}
if (iSec)
{
iSec->detach(&st);
check("IAttachment::detach", &st);
iSec = NULL;
}
}
catch (const Exception&)
{
if (iDb)
iDb->release();
if (iSec)
iSec->release();
throw;
}
for (AuthReader rdr(newBlock); rdr.getInfo(info); rdr.moveNext())
{
if (db && info.secDb == db)
@ -1134,15 +1302,21 @@ bool mapUser(string& name, string& trusted_role, Firebird::string* auth_method,
}
}
ULONG rc = secDown || dbDown ? MAPUSER_MAP_DOWN : 0;
if (fName.found == Found::FND_NOTHING)
{
if (throwNotFoundError)
{
Arg::Gds v(isc_sec_context);
v << alias;
if (secDown || dbDown)
if (rc & MAPUSER_MAP_DOWN)
v << Arg::Gds(isc_map_down);
v.raise();
}
rc |= MAPUSER_ERROR_NOT_THROWN;
}
else
{
name = fName.value.ToString();
trusted_role = fRole.value.ToString();
MAP_DEBUG(fprintf(stderr, "login=%s tr=%s\n", name.c_str(), trusted_role.c_str()));
@ -1156,13 +1330,41 @@ bool mapUser(string& name, string& trusted_role, Firebird::string* auth_method,
MAP_DEBUG(fprintf(stderr, "Saved to newAuthBlock %u bytes\n",
static_cast<unsigned>(newAuthBlock->getCount())));
}
return secDown || dbDown;
}
void clearMap(const char* dbName)
if (name.hasData() || trusted_role.hasData())
{
mappingIpc->clearMap(dbName);
if (system_privileges && db)
{
system_privileges->clearAll();
Sync sync(spCache().getSync(), FB_FUNCTION);
sync.lock(SYNC_SHARED);
if (!spCache().getPrivileges(db, name, trusted_role, *system_privileges))
{
sync.unlock();
sync.lock(SYNC_EXCLUSIVE);
if (!spCache().getPrivileges(db, name, trusted_role, *system_privileges))
{
if (!iDb)
iDb.attach(st, alias, cryptCb);
if (iDb)
{
spCache().populate(db, iDb, name, trusted_role);
spCache().getPrivileges(db, name, trusted_role, *system_privileges);
}
}
}
}
}
return rc;
}
void clearMappingCache(const char* dbName, USHORT index)
{
mappingIpc->clearCache(dbName, index);
}
const Format* GlobalMappingScan::getFormat(thread_db* tdbb, jrd_rel* relation) const
@ -1210,8 +1412,8 @@ RecordBuffer* MappingList::getList(thread_db* tdbb, jrd_rel* relation)
{
ClumpletWriter embeddedSysdba(ClumpletWriter::Tagged,
MAX_DPB_SIZE, isc_dpb_version1);
embeddedSysdba.insertString(isc_dpb_user_name, SYSDBA_USER_NAME,
fb_strlen(SYSDBA_USER_NAME));
embeddedSysdba.insertString(isc_dpb_user_name, DBA_USER_NAME,
fb_strlen(DBA_USER_NAME));
embeddedSysdba.insertByte(isc_dpb_sec_attach, TRUE);
embeddedSysdba.insertByte(isc_dpb_no_db_triggers, TRUE);

View File

@ -34,13 +34,23 @@
#include "../common/classes/ClumpletReader.h"
#include "../jrd/recsrc/RecordSource.h"
#include "../jrd/Monitoring.h"
#include "../jrd/scl.h"
namespace Jrd {
bool mapUser(Firebird::string& name, Firebird::string& trusted_role, Firebird::string* auth_method,
Firebird::AuthReader::AuthBlock* newAuthBlock, const Firebird::AuthReader::AuthBlock& authBlock,
const char* alias, const char* db, const char* securityDb, Firebird::ICryptKeyCallback* cryptCb);
void clearMap(const char* dbName);
ULONG mapUser(const bool throwNotFoundError,
Firebird::string& name, Firebird::string& trusted_role, Firebird::string* auth_method,
Firebird::AuthReader::AuthBlock* newAuthBlock, UserId::Privileges* system_privileges,
const Firebird::AuthReader::AuthBlock& authBlock, const char* alias, const char* db,
const char* securityDb, Firebird::ICryptKeyCallback* cryptCb, Firebird::IAttachment* att);
// bits returned by mapUser
const ULONG MAPUSER_ERROR_NOT_THROWN = 1;
const ULONG MAPUSER_MAP_DOWN = 2;
void clearMappingCache(const char* dbName, USHORT index);
// possible index values
const USHORT MAPPING_CACHE = 0;
const USHORT SYSTEM_PRIVILEGES_CACHE = 1;
class GlobalMappingScan: public VirtualTableScan
{

View File

@ -391,8 +391,8 @@ MonitoringSnapshot::MonitoringSnapshot(thread_db* tdbb, MemoryPool& pool)
// Enumerate active sessions
const MetaName& user_name = attachment->att_user->usr_user_name;
const bool locksmith = attachment->locksmith();
const MetaName& user_name = attachment->att_user->getUserName();
const bool locksmith = attachment->locksmith(tdbb, MONITOR_ANY_ATTACHMENT);
const char* user_name_ptr = locksmith ? NULL : user_name.c_str();
MonitoringData::SessionList sessions(pool);
@ -876,7 +876,7 @@ void Monitoring::putAttachment(SnapshotData::DumpRecord& record, const Jrd::Atta
ISC_systemToUtf8(attName);
// user (MUST BE ALWAYS THE FIRST ITEM PASSED!)
record.storeString(f_mon_att_user, attachment->att_user->usr_user_name);
record.storeString(f_mon_att_user, attachment->att_user->getUserName());
// attachment id
record.storeInteger(f_mon_att_id, attachment->att_attachment_id);
// process id
@ -886,7 +886,7 @@ void Monitoring::putAttachment(SnapshotData::DumpRecord& record, const Jrd::Atta
// attachment name
record.storeString(f_mon_att_name, attName);
// role
record.storeString(f_mon_att_role, attachment->att_user->usr_sql_role_name);
record.storeString(f_mon_att_role, attachment->att_user->getSqlRole());
// remote protocol
record.storeString(f_mon_att_remote_proto, attachment->att_network_protocol);
// remote address
@ -1240,7 +1240,7 @@ void Monitoring::dumpAttachment(thread_db* tdbb, Attachment* attachment)
attachment->mergeStats();
const AttNumber att_id = attachment->att_attachment_id;
const MetaName& user_name = attachment->att_user->usr_user_name;
const MetaName& user_name = attachment->att_user->getUserName();
if (!dbb->dbb_monitoring_data)
dbb->dbb_monitoring_data = FB_NEW_POOL(pool) MonitoringData(dbb);
@ -1309,7 +1309,7 @@ void Monitoring::publishAttachment(thread_db* tdbb)
if (!dbb->dbb_monitoring_data)
dbb->dbb_monitoring_data = FB_NEW_POOL(*dbb->dbb_permanent) MonitoringData(dbb);
const MetaName& user_name = attachment->att_user->usr_user_name;
const MetaName& user_name = attachment->att_user->getUserName();
MonitoringData::Guard guard(dbb->dbb_monitoring_data);
dbb->dbb_monitoring_data->setup(attachment->att_attachment_id, user_name.c_str());

View File

@ -45,6 +45,7 @@
#include "../jrd/mov_proto.h"
#include "../jrd/pag_proto.h"
#include "../jrd/tra_proto.h"
#include "../jrd/scl_proto.h"
#include "../common/os/guid.h"
#include "../jrd/license.h"
#include "../jrd/trace/TraceManager.h"
@ -186,6 +187,7 @@ dsc* evlRoleInUse(thread_db* tdbb, const SysFunction* function, const NestValueA
dsc* evlRound(thread_db* tdbb, const SysFunction* function, const NestValueArray& args, impure_value* impure);
dsc* evlSign(thread_db* tdbb, const SysFunction* function, const NestValueArray& args, impure_value* impure);
dsc* evlSqrt(thread_db* tdbb, const SysFunction* function, const NestValueArray& args, impure_value* impure);
dsc* evlSystemPrivilege(thread_db* tdbb, const SysFunction* function, const NestValueArray& args, impure_value* impure);
dsc* evlTrunc(thread_db* tdbb, const SysFunction* function, const NestValueArray& args, impure_value* impure);
dsc* evlUuidToChar(thread_db* tdbb, const SysFunction* function, const NestValueArray& args, impure_value* impure);
@ -2231,17 +2233,23 @@ dsc* evlGetContext(thread_db* tdbb, const SysFunction*, const NestValueArray& ar
}
else if (nameStr == CURRENT_USER_NAME)
{
if (!attachment->att_user || attachment->att_user->usr_user_name.isEmpty())
return NULL;
MetaName user;
if (attachment->att_user)
user = attachment->att_user->getUserName();
resultStr = attachment->att_user->usr_user_name.c_str();
if (user.isEmpty())
return NULL;
resultStr = user.c_str();
}
else if (nameStr == CURRENT_ROLE_NAME)
{
if (!attachment->att_user || attachment->att_user->usr_sql_role_name.isEmpty())
return NULL;
MetaName role;
if (attachment->att_user)
role = attachment->att_user->getSqlRole();
resultStr = attachment->att_user->usr_sql_role_name.c_str();
if (role.isEmpty())
return NULL;
resultStr = role.c_str();
}
else if (nameStr == TRANSACTION_ID_NAME)
resultStr.printf("%" SQUADFORMAT, transaction->tra_number);
@ -3803,13 +3811,36 @@ dsc* evlRoleInUse(thread_db* tdbb, const SysFunction*, const NestValueArray& arg
string roleStr(MOV_make_string2(tdbb, value, ttype_none));
roleStr.upper();
impure->vlu_misc.vlu_uchar = attachment->att_user->usr_granted_roles.exist(roleStr) ? 1 : 0;
impure->vlu_misc.vlu_uchar = attachment->att_user->roleInUse(tdbb, roleStr.c_str()) ? FB_TRUE : FB_FALSE;
impure->vlu_desc.makeBoolean(&impure->vlu_misc.vlu_uchar);
return &impure->vlu_desc;
}
dsc* evlSystemPrivilege(thread_db* tdbb, const SysFunction*, const NestValueArray& args,
impure_value* impure)
{
fb_assert(args.getCount() == 1);
jrd_req* request = tdbb->getRequest();
Jrd::Attachment* attachment = tdbb->getAttachment();
const dsc* value = EVL_expr(tdbb, request, args[0]);
if (request->req_flags & req_null) // return NULL if value is NULL
return NULL;
string privStr(MOV_make_string2(tdbb, value, ttype_none));
privStr.upper();
USHORT p = SCL_convert_privilege(tdbb, tdbb->getTransaction(), privStr);
impure->vlu_misc.vlu_uchar = attachment->att_user->locksmith(tdbb, p) ? FB_TRUE : FB_FALSE;
impure->vlu_desc.makeBoolean(&impure->vlu_misc.vlu_uchar);
return &impure->vlu_desc;
}
} // anonymous namespace
@ -3862,6 +3893,7 @@ const SysFunction SysFunction::functions[] =
{RDB_GET_CONTEXT, 2, 2, setParamsGetSetContext, makeGetSetContext, evlGetContext, NULL},
{"RDB$ROLE_IN_USE", 1, 1, setParamsAsciiVal, makeBooleanResult, evlRoleInUse, NULL},
{RDB_SET_CONTEXT, 3, 3, setParamsGetSetContext, makeGetSetContext, evlSetContext, NULL},
{"RDB$SYSTEM_PRIVILEGE", 1, 1, setParamsAsciiVal, makeBooleanResult, evlSystemPrivilege, NULL},
{"REPLACE", 3, 3, setParamsFromList, makeReplace, evlReplace, NULL},
{"REVERSE", 1, 1, NULL, makeReverse, evlReverse, NULL},
{"RIGHT", 2, 2, setParamsSecondInteger, makeLeftRight, evlRight, NULL},

View File

@ -0,0 +1,49 @@
/* license? */
#if defined(SYSTEM_PRIVILEGE) || (!defined(FB_JRD_SYSTEM_PRIVILEGES))
#ifndef SYSTEM_PRIVILEGE
#define SYSTEM_PRIVILEGE(p) p,
#define FB_JRD_SYSTEM_PRIVILEGES
#define FB_JRD_SYSTEM_PRIVILEGES_TMP
namespace Jrd {
enum SystemPrivilege
{
NULL_PRIVILEGE,
#endif
SYSTEM_PRIVILEGE(USER_MANAGEMENT)
SYSTEM_PRIVILEGE(READ_RAW_PAGES)
SYSTEM_PRIVILEGE(CREATE_USER_TYPES)
SYSTEM_PRIVILEGE(USE_NBACKUP_UTILITY)
SYSTEM_PRIVILEGE(CHANGE_SHUTDOWN_MODE)
SYSTEM_PRIVILEGE(TRACE_ANY_ATTACHMENT)
SYSTEM_PRIVILEGE(MONITOR_ANY_ATTACHMENT)
SYSTEM_PRIVILEGE(ACCESS_SHUTDOWN_DATABASE)
SYSTEM_PRIVILEGE(CREATE_DATABASE)
SYSTEM_PRIVILEGE(DROP_DATABASE)
SYSTEM_PRIVILEGE(USE_GBAK_UTILITY)
SYSTEM_PRIVILEGE(USE_GSTAT_UTILITY)
SYSTEM_PRIVILEGE(USE_GFIX_UTILITY)
SYSTEM_PRIVILEGE(IGNORE_DB_TRIGGERS)
SYSTEM_PRIVILEGE(CHANGE_HEADER_SETTINGS)
SYSTEM_PRIVILEGE(SELECT_ANY_OBJECT_IN_DATABASE)
SYSTEM_PRIVILEGE(ACCESS_ANY_OBJECT_IN_DATABASE)
SYSTEM_PRIVILEGE(MODIFY_ANY_OBJECT_IN_DATABASE)
SYSTEM_PRIVILEGE(CHANGE_MAPPING_RULES)
SYSTEM_PRIVILEGE(USE_GRANTED_BY_CLAUSE)
SYSTEM_PRIVILEGE(GRANT_REVOKE_ON_ANY_OBJECT)
SYSTEM_PRIVILEGE(GRANT_REVOKE_ANY_DDL_RIGHT)
SYSTEM_PRIVILEGE(CREATE_PRIVILEGED_ROLES)
#ifdef FB_JRD_SYSTEM_PRIVILEGES_TMP
maxSystemPrivilege
};
} // namespace Jrd
#undef SYSTEM_PRIVILEGE
#undef FB_JRD_SYSTEM_PRIVILEGES_TMP
#endif
#endif

View File

@ -47,12 +47,12 @@ namespace
// ILogonInfo implementation
const char* name()
{
return att->att_user->usr_user_name.c_str();
return att->att_user->getUserName().c_str();
}
const char* role()
{
return att->att_user->usr_sql_role_name.c_str();
return att->att_user->getSqlRole().c_str();
}
const char* networkProtocol()
@ -479,7 +479,7 @@ void UserManagement::list(IUser* u, unsigned cachePosition)
const char* uname = u->userName()->get();
putField(threadDbb, record,
DumpField(f_sec_user_name, VALUE_STRING, static_cast<USHORT>(strlen(uname)), uname));
su = strcmp(uname, SYSDBA_USER_NAME) == 0;
su = strcmp(uname, DBA_USER_NAME) == 0;
}
if (u->firstName()->entered())

View File

@ -73,7 +73,9 @@ const int id_sql_role = 11; // SQL role
const int id_package = 12; // Package name
const int id_function = 13; // Function name
const int id_filter = 14; // Filter name
const int id_max = 15;
// New in FB4
const int id_privilege = 15; // System privilege
const int id_max = 16;
/* Format of access control list:

View File

@ -2860,7 +2860,7 @@ static THREAD_ENTRY_DECLARE cache_writer(THREAD_ENTRY_PARAM arg)
try
{
UserId user;
user.usr_user_name = "Cache Writer";
user.setUserName("Cache Writer");
Jrd::Attachment* const attachment = Jrd::Attachment::create(dbb);
RefPtr<SysStableAttachment> sAtt(FB_NEW SysStableAttachment(attachment));

View File

@ -86,7 +86,7 @@ const char* const NULL_ROLE = "NONE";
// User name assigned to any user granted USR_locksmith rights.
// If this name is changed, modify also the trigger in
// jrd/grant.gdl (which turns into jrd/trig.h.
const char* const SYSDBA_USER_NAME = "SYSDBA";
const char* const DBA_USER_NAME = "SYSDBA";
const char* const PRIMARY_KEY = "PRIMARY KEY";
const char* const FOREIGN_KEY = "FOREIGN KEY";

View File

@ -65,5 +65,15 @@ static const UCHAR dflt_restrict[] =
blr_eoc
};
/* default value of all "\000" for RDB$SYSTEM_PRIVILEGES */
static const UCHAR dflt_no_privs[] =
{
blr_version5,
blr_literal, blr_text2, TWOBYTES(ttype_binary), 8, 0, '\0', '\0', '\0', '\0',
'\0', '\0', '\0', '\0',
blr_eoc
};
#endif // JRD_DFLT_H

View File

@ -483,7 +483,7 @@ static bool drop_package_body(thread_db*, SSHORT, DeferredWork*, jrd_tra*);
static bool grant_privileges(thread_db*, SSHORT, DeferredWork*, jrd_tra*);
static bool db_crypt(thread_db*, SSHORT, DeferredWork*, jrd_tra*);
static bool set_linger(thread_db*, SSHORT, DeferredWork*, jrd_tra*);
static bool clear_mapping(thread_db*, SSHORT, DeferredWork*, jrd_tra*);
static bool clear_cache(thread_db*, SSHORT, DeferredWork*, jrd_tra*);
// ----------------------------------------------------------------
@ -1177,7 +1177,7 @@ static const deferred_task task_table[] =
{ dfw_store_view_context_type, store_view_context_type },
{ dfw_db_crypt, db_crypt },
{ dfw_set_linger, set_linger },
{ dfw_clear_mapping, clear_mapping },
{ dfw_clear_cache, clear_cache },
{ dfw_null, NULL }
};
@ -2234,11 +2234,11 @@ static bool set_linger(thread_db* tdbb, SSHORT phase, DeferredWork* work, jrd_tr
return false;
}
static bool clear_mapping(thread_db* tdbb, SSHORT phase, DeferredWork* work, jrd_tra*)
static bool clear_cache(thread_db* tdbb, SSHORT phase, DeferredWork* work, jrd_tra*)
{
/**************************************
*
* c l e a r _ m a p p i n g
* c l e a r _ c a c h e
*
**************************************
*
@ -2256,7 +2256,7 @@ static bool clear_mapping(thread_db* tdbb, SSHORT phase, DeferredWork* work, jrd
return true;
case 3:
clearMap(dbb->dbb_filename.c_str());
clearMappingCache(dbb->dbb_filename.c_str(), work->dfw_id);
break;
}

View File

@ -130,7 +130,6 @@ enum drq_type_t
drq_gcg4, // grantor_can_grant
drq_gcg5, // grantor_can_grant
drq_l_view_idx, // table is view?
drq_role_gens, // store SQL role
drq_get_role_nm, // get SQL role
drq_get_role_au, // get SQL role auth
drq_del_role_1, // delete SQL role from rdb$user_privilege

View File

@ -147,9 +147,9 @@ void InternalConnection::attach(thread_db* tdbb, const PathName& dbName,
setWrapErrors(false);
Jrd::Attachment* attachment = tdbb->getAttachment();
if ((user.isEmpty() || user == attachment->att_user->usr_user_name) &&
if ((user.isEmpty() || user == attachment->att_user->getUserName()) &&
pwd.isEmpty() &&
(role.isEmpty() || role == attachment->att_user->usr_sql_role_name))
(role.isEmpty() || role == attachment->att_user->getSqlRole()))
{
m_isCurrent = true;
m_attachment = attachment->getInterface();
@ -249,9 +249,9 @@ bool InternalConnection::isSameDatabase(thread_db* tdbb, const PathName& dbName,
if (m_isCurrent)
{
const UserId* attUser = m_attachment->getHandle()->att_user;
return ((user.isEmpty() || user == attUser->usr_user_name) &&
return ((user.isEmpty() || user == attUser->getUserName()) &&
pwd.isEmpty() &&
(role.isEmpty() || role == attUser->usr_sql_role_name));
(role.isEmpty() || role == attUser->getSqlRole()));
}
return Connection::isSameDatabase(tdbb, dbName, user, pwd, role);

View File

@ -192,3 +192,5 @@
FIELD(fld_gen_increment , nam_gen_increment , dtype_long , sizeof(SLONG) , 0 , NULL , false)
FIELD(fld_plan , nam_plan , dtype_blob , BLOB_SIZE , isc_blob_text , NULL , true)
FIELD(fld_system_privileges, nam_system_privileges, dtype_text, 8 , dsc_text_type_fixed , dflt_no_privs, true)

View File

@ -27,6 +27,8 @@
#include "firebird.h"
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include "../jrd/jrd.h"
#include "../jrd/scl.h"
#include "../jrd/acl.h"
@ -624,6 +626,11 @@ static void grant_user(Acl& acl,
CHECK_AND_MOVE(acl, id_view);
break;
case obj_privilege:
CHECK_AND_MOVE(acl, id_privilege);
fb_assert(isdigit(user[0]));
break;
default:
BUGCHECK(292); // Illegal user_type
@ -1043,6 +1050,13 @@ static SecurityClass::flags_t squeeze_acl(Acl& acl, const Firebird::MetaName& us
hit = false;
break;
case id_privilege:
if (user_type != obj_privilege)
hit = false;
if (check_string(a, user))
hit = false;
break;
default:
BUGCHECK(293); // bad ACL
}

View File

@ -569,11 +569,11 @@ void INF_database_info(thread_db* tdbb,
case isc_info_user_names:
// Assumes user names will be smaller than sizeof(buffer) - 1.
if (!(tdbb->getAttachment()->locksmith()))
if (!(tdbb->getAttachment()->locksmith(tdbb, USER_MANAGEMENT)))
{
const UserId* user = tdbb->getAttachment()->att_user;
const char* uname = (user && user->usr_user_name.hasData()) ?
user->usr_user_name.c_str() : "<Unknown>";
const char* uname = (user && user->getUserName().hasData()) ?
user->getUserName().c_str() : "<Unknown>";
const SSHORT len = static_cast<SSHORT>(strlen(uname));
*p++ = len;
memcpy(p, uname, len);
@ -595,8 +595,8 @@ void INF_database_info(thread_db* tdbb,
if (user)
{
const char* user_name = user->usr_user_name.hasData() ?
user->usr_user_name.c_str() : "(Firebird Worker Thread)";
const char* user_name = user->getUserName().hasData() ?
user->getUserName().c_str() : "(Firebird Worker Thread)";
p = buffer;
const SSHORT len = static_cast<SSHORT>(strlen(user_name));
*p++ = len;
@ -729,7 +729,7 @@ void INF_database_info(thread_db* tdbb,
break;
case fb_info_page_contents:
if (tdbb->getAttachment()->locksmith())
if (tdbb->getAttachment()->locksmith(tdbb, READ_RAW_PAGES))
{
length = gds__vax_integer(items, 2);
items += 2;

View File

@ -58,6 +58,7 @@
#include "../jrd/IntlManager.h"
#include "../jrd/PreparedStatement.h"
#include "../jrd/constants.h"
#include "../jrd/grant_proto.h"
using namespace Firebird;
using namespace Jrd;
@ -80,7 +81,11 @@ static void store_intlnames(thread_db*, const MetaName&);
static void store_message(thread_db*, const trigger_msg*, AutoRequest&);
static void store_relation_field(thread_db*, const int*, const int*, int, AutoRequest&);
static void store_trigger(thread_db*, const jrd_trg*, AutoRequest&);
static void store_admin_grant(thread_db*, const char* grantee, USHORT grantee_type,
const char* object, USHORT object_type, const char* prvl, USHORT option = 0, bool dflt = false);
static void store_admin_role_grant(thread_db*, const char*);
static void store_admin_role(thread_db*, const MetaName&, MetaName, UserId::Privileges*);
static bool get_charset_by_text_type(SSHORT& charSet, const USHORT sub_type);
// This is the table used in defining triggers; note that
// RDB$TRIGGER_0 was first changed to RDB$TRIGGER_7 to make it easier to
@ -318,25 +323,18 @@ void INI_format(const char* owner, const char* charset)
rdbRelationId = USER_DEF_REL_INIT_ID;
ps->execute(tdbb, transaction);
// Store ADMIN_ROLE record
// Store system role
handle1.reset();
store_admin_role(tdbb, ADMIN_ROLE, ownerName, NULL);
STORE(REQUEST_HANDLE handle1) X IN RDB$ROLES
{
PAD (ADMIN_ROLE, X.RDB$ROLE_NAME);
X.RDB$ROLE_NAME.NULL = FALSE;
if (ownerName.hasData())
PAD(ownerName.c_str(), X.RDB$OWNER_NAME);
else
PAD(SYSDBA_USER_NAME, X.RDB$OWNER_NAME);
X.RDB$OWNER_NAME.NULL = FALSE;
X.RDB$SYSTEM_FLAG = 1; // We have single system role, always treat it as privileged
X.RDB$SYSTEM_FLAG.NULL = FALSE;
}
END_STORE
// Store grants of admin role to valuable users
store_admin_role_grant(tdbb, DBA_USER_NAME);
if (ownerName != DBA_USER_NAME)
store_admin_role_grant(tdbb, ownerName.c_str());
// Create indices for system relations
add_index_set(tdbb);
// Create parameter types
@ -549,6 +547,22 @@ void INI_format(const char* owner, const char* charset)
for (const trigger_msg* message = trigger_messages; message->trigmsg_name; ++message)
store_message(tdbb, message, handle1);
// Add additional grants
MetaName buf;
buf.printf("%d", USE_NBACKUP_UTILITY);
store_admin_grant(tdbb, buf.c_str(), obj_privilege, "RDB$BACKUP_HISTORY", obj_relation, "SIUDR");
GRANT_privileges(tdbb, "RDB$BACKUP_HISTORY", obj_relation, attachment->getSysTransaction());
buf.printf("%d", CREATE_USER_TYPES);
store_admin_grant(tdbb, buf.c_str(), obj_privilege, "RDB$TYPES", obj_relation, "SIUDR");
GRANT_privileges(tdbb, "RDB$TYPES", obj_relation, attachment->getSysTransaction());
buf.printf("%d", GRANT_REVOKE_ANY_DDL_RIGHT);
store_admin_grant(tdbb, buf.c_str(), obj_privilege, "RDB$DB_CREATORS", obj_relation, "SIUDR");
GRANT_privileges(tdbb, "RDB$DB_CREATORS", obj_relation, attachment->getSysTransaction());
DFW_perform_system_work(tdbb);
}
@ -647,9 +661,7 @@ void INI_init(thread_db* tdbb)
if (desc->isText())
{
if (gfield->gfld_sub_type & dsc_text_type_metadata)
desc->dsc_sub_type = CS_METADATA;
else
if (!get_charset_by_text_type(desc->dsc_sub_type, gfield->gfld_sub_type))
desc->dsc_sub_type = CS_NONE;
}
else
@ -758,7 +770,7 @@ void INI_init_dsql(thread_db* tdbb, dsql_dbb* database)
relation->rel_id = relfld[RFLD_R_ID];
relation->rel_name = names[relfld[RFLD_R_NAME]];
relation->rel_owner = SYSDBA_USER_NAME;
relation->rel_owner = DBA_USER_NAME;
relation->rel_dbkey_length = 8;
dsql_fld** ptr = &relation->rel_fields;
@ -798,20 +810,7 @@ void INI_init_dsql(thread_db* tdbb, dsql_dbb* database)
}
if (DTYPE_IS_TEXT(gfield->gfld_dtype))
{
switch (gfield->gfld_sub_type)
{
case dsc_text_type_metadata:
field->charSetId = CS_METADATA;
break;
case dsc_text_type_ascii:
field->charSetId = CS_ASCII;
break;
case dsc_text_type_fixed:
field->charSetId = CS_BINARY;
break;
}
}
get_charset_by_text_type(field->charSetId, gfield->gfld_sub_type);
if (gfield->gfld_nullable)
field->flags |= FLD_nullable;
@ -1205,6 +1204,65 @@ static void add_security_to_sys_obj(thread_db* tdbb,
}
static void store_admin_grant(thread_db* tdbb, const char* user, USHORT user_type,
const char* object, USHORT object_type, const char* prvl, USHORT option, bool dflt)
{
Attachment* attachment = tdbb->getAttachment(); // needed for preprocessed code
AutoRequest handle;
while (*prvl)
{
STORE(REQUEST_HANDLE handle) PRIV IN RDB$USER_PRIVILEGES
PAD(user, PRIV.RDB$USER);
PAD(object, PRIV.RDB$RELATION_NAME);
if (dflt)
{
PRIV.RDB$FIELD_NAME[0] = 'D';
PRIV.RDB$FIELD_NAME[1] = 0;
PRIV.RDB$FIELD_NAME.NULL = FALSE;
}
else
PRIV.RDB$FIELD_NAME.NULL = TRUE;
PRIV.RDB$PRIVILEGE[0] = *prvl++;
PRIV.RDB$PRIVILEGE[1] = 0;
PRIV.RDB$GRANT_OPTION = option;
PRIV.RDB$USER_TYPE = user_type;
PRIV.RDB$OBJECT_TYPE = object_type;
PRIV.RDB$GRANTOR.NULL = TRUE;
END_STORE
}
}
static void store_admin_role_grant(thread_db* tdbb, const char* user)
{
store_admin_grant(tdbb, user, obj_user, ADMIN_ROLE, obj_sql_role, "M", 2, true);
}
static void store_admin_role(thread_db* tdbb, const MetaName& roleName, MetaName ownerName,
UserId::Privileges* priv)
{
if (!ownerName.hasData())
ownerName = DBA_USER_NAME;
string p;
if (priv)
priv->store(p.getBuffer(priv->BYTES_COUNT));
else
p = INI_owner_privileges();
PreparedStatement::Builder sql;
sql << "insert into rdb$roles(rdb$role_name, rdb$owner_name, rdb$system_flag, rdb$system_privileges)"
<< "values (" << roleName << "," << ownerName << ", 1," << p << ")";
Attachment* attachment = tdbb->getAttachment();
jrd_tra* transaction = attachment->getSysTransaction();
AutoPreparedStatement ps(attachment->prepareStatement(tdbb, transaction, sql));
ps->execute(tdbb, transaction);
}
// Add security class.
static void add_security_class(thread_db* tdbb, const MetaName& class_name, USHORT acl_length, const UCHAR* acl)
{
@ -1574,7 +1632,7 @@ static void store_trigger(thread_db* tdbb, const jrd_trg* trigger, AutoRequest&
*
**************************************/
SET_TDBB(tdbb);
Jrd::Attachment* attachment = tdbb->getAttachment();
Attachment* attachment = tdbb->getAttachment();
// indicate that the relation format needs revising
dsc desc;
@ -1598,3 +1656,30 @@ static void store_trigger(thread_db* tdbb, const jrd_trg* trigger, AutoRequest&
}
END_STORE
}
string INI_owner_privileges()
{
return string(gfields[fld_system_privileges].gfld_length, '\xff');
}
static bool get_charset_by_text_type(SSHORT& charSet, const USHORT sub_type)
{
switch (sub_type)
{
case dsc_text_type_metadata:
charSet = CS_METADATA;
break;
case dsc_text_type_ascii:
charSet = CS_ASCII;
break;
case dsc_text_type_fixed:
charSet = CS_BINARY;
break;
default:
return false;
}
return true;
}

View File

@ -159,6 +159,13 @@ static const int relfields[] =
#undef FIELD
#undef END_RELATION
//******************************
// SystemPrivileges.h
// should go before types.h
//******************************
#include "SystemPrivileges.h"
//******************************
// types.h
//******************************

View File

@ -34,5 +34,6 @@ USHORT INI_get_trig_flags(const TEXT*);
void INI_init(Jrd::thread_db*);
void INI_init2(Jrd::thread_db*);
void INI_init_dsql(Jrd::thread_db*, Jrd::dsql_dbb* database);
Firebird::string INI_owner_privileges();
#endif // JRD_INI_PROTO_H

View File

@ -106,6 +106,7 @@ enum irq_type_t
irq_l_check2, // lookup constraint for index
irq_c_trg_perm, // check if trig can ignore perm. checks
irq_get_role_name, // get SQL role name
irq_get_priv_bit, // get privilege bit by name
irq_is_admin_role, // check is current role admin or not
irq_get_att_class, // get security class for current attachment
irq_format6, // make a new format for a record

View File

@ -73,6 +73,7 @@
#include "../intl/charsets.h"
#include "../jrd/sort.h"
#include "../jrd/PreparedStatement.h"
#include "../jrd/ResultSet.h"
#include "../dsql/StmtNodes.h"
#include "../jrd/blb_proto.h"
@ -727,15 +728,27 @@ namespace
};
void validateAccess(const Jrd::Attachment* attachment)
void validateAccess(thread_db* tdbb, Jrd::Attachment* attachment, SystemPrivilege sp)
{
if (!attachment->locksmith())
if (!attachment->locksmith(tdbb, sp))
{
PreparedStatement::Builder sql;
MetaName missPriv("UNKNOWN");
sql << "select" << sql("rdb$type_name", missPriv) << "from rdb$types"
<< "where rdb$field_name = 'RDB$SYSTEM_PRIVILEGES'"
<< " and rdb$type =" << SSHORT(sp);
jrd_tra* transaction = attachment->getSysTransaction();
AutoPreparedStatement ps(attachment->prepareStatement(tdbb, transaction, sql));
AutoResultSet rs(ps->executeQuery(tdbb, transaction));
rs->fetch(tdbb);
UserId* u = attachment->att_user;
if (u->usr_flags & USR_mapdown)
ERR_post(Arg::Gds(isc_adm_task_denied) << Arg::Gds(isc_map_down));
else
ERR_post(Arg::Gds(isc_adm_task_denied));
Arg::Gds err(isc_miss_prvlg);
err << missPriv;
if (u->testFlag(USR_mapdown))
err << Arg::Gds(isc_map_down);
ERR_post(err);
}
}
@ -981,7 +994,7 @@ public:
// TraceConnection implementation
unsigned getKind() { return KIND_DATABASE; };
int getProcessID() { return m_options->dpb_remote_pid; }
const char* getUserName() { return m_id.usr_user_name.c_str(); }
const char* getUserName() { return m_id.getUserName().c_str(); }
const char* getRoleName() { return m_options->dpb_role_name.c_str(); }
const char* getCharSet() { return m_options->dpb_lc_ctype.c_str(); }
const char* getRemoteProtocol() { return m_options->dpb_network_protocol.c_str(); }
@ -1027,7 +1040,6 @@ static void rollback(thread_db*, jrd_tra*, const bool);
static void purge_attachment(thread_db* tdbb, StableAttachmentPart* sAtt, unsigned flags = 0);
static void getUserInfo(UserId&, const DatabaseOptions&, const char*, const char*,
const RefPtr<Config>*, bool, ICryptKeyCallback*);
static void makeRoleName(Database*, MetaName&, DatabaseOptions&);
static THREAD_ENTRY_DECLARE shutdown_thread(THREAD_ENTRY_PARAM);
@ -1098,44 +1110,6 @@ static void successful_completion(CheckStatusWrapper* s, ISC_STATUS acceptCode =
}
static void makeRoleName(Database* dbb, MetaName& userIdRole, DatabaseOptions& options)
{
if (userIdRole.isEmpty())
return;
switch (options.dpb_sql_dialect)
{
case 0:
// V6 Client --> V6 Server, dummy client SQL dialect 0 was passed
// It means that client SQL dialect was not set by user
// and takes DB SQL dialect as client SQL dialect
if (dbb->dbb_flags & DBB_DB_SQL_dialect_3)
{
// DB created in IB V6.0 by client SQL dialect 3
options.dpb_sql_dialect = SQL_DIALECT_V6;
}
else
{
// old DB was gbaked in IB V6.0
options.dpb_sql_dialect = SQL_DIALECT_V5;
}
break;
case 99:
// V5 Client --> V6 Server, old client has no concept of dialect
options.dpb_sql_dialect = SQL_DIALECT_V5;
break;
default:
// V6 Client --> V6 Server, but client SQL dialect was set
// by user and was passed.
break;
}
JRD_make_role_name(userIdRole, options.dpb_sql_dialect);
}
// Stuff exception transliterated to the client charset.
ISC_STATUS transliterateException(thread_db* tdbb, const Exception& ex, FbStatusVector* vector,
const char* func) throw()
@ -1300,28 +1274,6 @@ static void trace_failed_attach(TraceManager* traceManager, const char* filename
}
void JRD_make_role_name(MetaName& userIdRole, const int dialect)
{
switch (dialect)
{
case SQL_DIALECT_V5:
// Invoke utility twice: first to strip quotes, next to uppercase if needed
// For unquoted string nothing bad happens
fb_utils::dpbItemUpper(userIdRole);
fb_utils::dpbItemUpper(userIdRole);
break;
case SQL_DIALECT_V6_TRANSITION:
case SQL_DIALECT_V6:
fb_utils::dpbItemUpper(userIdRole);
break;
default:
break;
}
}
namespace Jrd {
JTransaction* JAttachment::getTransactionInterface(CheckStatusWrapper* status, ITransaction* tra)
@ -1553,7 +1505,7 @@ JAttachment* JProvider::internalAttach(CheckStatusWrapper* user_status, const ch
// Here we do not let anyone except SYSDBA (like DBO) to change dbb_page_buffers,
// cause other flags is UserId can be set only when DB is opened.
// No idea how to test for other cases before init is complete.
if ((config->getServerMode() != MODE_SUPER) || userId.locksmith())
if ((config->getServerMode() != MODE_SUPER) || userId.locksmith(tdbb, CHANGE_HEADER_SETTINGS))
dbb->dbb_page_buffers = options.dpb_page_buffers;
}
@ -1639,12 +1591,38 @@ JAttachment* JProvider::internalAttach(CheckStatusWrapper* user_status, const ch
Arg::Gds(isc_valid_client_dialects) << Arg::Str("1, 2 or 3"));
}
makeRoleName(dbb, userId.usr_sql_role_name, options);
makeRoleName(dbb, userId.usr_trusted_role, options);
switch (options.dpb_sql_dialect)
{
case 0:
// V6 Client --> V6 Server, dummy client SQL dialect 0 was passed
// It means that client SQL dialect was not set by user
// and takes DB SQL dialect as client SQL dialect
if (dbb->dbb_flags & DBB_DB_SQL_dialect_3)
{
// DB created in IB V6.0 by client SQL dialect 3
options.dpb_sql_dialect = SQL_DIALECT_V6;
}
else
{
// old DB was gbaked in IB V6.0
options.dpb_sql_dialect = SQL_DIALECT_V5;
}
break;
options.dpb_sql_dialect = 0;
case 99:
// V5 Client --> V6 Server, old client has no concept of dialect
options.dpb_sql_dialect = SQL_DIALECT_V5;
break;
SCL_init(tdbb, false, userId);
default:
// V6 Client --> V6 Server, but client SQL dialect was set
// by user and was passed.
break;
}
userId.makeRoleName(options.dpb_sql_dialect);
UserId::sclInit(tdbb, false, userId);
// This pair (SHUT_database/SHUT_online) checks itself for valid user name
if (options.dpb_shutdown)
@ -1686,7 +1664,7 @@ JAttachment* JProvider::internalAttach(CheckStatusWrapper* user_status, const ch
if (dbb->dbb_ast_flags & DBB_shutdown)
{
// Allow only SYSDBA/owner to access database that is shut down
bool allow_access = attachment->locksmith();
bool allow_access = attachment->locksmith(tdbb, ACCESS_SHUTDOWN_DATABASE);
// Handle special shutdown modes
if (allow_access)
{
@ -1711,7 +1689,7 @@ JAttachment* JProvider::internalAttach(CheckStatusWrapper* user_status, const ch
// Note we throw exception here when entering full-shutdown mode
Arg::Gds v(isc_shutdown);
v << Arg::Str(org_filename);
if (attachment->att_user->usr_flags & USR_mapdown)
if (attachment->att_user->testFlag(USR_mapdown))
v << Arg::Gds(isc_map_down);
ERR_post(v);
}
@ -1727,11 +1705,14 @@ JAttachment* JProvider::internalAttach(CheckStatusWrapper* user_status, const ch
// database. smistry 10/5/98
if (attachment->isUtility())
validateAccess(attachment);
validateAccess(tdbb, attachment,
attachment->att_utility == Attachment::UTIL_GBAK ? USE_GBAK_UTILITY :
attachment->att_utility == Attachment::UTIL_GFIX ? USE_GFIX_UTILITY :
USE_GSTAT_UTILITY);
if (options.dpb_verify)
{
validateAccess(attachment);
validateAccess(tdbb, attachment, USE_GFIX_UTILITY);
if (!CCH_exclusive(tdbb, LCK_PW, WAIT_PERIOD, NULL))
ERR_post(Arg::Gds(isc_bad_dpb_content) << Arg::Gds(isc_cant_validate));
@ -1745,7 +1726,7 @@ JAttachment* JProvider::internalAttach(CheckStatusWrapper* user_status, const ch
if (options.dpb_reset_icu)
{
validateAccess(attachment);
validateAccess(tdbb, attachment, USE_GFIX_UTILITY);
DFW_reset_icu(tdbb);
}
@ -1766,42 +1747,42 @@ JAttachment* JProvider::internalAttach(CheckStatusWrapper* user_status, const ch
if (options.dpb_no_db_triggers)
{
validateAccess(attachment);
validateAccess(tdbb, attachment, IGNORE_DB_TRIGGERS);
attachment->att_flags |= ATT_no_db_triggers;
}
if (options.dpb_set_db_sql_dialect)
{
validateAccess(attachment);
validateAccess(tdbb, attachment, CHANGE_HEADER_SETTINGS);
PAG_set_db_SQL_dialect(tdbb, options.dpb_set_db_sql_dialect);
dbb->dbb_linger_seconds = 0;
}
if (options.dpb_sweep_interval > -1)
{
validateAccess(attachment);
validateAccess(tdbb, attachment, CHANGE_HEADER_SETTINGS);
PAG_sweep_interval(tdbb, options.dpb_sweep_interval);
dbb->dbb_sweep_interval = options.dpb_sweep_interval;
}
if (options.dpb_set_force_write)
{
validateAccess(attachment);
validateAccess(tdbb, attachment, CHANGE_HEADER_SETTINGS);
PAG_set_force_write(tdbb, options.dpb_force_write);
}
if (options.dpb_set_no_reserve)
{
validateAccess(attachment);
validateAccess(tdbb, attachment, CHANGE_HEADER_SETTINGS);
PAG_set_no_reserve(tdbb, options.dpb_no_reserve);
}
if (options.dpb_set_page_buffers)
{
if (dbb->dbb_flags & DBB_shared)
validateAccess(attachment);
validateAccess(tdbb, attachment, CHANGE_HEADER_SETTINGS);
if (attachment->locksmith())
if (attachment->locksmith(tdbb, CHANGE_HEADER_SETTINGS))
{
PAG_set_page_buffers(tdbb, options.dpb_page_buffers);
dbb->dbb_linger_seconds = 0;
@ -1810,7 +1791,7 @@ JAttachment* JProvider::internalAttach(CheckStatusWrapper* user_status, const ch
if (options.dpb_set_db_readonly)
{
validateAccess(attachment);
validateAccess(tdbb, attachment, CHANGE_HEADER_SETTINGS);
if (!CCH_exclusive(tdbb, LCK_EX, WAIT_PERIOD, NULL))
{
ERR_post(Arg::Gds(isc_lock_timeout) <<
@ -2578,7 +2559,7 @@ JAttachment* JProvider::createDatabase(CheckStatusWrapper* user_status, const ch
if (options.dpb_overwrite)
{
// isc_dpb_no_db_triggers is required for 2 reasons
// - it disables non-DBA attaches with isc_adm_task_denied error
// - it disables non-DBA attaches with isc_adm_task_denied or isc_miss_prvlg error
// - it disables any user code to be executed when we later lock
// databases_mutex with OverwriteHolder
ClumpletWriter dpbWriter(ClumpletReader::dpbList, MAX_DPB_SIZE, dpb, dpb_length);
@ -2590,16 +2571,20 @@ JAttachment* JProvider::createDatabase(CheckStatusWrapper* user_status, const ch
JAttachment* attachment2 = internalAttach(user_status, filename, dpb_length,
dpb, INTERNAL_ATT_OVERWRITE_CHECK);
if (user_status->getErrors()[1] == isc_adm_task_denied)
switch (user_status->getErrors()[1])
{
case isc_adm_task_denied:
case isc_miss_prvlg:
throw;
default:
break;
}
bool allow_overwrite = false;
if (attachment2)
{
allow_overwrite = attachment2->getHandle()->att_user->locksmith();
allow_overwrite = attachment2->getHandle()->att_user->locksmith(tdbb, DROP_DATABASE);
attachment2->detach(user_status);
}
else
@ -2645,7 +2630,7 @@ JAttachment* JProvider::createDatabase(CheckStatusWrapper* user_status, const ch
INI_init(tdbb);
PAG_init(tdbb);
SCL_init(tdbb, true, userId);
UserId::sclInit(tdbb, true, userId);
if (options.dpb_set_page_buffers)
dbb->dbb_page_buffers = options.dpb_page_buffers;
@ -2685,7 +2670,7 @@ JAttachment* JProvider::createDatabase(CheckStatusWrapper* user_status, const ch
if (options.dpb_set_no_reserve)
PAG_set_no_reserve(tdbb, options.dpb_no_reserve);
INI_format(attachment->att_user->usr_user_name.c_str(),
INI_format(attachment->att_user->getUserName().c_str(),
options.dpb_set_db_charset.c_str());
// If we have not allocated first TIP page, do it now.
@ -2947,7 +2932,7 @@ void JAttachment::dropDatabase(CheckStatusWrapper* user_status)
const PathName& file_name = attachment->att_filename;
if (!attachment->locksmith())
if (!attachment->locksmith(tdbb, DROP_DATABASE))
{
ERR_post(Arg::Gds(isc_no_priv) << Arg::Str("drop") <<
Arg::Str("database") <<
@ -5395,7 +5380,7 @@ static void check_database(thread_db* tdbb, bool async)
if ((attachment->att_flags & ATT_shutdown) &&
(attachment->att_purge_tid != Thread::getId()) ||
((dbb->dbb_ast_flags & DBB_shutdown) &&
((dbb->dbb_ast_flags & DBB_shutdown_full) || !attachment->locksmith())))
((dbb->dbb_ast_flags & DBB_shutdown_full) || !attachment->locksmith(tdbb, ACCESS_SHUTDOWN_DATABASE))))
{
if (dbb->dbb_ast_flags & DBB_shutdown)
{
@ -7104,10 +7089,11 @@ static void getUserInfo(UserId& user, const DatabaseOptions& options,
}
else if (options.dpb_auth_block.hasData())
{
if (mapUser(name, trusted_role, &auth_method, &user.usr_auth_block, options.dpb_auth_block,
aliasName, dbName, (config ? (*config)->getSecurityDatabase() : NULL), cryptCb))
if (mapUser(true, name, trusted_role, &auth_method, &user.usr_auth_block, NULL,
options.dpb_auth_block, aliasName, dbName,
(config ? (*config)->getSecurityDatabase() : NULL), cryptCb, NULL) & MAPUSER_MAP_DOWN)
{
user.usr_flags |= USR_mapdown;
user.setFlag(USR_mapdown);
}
if (creating && config) // when config is NULL we are in error handler
@ -7122,7 +7108,7 @@ static void getUserInfo(UserId& user, const DatabaseOptions& options,
wheel = ISC_get_user(&name, &id, &group);
ISC_systemToUtf8(name);
fb_utils::dpbItemUpper(name);
if (id == 0)
if (wheel || id == 0)
{
auth_method = "OS user name / wheel";
wheel = true;
@ -7132,7 +7118,7 @@ static void getUserInfo(UserId& user, const DatabaseOptions& options,
// if the name from the user database is defined as SYSDBA,
// we define that user id as having system privileges
if (name == SYSDBA_USER_NAME)
if (name == DBA_USER_NAME)
{
wheel = true;
}
@ -7143,7 +7129,7 @@ static void getUserInfo(UserId& user, const DatabaseOptions& options,
if (wheel)
{
name = SYSDBA_USER_NAME;
name = DBA_USER_NAME;
}
if (name.length() > USERNAME_LENGTH)
@ -7152,26 +7138,21 @@ static void getUserInfo(UserId& user, const DatabaseOptions& options,
<< Arg::Num(USERNAME_LENGTH));
}
user.usr_user_name = name;
user.setUserName(name);
user.usr_project_name = "";
user.usr_org_name = "";
user.usr_auth_method = auth_method;
user.usr_user_id = id;
user.usr_group_id = group;
if (wheel)
if (trusted_role.hasData())
{
user.usr_flags |= USR_locksmith;
user.setTrustedRole(trusted_role);
}
if (options.dpb_role_name.hasData())
{
user.usr_sql_role_name = options.dpb_role_name;
}
if (trusted_role.hasData())
{
user.usr_trusted_role = trusted_role;
user.setSqlRole(options.dpb_role_name.c_str());
}
}

View File

@ -405,3 +405,5 @@ NAME("RDB$DB_CREATORS", nam_db_creators)
NAME("SEC$DB_CREATORS", nam_sec_db_creators)
NAME("SEC$USER", nam_sec_user)
NAME("SEC$USER_TYPE", nam_sec_user_type)
NAME("RDB$SYSTEM_PRIVILEGES", nam_system_privileges)

View File

@ -47,28 +47,31 @@ const int obj_blob_filter = 16;
const int obj_collation = 17;
const int obj_package_header = 18;
const int obj_package_body = 19;
const int obj_privilege = 20;
const int obj_last_non_ddl = 20; // keep in sync!!!
// 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_charsets = 30;
const int obj_collations = 31;
const int obj_filters = 32;
const int obj_database = obj_last_non_ddl + 1;
const int obj_relations = obj_last_non_ddl + 2;
const int obj_views = obj_last_non_ddl + 3;
const int obj_procedures = obj_last_non_ddl + 4;
const int obj_functions = obj_last_non_ddl + 5;
const int obj_packages = obj_last_non_ddl + 6;
const int obj_generators = obj_last_non_ddl + 7;
const int obj_domains = obj_last_non_ddl + 8;
const int obj_exceptions = obj_last_non_ddl + 9;
const int obj_roles = obj_last_non_ddl + 10;
const int obj_charsets = obj_last_non_ddl + 11;
const int obj_collations = obj_last_non_ddl + 12;
const int obj_filters = obj_last_non_ddl + 13;
const int obj_type_MAX = 33; // keep this last!
const int obj_type_MAX = obj_last_non_ddl + 14; // keep this last!
// used in the parser only / no relation with obj_type_MAX
const int obj_user_or_role = 34;
const int obj_schema = 35;
const int obj_parameter = 36;
// used in the parser only / no relation with obj_type_MAX (should be greater)
const int obj_user_or_role = 100;
const int obj_schema = 101;
const int obj_parameter = 102;
inline const char* get_object_name(int object_type)
{

View File

@ -138,6 +138,8 @@ const USHORT ODS_11_1 = ENCODE_ODS(ODS_VERSION11, 1);
const USHORT ODS_11_2 = ENCODE_ODS(ODS_VERSION11, 2);
const USHORT ODS_12_0 = ENCODE_ODS(ODS_VERSION12, 0);
const USHORT ODS_FB4 = ODS_12_0; // temporal const to be fixed somehow later
const USHORT ODS_FIREBIRD_FLAG = 0x8000;
// Decode ODS version to Major and Minor parts. The 4 LSB's are minor and

View File

@ -451,6 +451,7 @@ RELATION(nam_roles, rel_roles, ODS_9_0, rel_persistent)
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)
FIELD(f_rol_sys_priv, nam_system_privileges, fld_system_privileges, 1, ODS_FB4)
END_RELATION
// Relation 32 (RDB$BACKUP_HISTORY)

View File

@ -44,6 +44,7 @@
#include "../jrd/cmp_proto.h"
#include "../jrd/err_proto.h"
#include "../jrd/exe_proto.h"
#include "../jrd/ini_proto.h"
#include "../yvalve/gds_proto.h"
#include "../common/isc_proto.h"
#include "../jrd/met_proto.h"
@ -56,6 +57,8 @@
#include "../common/config/config.h"
#include "../common/os/os_utils.h"
#include "../common/classes/ClumpletWriter.h"
#include "../jrd/PreparedStatement.h"
#include "../jrd/ResultSet.h"
const int UIC_BASE = 10;
@ -211,9 +214,7 @@ void SCL_check_access(thread_db* tdbb,
**************************************
*
* Functional description
* Check security class for desired permission. Check first that
* the desired access has been granted to the database then to the
* object in question.
* Check security class for desired permission.
*
**************************************/
SET_TDBB(tdbb);
@ -228,27 +229,13 @@ void SCL_check_access(thread_db* tdbb,
Arg::Str(s_class->scl_name));
}
const Jrd::Attachment& attachment = *tdbb->getAttachment();
// Allow the database owner to back up a database even if he does not have
// read access to all the tables in the database
if (attachment.isGbak() && (mask & SCL_select))
return;
// Allow the locksmith any access to database
if (attachment.locksmith())
return;
// 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;
if (!s_class || (mask & s_class->scl_flags)) {
if (!s_class || (mask & s_class->scl_flags))
return;
}
const jrd_rel* view = NULL;
@ -373,15 +360,13 @@ void SCL_check_database(thread_db* tdbb, SecurityClass::flags_t mask)
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;
if (mask == SCL_alter && attachment->locksmith(tdbb, USE_NBACKUP_UTILITY))
return;
const P_NAMES* names;
for (names = p_names; names->p_names_priv; names++)
{
@ -893,17 +878,12 @@ SecurityClass* SCL_get_class(thread_db* tdbb, const TEXT* par_string)
// Name may be absent or terminated with NULL or blank. Clean up name.
if (!par_string) {
if (!par_string)
return NULL;
}
Firebird::MetaName string(par_string);
//fb_utils::exact_name(string);
if (string.isEmpty()) {
if (string.isEmpty())
return NULL;
}
Jrd::Attachment* const attachment = tdbb->getAttachment();
@ -1003,9 +983,6 @@ bool SCL_role_granted(thread_db* tdbb, const UserId& usr, const TEXT* sql_role)
return true;
}
Firebird::MetaName loginName(usr.usr_user_name);
const TEXT* login_name = loginName.c_str();
bool found = false;
AutoCacheRequest request(tdbb, irq_verify_role_name, IRQ_REQUESTS);
@ -1022,7 +999,7 @@ bool SCL_role_granted(thread_db* tdbb, const UserId& usr, const TEXT* sql_role)
WITH RR.RDB$ROLE_NAME EQ sql_role
AND RR.RDB$ROLE_NAME EQ UU.RDB$RELATION_NAME
AND UU.RDB$OBJECT_TYPE EQ obj_sql_role
AND (UU.RDB$USER EQ login_name
AND (UU.RDB$USER EQ usr.getUserName().c_str()
OR UU.RDB$USER EQ "PUBLIC")
AND UU.RDB$USER_TYPE EQ obj_user
AND UU.RDB$PRIVILEGE EQ "M"
@ -1036,74 +1013,57 @@ bool SCL_role_granted(thread_db* tdbb, const UserId& usr, const TEXT* sql_role)
}
// TODO: Remove recursion. See dfw.epp/check_computed_dependencies as a model.
void SCL_find_granted_roles(thread_db* tdbb, const Firebird::MetaName& object, bool isRole,
Firebird::SortedArray<Firebird::MetaName>& grantedRoles, bool defaultOnly)
void UserId::findGrantedRoles(thread_db* tdbb) const
{
SET_TDBB(tdbb);
Jrd::Attachment* const attachment = tdbb->getAttachment();
const int obj_type = isRole ? obj_sql_role : obj_user;
AutoCacheRequest request(tdbb, drq_l_granted_roles, DYN_REQUESTS);
FOR(REQUEST_HANDLE request)
U IN RDB$USER_PRIVILEGES WITH
U.RDB$USER EQ object.c_str() AND
U.RDB$USER_TYPE EQ obj_type AND
U.RDB$OBJECT_TYPE EQ obj_sql_role AND
U.RDB$PRIVILEGE EQ "M"
const Firebird::MetaName roleName = U.RDB$RELATION_NAME;
const bool defaultRole = !defaultOnly || !U.RDB$FIELD_NAME.NULL && (U.RDB$FIELD_NAME[0] == 'D');
if (defaultRole && !grantedRoles.exist(roleName))
{
grantedRoles.add(roleName);
SCL_find_granted_roles(tdbb, roleName, true, grantedRoles, defaultOnly);
}
END_FOR
}
bool SCL_admin_role(thread_db* tdbb, const Firebird::SortedArray<Firebird::MetaName>& roles)
{
/**************************************
*
* S C L _ a d m i n _ r o l e
*
**************************************
*
* Functional description
* Check if roles has an admin role.
*
**************************************/
SET_TDBB(tdbb);
Jrd::Attachment* const attachment = tdbb->getAttachment();
bool adminRole = false;
PreparedStatement::Builder sql;
MetaName usr_get_role;
string usr_get_priv;
sql << "with recursive role_tree as ( "
<< " select rdb$relation_name as nm, 0 as ur from rdb$user_privileges "
<< " where rdb$privilege = 'M' and rdb$field_name = 'D' and rdb$user = " << usr_user_name << " and rdb$user_type = 8 "
<< " union all "
<< " select rdb$role_name as nm, 1 as ur from rdb$roles "
<< " where rdb$role_name = " << usr_sql_role_name
<< " union all "
<< " select p.rdb$relation_name as nm, t.ur from rdb$user_privileges p "
<< " join role_tree t on t.nm = p.rdb$user "
<< " where p.rdb$privilege = 'M' and (p.rdb$field_name = 'D' or t.ur = 1)) "
<< "select " << sql("r.rdb$role_name, ", usr_get_role)
<< sql("r.rdb$system_privileges ", usr_get_priv)
<< " from role_tree t join rdb$roles r on t.nm = r.rdb$role_name ";
for (int i = 0; !adminRole && (i < roles.getCount()); i++)
AutoPreparedStatement stmt(attachment->prepareStatement(tdbb, attachment->getSysTransaction(), sql));
AutoResultSet rs(stmt->executeQuery(tdbb, attachment->getSysTransaction()));
usr_granted_roles.clear();
usr_privileges.clearAll();
while (rs->fetch(tdbb))
{
AutoCacheRequest request(tdbb, irq_is_admin_role, IRQ_REQUESTS);
FOR(REQUEST_HANDLE request) R IN RDB$ROLES
WITH R.RDB$ROLE_NAME EQ roles[i].c_str() AND
R.RDB$SYSTEM_FLAG != 0
if (!usr_granted_roles.exist(usr_get_role)) // SQL request can return duplicates
{
adminRole = true;
break;
usr_granted_roles.add(usr_get_role);
Privileges p;
p.load(usr_get_priv.c_str());
usr_privileges |= p;
}
END_FOR
}
return adminRole;
usr_flags &= ~USR_newrole;
}
void SCL_init(thread_db* tdbb, bool create, const UserId& tempId)
void UserId::setRoleTrusted()
{
if (!usr_trusted_role.hasData())
Arg::Gds(isc_miss_trusted_role).raise();
setSqlRole(usr_trusted_role);
}
void UserId::sclInit(thread_db* tdbb, bool create, const UserId& tempId)
{
/**************************************
*
@ -1122,16 +1082,13 @@ void SCL_init(thread_db* tdbb, bool create, const UserId& tempId)
Database* const dbb = tdbb->getDatabase();
Jrd::Attachment* const attachment = tdbb->getAttachment();
const TEXT* sql_role = tempId.usr_sql_role_name.nullStr();
const TEXT* sql_role = tempId.getSqlRole().nullStr();
// CVC: We'll verify the role and wipe it out when it doesn't exist
if (tempId.usr_user_name.hasData())
if (tempId.getUserName().hasData() && !create)
{
if (!create)
{
Firebird::MetaName loginName(tempId.usr_user_name);
const TEXT* login_name = loginName.c_str();
const TEXT* login_name = tempId.getUserName().c_str();
AutoCacheRequest request(tdbb, irq_get_role_name, IRQ_REQUESTS);
@ -1142,7 +1099,6 @@ void SCL_init(thread_db* tdbb, bool create, const UserId& tempId)
}
END_FOR
}
}
// CVC: If we aren't creating a db and sql_role was specified,
// then verify it against rdb$roles and rdb$user_privileges
@ -1154,28 +1110,17 @@ void SCL_init(thread_db* tdbb, bool create, const UserId& tempId)
}
if (!sql_role)
sql_role = tempId.usr_trusted_role.nullStr();
sql_role = tempId.getTrustedRole().nullStr();
MetaName role_name(sql_role ? sql_role : NULL_ROLE);
MemoryPool& pool = *attachment->att_pool;
UserId* const user = FB_NEW_POOL(pool) UserId(pool, tempId);
user->usr_sql_role_name = role_name.c_str();
user->setSqlRole(role_name);
attachment->att_user = user;
if (!create)
{
const bool isRole = role_name != NULL_ROLE;
if (isRole)
{
// Add role itself and all roles cumulatively granted to it. Not only default.
user->usr_granted_roles.add(user->usr_sql_role_name);
SCL_find_granted_roles(tdbb, user->usr_sql_role_name, true, user->usr_granted_roles, false);
}
// Add all default roles granted to user
SCL_find_granted_roles(tdbb, user->usr_user_name, false, user->usr_granted_roles, true);
AutoCacheRequest request(tdbb, irq_get_att_class, IRQ_REQUESTS);
FOR(REQUEST_HANDLE request) X IN RDB$DATABASE
@ -1198,17 +1143,15 @@ void SCL_init(thread_db* tdbb, bool create, const UserId& tempId)
}
END_FOR
}
if (dbb->dbb_owner == user->usr_user_name)
user->usr_flags |= USR_owner;
if (sql_role && SCL_admin_role(tdbb, user->usr_granted_roles))
user->usr_flags |= USR_dba;
}
else
{
dbb->dbb_owner = user->usr_user_name;
user->usr_flags |= USR_owner;
dbb->dbb_owner = user->getUserName();
user->usr_privileges.load(INI_owner_privileges().c_str());
user->usr_granted_roles.clear();
user->usr_granted_roles.add("RDB$ADMIN");
user->usr_flags &= ~USR_newrole;
}
}
@ -1259,15 +1202,13 @@ SecurityClass* SCL_recompute_class(thread_db* tdbb, const TEXT* string)
SET_TDBB(tdbb);
SecurityClass* s_class = SCL_get_class(tdbb, string);
if (!s_class) {
if (!s_class)
return NULL;
}
s_class->scl_flags = compute_access(tdbb, s_class, NULL, 0, NULL);
if (s_class->scl_flags & SCL_exists) {
if (s_class->scl_flags & SCL_exists)
return s_class;
}
// Class no long exists - get rid of it!
@ -1337,6 +1278,31 @@ SecurityClass::flags_t SCL_get_object_mask(const int object_type)
return -1 & ~SCL_corrupt;
}
ULONG SCL_get_number(const UCHAR* acl)
{
/**************************************
*
* g e t _ n u m b e r
*
**************************************
*
* Functional description
* Get value of acl numeric string.
*
**************************************/
ULONG n = 0;
USHORT l = *acl++;
if (l)
{
do {
n = n * UIC_BASE + *acl++ - '0';
} while (--l);
}
return n;
}
static bool check_number(const UCHAR* acl, USHORT number)
{
/**************************************
@ -1350,16 +1316,7 @@ static bool check_number(const UCHAR* acl, USHORT number)
* return true.
*
**************************************/
int n = 0;
USHORT l = *acl++;
if (l)
{
do {
n = n * UIC_BASE + *acl++ - '0';
} while (--l);
}
return (n != number);
return (SCL_get_number(acl) != number);
}
@ -1389,7 +1346,7 @@ static bool check_user_group(thread_db* tdbb, const UCHAR* acl, USHORT number)
**************************************/
SET_TDBB(tdbb);
SLONG n = 0;
ULONG n = 0;
USHORT l = *acl++;
if (l)
@ -1482,13 +1439,26 @@ static SecurityClass::flags_t compute_access(thread_db* tdbb,
jrd_tra* sysTransaction = attachment->getSysTransaction();
SecurityClass::flags_t privileges = 0;
SecurityClass::flags_t sysPriv = SCL_exists;
const SecurityClass::flags_t selectAnyObject = SCL_select | SCL_references;
const SecurityClass::flags_t accessAnyObject = SCL_insert | SCL_update | SCL_delete |
SCL_execute | SCL_usage | selectAnyObject;
const SecurityClass::flags_t anyDdl = SCL_create | SCL_alter | SCL_control | SCL_drop;
if (attachment->locksmith(tdbb, ACCESS_ANY_OBJECT_IN_DATABASE))
sysPriv |= accessAnyObject;
else if (attachment->locksmith(tdbb, SELECT_ANY_OBJECT_IN_DATABASE))
sysPriv |= selectAnyObject;
if (attachment->locksmith(tdbb, MODIFY_ANY_OBJECT_IN_DATABASE))
sysPriv |= anyDdl;
AutoCacheRequest request(tdbb, irq_l_security, IRQ_REQUESTS);
FOR(REQUEST_HANDLE request) X IN RDB$SECURITY_CLASSES
WITH X.RDB$SECURITY_CLASS EQ s_class->scl_name.c_str()
{
privileges |= SCL_exists;
privileges |= sysPriv;
blb* blob = blb::open(tdbb, sysTransaction, &X.RDB$ACL);
UCHAR* buffer = acl.getBuffer(ACL_BLOB_BUFFER_SIZE);
UCHAR* end = buffer;
@ -1552,7 +1522,7 @@ static SecurityClass::flags_t walk_acl(thread_db* tdbb,
// privileges to the base table or (2b) the view must have
// sufficient privileges on the base table.
user.usr_user_name = view->rel_owner_name.c_str();
user.setUserName(view->rel_owner_name.c_str());
}
SecurityClass::flags_t privilege = 0;
@ -1563,11 +1533,6 @@ static SecurityClass::flags_t walk_acl(thread_db* tdbb,
BUGCHECK(160); // msg 160 wrong ACL version
}
if (user.locksmith())
{
return -1 & ~SCL_corrupt;
}
const TEXT* p;
bool hit = false;
UCHAR c;
@ -1583,7 +1548,7 @@ static SecurityClass::flags_t walk_acl(thread_db* tdbb,
switch (c)
{
case id_person:
if (!(p = user.usr_user_name.nullStr()) || check_string(a, p))
if (!(p = user.getUserName().nullStr()) || check_string(a, p))
hit = false;
break;
@ -1606,7 +1571,7 @@ static SecurityClass::flags_t walk_acl(thread_db* tdbb,
{
Firebird::MetaName role_name;
get_string(a, role_name);
if (!user.usr_granted_roles.exist(role_name))
if (!user.roleInUse(tdbb, role_name))
hit = false;
break;
}
@ -1640,6 +1605,11 @@ static SecurityClass::flags_t walk_acl(thread_db* tdbb,
hit = false;
break;
case id_privilege:
if (!user.locksmith(tdbb, SCL_get_number(a)))
hit = false;
break;
case id_node:
break;
@ -1739,10 +1709,71 @@ static SecurityClass::flags_t walk_acl(thread_db* tdbb,
return privilege;
}
void Jrd::UserId::populateDpb(Firebird::ClumpletWriter& dpb)
void UserId::populateDpb(Firebird::ClumpletWriter& dpb)
{
if (usr_auth_block.hasData())
dpb.insertBytes(isc_dpb_auth_block, usr_auth_block.begin(), usr_auth_block.getCount());
else
dpb.insertString(isc_dpb_user_name, usr_user_name);
}
void UserId::makeRoleName(Firebird::MetaName& role, const int dialect)
{
if (role.isEmpty())
return;
switch (dialect)
{
case SQL_DIALECT_V5:
// Invoke utility twice: first to strip quotes, next to uppercase if needed
// For unquoted string nothing bad happens
fb_utils::dpbItemUpper(role);
fb_utils::dpbItemUpper(role);
break;
case SQL_DIALECT_V6_TRANSITION:
case SQL_DIALECT_V6:
fb_utils::dpbItemUpper(role);
break;
default:
break;
}
}
// get privilege bit by name
USHORT SCL_convert_privilege(thread_db* tdbb, jrd_tra* transaction, const Firebird::string& priv)
{
static GlobalPtr<Mutex> privCacheMutex;
static bool cacheFlag = false;
typedef NonPooled<MetaName, USHORT> CachedPriv;
static GlobalPtr<GenericMap<CachedPriv> > privCache;
if (!cacheFlag)
{
MutexLockGuard g(privCacheMutex, FB_FUNCTION);
if (!cacheFlag)
{
privCache->clear();
AutoCacheRequest request(tdbb, irq_get_priv_bit, IRQ_REQUESTS);
FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction)
T IN RDB$TYPES
WITH T.RDB$FIELD_NAME EQ 'RDB$SYSTEM_PRIVILEGES'
{
privCache->put(T.RDB$TYPE_NAME, T.RDB$TYPE);
}
END_FOR
cacheFlag = true;
}
}
USHORT rc;
if (!privCache->get(priv, rc))
(Arg::Gds(isc_wrong_prvlg) << priv).raise();
return rc;
}

View File

@ -28,6 +28,7 @@
#include "../common/classes/tree.h"
#include "../common/security.h"
#include "../jrd/obj.h"
#include "../jrd/SystemPrivileges.h"
namespace Firebird {
class ClumpletWriter;
@ -35,6 +36,8 @@ class ClumpletWriter;
namespace Jrd {
class thread_db;
const size_t ACL_BLOB_BUFFER_SIZE = MAX_USHORT; // used to read/write acl blob
// Security class definition
@ -80,33 +83,149 @@ const SecurityClass::flags_t SCL_usage = 2048; // USAGE access
const SecurityClass::flags_t SCL_create = 4096;
/*
scl pathcalls
SCL_check_access => SCL_get_object_mask => SCL_recompute_class => SCL_get_class => compute_access
=> compute_access => compute_access
SCL_check_database => att_security_class => SCL_get_class => compute_access
=> SCL_recompute_class => SCL_get_class => compute_access
compute_access => walk_acl
*/
// information about the user
const USHORT USR_locksmith = 1; // User has great karma
const USHORT USR_dba = 2; // User has DBA privileges
const USHORT USR_owner = 4; // User owns database
const USHORT USR_mapdown = 8; // Mapping failed when getting context
const USHORT USR_mapdown = 1; // Mapping failed when getting context
const USHORT USR_newrole = 2; // usr_granted_roles array needs refresh
const USHORT USR_external = USR_mapdown;
class UserId
{
public:
// Arbitrary size bitmask
template <unsigned N>
class Bits
{
static const unsigned shift = 3;
static const unsigned bitmask = (1 << shift) - 1;
static const unsigned L = (N >> shift) + (N & bitmask ? 1 : 0);
public:
static const unsigned BYTES_COUNT = L;
Bits()
{
clearAll();
}
Bits(const Bits& b)
{
assign(b);
}
Bits& operator=(const Bits& b)
{
assign(b);
return *this;
}
Bits& set(unsigned i)
{
fb_assert(i < N);
if (i < N)
data[index(i)] |= mask(i);
return *this;
}
Bits& setAll()
{
memset(data, ~0, sizeof data);
return *this;
}
Bits& clear(unsigned i)
{
fb_assert(i < N);
if (i < N)
data[index(i)] &= ~mask(i);
return *this;
}
Bits& clearAll()
{
memset(data, 0, sizeof data);
return *this;
}
bool test(unsigned int i) const
{
fb_assert(i < N);
if (i >= N)
return false;
return data[index(i)] & mask(i);
}
void load(const void* from)
{
memcpy(data, from, sizeof data);
}
void store(void* to) const
{
memcpy(to, data, sizeof data);
}
Bits& operator|=(const Bits& b)
{
for (unsigned n = 0; n < L; ++n)
data[n] |= b.data[n];
return *this;
}
private:
UCHAR data[L];
void assign(const Bits& b)
{
memcpy(data, b.data, sizeof data);
}
static unsigned index(unsigned i)
{
return i >> shift;
}
static UCHAR mask(unsigned i)
{
return 1U << (i & bitmask);
}
};
typedef Bits<maxSystemPrivilege> Privileges;
private:
Firebird::MetaName usr_user_name; // User name
Firebird::MetaName usr_sql_role_name; // Role name
Firebird::SortedArray<Firebird::MetaName> usr_granted_roles; // Granted roles list
mutable Firebird::SortedArray<Firebird::MetaName> usr_granted_roles; // Granted roles list
Firebird::MetaName usr_trusted_role; // Trusted role if set
public:
Firebird::string usr_project_name; // Project name
Firebird::string usr_org_name; // Organization name
Firebird::string usr_auth_method; // Authentication method
private:
mutable Privileges usr_privileges; // Privileges granted to user by default
public:
Auth::AuthenticationBlock usr_auth_block; // Authentication block after mapping
USHORT usr_user_id; // User id
USHORT usr_group_id; // Group id
USHORT usr_flags; // Misc. crud
bool locksmith() const
{
return usr_flags & (USR_locksmith | USR_owner | USR_dba);
}
private:
mutable USHORT usr_flags; // Misc. crud
public:
UserId()
: usr_user_id(0), usr_group_id(0), usr_flags(0)
{}
@ -119,48 +238,132 @@ public:
usr_project_name(p, ui.usr_project_name),
usr_org_name(p, ui.usr_org_name),
usr_auth_method(p, ui.usr_auth_method),
usr_privileges(ui.usr_privileges),
usr_auth_block(p),
usr_user_id(ui.usr_user_id),
usr_group_id(ui.usr_group_id),
usr_flags(ui.usr_flags)
{
usr_auth_block.assign(ui.usr_auth_block);
if (!testFlag(USR_newrole))
usr_granted_roles = ui.usr_granted_roles;
}
UserId(const UserId& ui)
: usr_user_name(ui.usr_user_name),
usr_sql_role_name(ui.usr_sql_role_name),
usr_granted_roles(ui.usr_granted_roles),
usr_trusted_role(ui.usr_trusted_role),
usr_project_name(ui.usr_project_name),
usr_org_name(ui.usr_org_name),
usr_auth_method(ui.usr_auth_method),
usr_privileges(ui.usr_privileges),
usr_user_id(ui.usr_user_id),
usr_group_id(ui.usr_group_id),
usr_flags(ui.usr_flags)
{
usr_auth_block.assign(ui.usr_auth_block);
if (!testFlag(USR_newrole))
usr_granted_roles = ui.usr_granted_roles;
}
UserId& operator=(const UserId& ui)
{
usr_user_name = ui.usr_user_name;
usr_sql_role_name = ui.usr_sql_role_name;
usr_granted_roles = ui.usr_granted_roles;
usr_trusted_role = ui.usr_trusted_role;
usr_project_name = ui.usr_project_name;
usr_org_name = ui.usr_org_name;
usr_privileges = ui.usr_privileges;
usr_auth_method = ui.usr_auth_method;
usr_user_id = ui.usr_user_id;
usr_group_id = ui.usr_group_id;
usr_flags = ui.usr_flags;
usr_auth_block.assign(ui.usr_auth_block);
if (!testFlag(USR_newrole))
usr_granted_roles = ui.usr_granted_roles;
return *this;
}
void populateDpb(Firebird::ClumpletWriter& dpb);
bool locksmith(thread_db* tdbb, ULONG sp) const
{
if (testFlag(USR_newrole))
findGrantedRoles(tdbb);
return usr_privileges.test(sp);
}
static void sclInit(thread_db* tdbb, bool create, const UserId& tempId);
void setUserName(const Firebird::MetaName& userName)
{
if (userName != usr_user_name)
{
usr_flags |= USR_newrole;
usr_user_name = userName;
}
}
const Firebird::MetaName& getUserName() const
{
return usr_user_name;
}
void setTrustedRole(const Firebird::MetaName& roleName)
{
usr_trusted_role = roleName;
}
const Firebird::MetaName& getTrustedRole() const
{
return usr_trusted_role;
}
void setSqlRole(const Firebird::MetaName& roleName)
{
if (roleName != usr_sql_role_name)
{
usr_flags |= USR_newrole;
usr_sql_role_name = roleName;
}
}
const Firebird::MetaName& getSqlRole() const
{
return usr_sql_role_name;
}
void setRoleTrusted();
bool roleInUse(thread_db* tdbb, const Firebird::MetaName& role) const
{
if (testFlag(USR_newrole))
findGrantedRoles(tdbb);
return usr_granted_roles.exist(role);
}
void makeRoleName(const int dialect)
{
makeRoleName(usr_sql_role_name, dialect);
makeRoleName(usr_trusted_role, dialect);
}
bool testFlag(USHORT mask) const
{
return usr_flags & mask;
}
void setFlag(USHORT mask)
{
usr_flags |= (mask & USR_external);
}
static void makeRoleName(Firebird::MetaName& role, const int dialect);
private:
void findGrantedRoles(thread_db* tdbb) const;
};
// These numbers are arbitrary and only used at run-time. Can be changed if necessary at any moment.

View File

@ -53,14 +53,12 @@ void SCL_check_view(Jrd::thread_db* tdbb, const dsc*, Jrd::SecurityClass::flags_
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);
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);
void SCL_find_granted_roles(Jrd::thread_db* tdbb, const Firebird::MetaName& object, bool isRole,
Firebird::SortedArray<Firebird::MetaName>& grantedRoles, bool defaultOnly);
bool SCL_admin_role(Jrd::thread_db* tdbb, const Firebird::SortedArray<Firebird::MetaName>& roles);
Jrd::SecurityClass::flags_t SCL_get_object_mask(const int object_type);
ULONG SCL_get_number(const UCHAR*);
USHORT SCL_convert_privilege(Jrd::thread_db* tdbb, Jrd::jrd_tra* transaction, const Firebird::string& priv);
namespace Jrd {
typedef Firebird::Array<UCHAR> Acl;

View File

@ -158,10 +158,10 @@ void SHUT_database(thread_db* tdbb, SSHORT flag, SSHORT delay, Sync* guard)
// Only platform's user locksmith can shutdown or bring online a database
if (!attachment->locksmith())
if (!attachment->locksmith(tdbb, CHANGE_SHUTDOWN_MODE))
{
ERR_post_nothrow(Arg::Gds(isc_no_priv) << "shutdown" << "database" << dbb->dbb_filename);
if (attachment->att_user->usr_flags & USR_mapdown)
if (attachment->att_user->testFlag(USR_mapdown))
ERR_post_nothrow(Arg::Gds(isc_map_down));
ERR_punt();
}
@ -340,10 +340,10 @@ void SHUT_online(thread_db* tdbb, SSHORT flag, Sync* guard)
// Only platform's user locksmith can shutdown or bring online a database
if (!attachment->att_user->locksmith())
if (!attachment->att_user->locksmith(tdbb, CHANGE_SHUTDOWN_MODE))
{
ERR_post_nothrow(Arg::Gds(isc_no_priv) << "bring online" << "database" << dbb->dbb_filename);
if (attachment->att_user->usr_flags & USR_mapdown)
if (attachment->att_user->testFlag(USR_mapdown))
ERR_post_nothrow(Arg::Gds(isc_map_down));
ERR_punt();
}

View File

@ -39,23 +39,24 @@ namespace Jrd
{
typedef Firebird::CheckStatusWrapper FbStatusVector;
class FbLocalStatus
template <class SW>
class LocalStatusWrapper
{
public:
FbLocalStatus()
LocalStatusWrapper()
: localStatusVector(&localStatus)
{ }
explicit FbLocalStatus(Firebird::MemoryPool& p)
explicit LocalStatusWrapper(Firebird::MemoryPool& p)
: localStatus(p), localStatusVector(&localStatus)
{ }
FbStatusVector* operator->()
SW* operator->()
{
return &localStatusVector;
}
FbStatusVector* operator&()
SW* operator&()
{
return &localStatusVector;
}
@ -66,12 +67,12 @@ namespace Jrd
return localStatusVector.getErrors()[n];
}
const FbStatusVector* operator->() const
const SW* operator->() const
{
return &localStatusVector;
}
const FbStatusVector* operator&() const
const SW* operator&() const
{
return &localStatusVector;
}
@ -85,7 +86,7 @@ namespace Jrd
}
}
void copyTo(FbStatusVector* to) const
void copyTo(SW* to) const
{
fb_utils::copyStatus(to, &localStatusVector);
}
@ -102,9 +103,11 @@ namespace Jrd
private:
Firebird::LocalStatus localStatus;
FbStatusVector localStatusVector;
SW localStatusVector;
};
typedef LocalStatusWrapper<FbStatusVector> FbLocalStatus;
typedef LocalStatusWrapper<Firebird::ThrowStatusWrapper> ThrowLocalStatus;
}
#endif // JRD_STATUS_H

View File

@ -712,8 +712,8 @@ Service::Service(const TEXT* service_name, USHORT spb_length, const UCHAR* spb_d
expandDatabaseName(svc_expected_db, dummy, &config);
string trusted_role;
mapUser(svc_username, trusted_role, NULL, &svc_auth_block, svc_auth_block,
"services manager", NULL, config->getSecurityDatabase(), svc_crypt_callback);
mapUser(true, svc_username, trusted_role, NULL, &svc_auth_block, NULL,
svc_auth_block, "services manager", NULL, config->getSecurityDatabase(), svc_crypt_callback, NULL);
trusted_role.upper();
svc_trusted_role = trusted_role == ADMIN_ROLE;
}
@ -722,7 +722,7 @@ Service::Service(const TEXT* service_name, USHORT spb_length, const UCHAR* spb_d
// we have embedded service connection, check OS auth
if (ISC_get_user(&svc_username, NULL, NULL))
{
svc_username = SYSDBA_USER_NAME;
svc_username = DBA_USER_NAME;
}
}
}
@ -741,7 +741,7 @@ Service::Service(const TEXT* service_name, USHORT spb_length, const UCHAR* spb_d
}
// Check that the validated user has the authority to access this service
if (svc_username != SYSDBA_USER_NAME && !svc_trusted_role) {
if (svc_username != DBA_USER_NAME && !svc_trusted_role) {
user_flag = SVC_user_any;
}
else {

View File

@ -385,7 +385,7 @@ void TRA_commit(thread_db* tdbb, jrd_tra* transaction, const bool retaining_flag
status_exception::raise(&st);
secContext->tra = NULL;
clearMap(tdbb->getDatabase()->dbb_config->getSecurityDatabase());
clearMappingCache(tdbb->getDatabase()->dbb_config->getSecurityDatabase(), MAPPING_CACHE);
transaction->eraseSecDbContext();
}
@ -3637,7 +3637,7 @@ TraceSweepEvent::TraceSweepEvent(thread_db* tdbb)
gds__log("Sweep is started by %s\n"
"\tDatabase \"%s\" \n"
"\tOIT %" SQUADFORMAT", OAT %" SQUADFORMAT", OST %" SQUADFORMAT", Next %" SQUADFORMAT,
att->att_user->usr_user_name.c_str(),
att->att_user->getUserName().c_str(),
att->att_filename.c_str(),
m_sweep_info.getOIT(),
m_sweep_info.getOAT(),

View File

@ -497,7 +497,7 @@ enum dfw_t {
dfw_arg_field_not_null, // set domain to not nullable
dfw_db_crypt, // change database encryption status
dfw_set_linger, // set database linger
dfw_clear_mapping // clear user mapping cache
dfw_clear_cache // clear user mapping cache
};
} //namespace Jrd

View File

@ -278,7 +278,7 @@ void ConfigStorage::checkFile()
gds__log("Audit configuration file \"%s\" is empty", configFileName.c_str());
}
session.ses_user = SYSDBA_USER_NAME;
session.ses_user = DBA_USER_NAME;
session.ses_name = "Firebird Audit";
session.ses_flags = trs_admin | trs_system;

View File

@ -245,30 +245,30 @@ void TraceManager::update_session(const TraceSession& session)
string s_user = session.ses_user;
string t_role;
UserId::Privileges priv;
ULONG mapResult;
{ // scope
AutoSetRestoreFlag<ULONG> autoRestore(&attachment->att_flags, ATT_mapping, true);
Database* dbb = attachment->att_database;
fb_assert(dbb);
mapResult = mapUser(false, s_user, t_role, NULL, NULL, &priv, session.ses_auth,
attachment->att_filename.c_str(), dbb->dbb_filename.c_str(),
dbb->dbb_config->getSecurityDatabase(), dbb->dbb_provider->getCryptCallback(),
attachment->getInterface());
}
if (session.ses_auth.hasData())
{
Database* dbb = attachment->att_database;
fb_assert(dbb);
try
{
mapUser(s_user, t_role, NULL, NULL, session.ses_auth,
attachment->att_filename.c_str(), dbb->dbb_filename.c_str(),
dbb->dbb_config->getSecurityDatabase(),
dbb->dbb_provider->getCryptCallback());
}
catch (const Firebird::Exception&)
{
// Error in mapUser() means missing context, therefore...
return;
}
if (mapResult & MAPUSER_ERROR_NOT_THROWN)
return; // Error in mapUser() means missing context
t_role.upper();
}
if (s_user != SYSDBA_USER_NAME && t_role != ADMIN_ROLE &&
attachment->att_user->usr_user_name != s_user)
if (s_user != DBA_USER_NAME && t_role != ADMIN_ROLE &&
attachment->att_user->getUserName() != s_user && (!priv.test(TRACE_ANY_ATTACHMENT)))
{
return;
}
@ -284,12 +284,9 @@ void TraceManager::update_session(const TraceSession& session)
RefPtr<Config> config;
expandDatabaseName(service->getExpectedDb(), dummy, &config);
try
{
mapUser(s_user, t_role, NULL, NULL, session.ses_auth, "services manager", NULL,
config->getSecurityDatabase(), service->getCryptCallback());
}
catch (const Firebird::Exception&)
if (mapUser(false, s_user, t_role, NULL, NULL, NULL, session.ses_auth, "services manager",
NULL, config->getSecurityDatabase(), service->getCryptCallback(),
NULL) & MAPUSER_ERROR_NOT_THROWN)
{
// Error in mapUser() means missing context, therefore...
return;
@ -298,7 +295,7 @@ void TraceManager::update_session(const TraceSession& session)
t_role.upper();
}
if (s_user != SYSDBA_USER_NAME && t_role != ADMIN_ROLE && service->getUserName() != s_user)
if (s_user != DBA_USER_NAME && t_role != ADMIN_ROLE && service->getUserName() != s_user)
return;
}
else

View File

@ -84,13 +84,13 @@ const char* TraceConnectionImpl::getDatabaseName()
const char* TraceConnectionImpl::getUserName()
{
const UserId* user = m_att->att_user;
return user ? user->usr_user_name.c_str() : NULL;
return user ? user->getUserName().c_str() : NULL;
}
const char* TraceConnectionImpl::getRoleName()
{
const UserId* user = m_att->att_user;
return user ? user->usr_sql_role_name.c_str() : NULL;
return user ? user->getSqlRole().c_str() : NULL;
}
const char* TraceConnectionImpl::getCharSet()

View File

@ -79,7 +79,7 @@ void TraceSvcJrd::setAttachInfo(const string& /*svc_name*/, const string& user,
{
m_authBlock = authBlock;
m_user = user;
m_admin = isAdmin || (m_user == SYSDBA_USER_NAME);
m_admin = isAdmin || (m_user == DBA_USER_NAME);
}
void TraceSvcJrd::startSession(TraceSession& session, bool interactive)

View File

@ -258,13 +258,10 @@ static const UCHAR trigger1[] =
blr_field, 6, 14, 'R', 'D', 'B', '$', 'O', 'W', 'N', 'E', 'R', '_', 'N',
'A', 'M', 'E',
blr_field, 1, 8, 'R', 'D', 'B', '$', 'U', 'S', 'E', 'R',
blr_or,
blr_eql,
blr_user_name,
blr_literal, blr_text, 6, 0, 'S', 'Y', 'S', 'D', 'B', 'A',
blr_eql,
blr_current_role,
blr_literal, blr_text, 9, 0, 'R', 'D', 'B', '$', 'A', 'D', 'M', 'I', 'N',
blr_sys_function, 20, 'R','D','B','$','S','Y','S','T','E','M','_','P','R','I','V','I','L','E','G','E',1,
blr_literal, blr_text2, 2,0, 26,0, 'G','R','A','N','T','_','R','E','V','O','K','E','_','O','N','_','A','N','Y','_','O','B','J','E','C','T',
blr_literal, blr_bool, 1,
blr_begin,
blr_end,
blr_if,
@ -382,13 +379,10 @@ static const UCHAR trigger1[] =
'A', 'M', 'E',
blr_field, 6, 14, 'R', 'D', 'B', '$', 'O', 'W', 'N', 'E', 'R', '_', 'N',
'A', 'M', 'E',
blr_and,
blr_neq,
blr_user_name,
blr_literal, blr_text, 6, 0, 'S', 'Y', 'S', 'D', 'B', 'A',
blr_neq,
blr_current_role,
blr_literal, blr_text, 9, 0, 'R', 'D', 'B', '$', 'A', 'D', 'M', 'I', 'N',
blr_sys_function, 20, 'R','D','B','$','S','Y','S','T','E','M','_','P','R','I','V','I','L','E','G','E',1,
blr_literal, blr_text2, 2,0, 26,0, 'G','R','A','N','T','_','R','E','V','O','K','E','_','O','N','_','A','N','Y','_','O','B','J','E','C','T',
blr_literal, blr_bool, 1,
blr_begin,
blr_if,
blr_not,
@ -473,13 +467,10 @@ static const UCHAR trigger1[] =
'A', 'M', 'E',
blr_field, 6, 14, 'R', 'D', 'B', '$', 'O', 'W', 'N', 'E', 'R', '_', 'N',
'A', 'M', 'E',
blr_and,
blr_neq,
blr_user_name,
blr_literal, blr_text, 6, 0, 'S', 'Y', 'S', 'D', 'B', 'A',
blr_neq,
blr_current_role,
blr_literal, blr_text, 9, 0, 'R', 'D', 'B', '$', 'A', 'D', 'M', 'I', 'N',
blr_sys_function, 20, 'R','D','B','$','S','Y','S','T','E','M','_','P','R','I','V','I','L','E','G','E',1,
blr_literal, blr_text2, 2,0, 26,0, 'G','R','A','N','T','_','R','E','V','O','K','E','_','O','N','_','A','N','Y','_','O','B','J','E','C','T',
blr_literal, blr_bool, 1,
blr_begin,
blr_if,
blr_not,
@ -632,13 +623,10 @@ static const UCHAR trigger1[] =
blr_field, 18, 14, 'R', 'D', 'B', '$', 'O', 'W', 'N', 'E', 'R', '_', 'N',
'A', 'M', 'E',
blr_user_name,
blr_and,
blr_neq,
blr_user_name,
blr_literal, blr_text, 6, 0, 'S', 'Y', 'S', 'D', 'B', 'A',
blr_neq,
blr_current_role,
blr_literal, blr_text, 9, 0, 'R', 'D', 'B', '$', 'A', 'D', 'M', 'I', 'N',
blr_sys_function, 20, 'R','D','B','$','S','Y','S','T','E','M','_','P','R','I','V','I','L','E','G','E',1,
blr_literal, blr_text2, 2,0, 26,0, 'G','R','A','N','T','_','R','E','V','O','K','E','_','O','N','_','A','N','Y','_','O','B','J','E','C','T',
blr_literal, blr_bool, 1,
blr_if,
blr_not,
blr_any,
@ -743,13 +731,10 @@ static const UCHAR trigger1[] =
blr_field, 26, 14, 'R', 'D', 'B', '$', 'O', 'W', 'N', 'E', 'R', '_', 'N',
'A', 'M', 'E',
blr_user_name,
blr_and,
blr_neq,
blr_user_name,
blr_literal, blr_text, 6, 0, 'S', 'Y', 'S', 'D', 'B', 'A',
blr_neq,
blr_current_role,
blr_literal, blr_text, 9, 0, 'R', 'D', 'B', '$', 'A', 'D', 'M', 'I', 'N',
blr_sys_function, 20, 'R','D','B','$','S','Y','S','T','E','M','_','P','R','I','V','I','L','E','G','E',1,
blr_literal, blr_text2, 2,0, 26,0, 'G','R','A','N','T','_','R','E','V','O','K','E','_','O','N','_','A','N','Y','_','O','B','J','E','C','T',
blr_literal, blr_bool, 1,
blr_if,
blr_not,
blr_any,
@ -850,13 +835,10 @@ static const UCHAR trigger1[] =
blr_field, 22, 14, 'R', 'D', 'B', '$', 'O', 'W', 'N', 'E', 'R', '_', 'N',
'A', 'M', 'E',
blr_user_name,
blr_and,
blr_neq,
blr_user_name,
blr_literal, blr_text, 6, 0, 'S', 'Y', 'S', 'D', 'B', 'A',
blr_neq,
blr_current_role,
blr_literal, blr_text, 9, 0, 'R', 'D', 'B', '$', 'A', 'D', 'M', 'I', 'N',
blr_sys_function, 20, 'R','D','B','$','S','Y','S','T','E','M','_','P','R','I','V','I','L','E','G','E',1,
blr_literal, blr_text2, 2,0, 26,0, 'G','R','A','N','T','_','R','E','V','O','K','E','_','O','N','_','A','N','Y','_','O','B','J','E','C','T',
blr_literal, blr_bool, 1,
blr_if,
blr_not,
blr_any,
@ -2383,13 +2365,10 @@ static const UCHAR trigger31[] =
blr_neq,
blr_field, 1, 11, 'R', 'D', 'B', '$', 'G', 'R', 'A', 'N', 'T', 'O', 'R',
blr_user_name,
blr_and,
blr_neq,
blr_user_name,
blr_literal, blr_text, 6, 0, 'S', 'Y', 'S', 'D', 'B', 'A',
blr_neq,
blr_current_role,
blr_literal, blr_text, 9, 0, 'R', 'D', 'B', '$', 'A', 'D', 'M', 'I', 'N',
blr_sys_function, 20, 'R','D','B','$','S','Y','S','T','E','M','_','P','R','I','V','I','L','E','G','E',1,
blr_literal, blr_text2, 2,0, 21,0, 'U','S','E','_','G','R','A','N','T','E','D','_','B','Y','_','C','L','A','U','S','E',
blr_literal, blr_bool, 1,
blr_begin,
blr_for,
blr_rse, 1,

View File

@ -187,3 +187,7 @@ TYPE("DETERMINISTIC", 1, nam_deterministic_flag)
TYPE("USER", 0, nam_map_to_type)
TYPE("ROLE", 1, nam_map_to_type)
#define SYSTEM_PRIVILEGE(p) TYPE(STRINGIZE(p), int(Jrd::p), nam_system_privileges)
#include "SystemPrivileges.h"
#undef SYSTEM_PRIVILEGE

View File

@ -1464,14 +1464,14 @@ void VIO_erase(thread_db* tdbb, record_param* rpb, jrd_tra* transaction)
break;
case rel_types:
if (!tdbb->getAttachment()->locksmith())
if (!tdbb->getAttachment()->locksmith(tdbb, CREATE_USER_TYPES))
protect_system_table_delupd(tdbb, relation, "DELETE", true);
if (EVL_field(0, rpb->rpb_record, f_typ_sys_flag, &desc) && MOV_get_long(&desc, 0))
protect_system_table_delupd(tdbb, relation, "DELETE", true);
break;
case rel_db_creators:
if (!tdbb->getAttachment()->locksmith())
if (!tdbb->getAttachment()->locksmith(tdbb, GRANT_REVOKE_ANY_DDL_RIGHT))
protect_system_table_delupd(tdbb, relation, "DELETE");
break;
@ -2486,14 +2486,14 @@ void VIO_modify(thread_db* tdbb, record_param* org_rpb, record_param* new_rpb, j
break;
case rel_types:
if (!tdbb->getAttachment()->locksmith())
if (!tdbb->getAttachment()->locksmith(tdbb, CREATE_USER_TYPES))
protect_system_table_delupd(tdbb, relation, "UPDATE", true);
if (EVL_field(0, org_rpb->rpb_record, f_typ_sys_flag, &desc1) && MOV_get_long(&desc1, 0))
protect_system_table_delupd(tdbb, relation, "UPDATE", true);
break;
case rel_db_creators:
if (!tdbb->getAttachment()->locksmith())
if (!tdbb->getAttachment()->locksmith(tdbb, GRANT_REVOKE_ANY_DDL_RIGHT))
protect_system_table_delupd(tdbb, relation, "UPDATE");
break;
@ -3114,14 +3114,14 @@ void VIO_store(thread_db* tdbb, record_param* rpb, jrd_tra* transaction)
break;
case rel_db_creators:
if (!tdbb->getAttachment()->locksmith())
if (!tdbb->getAttachment()->locksmith(tdbb, GRANT_REVOKE_ANY_DDL_RIGHT))
protect_system_table_insert(tdbb, request, relation);
break;
case rel_types:
if (!(tdbb->getDatabase()->dbb_flags & DBB_creating))
{
if (!tdbb->getAttachment()->locksmith())
if (!tdbb->getAttachment()->locksmith(tdbb, CREATE_USER_TYPES))
protect_system_table_insert(tdbb, request, relation, true);
else if (EVL_field(0, rpb->rpb_record, f_typ_sys_flag, &desc) && MOV_get_long(&desc, 0))
protect_system_table_insert(tdbb, request, relation, true);
@ -3390,7 +3390,7 @@ void VIO_store(thread_db* tdbb, record_param* rpb, jrd_tra* transaction)
break;
case rel_backup_history:
if (!tdbb->getAttachment()->locksmith())
if (!tdbb->getAttachment()->locksmith(tdbb, USE_NBACKUP_UTILITY))
protect_system_table_insert(tdbb, request, relation);
set_metadata_id(tdbb, rpb->rpb_record,
f_backup_id, drq_g_nxt_nbakhist_id, "RDB$BACKUP_HISTORY");
@ -3823,7 +3823,7 @@ static void check_class(thread_db* tdbb,
static bool check_nullify_source(thread_db* tdbb, record_param* org_rpb, record_param* new_rpb,
int field_id_1, int field_id_2)
{
if (!tdbb->getAttachment()->locksmith())
if (!tdbb->getAttachment()->locksmith(tdbb, NULL_PRIVILEGE)) // legacy right - no system privilege tuning !!!
return false;
bool nullify_found = false;
@ -3880,7 +3880,7 @@ static void check_owner(thread_db* tdbb,
return;
const Jrd::Attachment* const attachment = tdbb->getAttachment();
const Firebird::MetaName name(attachment->att_user->usr_user_name);
const Firebird::MetaName name(attachment->att_user->getUserName());
desc2.makeText((USHORT) name.length(), CS_METADATA, (UCHAR*) name.c_str());
if (!MOV_compare(&desc1, &desc2))
return;
@ -3905,7 +3905,7 @@ static bool check_user(thread_db* tdbb, const dsc* desc)
const TEXT* p = (TEXT *) desc->dsc_address;
const TEXT* const end = p + desc->dsc_length;
const TEXT* q = tdbb->getAttachment()->att_user->usr_user_name.c_str();
const TEXT* q = tdbb->getAttachment()->att_user->getUserName().c_str();
// It is OK to not internationalize this function for v4.00 as
// User names are limited to 7-bit ASCII for v4.00
@ -4302,7 +4302,7 @@ static THREAD_ENTRY_DECLARE garbage_collector(THREAD_ENTRY_PARAM arg)
try
{
UserId user;
user.usr_user_name = "Garbage Collector";
user.setUserName("Garbage Collector");
Jrd::Attachment* const attachment = Jrd::Attachment::create(dbb);
RefPtr<SysStableAttachment> sAtt(FB_NEW SysStableAttachment(attachment));
@ -5590,7 +5590,7 @@ static void set_owner_name(thread_db* tdbb, Record* record, USHORT field_id)
if (!EVL_field(0, record, field_id, &desc1))
{
const Jrd::Attachment* const attachment = tdbb->getAttachment();
const Firebird::MetaName name(attachment->att_user->usr_user_name);
const Firebird::MetaName name(attachment->att_user->getUserName());
dsc desc2;
desc2.makeText((USHORT) name.length(), CS_METADATA, (UCHAR*) name.c_str());
MOV_move(tdbb, &desc2, &desc1);

View File

@ -1,19 +1,19 @@
/* 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 (?, ?, ?, ?);
--
('2016-05-15 12:46:00', 'JRD', 0, 791)
('2016-05-26 12:14:49', 'JRD', 0, 793)
('2015-03-17 18:33:00', 'QLI', 1, 533)
('2015-01-07 18:01:51', 'GFIX', 3, 134)
('1996-11-07 13:39:40', 'GPRE', 4, 1)
('2016-02-23 00:00:00', 'DSQL', 7, 40)
('2016-03-22 17:41:18', 'DYN', 8, 292)
('2016-05-30 17:56:47', 'DYN', 8, 296)
('1996-11-07 13:39:40', 'INSTALL', 10, 1)
('1996-11-07 13:38:41', 'TEST', 11, 4)
('2015-07-23 14:20:00', 'GBAK', 12, 370)
('2015-08-05 12:40:00', 'SQLERR', 13, 1045)
('1996-11-07 13:38:42', 'SQLWARN', 14, 613)
('2006-09-10 03:04:31', 'JRD_BUGCHK', 15, 307)
('2016-01-18 19:20:48', 'ISQL', 17, 195)
('2016-05-26 13:53:45', 'ISQL', 17, 196)
('2010-07-10 10:50:30', 'GSEC', 18, 105)
('2015-01-07 18:01:51', 'GSTAT', 21, 58)
('2013-12-19 17:31:31', 'FBSVCMGR', 22, 58)

View File

@ -898,6 +898,8 @@ Data source : @4', NULL, NULL)
('bad_crypt_key', NULL, 'CryptoManager.cpp', NULL, 0, 788, NULL, 'Invalid crypt key @1', NULL, NULL);
('encrypt_error', NULL, 'CryptoManager.cpp', NULL, 0, 789, NULL, 'Page requires encyption but crypt plugin is missing', NULL, NULL);
('max_idx_depth', NULL, 'btr.cpp', NULL, 0, 790, NULL, 'Maximum index depth (@1 levels) is reached', NULL, NULL);
('wrong_prvlg', 'SCL_convert_privilege', 'scl.epp', NULL, 0, 791, NULL, 'System privilege @1 does not exist', NULL, NULL);
('miss_prvlg', 'validateAccess', 'jrd.cpp', NULL, 0, 792, NULL, 'Unable to perform operation: system privilege @1 is missing', 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);
@ -1931,7 +1933,7 @@ COMMIT WORK;
('dyn_cannot_addrem_computed', 'DYN_modify_sql_field', 'dyn_mod.epp', NULL, 8, 249, NULL, 'Cannot add or remove COMPUTED from column @1', NULL, NULL);
('dyn_no_empty_pw', 'dyn_user', 'dyn.epp', NULL, 8, 250, NULL, 'Password should not be empty string', NULL, NULL);
('dyn_dup_index', 'DYN_define_index', 'dyn_def.epp', NULL, 8, 251, NULL, 'Index @1 already exists', NULL, NULL);
('dyn_locksmith_use_granted', 'grant/revoke', 'dyn.epp', NULL, 8, 252, NULL, 'Only @1 or database owner can use GRANTED BY clause', NULL, NULL);
('dyn_locksmith_use_granted', 'grant/revoke', 'dyn.epp', NULL, 8, 252, NULL, 'Only @1 or user with privilege USE_GRANTED_BY_CLAUSE can use GRANTED BY clause', NULL, NULL);
('dyn_dup_exception', 'DYN_define_exception', 'dyn_def.epp', NULL, 8, 253, NULL, 'Exception @1 already exists', NULL, NULL);
('dyn_dup_generator', 'DYN_define_generator', 'dyn_def.epp', NULL, 8, 254, NULL, 'Sequence @1 already exists', NULL, NULL);
(NULL, 'revoke_all', 'dyn.epp', NULL, 8, 255, NULL, 'ERASE RDB$USER_PRIVILEGES failed in REVOKE ALL ON ALL', NULL, NULL);
@ -1972,6 +1974,9 @@ COMMIT WORK;
('dyn_defvaldecl_package_func', 'CreatePackageBodyNode::execute', 'PackageNodes.epp', NULL, 8, 290, NULL, 'Default values for parameters are allowed only in declaration of packaged function @1.@2', NULL, NULL);
('dyn_create_user_no_password', 'CreateAlterUserNode', 'DdlNodes.epp', NULL, 8, 291, NULL, 'Password must be specified when creating user', NULL, NULL);
('dyn_cyclic_role', 'GrantRevokeNode::grantRevoke', 'DdlNodes.epp', NULL, 8, 292, NULL, 'role @1 can not be granted to role @2', NULL, NULL);
(NULL, 'CreateAlterRoleNode::execute', 'DdlNodes.epp', NULL, 8, 293, NULL, 'DROP SYSTEM PRIVILEGES should not be used in CREATE ROLE operator', NULL, NULL);
(NULL, 'CreateAlterRoleNode::execute', 'DdlNodes.epp', NULL, 8, 294, NULL, 'Access to SYSTEM PRIVILEGES in ROLES denied to @1', NULL, NULL);
(NULL, 'grant/revoke', 'DdlNode.epp', NULL, 8, 295, NULL, 'Only @1, DB owner @2 or user with privilege USE_GRANTED_BY_CLAUSE can use GRANTED BY clause', NULL, NULL);
COMMIT WORK;
-- TEST
(NULL, 'main', 'test.c', NULL, 11, 0, NULL, 'This is a modified text message', NULL, NULL);
@ -3054,6 +3059,7 @@ Fetches = !', NULL, NULL);
('DATABASE_CRYPTED', 'SHOW_dbb_parameters', 'show.epp', NULL, 17, 192, NULL, 'Database encrypted', NULL, NULL);
('DATABASE_NOT_CRYPTED', 'SHOW_dbb_parameters', 'show.epp', NULL, 17, 193, NULL, 'Database not encrypted', NULL, NULL);
('DATABASE_CRYPT_PROCESS', 'SHOW_dbb_parameters', 'show.epp', NULL, 17, 194, NULL, 'crypt thread not complete', NULL, NULL);
('MSG_ROLES', 'SHOW_metadata', 'show.epp', NULL, 17, 195, NULL, 'Roles:', NULL, NULL);
-- GSEC
('GsecMsg1', 'get_line', 'gsec.e', NULL, 18, 1, NULL, 'GSEC>', NULL, NULL);
('GsecMsg2', 'printhelp', 'gsec.e', 'This message is used in the Help display. It should be the same as number 1 (but in lower case).', 18, 2, NULL, 'gsec', NULL, NULL);

View File

@ -797,6 +797,8 @@ set bulk_insert INSERT INTO SYSTEM_ERRORS (SQL_CODE, SQL_CLASS, SQL_SUBCLASS, FA
(-902, '08', '006', 0, 788, 'bad_crypt_key', NULL, NULL)
(-901, 'XX', '000', 0, 789, 'encrypt_error', NULL, NULL)
(-904, '54', '000', 0, 790, 'max_idx_depth', NULL, NULL)
(-901, '0A', '000', 0, 791, 'wrong_prvlg', NULL, NULL)
(-902, '28', '000', 0, 792, 'miss_prvlg', NULL, NULL)
-- GFIX
(-901, '00', '000', 3, 1, 'gfix_db_name', NULL, NULL)
(-901, '00', '000', 3, 2, 'gfix_invalid_sw', NULL, NULL)

View File

@ -131,7 +131,7 @@ int CLIB_ROUTINE main( int argc, char **argv)
!strcmp(pw->pw_name, INTERBASE_USER_NAME) ||
!strcmp(pw->pw_name, INTERBASE_USER_SHORT))
{
strcpy(ibmgr_data.user, SYSDBA_USER_NAME);
strcpy(ibmgr_data.user, DBA_USER_NAME);
}
else
copy_str_upper(ibmgr_data.user, pw->pw_name);
@ -882,7 +882,7 @@ static SSHORT parse_cmd_line( int argc, TEXT** argv, bool zapPasswd)
switch (ibmgr_data.operation)
{
case OP_SHUT:
if (strcmp(ibmgr_data.user, SYSDBA_USER_NAME))
if (strcmp(ibmgr_data.user, DBA_USER_NAME))
{
SRVRMGR_msg_get(MSG_NOPERM, msg);
fprintf(OUTFILE, "%s\n", msg);
@ -906,7 +906,7 @@ static SSHORT parse_cmd_line( int argc, TEXT** argv, bool zapPasswd)
strcmp(ibmgr_data.real_user, FIREBIRD_USER_NAME) &&
strcmp(ibmgr_data.real_user, INTERBASE_USER_NAME) &&
strcmp(ibmgr_data.real_user, INTERBASE_USER_SHORT)) ||
strcmp(ibmgr_data.user, SYSDBA_USER_NAME))
strcmp(ibmgr_data.user, DBA_USER_NAME))
{
SRVRMGR_msg_get(MSG_NOPERM, msg);
fprintf(OUTFILE, "%s\n", msg);

View File

@ -325,12 +325,12 @@ static bool attach_service( ibmgr_data_t* data)
TEXT spb[SPB_BUFLEN];
TEXT* p = spb;
if (!strcmp(data->user, SYSDBA_USER_NAME))
if (!strcmp(data->user, DBA_USER_NAME))
{
*p++ = isc_spb_version1;
*p++ = isc_spb_user_name;
*p++ = strlen(SYSDBA_USER_NAME);
strcpy(p, SYSDBA_USER_NAME);
*p++ = strlen(DBA_USER_NAME);
strcpy(p, DBA_USER_NAME);
p += strlen(p);
*p++ = isc_spb_password;
*p++ = strlen(data->password);

View File

@ -318,6 +318,7 @@ static const TOK tokens[] =
{PRESERVE, "PRESERVE", 2, true},
{PRIMARY, "PRIMARY", 1, false},
{PRIOR, "PRIOR", 2, true},
{PRIVILEGE, "PRIVILEGE", 1, false},
{PRIVILEGES, "PRIVILEGES", 1, false},
{PROCEDURE, "PROCEDURE", 1, false},
{PROTECTED, "PROTECTED", 1, false},
@ -328,6 +329,7 @@ static const TOK tokens[] =
{RDB_RECORD_VERSION, "RDB$RECORD_VERSION", 2, false},
{RDB_ROLE_IN_USE, "RDB$ROLE_IN_USE", 2, false},
{RDB_SET_CONTEXT, "RDB$SET_CONTEXT", 2, true},
{RDB_SYSTEM_PRIVILEGE, "RDB$SYSTEM_PRIVILEGE", 2, false},
{READ, "READ", 1, false},
{REAL, "REAL", 1, false},
{VERSION, "RECORD_VERSION", 1, false},
@ -408,6 +410,7 @@ static const TOK tokens[] =
{SUB_TYPE, "SUB_TYPE", 1, false},
{SUM, "SUM", 1, false},
{SUSPEND, "SUSPEND", 1, false},
{SYSTEM, "SYSTEM", 1, false},
{TABLE, "TABLE", 1, false},
{TAGS, "TAGS", 2, true},
{TAN, "TAN", 2, false},