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

Implemented CORE-4538: Access rights for CREATE DATABASE operator

This commit is contained in:
alexpeshkoff 2014-09-02 16:55:14 +00:00
parent 45a5d66a32
commit 2a293c2691
24 changed files with 869 additions and 275 deletions

View File

@ -17,7 +17,7 @@ REVOKE [GRANT OPTION FOR] DROP ANY <OBJECT> FROM [USER | ROLE] <user/role name>;
Where <OBJECT> could be: Where <OBJECT> could be:
TABLE, VIEW, PROCEDURE, FUNCTION, PACKAGE, GENERATOR, SEQUENCE, DOMAIN, TABLE, VIEW, PROCEDURE, FUNCTION, PACKAGE, GENERATOR, SEQUENCE, DOMAIN,
EXCEPTION, ROLE, DATABASE, CHARACTER SET, COLLATION, FILTER EXCEPTION, ROLE, CHARACTER SET, COLLATION, FILTER
Description: Description:
@ -33,3 +33,13 @@ Sample:
GRANT CREATE TABLE TO Joe; GRANT CREATE TABLE TO Joe;
GRANT ALTER ANY TABLE TO Joe; GRANT ALTER ANY TABLE TO Joe;
REVOKE CREATE TABLE FROM 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>;

View File

@ -1604,6 +1604,12 @@ C --
PARAMETER (GDS__dsql_cant_grant_option = 335545095) PARAMETER (GDS__dsql_cant_grant_option = 335545095)
INTEGER*4 GDS__read_conflict INTEGER*4 GDS__read_conflict
PARAMETER (GDS__read_conflict = 335545096) 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 INTEGER*4 GDS__gfix_db_name
PARAMETER (GDS__gfix_db_name = 335740929) PARAMETER (GDS__gfix_db_name = 335740929)
INTEGER*4 GDS__gfix_invalid_sw INTEGER*4 GDS__gfix_invalid_sw

View File

@ -809,6 +809,9 @@ const
gds_dyn_no_priv = 335545094; gds_dyn_no_priv = 335545094;
gds_dsql_cant_grant_option = 335545095; gds_dsql_cant_grant_option = 335545095;
gds_read_conflict = 335545096; gds_read_conflict = 335545096;
gds_crdb_load = 335545097;
gds_crdb_nodb = 335545098;
gds_crdb_notable = 335545099;
gds_gfix_db_name = 335740929; gds_gfix_db_name = 335740929;
gds_gfix_invalid_sw = 335740930; gds_gfix_invalid_sw = 335740930;
gds_gfix_incmp_sw = 335740932; gds_gfix_incmp_sw = 335740932;

View File

