Skip to content

Commit b495b3f

Browse files
authored
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
1 parent a0ff6b9 commit b495b3f

File tree

11 files changed

+89
-21
lines changed

11 files changed

+89
-21
lines changed

doc/sql.extensions/README.ddl.txt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -618,3 +618,9 @@ ALTER PROCEDURE <name> SQL SECURITY {DEFINER | INVOKER} | DROP SQL SECURITY
618618
(Alexander Zhdanov)
619619

620620
ALTER PACKAGE <name> SQL SECURITY {DEFINER | INVOKER} | DROP SQL SECURITY
621+
622+
27) Added OWNER clause to CREATE DATABASE statement.
623+
(Dmitry Sibiryakov)
624+
625+
<db_initial_option> list is expanded by "OWNER username" clause which allows to set an owner user name for the created database.
626+
Only users with administrator rights can use this option.

doc/sql.extensions/README.isc_dpb_xxx

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
New Database Parameter Block items:
2+
3+
1. isc_dpb_owner :
4+
Used for createDatabase() call to set the owner for the new database
5+
to be different from user set with isc_user_name.
6+
Can be used only by users with admin rights.

src/common/IntlParametersBlock.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,7 @@ IntlParametersBlock::TagType IntlDpb::checkTag(UCHAR tag, const char** tagName)
194194
FB_IPB_TAG(isc_dpb_process_name);
195195
FB_IPB_TAG(isc_dpb_host_name);
196196
FB_IPB_TAG(isc_dpb_os_user);
197+
FB_IPB_TAG(isc_dpb_owner);
197198
return TAG_STRING;
198199
}
199200

src/common/ParserTokens.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -350,6 +350,7 @@ PARSER_TOKEN(TOK_OVER, "OVER", false)
350350
PARSER_TOKEN(TOK_OVERFLOW, "OVERFLOW", true)
351351
PARSER_TOKEN(TOK_OVERLAY, "OVERLAY", true)
352352
PARSER_TOKEN(TOK_OVERRIDING, "OVERRIDING", true)
353+
PARSER_TOKEN(TOK_OWNER, "OWNER", true)
353354
PARSER_TOKEN(TOK_PACKAGE, "PACKAGE", true)
354355
PARSER_TOKEN(TOK_PAD, "PAD", true)
355356
PARSER_TOKEN(TOK_PAGE, "PAGE", true)

src/dsql/parse.y

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -695,6 +695,7 @@ using namespace Firebird;
695695
%token <metaNamePtr> TIMEZONE_NAME
696696
%token <metaNamePtr> UNICODE_CHAR
697697
%token <metaNamePtr> UNICODE_VAL
698+
%token <metaNamePtr> OWNER
698699

699700
// tokens added for Firebird 6.0
700701

@@ -2155,6 +2156,8 @@ db_initial_option($alterDatabaseNode)
21552156
: PAGE_SIZE equals NUMBER32BIT
21562157
| USER symbol_user_name
21572158
| USER utf_string
2159+
| OWNER symbol_user_name
2160+
| OWNER utf_string
21582161
| ROLE valid_symbol_name
21592162
| ROLE utf_string
21602163
| PASSWORD utf_string
@@ -9464,6 +9467,7 @@ non_reserved_word
94649467
// added in FB 6.0
94659468
| ANY_VALUE
94669469
| FORMAT
9470+
| OWNER
94679471
;
94689472

94699473
%%

src/include/firebird/impl/consts_pub.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,7 @@
132132
#define isc_dpb_upgrade_db 97
133133
#define isc_dpb_parallel_workers 100
134134
#define isc_dpb_worker_attach 101
135+
#define isc_dpb_owner 102
135136

136137

137138
/**************************************************/

src/include/gen/Firebird.pas

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4044,6 +4044,7 @@ IProfilerStatsImpl = class(IProfilerStats)
40444044
isc_dpb_upgrade_db = byte(97);
40454045
isc_dpb_parallel_workers = byte(100);
40464046
isc_dpb_worker_attach = byte(101);
4047+
isc_dpb_owner = byte(102);
40474048
isc_dpb_address = byte(1);
40484049
isc_dpb_addr_protocol = byte(1);
40494050
isc_dpb_addr_endpoint = byte(2);

