|
From: <ale...@us...> - 2014-09-02 16:55:25
|
Revision: 60025
http://sourceforge.net/p/firebird/code/60025
Author: alexpeshkoff
Date: 2014-09-02 16:55:14 +0000 (Tue, 02 Sep 2014)
Log Message:
-----------
Implemented CORE-4538: Access rights for CREATE DATABASE operator
Modified Paths:
--------------
firebird/trunk/doc/sql.extensions/README.ddl_access.txt
firebird/trunk/lang_helpers/gds_codes.ftn
firebird/trunk/lang_helpers/gds_codes.pas
firebird/trunk/src/dsql/DdlNodes.epp
firebird/trunk/src/dsql/DdlNodes.h
firebird/trunk/src/dsql/parse.y
firebird/trunk/src/include/gen/codetext.h
firebird/trunk/src/include/gen/iberror.h
firebird/trunk/src/include/gen/ids.h
firebird/trunk/src/include/gen/msgs.h
firebird/trunk/src/include/gen/sql_code.h
firebird/trunk/src/include/gen/sql_state.h
firebird/trunk/src/isql/show.epp
firebird/trunk/src/jrd/jrd.cpp
firebird/trunk/src/jrd/names.h
firebird/trunk/src/jrd/opt.cpp
firebird/trunk/src/jrd/relations.h
firebird/trunk/src/jrd/tra.cpp
firebird/trunk/src/jrd/tra.h
firebird/trunk/src/msgs/facilities2.sql
firebird/trunk/src/msgs/messages2.sql
firebird/trunk/src/msgs/system_errors2.sql
Added Paths:
-----------
firebird/trunk/src/jrd/DbCreators.cpp
firebird/trunk/src/jrd/DbCreators.h
Modified: firebird/trunk/doc/sql.extensions/README.ddl_access.txt
===================================================================
--- firebird/trunk/doc/sql.extensions/README.ddl_access.txt 2014-09-02 06:29:44 UTC (rev 60024)
+++ firebird/trunk/doc/sql.extensions/README.ddl_access.txt 2014-09-02 16:55:14 UTC (rev 60025)
@@ -16,12 +16,12 @@
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
+TABLE, VIEW, PROCEDURE, FUNCTION, PACKAGE, GENERATOR, SEQUENCE, DOMAIN,
+EXCEPTION, ROLE, CHARACTER SET, COLLATION, FILTER
Description:
-Makes it possible to grant and revoke privileges on DDL operations.
+Makes it possible to grant and revoke privileges on DDL operations.
DDL operations for managing triggers and indices re-use table privileges.
@@ -31,5 +31,15 @@
Sample:
GRANT CREATE TABLE TO Joe;
-GRANT ALTER ANY 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>;
Modified: firebird/trunk/lang_helpers/gds_codes.ftn
===================================================================
--- firebird/trunk/lang_helpers/gds_codes.ftn 2014-09-02 06:29:44 UTC (rev 60024)
+++ firebird/trunk/lang_helpers/gds_codes.ftn 2014-09-02 16:55:14 UTC (rev 60025)
@@ -1604,6 +1604,12 @@
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
Modified: firebird/trunk/lang_helpers/gds_codes.pas
===================================================================
--- firebird/trunk/lang_helpers/gds_codes.pas 2014-09-02 06:29:44 UTC (rev 60024)
+++ firebird/trunk/lang_helpers/gds_codes.pas 2014-09-02 16:55:14 UTC (rev 60025)
@@ -809,6 +809,9 @@
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;
Modified: firebird/trunk/src/dsql/DdlNodes.epp
===================================================================
--- firebird/trunk/src/dsql/DdlNodes.epp 2014-09-02 06:29:44 UTC (rev 60024)
+++ firebird/trunk/src/dsql/DdlNodes.epp 2014-09-02 16:55:14 UTC (rev 60025)
@@ -115,7 +115,61 @@
//----------------------
+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;
+ }
+}
+
+
+//----------------------
+
+
// Check temporary table reference rules between given child relation and master
// relation (owner of given PK/UK index).
static void checkForeignKeyTempScope(thread_db* tdbb, jrd_tra* transaction,
@@ -9662,243 +9716,213 @@
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));
+ Firebird::LocalStatus st;
+ IStatus* s = &st;
- if (global)
+ // 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;
+
+ switch(op)
{
- LocalStatus st;
- LocalStatus s2; // we will use it in DDL case and remember
- IStatus* s = &st;
+ case MAP_ADD:
+ ddl = "CREATE MAPPING ";
+ break;
+ case MAP_MOD:
+ ddl = "ALTER MAPPING ";
+ break;
+ case MAP_DROP:
+ ddl = "DROP MAPPING ";
+ break;
+ case MAP_RPL:
+ ddl = "CREATE OR ALTER MAPPING ";
+ break;
+ }
- SecDbContext* secDbContext = transaction->getSecDbContext();
- if (!secDbContext)
+ addItem(ddl, name.c_str());
+ if (op != MAP_DROP)
+ {
+ ddl += " USING ";
+ switch (mode)
{
- 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);
+ case 'P':
+ if (!plugin)
+ ddl += "ANY PLUGIN ";
+ else
+ {
+ ddl += "PLUGIN ";
+ addItem(ddl, plugin->c_str());
+ ddl += ' ';
+ }
+ break;
+ case 'S':
+ ddl += "ANY PLUGIN SERVERWIDE ";
+ break;
+ case '*':
+ ddl += "* ";
+ break;
+ case 'M':
+ ddl += "MAPPING ";
+ break;
+ }
- ITransaction* tra = att->startTransaction(s, 0, NULL);
- check(s);
+ if (db)
+ {
+ ddl += "IN ";
+ addItem(ddl, db->c_str());
+ ddl += ' ';
+ }
- secDbContext = transaction->setSecDbContext(att, tra);
+ if (fromType)
+ {
+ ddl += "FROM ";
+ if (!from)
+ ddl += "ANY ";
+ addItem(ddl, fromType->c_str());
+ ddl += ' ';
+ if (from)
+ {
+ addItem(ddl, from->getString().c_str());
+ ddl += ' ';
+ }
}
- // 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);
+ ddl += "TO ";
+ ddl += (role ? "ROLE" : "USER");
+ if (to)
+ {
+ ddl += ' ';
+ addItem(ddl, to->c_str());
+ }
+ }
+ // Now try to run DDL
+ secDbContext->att->execute(s, secDbContext->tra, 0, ddl.c_str(), SQL_DIALECT_V6,
+ NULL, NULL, NULL, NULL);
+
+ if (s->getStatus() & IStatus::FB_HAS_ERRORS)
+ {
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;
+ // 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;
+ Field<Varying> nm(msgCheck, 1);
+ nm = name.c_str();
+
+ Message result;
+ Field<ISC_INT64> cnt(result);
+
+ const char* checkSql = "select count(*) from RDB$AUTH_MAPPING where RDB$MAP_NAME = ?";
+
+ secDbContext->att->execute(s, secDbContext->tra, 0, checkSql, SQL_DIALECT_V6,
+ msgCheck.getMetadata(), msgCheck.getBuffer(), result.getMetadata(), result.getBuffer());
+ check(s);
+
+ if (cnt > 1 && op != MAP_DROP)
+ ERRD_bugcheck("Database mapping misconfigured");
+
+ bool hasLine = cnt > 0;
switch(op)
{
case MAP_ADD:
- ddl = "CREATE MAPPING ";
+ if (hasLine)
+ (Arg::Gds(isc_map_already_exists) << name).raise();
break;
+
case MAP_MOD:
- ddl = "ALTER MAPPING ";
- break;
case MAP_DROP:
- ddl = "DROP MAPPING ";
+ if (!hasLine)
+ (Arg::Gds(isc_map_not_exists) << name).raise();
break;
+
case MAP_RPL:
- ddl = "CREATE OR ALTER MAPPING ";
+ op = hasLine ? MAP_MOD : MAP_DROP;
break;
}
- addItem(ddl, name.c_str());
- if (op != MAP_DROP)
- {
- ddl += " USING ";
- switch (mode)
- {
- case 'P':
- if (!plugin)
- ddl += "ANY PLUGIN ";
- else
- {
- ddl += "PLUGIN ";
- addItem(ddl, plugin->c_str());
- ddl += ' ';
- }
- break;
- case 'S':
- ddl += "ANY PLUGIN SERVERWIDE ";
- break;
- case '*':
- ddl += "* ";
- break;
- case 'M':
- ddl += "MAPPING ";
- break;
- }
+ // Get ready to modify table
+ Message full;
+ Field<ISC_SHORT> toType(full);
+ Field<Varying> t(full, MAX_SQL_IDENTIFIER_LEN);
+ Field<Varying> usng2(full, 1);
+ Field<Varying> plug2(full, MAX_SQL_IDENTIFIER_LEN);
+ Field<Varying> d2(full, MAX_SQL_IDENTIFIER_LEN);
+ Field<Varying> type2(full, MAX_SQL_IDENTIFIER_LEN);
+ Field<Varying> f2(full, 255);
+ Field<Varying> nm2(full, MAX_SQL_IDENTIFIER_LEN);
- if (db)
- {
- ddl += "IN ";
- addItem(ddl, db->c_str());
- ddl += ' ';
- }
+ toType = role ? 1 : 0;
+ if (to)
+ t = to->c_str();
+ usng2.set(1, &mode);
+ if (plugin)
+ plug2 = plugin->c_str();
+ if (db)
+ d2 = db->c_str();
+ if (fromType)
+ type2 = fromType->c_str();
+ if (from)
+ f2 = from->getString().c_str();
+ nm2 = name.c_str();
- if (fromType)
- {
- ddl += "FROM ";
- if (!from)
- ddl += "ANY ";
- addItem(ddl, fromType->c_str());
- ddl += ' ';
- if (from)
- {
- addItem(ddl, from->getString().c_str());
- ddl += ' ';
- }
- }
-
- ddl += "TO ";
- ddl += (role ? "ROLE" : "USER");
- if (to)
- {
- ddl += ' ';
- addItem(ddl, to->c_str());
- }
+ Message* msg = NULL;
+ const char* sql = NULL;
+ switch(op)
+ {
+ case MAP_ADD:
+ sql = "insert into RDB$AUTH_MAPPING(RDB$MAP_TO_TYPE, RDB$MAP_TO, RDB$MAP_USING, "
+ "RDB$MAP_PLUGIN, RDB$MAP_DB, RDB$MAP_FROM_TYPE, RDB$MAP_FROM, RDB$MAP_NAME) "
+ "values (?, ?, ?, ?, ?, ?, ?, ?)";
+ msg = &full;
+ break;
+ case MAP_MOD:
+ sql = "update RDB$AUTH_MAPPING set RDB$MAP_TO_TYPE = ?, RDB$MAP_TO = ?, "
+ "RDB$MAP_USING = ?, RDB$MAP_PLUGIN = ?, RDB$MAP_DB = ?, "
+ "RDB$MAP_FROM_TYPE = ?, RDB$MAP_FROM = ? "
+ "where RDB$MAP_NAME = ?";
+ msg = &full;
+ break;
+ case MAP_DROP:
+ sql = "delete from RDBAUTH_MAPPING where RDB$MAP_NAME = ?";
+ msg = &msgCheck;
+ break;
}
- // Now try to run DDL
- secDbContext->att->execute(&s2, secDbContext->tra, 0, ddl.c_str(), SQL_DIALECT_V6,
- NULL, NULL, NULL, NULL);
-
- if (s2.getStatus() & IStatus::FB_HAS_ERRORS)
- {
- // try direct access to rdb$auth_mapping table in secure db
-
- // check presence of such record in the table
- Message msgCheck;
- Field<Varying> nm(msgCheck, 1);
- nm = name.c_str();
-
- Message result;
- Field<ISC_INT64> cnt(result);
-
- const char* checkSql = "select count(*) from RDB$AUTH_MAPPING where RDB$MAP_NAME = ?";
-
- secDbContext->att->execute(s, secDbContext->tra, 0, checkSql, SQL_DIALECT_V6,
- msgCheck.getMetadata(), msgCheck.getBuffer(), result.getMetadata(), result.getBuffer());
- check(s);
-
- if (cnt > 1 && op != MAP_DROP)
- ERRD_bugcheck("Database mapping misconfigured");
-
- bool hasLine = cnt > 0;
- switch(op)
- {
- case MAP_ADD:
- if (hasLine)
- (Arg::Gds(isc_map_already_exists) << name).raise();
- break;
-
- case MAP_MOD:
- case MAP_DROP:
- if (!hasLine)
- (Arg::Gds(isc_map_not_exists) << name).raise();
- break;
-
- case MAP_RPL:
- op = hasLine ? MAP_MOD : MAP_DROP;
- break;
- }
-
- // Get ready to modify table
- Message full;
- Field<ISC_SHORT> toType(full);
- Field<Varying> t(full, MAX_SQL_IDENTIFIER_LEN);
- Field<Varying> usng2(full, 1);
- Field<Varying> plug2(full, MAX_SQL_IDENTIFIER_LEN);
- Field<Varying> d2(full, MAX_SQL_IDENTIFIER_LEN);
- Field<Varying> type2(full, MAX_SQL_IDENTIFIER_LEN);
- Field<Varying> f2(full, 255);
- Field<Varying> nm2(full, MAX_SQL_IDENTIFIER_LEN);
-
- toType = role ? 1 : 0;
- if (to)
- t = to->c_str();
- usng2.set(1, &mode);
- if (plugin)
- plug2 = plugin->c_str();
- if (db)
- d2 = db->c_str();
- if (fromType)
- type2 = fromType->c_str();
- if (from)
- f2 = from->getString().c_str();
- nm2 = name.c_str();
-
- Message* msg = NULL;
- const char* sql = NULL;
- switch(op)
- {
- case MAP_ADD:
- sql = "insert into RDB$AUTH_MAPPING(RDB$MAP_TO_TYPE, RDB$MAP_TO, RDB$MAP_USING, "
- "RDB$MAP_PLUGIN, RDB$MAP_DB, RDB$MAP_FROM_TYPE, RDB$MAP_FROM, RDB$MAP_NAME) "
- "values (?, ?, ?, ?, ?, ?, ?, ?)";
- msg = &full;
- break;
- case MAP_MOD:
- sql = "update RDB$AUTH_MAPPING set RDB$MAP_TO_TYPE = ?, RDB$MAP_TO = ?, "
- "RDB$MAP_USING = ?, RDB$MAP_PLUGIN = ?, RDB$MAP_DB = ?, "
- "RDB$MAP_FROM_TYPE = ?, RDB$MAP_FROM = ? "
- "where RDB$MAP_NAME = ?";
- msg = &full;
- break;
- case MAP_DROP:
- sql = "delete from RDBAUTH_MAPPING where RDB$MAP_NAME = ?";
- msg = &msgCheck;
- break;
- }
-
- // Actual modification
- fb_assert(sql && msg);
- 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);
- }
+ // Actual modification
+ fb_assert(sql && msg);
+ secDbContext->att->execute(s, secDbContext->tra, 0, sql, SQL_DIALECT_V6,
+ msg->getMetadata(), msg->getBuffer(), NULL, NULL);
+ 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 @@
// run all statements under savepoint control
AutoSavePoint savePoint(tdbb, transaction);
+ createDbJobs.clear();
+
const GranteeClause* usersPtr;
const GranteeClause* usersEnd;
@@ -10356,9 +10382,83 @@
}
}
+ 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 @@
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,30 +10579,15 @@
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";
+ 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;
}
@@ -10527,6 +10613,30 @@
}
}
+ 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';
Modified: firebird/trunk/src/dsql/DdlNodes.h
===================================================================
--- firebird/trunk/src/dsql/DdlNodes.h 2014-09-02 06:29:44 UTC (rev 60024)
+++ firebird/trunk/src/dsql/DdlNodes.h 2014-09-02 16:55:14 UTC (rev 60025)
@@ -41,8 +41,8 @@
class CompoundStmtNode;
class RelationSourceNode;
class ValueListNode;
+class SecDbContext;
-
struct BoolSourceClause
{
explicit BoolSourceClause(MemoryPool& p)
@@ -135,6 +135,18 @@
};
+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 @@
};
-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 @@
(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 @@
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 @@
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 @@
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;
Modified: firebird/trunk/src/dsql/parse.y
===================================================================
--- firebird/trunk/src/dsql/parse.y 2014-09-02 06:29:44 UTC (rev 60024)
+++ firebird/trunk/src/dsql/parse.y 2014-09-02 16:55:14 UTC (rev 60025)
@@ -976,6 +976,7 @@
%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)); }
;
Modified: firebird/trunk/src/include/gen/codetext.h
===================================================================
--- firebird/trunk/src/include/gen/codetext.h 2014-09-02 06:29:44 UTC (rev 60024)
+++ firebird/trunk/src/include/gen/codetext.h 2014-09-02 16:55:14 UTC (rev 60025)
@@ -798,6 +798,9 @@
{"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},
Modified: firebird/trunk/src/include/gen/iberror.h
===================================================================
--- firebird/trunk/src/include/gen/iberror.h 2014-09-02 06:29:44 UTC (rev 60024)
+++ firebird/trunk/src/include/gen/iberror.h 2014-09-02 16:55:14 UTC (rev 60025)
@@ -832,6 +832,9 @@
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_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 @@
#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 @@
#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
Modified: firebird/trunk/src/include/gen/ids.h
===================================================================
--- firebird/trunk/src/include/gen/ids.h 2014-09-02 06:29:44 UTC (rev 60024)
+++ firebird/trunk/src/include/gen/ids.h 2014-09-02 16:55:14 UTC (rev 60025)
@@ -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;
+
+
Modified: firebird/trunk/src/include/gen/msgs.h
===================================================================
--- firebird/trunk/src/include/gen/msgs.h 2014-09-02 06:29:44 UTC (rev 60024)
+++ firebird/trunk/src/include/gen/msgs.h 2014-09-02 16:55:14 UTC (rev 60025)
@@ -801,6 +801,9 @@
{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 */
Modified: firebird/trunk/src/include/gen/sql_code.h
===================================================================
--- firebird/trunk/src/include/gen/sql_code.h 2014-09-02 06:29:44 UTC (rev 60024)
+++ firebird/trunk/src/include/gen/sql_code.h 2014-09-02 16:55:14 UTC (rev 60025)
@@ -797,6 +797,9 @@
{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 */
Modified: firebird/trunk/src/include/gen/sql_state.h
===================================================================
--- firebird/trunk/src/include/gen/sql_state.h 2014-09-02 06:29:44 UTC (rev 60024)
+++ firebird/trunk/src/include/gen/sql_state.h 2014-09-02 16:55:14 UTC (rev 60025)
@@ -797,6 +797,9 @@
{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
Modified: firebird/trunk/src/isql/show.epp
===================================================================
--- firebird/trunk/src/isql/show.epp 2014-09-02 06:29:44 UTC (rev 60024)
+++ firebird/trunk/src/isql/show.epp 2014-09-02 16:55:14 UTC (rev 60025)
@@ -1452,6 +1452,44 @@
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);
}
Added: firebird/trunk/src/jrd/DbCreators.cpp
===================================================================
--- firebird/trunk/src/jrd/DbCreators.cpp (rev 0)
+++ firebird/trunk/src/jrd/DbCreators.cpp 2014-09-02 16:55:14 UTC (rev 60025)
@@ -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
Property changes on: firebird/trunk/src/jrd/DbCreators.cpp
___________________________________________________________________
Added: svn:mime-type
## -0,0 +1 ##
+text/x-c++src
\ No newline at end of property
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: firebird/trunk/src/jrd/DbCreators.h
===================================================================
--- firebird/trunk/src/jrd/DbCreators.h (rev 0)
+++ firebird/trunk/src/jrd/DbCreators.h 2014-09-02 16:55:14 UTC (rev 60025)
@@ -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
Property changes on: firebird/trunk/src/jrd/DbCreators.h
___________________________________________________________________
Added: svn:mime-type
## -0,0 +1 ##
+text/x-chdr
\ No newline at end of property
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Modified: firebird/trunk/src/jrd/jrd.cpp
===================================================================
--- firebird/trunk/src/jrd/jrd.cpp 2014-09-02 06:29:44 UTC (rev 60024)
+++ firebird/trunk/src/jrd/jrd.cpp 2014-09-02 16:55:14 UTC (rev 60025)
@@ -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 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 @@
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 @@
}
// 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 @@
}
// 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 @@
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 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 @@
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
{
Modified: firebird/trunk/src/jrd/names.h
===================================================================
--- firebird/trunk/src/jrd/names.h 2014-09-02 06:29:44 UTC (rev 60024)
+++ firebird/trunk/src/jrd/names.h 2014-09-02 16:55:14 UTC (rev 60025)
@@ -394,3 +394,8 @@
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)
Modified: firebird/trunk/src/jrd/opt.cpp
===================================================================
--- firebird/trunk/src/jrd/opt.cpp 2014-09-02 06:29:44 UTC (rev 60024)
+++ firebird/trunk/src/jrd/opt.cpp 2014-09-02 16:55:14 UTC (rev 60025)
@@ -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 @@
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
Modified: firebird/trunk/src/jrd/relations.h
===================================================================
--- firebird/trunk/src/jrd/relations.h 2014-09-02 06:29:44 UTC (rev 60024)
+++ firebird/trunk/src/jrd/relations.h 2014-09-02 16:55:14 UTC (rev 60025)
@@ -649,7 +649,7 @@
// 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 @@
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
Modified: firebird/trunk/src/jrd/tra.cpp
===================================================================
--- firebird/trunk/src/jrd/tra.cpp 2014-09-02 06:29:44 UTC (rev 60024)
+++ firebird/trunk/src/jrd/tra.cpp 2014-09-02 16:55:14 UTC (rev 60025)
@@ -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,7 +3402,16 @@
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* tra = this;
Modified: firebird/trunk/src/jrd/tra.h
===================================================================
--- firebird/trunk/src/jrd/tra.h 2014-09-02 06:29:44 UTC (rev 60024)
+++ firebird/trunk/src/jrd/tra.h 2014-09-02 16:55:14 UTC (rev 60025)
@@ -71,6 +71,7 @@
class dsql_opn;
class UserManagement;
class MappingList;
+class DbCreatorsList;
class thread_db;
class SecDbContext
@@ -303,6 +304,7 @@
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 @@
SecDbContext* setSecDbContext(Firebird::IAttachment* att, Firebird::ITransaction* tra);
void eraseSecDbContext();
MappingList* getMappingList();
+ DbCreatorsList* getDbCreatorsList();
GenIdCache* getGenIdCache()
{
Modified: firebird/trunk/src/msgs/facilities2.sql
===================================================================
--- firebird/trunk/src/msgs/facilities2.sql 2014-09-02 06:29:44 UTC (rev 60024)
+++ firebird/trunk/src/msgs/facilities2.sql 2014-09-02 16:55:14 UTC (rev 60025)
@@ -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)
Modified: firebird/trunk/src/msgs/messages2.sql
===================================================================
--- firebird/trunk/src/msgs/messages2.sql 2014-09-02 06:29:44 UTC (rev 60024)
+++ firebird/trunk/src/msgs/messages2.sql 2014-09-02 16:55:14 UTC (rev 60025)
@@ -884,6 +884,9 @@
('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);
Modified: firebird/trunk/src/msgs/system_errors2.sql
===================================================================
--- firebird/trunk/src/msgs/system_errors2.sql 2014-09-02 06:29:44 UTC (rev 60024)
+++ firebird/trunk/src/msgs/system_errors2.sql 2014-09-02 16:55:14 UTC (rev 60025)
@@ -783,6 +783,9 @@
(-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)
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|