mirror of
https://github.com/FirebirdSQL/firebird.git
synced 2025-02-02 10:40:38 +01:00
Implemented CORE-1377: Add an ability to change role without reconnecting to database
This commit is contained in:
parent
235fb16aa9
commit
9bd0939f09
@ -1590,6 +1590,10 @@ C --
|
||||
PARAMETER (GDS__map_nodb = 335545088)
|
||||
INTEGER*4 GDS__map_notable
|
||||
PARAMETER (GDS__map_notable = 335545089)
|
||||
INTEGER*4 GDS__miss_trusted_role
|
||||
PARAMETER (GDS__miss_trusted_role = 335545090)
|
||||
INTEGER*4 GDS__set_invalid_role
|
||||
PARAMETER (GDS__set_invalid_role = 335545091)
|
||||
INTEGER*4 GDS__gfix_db_name
|
||||
PARAMETER (GDS__gfix_db_name = 335740929)
|
||||
INTEGER*4 GDS__gfix_invalid_sw
|
||||
|
@ -802,6 +802,8 @@ const
|
||||
gds_baddpb_temp_buffers = 335545087;
|
||||
gds_map_nodb = 335545088;
|
||||
gds_map_notable = 335545089;
|
||||
gds_miss_trusted_role = 335545090;
|
||||
gds_set_invalid_role = 335545091;
|
||||
gds_gfix_db_name = 335740929;
|
||||
gds_gfix_invalid_sw = 335740930;
|
||||
gds_gfix_incmp_sw = 335740932;
|
||||
|
@ -49,6 +49,7 @@
|
||||
#include "../jrd/par_proto.h"
|
||||
#include "../jrd/rlck_proto.h"
|
||||
#include "../jrd/tra_proto.h"
|
||||
#include "../jrd/scl_proto.h"
|
||||
#include "../dsql/ddl_proto.h"
|
||||
#include "../dsql/metd_proto.h"
|
||||
#include "../jrd/vio_proto.h"
|
||||
@ -7593,6 +7594,45 @@ void SetTransactionNode::genTableLock(DsqlCompilerScratch* dsqlScratch,
|
||||
//--------------------
|
||||
|
||||
|
||||
SetRoleNode* SetRoleNode::dsqlPass(DsqlCompilerScratch* dsqlScratch)
|
||||
{
|
||||
dsqlScratch->getStatement()->setType(DsqlCompiledStatement::TYPE_SET_ROLE);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
void SetRoleNode::execute(thread_db* tdbb, dsql_req* request, jrd_tra** transaction) const
|
||||
{
|
||||
SET_TDBB(tdbb);
|
||||
Attachment* const attachment = tdbb->getAttachment();
|
||||
UserId* user = attachment->att_user;
|
||||
fb_assert(user);
|
||||
|
||||
if (trusted)
|
||||
{
|
||||
if (!user->usr_trusted_role.hasData())
|
||||
Arg::Gds(isc_miss_trusted_role).raise();
|
||||
user->usr_sql_role_name = user->usr_trusted_role;
|
||||
}
|
||||
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();
|
||||
}
|
||||
|
||||
if (SCL_admin_role(tdbb, user->usr_sql_role_name.c_str()))
|
||||
user->usr_flags |= USR_dba;
|
||||
else
|
||||
user->usr_flags &= ~USR_dba;
|
||||
|
||||
SCL_release_all(attachment->att_security_classes);
|
||||
}
|
||||
|
||||
|
||||
//--------------------
|
||||
|
||||
|
||||
StmtNode* UpdateOrInsertNode::dsqlPass(DsqlCompilerScratch* dsqlScratch)
|
||||
{
|
||||
thread_db* tdbb = JRD_get_thread_data(); // necessary?
|
||||
|
@ -1509,6 +1509,42 @@ public:
|
||||
};
|
||||
|
||||
|
||||
// This node should better be session management node,
|
||||
// but as long as we do not have other session management and
|
||||
// node is rather similiar internally to transaction management
|
||||
// let it for now be transaction management node.
|
||||
class SetRoleNode : public TransactionNode
|
||||
{
|
||||
public:
|
||||
explicit SetRoleNode(MemoryPool& pool)
|
||||
: TransactionNode(pool),
|
||||
trusted(true),
|
||||
roleName(pool)
|
||||
{
|
||||
}
|
||||
|
||||
SetRoleNode(MemoryPool& pool, Firebird::MetaName* name)
|
||||
: TransactionNode(pool),
|
||||
trusted(false),
|
||||
roleName(pool, *name)
|
||||
{
|
||||
}
|
||||
|
||||
public:
|
||||
virtual void print(Firebird::string& text) const
|
||||
{
|
||||
text = "SetRoleNode";
|
||||
}
|
||||
|
||||
virtual SetRoleNode* dsqlPass(DsqlCompilerScratch* dsqlScratch);
|
||||
virtual void execute(thread_db* tdbb, dsql_req* request, jrd_tra** transaction) const;
|
||||
|
||||
public:
|
||||
bool trusted;
|
||||
Firebird::MetaName roleName;
|
||||
};
|
||||
|
||||
|
||||
class UpdateOrInsertNode : public TypedNode<DsqlOnlyStmtNode, StmtNode::TYPE_UPDATE_OR_INSERT>
|
||||
{
|
||||
public:
|
||||
|
@ -1822,6 +1822,7 @@ static void sql_info(thread_db* tdbb,
|
||||
break;
|
||||
case DsqlCompiledStatement::TYPE_CREATE_DB:
|
||||
case DsqlCompiledStatement::TYPE_DDL:
|
||||
case DsqlCompiledStatement::TYPE_SET_ROLE:
|
||||
number = isc_info_sql_stmt_ddl;
|
||||
break;
|
||||
case DsqlCompiledStatement::TYPE_COMMIT:
|
||||
|
@ -429,7 +429,7 @@ public:
|
||||
TYPE_SELECT, TYPE_SELECT_UPD, TYPE_INSERT, TYPE_DELETE, TYPE_UPDATE, TYPE_UPDATE_CURSOR,
|
||||
TYPE_DELETE_CURSOR, TYPE_COMMIT, TYPE_ROLLBACK, TYPE_CREATE_DB, TYPE_DDL, TYPE_START_TRANS,
|
||||
TYPE_EXEC_PROCEDURE, TYPE_COMMIT_RETAIN, TYPE_ROLLBACK_RETAIN, TYPE_SET_GENERATOR,
|
||||
TYPE_SAVEPOINT, TYPE_EXEC_BLOCK, TYPE_SELECT_BLOCK
|
||||
TYPE_SAVEPOINT, TYPE_EXEC_BLOCK, TYPE_SELECT_BLOCK, TYPE_SET_ROLE
|
||||
};
|
||||
|
||||
// Statement flags.
|
||||
|
@ -569,6 +569,7 @@ using namespace Firebird;
|
||||
%token <metaNamePtr> PLUGIN
|
||||
%token <metaNamePtr> SERVERWIDE
|
||||
%token <metaNamePtr> INCREMENT
|
||||
%token <metaNamePtr> TRUSTED
|
||||
|
||||
// precedence declarations for expression evaluation
|
||||
|
||||
@ -697,6 +698,7 @@ using namespace Firebird;
|
||||
Jrd::CreateAlterUserNode* createAlterUserNode;
|
||||
Jrd::MappingNode* mappingNode;
|
||||
Jrd::MappingNode::OP mappingOp;
|
||||
Jrd::SetRoleNode* setRoleNode;
|
||||
}
|
||||
|
||||
%include types.y
|
||||
@ -749,6 +751,7 @@ tra_statement
|
||||
: set_transaction { $$ = $1; }
|
||||
| commit { $$ = $1; }
|
||||
| rollback { $$ = $1; }
|
||||
| set_role { $$ = $1; }
|
||||
;
|
||||
|
||||
|
||||
@ -4468,6 +4471,14 @@ set_transaction
|
||||
{ $$ = $3; }
|
||||
;
|
||||
|
||||
%type <setRoleNode> set_role
|
||||
set_role
|
||||
: SET ROLE valid_symbol_name
|
||||
{ $$ = newNode<SetRoleNode>($3); }
|
||||
| SET TRUSTED ROLE
|
||||
{ $$ = newNode<SetRoleNode>(); }
|
||||
;
|
||||
|
||||
%type tran_option_list_opt(<setTransactionNode>)
|
||||
tran_option_list_opt($setTransactionNode)
|
||||
: // nothing
|
||||
@ -7373,6 +7384,7 @@ non_reserved_word
|
||||
| PLUGIN
|
||||
| SERVERWIDE
|
||||
| INCREMENT
|
||||
| TRUSTED
|
||||
;
|
||||
|
||||
%%
|
||||
|
@ -791,6 +791,8 @@ static const struct {
|
||||
{"baddpb_temp_buffers", 335545087},
|
||||
{"map_nodb", 335545088},
|
||||
{"map_notable", 335545089},
|
||||
{"miss_trusted_role", 335545090},
|
||||
{"set_invalid_role", 335545091},
|
||||
{"gfix_db_name", 335740929},
|
||||
{"gfix_invalid_sw", 335740930},
|
||||
{"gfix_incmp_sw", 335740932},
|
||||
|
@ -825,6 +825,8 @@ const ISC_STATUS isc_baddpb_buffers_range = 335545086L;
|
||||
const ISC_STATUS isc_baddpb_temp_buffers = 335545087L;
|
||||
const ISC_STATUS isc_map_nodb = 335545088L;
|
||||
const ISC_STATUS isc_map_notable = 335545089L;
|
||||
const ISC_STATUS isc_miss_trusted_role = 335545090L;
|
||||
const ISC_STATUS isc_set_invalid_role = 335545091L;
|
||||
const ISC_STATUS isc_gfix_db_name = 335740929L;
|
||||
const ISC_STATUS isc_gfix_invalid_sw = 335740930L;
|
||||
const ISC_STATUS isc_gfix_incmp_sw = 335740932L;
|
||||
@ -1278,7 +1280,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 = 1222;
|
||||
const ISC_STATUS isc_err_max = 1224;
|
||||
|
||||
#else /* c definitions */
|
||||
|
||||
@ -2073,6 +2075,8 @@ const ISC_STATUS isc_err_max = 1222;
|
||||
#define isc_baddpb_temp_buffers 335545087L
|
||||
#define isc_map_nodb 335545088L
|
||||
#define isc_map_notable 335545089L
|
||||
#define isc_miss_trusted_role 335545090L
|
||||
#define isc_set_invalid_role 335545091L
|
||||
#define isc_gfix_db_name 335740929L
|
||||
#define isc_gfix_invalid_sw 335740930L
|
||||
#define isc_gfix_incmp_sw 335740932L
|
||||
@ -2526,7 +2530,7 @@ const ISC_STATUS isc_err_max = 1222;
|
||||
#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 1222
|
||||
#define isc_err_max 1224
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -794,6 +794,8 @@ Data source : @4"}, /* eds_statement */
|
||||
{335545087, "Attempt to temporarily set number of buffers less than @1"}, /* baddpb_temp_buffers */
|
||||
{335545088, "Global mapping is not available when database @1 is not present"}, /* map_nodb */
|
||||
{335545089, "Global mapping is not available when table RDB$MAP is not present in database @1"}, /* map_notable */
|
||||
{335545090, "Your attachment has no trusted role"}, /* miss_trusted_role */
|
||||
{335545091, "Role @1 is invalid or unavailable"}, /* set_invalid_role */
|
||||
{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 */
|
||||
|
@ -790,6 +790,8 @@ static const struct {
|
||||
{335545087, -924}, /* 767 baddpb_temp_buffers */
|
||||
{335545088, -901}, /* 768 map_nodb */
|
||||
{335545089, -901}, /* 769 map_notable */
|
||||
{335545090, -901}, /* 770 miss_trusted_role */
|
||||
{335545091, -901}, /* 771 set_invalid_role */
|
||||
{335740929, -901}, /* 1 gfix_db_name */
|
||||
{335740930, -901}, /* 2 gfix_invalid_sw */
|
||||
{335740932, -901}, /* 4 gfix_incmp_sw */
|
||||
|
@ -790,6 +790,8 @@ static const struct {
|
||||
{335545087, "HY000"}, // 767 baddpb_temp_buffers
|
||||
{335545088, "0A000"}, // 768 map_nodb
|
||||
{335545089, "0A000"}, // 769 map_notable
|
||||
{335545090, "0P000"}, // 770 miss_trusted_role
|
||||
{335545091, "0P000"}, // 771 set_invalid_role
|
||||
{335740929, "00000"}, // 1 gfix_db_name
|
||||
{335740930, "00000"}, // 2 gfix_invalid_sw
|
||||
{335740932, "00000"}, // 4 gfix_incmp_sw
|
||||
|
@ -4918,7 +4918,7 @@ static processing_state frontend_set(const char* cmd, const char* const* parms,
|
||||
//#ifdef DEV_BUILD
|
||||
sqlda_display,
|
||||
//#endif
|
||||
sql, warning, generator, statistics, heading, bail,
|
||||
sql, warning, sqlCont, heading, bail,
|
||||
bulk_insert, maxrows, wrong
|
||||
};
|
||||
SetOptions(const optionsMap* inmap, size_t insize, int wrongval)
|
||||
@ -4948,13 +4948,15 @@ static processing_state frontend_set(const char* cmd, const char* const* parms,
|
||||
{SetOptions::sql, "SQL", 0},
|
||||
{SetOptions::warning, "WARNINGS", 7},
|
||||
{SetOptions::warning, "WNG", 0},
|
||||
{SetOptions::generator, "GENERATOR", 0},
|
||||
{SetOptions::statistics, "STATISTICS", 0},
|
||||
{SetOptions::sqlCont, "GENERATOR", 0},
|
||||
{SetOptions::sqlCont, "STATISTICS", 0},
|
||||
{SetOptions::heading, "HEADING", 0},
|
||||
{SetOptions::bail, "BAIL", 0},
|
||||
{SetOptions::bulk_insert, "BULK_INSERT", 0},
|
||||
{SetOptions::maxrows, "ROWCOUNT", 0}, // legacy, compatible with FB2.5
|
||||
{SetOptions::maxrows, "MAXROWS", 0},
|
||||
{SetOptions::sqlCont, "ROLE", 0},
|
||||
{SetOptions::sqlCont, "TRUSTED", 0}, // TRUSTED ROLE, will get DSQL error other case
|
||||
};
|
||||
|
||||
// Display current set options
|
||||
@ -4965,6 +4967,10 @@ static processing_state frontend_set(const char* cmd, const char* const* parms,
|
||||
const SetOptions setoptions(options, FB_NELEM(options), SetOptions::wrong);
|
||||
switch (setoptions.getCommand(parms[1]))
|
||||
{
|
||||
case SetOptions::sqlCont:
|
||||
ret = CONT;
|
||||
break;
|
||||
|
||||
case SetOptions::stat:
|
||||
ret = do_set_command(parms[2], &Stats);
|
||||
break;
|
||||
@ -5082,11 +5088,6 @@ static processing_state frontend_set(const char* cmd, const char* const* parms,
|
||||
ret = do_set_command (parms[2], &Warnings);
|
||||
break;
|
||||
|
||||
case SetOptions::generator:
|
||||
case SetOptions::statistics:
|
||||
ret = CONT;
|
||||
break;
|
||||
|
||||
case SetOptions::heading:
|
||||
ret = do_set_command(parms[2], &Heading);
|
||||
break;
|
||||
|
@ -103,6 +103,8 @@ enum irq_type_t
|
||||
irq_c_trg_perm, // check if trig can ignore perm. checks
|
||||
irq_get_role_mem, // get SQL role membership
|
||||
irq_get_role_name, // get SQL role 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
|
||||
irq_r_gen_id_num, // lookup generator by ID.
|
||||
irq_upd_gen_id_step, // update the STEP of a generator (only for legacy code).
|
||||
|
164
src/jrd/jrd.cpp
164
src/jrd/jrd.cpp
@ -1223,6 +1223,87 @@ jrd_tra* JAttachment::getEngineTransaction(IStatus* status, ITransaction* tra)
|
||||
return getTransactionInterface(status, tra)->getHandle();
|
||||
}
|
||||
|
||||
static void makeRoleName(Database* dbb, string& userIdRole, DatabaseOptions& options)
|
||||
{
|
||||
if (userIdRole.hasData())
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
CharSet* utf8CharSet = IntlUtil::getUtf8CharSet();
|
||||
|
||||
switch (options.dpb_sql_dialect)
|
||||
{
|
||||
case SQL_DIALECT_V5:
|
||||
{
|
||||
strip_quotes(userIdRole);
|
||||
IntlUtil::toUpper(utf8CharSet, userIdRole);
|
||||
}
|
||||
break;
|
||||
|
||||
case SQL_DIALECT_V6_TRANSITION:
|
||||
case SQL_DIALECT_V6:
|
||||
{
|
||||
if (userIdRole.hasData() && (userIdRole[0] == DBL_QUOTE || userIdRole[0] == SINGLE_QUOTE))
|
||||
{
|
||||
const char end_quote = userIdRole[0];
|
||||
// remove the delimited quotes and escape quote
|
||||
// from ROLE name
|
||||
userIdRole.erase(0, 1);
|
||||
for (string::iterator p = userIdRole.begin(); p < userIdRole.end(); ++p)
|
||||
{
|
||||
if (*p == end_quote)
|
||||
{
|
||||
if (++p < userIdRole.end() && *p == end_quote)
|
||||
{
|
||||
// skip the escape quote here
|
||||
userIdRole.erase(p--);
|
||||
}
|
||||
else
|
||||
{
|
||||
// delimited done
|
||||
userIdRole.erase(--p, userIdRole.end());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
IntlUtil::toUpper(utf8CharSet, userIdRole);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
JAttachment* FB_CARG JProvider::attachDatabase(IStatus* user_status, const char* filename,
|
||||
unsigned int dpb_length, const unsigned char* dpb)
|
||||
{
|
||||
@ -1505,82 +1586,8 @@ JAttachment* FB_CARG JProvider::attachDatabase(IStatus* user_status, const char*
|
||||
Arg::Gds(isc_valid_client_dialects) << Arg::Str("1, 2 or 3"));
|
||||
}
|
||||
|
||||
if (userId.usr_sql_role_name.hasData())
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
CharSet* utf8CharSet = IntlUtil::getUtf8CharSet();
|
||||
|
||||
switch (options.dpb_sql_dialect)
|
||||
{
|
||||
case SQL_DIALECT_V5:
|
||||
{
|
||||
strip_quotes(userId.usr_sql_role_name);
|
||||
IntlUtil::toUpper(utf8CharSet, userId.usr_sql_role_name);
|
||||
}
|
||||
break;
|
||||
|
||||
case SQL_DIALECT_V6_TRANSITION:
|
||||
case SQL_DIALECT_V6:
|
||||
{
|
||||
string& role = userId.usr_sql_role_name;
|
||||
if (role.hasData() && (role[0] == DBL_QUOTE || role[0] == SINGLE_QUOTE))
|
||||
{
|
||||
const char end_quote = role[0];
|
||||
// remove the delimited quotes and escape quote
|
||||
// from ROLE name
|
||||
role.erase(0, 1);
|
||||
for (string::iterator p = role.begin(); p < role.end(); ++p)
|
||||
{
|
||||
if (*p == end_quote)
|
||||
{
|
||||
if (++p < role.end() && *p == end_quote)
|
||||
{
|
||||
// skip the escape quote here
|
||||
role.erase(p--);
|
||||
}
|
||||
else
|
||||
{
|
||||
// delimited done
|
||||
role.erase(--p, role.end());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
IntlUtil::toUpper(utf8CharSet, role);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
makeRoleName(dbb, userId.usr_sql_role_name, options);
|
||||
makeRoleName(dbb, userId.usr_trusted_role, options);
|
||||
|
||||
options.dpb_sql_dialect = 0;
|
||||
|
||||
@ -7126,10 +7133,9 @@ static void getUserInfo(UserId& user, const DatabaseOptions& options,
|
||||
{
|
||||
user.usr_sql_role_name = options.dpb_role_name;
|
||||
}
|
||||
else if (trusted_role.hasData())
|
||||
if (trusted_role.hasData())
|
||||
{
|
||||
user.usr_sql_role_name = trusted_role;
|
||||
user.usr_flags |= USR_trole;
|
||||
user.usr_trusted_role = trusted_role;
|
||||
}
|
||||
}
|
||||
|
||||
|
168
src/jrd/scl.epp
168
src/jrd/scl.epp
@ -804,6 +804,91 @@ SecurityClass::flags_t SCL_get_mask(thread_db* tdbb, const TEXT* relation_name,
|
||||
}
|
||||
|
||||
|
||||
bool SCL_role_granted(thread_db* tdbb, const UserId& usr, const TEXT* sql_role)
|
||||
{
|
||||
/**************************************
|
||||
*
|
||||
* S C L _ r o l e _ g r a n t e d
|
||||
*
|
||||
**************************************
|
||||
*
|
||||
* Functional description
|
||||
* Check is sql_role granted to the user.
|
||||
*
|
||||
**************************************/
|
||||
SET_TDBB(tdbb);
|
||||
Jrd::Attachment* const attachment = tdbb->getAttachment();
|
||||
|
||||
if (!strcmp(sql_role, NULL_ROLE))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
Firebird::string loginName(usr.usr_user_name);
|
||||
loginName.upper();
|
||||
const TEXT* login_name = loginName.c_str();
|
||||
|
||||
bool found = false;
|
||||
|
||||
AutoCacheRequest request(tdbb, irq_verify_role_name, IRQ_REQUESTS);
|
||||
|
||||
// CVC: The caller has hopefully uppercased the role or stripped quotes. Of course,
|
||||
// uppercase-UPPER7 should only happen if the role wasn't enclosed in quotes.
|
||||
// Shortsighted developers named the field rdb$relation_name instead of rdb$object_name.
|
||||
// This request is not exactly the same than irq_get_role_mem, sorry, I can't reuse that.
|
||||
// If you think that an unknown role cannot be granted, think again: someone made sure
|
||||
// in DYN that SYSDBA can do almost anything, including invalid grants.
|
||||
|
||||
FOR (REQUEST_HANDLE request) FIRST 1 RR IN RDB$ROLES
|
||||
CROSS UU IN RDB$USER_PRIVILEGES
|
||||
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
|
||||
OR UU.RDB$USER EQ "PUBLIC")
|
||||
AND UU.RDB$USER_TYPE EQ obj_user
|
||||
AND UU.RDB$PRIVILEGE EQ "M"
|
||||
{
|
||||
if (!UU.RDB$USER.NULL)
|
||||
found = true;
|
||||
}
|
||||
END_FOR
|
||||
|
||||
return found;
|
||||
}
|
||||
|
||||
|
||||
bool SCL_admin_role(thread_db* tdbb, const TEXT* sql_role)
|
||||
{
|
||||
/**************************************
|
||||
*
|
||||
* S C L _ a d m i n _ r o l e
|
||||
*
|
||||
**************************************
|
||||
*
|
||||
* Functional description
|
||||
* Check is sql_role is an admin role.
|
||||
*
|
||||
**************************************/
|
||||
SET_TDBB(tdbb);
|
||||
Jrd::Attachment* const attachment = tdbb->getAttachment();
|
||||
|
||||
bool adminRole = false;
|
||||
|
||||
AutoCacheRequest request(tdbb, irq_is_admin_role, IRQ_REQUESTS);
|
||||
|
||||
FOR(REQUEST_HANDLE request) R IN RDB$ROLES
|
||||
WITH R.RDB$ROLE_NAME EQ sql_role
|
||||
{
|
||||
if (R.RDB$SYSTEM_FLAG & ROLE_FLAG_DBO)
|
||||
adminRole = true;
|
||||
}
|
||||
END_FOR
|
||||
|
||||
return adminRole;
|
||||
}
|
||||
|
||||
|
||||
void SCL_init(thread_db* tdbb, bool create, const UserId& tempId)
|
||||
{
|
||||
/**************************************
|
||||
@ -815,10 +900,8 @@ void SCL_init(thread_db* tdbb, bool create, const UserId& tempId)
|
||||
* Functional description
|
||||
* Check database access control list.
|
||||
*
|
||||
* Checks the userinfo database to get the
|
||||
* password and other stuff about the specified
|
||||
* user. Compares the password to that passed
|
||||
* in, encrypting if necessary.
|
||||
* Finally fills UserId information
|
||||
* (role, flags, etc.).
|
||||
*
|
||||
**************************************/
|
||||
SET_TDBB(tdbb);
|
||||
@ -826,17 +909,17 @@ void SCL_init(thread_db* tdbb, bool create, const UserId& tempId)
|
||||
Jrd::Attachment* const attachment = tdbb->getAttachment();
|
||||
|
||||
const TEXT* sql_role = tempId.usr_sql_role_name.nullStr();
|
||||
Firebird::string loginName(tempId.usr_user_name);
|
||||
loginName.upper();
|
||||
const TEXT* login_name = loginName.c_str();
|
||||
Firebird::MetaName role_name;
|
||||
|
||||
// CVC: We'll verify the role and wipe it out when it doesn't exist
|
||||
|
||||
if (strlen(login_name) != 0)
|
||||
if (tempId.usr_user_name.hasData())
|
||||
{
|
||||
if (!create)
|
||||
{
|
||||
Firebird::string loginName(tempId.usr_user_name);
|
||||
loginName.upper();
|
||||
const TEXT* login_name = loginName.c_str();
|
||||
|
||||
AutoCacheRequest request(tdbb, irq_get_role_name, IRQ_REQUESTS);
|
||||
|
||||
FOR(REQUEST_HANDLE request) X IN RDB$ROLES
|
||||
@ -851,50 +934,16 @@ void SCL_init(thread_db* tdbb, bool create, const UserId& tempId)
|
||||
// CVC: If we aren't creating a db and sql_role was specified,
|
||||
// then verify it against rdb$roles and rdb$user_privileges
|
||||
|
||||
if (!create && sql_role && *sql_role && strcmp(sql_role, NULL_ROLE))
|
||||
if (!create && sql_role && *sql_role)
|
||||
{
|
||||
bool found = false;
|
||||
|
||||
AutoCacheRequest request(tdbb, irq_verify_role_name, IRQ_REQUESTS);
|
||||
|
||||
// CVC: The caller has hopefully uppercased the role or stripped quotes. Of course,
|
||||
// uppercase-UPPER7 should only happen if the role wasn't enclosed in quotes.
|
||||
// Shortsighted developers named the field rdb$relation_name instead of rdb$object_name.
|
||||
// This request is not exactly the same than irq_get_role_mem, sorry, I can't reuse that.
|
||||
// If you think that an unknown role cannot be granted, think again: someone made sure
|
||||
// in DYN that SYSDBA can do almost anything, including invalid grants.
|
||||
|
||||
if (!(tempId.usr_flags & USR_trole))
|
||||
{
|
||||
FOR (REQUEST_HANDLE request) FIRST 1 RR IN RDB$ROLES
|
||||
CROSS UU IN RDB$USER_PRIVILEGES
|
||||
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
|
||||
OR UU.RDB$USER EQ "PUBLIC")
|
||||
AND UU.RDB$USER_TYPE EQ obj_user
|
||||
AND UU.RDB$PRIVILEGE EQ "M"
|
||||
{
|
||||
if (!UU.RDB$USER.NULL)
|
||||
found = true;
|
||||
}
|
||||
END_FOR
|
||||
}
|
||||
else
|
||||
found = true;
|
||||
|
||||
if (!found)
|
||||
role_name = NULL_ROLE;
|
||||
if (!SCL_role_granted(tdbb, tempId, sql_role))
|
||||
sql_role = NULL;
|
||||
}
|
||||
|
||||
if (sql_role)
|
||||
{
|
||||
if (role_name != NULL_ROLE)
|
||||
role_name = sql_role;
|
||||
}
|
||||
else
|
||||
role_name = NULL_ROLE;
|
||||
if (!sql_role)
|
||||
sql_role = tempId.usr_trusted_role.nullStr();
|
||||
|
||||
MetaName role_name(sql_role ? sql_role : NULL_ROLE);
|
||||
|
||||
MemoryPool& pool = *attachment->att_pool;
|
||||
UserId* const user = FB_NEW(pool) UserId(pool, tempId);
|
||||
@ -903,9 +952,9 @@ void SCL_init(thread_db* tdbb, bool create, const UserId& tempId)
|
||||
|
||||
if (!create)
|
||||
{
|
||||
AutoRequest handle, handle1, handle2;
|
||||
AutoCacheRequest request(tdbb, irq_get_att_class, IRQ_REQUESTS);
|
||||
|
||||
FOR(REQUEST_HANDLE handle) X IN RDB$DATABASE
|
||||
FOR(REQUEST_HANDLE request) X IN RDB$DATABASE
|
||||
{
|
||||
if (!X.RDB$SECURITY_CLASS.NULL)
|
||||
attachment->att_security_class = SCL_get_class(tdbb, X.RDB$SECURITY_CLASS);
|
||||
@ -914,7 +963,9 @@ void SCL_init(thread_db* tdbb, bool create, const UserId& tempId)
|
||||
|
||||
if (dbb->dbb_owner.isEmpty())
|
||||
{
|
||||
FOR(REQUEST_HANDLE handle1)
|
||||
AutoRequest request;
|
||||
|
||||
FOR(REQUEST_HANDLE request)
|
||||
FIRST 1 REL IN RDB$RELATIONS
|
||||
WITH REL.RDB$RELATION_NAME EQ "RDB$DATABASE"
|
||||
{
|
||||
@ -927,13 +978,8 @@ void SCL_init(thread_db* tdbb, bool create, const UserId& tempId)
|
||||
if (dbb->dbb_owner == user->usr_user_name)
|
||||
user->usr_flags |= USR_owner;
|
||||
|
||||
FOR(REQUEST_HANDLE handle2) R IN RDB$ROLES
|
||||
WITH R.RDB$ROLE_NAME EQ role_name.c_str()
|
||||
{
|
||||
if (R.RDB$SYSTEM_FLAG & ROLE_FLAG_DBO)
|
||||
user->usr_flags |= USR_dba;
|
||||
}
|
||||
END_FOR
|
||||
if (sql_role && SCL_admin_role(tdbb, role_name.c_str()))
|
||||
user->usr_flags |= USR_dba;
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -1294,6 +1340,8 @@ static SecurityClass::flags_t walk_acl(thread_db* tdbb,
|
||||
case id_sql_role:
|
||||
if (!role_name || check_string(a, role_name))
|
||||
hit = false;
|
||||
else if (user.usr_sql_role_name == user.usr_trusted_role)
|
||||
hit = true;
|
||||
else
|
||||
{
|
||||
TEXT login_name[129];
|
||||
|
@ -84,14 +84,13 @@ const SecurityClass::flags_t SCL_usage = 2048; // USAGE access
|
||||
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_trole = 8; // Role was set by trusted auth
|
||||
|
||||
|
||||
class UserId
|
||||
{
|
||||
public:
|
||||
Firebird::string usr_user_name; // User name
|
||||
Firebird::string usr_sql_role_name; // Role name
|
||||
Firebird::string usr_trusted_role; // Trusted role if set
|
||||
Firebird::string usr_project_name; // Project name
|
||||
Firebird::string usr_org_name; // Organization name
|
||||
Firebird::string usr_auth_method; // Authentication method
|
||||
@ -112,6 +111,7 @@ public:
|
||||
UserId(Firebird::MemoryPool& p, const UserId& ui)
|
||||
: usr_user_name(p, ui.usr_user_name),
|
||||
usr_sql_role_name(p, ui.usr_sql_role_name),
|
||||
usr_trusted_role(p, ui.usr_trusted_role),
|
||||
usr_project_name(p, ui.usr_project_name),
|
||||
usr_org_name(p, ui.usr_org_name),
|
||||
usr_auth_method(p, ui.usr_auth_method),
|
||||
@ -126,6 +126,7 @@ public:
|
||||
UserId(const UserId& ui)
|
||||
: usr_user_name(ui.usr_user_name),
|
||||
usr_sql_role_name(ui.usr_sql_role_name),
|
||||
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),
|
||||
@ -140,6 +141,7 @@ public:
|
||||
{
|
||||
usr_user_name = ui.usr_user_name;
|
||||
usr_sql_role_name = ui.usr_sql_role_name;
|
||||
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;
|
||||
|
@ -51,6 +51,8 @@ Jrd::SecurityClass::flags_t SCL_get_mask(Jrd::thread_db* tdbb, const TEXT*, cons
|
||||
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);
|
||||
bool SCL_admin_role(Jrd::thread_db* tdbb, const TEXT* sql_role);
|
||||
|
||||
namespace Jrd {
|
||||
typedef Firebird::Array<UCHAR> Acl;
|
||||
|
@ -1,7 +1,7 @@
|
||||
/* MAX_NUMBER is the next number to be used, always one more than the highest message number. */
|
||||
set bulk_insert INSERT INTO FACILITIES (LAST_CHANGE, FACILITY, FAC_CODE, MAX_NUMBER) VALUES (?, ?, ?, ?);
|
||||
--
|
||||
('2014-04-18 19:01:37', 'JRD', 0, 770)
|
||||
('2014-04-30 18:55:42', 'JRD', 0, 772)
|
||||
('2012-01-23 20:10:30', 'QLI', 1, 532)
|
||||
('2013-11-13 15:59:10', 'GFIX', 3, 122)
|
||||
('1996-11-07 13:39:40', 'GPRE', 4, 1)
|
||||
|
@ -877,6 +877,8 @@ Data source : @4', NULL, NULL)
|
||||
('baddpb_temp_buffers', 'DatabaseOptions::get', 'jrd.cpp', NULL, 0, 767, NULL, 'Attempt to temporarily set number of buffers less than @1', NULL, NULL);
|
||||
('map_nodb', 'MappingList::getList', 'Mapping.cpp', NULL, 0, 768, NULL, 'Global mapping is not available when database @1 is not present', NULL, NULL);
|
||||
('map_notable', 'MappingList::getList', 'Mapping.cpp', NULL, 0, 769, NULL, 'Global mapping is not available when table RDB$MAP is not present in database @1', NULL, NULL);
|
||||
('miss_trusted_role', 'SetRoleNode::execute', 'StmtNodes.cpp', NULL, 0, 770, NULL, 'Your attachment has no trusted role', NULL, NULL);
|
||||
('set_invalid_role', 'SetRoleNode::execute', 'StmtNodes.cpp', NULL, 0, 771, NULL, 'Role @1 is invalid or unavailable', 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);
|
||||
|
@ -776,6 +776,8 @@ set bulk_insert INSERT INTO SYSTEM_ERRORS (SQL_CODE, SQL_CLASS, SQL_SUBCLASS, FA
|
||||
(-924, 'HY', '000', 0, 767, 'baddpb_temp_buffers', NULL, NULL);
|
||||
(-901, '0A', '000', 0, 768, 'map_nodb', NULL, NULL);
|
||||
(-901, '0A', '000', 0, 769, 'map_notable', NULL, NULL);
|
||||
(-901, '0P', '000', 0, 770, 'miss_trusted_role', NULL, NULL);
|
||||
(-901, '0P', '000', 0, 771, 'set_invalid_role', NULL, NULL);
|
||||
-- GFIX
|
||||
(-901, '00', '000', 3, 1, 'gfix_db_name', NULL, NULL)
|
||||
(-901, '00', '000', 3, 2, 'gfix_invalid_sw', NULL, NULL)
|
||||
|
@ -407,6 +407,7 @@ static const TOK tokens[] =
|
||||
{TRIM, "TRIM", 2, false},
|
||||
{KW_TRUE, "TRUE", 2, false},
|
||||
{TRUNC, "TRUNC", 2, false},
|
||||
{TRUSTED, "TRUSTED", 2, false},
|
||||
{TWO_PHASE, "TWO_PHASE", 2, true},
|
||||
{KW_TYPE, "TYPE", 2, true},
|
||||
{UNCOMMITTED, "UNCOMMITTED", 1, false},
|
||||
|
Loading…
Reference in New Issue
Block a user