mirror of
https://github.com/FirebirdSQL/firebird.git
synced 2025-01-22 16: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)
|
(Alexander Zhdanov)
|
||||||
|
|
||||||
ALTER PACKAGE <name> SQL SECURITY {DEFINER | INVOKER} | DROP SQL SECURITY
|
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_process_name);
|
||||||
FB_IPB_TAG(isc_dpb_host_name);
|
FB_IPB_TAG(isc_dpb_host_name);
|
||||||
FB_IPB_TAG(isc_dpb_os_user);
|
FB_IPB_TAG(isc_dpb_os_user);
|
||||||
|
FB_IPB_TAG(isc_dpb_owner);
|
||||||
return TAG_STRING;
|
return TAG_STRING;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -350,6 +350,7 @@ PARSER_TOKEN(TOK_OVER, "OVER", false)
|
|||||||
PARSER_TOKEN(TOK_OVERFLOW, "OVERFLOW", true)
|
PARSER_TOKEN(TOK_OVERFLOW, "OVERFLOW", true)
|
||||||
PARSER_TOKEN(TOK_OVERLAY, "OVERLAY", true)
|
PARSER_TOKEN(TOK_OVERLAY, "OVERLAY", true)
|
||||||
PARSER_TOKEN(TOK_OVERRIDING, "OVERRIDING", true)
|
PARSER_TOKEN(TOK_OVERRIDING, "OVERRIDING", true)
|
||||||
|
PARSER_TOKEN(TOK_OWNER, "OWNER", true)
|
||||||
PARSER_TOKEN(TOK_PACKAGE, "PACKAGE", true)
|
PARSER_TOKEN(TOK_PACKAGE, "PACKAGE", true)
|
||||||
PARSER_TOKEN(TOK_PAD, "PAD", true)
|
PARSER_TOKEN(TOK_PAD, "PAD", true)
|
||||||
PARSER_TOKEN(TOK_PAGE, "PAGE", true)
|
PARSER_TOKEN(TOK_PAGE, "PAGE", true)
|
||||||
|
@ -695,6 +695,7 @@ using namespace Firebird;
|
|||||||
%token <metaNamePtr> TIMEZONE_NAME
|
%token <metaNamePtr> TIMEZONE_NAME
|
||||||
%token <metaNamePtr> UNICODE_CHAR
|
%token <metaNamePtr> UNICODE_CHAR
|
||||||
%token <metaNamePtr> UNICODE_VAL
|
%token <metaNamePtr> UNICODE_VAL
|
||||||
|
%token <metaNamePtr> OWNER
|
||||||
|
|
||||||
// tokens added for Firebird 6.0
|
// tokens added for Firebird 6.0
|
||||||
|
|
||||||
@ -2155,6 +2156,8 @@ db_initial_option($alterDatabaseNode)
|
|||||||
: PAGE_SIZE equals NUMBER32BIT
|
: PAGE_SIZE equals NUMBER32BIT
|
||||||
| USER symbol_user_name
|
| USER symbol_user_name
|
||||||
| USER utf_string
|
| USER utf_string
|
||||||
|
| OWNER symbol_user_name
|
||||||
|
| OWNER utf_string
|
||||||
| ROLE valid_symbol_name
|
| ROLE valid_symbol_name
|
||||||
| ROLE utf_string
|
| ROLE utf_string
|
||||||
| PASSWORD utf_string
|
| PASSWORD utf_string
|
||||||
@ -9464,6 +9467,7 @@ non_reserved_word
|
|||||||
// added in FB 6.0
|
// added in FB 6.0
|
||||||
| ANY_VALUE
|
| ANY_VALUE
|
||||||
| FORMAT
|
| FORMAT
|
||||||
|
| OWNER
|
||||||
;
|
;
|
||||||
|
|
||||||
%%
|
%%
|
||||||
|
@ -132,6 +132,7 @@
|
|||||||
#define isc_dpb_upgrade_db 97
|
#define isc_dpb_upgrade_db 97
|
||||||
#define isc_dpb_parallel_workers 100
|
#define isc_dpb_parallel_workers 100
|
||||||
#define isc_dpb_worker_attach 101
|
#define isc_dpb_worker_attach 101
|
||||||
|
#define isc_dpb_owner 102
|
||||||
|
|
||||||
|
|
||||||
/**************************************************/
|
/**************************************************/
|
||||||
|
@ -4044,6 +4044,7 @@ const
|
|||||||
isc_dpb_upgrade_db = byte(97);
|
isc_dpb_upgrade_db = byte(97);
|
||||||
isc_dpb_parallel_workers = byte(100);
|
isc_dpb_parallel_workers = byte(100);
|
||||||
isc_dpb_worker_attach = byte(101);
|
isc_dpb_worker_attach = byte(101);
|
||||||
|
isc_dpb_owner = byte(102);
|
||||||
isc_dpb_address = byte(1);
|
isc_dpb_address = byte(1);
|
||||||
isc_dpb_addr_protocol = byte(1);
|
isc_dpb_addr_protocol = byte(1);
|
||||||
isc_dpb_addr_endpoint = byte(2);
|
isc_dpb_addr_endpoint = byte(2);
|
||||||
|
@ -104,11 +104,11 @@ bool openDb(const char* securityDb, RefPtr<IAttachment>& att, RefPtr<ITransactio
|
|||||||
|
|
||||||
namespace Jrd {
|
namespace Jrd {
|
||||||
|
|
||||||
bool checkCreateDatabaseGrant(const MetaString& userName, const MetaString& trustedRole,
|
CreateGrant checkCreateDatabaseGrant(const MetaString& userName, const MetaString& trustedRole,
|
||||||
const MetaString& sqlRole, const char* securityDb)
|
const MetaString& sqlRole, const char* securityDb)
|
||||||
{
|
{
|
||||||
if (userName == DBA_USER_NAME)
|
if (userName == DBA_USER_NAME)
|
||||||
return true;
|
return CreateGrant::ASSUMED;
|
||||||
|
|
||||||
RefPtr<IAttachment> att;
|
RefPtr<IAttachment> att;
|
||||||
RefPtr<ITransaction> tra;
|
RefPtr<ITransaction> tra;
|
||||||
@ -169,10 +169,10 @@ bool checkCreateDatabaseGrant(const MetaString& userName, const MetaString& trus
|
|||||||
role = trustedRole;
|
role = trustedRole;
|
||||||
|
|
||||||
if (role == ADMIN_ROLE)
|
if (role == ADMIN_ROLE)
|
||||||
return true;
|
return CreateGrant::ASSUMED;
|
||||||
|
|
||||||
if (!hasDb)
|
if (!hasDb)
|
||||||
return false;
|
return CreateGrant::NONE;
|
||||||
|
|
||||||
// check db creators table
|
// check db creators table
|
||||||
Message gr;
|
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
|
// isc_dsql_relation_err when exec SQL - i.e. table RDB$DB_CREATORS
|
||||||
// is missing due to non-FB3 security DB
|
// is missing due to non-FB3 security DB
|
||||||
return false;
|
return CreateGrant::NONE;
|
||||||
}
|
}
|
||||||
check("IAttachment::execute", &st);
|
check("IAttachment::execute", &st);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cnt > 0)
|
if (cnt > 0)
|
||||||
return true;
|
return CreateGrant::GRANTED;
|
||||||
|
|
||||||
if (!role.hasData())
|
if (!role.hasData())
|
||||||
role = "NONE";
|
role = "NONE";
|
||||||
@ -247,7 +247,7 @@ bool checkCreateDatabaseGrant(const MetaString& userName, const MetaString& trus
|
|||||||
|
|
||||||
check("IResultSet::fetchNext", &st);
|
check("IResultSet::fetchNext", &st);
|
||||||
|
|
||||||
return wrk.test(CREATE_DATABASE);
|
return wrk.test(CREATE_DATABASE) ? CreateGrant::GRANTED : CreateGrant::NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -36,7 +36,14 @@
|
|||||||
|
|
||||||
namespace Jrd {
|
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);
|
const Firebird::MetaString& sqlRole, const char* securityDb);
|
||||||
|
|
||||||
class DbCreatorsScan: public VirtualTableScan
|
class DbCreatorsScan: public VirtualTableScan
|
||||||
|
@ -1111,6 +1111,7 @@ namespace Jrd
|
|||||||
PathName dpb_set_bind;
|
PathName dpb_set_bind;
|
||||||
string dpb_decfloat_round;
|
string dpb_decfloat_round;
|
||||||
string dpb_decfloat_traps;
|
string dpb_decfloat_traps;
|
||||||
|
string dpb_owner;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static const ULONG DPB_FLAGS_MASK = DBB_damaged;
|
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 rollback(thread_db*, jrd_tra*, const bool);
|
||||||
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*,
|
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 void waitForShutdown(Semaphore&);
|
||||||
|
|
||||||
static THREAD_ENTRY_DECLARE shutdown_thread(THREAD_ENTRY_PARAM);
|
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 mapping(Mapping::MAP_ERROR_HANDLER, NULL);
|
||||||
mapping.setAuthBlock(m_options->dpb_auth_block);
|
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
|
try
|
||||||
{
|
{
|
||||||
mapping.setDb(filename, expanded_name.c_str(), jAtt);
|
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&)
|
catch(const Exception&)
|
||||||
{
|
{
|
||||||
@ -2847,7 +2848,41 @@ JAttachment* JProvider::createDatabase(CheckStatusWrapper* user_status, const ch
|
|||||||
|
|
||||||
// Check for correct credentials supplied
|
// Check for correct credentials supplied
|
||||||
mapping.setSecurityDbAlias(config->getSecurityDatabase(), nullptr);
|
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
|
#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
|
||||||
@ -7274,6 +7309,10 @@ void DatabaseOptions::get(const UCHAR* dpb, USHORT dpb_length, bool& invalid_cli
|
|||||||
dpb_upgrade_db = true;
|
dpb_upgrade_db = true;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case isc_dpb_owner:
|
||||||
|
getString(rdr, dpb_owner);
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -8543,13 +8582,12 @@ static VdnResult verifyDatabaseName(const PathName& name, FbStatusVector* status
|
|||||||
@param aliasName
|
@param aliasName
|
||||||
@param dbName
|
@param dbName
|
||||||
@param config
|
@param config
|
||||||
@param creating
|
|
||||||
@param iAtt
|
@param iAtt
|
||||||
@param cryptCb
|
@param cryptCb
|
||||||
|
|
||||||
**/
|
**/
|
||||||
static void getUserInfo(UserId& user, const DatabaseOptions& options, const char* aliasName,
|
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;
|
bool wheel = false;
|
||||||
int id = -1, group = -1; // CVC: This var contained trash
|
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)
|
if (mapping.mapUser(name, trusted_role) & Mapping::MAP_DOWN)
|
||||||
user.setFlag(USR_mapdown);
|
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
|
else
|
||||||
{
|
{
|
||||||
|
@ -47,7 +47,8 @@ enum pp_vals {
|
|||||||
PP_PAGE = 9,
|
PP_PAGE = 9,
|
||||||
PP_SET = 10,
|
PP_SET = 10,
|
||||||
PP_NAMES = 11,
|
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},
|
{"SET", PP_SET},
|
||||||
{"NAMES", PP_NAMES},
|
{"NAMES", PP_NAMES},
|
||||||
{"ROLE", PP_ROLE},
|
{"ROLE", PP_ROLE},
|
||||||
|
{"OWNER", PP_OWNER},
|
||||||
{"", 0}
|
{"", 0}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -310,6 +312,13 @@ bool PREPARSE_execute(CheckStatusWrapper* status, Why::YAttachment** ptrAtt,
|
|||||||
case PP_PAGES:
|
case PP_PAGES:
|
||||||
matched = true;
|
matched = true;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case PP_OWNER:
|
||||||
|
token = getToken(pos, tks);
|
||||||
|
|
||||||
|
dpb.insertString(isc_dpb_owner, token);
|
||||||
|
matched = true;
|
||||||
|
break;
|
||||||
} // switch
|
} // switch
|
||||||
} // if
|
} // if
|
||||||
} // for
|
} // for
|
||||||
|
Loading…
Reference in New Issue
Block a user