@ -113,6 +113,60 @@ static const char* const CHECK_CONSTRAINT_EXCEPTION = "check_constraint";
DATABASE DB = STATIC "ODS.RDB"; 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; return false;
} }
// It's purpose is to add/drop mapping from any security name to DB security object. void MappingNode::runInSecurityDb(SecDbContext* secDbContext)
void MappingNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, jrd_tra* transaction)
{ {
if (!(tdbb->getAttachment() && tdbb->getAttachment()->locksmith())) Firebird::LocalStatus st;
status_exception::raise(Arg::Gds(isc_adm_task_denied));
if (global)
{
LocalStatus st;
LocalStatus s2; // we will use it in DDL case and remember
IStatus* s = &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 // first of all try to use regenerated DDL statement
// that's the best way if security database is FB3 or higher fb version // that's the best way if security database is FB3 or higher fb version
string ddl; string ddl;
@ -9778,12 +9799,16 @@ void MappingNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, jrd
} }
// Now try to run DDL // 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); 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 // try direct access to rdb$auth_mapping table in secure db
LocalStatus s2;
s = &s2;
// check presence of such record in the table // check presence of such record in the table
Message msgCheck; 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, secDbContext->att->execute(s, secDbContext->tra, 0, sql, SQL_DIALECT_V6,
msg->getMetadata(), msg->getBuffer(), NULL, NULL); msg->getMetadata(), msg->getBuffer(), NULL, NULL);
check(s); 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& ex)
catch (const Exception&)
{ {
if (savePoint.hasData()) if (st.getStatus() & IStatus::FB_HAS_ERRORS)
{ {
secDbContext->att->execute(s, secDbContext->tra, 0, ("ROLLBACK TO SAVEPOINT " + savePoint).c_str(), const ISC_STATUS* stat2 = st.getErrors();
SQL_DIALECT_V6, NULL, NULL, NULL, NULL);
}
if (s2.getStatus() & IStatus::FB_HAS_ERRORS)
{
const ISC_STATUS* stat2 = s2.getErrors();
if (stat2[1] != isc_dsql_token_unk_err) if (stat2[1] != isc_dsql_token_unk_err)
status_exception::raise(&s2); status_exception::raise(&st);
} }
throw; 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; return;
} }
@ -10319,6 +10343,8 @@ void GrantRevokeNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch,
// run all statements under savepoint control // run all statements under savepoint control
AutoSavePoint savePoint(tdbb, transaction); AutoSavePoint savePoint(tdbb, transaction);
createDbJobs.clear();
const GranteeClause* usersPtr; const GranteeClause* usersPtr;
const GranteeClause* usersEnd; 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 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, void GrantRevokeNode::modifyPrivileges(thread_db* tdbb, jrd_tra* transaction, SSHORT option,
const GranteeClause* user) 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 if (!isGrant && !privs) // REVOKE ALL ON ALL
{ {
AutoCacheRequest request(tdbb, drq_e_grant3, DYN_REQUESTS); AutoCacheRequest request(tdbb, drq_e_grant3, DYN_REQUESTS);
bool grantErased = false; CreateDbJob all(userType, user);
bool badGrantor = false; all.allOnAll = true;
all.revoker = grantorRevoker;
FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction) FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction)
PRIV IN RDB$USER_PRIVILEGES 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) if (tdbb->getAttachment()->att_user->locksmith() || grantorRevoker == PRIV.RDB$GRANTOR)
{ {
ERASE PRIV; ERASE PRIV;
grantErased = true; all.grantErased = true;
} }
else else
badGrantor = true; all.badGrantor = true;
} }
END_FOR END_FOR
const char* all = "ALL"; createDbJobs.push(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));
}
return; 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]; char priv[2];
priv[1] = '\0'; priv[1] = '\0';

View File

