mirror of
https://github.com/FirebirdSQL/firebird.git
synced 2025-01-22 14:03:03 +01:00
Allow to create database with different owner (#7718)
* Allow to create database with different owner via API * Support for OWNER clause in executeCreateDatabase() * squash! Support for OWNER clause in executeCreateDatabase() Fix rebase error
This commit is contained in:
parent
a0ff6b90a3
commit
b495b3f174
@ -618,3 +618,9 @@ ALTER PROCEDURE <name> SQL SECURITY {DEFINER | INVOKER} | DROP SQL SECURITY
|
||||
(Alexander Zhdanov)
|
||||
|
||||
ALTER PACKAGE <name> SQL SECURITY {DEFINER | INVOKER} | DROP SQL SECURITY
|
||||
|
||||
27) Added OWNER clause to CREATE DATABASE statement.
|
||||
(Dmitry Sibiryakov)
|
||||
|
||||
<db_initial_option> list is expanded by "OWNER username" clause which allows to set an owner user name for the created database.
|
||||
Only users with administrator rights can use this option.
|
||||
|
6
doc/sql.extensions/README.isc_dpb_xxx
Normal file
6
doc/sql.extensions/README.isc_dpb_xxx
Normal file
@ -0,0 +1,6 @@
|
||||
New Database Parameter Block items:
|
||||
|
||||
1. isc_dpb_owner :
|
||||
Used for createDatabase() call to set the owner for the new database
|
||||
to be different from user set with isc_user_name.
|
||||
Can be used only by users with admin rights.
|
@ -194,6 +194,7 @@ IntlParametersBlock::TagType IntlDpb::checkTag(UCHAR tag, const char** tagName)
|
||||
FB_IPB_TAG(isc_dpb_process_name);
|
||||
FB_IPB_TAG(isc_dpb_host_name);
|
||||
FB_IPB_TAG(isc_dpb_os_user);
|
||||
FB_IPB_TAG(isc_dpb_owner);
|
||||
return TAG_STRING;
|
||||
}
|
||||
|
||||
|
@ -350,6 +350,7 @@ PARSER_TOKEN(TOK_OVER, "OVER", false)
|
||||
PARSER_TOKEN(TOK_OVERFLOW, "OVERFLOW", true)
|
||||
PARSER_TOKEN(TOK_OVERLAY, "OVERLAY", true)
|
||||
PARSER_TOKEN(TOK_OVERRIDING, "OVERRIDING", true)
|
||||
PARSER_TOKEN(TOK_OWNER, "OWNER", true)
|
||||
PARSER_TOKEN(TOK_PACKAGE, "PACKAGE", true)
|
||||
PARSER_TOKEN(TOK_PAD, "PAD", true)
|
||||
PARSER_TOKEN(TOK_PAGE, "PAGE", true)
|
||||
|
@ -695,6 +695,7 @@ using namespace Firebird;
|
||||
%token <metaNamePtr> TIMEZONE_NAME
|
||||
%token <metaNamePtr> UNICODE_CHAR
|
||||
%token <metaNamePtr> UNICODE_VAL
|
||||
%token <metaNamePtr> OWNER
|
||||
|
||||
// tokens added for Firebird 6.0
|
||||
|
||||
@ -2155,6 +2156,8 @@ db_initial_option($alterDatabaseNode)
|
||||
: PAGE_SIZE equals NUMBER32BIT
|
||||
| USER symbol_user_name
|
||||
| USER utf_string
|
||||
| OWNER symbol_user_name
|
||||
| OWNER utf_string
|
||||
| ROLE valid_symbol_name
|
||||
| ROLE utf_string
|
||||
| PASSWORD utf_string
|
||||
@ -9464,6 +9467,7 @@ non_reserved_word
|
||||
// added in FB 6.0
|
||||
| ANY_VALUE
|
||||
| FORMAT
|
||||
| OWNER
|
||||
;
|
||||
|
||||
%%
|
||||
|
@ -132,6 +132,7 @@
|
||||
#define isc_dpb_upgrade_db 97
|
||||
#define isc_dpb_parallel_workers 100
|
||||
#define isc_dpb_worker_attach 101
|
||||
#define isc_dpb_owner 102
|
||||
|
||||
|
||||
/**************************************************/
|
||||
|
@ -4044,6 +4044,7 @@ const
|
||||
isc_dpb_upgrade_db = byte(97);
|
||||
isc_dpb_parallel_workers = byte(100);
|
||||
isc_dpb_worker_attach = byte(101);
|
||||
isc_dpb_owner = byte(102);
|
||||
isc_dpb_address = byte(1);
|
||||
isc_dpb_addr_protocol = byte(1);
|
||||
isc_dpb_addr_endpoint = byte(2);
|
||||
|
@ -104,11 +104,11 @@ bool openDb(const char* securityDb, RefPtr<IAttachment>& att, RefPtr<ITransactio
|
||||
|
||||
namespace Jrd {
|
||||
|
||||
bool checkCreateDatabaseGrant(const MetaString& userName, const MetaString& trustedRole,
|
||||
CreateGrant checkCreateDatabaseGrant(const MetaString& userName, const MetaString& trustedRole,
|
||||
const MetaString& sqlRole, const char* securityDb)
|
||||
{
|
||||
if (userName == DBA_USER_NAME)
|
||||
return true;
|
||||
return CreateGrant::ASSUMED;
|
||||
|
||||
RefPtr<IAttachment> att;
|
||||
RefPtr<ITransaction> tra;
|
||||
@ -169,10 +169,10 @@ bool checkCreateDatabaseGrant(const MetaString& userName, const MetaString& trus
|
||||
role = trustedRole;
|
||||
|
||||
if (role == ADMIN_ROLE)
|
||||
return true;
|
||||
return CreateGrant::ASSUMED;
|
||||
|
||||
if (!hasDb)
|
||||
return false;
|
||||
return CreateGrant::NONE;
|
||||
|
||||
// check db creators table
|
||||
Message gr;
|
||||
@ -198,13 +198,13 @@ bool checkCreateDatabaseGrant(const MetaString& userName, const MetaString& trus
|
||||
{
|
||||
// isc_dsql_relation_err when exec SQL - i.e. table RDB$DB_CREATORS
|
||||
// is missing due to non-FB3 security DB
|
||||
return false;
|
||||
return CreateGrant::NONE;
|
||||
}
|
||||
check("IAttachment::execute", &st);
|
||||
}
|
||||
|
||||
if (cnt > 0)
|
||||
return true;
|
||||
return CreateGrant::GRANTED;
|
||||
|
||||
if (!role.hasData())
|
||||
role = "NONE";
|
||||
@ -247,7 +247,7 @@ bool checkCreateDatabaseGrant(const MetaString& userName, const MetaString& trus
|
||||
|
||||
check("IResultSet::fetchNext", &st);
|
||||
|
||||
return wrk.test(CREATE_DATABASE);
|
||||
return wrk.test(CREATE_DATABASE) ? CreateGrant::GRANTED : CreateGrant::NONE;
|
||||
}
|
||||
|
||||
|
||||
|
@ -36,7 +36,14 @@
|
||||
|
||||
namespace Jrd {
|
||||
|
||||
bool checkCreateDatabaseGrant(const Firebird::MetaString& userName, const Firebird::MetaString& trustedRole,
|
||||
enum class CreateGrant
|
||||
{
|
||||
NONE, // This user cannot create databases
|
||||
GRANTED, // User was granted privilege to create database
|
||||
ASSUMED // User is admin and has all rights
|
||||
};
|
||||
|
||||
CreateGrant checkCreateDatabaseGrant(const Firebird::MetaString& userName, const Firebird::MetaString& trustedRole,
|
||||
const Firebird::MetaString& sqlRole, const char* securityDb);
|
||||
|
||||
class DbCreatorsScan: public VirtualTableScan
|
||||
|
@ -1111,6 +1111,7 @@ namespace Jrd
|
||||
PathName dpb_set_bind;
|
||||
string dpb_decfloat_round;
|
||||
string dpb_decfloat_traps;
|
||||
string dpb_owner;
|
||||
|
||||
public:
|
||||
static const ULONG DPB_FLAGS_MASK = DBB_damaged;
|
||||
@ -1337,7 +1338,7 @@ static void start_transaction(thread_db* tdbb, bool transliterate, jrd_tra** tr
|
||||
static void rollback(thread_db*, jrd_tra*, const bool);
|
||||
static void purge_attachment(thread_db* tdbb, StableAttachmentPart* sAtt, unsigned flags = 0);
|
||||
static void getUserInfo(UserId&, const DatabaseOptions&, const char*,
|
||||
const RefPtr<const Config>*, bool, Mapping& mapping, bool);
|
||||
const RefPtr<const Config>*, Mapping& mapping, bool);
|
||||
static void waitForShutdown(Semaphore&);
|
||||
|
||||
static THREAD_ENTRY_DECLARE shutdown_thread(THREAD_ENTRY_PARAM);
|
||||
@ -1353,7 +1354,7 @@ TraceFailedConnection::TraceFailedConnection(const char* filename, const Databas
|
||||
{
|
||||
Mapping mapping(Mapping::MAP_ERROR_HANDLER, NULL);
|
||||
mapping.setAuthBlock(m_options->dpb_auth_block);
|
||||
getUserInfo(m_id, *m_options, m_filename, NULL, false, mapping, false);
|
||||
getUserInfo(m_id, *m_options, m_filename, NULL, mapping, false);
|
||||
}
|
||||
|
||||
|
||||
@ -1949,7 +1950,7 @@ JAttachment* JProvider::internalAttach(CheckStatusWrapper* user_status, const ch
|
||||
try
|
||||
{
|
||||
mapping.setDb(filename, expanded_name.c_str(), jAtt);
|
||||
getUserInfo(userId, options, filename, &config, false, mapping, options.dpb_reset_icu);
|
||||
getUserInfo(userId, options, filename, &config, mapping, options.dpb_reset_icu);
|
||||
}
|
||||
catch(const Exception&)
|
||||
{
|
||||
@ -2847,7 +2848,41 @@ JAttachment* JProvider::createDatabase(CheckStatusWrapper* user_status, const ch
|
||||
|
||||
// Check for correct credentials supplied
|
||||
mapping.setSecurityDbAlias(config->getSecurityDatabase(), nullptr);
|
||||
getUserInfo(userId, options, filename, &config, true, mapping, false);
|
||||
getUserInfo(userId, options, filename, &config, mapping, false);
|
||||
|
||||
// Check user's power level
|
||||
CreateGrant powerLevel = CreateGrant::ASSUMED; // By default it is a boot build or embedded mode where everything is allowed
|
||||
if (options.dpb_auth_block.hasData())
|
||||
{
|
||||
powerLevel = checkCreateDatabaseGrant(userId.getUserName(), userId.getTrustedRole(), userId.getSqlRole(), config->getSecurityDatabase());
|
||||
}
|
||||
|
||||
switch (powerLevel)
|
||||
{
|
||||
case CreateGrant::NONE:
|
||||
(Arg::Gds(isc_no_priv) << "CREATE" << "DATABASE" << filename).raise();
|
||||
|
||||
case CreateGrant::ASSUMED:
|
||||
if (options.dpb_owner.hasData())
|
||||
{
|
||||
// Superuser can create databases for anyone other
|
||||
fb_utils::dpbItemUpper(options.dpb_owner);
|
||||
userId.setUserName(options.dpb_owner);
|
||||
}
|
||||
break;
|
||||
|
||||
case CreateGrant::GRANTED:
|
||||
if (options.dpb_owner.hasData())
|
||||
{
|
||||
// Superuser can create databases for anyone other
|
||||
fb_utils::dpbItemUpper(options.dpb_owner);
|
||||
if (userId.getUserName() != options.dpb_owner)
|
||||
{
|
||||
(Arg::Gds(isc_no_priv) << "IMPERSONATE USER" << "DATABASE" << filename).raise();
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
#ifdef WIN_NT
|
||||
guardDbInit.enter(); // Required to correctly expand name of just created database
|
||||
@ -7274,6 +7309,10 @@ void DatabaseOptions::get(const UCHAR* dpb, USHORT dpb_length, bool& invalid_cli
|
||||
dpb_upgrade_db = true;
|
||||
break;
|
||||
|
||||
case isc_dpb_owner:
|
||||
getString(rdr, dpb_owner);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@ -8543,13 +8582,12 @@ static VdnResult verifyDatabaseName(const PathName& name, FbStatusVector* status
|
||||
@param aliasName
|
||||
@param dbName
|
||||
@param config
|
||||
@param creating
|
||||
@param iAtt
|
||||
@param cryptCb
|
||||
|
||||
**/
|
||||
static void getUserInfo(UserId& user, const DatabaseOptions& options, const char* aliasName,
|
||||
const RefPtr<const Config>* config, bool creating, Mapping& mapping, bool icuReset)
|
||||
const RefPtr<const Config>* config, Mapping& mapping, bool icuReset)
|
||||
{
|
||||
bool wheel = false;
|
||||
int id = -1, group = -1; // CVC: This var contained trash
|
||||
@ -8580,12 +8618,6 @@ static void getUserInfo(UserId& user, const DatabaseOptions& options, const char
|
||||
|
||||
if (mapping.mapUser(name, trusted_role) & Mapping::MAP_DOWN)
|
||||
user.setFlag(USR_mapdown);
|
||||
|
||||
if (creating && config) // when config is NULL we are in error handler
|
||||
{
|
||||
if (!checkCreateDatabaseGrant(name, trusted_role, options.dpb_role_name, (*config)->getSecurityDatabase()))
|
||||
(Arg::Gds(isc_no_priv) << "CREATE" << "DATABASE" << aliasName).raise();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -47,7 +47,8 @@ enum pp_vals {
|
||||
PP_PAGE = 9,
|
||||
PP_SET = 10,
|
||||
PP_NAMES = 11,
|
||||
PP_ROLE = 12
|
||||
PP_ROLE = 12,
|
||||
PP_OWNER = 13
|
||||
};
|
||||
|
||||
|
||||
@ -76,6 +77,7 @@ static const pp_table pp_symbols[] =
|
||||
{"SET", PP_SET},
|
||||
{"NAMES", PP_NAMES},
|
||||
{"ROLE", PP_ROLE},
|
||||
{"OWNER", PP_OWNER},
|
||||
{"", 0}
|
||||
};
|
||||
|
||||
@ -310,6 +312,13 @@ bool PREPARSE_execute(CheckStatusWrapper* status, Why::YAttachment** ptrAtt,
|
||||
case PP_PAGES:
|
||||
matched = true;
|
||||
break;
|
||||
|
||||
case PP_OWNER:
|
||||
token = getToken(pos, tks);
|
||||
|
||||
dpb.insertString(isc_dpb_owner, token);
|
||||
matched = true;
|
||||
break;
|
||||
} // switch
|
||||
} // if
|
||||
} // for
|
||||
|
Loading…
Reference in New Issue
Block a user