mirror of
https://github.com/FirebirdSQL/firebird.git
synced 2025-01-22 17:23:03 +01:00
Added support for system privileges
This commit is contained in:
parent
70e3848eeb
commit
7ad99b795e
@ -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
|
||||
-------
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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,10 +108,18 @@ 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);
|
||||
check(&statusWrapper);
|
||||
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);
|
||||
}
|
||||
|
||||
ddlTran->commit(&statusWrapper);
|
||||
|
@ -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());
|
||||
|
@ -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
|
||||
{
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
|
@ -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; }
|
||||
|
||||
|
@ -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)
|
||||
{
|
||||
SCL_check_create_access(tdbb, SCL_object_role);
|
||||
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,11 +11253,13 @@ 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);
|
||||
// 292: role @1 can not be granted to role @2
|
||||
if (grantedRoles.exist(user.c_str()))
|
||||
UserId grantedRoles;
|
||||
grantedRoles.setSqlRole(objName);
|
||||
if (grantedRoles.roleInUse(tdbb, user))
|
||||
{
|
||||
// 292: role @1 can not be granted to role @2
|
||||
status_exception::raise(Arg::PrivateDyn(292) << objName.c_str() << user.c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
@ -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);
|
||||
|
@ -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),
|
||||
|
@ -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));
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
;
|
||||
|
||||
%%
|
||||
|
@ -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;
|
||||
|
@ -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},
|
||||
|
@ -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
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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 */
|
||||
|
@ -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 */
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
*
|
||||
**************************************/
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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()
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
@ -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()
|
||||
|
@ -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,161 +1166,91 @@ 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 (;;)
|
||||
{
|
||||
for (;;)
|
||||
if (syncType == SYNC_EXCLUSIVE)
|
||||
{
|
||||
if (syncType == SYNC_EXCLUSIVE)
|
||||
if (!iSec)
|
||||
iSec.attach(st, securityAlias, cryptCb);
|
||||
|
||||
if (db && !iDb)
|
||||
iDb.attach(st, alias, cryptCb);
|
||||
}
|
||||
|
||||
MutexEnsureUnlock g(treeMutex, FB_FUNCTION);
|
||||
g.enter();
|
||||
|
||||
Cache* cDb = NULL;
|
||||
if (db)
|
||||
cDb = locate(alias, db);
|
||||
Cache* cSec = locate(securityAlias, securityDb);
|
||||
if (cDb == cSec)
|
||||
cDb = NULL;
|
||||
|
||||
SyncObject dummySync1, dummySync2;
|
||||
Sync sDb(((!(flags & FLAG_DB)) && cDb) ? &cDb->syncObject : &dummySync1, FB_FUNCTION);
|
||||
Sync sSec((!(flags & FLAG_SEC)) ? &cSec->syncObject : &dummySync2, FB_FUNCTION);
|
||||
|
||||
sSec.lock(syncType);
|
||||
if (!sDb.lockConditional(syncType))
|
||||
{
|
||||
// Avoid deadlocks cause hell knows which db is security for which
|
||||
sSec.unlock();
|
||||
// Now safely wait for sSec
|
||||
sDb.lock(syncType);
|
||||
// and repeat whole operation
|
||||
continue;
|
||||
}
|
||||
|
||||
// Required cache(s) are locked somehow - release treeMutex
|
||||
g.leave();
|
||||
|
||||
// Check is it required to populate caches from DB
|
||||
if ((cDb && !cDb->dataFlag) || !cSec->dataFlag)
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MutexEnsureUnlock g(treeMutex, FB_FUNCTION);
|
||||
g.enter();
|
||||
|
||||
Cache* cDb = NULL;
|
||||
if (db)
|
||||
cDb = locate(alias, db);
|
||||
Cache* cSec = locate(securityAlias, securityDb);
|
||||
if (cDb == cSec)
|
||||
cDb = NULL;
|
||||
|
||||
SyncObject dummySync1, dummySync2;
|
||||
Sync sDb(((!(flags & FLAG_DB)) && cDb) ? &cDb->syncObject : &dummySync1, FB_FUNCTION);
|
||||
Sync sSec((!(flags & FLAG_SEC)) ? &cSec->syncObject : &dummySync2, FB_FUNCTION);
|
||||
|
||||
sSec.lock(syncType);
|
||||
if (!sDb.lockConditional(syncType))
|
||||
{
|
||||
// Avoid deadlocks cause hell knows which db is security for which
|
||||
syncType = SYNC_EXCLUSIVE;
|
||||
sSec.unlock();
|
||||
// Now safely wait for sSec
|
||||
sDb.lock(syncType);
|
||||
// and repeat whole operation
|
||||
sDb.unlock();
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
// Required cache(s) are locked somehow - release treeMutex
|
||||
g.leave();
|
||||
|
||||
// Check is it required to populate caches from DB
|
||||
if ((cDb && !cDb->dataFlag) || !cSec->dataFlag)
|
||||
{
|
||||
if (syncType != SYNC_EXCLUSIVE)
|
||||
{
|
||||
syncType = SYNC_EXCLUSIVE;
|
||||
sSec.unlock();
|
||||
sDb.unlock();
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (cDb)
|
||||
cDb->populate(iDb, dbDown);
|
||||
cSec->populate(iSec, secDown);
|
||||
|
||||
sSec.downgrade(SYNC_SHARED);
|
||||
sDb.downgrade(SYNC_SHARED);
|
||||
}
|
||||
|
||||
// use down flags from caches
|
||||
if (cDb)
|
||||
dbDown = cDb->downFlag;
|
||||
secDown = cSec->downFlag;
|
||||
cDb->populate(iDb, dbDown);
|
||||
cSec->populate(iSec, secDown);
|
||||
|
||||
// Caches are ready somehow - proceed with analysis
|
||||
AuthReader auth(authBlock);
|
||||
sSec.downgrade(SYNC_SHARED);
|
||||
sDb.downgrade(SYNC_SHARED);
|
||||
}
|
||||
|
||||
// Map in simple mode first main, next security db
|
||||
if (cDb && cDb->map4(false, flags & FLAG_DB, auth, info, newBlock))
|
||||
break;
|
||||
if (cSec->map4(false, flags & FLAG_SEC, auth, info, newBlock))
|
||||
break;
|
||||
// use down flags from caches
|
||||
if (cDb)
|
||||
dbDown = cDb->downFlag;
|
||||
secDown = cSec->downFlag;
|
||||
|
||||
// Map in wildcard mode first main, next security db
|
||||
if (cDb && cDb->map4(true, flags & FLAG_DB, auth, info, newBlock))
|
||||
break;
|
||||
cSec->map4(true, flags & FLAG_SEC, auth, info, newBlock);
|
||||
// Caches are ready somehow - proceed with analysis
|
||||
AuthReader auth(authBlock);
|
||||
|
||||
// Map in simple mode first main, next security db
|
||||
if (cDb && cDb->map4(false, flags & FLAG_DB, auth, info, newBlock))
|
||||
break;
|
||||
if (cSec->map4(false, flags & FLAG_SEC, auth, info, newBlock))
|
||||
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;
|
||||
// Map in wildcard mode first main, next security db
|
||||
if (cDb && cDb->map4(true, flags & FLAG_DB, auth, info, newBlock))
|
||||
break;
|
||||
cSec->map4(true, flags & FLAG_SEC, auth, info, newBlock);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
for (AuthReader rdr(newBlock); rdr.getInfo(info); rdr.moveNext())
|
||||
@ -1134,35 +1302,69 @@ 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)
|
||||
{
|
||||
Arg::Gds v(isc_sec_context);
|
||||
v << alias;
|
||||
if (secDown || dbDown)
|
||||
v << Arg::Gds(isc_map_down);
|
||||
v.raise();
|
||||
if (throwNotFoundError)
|
||||
{
|
||||
Arg::Gds v(isc_sec_context);
|
||||
v << alias;
|
||||
if (rc & MAPUSER_MAP_DOWN)
|
||||
v << Arg::Gds(isc_map_down);
|
||||
v.raise();
|
||||
}
|
||||
rc |= MAPUSER_ERROR_NOT_THROWN;
|
||||
}
|
||||
|
||||
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()));
|
||||
if (auth_method)
|
||||
*auth_method = fName.method.ToString();
|
||||
|
||||
if (newAuthBlock)
|
||||
else
|
||||
{
|
||||
newAuthBlock->shrink(0);
|
||||
newAuthBlock->push(newBlock.getBuffer(), newBlock.getBufferLength());
|
||||
MAP_DEBUG(fprintf(stderr, "Saved to newAuthBlock %u bytes\n",
|
||||
static_cast<unsigned>(newAuthBlock->getCount())));
|
||||
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()));
|
||||
if (auth_method)
|
||||
*auth_method = fName.method.ToString();
|
||||
|
||||
if (newAuthBlock)
|
||||
{
|
||||
newAuthBlock->shrink(0);
|
||||
newAuthBlock->push(newBlock.getBuffer(), newBlock.getBufferLength());
|
||||
MAP_DEBUG(fprintf(stderr, "Saved to newAuthBlock %u bytes\n",
|
||||
static_cast<unsigned>(newAuthBlock->getCount())));
|
||||
}
|
||||
}
|
||||
|
||||
return secDown || dbDown;
|
||||
if (name.hasData() || trusted_role.hasData())
|
||||
{
|
||||
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 clearMap(const char* dbName)
|
||||
void clearMappingCache(const char* dbName, USHORT index)
|
||||
{
|
||||
mappingIpc->clearMap(dbName);
|
||||
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);
|
||||
|
||||
|
@ -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
|
||||
{
|
||||
|
@ -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());
|
||||
|
@ -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},
|
||||
|
49
src/jrd/SystemPrivileges.h
Normal file
49
src/jrd/SystemPrivileges.h
Normal 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
|
@ -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())
|
||||
|
@ -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:
|
||||
|
||||
|
@ -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));
|
||||
|
@ -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";
|
||||
|
@ -55,7 +55,7 @@ static const UCHAR dflt_full[] =
|
||||
};
|
||||
|
||||
/* default value of "RESTRICT" for RDB$UPDATE_RULE, RDB$DELETE_RULE in
|
||||
RDB$REF_CONSTRAINTS */
|
||||
RDB$REF_CONSTRAINTS */
|
||||
|
||||
static const UCHAR dflt_restrict[] =
|
||||
{
|
||||
@ -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
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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;
|
||||
|
155
src/jrd/ini.epp
155
src/jrd/ini.epp
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
//******************************
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
199
src/jrd/jrd.cpp
199
src/jrd/jrd.cpp
@ -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])
|
||||
{
|
||||
throw;
|
||||
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());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
329
src/jrd/scl.epp
329
src/jrd/scl.epp
@ -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,26 +1082,22 @@ 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)
|
||||
const TEXT* login_name = tempId.getUserName().c_str();
|
||||
|
||||
AutoCacheRequest request(tdbb, irq_get_role_name, IRQ_REQUESTS);
|
||||
|
||||
FOR(REQUEST_HANDLE request) X IN RDB$ROLES
|
||||
WITH X.RDB$ROLE_NAME EQ login_name
|
||||
{
|
||||
Firebird::MetaName loginName(tempId.usr_user_name);
|
||||
const TEXT* login_name = loginName.c_str();
|
||||
|
||||
AutoCacheRequest request(tdbb, irq_get_role_name, IRQ_REQUESTS);
|
||||
|
||||
FOR(REQUEST_HANDLE request) X IN RDB$ROLES
|
||||
WITH X.RDB$ROLE_NAME EQ login_name
|
||||
{
|
||||
ERR_post(Arg::Gds(isc_login_same_as_role_name) << Arg::Str(login_name));
|
||||
}
|
||||
END_FOR
|
||||
ERR_post(Arg::Gds(isc_login_same_as_role_name) << Arg::Str(login_name));
|
||||
}
|
||||
END_FOR
|
||||
}
|
||||
|
||||
// CVC: If we aren't creating a db and sql_role was specified,
|
||||
@ -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;
|
||||
}
|
||||
|
||||
|
231
src/jrd/scl.h
231
src/jrd/scl.h
@ -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);
|
||||
usr_granted_roles = ui.usr_granted_roles;
|
||||
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.
|
||||
|
@ -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;
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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 {
|
||||
|
@ -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(),
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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
|
||||
|
@ -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()
|
||||
|
@ -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)
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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},
|
||||
|
Loading…
Reference in New Issue
Block a user