src/jrd/DbCreators.cpp

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -104,11 +104,11 @@ bool openDb(const char* securityDb, RefPtr<IAttachment>& att, RefPtr<ITransactio
104104

105105
namespace Jrd {
106106

107-
bool checkCreateDatabaseGrant(const MetaString& userName, const MetaString& trustedRole,
107+
CreateGrant checkCreateDatabaseGrant(const MetaString& userName, const MetaString& trustedRole,
108108
const MetaString& sqlRole, const char* securityDb)
109109
{
110110
if (userName == DBA_USER_NAME)
111-
return true;
111+
return CreateGrant::ASSUMED;
112112

113113
RefPtr<IAttachment> att;
114114
RefPtr<ITransaction> tra;
@@ -169,10 +169,10 @@ bool checkCreateDatabaseGrant(const MetaString& userName, const MetaString& trus
169169
role = trustedRole;
170170

171171
if (role == ADMIN_ROLE)
172-
return true;
172+
return CreateGrant::ASSUMED;
173173

174174
if (!hasDb)
175-
return false;
175+
return CreateGrant::NONE;
176176

177177
// check db creators table
178178
Message gr;
@@ -198,13 +198,13 @@ bool checkCreateDatabaseGrant(const MetaString& userName, const MetaString& trus
198198
{
199199
// isc_dsql_relation_err when exec SQL - i.e. table RDB$DB_CREATORS
200200
// is missing due to non-FB3 security DB
201-
return false;
201+
return CreateGrant::NONE;
202202
}
203203
check("IAttachment::execute", &st);
204204
}
205205

206206
if (cnt > 0)
207-
return true;
207+
return CreateGrant::GRANTED;
208208

209209
if (!role.hasData())
210210
role = "NONE";
@@ -247,7 +247,7 @@ bool checkCreateDatabaseGrant(const MetaString& userName, const MetaString& trus
247247

248248
check("IResultSet::fetchNext", &st);
249249

250-
return wrk.test(CREATE_DATABASE);
250+
return wrk.test(CREATE_DATABASE) ? CreateGrant::GRANTED : CreateGrant::NONE;
251251
}
252252

253253

src/jrd/DbCreators.h

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,14 @@
3636

3737
namespace Jrd {
3838

39-
bool checkCreateDatabaseGrant(const Firebird::MetaString& userName, const Firebird::MetaString& trustedRole,
39+
enum class CreateGrant
40+
{
41+
NONE, // This user cannot create databases
42+
GRANTED, // User was granted privilege to create database
43+
ASSUMED // User is admin and has all rights
44+
};
45+
46+
CreateGrant checkCreateDatabaseGrant(const Firebird::MetaString& userName, const Firebird::MetaString& trustedRole,
4047
const Firebird::MetaString& sqlRole, const char* securityDb);
4148

4249
class DbCreatorsScan: public VirtualTableScan

src/jrd/jrd.cpp

Lines changed: 44 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1111,6 +1111,7 @@ namespace Jrd
11111111
PathName dpb_set_bind;
11121112
string dpb_decfloat_round;
11131113
string dpb_decfloat_traps;
1114+
string dpb_owner;
11141115

11151116
public:
11161117
static const ULONG DPB_FLAGS_MASK = DBB_damaged;
@@ -1337,7 +1338,7 @@ static void start_transaction(thread_db* tdbb, bool transliterate, jrd_tra** tr
13371338
static void rollback(thread_db*, jrd_tra*, const bool);
13381339
static void purge_attachment(thread_db* tdbb, StableAttachmentPart* sAtt, unsigned flags = 0);
13391340
static void getUserInfo(UserId&, const DatabaseOptions&, const char*,
1340-
const RefPtr<const Config>*, bool, Mapping& mapping, bool);
1341+
const RefPtr<const Config>*, Mapping& mapping, bool);
13411342
static void waitForShutdown(Semaphore&);
13421343

13431344
static THREAD_ENTRY_DECLARE shutdown_thread(THREAD_ENTRY_PARAM);
@@ -1353,7 +1354,7 @@ TraceFailedConnection::TraceFailedConnection(const char* filename, const Databas
13531354
{
13541355
Mapping mapping(Mapping::MAP_ERROR_HANDLER, NULL);
13551356
mapping.setAuthBlock(m_options->dpb_auth_block);
1356-
getUserInfo(m_id, *m_options, m_filename, NULL, false, mapping, false);
1357+
getUserInfo(m_id, *m_options, m_filename, NULL, mapping, false);
13571358
}
13581359

13591360

@@ -1949,7 +1950,7 @@ JAttachment* JProvider::internalAttach(CheckStatusWrapper* user_status, const ch
19491950
try
19501951
{
19511952
mapping.setDb(filename, expanded_name.c_str(), jAtt);
1952-
getUserInfo(userId, options, filename, &config, false, mapping, options.dpb_reset_icu);
1953+
getUserInfo(userId, options, filename, &config, mapping, options.dpb_reset_icu);
19531954
}
19541955
catch(const Exception&)
19551956
{
@@ -2847,7 +2848,41 @@ JAttachment* JProvider::createDatabase(CheckStatusWrapper* user_status, const ch
28472848

28482849
// Check for correct credentials supplied
28492850
mapping.setSecurityDbAlias(config->getSecurityDatabase(), nullptr);
2850-
getUserInfo(userId, options, filename, &config, true, mapping, false);
2851+
getUserInfo(userId, options, filename, &config, mapping, false);
2852+
2853+
// Check user's power level
2854+
CreateGrant powerLevel = CreateGrant::ASSUMED; // By default it is a boot build or embedded mode where everything is allowed
2855+
if (options.dpb_auth_block.hasData())
2856+
{
2857+
powerLevel = checkCreateDatabaseGrant(userId.getUserName(), userId.getTrustedRole(), userId.getSqlRole(), config->getSecurityDatabase());
2858+
}
2859+
2860+
switch (powerLevel)
2861+
{
2862+
case CreateGrant::NONE:
2863+
(Arg::Gds(isc_no_priv) << "CREATE" << "DATABASE" << filename).raise();
2864+
2865+
case CreateGrant::ASSUMED:
2866+
if (options.dpb_owner.hasData())
2867+
{
2868+
// Superuser can create databases for anyone other
2869+
fb_utils::dpbItemUpper(options.dpb_owner);
2870+
userId.setUserName(options.dpb_owner);
2871+
}
2872+
break;
2873+
2874+
case CreateGrant::GRANTED:
2875+
if (options.dpb_owner.hasData())
2876+
{
2877+
// Superuser can create databases for anyone other
2878+
fb_utils::dpbItemUpper(options.dpb_owner);
2879+
if (userId.getUserName() != options.dpb_owner)
2880+
{
2881+
(Arg::Gds(isc_no_priv) << "IMPERSONATE USER" << "DATABASE" << filename).raise();
2882+
}
2883+
}
2884+
break;
2885+
}
28512886

28522887
#ifdef WIN_NT
28532888
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
72747309
dpb_upgrade_db = true;
72757310
break;
72767311

7312+
case isc_dpb_owner:
7313+
getString(rdr, dpb_owner);
7314+
break;
7315+
72777316
default:
72787317
break;
72797318
}
@@ -8543,13 +8582,12 @@ static VdnResult verifyDatabaseName(const PathName& name, FbStatusVector* status
85438582
@param aliasName
85448583
@param dbName
85458584
@param config
8546-
@param creating
85478585
@param iAtt
85488586
@param cryptCb
85498587
85508588
**/
85518589
static void getUserInfo(UserId& user, const DatabaseOptions& options, const char* aliasName,
8552-
const RefPtr<const Config>* config, bool creating, Mapping& mapping, bool icuReset)
8590+
const RefPtr<const Config>* config, Mapping& mapping, bool icuReset)
85538591
{
85548592
bool wheel = false;
85558593
int id = -1, group = -1; // CVC: This var contained trash
@@ -8580,12 +8618,6 @@ static void getUserInfo(UserId& user, const DatabaseOptions& options, const char
85808618

85818619
if (mapping.mapUser(name, trusted_role) & Mapping::MAP_DOWN)
85828620
user.setFlag(USR_mapdown);
8583-
8584-
if (creating && config) // when config is NULL we are in error handler
8585-
{
8586-
if (!checkCreateDatabaseGrant(name, trusted_role, options.dpb_role_name, (*config)->getSecurityDatabase()))
8587-
(Arg::Gds(isc_no_priv) << "CREATE" << "DATABASE" << aliasName).raise();
8588-
}
85898621
}
85908622
else
85918623
{

0 commit comments

Comments
 (0)