mirror of
https://github.com/FirebirdSQL/firebird.git
synced 2025-01-23 02:03:04 +01:00
Fixed transactions support in user management commands
This commit is contained in:
parent
6419e52c2e
commit
40e2f7f892
@ -26,6 +26,8 @@
|
||||
#include "../jrd/common.h"
|
||||
#include "../jrd/jrd.h"
|
||||
#include "../jrd/jrd_pwd.h"
|
||||
#include "../jrd/tra.h"
|
||||
#include "../jrd/msg_encode.h"
|
||||
#include "../utilities/gsec/gsec.h"
|
||||
#include "../utilities/gsec/secur_proto.h"
|
||||
|
||||
@ -33,13 +35,13 @@ using namespace Jrd;
|
||||
using namespace Firebird;
|
||||
|
||||
|
||||
UserManagement::UserManagement(thread_db* tdbb)
|
||||
: database(0), transaction(0)
|
||||
UserManagement::UserManagement(jrd_tra* tra)
|
||||
: database(0), transaction(0), commands(*tra->tra_pool)
|
||||
{
|
||||
char securityDatabaseName[MAXPATHLEN];
|
||||
SecurityDatabase::getPath(securityDatabaseName);
|
||||
ISC_STATUS_ARRAY status;
|
||||
Attachment* att = tdbb->getAttachment();
|
||||
Attachment* att = tra->tra_attachment;
|
||||
|
||||
ClumpletWriter dpb(ClumpletReader::Tagged, MAX_DPB_SIZE, isc_dpb_version1);
|
||||
dpb.insertByte(isc_dpb_gsec_attach, TRUE);
|
||||
@ -61,22 +63,14 @@ UserManagement::UserManagement(thread_db* tdbb)
|
||||
}
|
||||
}
|
||||
|
||||
void UserManagement::commit()
|
||||
{
|
||||
ISC_STATUS_ARRAY status;
|
||||
if (transaction)
|
||||
{
|
||||
// Commit transaction in security database
|
||||
if (isc_commit_transaction(status, &transaction))
|
||||
{
|
||||
status_exception::raise(status);
|
||||
}
|
||||
transaction = 0;
|
||||
}
|
||||
}
|
||||
|
||||
UserManagement::~UserManagement()
|
||||
{
|
||||
for (ULONG i = 0; i < commands.getCount(); ++i)
|
||||
{
|
||||
delete commands[i];
|
||||
}
|
||||
commands.clear();
|
||||
|
||||
ISC_STATUS_ARRAY status;
|
||||
if (transaction)
|
||||
{
|
||||
@ -96,13 +90,72 @@ UserManagement::~UserManagement()
|
||||
}
|
||||
}
|
||||
|
||||
int UserManagement::execute(ISC_STATUS* status, internal_user_data* u)
|
||||
void UserManagement::commit()
|
||||
{
|
||||
ISC_STATUS_ARRAY status;
|
||||
if (transaction)
|
||||
{
|
||||
// Commit transaction in security database
|
||||
if (isc_commit_transaction(status, &transaction))
|
||||
{
|
||||
status_exception::raise(status);
|
||||
}
|
||||
transaction = 0;
|
||||
}
|
||||
}
|
||||
|
||||
USHORT UserManagement::put(internal_user_data* userData)
|
||||
{
|
||||
size_t ret = commands.getCount();
|
||||
if (ret > MAX_USHORT)
|
||||
{
|
||||
status_exception::raise(Arg::Gds(isc_random) << "Too many user management DDL per transaction)");
|
||||
}
|
||||
commands.push(userData);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void UserManagement::execute(USHORT id)
|
||||
{
|
||||
#if (defined BOOT_BUILD || defined EMBEDDED)
|
||||
status_exception::raise(Arg::Gds(isc_wish_list));
|
||||
return 0; // make the compiler happy
|
||||
#else
|
||||
return (!u->user_name_entered) ?
|
||||
GsecMsg18 : SECURITY_exec_line(status, database, transaction, u, NULL, NULL);
|
||||
if ((!transaction) || (!commands[id]))
|
||||
{
|
||||
// Already executed
|
||||
return;
|
||||
}
|
||||
|
||||
if (id >= commands.getCount())
|
||||
{
|
||||
status_exception::raise(Arg::Gds(isc_random) << "Wrong job id passed to UserManagement::execute()");
|
||||
}
|
||||
|
||||
ISC_STATUS_ARRAY status;
|
||||
int errcode = (!commands[id]->user_name_entered) ? GsecMsg18 :
|
||||
SECURITY_exec_line(status, database, transaction, commands[id], NULL, NULL);
|
||||
|
||||
switch (errcode)
|
||||
{
|
||||
case 0: // nothing
|
||||
break;
|
||||
case GsecMsg22:
|
||||
status_exception::raise(Arg::Gds(ENCODE_ISC_MSG(errcode, GSEC_MSG_FAC)) <<
|
||||
Arg::Str(commands[id]->user_name));
|
||||
default:
|
||||
status_exception::raise(Arg::Gds(ENCODE_ISC_MSG(errcode, GSEC_MSG_FAC)));
|
||||
}
|
||||
|
||||
delete commands[id];
|
||||
commands[id] = 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
UserManagement* jrd_tra::getUserManagement()
|
||||
{
|
||||
if (!tra_user_management)
|
||||
{
|
||||
tra_user_management = FB_NEW(*tra_pool) UserManagement(this);
|
||||
}
|
||||
return tra_user_management;
|
||||
}
|
||||
|
@ -24,6 +24,7 @@
|
||||
#define JRD_USER_MANAGEMENT_H
|
||||
|
||||
#include "firebird.h"
|
||||
#include "../common/classes/array.h"
|
||||
#include "../jrd/ibase.h"
|
||||
|
||||
struct internal_user_data;
|
||||
@ -31,20 +32,25 @@ struct internal_user_data;
|
||||
namespace Jrd {
|
||||
|
||||
class thread_db;
|
||||
class jrd_tra;
|
||||
|
||||
// User management argument for deferred work
|
||||
class UserManagement
|
||||
{
|
||||
public:
|
||||
explicit UserManagement(thread_db* tdbb);
|
||||
explicit UserManagement(jrd_tra* tra);
|
||||
~UserManagement();
|
||||
|
||||
// store userData for DFW-time processing
|
||||
USHORT put(internal_user_data* userData);
|
||||
// execute command with ID
|
||||
void execute(USHORT id);
|
||||
// commit transaction in security database
|
||||
void commit();
|
||||
|
||||
private:
|
||||
FB_API_HANDLE database, transaction;
|
||||
|
||||
public:
|
||||
int execute(ISC_STATUS* status, internal_user_data* u);
|
||||
void commit();
|
||||
Firebird::HalfStaticArray<internal_user_data*, 8> commands;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
@ -378,20 +378,12 @@ DeferredWork::~DeferredWork()
|
||||
{
|
||||
if (dfw_args)
|
||||
{
|
||||
if (dfw_type == dfw_user_management)
|
||||
DeferredWork* tmp = dfw_args;
|
||||
while (tmp)
|
||||
{
|
||||
UserManagement* sec = reinterpret_cast<UserManagement*>(dfw_args);
|
||||
delete sec;
|
||||
}
|
||||
else
|
||||
{
|
||||
DeferredWork* tmp = dfw_args;
|
||||
while (tmp)
|
||||
{
|
||||
DeferredWork* next = tmp->dfw_next;
|
||||
delete tmp;
|
||||
tmp = next;
|
||||
}
|
||||
DeferredWork* next = tmp->dfw_next;
|
||||
delete tmp;
|
||||
tmp = next;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1260,12 +1252,10 @@ static bool user_management(thread_db* tdbb,
|
||||
case 2:
|
||||
return true;
|
||||
case 3:
|
||||
// Commit
|
||||
sec = reinterpret_cast<UserManagement*>(work->dfw_args);
|
||||
if (sec)
|
||||
{
|
||||
sec->commit();
|
||||
}
|
||||
transaction->getUserManagement()->execute(work->dfw_id);
|
||||
return true;
|
||||
case 4:
|
||||
transaction->getUserManagement()->commit(); // safe to be called multiple times
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -5094,10 +5084,19 @@ static DeferredWork* post_work(jrd_tra* transaction,
|
||||
*ptr = FB_NEW(*transaction->tra_pool)
|
||||
DeferredWork(*transaction->tra_pool, type, id, sav_number, string, length);
|
||||
|
||||
if (type != dfw_post_event)
|
||||
switch (type)
|
||||
{
|
||||
case dfw_user_management:
|
||||
transaction->tra_flags |= TRA_deferred_meta;
|
||||
else if (transaction->tra_save_point)
|
||||
transaction->tra_save_point->sav_flags |= SAV_event_post;
|
||||
// fall down ...
|
||||
case dfw_post_event:
|
||||
if (transaction->tra_save_point)
|
||||
transaction->tra_save_point->sav_flags |= SAV_force_dfw;
|
||||
break;
|
||||
default:
|
||||
transaction->tra_flags |= TRA_deferred_meta;
|
||||
break;
|
||||
}
|
||||
|
||||
return *ptr;
|
||||
}
|
||||
|
@ -2292,15 +2292,7 @@ static void dyn_user(Global* gbl, const UCHAR** ptr)
|
||||
ISC_STATUS_ARRAY status;
|
||||
try
|
||||
{
|
||||
DeferredWork* work = DFW_post_work(tra, dfw_user_management, NULL, 0);
|
||||
UserManagement* sec = reinterpret_cast<UserManagement*>(work->dfw_args);
|
||||
if (!sec)
|
||||
{
|
||||
sec = FB_NEW(*tra->tra_pool) UserManagement(tdbb);
|
||||
work->dfw_args = reinterpret_cast<DeferredWork*>(sec);
|
||||
}
|
||||
|
||||
internal_user_data userData;
|
||||
internal_user_data* userData = FB_NEW(*tra->tra_pool) internal_user_data;
|
||||
UCHAR verb;
|
||||
while ((verb = *(*ptr)++) != isc_user_end)
|
||||
{
|
||||
@ -2311,23 +2303,23 @@ static void dyn_user(Global* gbl, const UCHAR** ptr)
|
||||
{
|
||||
case isc_dyn_user_add:
|
||||
text.upper();
|
||||
userData.operation = ADD_OPER;
|
||||
text.copyTo(userData.user_name, sizeof(userData.user_name));
|
||||
userData.user_name_entered = true;
|
||||
userData->operation = ADD_OPER;
|
||||
text.copyTo(userData->user_name, sizeof(userData->user_name));
|
||||
userData->user_name_entered = true;
|
||||
break;
|
||||
|
||||
case isc_dyn_user_mod:
|
||||
text.upper();
|
||||
userData.operation = MOD_OPER;
|
||||
text.copyTo(userData.user_name, sizeof(userData.user_name));
|
||||
userData.user_name_entered = true;
|
||||
userData->operation = MOD_OPER;
|
||||
text.copyTo(userData->user_name, sizeof(userData->user_name));
|
||||
userData->user_name_entered = true;
|
||||
break;
|
||||
|
||||
case isc_dyn_user_del:
|
||||
text.upper();
|
||||
userData.operation = DEL_OPER;
|
||||
text.copyTo(userData.user_name, sizeof(userData.user_name));
|
||||
userData.user_name_entered = true;
|
||||
userData->operation = DEL_OPER;
|
||||
text.copyTo(userData->user_name, sizeof(userData->user_name));
|
||||
userData->user_name_entered = true;
|
||||
break;
|
||||
|
||||
case isc_dyn_user_passwd:
|
||||
@ -2336,63 +2328,53 @@ static void dyn_user(Global* gbl, const UCHAR** ptr)
|
||||
// 249: Password should not be empty string
|
||||
status_exception::raise(Arg::Gds(ENCODE_ISC_MSG(249, DYN_MSG_FAC)));
|
||||
}
|
||||
text.copyTo(userData.password, sizeof(userData.password));
|
||||
userData.password_entered = true;
|
||||
text.copyTo(userData->password, sizeof(userData->password));
|
||||
userData->password_entered = true;
|
||||
break;
|
||||
|
||||
case isc_dyn_user_first:
|
||||
if (text.hasData())
|
||||
{
|
||||
text.copyTo(userData.first_name, sizeof(userData.first_name));
|
||||
userData.first_name_entered = true;
|
||||
text.copyTo(userData->first_name, sizeof(userData->first_name));
|
||||
userData->first_name_entered = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
userData.first_name_entered = false;
|
||||
userData.first_name_specified = true;
|
||||
userData->first_name_entered = false;
|
||||
userData->first_name_specified = true;
|
||||
}
|
||||
break;
|
||||
|
||||
case isc_dyn_user_middle:
|
||||
if (text.hasData())
|
||||
{
|
||||
text.copyTo(userData.middle_name, sizeof(userData.middle_name));
|
||||
userData.middle_name_entered = true;
|
||||
text.copyTo(userData->middle_name, sizeof(userData->middle_name));
|
||||
userData->middle_name_entered = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
userData.middle_name_entered = false;
|
||||
userData.middle_name_specified = true;
|
||||
userData->middle_name_entered = false;
|
||||
userData->middle_name_specified = true;
|
||||
}
|
||||
break;
|
||||
|
||||
case isc_dyn_user_last:
|
||||
if (text.hasData())
|
||||
{
|
||||
text.copyTo(userData.last_name, sizeof(userData.last_name));
|
||||
userData.last_name_entered = true;
|
||||
text.copyTo(userData->last_name, sizeof(userData->last_name));
|
||||
userData->last_name_entered = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
userData.last_name_entered = false;
|
||||
userData.last_name_specified = true;
|
||||
userData->last_name_entered = false;
|
||||
userData->last_name_specified = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
int errcode = sec->execute(status, &userData);
|
||||
|
||||
switch (errcode)
|
||||
{
|
||||
case 0: // nothing
|
||||
break;
|
||||
case GsecMsg22:
|
||||
status_exception::raise(Arg::Gds(ENCODE_ISC_MSG(errcode, GSEC_MSG_FAC)) <<
|
||||
Arg::Str(userData.user_name));
|
||||
default:
|
||||
status_exception::raise(Arg::Gds(ENCODE_ISC_MSG(errcode, GSEC_MSG_FAC)));
|
||||
}
|
||||
USHORT id = tra->getUserManagement()->put(userData);
|
||||
DeferredWork* work = DFW_post_work(tra, dfw_user_management, NULL, id);
|
||||
}
|
||||
catch (const Exception& e)
|
||||
{
|
||||
|
@ -3472,6 +3472,7 @@ jrd_tra::~jrd_tra()
|
||||
{
|
||||
delete tra_undo_record;
|
||||
delete tra_undo_space;
|
||||
delete tra_user_management;
|
||||
|
||||
if (!tra_outer)
|
||||
{
|
||||
|
@ -60,6 +60,8 @@ class ArrayField;
|
||||
class Attachment;
|
||||
class DeferredWork;
|
||||
class dsql_opn;
|
||||
class UserManagement;
|
||||
class thread_db;
|
||||
|
||||
// Blobs active in transaction identified by bli_temp_id. Please keep this
|
||||
// structure small as there can be huge amount of them floating in memory.
|
||||
@ -120,7 +122,8 @@ public:
|
||||
tra_transactions(*p),
|
||||
tra_blob_space(NULL),
|
||||
tra_undo_space(NULL),
|
||||
tra_undo_record(NULL)
|
||||
tra_undo_record(NULL),
|
||||
tra_user_management(NULL)
|
||||
{
|
||||
if (outer)
|
||||
{
|
||||
@ -212,6 +215,7 @@ private:
|
||||
TempSpace* tra_undo_space; // undo log storage
|
||||
|
||||
Record* tra_undo_record; // temporary record used for the undo purposes
|
||||
UserManagement* tra_user_management;
|
||||
|
||||
public:
|
||||
SSHORT getLockWait() const
|
||||
@ -250,6 +254,9 @@ public:
|
||||
|
||||
return tra_undo_record;
|
||||
}
|
||||
|
||||
// get UserManagement object for transaction, defined in UserManagement.cpp
|
||||
UserManagement* getUserManagement();
|
||||
};
|
||||
|
||||
// System transaction is always transaction 0.
|
||||
@ -327,7 +334,7 @@ public:
|
||||
/* Savepoint block flags. */
|
||||
|
||||
const int SAV_trans_level = 1; /* savepoint was started by TRA_start */
|
||||
const int SAV_event_post = 2; /* event posted in the save point */
|
||||
const int SAV_force_dfw = 2; /* DFW is present even if savepoint is empty */
|
||||
const int SAV_user = 4; /* named user savepoint as opposed to system ones */
|
||||
|
||||
/* Maximum size in bytes of transaction-level savepoint data.
|
||||
|
@ -2909,7 +2909,7 @@ void VIO_verb_cleanup(thread_db* tdbb, jrd_tra* transaction)
|
||||
|
||||
/* Cleanup/merge deferred work/event post */
|
||||
|
||||
if (sav_point->sav_verb_actions || (sav_point->sav_flags & SAV_event_post))
|
||||
if (sav_point->sav_verb_actions || (sav_point->sav_flags & SAV_force_dfw))
|
||||
{
|
||||
if (sav_point->sav_verb_count) {
|
||||
DFW_delete_deferred(transaction, sav_point->sav_number);
|
||||
@ -2923,13 +2923,13 @@ void VIO_verb_cleanup(thread_db* tdbb, jrd_tra* transaction)
|
||||
* not rolled back, set flag for the previous save point.
|
||||
*/
|
||||
|
||||
if (sav_point->sav_flags & SAV_event_post) {
|
||||
if (sav_point->sav_flags & SAV_force_dfw) {
|
||||
if (transaction->tra_save_point && !sav_point->sav_verb_count)
|
||||
{
|
||||
transaction->tra_save_point->sav_flags |= SAV_event_post;
|
||||
transaction->tra_save_point->sav_flags |= SAV_force_dfw;
|
||||
}
|
||||
|
||||
sav_point->sav_flags &= ~SAV_event_post;
|
||||
sav_point->sav_flags &= ~SAV_force_dfw;
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user