@ -41,7 +41,7 @@ namespace Jrd {
class CompoundStmtNode; class CompoundStmtNode;
class RelationSourceNode; class RelationSourceNode;
class ValueListNode; class ValueListNode;
class SecDbContext;
struct BoolSourceClause 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> template <typename CreateNode, typename DropNode, ISC_STATUS ERROR_CODE>
class RecreateNode : public DdlNode class RecreateNode : public DdlNode
{ {
@ -1802,7 +1814,7 @@ public:
}; };
class MappingNode : public DdlNode class MappingNode : public DdlNode, private ExecInSecurityDb
{ {
public: public:
enum OP {MAP_ADD, MAP_MOD, MAP_RPL, MAP_DROP}; enum OP {MAP_ADD, MAP_MOD, MAP_RPL, MAP_DROP};
@ -1836,6 +1848,7 @@ protected:
(op == MAP_ADD ? "CREATE" : op == MAP_MOD ? (op == MAP_ADD ? "CREATE" : op == MAP_MOD ?
"ALTER" : op == MAP_RPL ? "CREATE OR ALTER" : "DROP"); "ALTER" : op == MAP_RPL ? "CREATE OR ALTER" : "DROP");
} }
void runInSecurityDb(SecDbContext* secDbContext);
private: private:
void addItem(Firebird::string& ddl, const char* text); 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<char, ValueListNode*> > PrivilegeClause;
typedef Firebird::Pair<Firebird::NonPooled<SSHORT, Firebird::MetaName> > GranteeClause; typedef Firebird::Pair<Firebird::NonPooled<SSHORT, Firebird::MetaName> > GranteeClause;
class GrantRevokeNode : public DdlNode class GrantRevokeNode : public DdlNode, private ExecInSecurityDb
{ {
public: public:
GrantRevokeNode(MemoryPool& p, bool aIsGrant) GrantRevokeNode(MemoryPool& p, bool aIsGrant)
: DdlNode(p), : DdlNode(p),
createDbJobs(p),
isGrant(aIsGrant), isGrant(aIsGrant),
privileges(p), privileges(p),
roles(p), roles(p),
@ -2001,6 +2015,7 @@ protected:
statusVector << statusVector <<
Firebird::Arg::Gds(isGrant ? isc_dsql_grant_failed : isc_dsql_revoke_failed); Firebird::Arg::Gds(isGrant ? isc_dsql_grant_failed : isc_dsql_revoke_failed);
} }
void runInSecurityDb(SecDbContext* secDbContext);
private: private:
void modifyPrivileges(thread_db* tdbb, jrd_tra* transaction, SSHORT option, const GranteeClause* user); void modifyPrivileges(thread_db* tdbb, jrd_tra* transaction, SSHORT option, const GranteeClause* user);
@ -2043,6 +2058,19 @@ private:
return "<Unknown>"; 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: public:
bool isGrant; bool isGrant;
Firebird::Array<PrivilegeClause> privileges; Firebird::Array<PrivilegeClause> privileges;

View File

@ -976,6 +976,7 @@ db_ddl_privilege_list($privilegeArray)
%type db_ddl_privilege(<privilegeArray>) %type db_ddl_privilege(<privilegeArray>)
db_ddl_privilege($privilegeArray) db_ddl_privilege($privilegeArray)
| CREATE { $privilegeArray->add(PrivilegeClause('C', NULL)); }
| ALTER { $privilegeArray->add(PrivilegeClause('L', NULL)); } | ALTER { $privilegeArray->add(PrivilegeClause('L', NULL)); }
| DROP { $privilegeArray->add(PrivilegeClause('O', NULL)); } | DROP { $privilegeArray->add(PrivilegeClause('O', NULL)); }
; ;

View File

@ -798,6 +798,9 @@ static const struct {
{"dyn_no_priv", 335545094}, {"dyn_no_priv", 335545094},
{"dsql_cant_grant_option", 335545095}, {"dsql_cant_grant_option", 335545095},
{"read_conflict", 335545096}, {"read_conflict", 335545096},
{"crdb_load", 335545097},
{"crdb_nodb", 335545098},
{"crdb_notable", 335545099},
{"gfix_db_name", 335740929}, {"gfix_db_name", 335740929},
{"gfix_invalid_sw", 335740930}, {"gfix_invalid_sw", 335740930},
{"gfix_incmp_sw", 335740932}, {"gfix_incmp_sw", 335740932},

View File

@ -832,6 +832,9 @@ const ISC_STATUS isc_dup_attribute = 335545093L;
const ISC_STATUS isc_dyn_no_priv = 335545094L; const ISC_STATUS isc_dyn_no_priv = 335545094L;
const ISC_STATUS isc_dsql_cant_grant_option = 335545095L; const ISC_STATUS isc_dsql_cant_grant_option = 335545095L;
const ISC_STATUS isc_read_conflict = 335545096L; 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_db_name = 335740929L;
const ISC_STATUS isc_gfix_invalid_sw = 335740930L; const ISC_STATUS isc_gfix_invalid_sw = 335740930L;
const ISC_STATUS isc_gfix_incmp_sw = 335740932L; 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_switch_param_miss = 337182758L;
const ISC_STATUS isc_trace_param_act_notcompat = 337182759L; const ISC_STATUS isc_trace_param_act_notcompat = 337182759L;
const ISC_STATUS isc_trace_mandatory_switch_miss = 337182760L; 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 */ #else /* c definitions */
@ -2092,6 +2095,9 @@ const ISC_STATUS isc_err_max = 1234;
#define isc_dyn_no_priv 335545094L #define isc_dyn_no_priv 335545094L
#define isc_dsql_cant_grant_option 335545095L #define isc_dsql_cant_grant_option 335545095L
#define isc_read_conflict 335545096L #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_db_name 335740929L
#define isc_gfix_invalid_sw 335740930L #define isc_gfix_invalid_sw 335740930L
#define isc_gfix_incmp_sw 335740932L #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_switch_param_miss 337182758L
#define isc_trace_param_act_notcompat 337182759L #define isc_trace_param_act_notcompat 337182759L
#define isc_trace_mandatory_switch_miss 337182760L #define isc_trace_mandatory_switch_miss 337182760L
#define isc_err_max 1234 #define isc_err_max 1237
#endif #endif

View File

@ -660,3 +660,15 @@
const USHORT f_sec_map_to = 7; 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;

View File

@ -801,6 +801,9 @@ Data source : @4"}, /* eds_statement */
{335545094, "There is no privilege for this operation"}, /* dyn_no_priv */ {335545094, "There is no privilege for this operation"}, /* dyn_no_priv */
{335545095, "Using GRANT OPTION on @1 not allowed"}, /* dsql_cant_grant_option */ {335545095, "Using GRANT OPTION on @1 not allowed"}, /* dsql_cant_grant_option */
{335545096, "read conflicts with concurrent update"}, /* read_conflict */ {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 */ {335740929, "data base file name (@1) already given"}, /* gfix_db_name */
{335740930, "invalid switch @1"}, /* gfix_invalid_sw */ {335740930, "invalid switch @1"}, /* gfix_invalid_sw */
{335740932, "incompatible switch combination"}, /* gfix_incmp_sw */ {335740932, "incompatible switch combination"}, /* gfix_incmp_sw */

View File

@ -797,6 +797,9 @@ static const struct {
{335545094, -901}, /* 774 dyn_no_priv */ {335545094, -901}, /* 774 dyn_no_priv */
{335545095, -901}, /* 775 dsql_cant_grant_option */ {335545095, -901}, /* 775 dsql_cant_grant_option */
{335545096, -904}, /* 776 read_conflict */ {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 */ {335740929, -901}, /* 1 gfix_db_name */
{335740930, -901}, /* 2 gfix_invalid_sw */ {335740930, -901}, /* 2 gfix_invalid_sw */
{335740932, -901}, /* 4 gfix_incmp_sw */ {335740932, -901}, /* 4 gfix_incmp_sw */

View File

@ -797,6 +797,9 @@ static const struct {
{335545094, "42000"}, // 774 dyn_no_priv {335545094, "42000"}, // 774 dyn_no_priv
{335545095, "42000"}, // 775 dsql_cant_grant_option {335545095, "42000"}, // 775 dsql_cant_grant_option
{335545096, "40001"}, // 776 read_conflict {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 {335740929, "00000"}, // 1 gfix_db_name
{335740930, "00000"}, // 2 gfix_invalid_sw {335740930, "00000"}, // 2 gfix_invalid_sw
{335740932, "00000"}, // 4 gfix_incmp_sw {335740932, "00000"}, // 4 gfix_incmp_sw

View File

@ -1452,6 +1452,44 @@ processing_state SHOW_grants2 (const SCHAR* object,
return ps_ERR; return ps_ERR;
END_ERROR 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) if (!first)
return (SKIP); return (SKIP);
} }

249
src/jrd/DbCreators.cpp Normal file
View 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
View 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

View File

@ -126,6 +126,7 @@
#include "../jrd/DebugInterface.h" #include "../jrd/DebugInterface.h"
#include "../jrd/EngineInterface.h" #include "../jrd/EngineInterface.h"
#include "../jrd/CryptoManager.h" #include "../jrd/CryptoManager.h"
#include "../jrd/DbCreators.h"
#include "../dsql/dsql.h" #include "../dsql/dsql.h"
#include "../dsql/dsql_proto.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 rollback(thread_db*, jrd_tra*, const bool);
static void strip_quotes(string&); static void strip_quotes(string&);
static void purge_attachment(thread_db* tdbb, StableAttachmentPart* sAtt, unsigned flags = 0); 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); static THREAD_ENTRY_DECLARE shutdown_thread(THREAD_ENTRY_PARAM);
@ -1007,7 +1008,7 @@ TraceFailedConnection::TraceFailedConnection(const char* filename, const Databas
m_filename(filename), m_filename(filename),
m_options(options) 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 // 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 #ifdef WIN_NT
guardDbInit.enter(); // Required to correctly expand name of just created database 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 // 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 #ifdef WIN_NT
guardDbInit.enter(); // Required to correctly expand name of just created database 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 getUserInfo
@brief Almost stub-like now. @brief Fills UserId structure with resulting values.
Planned to take into an account mapping of users and groups. Takes into an account mapping of users and groups.
Fills UserId structure with resulting values.
@param user @param user
@param options @param options
@ -7065,7 +7065,7 @@ static VdnResult verifyDatabaseName(const PathName& name, ISC_STATUS* status, bo
**/ **/
static void getUserInfo(UserId& user, const DatabaseOptions& options, 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; bool wheel = false;
int id = -1, group = -1; // CVC: This var contained trash 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)); aliasName, dbName, (config ? (*config)->getSecurityDatabase() : NULL));
ISC_systemToUtf8(name); ISC_systemToUtf8(name);
ISC_systemToUtf8(trusted_role); 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 else
{ {

View File

@ -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_FROM", nam_sec_map_from)
NAME("SEC$MAP_TO_TYPE", nam_sec_map_to_type) NAME("SEC$MAP_TO_TYPE", nam_sec_map_to_type)
NAME("SEC$MAP_TO", nam_sec_map_to) 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)

View File

@ -85,6 +85,7 @@
#include "../jrd/recsrc/RecordSource.h" #include "../jrd/recsrc/RecordSource.h"
#include "../jrd/recsrc/Cursor.h" #include "../jrd/recsrc/Cursor.h"
#include "../jrd/Mapping.h" #include "../jrd/Mapping.h"
#include "../jrd/DbCreators.h"
#include "../jrd/Optimizer.h" #include "../jrd/Optimizer.h"
#include "../dsql/BoolNodes.h" #include "../dsql/BoolNodes.h"
@ -2264,17 +2265,24 @@ static RecordSource* gen_retrieval(thread_db* tdbb,
else if (relation->isVirtual()) else if (relation->isVirtual())
{ {
// Virtual table: monitoring or security // 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); rsb = FB_NEW(*tdbb->getDefaultPool()) GlobalMappingScan(csb, alias, stream, relation);
} break;
else if (relation->rel_id == rel_sec_users || relation->rel_id == rel_sec_user_attributes)
{ case rel_sec_users:
case rel_sec_user_attributes:
rsb = FB_NEW(*tdbb->getDefaultPool()) UsersTableScan(csb, alias, stream, relation); rsb = FB_NEW(*tdbb->getDefaultPool()) UsersTableScan(csb, alias, stream, relation);
} break;
else
{ 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); rsb = FB_NEW(*tdbb->getDefaultPool()) MonitoringTableScan(csb, alias, stream, relation);
break;
} }
} }
else else

View File

@ -649,7 +649,7 @@ END_RELATION
// Relation 46 (SEC$GLOBAL_AUTH_MAPPING) // Relation 46 (SEC$GLOBAL_AUTH_MAPPING)
RELATION(nam_sec_global_auth_mapping, rel_global_auth_mapping, ODS_12_0, rel_virtual) 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_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_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) 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_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) FIELD(f_sec_map_to, nam_sec_map_to, fld_map_to, 0, ODS_12_0)
END_RELATION 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

View File

@ -73,6 +73,7 @@
#include "../jrd/Function.h" #include "../jrd/Function.h"
#include "../jrd/Collation.h" #include "../jrd/Collation.h"
#include "../jrd/Mapping.h" #include "../jrd/Mapping.h"
#include "../jrd/DbCreators.h"
const int DYN_MSG_FAC = 8; const int DYN_MSG_FAC = 8;
@ -3401,6 +3402,15 @@ MappingList* jrd_tra::getMappingList()
return tra_mapping_list; 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() jrd_tra* jrd_tra::getOuter()
{ {

View File

@ -71,6 +71,7 @@ class DeferredJob;
class dsql_opn; class dsql_opn;
class UserManagement; class UserManagement;
class MappingList; class MappingList;
class DbCreatorsList;
class thread_db; class thread_db;
class SecDbContext class SecDbContext
@ -303,6 +304,7 @@ private:
UserManagement* tra_user_management; UserManagement* tra_user_management;
SecDbContext* tra_sec_db_context; SecDbContext* tra_sec_db_context;
MappingList* tra_mapping_list; MappingList* tra_mapping_list;
DbCreatorsList* tra_dbcreators_list;
MemoryPool* tra_autonomous_pool; MemoryPool* tra_autonomous_pool;
USHORT tra_autonomous_cnt; USHORT tra_autonomous_cnt;
static const USHORT TRA_AUTONOMOUS_PER_POOL = 64; static const USHORT TRA_AUTONOMOUS_PER_POOL = 64;
@ -359,6 +361,7 @@ public:
SecDbContext* setSecDbContext(Firebird::IAttachment* att, Firebird::ITransaction* tra); SecDbContext* setSecDbContext(Firebird::IAttachment* att, Firebird::ITransaction* tra);
void eraseSecDbContext(); void eraseSecDbContext();
MappingList* getMappingList(); MappingList* getMappingList();
DbCreatorsList* getDbCreatorsList();
GenIdCache* getGenIdCache() GenIdCache* getGenIdCache()
{ {

View File

@ -1,7 +1,7 @@
/* MAX_NUMBER is the next number to be used, always one more than the highest message number. */ /* 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 (?, ?, ?, ?); 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) ('2012-01-23 20:10:30', 'QLI', 1, 532)
('2013-11-13 15:59:10', 'GFIX', 3, 122) ('2013-11-13 15:59:10', 'GFIX', 3, 122)
('1996-11-07 13:39:40', 'GPRE', 4, 1) ('1996-11-07 13:39:40', 'GPRE', 4, 1)

View File

@ -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); ('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); ('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); ('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 -- QLI
(NULL, NULL, NULL, NULL, 1, 0, NULL, 'expected type', NULL, NULL); (NULL, NULL, NULL, NULL, 1, 0, NULL, 'expected type', NULL, NULL);
(NULL, NULL, NULL, NULL, 1, 1, NULL, 'bad block type', NULL, NULL); (NULL, NULL, NULL, NULL, 1, 1, NULL, 'bad block type', NULL, NULL);

View File

@ -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, 774, 'dyn_no_priv', NULL, NULL)
(-901, '42', '000', 0, 775, 'dsql_cant_grant_option', NULL, NULL); (-901, '42', '000', 0, 775, 'dsql_cant_grant_option', NULL, NULL);
(-904, '40', '001', 0, 776, 'read_conflict', 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 -- GFIX
(-901, '00', '000', 3, 1, 'gfix_db_name', NULL, NULL) (-901, '00', '000', 3, 1, 'gfix_db_name', NULL, NULL)
(-901, '00', '000', 3, 2, 'gfix_invalid_sw', NULL, NULL) (-901, '00', '000', 3, 2, 'gfix_invalid_sw', NULL, NULL)