mirror of
https://github.com/FirebirdSQL/firebird.git
synced 2025-01-22 20:43:02 +01:00
Implemented CORE-4538: Access rights for CREATE DATABASE operator
This commit is contained in:
parent
45a5d66a32
commit
2a293c2691
@ -17,7 +17,7 @@ REVOKE [GRANT OPTION FOR] DROP ANY <OBJECT> FROM [USER | ROLE] <user/role name>;
|
||||
|
||||
Where <OBJECT> could be:
|
||||
TABLE, VIEW, PROCEDURE, FUNCTION, PACKAGE, GENERATOR, SEQUENCE, DOMAIN,
|
||||
EXCEPTION, ROLE, DATABASE, CHARACTER SET, COLLATION, FILTER
|
||||
EXCEPTION, ROLE, CHARACTER SET, COLLATION, FILTER
|
||||
|
||||
Description:
|
||||
|
||||
@ -33,3 +33,13 @@ Sample:
|
||||
GRANT CREATE TABLE TO Joe;
|
||||
GRANT ALTER ANY TABLE TO Joe;
|
||||
REVOKE CREATE TABLE FROM Joe;
|
||||
|
||||
For database access special form is supported:
|
||||
|
||||
GRANT CREATE DATABASE TO [USER | ROLE] <user/role name>;
|
||||
GRANT ALTER DATABASE TO [USER | ROLE] <user/role name> [WITH GRANT OPTION];
|
||||
GRANT DROP DATABASE TO [USER | ROLE] <user/role name> [WITH GRANT OPTION];
|
||||
|
||||
REVOKE CREATE DATABASE FROM [USER | ROLE] <user/role name>;
|
||||
REVOKE [GRANT OPTION FOR] ALTER DATABASE FROM [USER | ROLE] <user/role name>;
|
||||
REVOKE [GRANT OPTION FOR] DROP DATABASE FROM [USER | ROLE] <user/role name>;
|
||||
|
@ -1604,6 +1604,12 @@ C --
|
||||
PARAMETER (GDS__dsql_cant_grant_option = 335545095)
|
||||
INTEGER*4 GDS__read_conflict
|
||||
PARAMETER (GDS__read_conflict = 335545096)
|
||||
INTEGER*4 GDS__crdb_load
|
||||
PARAMETER (GDS__crdb_load = 335545097)
|
||||
INTEGER*4 GDS__crdb_nodb
|
||||
PARAMETER (GDS__crdb_nodb = 335545098)
|
||||
INTEGER*4 GDS__crdb_notable
|
||||
PARAMETER (GDS__crdb_notable = 335545099)
|
||||
INTEGER*4 GDS__gfix_db_name
|
||||
PARAMETER (GDS__gfix_db_name = 335740929)
|
||||
INTEGER*4 GDS__gfix_invalid_sw
|
||||
|
@ -809,6 +809,9 @@ const
|
||||
gds_dyn_no_priv = 335545094;
|
||||
gds_dsql_cant_grant_option = 335545095;
|
||||
gds_read_conflict = 335545096;
|
||||
gds_crdb_load = 335545097;
|
||||
gds_crdb_nodb = 335545098;
|
||||
gds_crdb_notable = 335545099;
|
||||
gds_gfix_db_name = 335740929;
|
||||
gds_gfix_invalid_sw = 335740930;
|
||||
gds_gfix_incmp_sw = 335740932;
|
||||
|
@ -113,6 +113,60 @@ static const char* const CHECK_CONSTRAINT_EXCEPTION = "check_constraint";
|
||||
DATABASE DB = STATIC "ODS.RDB";
|
||||
|
||||
|
||||
//----------------------
|
||||
|
||||
void ExecInSecurityDb::executeInSecurityDb(jrd_tra* localTransaction)
|
||||
{
|
||||
LocalStatus st;
|
||||
|
||||
SecDbContext* secDbContext = localTransaction->getSecDbContext();
|
||||
if (!secDbContext)
|
||||
{
|
||||
Attachment* lAtt = localTransaction->getAttachment();
|
||||
const char* secDb = lAtt->att_database->dbb_config->getSecurityDatabase();
|
||||
ClumpletWriter dpb(ClumpletWriter::WideTagged, MAX_DPB_SIZE, isc_dpb_version2);
|
||||
if (lAtt->att_user)
|
||||
lAtt->att_user->populateDpb(dpb);
|
||||
IAttachment* att = DispatcherPtr()->attachDatabase(&st, secDb,
|
||||
dpb.getBufferLength(), dpb.getBuffer());
|
||||
check(&st);
|
||||
|
||||
ITransaction* tra = att->startTransaction(&st, 0, NULL);
|
||||
check(&st);
|
||||
|
||||
secDbContext = localTransaction->setSecDbContext(att, tra);
|
||||
}
|
||||
|
||||
// run all statements under savepoint control
|
||||
string savePoint;
|
||||
savePoint.printf("ExecInSecurityDb%d", secDbContext->savePoint++);
|
||||
secDbContext->att->execute(&st, secDbContext->tra, 0, ("SAVEPOINT " + savePoint).c_str(),
|
||||
SQL_DIALECT_V6, NULL, NULL, NULL, NULL);
|
||||
check(&st);
|
||||
|
||||
try
|
||||
{
|
||||
runInSecurityDb(secDbContext);
|
||||
|
||||
secDbContext->att->execute(&st, secDbContext->tra, 0, ("RELEASE SAVEPOINT " + savePoint).c_str(),
|
||||
SQL_DIALECT_V6, NULL, NULL, NULL, NULL);
|
||||
savePoint.erase();
|
||||
check(&st);
|
||||
}
|
||||
catch (const Exception&)
|
||||
{
|
||||
if (savePoint.hasData())
|
||||
{
|
||||
LocalStatus tmp;
|
||||
secDbContext->att->execute(&tmp, secDbContext->tra, 0, ("ROLLBACK TO SAVEPOINT " + savePoint).c_str(),
|
||||
SQL_DIALECT_V6, NULL, NULL, NULL, NULL);
|
||||
}
|
||||
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//----------------------
|
||||
|
||||
|
||||
@ -9662,44 +9716,11 @@ bool MappingNode::checkPermission(thread_db* tdbb, jrd_tra* transaction)
|
||||
return false;
|
||||
}
|
||||
|
||||
// It's purpose is to add/drop mapping from any security name to DB security object.
|
||||
void MappingNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, jrd_tra* transaction)
|
||||
void MappingNode::runInSecurityDb(SecDbContext* secDbContext)
|
||||
{
|
||||
if (!(tdbb->getAttachment() && tdbb->getAttachment()->locksmith()))
|
||||
status_exception::raise(Arg::Gds(isc_adm_task_denied));
|
||||
|
||||
if (global)
|
||||
{
|
||||
LocalStatus st;
|
||||
LocalStatus s2; // we will use it in DDL case and remember
|
||||
Firebird::LocalStatus st;
|
||||
IStatus* s = &st;
|
||||
|
||||
SecDbContext* secDbContext = transaction->getSecDbContext();
|
||||
if (!secDbContext)
|
||||
{
|
||||
const char* secDb = tdbb->getDatabase()->dbb_config->getSecurityDatabase();
|
||||
ClumpletWriter dpb(ClumpletWriter::WideTagged, MAX_DPB_SIZE, isc_dpb_version2);
|
||||
if (tdbb->getAttachment()->att_user)
|
||||
tdbb->getAttachment()->att_user->populateDpb(dpb);
|
||||
IAttachment* att = DispatcherPtr()->attachDatabase(s, secDb,
|
||||
dpb.getBufferLength(), dpb.getBuffer());
|
||||
check(s);
|
||||
|
||||
ITransaction* tra = att->startTransaction(s, 0, NULL);
|
||||
check(s);
|
||||
|
||||
secDbContext = transaction->setSecDbContext(att, tra);
|
||||
}
|
||||
|
||||
// run all statements under savepoint control
|
||||
string savePoint;
|
||||
savePoint.printf("GLOBALMAP%d", secDbContext->savePoint++);
|
||||
secDbContext->att->execute(s, secDbContext->tra, 0, ("SAVEPOINT " + savePoint).c_str(),
|
||||
SQL_DIALECT_V6, NULL, NULL, NULL, NULL);
|
||||
check(s);
|
||||
|
||||
try
|
||||
{
|
||||
// first of all try to use regenerated DDL statement
|
||||
// that's the best way if security database is FB3 or higher fb version
|
||||
string ddl;
|
||||
@ -9778,12 +9799,16 @@ void MappingNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, jrd
|
||||
}
|
||||
|
||||
// Now try to run DDL
|
||||
secDbContext->att->execute(&s2, secDbContext->tra, 0, ddl.c_str(), SQL_DIALECT_V6,
|
||||
secDbContext->att->execute(s, secDbContext->tra, 0, ddl.c_str(), SQL_DIALECT_V6,
|
||||
NULL, NULL, NULL, NULL);
|
||||
|
||||
if (s2.getStatus() & IStatus::FB_HAS_ERRORS)
|
||||
if (s->getStatus() & IStatus::FB_HAS_ERRORS)
|
||||
{
|
||||
try
|
||||
{
|
||||
// try direct access to rdb$auth_mapping table in secure db
|
||||
LocalStatus s2;
|
||||
s = &s2;
|
||||
|
||||
// check presence of such record in the table
|
||||
Message msgCheck;
|
||||
@ -9874,31 +9899,30 @@ void MappingNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, jrd
|
||||
secDbContext->att->execute(s, secDbContext->tra, 0, sql, SQL_DIALECT_V6,
|
||||
msg->getMetadata(), msg->getBuffer(), NULL, NULL);
|
||||
check(s);
|
||||
|
||||
secDbContext->att->execute(s, secDbContext->tra, 0, ("RELEASE SAVEPOINT " + savePoint).c_str(),
|
||||
SQL_DIALECT_V6, NULL, NULL, NULL, NULL);
|
||||
savePoint.erase();
|
||||
check(s);
|
||||
}
|
||||
}
|
||||
catch (const Exception&)
|
||||
catch(const Exception& ex)
|
||||
{
|
||||
if (savePoint.hasData())
|
||||
if (st.getStatus() & IStatus::FB_HAS_ERRORS)
|
||||
{
|
||||
secDbContext->att->execute(s, secDbContext->tra, 0, ("ROLLBACK TO SAVEPOINT " + savePoint).c_str(),
|
||||
SQL_DIALECT_V6, NULL, NULL, NULL, NULL);
|
||||
}
|
||||
|
||||
if (s2.getStatus() & IStatus::FB_HAS_ERRORS)
|
||||
{
|
||||
const ISC_STATUS* stat2 = s2.getErrors();
|
||||
const ISC_STATUS* stat2 = st.getErrors();
|
||||
if (stat2[1] != isc_dsql_token_unk_err)
|
||||
status_exception::raise(&s2);
|
||||
status_exception::raise(&st);
|
||||
}
|
||||
|
||||
throw;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 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 (global)
|
||||
{
|
||||
executeInSecurityDb(transaction);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -10319,6 +10343,8 @@ void GrantRevokeNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch,
|
||||
// run all statements under savepoint control
|
||||
AutoSavePoint savePoint(tdbb, transaction);
|
||||
|
||||
createDbJobs.clear();
|
||||
|
||||
const GranteeClause* usersPtr;
|
||||
const GranteeClause* usersEnd;
|
||||
|
||||
@ -10356,9 +10382,83 @@ void GrantRevokeNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch,
|
||||
}
|
||||
}
|
||||
|
||||
if (createDbJobs.hasData())
|
||||
executeInSecurityDb(transaction);
|
||||
|
||||
savePoint.release(); // everything is ok
|
||||
}
|
||||
|
||||
void GrantRevokeNode::runInSecurityDb(SecDbContext* secDbContext)
|
||||
{
|
||||
for (unsigned n = 0; n < createDbJobs.getCount(); ++n)
|
||||
{
|
||||
CreateDbJob& j = createDbJobs[n];
|
||||
LocalStatus st;
|
||||
IStatus* s = &st;
|
||||
|
||||
Message gr;
|
||||
Field<ISC_SHORT> uType(gr);
|
||||
Field<Varying> u(gr, MAX_SQL_IDENTIFIER_LEN);
|
||||
uType = j.userType;
|
||||
u = j.user.c_str();
|
||||
|
||||
Message result;
|
||||
Field<ISC_INT64> cnt(result);
|
||||
|
||||
const char* checkSql = "select count(*) from RDB$DB_CREATORS where RDB$USER_TYPE = ? and RDB$USER = ?";
|
||||
secDbContext->att->execute(s, secDbContext->tra, 0, checkSql, SQL_DIALECT_V6,
|
||||
gr.getMetadata(), gr.getBuffer(), result.getMetadata(), result.getBuffer());
|
||||
check(s);
|
||||
|
||||
if (isGrant)
|
||||
{
|
||||
if (!cnt)
|
||||
{
|
||||
const char* insertSql = "insert into RDB$DB_CREATORS(RDB$USER_TYPE, RDB$USER) values(?, ?)";
|
||||
secDbContext->att->execute(s, secDbContext->tra, 0, insertSql, SQL_DIALECT_V6,
|
||||
gr.getMetadata(), gr.getBuffer(), NULL, NULL);
|
||||
check(s);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (cnt)
|
||||
{
|
||||
const char* deleteSql = "delete from RDB$DB_CREATORS where RDB$USER_TYPE = ? and RDB$USER = ?";
|
||||
secDbContext->att->execute(s, secDbContext->tra, 0, deleteSql, SQL_DIALECT_V6,
|
||||
gr.getMetadata(), gr.getBuffer(), NULL, NULL);
|
||||
|
||||
j.grantErased = true;
|
||||
}
|
||||
|
||||
if (!j.grantErased)
|
||||
{
|
||||
if (j.allOnAll)
|
||||
{
|
||||
const char* all = "ALL";
|
||||
|
||||
if (j.badGrantor)
|
||||
{
|
||||
// msg 246: @1 is not grantor of @2 on @3 to @4.
|
||||
(Arg::PrivateDyn(246) << j.revoker.c_str() << all << all << j.user).raise();
|
||||
}
|
||||
|
||||
// msg 247: Warning: @1 on @2 is not granted to @3.
|
||||
ERR_post_warning(
|
||||
Arg::Warning(isc_dyn_miss_priv_warning) <<
|
||||
all << all << j.user);
|
||||
}
|
||||
else
|
||||
{
|
||||
// msg 247: Warning: @1 on @2 is not granted to @3.
|
||||
ERR_post_warning(Arg::Warning(isc_dyn_miss_priv_warning) <<
|
||||
privilegeName('C') << "DATABASE" << j.user);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GrantRevokeNode::modifyPrivileges(thread_db* tdbb, jrd_tra* transaction, SSHORT option,
|
||||
const GranteeClause* user)
|
||||
{
|
||||
@ -10467,8 +10567,9 @@ void GrantRevokeNode::grantRevoke(thread_db* tdbb, jrd_tra* transaction, const G
|
||||
if (!isGrant && !privs) // REVOKE ALL ON ALL
|
||||
{
|
||||
AutoCacheRequest request(tdbb, drq_e_grant3, DYN_REQUESTS);
|
||||
bool grantErased = false;
|
||||
bool badGrantor = false;
|
||||
CreateDbJob all(userType, user);
|
||||
all.allOnAll = true;
|
||||
all.revoker = grantorRevoker;
|
||||
|
||||
FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction)
|
||||
PRIV IN RDB$USER_PRIVILEGES
|
||||
@ -10478,29 +10579,14 @@ void GrantRevokeNode::grantRevoke(thread_db* tdbb, jrd_tra* transaction, const G
|
||||
if (tdbb->getAttachment()->att_user->locksmith() || grantorRevoker == PRIV.RDB$GRANTOR)
|
||||
{
|
||||
ERASE PRIV;
|
||||
grantErased = true;
|
||||
all.grantErased = true;
|
||||
}
|
||||
else
|
||||
badGrantor = true;
|
||||
all.badGrantor = true;
|
||||
}
|
||||
END_FOR
|
||||
|
||||
const char* all = "ALL";
|
||||
|
||||
if (badGrantor && !grantErased)
|
||||
{
|
||||
// msg 246: @1 is not grantor of @2 on @3 to @4.
|
||||
status_exception::raise(Arg::PrivateDyn(246) <<
|
||||
grantorRevoker.c_str() << all << all << user.c_str());
|
||||
}
|
||||
|
||||
if (!grantErased)
|
||||
{
|
||||
// msg 247: Warning: @1 on @2 is not granted to @3.
|
||||
ERR_post_warning(
|
||||
Arg::Warning(isc_dyn_miss_priv_warning) <<
|
||||
all << all << Arg::Str(user));
|
||||
}
|
||||
createDbJobs.push(all);
|
||||
|
||||
return;
|
||||
}
|
||||
@ -10527,6 +10613,30 @@ void GrantRevokeNode::grantRevoke(thread_db* tdbb, jrd_tra* transaction, const G
|
||||
}
|
||||
}
|
||||
|
||||
if (objType == obj_database && strchr(privileges, 'C'))
|
||||
{
|
||||
if (options || grantor)
|
||||
{
|
||||
(Arg::Gds(isc_wish_list) << Arg::Gds(isc_random) <<
|
||||
"GRANT/ADMIN OPTION and GRANTED BY not supported for CREATE DATABASE grants").raise();
|
||||
}
|
||||
|
||||
if (userType != obj_sql_role && userType != obj_user)
|
||||
{
|
||||
(Arg::Gds(isc_wish_list) << Arg::Gds(isc_random) <<
|
||||
"Only grants to USER or ROLE are supported for CREATE DATABASE").raise();
|
||||
}
|
||||
|
||||
CreateDbJob job(userType, user);
|
||||
createDbJobs.push(job);
|
||||
|
||||
char* cPtr = strchr(privileges, 'C');
|
||||
size_t len = strlen(cPtr);
|
||||
memmove(cPtr, cPtr + 1, len);
|
||||
if (!privileges[0])
|
||||
return;
|
||||
}
|
||||
|
||||
char priv[2];
|
||||
priv[1] = '\0';
|
||||
|
||||
|
@ -41,7 +41,7 @@ namespace Jrd {
|
||||
class CompoundStmtNode;
|
||||
class RelationSourceNode;
|
||||
class ValueListNode;
|
||||
|
||||
class SecDbContext;
|
||||
|
||||
struct BoolSourceClause
|
||||
{
|
||||
@ -135,6 +135,18 @@ public:
|
||||
};
|
||||
|
||||
|
||||
class ExecInSecurityDb
|
||||
{
|
||||
public:
|
||||
virtual ~ExecInSecurityDb() { }
|
||||
|
||||
void executeInSecurityDb(jrd_tra* tra);
|
||||
|
||||
protected:
|
||||
virtual void runInSecurityDb(SecDbContext* secDbContext) = 0;
|
||||
};
|
||||
|
||||
|
||||
template <typename CreateNode, typename DropNode, ISC_STATUS ERROR_CODE>
|
||||
class RecreateNode : public DdlNode
|
||||
{
|
||||
@ -1802,7 +1814,7 @@ public:
|
||||
};
|
||||
|
||||
|
||||
class MappingNode : public DdlNode
|
||||
class MappingNode : public DdlNode, private ExecInSecurityDb
|
||||
{
|
||||
public:
|
||||
enum OP {MAP_ADD, MAP_MOD, MAP_RPL, MAP_DROP};
|
||||
@ -1836,6 +1848,7 @@ protected:
|
||||
(op == MAP_ADD ? "CREATE" : op == MAP_MOD ?
|
||||
"ALTER" : op == MAP_RPL ? "CREATE OR ALTER" : "DROP");
|
||||
}
|
||||
void runInSecurityDb(SecDbContext* secDbContext);
|
||||
|
||||
private:
|
||||
void addItem(Firebird::string& ddl, const char* text);
|
||||
@ -1974,11 +1987,12 @@ public:
|
||||
typedef Firebird::Pair<Firebird::NonPooled<char, ValueListNode*> > PrivilegeClause;
|
||||
typedef Firebird::Pair<Firebird::NonPooled<SSHORT, Firebird::MetaName> > GranteeClause;
|
||||
|
||||
class GrantRevokeNode : public DdlNode
|
||||
class GrantRevokeNode : public DdlNode, private ExecInSecurityDb
|
||||
{
|
||||
public:
|
||||
GrantRevokeNode(MemoryPool& p, bool aIsGrant)
|
||||
: DdlNode(p),
|
||||
createDbJobs(p),
|
||||
isGrant(aIsGrant),
|
||||
privileges(p),
|
||||
roles(p),
|
||||
@ -2001,6 +2015,7 @@ protected:
|
||||
statusVector <<
|
||||
Firebird::Arg::Gds(isGrant ? isc_dsql_grant_failed : isc_dsql_revoke_failed);
|
||||
}
|
||||
void runInSecurityDb(SecDbContext* secDbContext);
|
||||
|
||||
private:
|
||||
void modifyPrivileges(thread_db* tdbb, jrd_tra* transaction, SSHORT option, const GranteeClause* user);
|
||||
@ -2043,6 +2058,19 @@ private:
|
||||
return "<Unknown>";
|
||||
}
|
||||
|
||||
struct CreateDbJob
|
||||
{
|
||||
CreateDbJob(SSHORT a_userType, const Firebird::MetaName& a_user)
|
||||
: allOnAll(false), grantErased(false), badGrantor(false),
|
||||
userType(a_userType), user(a_user)
|
||||
{ }
|
||||
|
||||
bool allOnAll, grantErased, badGrantor;
|
||||
SSHORT userType;
|
||||
Firebird::MetaName user, revoker;
|
||||
};
|
||||
Firebird::Array<CreateDbJob> createDbJobs;
|
||||
|
||||
public:
|
||||
bool isGrant;
|
||||
Firebird::Array<PrivilegeClause> privileges;
|
||||
|
@ -976,6 +976,7 @@ db_ddl_privilege_list($privilegeArray)
|
||||
|
||||
%type db_ddl_privilege(<privilegeArray>)
|
||||
db_ddl_privilege($privilegeArray)
|
||||
| CREATE { $privilegeArray->add(PrivilegeClause('C', NULL)); }
|
||||
| ALTER { $privilegeArray->add(PrivilegeClause('L', NULL)); }
|
||||
| DROP { $privilegeArray->add(PrivilegeClause('O', NULL)); }
|
||||
;
|
||||
|
@ -798,6 +798,9 @@ static const struct {
|
||||
{"dyn_no_priv", 335545094},
|
||||
{"dsql_cant_grant_option", 335545095},
|
||||
{"read_conflict", 335545096},
|
||||
{"crdb_load", 335545097},
|
||||
{"crdb_nodb", 335545098},
|
||||
{"crdb_notable", 335545099},
|
||||
{"gfix_db_name", 335740929},
|
||||
{"gfix_invalid_sw", 335740930},
|
||||
{"gfix_incmp_sw", 335740932},
|
||||
|
@ -832,6 +832,9 @@ const ISC_STATUS isc_dup_attribute = 335545093L;
|
||||
const ISC_STATUS isc_dyn_no_priv = 335545094L;
|
||||
const ISC_STATUS isc_dsql_cant_grant_option = 335545095L;
|
||||
const ISC_STATUS isc_read_conflict = 335545096L;
|
||||
const ISC_STATUS isc_crdb_load = 335545097L;
|
||||
const ISC_STATUS isc_crdb_nodb = 335545098L;
|
||||
const ISC_STATUS isc_crdb_notable = 335545099L;
|
||||
const ISC_STATUS isc_gfix_db_name = 335740929L;
|
||||
const ISC_STATUS isc_gfix_invalid_sw = 335740930L;
|
||||
const ISC_STATUS isc_gfix_incmp_sw = 335740932L;
|
||||
@ -1290,7 +1293,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 = 1234;
|
||||
const ISC_STATUS isc_err_max = 1237;
|
||||
|
||||
#else /* c definitions */
|
||||
|
||||
@ -2092,6 +2095,9 @@ const ISC_STATUS isc_err_max = 1234;
|
||||
#define isc_dyn_no_priv 335545094L
|
||||
#define isc_dsql_cant_grant_option 335545095L
|
||||
#define isc_read_conflict 335545096L
|
||||
#define isc_crdb_load 335545097L
|
||||
#define isc_crdb_nodb 335545098L
|
||||
#define isc_crdb_notable 335545099L
|
||||
#define isc_gfix_db_name 335740929L
|
||||
#define isc_gfix_invalid_sw 335740930L
|
||||
#define isc_gfix_incmp_sw 335740932L
|
||||
@ -2550,7 +2556,7 @@ const ISC_STATUS isc_err_max = 1234;
|
||||
#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 1234
|
||||
#define isc_err_max 1237
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -660,3 +660,15 @@
|
||||
const USHORT f_sec_map_to = 7;
|
||||
|
||||
|
||||
// Relation 47 (RDB$DB_CREATORS)
|
||||
|
||||
const USHORT f_crt_user = 0;
|
||||
const USHORT f_crt_u_type = 1;
|
||||
|
||||
|
||||
// Relation 48 (SEC$DB_CREATORS)
|
||||
|
||||
const USHORT f_sec_crt_user = 0;
|
||||
const USHORT f_sec_crt_u_type = 1;
|
||||
|
||||
|
||||
|
@ -801,6 +801,9 @@ Data source : @4"}, /* eds_statement */
|
||||
{335545094, "There is no privilege for this operation"}, /* dyn_no_priv */
|
||||
{335545095, "Using GRANT OPTION on @1 not allowed"}, /* dsql_cant_grant_option */
|
||||
{335545096, "read conflicts with concurrent update"}, /* read_conflict */
|
||||
{335545097, "@1 failed when working with CREATE DATABASE grants"}, /* crdb_load */
|
||||
{335545098, "CREATE DATABASE grants check is not possible when database @1 is not present"}, /* crdb_nodb */
|
||||
{335545099, "CREATE DATABASE grants check is not possible when table RDB$DB_CREATORS is not present in database @1"}, /* crdb_notable */
|
||||
{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 */
|
||||
|
@ -797,6 +797,9 @@ static const struct {
|
||||
{335545094, -901}, /* 774 dyn_no_priv */
|
||||
{335545095, -901}, /* 775 dsql_cant_grant_option */
|
||||
{335545096, -904}, /* 776 read_conflict */
|
||||
{335545097, -901}, /* 777 crdb_load */
|
||||
{335545098, -901}, /* 778 crdb_nodb */
|
||||
{335545099, -901}, /* 779 crdb_notable */
|
||||
{335740929, -901}, /* 1 gfix_db_name */
|
||||
{335740930, -901}, /* 2 gfix_invalid_sw */
|
||||
{335740932, -901}, /* 4 gfix_incmp_sw */
|
||||
|
@ -797,6 +797,9 @@ static const struct {
|
||||
{335545094, "42000"}, // 774 dyn_no_priv
|
||||
{335545095, "42000"}, // 775 dsql_cant_grant_option
|
||||
{335545096, "40001"}, // 776 read_conflict
|
||||
{335545097, "08004"}, // 777 crdb_load
|
||||
{335545098, "0A000"}, // 778 crdb_nodb
|
||||
{335545099, "0A000"}, // 779 crdb_notable
|
||||
{335740929, "00000"}, // 1 gfix_db_name
|
||||
{335740930, "00000"}, // 2 gfix_invalid_sw
|
||||
{335740932, "00000"}, // 4 gfix_incmp_sw
|
||||
|
@ -1452,6 +1452,44 @@ processing_state SHOW_grants2 (const SCHAR* object,
|
||||
return ps_ERR;
|
||||
END_ERROR
|
||||
|
||||
if (obj_type == obj_database || obj_type == 255)
|
||||
{
|
||||
FOR PRV IN SEC$DB_CREATORS
|
||||
SORTED BY PRV.SEC$USER_TYPE, PRV.SEC$USER
|
||||
|
||||
if (first && optional_msg)
|
||||
isqlGlob.prints(optional_msg);
|
||||
|
||||
first = false;
|
||||
fb_utils::exact_name(PRV.SEC$USER);
|
||||
|
||||
switch (PRV.SEC$USER_TYPE)
|
||||
{
|
||||
case obj_sql_role:
|
||||
case obj_user:
|
||||
if (mangle && isqlGlob.db_SQL_dialect > SQL_DIALECT_V6_TRANSITION)
|
||||
IUTILS_copy_SQL_id(PRV.SEC$USER, SQL_identifier, DBL_QUOTE);
|
||||
else
|
||||
strcpy(SQL_identifier, PRV.SEC$USER);
|
||||
break;
|
||||
default:
|
||||
fb_assert(false);
|
||||
strcpy(SQL_identifier, PRV.SEC$USER);
|
||||
break;
|
||||
}
|
||||
|
||||
set_grantee(PRV.SEC$USER_TYPE, SQL_identifier, user_string);
|
||||
|
||||
isqlGlob.printf("GRANT CREATE DATABASE TO %s%s%s",
|
||||
user_string, terminator, NEWLINE);
|
||||
|
||||
END_FOR
|
||||
ON_ERROR
|
||||
ISQL_errmsg(fbStatus);
|
||||
return ps_ERR;
|
||||
END_ERROR
|
||||
}
|
||||
|
||||
if (!first)
|
||||
return (SKIP);
|
||||
}
|
||||
|
249
src/jrd/DbCreators.cpp
Normal file
249
src/jrd/DbCreators.cpp
Normal file
@ -0,0 +1,249 @@
|
||||
/*
|
||||
* PROGRAM: JRD access method
|
||||
* MODULE: DbCreators.cpp
|
||||
* DESCRIPTION: Checks CREATE DATABASE right (in security.db)
|
||||
*
|
||||
* The contents of this file are subject to the Initial
|
||||
* Developer's Public License Version 1.0 (the "License");
|
||||
* you may not use this file except in compliance with the
|
||||
* License. You may obtain a copy of the License at
|
||||
* http://www.ibphoenix.com/main.nfs?a=ibphoenix&page=ibp_idpl.
|
||||
*
|
||||
* Software distributed under the License is distributed AS IS,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing rights
|
||||
* and limitations under the License.
|
||||
*
|
||||
* The Original Code was created by Alex Peshkov
|
||||
* for the Firebird Open Source RDBMS project.
|
||||
*
|
||||
* Copyright (c) 2014 Alex Peshkov <peshkoff at mail.ru>
|
||||
* and all contributors signed below.
|
||||
*
|
||||
* All Rights Reserved.
|
||||
* Contributor(s): ______________________________________.
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#include "firebird.h"
|
||||
#include "firebird/Provider.h"
|
||||
#include "../auth/SecureRemotePassword/Message.h"
|
||||
#include "gen/iberror.h"
|
||||
|
||||
#include "../jrd/constants.h"
|
||||
#include "../common/classes/ClumpletWriter.h"
|
||||
#include "../common/classes/init.h"
|
||||
#include "../common/classes/Hash.h"
|
||||
#include "../common/classes/GenericMap.h"
|
||||
#include "../common/classes/RefMutex.h"
|
||||
#include "../common/classes/SyncObject.h"
|
||||
#include "../common/classes/MetaName.h"
|
||||
#include "../common/isc_s_proto.h"
|
||||
#include "../common/isc_proto.h"
|
||||
#include "../common/ThreadStart.h"
|
||||
#include "../common/db_alias.h"
|
||||
|
||||
#include "../jrd/DbCreators.h"
|
||||
#include "../jrd/tra.h"
|
||||
#include "../jrd/ini.h"
|
||||
#include "gen/ids.h"
|
||||
|
||||
#define DBC_DEBUG(A)
|
||||
|
||||
using namespace Firebird;
|
||||
|
||||
namespace {
|
||||
|
||||
void check(const char* s, IStatus* st)
|
||||
{
|
||||
if (!(st->getStatus() & IStatus::FB_HAS_ERRORS))
|
||||
return;
|
||||
|
||||
Arg::StatusVector newStatus(st);
|
||||
newStatus << Arg::Gds(isc_crdb_load) << s;
|
||||
newStatus.raise();
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
LocalStatus st;
|
||||
att = prov->attachDatabase(&st, securityDb,
|
||||
embeddedSysdba.getBufferLength(), embeddedSysdba.getBuffer());
|
||||
if (st.getStatus() & IStatus::FB_HAS_ERRORS)
|
||||
{
|
||||
if (!fb_utils::containsErrorCode(st.getErrors(), isc_io_error))
|
||||
check("IProvider::attachDatabase", &st);
|
||||
|
||||
// missing security DB - checking granted rights not possible
|
||||
return false;
|
||||
}
|
||||
|
||||
ClumpletWriter readOnly(ClumpletWriter::Tpb, MAX_DPB_SIZE, isc_tpb_version1);
|
||||
readOnly.insertTag(isc_tpb_read);
|
||||
readOnly.insertTag(isc_tpb_wait);
|
||||
tra = att->startTransaction(&st, readOnly.getBufferLength(), readOnly.getBuffer());
|
||||
check("IAttachment::startTransaction", &st);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
|
||||
namespace Jrd {
|
||||
|
||||
bool checkCreateDatabaseGrant(Firebird::string& userName, Firebird::string& trustedRole,
|
||||
const char* securityDb)
|
||||
{
|
||||
if (userName == SYSDBA_USER_NAME || trustedRole == ADMIN_ROLE)
|
||||
return true;
|
||||
|
||||
RefPtr<IAttachment> att;
|
||||
RefPtr<ITransaction> tra;
|
||||
if (!openDb(securityDb, att, tra))
|
||||
return false;
|
||||
|
||||
Message gr;
|
||||
Field<ISC_SHORT> uType(gr);
|
||||
Field<Varying> u(gr, MAX_SQL_IDENTIFIER_LEN);
|
||||
Field<ISC_SHORT> rType(gr);
|
||||
Field<Varying> r(gr, MAX_SQL_IDENTIFIER_LEN);
|
||||
uType = obj_user;
|
||||
u = userName.c_str();
|
||||
rType = trustedRole.hasData() ? obj_sql_role : 255;
|
||||
r = trustedRole.c_str();
|
||||
|
||||
Message result;
|
||||
Field<ISC_INT64> cnt(result);
|
||||
|
||||
LocalStatus st;
|
||||
att->execute(&st, tra, 0,
|
||||
"select count(*) from RDB$DB_CREATORS"
|
||||
" where (RDB$USER_TYPE = ? and RDB$USER = ?) or (RDB$USER_TYPE = ? and RDB$USER = ?)",
|
||||
SQL_DIALECT_V6, gr.getMetadata(), gr.getBuffer(), result.getMetadata(), result.getBuffer());
|
||||
if (st.getStatus() & IStatus::FB_HAS_ERRORS)
|
||||
{
|
||||
if (fb_utils::containsErrorCode(st.getErrors(), isc_dsql_relation_err))
|
||||
{
|
||||
// isc_dsql_relation_err when exec SQL - i.e. table RDB$DB_CREATORS
|
||||
// is missing due to non-FB3 security DB
|
||||
return false;
|
||||
}
|
||||
check("IAttachment::execute", &st);
|
||||
}
|
||||
|
||||
return cnt > 0;
|
||||
}
|
||||
|
||||
|
||||
const Format* DbCreatorsScan::getFormat(thread_db* tdbb, jrd_rel* relation) const
|
||||
{
|
||||
jrd_tra* const transaction = tdbb->getTransaction();
|
||||
return transaction->getDbCreatorsList()->getList(tdbb, relation)->getFormat();
|
||||
}
|
||||
|
||||
bool DbCreatorsScan::retrieveRecord(thread_db* tdbb, jrd_rel* relation,
|
||||
FB_UINT64 position, Record* record) const
|
||||
{
|
||||
jrd_tra* const transaction = tdbb->getTransaction();
|
||||
return transaction->getDbCreatorsList()->getList(tdbb, relation)->fetch(position, record);
|
||||
}
|
||||
|
||||
DbCreatorsList::DbCreatorsList(jrd_tra* tra)
|
||||
: SnapshotData(*tra->tra_pool)
|
||||
{ }
|
||||
|
||||
RecordBuffer* DbCreatorsList::makeBuffer(thread_db* tdbb)
|
||||
{
|
||||
MemoryPool* const pool = tdbb->getTransaction()->tra_pool;
|
||||
allocBuffer(tdbb, *pool, rel_sec_db_creators);
|
||||
return getData(rel_sec_db_creators);
|
||||
}
|
||||
|
||||
RecordBuffer* DbCreatorsList::getList(thread_db* tdbb, jrd_rel* relation)
|
||||
{
|
||||
fb_assert(relation);
|
||||
fb_assert(relation->rel_id == rel_sec_db_creators);
|
||||
|
||||
RecordBuffer* buffer = getData(relation);
|
||||
if (buffer)
|
||||
{
|
||||
return buffer;
|
||||
}
|
||||
|
||||
RefPtr<IAttachment> att;
|
||||
RefPtr<ITransaction> tra;
|
||||
const char* dbName = tdbb->getDatabase()->dbb_config->getSecurityDatabase();
|
||||
if (!openDb(dbName, att, tra))
|
||||
{
|
||||
// In embedded mode we are not raising any errors - silent return
|
||||
if (MasterInterfacePtr()->serverMode(-1) < 0)
|
||||
return makeBuffer(tdbb);
|
||||
|
||||
(Arg::Gds(isc_crdb_nodb) << dbName).raise();
|
||||
}
|
||||
|
||||
Message gr;
|
||||
Field<ISC_SHORT> uType(gr);
|
||||
Field<Varying> u(gr, MAX_SQL_IDENTIFIER_LEN);
|
||||
|
||||
LocalStatus st;
|
||||
RefPtr<IResultSet> curs(att->openCursor(&st, tra, 0,
|
||||
"select RDB$USER_TYPE, RDB$USER from RDB$DB_CREATORS",
|
||||
SQL_DIALECT_V6, NULL, NULL, gr.getMetadata(), NULL));
|
||||
|
||||
if (st.getStatus() & IStatus::FB_HAS_ERRORS)
|
||||
{
|
||||
if (!fb_utils::containsErrorCode(st.getErrors(), isc_dsql_relation_err))
|
||||
check("IAttachment::openCursor", &st);
|
||||
|
||||
// isc_dsql_relation_err when opening cursor - i.e. table
|
||||
// is missing due to non-FB3 security DB
|
||||
|
||||
// In embedded mode we are not raising any errors - silent return
|
||||
if (MasterInterfacePtr()->serverMode(-1) < 0)
|
||||
return makeBuffer(tdbb);
|
||||
|
||||
(Arg::Gds(isc_crdb_notable) << dbName).raise();
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
buffer = makeBuffer(tdbb);
|
||||
while (curs->fetchNext(&st, gr.getBuffer()) == IStatus::FB_OK)
|
||||
{
|
||||
int charset = CS_METADATA;
|
||||
Record* record = buffer->getTempRecord();
|
||||
record->nullify();
|
||||
|
||||
putField(tdbb, record,
|
||||
DumpField(f_sec_crt_user, VALUE_STRING, u->len, u->data),
|
||||
charset);
|
||||
|
||||
SINT64 v = uType;
|
||||
putField(tdbb, record,
|
||||
DumpField(f_sec_crt_u_type, VALUE_INTEGER, sizeof(v), &v),
|
||||
charset);
|
||||
|
||||
buffer->store(record);
|
||||
}
|
||||
check("IResultSet::fetchNext", &st);
|
||||
}
|
||||
catch (const Exception&)
|
||||
{
|
||||
clearSnapshot();
|
||||
throw;
|
||||
}
|
||||
|
||||
return getData(relation);
|
||||
}
|
||||
|
||||
} // namespace Jrd
|
69
src/jrd/DbCreators.h
Normal file
69
src/jrd/DbCreators.h
Normal file
@ -0,0 +1,69 @@
|
||||
/*
|
||||
* PROGRAM: JRD access method
|
||||
* MODULE: DbCreators.h
|
||||
* DESCRIPTION: GRANT CREATE DATABASE right (in security.db)
|
||||
*
|
||||
* The contents of this file are subject to the Initial
|
||||
* Developer's Public License Version 1.0 (the "License");
|
||||
* you may not use this file except in compliance with the
|
||||
* License. You may obtain a copy of the License at
|
||||
* http://www.ibphoenix.com/main.nfs?a=ibphoenix&page=ibp_idpl.
|
||||
*
|
||||
* Software distributed under the License is distributed AS IS,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing rights
|
||||
* and limitations under the License.
|
||||
*
|
||||
* The Original Code was created by Alex Peshkov
|
||||
* for the Firebird Open Source RDBMS project.
|
||||
*
|
||||
* Copyright (c) 2014 Alex Peshkov <peshkoff at mail.ru>
|
||||
* and all contributors signed below.
|
||||
*
|
||||
* All Rights Reserved.
|
||||
* Contributor(s): ______________________________________.
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef JRD_DB_CREATORS
|
||||
#define JRD_DB_CREATORS
|
||||
|
||||
#include "../common/classes/alloc.h"
|
||||
#include "../common/classes/fb_string.h"
|
||||
#include "../jrd/recsrc/RecordSource.h"
|
||||
#include "../jrd/Monitoring.h"
|
||||
|
||||
namespace Jrd {
|
||||
|
||||
bool checkCreateDatabaseGrant(Firebird::string& userName, Firebird::string& trustedRole,
|
||||
const char* securityDb);
|
||||
|
||||
class DbCreatorsScan: public VirtualTableScan
|
||||
{
|
||||
public:
|
||||
DbCreatorsScan(CompilerScratch* csb, const Firebird::string& alias,
|
||||
StreamType stream, jrd_rel* relation)
|
||||
: VirtualTableScan(csb, alias, stream, relation)
|
||||
{}
|
||||
|
||||
protected:
|
||||
const Format* getFormat(thread_db* tdbb, jrd_rel* relation) const;
|
||||
bool retrieveRecord(thread_db* tdbb, jrd_rel* relation, FB_UINT64 position, Record* record) const;
|
||||
};
|
||||
|
||||
class DbCreatorsList : public SnapshotData
|
||||
{
|
||||
public:
|
||||
explicit DbCreatorsList(jrd_tra* tra);
|
||||
|
||||
RecordBuffer* getList(thread_db* tdbb, jrd_rel* relation);
|
||||
|
||||
private:
|
||||
RecordBuffer* makeBuffer(thread_db* tdbb);
|
||||
};
|
||||
|
||||
} // namespace Jrd
|
||||
|
||||
|
||||
#endif // JRD_DB_CREATORS
|
@ -126,6 +126,7 @@
|
||||
#include "../jrd/DebugInterface.h"
|
||||
#include "../jrd/EngineInterface.h"
|
||||
#include "../jrd/CryptoManager.h"
|
||||
#include "../jrd/DbCreators.h"
|
||||
|
||||
#include "../dsql/dsql.h"
|
||||
#include "../dsql/dsql_proto.h"
|
||||
@ -995,7 +996,7 @@ static void release_attachment(thread_db*, Jrd::Attachment*);
|
||||
static void rollback(thread_db*, jrd_tra*, const bool);
|
||||
static void strip_quotes(string&);
|
||||
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>*);
|
||||
static void getUserInfo(UserId&, const DatabaseOptions&, const char*, const char*, const RefPtr<Config>*, bool);
|
||||
|
||||
static THREAD_ENTRY_DECLARE shutdown_thread(THREAD_ENTRY_PARAM);
|
||||
|
||||
@ -1007,7 +1008,7 @@ TraceFailedConnection::TraceFailedConnection(const char* filename, const Databas
|
||||
m_filename(filename),
|
||||
m_options(options)
|
||||
{
|
||||
getUserInfo(m_id, *m_options, m_filename, NULL, NULL);
|
||||
getUserInfo(m_id, *m_options, m_filename, NULL, NULL, false);
|
||||
}
|
||||
|
||||
|
||||
@ -1397,7 +1398,7 @@ JAttachment* FB_CARG JProvider::attachDatabase(IStatus* user_status, const char*
|
||||
}
|
||||
|
||||
// Check for correct credentials supplied
|
||||
getUserInfo(userId, options, org_filename.c_str(), expanded_name.c_str(), &config);
|
||||
getUserInfo(userId, options, org_filename.c_str(), expanded_name.c_str(), &config, false);
|
||||
|
||||
#ifdef WIN_NT
|
||||
guardDbInit.enter(); // Required to correctly expand name of just created database
|
||||
@ -2409,7 +2410,7 @@ JAttachment* FB_CARG JProvider::createDatabase(IStatus* user_status, const char*
|
||||
}
|
||||
|
||||
// Check for correct credentials supplied
|
||||
getUserInfo(userId, options, org_filename.c_str(), NULL, &config);
|
||||
getUserInfo(userId, options, org_filename.c_str(), NULL, &config, true);
|
||||
|
||||
#ifdef WIN_NT
|
||||
guardDbInit.enter(); // Required to correctly expand name of just created database
|
||||
@ -7055,9 +7056,8 @@ static VdnResult verifyDatabaseName(const PathName& name, ISC_STATUS* status, bo
|
||||
|
||||
getUserInfo
|
||||
|
||||
@brief Almost stub-like now.
|
||||
Planned to take into an account mapping of users and groups.
|
||||
Fills UserId structure with resulting values.
|
||||
@brief Fills UserId structure with resulting values.
|
||||
Takes into an account mapping of users and groups.
|
||||
|
||||
@param user
|
||||
@param options
|
||||
@ -7065,7 +7065,7 @@ static VdnResult verifyDatabaseName(const PathName& name, ISC_STATUS* status, bo
|
||||
|
||||
**/
|
||||
static void getUserInfo(UserId& user, const DatabaseOptions& options,
|
||||
const char* aliasName, const char* dbName, const RefPtr<Config>* config)
|
||||
const char* aliasName, const char* dbName, const RefPtr<Config>* config, bool creating)
|
||||
{
|
||||
bool wheel = false;
|
||||
int id = -1, group = -1; // CVC: This var contained trash
|
||||
@ -7092,6 +7092,12 @@ static void getUserInfo(UserId& user, const DatabaseOptions& options,
|
||||
aliasName, dbName, (config ? (*config)->getSecurityDatabase() : NULL));
|
||||
ISC_systemToUtf8(name);
|
||||
ISC_systemToUtf8(trusted_role);
|
||||
|
||||
if (creating && config) // when config is NULL we are in error handler
|
||||
{
|
||||
if (!checkCreateDatabaseGrant(name, trusted_role, (*config)->getSecurityDatabase()))
|
||||
(Arg::Gds(isc_no_priv) << "CREATE" << "DATABASE" << aliasName).raise();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -394,3 +394,8 @@ NAME("SEC$MAP_FROM_TYPE", nam_sec_map_from_type)
|
||||
NAME("SEC$MAP_FROM", nam_sec_map_from)
|
||||
NAME("SEC$MAP_TO_TYPE", nam_sec_map_to_type)
|
||||
NAME("SEC$MAP_TO", nam_sec_map_to)
|
||||
|
||||
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)
|
||||
|
@ -85,6 +85,7 @@
|
||||
#include "../jrd/recsrc/RecordSource.h"
|
||||
#include "../jrd/recsrc/Cursor.h"
|
||||
#include "../jrd/Mapping.h"
|
||||
#include "../jrd/DbCreators.h"
|
||||
|
||||
#include "../jrd/Optimizer.h"
|
||||
#include "../dsql/BoolNodes.h"
|
||||
@ -2264,17 +2265,24 @@ static RecordSource* gen_retrieval(thread_db* tdbb,
|
||||
else if (relation->isVirtual())
|
||||
{
|
||||
// Virtual table: monitoring or security
|
||||
if (relation->rel_id == rel_global_auth_mapping)
|
||||
switch(relation->rel_id)
|
||||
{
|
||||
case rel_global_auth_mapping:
|
||||
rsb = FB_NEW(*tdbb->getDefaultPool()) GlobalMappingScan(csb, alias, stream, relation);
|
||||
}
|
||||
else if (relation->rel_id == rel_sec_users || relation->rel_id == rel_sec_user_attributes)
|
||||
{
|
||||
break;
|
||||
|
||||
case rel_sec_users:
|
||||
case rel_sec_user_attributes:
|
||||
rsb = FB_NEW(*tdbb->getDefaultPool()) UsersTableScan(csb, alias, stream, relation);
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
|
||||
case rel_sec_db_creators:
|
||||
rsb = FB_NEW(*tdbb->getDefaultPool()) DbCreatorsScan(csb, alias, stream, relation);
|
||||
break;
|
||||
|
||||
default:
|
||||
rsb = FB_NEW(*tdbb->getDefaultPool()) MonitoringTableScan(csb, alias, stream, relation);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -649,7 +649,7 @@ END_RELATION
|
||||
|
||||
// Relation 46 (SEC$GLOBAL_AUTH_MAPPING)
|
||||
RELATION(nam_sec_global_auth_mapping, rel_global_auth_mapping, ODS_12_0, rel_virtual)
|
||||
FIELD(f_sec_map_name, nam_sec_map_name, fld_map_name, 1, ODS_12_0)
|
||||
FIELD(f_sec_map_name, nam_sec_map_name, fld_map_name, 0, ODS_12_0)
|
||||
FIELD(f_sec_map_using, nam_sec_map_using, fld_map_using, 0, ODS_12_0)
|
||||
FIELD(f_sec_map_plugin, nam_sec_map_plugin, fld_map_plugin, 0, ODS_12_0)
|
||||
FIELD(f_sec_map_db, nam_sec_map_db, fld_map_db, 0, ODS_12_0)
|
||||
@ -658,3 +658,15 @@ RELATION(nam_sec_global_auth_mapping, rel_global_auth_mapping, ODS_12_0, rel_vir
|
||||
FIELD(f_sec_map_to_type, nam_sec_map_to_type, fld_obj_type, 0, ODS_12_0)
|
||||
FIELD(f_sec_map_to, nam_sec_map_to, fld_map_to, 0, ODS_12_0)
|
||||
END_RELATION
|
||||
|
||||
// Relation 47 (RDB$DB_CREATORS)
|
||||
RELATION(nam_db_creators, rel_db_creators, ODS_12_0, rel_persistent)
|
||||
FIELD(f_crt_user, nam_user, fld_user, 1, ODS_12_0)
|
||||
FIELD(f_crt_u_type, nam_user_type, fld_obj_type, 1, ODS_12_0)
|
||||
END_RELATION
|
||||
|
||||
// Relation 48 (SEC$DB_CREATORS)
|
||||
RELATION(nam_sec_db_creators, rel_sec_db_creators, ODS_12_0, rel_virtual)
|
||||
FIELD(f_sec_crt_user, nam_sec_user, fld_user, 0, ODS_12_0)
|
||||
FIELD(f_sec_crt_u_type, nam_sec_user_type, fld_obj_type, 0, ODS_12_0)
|
||||
END_RELATION
|
||||
|
@ -73,6 +73,7 @@
|
||||
#include "../jrd/Function.h"
|
||||
#include "../jrd/Collation.h"
|
||||
#include "../jrd/Mapping.h"
|
||||
#include "../jrd/DbCreators.h"
|
||||
|
||||
|
||||
const int DYN_MSG_FAC = 8;
|
||||
@ -3401,6 +3402,15 @@ MappingList* jrd_tra::getMappingList()
|
||||
return tra_mapping_list;
|
||||
}
|
||||
|
||||
DbCreatorsList* jrd_tra::getDbCreatorsList()
|
||||
{
|
||||
if (!tra_dbcreators_list)
|
||||
{
|
||||
tra_dbcreators_list = FB_NEW(*tra_pool) DbCreatorsList(this);
|
||||
}
|
||||
return tra_dbcreators_list;
|
||||
}
|
||||
|
||||
|
||||
jrd_tra* jrd_tra::getOuter()
|
||||
{
|
||||
|
@ -71,6 +71,7 @@ class DeferredJob;
|
||||
class dsql_opn;
|
||||
class UserManagement;
|
||||
class MappingList;
|
||||
class DbCreatorsList;
|
||||
class thread_db;
|
||||
|
||||
class SecDbContext
|
||||
@ -303,6 +304,7 @@ private:
|
||||
UserManagement* tra_user_management;
|
||||
SecDbContext* tra_sec_db_context;
|
||||
MappingList* tra_mapping_list;
|
||||
DbCreatorsList* tra_dbcreators_list;
|
||||
MemoryPool* tra_autonomous_pool;
|
||||
USHORT tra_autonomous_cnt;
|
||||
static const USHORT TRA_AUTONOMOUS_PER_POOL = 64;
|
||||
@ -359,6 +361,7 @@ public:
|
||||
SecDbContext* setSecDbContext(Firebird::IAttachment* att, Firebird::ITransaction* tra);
|
||||
void eraseSecDbContext();
|
||||
MappingList* getMappingList();
|
||||
DbCreatorsList* getDbCreatorsList();
|
||||
|
||||
GenIdCache* getGenIdCache()
|
||||
{
|
||||
|
@ -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-08-27 16:38:00', 'JRD', 0, 777)
|
||||
('2014-09-02 19:54:57', 'JRD', 0, 780)
|
||||
('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)
|
||||
|
@ -884,6 +884,9 @@ Data source : @4', NULL, NULL)
|
||||
('dyn_no_priv', NULL, 'scl.epp', NULL, 0, 774, NULL, 'There is no privilege for this operation', NULL, NULL);
|
||||
('dsql_cant_grant_option', NULL, 'DdlNodes.epp', NULL, 0, 775, NULL, 'Using GRANT OPTION on @1 not allowed', NULL, NULL);
|
||||
('read_conflict', NULL, NULL, 'vio.cpp', 0, 776, NULL, 'read conflicts with concurrent update', NULL, NULL);
|
||||
('crdb_load', 'check', 'DbCreators.cpp', NULL, 0, 777, NULL, '@1 failed when working with CREATE DATABASE grants', NULL, NULL);
|
||||
('crdb_nodb', 'DbCreatorsList::getList', 'DbCreators.cpp', NULL, 0, 778, NULL, 'CREATE DATABASE grants check is not possible when database @1 is not present', NULL, NULL);
|
||||
('crdb_notable', 'DbCreatorsList::getList', 'DbCreators.cpp', NULL, 0, 779, NULL, 'CREATE DATABASE grants check is not possible when table RDB$DB_CREATORS is not present in database @1', 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);
|
||||
|
@ -783,6 +783,9 @@ set bulk_insert INSERT INTO SYSTEM_ERRORS (SQL_CODE, SQL_CLASS, SQL_SUBCLASS, FA
|
||||
(-901, '42', '000', 0, 774, 'dyn_no_priv', NULL, NULL)
|
||||
(-901, '42', '000', 0, 775, 'dsql_cant_grant_option', NULL, NULL);
|
||||
(-904, '40', '001', 0, 776, 'read_conflict', NULL, NULL);
|
||||
(-901, '08', '004', 0, 777, 'crdb_load', NULL, NULL);
|
||||
(-901, '0A', '000', 0, 778, 'crdb_nodb', NULL, NULL);
|
||||
(-901, '0A', '000', 0, 779, 'crdb_notable', NULL, NULL);
|
||||
-- GFIX
|
||||
(-901, '00', '000', 3, 1, 'gfix_db_name', NULL, NULL)
|
||||
(-901, '00', '000', 3, 2, 'gfix_invalid_sw', NULL, NULL)
|
||||
|
Loading…
Reference in New Issue
Block a user