From: <ale...@us...> - 2010-07-09 12:51:12
|
Revision: 51322 http://firebird.svn.sourceforge.net/firebird/?rev=51322&view=rev Author: alexpeshkoff Date: 2010-07-09 12:51:05 +0000 (Fri, 09 Jul 2010) Log Message: ----------- ODS change: made RDB$USERS system table, added virtual table SEC$USERS Modified Paths: -------------- firebird/trunk/builds/posix/Makefile.in.firebird firebird/trunk/builds/posix/make.shared.variables firebird/trunk/src/dbs/security.sql firebird/trunk/src/include/gen/ids.h firebird/trunk/src/jrd/DatabaseSnapshot.cpp firebird/trunk/src/jrd/DatabaseSnapshot.h firebird/trunk/src/jrd/Relation.h firebird/trunk/src/jrd/UserManagement.cpp firebird/trunk/src/jrd/UserManagement.h firebird/trunk/src/jrd/constants.h firebird/trunk/src/jrd/fields.h firebird/trunk/src/jrd/idx.h firebird/trunk/src/jrd/ini.epp firebird/trunk/src/jrd/met.epp firebird/trunk/src/jrd/names.h firebird/trunk/src/jrd/opt.cpp firebird/trunk/src/jrd/recsrc/RecordSource.h firebird/trunk/src/jrd/relations.h firebird/trunk/src/jrd/svc.cpp firebird/trunk/src/jrd/types.h firebird/trunk/src/msgs/facilities2.sql firebird/trunk/src/msgs/messages2.sql firebird/trunk/src/utilities/gsec/gsec.cpp firebird/trunk/src/utilities/gsec/gsec.h firebird/trunk/src/utilities/gsec/gsecswi.h firebird/trunk/src/utilities/gsec/secur_proto.h firebird/trunk/src/utilities/gsec/security.epp Added Paths: ----------- firebird/trunk/src/jrd/recsrc/UsersTableScan.cpp Modified: firebird/trunk/builds/posix/Makefile.in.firebird =================================================================== --- firebird/trunk/builds/posix/Makefile.in.firebird 2010-07-09 11:33:28 UTC (rev 51321) +++ firebird/trunk/builds/posix/Makefile.in.firebird 2010-07-09 12:51:05 UTC (rev 51322) @@ -76,9 +76,7 @@ # use the static files as a last resort. # # The bootstrap version of gpre (gpre_boot) is used to build all the -# engine files, except security.bin. security.epp requires the security -# database which is not available at this time. The code in jrd/alt.cpp -# that references the functions in security.bin has been #ifdef'ed out. +# engine file. # During this phase of the build process the limited version of alt.bin # is used. The full version of alt.bin is compiled later in the build # process after the security database is available. After the Modified: firebird/trunk/builds/posix/make.shared.variables =================================================================== --- firebird/trunk/builds/posix/make.shared.variables 2010-07-09 11:33:28 UTC (rev 51321) +++ firebird/trunk/builds/posix/make.shared.variables 2010-07-09 12:51:05 UTC (rev 51322) @@ -53,7 +53,7 @@ recsrc/MergeJoin.cpp recsrc/NestedLoopJoin.cpp \ recsrc/ProcedureScan.cpp recsrc/RecordSource.cpp recsrc/RecursiveStream.cpp \ recsrc/SingularStream.cpp recsrc/SkipRowsStream.cpp recsrc/SortedStream.cpp recsrc/Union.cpp \ - recsrc/VirtualTableScan.cpp recsrc/WindowedStream.cpp + recsrc/VirtualTableScan.cpp recsrc/UsersTableScan.cpp recsrc/WindowedStream.cpp JRD_ServerSources = $(addprefix jrd/, $(JRD_ServerFiles)) JRD_ServerSources += gpre/pretty.cpp @@ -357,7 +357,7 @@ # MOD 29-July-2002 # Stub for services entrypoints missing in static library -STUB_Sources = jrd/svc_stub.cpp +STUB_Sources = jrd/svc_stub.cpp utilities/gsec/security.epp STUB_Objects = $(addprefix $(OBJ)/, $(addsuffix .o, $(basename $(STUB_Sources)))) Modified: firebird/trunk/src/dbs/security.sql =================================================================== --- firebird/trunk/src/dbs/security.sql 2010-07-09 11:33:28 UTC (rev 51321) +++ firebird/trunk/src/dbs/security.sql 2010-07-09 12:51:05 UTC (rev 51322) @@ -22,57 +22,6 @@ * (see http://www.volny.cz/iprenosil/interbase/ for details). */ -/* Domain definitions */ -CREATE DOMAIN RDB$COMMENT AS BLOB SUB_TYPE TEXT SEGMENT SIZE 80 CHARACTER SET UNICODE_FSS; -CREATE DOMAIN RDB$NAME_PART AS VARCHAR(32) CHARACTER SET UNICODE_FSS DEFAULT _UNICODE_FSS ''; -CREATE DOMAIN RDB$GID AS INTEGER; -CREATE DOMAIN RDB$PASSWD AS VARCHAR(64) CHARACTER SET BINARY; -CREATE DOMAIN RDB$UID AS INTEGER; -CREATE DOMAIN RDB$USER_NAME AS VARCHAR(128) CHARACTER SET UNICODE_FSS; -CREATE DOMAIN RDB$USER_PRIVILEGE AS INTEGER; - - -/* Table: RDB$USERS */ -CREATE TABLE RDB$USERS ( - RDB$USER_NAME RDB$USER_NAME NOT NULL PRIMARY KEY, - /* local system user name for setuid for file permissions */ - RDB$SYS_USER_NAME RDB$USER_NAME, - RDB$GROUP_NAME RDB$USER_NAME, - RDB$UID RDB$UID, - RDB$GID RDB$GID, - RDB$PASSWD RDB$PASSWD NOT NULL, - - /* Privilege level of user - mark a user as having DBA privilege */ - RDB$PRIVILEGE RDB$USER_PRIVILEGE, - - RDB$COMMENT RDB$COMMENT, - RDB$FIRST_NAME RDB$NAME_PART, - RDB$MIDDLE_NAME RDB$NAME_PART, - RDB$LAST_NAME RDB$NAME_PART); - -COMMIT; - -/* View: USERS. Let's user modify his own password. */ -CREATE VIEW USERS (USER_NAME, SYS_USER_NAME, GROUP_NAME, UID, GID, PASSWD, - PRIVILEGE, COMMENT, FIRST_NAME, MIDDLE_NAME, LAST_NAME, FULL_NAME) AS - SELECT RDB$USER_NAME, RDB$SYS_USER_NAME, RDB$GROUP_NAME, RDB$UID, RDB$GID, RDB$PASSWD, - RDB$PRIVILEGE, RDB$COMMENT, RDB$FIRST_NAME, RDB$MIDDLE_NAME, RDB$LAST_NAME, - COALESCE (RDB$first_name || _UNICODE_FSS ' ', '') || - COALESCE (RDB$middle_name || _UNICODE_FSS ' ', '') || - COALESCE (RDB$last_name, '') - FROM RDB$USERS - WHERE CURRENT_USER = 'SYSDBA' - OR CURRENT_ROLE = 'RDB$ADMIN' - OR CURRENT_USER = RDB$USERS.RDB$USER_NAME; - -/* Access rights */ -GRANT ALL ON RDB$USERS to VIEW USERS; -GRANT SELECT ON USERS to PUBLIC; -GRANT UPDATE(PASSWD, GROUP_NAME, UID, GID, FIRST_NAME, MIDDLE_NAME, LAST_NAME) - ON USERS TO PUBLIC; - -COMMIT; - /* Needed record - with PASSWD = random + SHA1 (random + 'SYSDBA' + crypt('masterke')) */ INSERT INTO RDB$USERS(RDB$USER_NAME, RDB$PASSWD, RDB$FIRST_NAME, RDB$MIDDLE_NAME, RDB$LAST_NAME) VALUES ('SYSDBA', 'NLtwcs9LrxLMOYhG0uGM9i6KS7mf3QAKvFVpmRg=', 'Sql', 'Server', 'Administrator'); Modified: firebird/trunk/src/include/gen/ids.h =================================================================== --- firebird/trunk/src/include/gen/ids.h 2010-07-09 11:33:28 UTC (rev 51321) +++ firebird/trunk/src/include/gen/ids.h 2010-07-09 12:51:05 UTC (rev 51322) @@ -592,3 +592,28 @@ const USHORT f_pkg_desc = 6; +// Relation 43 (RDB$USERS) + + const USHORT f_user_name = 0; + const USHORT f_group_name = 1; + const USHORT f_uid = 2; + const USHORT f_gid = 3; + const USHORT f_passwd_type = 4; + const USHORT f_passwd = 5; + const USHORT f_first_name = 6; + const USHORT f_middle_name = 7; + const USHORT f_last_name = 8; + const USHORT f_user_desc = 9; + + +// Relation 44 (SEC$USERS) + + const USHORT f_sec_user_name = 0; + const USHORT f_sec_group_name = 1; + const USHORT f_sec_uid = 2; + const USHORT f_sec_gid = 3; + const USHORT f_sec_first_name = 4; + const USHORT f_sec_middle_name = 5; + const USHORT f_sec_last_name = 6; + + Modified: firebird/trunk/src/jrd/DatabaseSnapshot.cpp =================================================================== --- firebird/trunk/src/jrd/DatabaseSnapshot.cpp 2010-07-09 11:33:28 UTC (rev 51321) +++ firebird/trunk/src/jrd/DatabaseSnapshot.cpp 2010-07-09 12:51:05 UTC (rev 51322) @@ -370,7 +370,7 @@ DatabaseSnapshot::DatabaseSnapshot(thread_db* tdbb, MemoryPool& pool) - : snapshot(pool), idMap(pool), idCounter(0) + : DataDump(pool), snapshot(pool) { SET_TDBB(tdbb); @@ -589,7 +589,7 @@ jrd_rel* relation = MET_lookup_relation_id(tdbb, rel_id, false); fb_assert(relation); MET_scan_relation(tdbb, relation); - fb_assert(relation->isVirtual()); + fb_assert(relation->isVirtual() && !relation->isUsers()); Format* format = MET_current(tdbb, relation); fb_assert(format); @@ -601,7 +601,7 @@ } -void DatabaseSnapshot::clearRecord(Record* record) +void DataDump::clearRecord(Record* record) { fb_assert(record); @@ -612,7 +612,7 @@ } -void DatabaseSnapshot::putField(thread_db* tdbb, Record* record, const DumpField& field, +void DataDump::putField(thread_db* tdbb, Record* record, const DumpField& field, int& charset, bool set_charset) { fb_assert(record); Modified: firebird/trunk/src/jrd/DatabaseSnapshot.h =================================================================== --- firebird/trunk/src/jrd/DatabaseSnapshot.h 2010-07-09 11:33:28 UTC (rev 51321) +++ firebird/trunk/src/jrd/DatabaseSnapshot.h 2010-07-09 12:51:05 UTC (rev 51322) @@ -18,6 +18,7 @@ * * All Rights Reserved. * Contributor(s): ______________________________________. + * Alex Peshkoff, 2010 - divided into class DataDump and the remaining part of DatabaseSnapshot */ #ifndef JRD_DATABASE_SNAPSHOT_H @@ -26,24 +27,36 @@ #include "../common/classes/array.h" #include "../common/classes/init.h" #include "../jrd/isc_s_proto.h" +#include "../common/classes/timestamp.h" +#include "../jrd/val.h" namespace Jrd { // forward declarations class jrd_rel; +class Record; class RecordBuffer; class RuntimeStatistics; -class DatabaseSnapshot +class DataDump { +public: enum ValueType {VALUE_GLOBAL_ID, VALUE_INTEGER, VALUE_TIMESTAMP, VALUE_STRING}; + DataDump(MemoryPool& pool) + : idMap(pool), idCounter(0) { } + struct DumpField { + DumpField(USHORT p_id, ValueType p_type, USHORT p_length, const void* p_data) + : id(p_id), type(p_type), length(p_length), data(p_data) { } + DumpField() + : id(0), type(VALUE_GLOBAL_ID), length(0), data(NULL) { } + USHORT id; ValueType type; USHORT length; - void* data; + const void* data; }; class DumpRecord @@ -178,6 +191,16 @@ ULONG sizeLimit; }; + void clearRecord(Record*); + void putField(thread_db*, Record*, const DumpField&, int&, bool = false); + +private: + Firebird::GenericMap<Firebird::Pair<Firebird::NonPooled<SINT64, SLONG> > > idMap; + int idCounter; +}; + +class DatabaseSnapshot : public DataDump +{ struct RelationData { int rel_id; @@ -321,8 +344,6 @@ private: RecordBuffer* allocBuffer(thread_db*, MemoryPool&, int); - void clearRecord(Record*); - void putField(thread_db*, Record*, const DumpField&, int&, bool = false); static void dumpData(thread_db*); @@ -338,8 +359,6 @@ static void putMemoryUsage(const Firebird::MemoryStats&, Writer&, int, int); Firebird::Array<RelationData> snapshot; - Firebird::GenericMap<Firebird::Pair<Firebird::NonPooled<SINT64, SLONG> > > idMap; - int idCounter; }; } // namespace Modified: firebird/trunk/src/jrd/Relation.h =================================================================== --- firebird/trunk/src/jrd/Relation.h 2010-07-09 11:33:28 UTC (rev 51321) +++ firebird/trunk/src/jrd/Relation.h 2010-07-09 12:51:05 UTC (rev 51322) @@ -176,8 +176,8 @@ { public: USHORT rel_id; - USHORT rel_flags; USHORT rel_current_fmt; // Current format number + ULONG rel_flags; Format* rel_current_format; // Current record format Firebird::MetaName rel_name; // ascii relation name vec<Format*>* rel_formats; // Known record formats @@ -219,6 +219,7 @@ bool isSystem() const; bool isTemporary() const; bool isVirtual() const; + bool isUsers() const; // global temporary relations attributes RelationPages* getPages(thread_db* tdbb, SLONG tran = -1, bool allocPages = true); @@ -282,22 +283,23 @@ // rel_flags -const USHORT REL_scanned = 0x0001; // Field expressions scanned (or being scanned) -const USHORT REL_system = 0x0002; -const USHORT REL_deleted = 0x0004; // Relation known gonzo -const USHORT REL_get_dependencies = 0x0008; // New relation needs dependencies during scan -const USHORT REL_force_scan = 0x0010; // system relation has been updated since ODS change, force a scan -const USHORT REL_check_existence = 0x0020; // Existence lock released pending drop of relation -const USHORT REL_blocking = 0x0040; // Blocking someone from dropping relation -const USHORT REL_sys_triggers = 0x0080; // The relation has system triggers to compile -const USHORT REL_sql_relation = 0x0100; // Relation defined as sql table -const USHORT REL_check_partners = 0x0200; // Rescan primary dependencies and foreign references -const USHORT REL_being_scanned = 0x0400; // relation scan in progress -const USHORT REL_sys_trigs_being_loaded = 0x0800; // System triggers being loaded -const USHORT REL_deleting = 0x1000; // relation delete in progress -const USHORT REL_temp_tran = 0x2000; // relation is a GTT delete rows -const USHORT REL_temp_conn = 0x4000; // relation is a GTT preserve rows -const USHORT REL_virtual = 0x8000; // relation is virtual +const ULONG REL_scanned = 0x0001; // Field expressions scanned (or being scanned) +const ULONG REL_system = 0x0002; +const ULONG REL_deleted = 0x0004; // Relation known gonzo +const ULONG REL_get_dependencies = 0x0008; // New relation needs dependencies during scan +const ULONG REL_force_scan = 0x0010; // system relation has been updated since ODS change, force a scan +const ULONG REL_check_existence = 0x0020; // Existence lock released pending drop of relation +const ULONG REL_blocking = 0x0040; // Blocking someone from dropping relation +const ULONG REL_sys_triggers = 0x0080; // The relation has system triggers to compile +const ULONG REL_sql_relation = 0x0100; // Relation defined as sql table +const ULONG REL_check_partners = 0x0200; // Rescan primary dependencies and foreign references +const ULONG REL_being_scanned = 0x0400; // relation scan in progress +const ULONG REL_sys_trigs_being_loaded = 0x0800; // System triggers being loaded +const ULONG REL_deleting = 0x1000; // relation delete in progress +const ULONG REL_temp_tran = 0x2000; // relation is a GTT delete rows +const ULONG REL_temp_conn = 0x4000; // relation is a GTT preserve rows +const ULONG REL_virtual = 0x8000; // relation is virtual +const ULONG REL_users = 0x00010000; // relation is users list inline bool jrd_rel::isSystem() const @@ -312,9 +314,14 @@ inline bool jrd_rel::isVirtual() const { - return (rel_flags & REL_virtual); + return (rel_flags & (REL_virtual | REL_users)); } +inline bool jrd_rel::isUsers() const +{ + return (rel_flags & REL_users); +} + inline RelationPages* jrd_rel::getPages(thread_db* tdbb, SLONG tran, bool allocPages) { if (!isTemporary()) Modified: firebird/trunk/src/jrd/UserManagement.cpp =================================================================== --- firebird/trunk/src/jrd/UserManagement.cpp 2010-07-09 11:33:28 UTC (rev 51321) +++ firebird/trunk/src/jrd/UserManagement.cpp 2010-07-09 12:51:05 UTC (rev 51322) @@ -30,31 +30,36 @@ #include "../jrd/msg_encode.h" #include "../utilities/gsec/gsec.h" #include "../utilities/gsec/secur_proto.h" +#include "../jrd/met_proto.h" +#include "../jrd/ini.h" +#include "gen/ids.h" using namespace Jrd; using namespace Firebird; UserManagement::UserManagement(jrd_tra* tra) - : database(0), transaction(0), commands(*tra->tra_pool) + : DataDump(*tra->tra_pool), database(0), transaction(0), buffer(0), + threadDbb(NULL), realUser(NULL), commands(*tra->tra_pool) { - char securityDatabaseName[MAXPATHLEN]; - Auth::SecurityDatabase::getPath(securityDatabaseName); - ISC_STATUS_ARRAY status; Attachment* att = tra->tra_attachment; - - ClumpletWriter dpb(ClumpletReader::dpbList, MAX_DPB_SIZE); - dpb.insertByte(isc_dpb_gsec_attach, TRUE); - dpb.insertString(isc_dpb_trusted_auth, att->att_user->usr_user_name); - if (att->att_user->usr_flags & USR_trole) + if (!att || !att->att_user) { - dpb.insertString(isc_dpb_trusted_role, ADMIN_ROLE, strlen(ADMIN_ROLE)); + (Arg::Gds(isc_random) << "Unknown user name for given transaction").raise(); } - else if (!att->att_user->usr_sql_role_name.empty()) + if (!att->att_user->locksmith()) { - dpb.insertString(isc_dpb_trusted_role, att->att_user->usr_sql_role_name); + realUser = att->att_user->usr_user_name.c_str(); } + char securityDatabaseName[MAXPATHLEN]; + Auth::SecurityDatabase::getPath(securityDatabaseName); + + ClumpletWriter dpb(ClumpletReader::dpbList, MAX_DPB_SIZE); + dpb.insertByte(isc_dpb_gsec_attach, TRUE); + dpb.insertString(isc_dpb_trusted_auth, SYSDBA_USER_NAME); + + ISC_STATUS_ARRAY status; if (isc_attach_database(status, 0, securityDatabaseName, &database, dpb.getBufferLength(), reinterpret_cast<const char*>(dpb.getBuffer()))) { @@ -92,6 +97,8 @@ status_exception::raise(status); } } + + delete buffer; } void UserManagement::commit() @@ -119,6 +126,25 @@ return ret; } +void UserManagement::checkSecurityResult(int errcode, ISC_STATUS* status, const char* userName) +{ + Arg::StatusVector tmp; + + if (!errcode) + { + return; + } + + tmp << Arg::Gds(ENCODE_ISC_MSG(errcode, GSEC_MSG_FAC)); + if (errcode == GsecMsg22) + { + tmp << userName; + } + tmp.append(Arg::StatusVector(&status[0])); + + tmp.raise(); +} + void UserManagement::execute(USHORT id) { if (!transaction || !commands[id]) @@ -138,30 +164,108 @@ #else ISC_STATUS_ARRAY status; int errcode = (!commands[id]->user_name_entered) ? GsecMsg18 : - SECURITY_exec_line(status, database, transaction, commands[id], NULL, NULL); + SECURITY_exec_line(status, realUser, database, transaction, commands[id], NULL, NULL); - switch (errcode) + checkSecurityResult(errcode, status, commands[id]->user_name); + + delete commands[id]; + commands[id] = NULL; +#endif +} + +void UserManagement::display(void* arg, const internal_user_data* u, bool/*firstTime*/) +{ + UserManagement* instance = reinterpret_cast<UserManagement*>(arg); + fb_assert(instance && instance->buffer); + + instance->display(u); +} + +void UserManagement::display(const internal_user_data* u) +{ + Record* record = buffer->getTempRecord(); + clearRecord(record); + + int attachment_charset = ttype_none; + + if (u->user_name_entered) + putField(threadDbb, record, + DumpField(f_sec_user_name, VALUE_STRING, strlen(u->user_name), u->user_name), + attachment_charset); + if (u->group_name_entered) + putField(threadDbb, record, + DumpField(f_sec_group_name, VALUE_STRING, strlen(u->group_name), u->group_name), + attachment_charset); + if (u->uid_entered) + putField(threadDbb, record, + DumpField(f_sec_uid, VALUE_INTEGER, sizeof(int), &u->uid), + attachment_charset); + if (u->gid_entered) + putField(threadDbb, record, + DumpField(f_sec_gid, VALUE_INTEGER, sizeof(int), &u->gid), + attachment_charset); + if (u->first_name_entered) + putField(threadDbb, record, + DumpField(f_sec_first_name, VALUE_STRING, strlen(u->first_name), u->first_name), + attachment_charset); + if (u->middle_name_entered) + putField(threadDbb, record, + DumpField(f_sec_middle_name, VALUE_STRING, strlen(u->middle_name), u->middle_name), + attachment_charset); + if (u->last_name_entered) + putField(threadDbb, record, + DumpField(f_sec_last_name, VALUE_STRING, strlen(u->last_name), u->last_name), + attachment_charset); + + buffer->store(record); +} + +RecordBuffer* UserManagement::getList(thread_db* tdbb) +{ +#ifdef EMBEDDED + // this restriction for embedded is temporarty and will gone when new build system will be introduced + status_exception::raise(Arg::Gds(isc_random) << "User management not supported in embedded library"); +#else + if (buffer) { - case 0: // nothing - break; - case GsecMsg22: - { - Arg::StatusVector tmp; - tmp << Arg::Gds(ENCODE_ISC_MSG(errcode, GSEC_MSG_FAC)) << Arg::Str(commands[id]->user_name); - tmp.append(Arg::StatusVector(&status[0])); - tmp.raise(); - } + return buffer; + } - default: + try + { + threadDbb = tdbb; + + jrd_rel* relation = MET_lookup_relation_id(threadDbb, rel_sec_users, false); + fb_assert(relation); + + MET_scan_relation(threadDbb, relation); + fb_assert(relation->isUsers()); + + Format* format = MET_current(threadDbb, relation); + fb_assert(format); + + MemoryPool* pool = threadDbb->getTransaction()->tra_pool; + fb_assert(pool); + + buffer = FB_NEW(*pool) RecordBuffer(*pool, format); + fb_assert(buffer); + + ISC_STATUS_ARRAY status; + internal_user_data u; + u.operation = DIS_OPER; + int errcode = SECURITY_exec_line(status, realUser, database, transaction, &u, display, this); + checkSecurityResult(errcode, status, u.user_name); + } + catch (const Exception&) + { + if (buffer) { - Arg::StatusVector tmp; - tmp << Arg::Gds(ENCODE_ISC_MSG(errcode, GSEC_MSG_FAC)); - tmp.append(Arg::StatusVector(&status[0])); - tmp.raise(); + delete buffer; + buffer = NULL; } + throw; } - delete commands[id]; - commands[id] = NULL; + return buffer; #endif } Modified: firebird/trunk/src/jrd/UserManagement.h =================================================================== --- firebird/trunk/src/jrd/UserManagement.h 2010-07-09 11:33:28 UTC (rev 51321) +++ firebird/trunk/src/jrd/UserManagement.h 2010-07-09 12:51:05 UTC (rev 51322) @@ -25,7 +25,9 @@ #include "firebird.h" #include "../common/classes/array.h" +#include "../common/classes/fb_string.h" #include "../jrd/ibase.h" +#include "../jrd/DatabaseSnapshot.h" struct internal_user_data; @@ -33,9 +35,10 @@ class thread_db; class jrd_tra; +class RecordBuffer; // User management argument for deferred work -class UserManagement +class UserManagement : public DataDump { public: explicit UserManagement(jrd_tra* tra); @@ -47,10 +50,19 @@ void execute(USHORT id); // commit transaction in security database void commit(); + // return users list for SEC$USERS + RecordBuffer* getList(thread_db* tdbb); private: FB_API_HANDLE database, transaction; + RecordBuffer* buffer; + thread_db* threadDbb; + const char* realUser; Firebird::HalfStaticArray<internal_user_data*, 8> commands; + + static void display(void* arg, const internal_user_data* u, bool firstTime); + void display(const internal_user_data* u); + static void checkSecurityResult(int errcode, ISC_STATUS* status, const char* userName); }; } // namespace Modified: firebird/trunk/src/jrd/constants.h =================================================================== --- firebird/trunk/src/jrd/constants.h 2010-07-09 11:33:28 UTC (rev 51321) +++ firebird/trunk/src/jrd/constants.h 2010-07-09 12:51:05 UTC (rev 51322) @@ -202,7 +202,8 @@ rel_external = 2, rel_virtual = 3, rel_global_temp_preserve = 4, - rel_global_temp_delete = 5 + rel_global_temp_delete = 5, + rel_vrt_users = 6 }; // procedure types Modified: firebird/trunk/src/jrd/fields.h =================================================================== --- firebird/trunk/src/jrd/fields.h 2010-07-09 11:33:28 UTC (rev 51321) +++ firebird/trunk/src/jrd/fields.h 2010-07-09 12:51:05 UTC (rev 51322) @@ -166,3 +166,9 @@ FIELD(fld_arg_mechanism , nam_arg_mechanism , dtype_short , sizeof(SSHORT) , 0 , NULL , true) FIELD(fld_identity_type , nam_identity_type , dtype_short , sizeof(SSHORT) , 0 , NULL , true) + + FIELD(fld_uid , nam_uid , dtype_long , sizeof(SLONG) , 0 , NULL , true) + FIELD(fld_gid , nam_gid , dtype_long , sizeof(SLONG) , 0 , NULL , true) + FIELD(fld_passwd_type , nam_passwd_type , dtype_text , 32 , dsc_text_type_ascii , NULL , true) + FIELD(fld_passwd , nam_passwd , dtype_blob , BLOB_SIZE , isc_blob_untyped , NULL , true) + FIELD(fld_name_part , nam_name_part , dtype_text , 32 , dsc_text_type_metadata , NULL , true) Modified: firebird/trunk/src/jrd/idx.h =================================================================== --- firebird/trunk/src/jrd/idx.h 2010-07-09 11:33:28 UTC (rev 51321) +++ firebird/trunk/src/jrd/idx.h 2010-07-09 12:51:05 UTC (rev 51322) @@ -345,6 +345,10 @@ SEGMENT(f_prm_procedure, idx_metadata), // procedure name SEGMENT(f_prm_name, idx_metadata), // parameter name SEGMENT(f_prm_pkg_name, idx_metadata) // package name + }}, + // define index RDB$INDEX_52 for RDB$USERS unique RDB$USER_NAME; + INDEX(52, ODS_12_0, rel_users, idx_unique, 1) + SEGMENT(f_user_name, idx_metadata) // procedure name }} // Last index in ODS 12.0 is RDB$INDEX_51 Modified: firebird/trunk/src/jrd/ini.epp =================================================================== --- firebird/trunk/src/jrd/ini.epp 2010-07-09 11:33:28 UTC (rev 51321) +++ firebird/trunk/src/jrd/ini.epp 2010-07-09 12:51:05 UTC (rev 51322) @@ -71,7 +71,7 @@ static void add_index_set(thread_db*); static void add_security_to_sys_rel(thread_db*, const Firebird::MetaName&, - const TEXT*, const UCHAR*, const SSHORT); + const TEXT*, const UCHAR*, const SSHORT, const bool); static void store_generator(thread_db*, const gen*, AutoRequest&); static void store_global_field(thread_db*, const gfld*, AutoRequest&); static void store_intlnames(thread_db*); @@ -468,10 +468,39 @@ *acl++ = ACL_end; length = acl - buffer; - add_security_to_sys_rel(tdbb, ownerName, "RDB$ROLES", buffer, length); - add_security_to_sys_rel(tdbb, ownerName, "RDB$PAGES", buffer, length); + add_security_to_sys_rel(tdbb, ownerName, "RDB$ROLES", buffer, length, true); + add_security_to_sys_rel(tdbb, ownerName, "RDB$PAGES", buffer, length, true); // DFW writes here - add_security_to_sys_rel(tdbb, ownerName, "RDB$FORMATS", buffer, length); + add_security_to_sys_rel(tdbb, ownerName, "RDB$FORMATS", buffer, length, true); + + // nobody except DBA should access it + acl = buffer; + *acl++ = ACL_version; + *acl++ = ACL_id_list; + *acl++ = id_person; + + length = ownerName.length(); + if (length > MAX_UCHAR) + length = MAX_UCHAR; + + *acl++ = (UCHAR)length; + if (length) + { + const TEXT* p_1 = ownerName.c_str(); + memcpy(acl, p_1, length); + acl += length; + } + *acl++ = ACL_end; + *acl++ = ACL_priv_list; + *acl++ = priv_protect; + *acl++ = priv_control; + *acl++ = priv_delete; + *acl++ = priv_write; + *acl++ = priv_read; + *acl++ = ACL_end; + *acl++ = ACL_end; + length = acl - buffer; + add_security_to_sys_rel(tdbb, ownerName, "RDB$USERS", buffer, length, false); } @@ -863,7 +892,8 @@ const Firebird::MetaName& user_name, const TEXT* rel_name, const UCHAR* acl, - const SSHORT acl_length) + const SSHORT acl_length, + const bool pub_select) { /************************************** * @@ -935,7 +965,7 @@ handle1.reset(); - for (int cnt = 0; cnt < 6; cnt++) + for (int cnt = 0; cnt < (pub_select ? 6 : 5); cnt++) { STORE(REQUEST_HANDLE handle1) PRIV IN RDB$USER_PRIVILEGES switch (cnt) Modified: firebird/trunk/src/jrd/met.epp =================================================================== --- firebird/trunk/src/jrd/met.epp 2010-07-09 11:33:28 UTC (rev 51321) +++ firebird/trunk/src/jrd/met.epp 2010-07-09 12:51:05 UTC (rev 51322) @@ -3607,6 +3607,9 @@ case rel_view: fb_assert(relation->rel_view_rse); break; + case rel_vrt_users: + relation->rel_flags |= REL_users; + break; case rel_virtual: relation->rel_flags |= REL_virtual; break; Modified: firebird/trunk/src/jrd/names.h =================================================================== --- firebird/trunk/src/jrd/names.h 2010-07-09 11:33:28 UTC (rev 51321) +++ firebird/trunk/src/jrd/names.h 2010-07-09 12:51:05 UTC (rev 51322) @@ -257,6 +257,18 @@ NAME("RDB$ARGUMENT_NAME", nam_arg_name) NAME("RDB$IDENTITY_TYPE", nam_identity_type) +NAME("RDB$USERS", nam_users) +NAME("RDB$USER_NAME", nam_user_name) +NAME("RDB$GROUP_NAME", nam_group_name) +NAME("RDB$UID", nam_uid) +NAME("RDB$GID", nam_gid) +NAME("RDB$PASSWD_TYPE", nam_passwd_type) +NAME("RDB$PASSWD", nam_passwd) +NAME("RDB$FIRST_NAME", nam_first_name) +NAME("RDB$MIDDLE_NAME", nam_middle_name) +NAME("RDB$LAST_NAME", nam_last_name) +NAME("RDB$NAME_PART", nam_name_part) + NAME("MON$ATTACHMENTS", nam_mon_attachments) NAME("MON$ATTACHMENT_ID", nam_mon_att_id) NAME("MON$ATTACHMENT_NAME", nam_mon_att_name) @@ -331,6 +343,7 @@ NAME("MON$TRANSACTIONS", nam_mon_transactions) NAME("MON$TRANSACTION_ID", nam_mon_tra_id) NAME("MON$USER", nam_mon_user) +NAME("SEC$USERS", nam_sec_users) NAME("MON$VARIABLE_NAME", nam_mon_var_name) NAME("MON$VARIABLE_VALUE", nam_mon_var_value) NAME("MON$PACKAGE_NAME", nam_mon_pkg_name) Modified: firebird/trunk/src/jrd/opt.cpp =================================================================== --- firebird/trunk/src/jrd/opt.cpp 2010-07-09 11:33:28 UTC (rev 51321) +++ firebird/trunk/src/jrd/opt.cpp 2010-07-09 12:51:05 UTC (rev 51322) @@ -3074,6 +3074,11 @@ // External table rsb = FB_NEW(*tdbb->getDefaultPool()) ExternalTableScan(csb, alias, stream); } + else if (relation->isUsers()) + { + // Users table + rsb = FB_NEW(*tdbb->getDefaultPool()) UsersTableScan(csb, alias, stream); + } else if (relation->isVirtual()) { // Virtual table Modified: firebird/trunk/src/jrd/recsrc/RecordSource.h =================================================================== --- firebird/trunk/src/jrd/recsrc/RecordSource.h 2010-07-09 11:33:28 UTC (rev 51321) +++ firebird/trunk/src/jrd/recsrc/RecordSource.h 2010-07-09 12:51:05 UTC (rev 51322) @@ -302,6 +302,29 @@ const Firebird::string m_name; }; + class UsersTableScan : public RecordStream + { + struct Impure : public RecordSource::Impure + { + RecordBuffer* irsb_record_buffer; + }; + + public: + UsersTableScan(CompilerScratch* csb, const Firebird::string& name, UCHAR stream); + + void open(thread_db* tdbb) const; + void close(thread_db* tdbb) const; + + bool getRecord(thread_db* tdbb) const; + bool refetchRecord(thread_db* tdbb) const; + bool lockRecord(thread_db* tdbb) const; + + void dump(thread_db* tdbb, Firebird::UCharBuffer& buffer) const; + + private: + const Firebird::string m_name; + }; + class ProcedureScan : public RecordStream { struct Impure : public RecordSource::Impure Added: firebird/trunk/src/jrd/recsrc/UsersTableScan.cpp =================================================================== --- firebird/trunk/src/jrd/recsrc/UsersTableScan.cpp (rev 0) +++ firebird/trunk/src/jrd/recsrc/UsersTableScan.cpp 2010-07-09 12:51:05 UTC (rev 51322) @@ -0,0 +1,142 @@ +/* + * 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 Dmitry Yemanov + * for the Firebird Open Source RDBMS project. + * + * Copyright (c) 2009 Dmitry Yemanov <di...@fi...> + * and all contributors signed below. + * + * All Rights Reserved. + * Contributor(s): ______________________________________. + * Alex Peshkoff, 2010 - implemented users scan based on virtual tables + */ + +#include "firebird.h" +#include "../jrd/jrd.h" +#include "../jrd/req.h" +#include "../jrd/rse.h" +#include "../jrd/cmp_proto.h" +#include "../jrd/met_proto.h" +#include "../jrd/vio_proto.h" +#include "../jrd/UserManagement.h" +#include "../jrd/tra.h" + +#include "RecordSource.h" + +using namespace Firebird; +using namespace Jrd; + + +// ------------------------------- +// Data access: users table scan +// ------------------------------- + +UsersTableScan::UsersTableScan(CompilerScratch* csb, const string& name, UCHAR stream) + : RecordStream(csb, stream), m_name(csb->csb_pool, name) +{ + m_impure = CMP_impure(csb, sizeof(Impure)); +} + +void UsersTableScan::open(thread_db* tdbb) const +{ + jrd_req* const request = tdbb->getRequest(); + Impure* const impure = request->getImpure<Impure>(m_impure); + + impure->irsb_flags = irsb_open; + + record_param* const rpb = &request->req_rpb[m_stream]; + rpb->getWindow(tdbb).win_flags = 0; + + jrd_rel* const relation = rpb->rpb_relation; + + const Record* const record = rpb->rpb_record; + const Format* format = NULL; + if (!record || !record->rec_format) + { + format = MET_current(tdbb, relation); + VIO_record(tdbb, rpb, format, request->req_pool); + } + else + { + format = record->rec_format; + } + + rpb->rpb_number.setValue(BOF_NUMBER); + + impure->irsb_record_buffer = tdbb->getTransaction()->getUserManagement()->getList(tdbb); +} + +void UsersTableScan::close(thread_db* tdbb) const +{ + jrd_req* const request = tdbb->getRequest(); + + invalidateRecords(request); + + Impure* const impure = request->getImpure<Impure>(m_impure); + + if (impure->irsb_flags & irsb_open) + { + impure->irsb_flags &= ~irsb_open; + impure->irsb_record_buffer = NULL; + } +} + +bool UsersTableScan::getRecord(thread_db* tdbb) const +{ + jrd_req* const request = tdbb->getRequest(); + record_param* const rpb = &request->req_rpb[m_stream]; + Impure* const impure = request->getImpure<Impure>(m_impure); + + if (!(impure->irsb_flags & irsb_open)) + { + rpb->rpb_number.setValid(false); + return false; + } + + rpb->rpb_number.increment(); + + fb_assert(impure->irsb_record_buffer); + + if (impure->irsb_record_buffer->fetch(rpb->rpb_number.getValue(), rpb->rpb_record)) + { + rpb->rpb_number.setValid(true); + return true; + } + + rpb->rpb_number.setValid(false); + return false; +} + +bool UsersTableScan::refetchRecord(thread_db* tdbb) const +{ + return true; +} + +bool UsersTableScan::lockRecord(thread_db* tdbb) const +{ + status_exception::raise(Arg::Gds(isc_record_lock_not_supp)); + return false; // compiler silencer +} + +void UsersTableScan::dump(thread_db* tdbb, UCharBuffer& buffer) const +{ + buffer.add(isc_info_rsb_begin); + + buffer.add(isc_info_rsb_relation); + dumpName(tdbb, m_name, buffer); + + buffer.add(isc_info_rsb_type); + buffer.add(isc_info_rsb_virt_sequential); + + buffer.add(isc_info_rsb_end); +} Property changes on: firebird/trunk/src/jrd/recsrc/UsersTableScan.cpp ___________________________________________________________________ Added: svn:mime-type + text/plain Added: svn:eol-style + native Modified: firebird/trunk/src/jrd/relations.h =================================================================== --- firebird/trunk/src/jrd/relations.h 2010-07-09 11:33:28 UTC (rev 51321) +++ firebird/trunk/src/jrd/relations.h 2010-07-09 12:51:05 UTC (rev 51322) @@ -590,3 +590,28 @@ FIELD(f_pkg_sys_flag, nam_sys_flag, fld_flag, 1, ODS_12_0) FIELD(f_pkg_desc, nam_description, fld_description, 1, ODS_12_0) END_RELATION + +// Relation 43 (RDB$USERS) +RELATION(nam_users, rel_users, ODS_12_0, rel_persistent) + FIELD(f_user_name, nam_user_name, fld_user, 1, ODS_12_0) + FIELD(f_group_name, nam_group_name, fld_user, 1, ODS_12_0) + FIELD(f_uid, nam_uid, fld_uid, 1, ODS_12_0) + FIELD(f_gid, nam_gid, fld_gid, 1, ODS_12_0) + FIELD(f_passwd_type, nam_passwd_type, fld_passwd_type, 1, ODS_12_0) + FIELD(f_passwd, nam_passwd, fld_passwd, 1, ODS_12_0) + FIELD(f_first_name, nam_first_name, fld_name_part, 1, ODS_12_0) + FIELD(f_middle_name, nam_middle_name, fld_name_part, 1, ODS_12_0) + FIELD(f_last_name, nam_last_name, fld_name_part, 1, ODS_12_0) + FIELD(f_user_desc, nam_description, fld_description, 1, ODS_12_0) +END_RELATION + +// Relation 44 (SEC$USERS) +RELATION(nam_sec_users, rel_sec_users, ODS_12_0, rel_vrt_users) + FIELD(f_sec_user_name, nam_user_name, fld_user, 1, ODS_12_0) + FIELD(f_sec_group_name, nam_group_name, fld_user, 1, ODS_12_0) + FIELD(f_sec_uid, nam_uid, fld_uid, 1, ODS_12_0) + FIELD(f_sec_gid, nam_gid, fld_gid, 1, ODS_12_0) + FIELD(f_sec_first_name, nam_first_name, fld_name_part, 1, ODS_12_0) + FIELD(f_sec_middle_name, nam_middle_name, fld_name_part, 1, ODS_12_0) + FIELD(f_sec_last_name, nam_last_name, fld_name_part, 1, ODS_12_0) +END_RELATION Modified: firebird/trunk/src/jrd/svc.cpp =================================================================== --- firebird/trunk/src/jrd/svc.cpp 2010-07-09 11:33:28 UTC (rev 51321) +++ firebird/trunk/src/jrd/svc.cpp 2010-07-09 12:51:05 UTC (rev 51322) @@ -1924,27 +1924,31 @@ // Only need to add username and password information to those calls which need // to make a database connection - if (svc_id == isc_action_svc_backup || + + bool flNeedUser = (svc_id == isc_action_svc_backup || svc_id == isc_action_svc_restore || svc_id == isc_action_svc_nbak || svc_id == isc_action_svc_nrest || svc_id == isc_action_svc_repair || - svc_id == isc_action_svc_add_user || - svc_id == isc_action_svc_delete_user || - svc_id == isc_action_svc_modify_user || - svc_id == isc_action_svc_display_user || - svc_id == isc_action_svc_display_user_adm || svc_id == isc_action_svc_db_stats || svc_id == isc_action_svc_properties || svc_id == isc_action_svc_trace_start || svc_id == isc_action_svc_trace_stop || svc_id == isc_action_svc_trace_suspend || svc_id == isc_action_svc_trace_resume || - svc_id == isc_action_svc_trace_list || + svc_id == isc_action_svc_trace_list); + + bool flGsecUser = (svc_id == isc_action_svc_add_user || + svc_id == isc_action_svc_delete_user || + svc_id == isc_action_svc_modify_user || + svc_id == isc_action_svc_display_user || + svc_id == isc_action_svc_display_user_adm || svc_id == isc_action_svc_set_mapping || - svc_id == isc_action_svc_drop_mapping) + svc_id == isc_action_svc_drop_mapping); + + if (flNeedUser || flGsecUser) { - // add the username and password to the end of svc_switches if needed + // add the username to the end of svc_switches if needed if (svc_switches.hasData()) { if (svc_username.hasData()) @@ -1952,9 +1956,15 @@ string auth = "-"; auth += TRUSTED_USER_SWITCH; auth += ' '; + if (flGsecUser) + { + // gsec service - gsec will take care itself about security + auth += SYSDBA_USER_NAME; + auth += " -REAL_USER "; + } auth += svc_username; auth += ' '; - if (svc_trusted_role) + if (svc_trusted_role && (!flGsecUser)) { auth += "-"; auth += TRUSTED_ROLE_SWITCH; @@ -1965,6 +1975,7 @@ } } + // All services except for get_ib_log require switches spb.rewind(); if ((!svc_switches.hasData()) && svc_id != isc_action_svc_get_fb_log) Modified: firebird/trunk/src/jrd/types.h =================================================================== --- firebird/trunk/src/jrd/types.h 2010-07-09 11:33:28 UTC (rev 51321) +++ firebird/trunk/src/jrd/types.h 2010-07-09 12:51:05 UTC (rev 51322) @@ -112,6 +112,7 @@ TYPE ("VIRTUAL", rel_virtual, nam_r_type) TYPE ("GLOBAL_TEMPORARY_PRESERVE", rel_global_temp_preserve, nam_r_type) TYPE ("GLOBAL_TEMPORARY_DELETE", rel_global_temp_delete, nam_r_type) +TYPE ("USERS LIST", rel_vrt_users, nam_r_type) TYPE ("LEGACY", prc_legacy, nam_prc_type) TYPE ("SELECTABLE", prc_selectable, nam_prc_type) Modified: firebird/trunk/src/msgs/facilities2.sql =================================================================== --- firebird/trunk/src/msgs/facilities2.sql 2010-07-09 11:33:28 UTC (rev 51321) +++ firebird/trunk/src/msgs/facilities2.sql 2010-07-09 12:51:05 UTC (rev 51322) @@ -27,7 +27,7 @@ --('1996-11-07 13:38:43', 'GJRN', 16, 241) -- ('2009-12-21 04:00:05', 'ISQL', 17, 173) -('2009-11-13 17:49:54', 'GSEC', 18, 104) +('2009-11-13 17:49:54', 'GSEC', 18, 105) -- --('2002-03-05 02:30:12', 'LICENSE', 19, 60) --('2002-03-05 02:31:54', 'DOS', 20, 74) Modified: firebird/trunk/src/msgs/messages2.sql =================================================================== --- firebird/trunk/src/msgs/messages2.sql 2010-07-09 11:33:28 UTC (rev 51321) +++ firebird/trunk/src/msgs/messages2.sql 2010-07-09 12:51:05 UTC (rev 51322) @@ -2905,6 +2905,7 @@ ('GsecMsg101', 'gsec', 'gsec.cpp', NULL, 18, 101, NULL, 'use gsec -? to get help', NULL, NULL); ('GsecMsg102', 'gsec', 'gsec.cpp', NULL, 18, 102, NULL, '-admin {yes|no}', NULL, NULL); ('GsecMsg103', 'gsec', 'gsec.cpp', NULL, 18, 103, NULL, 'invalid parameter for -ADMIN, only YES or NO is accepted', NULL, NULL); +('GsecMsg104', 'SECURITY_exec_line', 'security.epp', NULL, 18, 104, NULL, 'not enough privileges to complete operation', NULL, NULL); -- GSTAT ('gstat_unknown_switch', 'main', 'dba.e', NULL, 21, 1, NULL, 'found unknown switch', NULL, NULL); ('gstat_retry', 'main', 'dba.e', NULL, 21, 2, NULL, 'please retry, giving a database name', NULL, NULL); Modified: firebird/trunk/src/utilities/gsec/gsec.cpp =================================================================== --- firebird/trunk/src/utilities/gsec/gsec.cpp 2010-07-09 11:33:28 UTC (rev 51321) +++ firebird/trunk/src/utilities/gsec/gsec.cpp 2010-07-09 12:51:05 UTC (rev 51322) @@ -278,7 +278,8 @@ uSvc->started(); if (! useServices) { - ret = SECURITY_exec_line(status, db_handle, user_data, data_print, NULL); + ret = SECURITY_exec_line(status, tdsec->tsec_real_user, + db_handle, user_data, data_print, NULL); if (ret) { GSEC_print(ret, user_data->user_name); @@ -596,8 +597,7 @@ user_data->gid_entered = true; break; case IN_SW_GSEC_SYSUSER: - fb_utils::copy_terminate(user_data->sys_user_name, string, sizeof(user_data->sys_user_name)); - user_data->sys_user_entered = true; + // ignore it break; case IN_SW_GSEC_GROUP: fb_utils::copy_terminate(user_data->group_name, string, sizeof(user_data->group_name)); @@ -653,6 +653,10 @@ fb_utils::copy_terminate(user_data->dba_trust_user_name, string, sizeof(user_data->dba_trust_user_name)); user_data->dba_trust_user_name_entered = true; break; + case IN_SW_GSEC_REAL_USER: + tdsec->utilSvc->checkService(); + tdsec->tsec_real_user = string; + break; case IN_SW_GSEC_MAPPING: { Firebird::string val(string); @@ -808,13 +812,7 @@ user_data->gid = 0; break; case IN_SW_GSEC_SYSUSER: - if (user_data->sys_user_specified) - { - err_msg_no = GsecMsg34; - break; - } - user_data->sys_user_specified = true; - user_data->sys_user_name[0] = '\0'; + // ignore it break; case IN_SW_GSEC_GROUP: if (user_data->group_name_specified) @@ -932,6 +930,8 @@ GSEC_diag(GsecMsg41); // gsec - ambiguous switch specified return false; + case IN_SW_GSEC_REAL_USER: + break; } last_sw = in_sw; } @@ -940,7 +940,7 @@ // is valid, and if not, indicate why not if (user_data->uid_entered || user_data->gid_entered || - user_data->sys_user_entered || user_data->group_name_entered || + user_data->group_name_entered || user_data->password_entered || user_data->first_name_entered || user_data->middle_name_entered || user_data->last_name_entered) { Modified: firebird/trunk/src/utilities/gsec/gsec.h =================================================================== --- firebird/trunk/src/utilities/gsec/gsec.h 2010-07-09 11:33:28 UTC (rev 51321) +++ firebird/trunk/src/utilities/gsec/gsec.h 2010-07-09 12:51:05 UTC (rev 51322) @@ -65,9 +65,6 @@ int gid; // the user's group id bool gid_entered; // GID entered flag bool gid_specified; // GID specified flag - TEXT sys_user_name [ALT_NAME_LEN]; // the sys_user's name - bool sys_user_entered; // sys_user entered flag - bool sys_user_specified; // sys_user specified flag TEXT group_name [ALT_NAME_LEN]; // the group name bool group_name_entered; // group_name entered flag bool group_name_specified; // group_name specified flag @@ -123,13 +120,15 @@ public: explicit tsec(Firebird::UtilSvc* uf) : ThreadData(ThreadData::tddSEC), utilSvc(uf), - tsec_user_data(0), tsec_exit_code(0), tsec_throw(false), + tsec_user_data(0), tsec_real_user(NULL), + tsec_exit_code(0), tsec_throw(false), tsec_interactive(false), tsec_sw_version(false) { } Firebird::UtilSvc* utilSvc; internal_user_data* tsec_user_data; + const char* tsec_real_user; int tsec_exit_code; bool tsec_throw; bool tsec_interactive; @@ -255,6 +254,7 @@ const USHORT GsecMsg101 = 101; // use gsec -? to get help const USHORT GsecMsg102 = 102; // -adm(in) {yes|no} const USHORT GsecMsg103 = 103; // invalid parameter for -ADMIN, only YES or NO is accepted +const USHORT GsecMsg104 = 104; // not enough privileges to complete operation #endif // UTILITIES_GSEC_H Modified: firebird/trunk/src/utilities/gsec/gsecswi.h =================================================================== --- firebird/trunk/src/utilities/gsec/gsecswi.h 2010-07-09 11:33:28 UTC (rev 51321) +++ firebird/trunk/src/utilities/gsec/gsecswi.h 2010-07-09 12:51:05 UTC (rev 51322) @@ -34,7 +34,7 @@ const int IN_SW_GSEC_0 = 0; // not a known switch const int IN_SW_GSEC_UID = 1; // uid is specified const int IN_SW_GSEC_GID = 2; // gid is specified -const int IN_SW_GSEC_SYSUSER = 3; // sys_user_name is specified +const int IN_SW_GSEC_SYSUSER = 3; // sys_user name is specified const int IN_SW_GSEC_GROUP = 4; // group is specified const int IN_SW_GSEC_PASSWORD = 5; // password is specified const int IN_SW_GSEC_FNAME = 6; // first name is specified @@ -62,6 +62,7 @@ const int IN_SW_GSEC_MAPPING = 26; // Change auto admin mapping const int IN_SW_GSEC_ADMIN = 27; // Grant/revoke RDB$ADMIN in security database const int IN_SW_GSEC_DIS_ADM = 28; // display user(s) with admin info +const int IN_SW_GSEC_REAL_USER = 29; // svc user, if not SYSDBA static const struct Switches::in_sw_tab_t gsec_in_sw_table [] = { @@ -85,6 +86,7 @@ {IN_SW_GSEC_DBA_USER_NAME, 0, "USER", 0, 0, 0, false, 0, 1, NULL}, // Database Admin. User name {IN_SW_GSEC_DBA_PASSWORD, 0, "PASSWORD", 0, 0, 0, false, 0, 2, NULL}, // Database Admin. Password {IN_SW_GSEC_FETCH_PASSWORD, 0, "FETCH_PASSWORD", 0, 0, 0, false, 0, 2, NULL}, // Fetch Database Admin. Password + {IN_SW_GSEC_REAL_USER, 0, "REAL_USER", 0, 0, 0, false, 0, 9, NULL}, // name of real user, connected to services {IN_SW_GSEC_SQL_ROLE_NAME, isc_spb_sql_role_name, "ROLE", 0, 0, 0, false, 0, 2, NULL}, // SQL Role to assume {IN_SW_GSEC_DBA_TRUSTED_USER, 0, TRUSTED_USER_SWITCH, 0, 0, 0, false, 0, TRUSTED_USER_SWITCH_LEN, NULL}, // Database Admin. Trusted User name Modified: firebird/trunk/src/utilities/gsec/secur_proto.h =================================================================== --- firebird/trunk/src/utilities/gsec/secur_proto.h 2010-07-09 11:33:28 UTC (rev 51321) +++ firebird/trunk/src/utilities/gsec/secur_proto.h 2010-07-09 12:51:05 UTC (rev 51322) @@ -25,10 +25,10 @@ #define UTILITIES_SECUR_PROTO_H typedef void (*FPTR_SECURITY_CALLBACK)(void*, const internal_user_data*, bool); -SSHORT SECURITY_exec_line (ISC_STATUS* isc_status, FB_API_HANDLE DB, FB_API_HANDLE trans, +SSHORT SECURITY_exec_line (ISC_STATUS* isc_status, const char* realUser, FB_API_HANDLE DB, FB_API_HANDLE trans, internal_user_data* io_user_data, FPTR_SECURITY_CALLBACK display_func, void* callback_arg); -SSHORT SECURITY_exec_line (ISC_STATUS* isc_status, FB_API_HANDLE DB, +SSHORT SECURITY_exec_line (ISC_STATUS* isc_status, const char* realUser, FB_API_HANDLE DB, internal_user_data* io_user_data, FPTR_SECURITY_CALLBACK display_func, void* callback_arg); Modified: firebird/trunk/src/utilities/gsec/security.epp =================================================================== --- firebird/trunk/src/utilities/gsec/security.epp 2010-07-09 11:33:28 UTC (rev 51321) +++ firebird/trunk/src/utilities/gsec/security.epp 2010-07-09 12:51:05 UTC (rev 51322) @@ -37,6 +37,7 @@ #include "../utilities/gsec/secur_proto.h" #include "../common/utils_proto.h" #include "../common/classes/init.h" +#include "../common/classes/UserBlob.h" DATABASE DB = STATIC FILENAME "security2.fdb"; @@ -84,7 +85,27 @@ } +static bool storePasswd(ISC_STATUS* isc_status, FB_API_HANDLE DB, FB_API_HANDLE trans, + ISC_QUAD& blobId, const Firebird::string& passwd) +{ + UserBlob blob(isc_status); + const UCHAR blob_desc[] = {isc_bpb_version1, isc_bpb_type, 1, isc_blob_untyped}; + + if (!blob.create(DB, trans, blobId, sizeof(blob_desc), blob_desc)) + { + return false; + } + + if (!blob.putData(passwd.length(), passwd.c_str())) + { + return false; + } + + return blob.close(); +} + SSHORT SECURITY_exec_line(ISC_STATUS* isc_status, + const char *realUser, FB_API_HANDLE DB, FB_API_HANDLE trans, internal_user_data* io_user_data, @@ -173,7 +194,12 @@ { case MAP_DROP_OPER: case MAP_SET_OPER: + if (realUser) { + ret = GsecMsg104; + break; + } + { Firebird::string sql; sql.printf("ALTER ROLE RDB$ADMIN %s AUTO ADMIN MAPPING", io_user_data->operation == MAP_SET_OPER ? "SET" : "DROP"); @@ -185,62 +211,71 @@ } break; case ADD_OPER: + if (realUser) + { + ret = GsecMsg104; + break; + } // this checks the "entered" flags for each parameter (except the name) // and makes all non-entered parameters null valued - STORE (TRANSACTION_HANDLE trans REQUEST_HANDLE request) U IN USERS USING - strcpy(U.USER_NAME, io_user_data->user_name); + STORE (TRANSACTION_HANDLE trans REQUEST_HANDLE request) U IN RDB$USERS USING + strcpy(U.RDB$USER_NAME, io_user_data->user_name); if (io_user_data->uid_entered) { - U.UID = io_user_data->uid; - U.UID.NULL = ISC_FALSE; + U.RDB$UID = io_user_data->uid; + U.RDB$UID.NULL = ISC_FALSE; } else - U.UID.NULL = ISC_TRUE; + U.RDB$UID.NULL = ISC_TRUE; if (io_user_data->gid_entered) { - U.GID = io_user_data->gid; - U.GID.NULL = ISC_FALSE; + U.RDB$GID = io_user_data->gid; + U.RDB$GID.NULL = ISC_FALSE; } else - U.GID.NULL = ISC_TRUE; + U.RDB$GID.NULL = ISC_TRUE; if (io_user_data->group_name_entered) { - strcpy(U.GROUP_NAME, io_user_data->group_name); - U.GROUP_NAME.NULL = ISC_FALSE; + strcpy(U.RDB$GROUP_NAME, io_user_data->group_name); + U.RDB$GROUP_NAME.NULL = ISC_FALSE; } else - U.GROUP_NAME.NULL = ISC_TRUE; + U.RDB$GROUP_NAME.NULL = ISC_TRUE; if (io_user_data->password_entered) { ENC_crypt(encrypted1, sizeof encrypted1, io_user_data->password, Auth::PASSWORD_SALT); Auth::SecurityDatabase::hash(encrypted2, io_user_data->user_name, &encrypted1[2]); - strcpy(U.PASSWD, encrypted2.c_str()); - U.PASSWD.NULL = ISC_FALSE; + if (!storePasswd(isc_status, DB, trans, U.RDB$PASSWD, encrypted2)) + { + ret = GsecMsg19; + break; + } + U.RDB$PASSWD.NULL = ISC_FALSE; } else - U.PASSWD.NULL = ISC_TRUE; + U.RDB$PASSWD.NULL = ISC_TRUE; if (io_user_data->first_name_entered) { - strcpy(U.FIRST_NAME, io_user_data->first_name); - U.FIRST_NAME.NULL = ISC_FALSE; + strcpy(U.RDB$FIRST_NAME, io_user_data->first_name); + U.RDB$FIRST_NAME.NULL = ISC_FALSE; } else - U.FIRST_NAME.NULL = ISC_TRUE; + U.RDB$FIRST_NAME.NULL = ISC_TRUE; if (io_user_data->middle_name_entered) { - strcpy(U.MIDDLE_NAME, io_user_data->middle_name); - U.MIDDLE_NAME.NULL = ISC_FALSE; + strcpy(U.RDB$MIDDLE_NAME, io_user_data->middle_name); + U.RDB$MIDDLE_NAME.NULL = ISC_FALSE; } else - U.MIDDLE_NAME.NULL = ISC_TRUE; + U.RDB$MIDDLE_NAME.NULL = ISC_TRUE; if (io_user_data->last_name_entered) { - strcpy(U.LAST_NAME, io_user_data->last_name); - U.LAST_NAME.NULL = ISC_FALSE; + strcpy(U.RDB$LAST_NAME, io_user_data->last_name); + U.RDB$LAST_NAME.NULL = ISC_FALSE; } else - U.LAST_NAME.NULL = ISC_TRUE; + U.RDB$LAST_NAME.NULL = ISC_TRUE; END_STORE ON_ERROR ret = GsecMsg19; // gsec - add record error @@ -252,66 +287,76 @@ break; case MOD_OPER: + if (realUser && strcmp(realUser, io_user_data->user_name)) + { + ret = GsecMsg104; + break; + } + // this updates an existing record, replacing all fields that are // entered, and for those that were specified but not entered, it // changes the current value to the null value found = false; - FOR (TRANSACTION_HANDLE trans REQUEST_HANDLE request) U IN USERS - WITH U.USER_NAME EQ io_user_data->user_name + FOR (TRANSACTION_HANDLE trans REQUEST_HANDLE request) U IN RDB$USERS + WITH U.RDB$USER_NAME EQ io_user_data->user_name found = true; MODIFY U USING if (io_user_data->uid_entered) { - U.UID = io_user_data->uid; - U.UID.NULL = ISC_FALSE; + U.RDB$UID = io_user_data->uid; + U.RDB$UID.NULL = ISC_FALSE; } else if (io_user_data->uid_specified) - U.UID.NULL = ISC_TRUE; + U.RDB$UID.NULL = ISC_TRUE; if (io_user_data->gid_entered) { - U.GID = io_user_data->gid; - U.GID.NULL = ISC_FALSE; + U.RDB$GID = io_user_data->gid; + U.RDB$GID.NULL = ISC_FALSE; } else if (io_user_data->gid_specified) - U.GID.NULL = ISC_TRUE; + U.RDB$GID.NULL = ISC_TRUE; if (io_user_data->group_name_entered) { - strcpy(U.GROUP_NAME, io_user_data->group_name); - U.GROUP_NAME.NULL = ISC_FALSE; + strcpy(U.RDB$GROUP_NAME, io_user_data->group_name); + U.RDB$GROUP_NAME.NULL = ISC_FALSE; } else if (io_user_data->group_name_specified) - U.GROUP_NAME.NULL = ISC_TRUE; + U.RDB$GROUP_NAME.NULL = ISC_TRUE; if (io_user_data->password_entered) { ENC_crypt(encrypted1, sizeof encrypted1, io_user_data->password, Auth::PASSWORD_SALT); Auth::SecurityDatabase::hash(encrypted2, io_user_data->user_name, &encrypted1[2]); - strcpy(U.PASSWD, encrypted2.c_str()); - U.PASSWD.NULL = ISC_FALSE; + if (!storePasswd(isc_status, DB, trans, U.RDB$PASSWD, encrypted2)) + { + ret = GsecMsg21; + break; + } + U.RDB$PASSWD.NULL = ISC_FALSE; } else if (io_user_data->password_specified) - U.PASSWD.NULL = ISC_TRUE; + U.RDB$PASSWD.NULL = ISC_TRUE; if (io_user_data->first_name_entered) { - strcpy(U.FIRST_NAME, io_user_data->first_name); - U.FIRST_NAME.NULL = ISC_FALSE; + strcpy(U.RDB$FIRST_NAME, io_user_data->first_name); + U.RDB$FIRST_NAME.NULL = ISC_FALSE; } else if (io_user_data->first_name_specified) - U.FIRST_NAME.NULL = ISC_TRUE; + U.RDB$FIRST_NAME.NULL = ISC_TRUE; if (io_user_data->middle_name_entered) { - strcpy(U.MIDDLE_NAME, io_user_data->middle_name); - U.MIDDLE_NAME.NULL = ISC_FALSE; + strcpy(U.RDB$MIDDLE_NAME, io_user_data->middle_name); + U.RDB$MIDDLE_NAME.NULL = ISC_FALSE; } else if (io_user_data->middle_name_specified) - U.MIDDLE_NAME.NULL = ISC_TRUE; + U.RDB$MIDDLE_NAME.NULL = ISC_TRUE; if (io_user_data->last_name_entered) { - strcpy(U.LAST_NAME, io_user_data->last_name); - U.LAST_NAME.NULL = ISC_FALSE; + strcpy(U.RDB$LAST_NAME, io_user_data->last_name); + U.RDB$LAST_NAME.NULL = ISC_FALSE; } else if (io_user_data->last_name_specified) - U.LAST_NAME.NULL = ISC_TRUE; + U.RDB$LAST_NAME.NULL = ISC_TRUE; END_MODIFY ON_ERROR ret = GsecMsg20; @@ -329,6 +374,12 @@ break; case DEL_OPER: + if (realUser) + { + ret = GsecMsg104; + break; + } + // looks up the specified user record and deletes it found = false; @@ -337,8 +388,8 @@ ret = GsecMsg23; else { - FOR (TRANSACTION_HANDLE trans REQUEST_HANDLE request) U IN USERS - WITH U.USER_NAME EQ io_user_data->user_name + FOR (TRANSACTION_HANDLE trans REQUEST_HANDLE request) U IN RDB$USERS + WITH U.RDB$USER_NAME EQ io_user_data->user_name found = true; ERASE U ON_ERROR @@ -363,25 +414,51 @@ case DIS_OPER: case OLD_DIS_OPER: + if (realUser) + { + if (io_user_data->user_name_entered && strcmp(realUser, io_user_data->user_name)) + { + ret = GsecMsg104; + break; + } + if (!io_user_data->user_name_entered) + { + if (strlen(realUser) > sizeof(io_user_data->user_name) - 1) + { + ret = GsecMsg104; + break; + } + strcpy(io_user_data->user_name, realUser); + io_user_data->user_name_entered = true; + } + } + // gets either the desired record, or all records, and displays them found = false; if (!io_user_data->user_name_entered) { - FOR (TRANSACTION_HANDLE trans REQUEST_HANDLE request) U IN USERS - io_user_data->uid = U.UID; - io_user_data->gid = U.GID; - *(io_user_data->sys_user_name) = '\0'; - strcpy(io_user_data->user_name, U.USER_NAME); - strcpy(io_user_data->group_name, U.GROUP_NAME); + FOR (TRANSACTION_HANDLE trans REQUEST_HANDLE request) U IN RDB$USERS + io_user_data->uid = U.RDB$UID; + io_user_data->uid_entered = !U.RDB$UID.NULL; + io_user_data->gid = U.RDB$GID; + io_user_data->gid_entered = !U.RDB$GID.NULL; + strcpy(io_user_data->user_name, U.RDB$USER_NAME); + io_user_data->user_name_entered = !U.RDB$USER_NAME.NULL; + strcpy(io_user_data->group_name, U.RDB$GROUP_NAME); + io_user_data->group_name_entered = !U.RDB$GROUP_NAME.NULL; io_user_data->password[0] = 0; - strcpy(io_user_data->first_name, U.FIRST_NAME); - strcpy(io_user_data->middle_name, U.MIDDLE_NAME); - strcpy(io_user_data->last_name, U.LAST_NAME); + io_user_data->password_entered = false; + strcpy(io_user_data->first_name, U.RDB$FIRST_NAME); + io_user_data->first_name_entered = !U.RDB$FIRST_NAME.NULL; + strcpy(io_user_data->middle_name, U.RDB$MIDDLE_NAME); + io_user_data->middle_name_entered = !U.RDB$MIDDLE_NAME.NULL; + strcpy(io_user_data->last_name, U.RDB$LAST_NAME); + io_user_data->last_name_entered = !U.RDB$LAST_NAME.NULL; io_user_data->admin = 0; FOR (TRANSACTION_HANDLE trans REQUEST_HANDLE request2) P IN RDB$USER_PRIVILEGES - WITH P.RDB$USER EQ U.USER_NAME + WITH P.RDB$USER EQ U.RDB$USER_NAME AND P.RDB$RELATION_NAME EQ 'RDB$ADMIN' AND P.RDB$PRIVILEGE EQ 'M' io_user_data->admin = 1; @@ -397,21 +474,28 @@ } else { - FOR (TRANSACTION_HANDLE trans REQUEST_HANDLE request) U IN USERS - WITH U.USER_NAME EQ io_user_data->user_name - io_user_data->uid = U.UID; - io_user_data->gid = U.GID; - *(io_user_data->sys_user_name) = '\0'; - strcpy(io_user_data->user_name, U.USER_NAME); - strcpy(io_user_data->group_name, U.GROUP_NAME); + FOR (TRANSACTION_HANDLE trans REQUEST_HANDLE request) U IN RDB$USERS + WITH U.RDB$USER_NAME EQ io_user_data->user_name + io_user_data->uid = U.RDB$UID; + io_user_data->uid_entered = !U.RDB$UID.NULL; + io_user_data->gid = U.RDB$GID; + io_user_data->gid_entered = !U.RDB$GID.NULL; + strcpy(io_user_data->user_name, U.RDB$USER_NAME); + io_user_data->user_name_entered = !U.RDB$USER_NAME.NULL; + strcpy(io_user_data->group_name, U.RDB$GROUP_NAME); + io_user_data->group_name_entered = !U.RDB$GROUP_NAME.NULL; io_user_data->password[0] = 0; - strcpy(io_user_data->first_name, U.FIRST_NAME); - strcpy(io_user_data->middle_name, U.MIDDLE_NAME); - strcpy(io_user_data->last_name, U.LAST_NAME); + io_user_data->password_entered = false; + strcpy(io_user_data->first_name, U.RDB$FIRST_NAME); + io_user_data->first_name_entered = !U.RDB$FIRST_NAME.NULL; + strcpy(io_user_data->middle_name, U.RDB$MIDDLE_NAME); + io_user_data->middle_name_entered = !U.RDB$MIDDLE_NAME.NULL; + strcpy(io_user_data->last_name, U.RDB$LAST_NAME); + io_user_data->last_name_entered = !U.RDB$LAST_NAME.NULL; io_user_data->admin = 0; FOR (TRANSACTION_HANDLE trans REQUEST_HANDLE request2) P IN RDB$USER_PRIVILEGES - WITH P.RDB$USER EQ U.USER_NAME + WITH P.RDB$USER EQ U.RDB$USER_NAME AND P.RDB$RELATION_NAME EQ 'RDB$ADMIN' AND P.RDB$PRIVILEGE EQ 'M' io_user_data->admin = 1; @@ -460,6 +544,7 @@ } SSHORT SECURITY_exec_line(ISC_STATUS* isc_status, + const char *realUser, FB_API_HANDLE DB, internal_user_data* io_user_data, FPTR_SECURITY_CALLBACK display_func, @@ -472,7 +557,7 @@ return GsecMsg75; // gsec error END_ERROR; - SSHORT ret = SECURITY_exec_line(isc_status, DB, gds_trans, io_user_data, display_func, callback_arg); + SSHORT ret = SECURITY_exec_line(isc_status, realUser, DB, gds_trans, io_user_data, display_func, callback_arg); // rollback if we have an error using tmp_status to avoid // overwriting the error status which the caller wants to see This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |