From: <ale...@us...> - 2011-03-02 13:43:08
|
Revision: 52492 http://firebird.svn.sourceforge.net/firebird/?rev=52492&view=rev Author: alexpeshkoff Date: 2011-03-02 13:42:56 +0000 (Wed, 02 Mar 2011) Log Message: ----------- Fixed CORE-3369: first step to make it possible to specify non-default security database for specific database Modified Paths: -------------- firebird/trunk/builds/posix/make.shared.variables firebird/trunk/src/auth/AuthInterface.h firebird/trunk/src/auth/SecurityDatabase/LegacyManagement.epp firebird/trunk/src/auth/SecurityDatabase/LegacyManagement.h firebird/trunk/src/common/call_service.cpp firebird/trunk/src/common/call_service.h firebird/trunk/src/common/classes/ImplementHelper.h firebird/trunk/src/common/classes/PublicHandle.cpp firebird/trunk/src/common/classes/PublicHandle.h firebird/trunk/src/common/classes/alloc.cpp firebird/trunk/src/common/classes/alloc.h firebird/trunk/src/common/classes/init.h firebird/trunk/src/common/config/config.cpp firebird/trunk/src/common/config/config.h firebird/trunk/src/common/config/config_file.cpp firebird/trunk/src/common/config/config_file.h firebird/trunk/src/common/fb_exception.cpp firebird/trunk/src/common/isc_sync.cpp firebird/trunk/src/dbs/security.sql firebird/trunk/src/include/FirebirdPluginApi.h firebird/trunk/src/include/Interface.h firebird/trunk/src/jrd/ExtEngineManager.cpp firebird/trunk/src/jrd/UserManagement.cpp firebird/trunk/src/jrd/UserManagement.h firebird/trunk/src/jrd/dyn.epp firebird/trunk/src/jrd/jrd.cpp firebird/trunk/src/jrd/svc.cpp firebird/trunk/src/jrd/trace/TraceManager.cpp firebird/trunk/src/remote/client/interface.cpp firebird/trunk/src/remote/server/os/posix/inet_server.cpp firebird/trunk/src/remote/server/os/win32/srvr_w32.cpp firebird/trunk/src/remote/server/server.cpp 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/gstat/dba.epp firebird/trunk/src/yvalve/MasterImplementation.cpp firebird/trunk/src/yvalve/PluginManager.cpp firebird/trunk/src/yvalve/PluginManager.h firebird/trunk/src/yvalve/alt.cpp firebird/trunk/src/yvalve/why.cpp Added Paths: ----------- firebird/trunk/src/auth/SecurityDatabase/LegacyServer.cpp firebird/trunk/src/auth/SecurityDatabase/LegacyServer.h firebird/trunk/src/common/classes/GetPlugins.h firebird/trunk/src/common/security.cpp firebird/trunk/src/common/security.h Removed Paths: ------------- firebird/trunk/src/auth/SecurityDatabase/jrd_pwd.h firebird/trunk/src/auth/SecurityDatabase/pwd.cpp firebird/trunk/src/utilities/gsec/secur_proto.h firebird/trunk/src/utilities/gsec/security.cpp Modified: firebird/trunk/builds/posix/make.shared.variables =================================================================== --- firebird/trunk/builds/posix/make.shared.variables 2011-03-02 12:25:11 UTC (rev 52491) +++ firebird/trunk/builds/posix/make.shared.variables 2011-03-02 13:42:56 UTC (rev 52492) @@ -36,7 +36,8 @@ GPRE_Common_Objects:= $(call dirObjects,gpre) $(call makeObjects,gpre/languages,@GPRE_LANGUAGE_MODULES@) GPRE_std:= $(call dirObjects,gpre/std) GPRE_Objects:= $(GPRE_Common_Objects) $(GPRE_std) -GPRE_boot:= $(call dirObjects,gpre/boot) $(call makeObjects,yvalve,gds.cpp) +GPRE_boot:= $(call dirObjects,gpre/boot) $(call makeObjects,yvalve,gds.cpp) \ + $(call makeObjects,yvalve,MasterImplementation.cpp) $(call makeObjects,yvalve,PluginManager.cpp) GPRE_Boot_Objects:= $(GPRE_Common_Objects) $(GPRE_boot) AllObjects += $(GPRE_Common_Objects) $(GPRE_std) $(GPRE_boot) @@ -50,8 +51,8 @@ # Remote Remote_Common:= $(call dirObjects,remote) -Remote_Server:= $(call dirObjects,remote/server) $(call makeObjects,auth/SecurityDatabase,pwd.cpp) - # legacy security database pwd.cpp should become SA plugin +Remote_Server:= $(call dirObjects,remote/server) $(call makeObjects,auth/SecurityDatabase,LegacyServer.cpp) + # legacy security database LegacyServer.cpp should become SA plugin Remote_Client:= $(call dirObjects,remote/client) $(call makeObjects,auth/SecurityDatabase,LegacyClient.cpp) Remote_Server_Objects:= $(Remote_Common) $(Remote_Server) Remote_Client_Objects:= $(Remote_Common) $(Remote_Client) Modified: firebird/trunk/src/auth/AuthInterface.h =================================================================== --- firebird/trunk/src/auth/AuthInterface.h 2011-03-02 12:25:11 UTC (rev 52491) +++ firebird/trunk/src/auth/AuthInterface.h 2011-03-02 13:42:56 UTC (rev 52492) @@ -31,10 +31,6 @@ #include "FirebirdPluginApi.h" -// This is temporal measure - see later -struct internal_user_data; -#include "../utilities/gsec/secur_proto.h" - namespace Firebird { class Status; } @@ -81,16 +77,79 @@ }; #define FB_AUTH_CLIENT_VERSION (FB_PLUGIN_VERSION + 3) +class UserField : public Firebird::Interface +{ +public: + virtual int FB_CARG entered() = 0; + virtual int FB_CARG specified() = 0; + virtual void FB_CARG setEntered(int newValue) = 0; +}; +#define FB_USER_FIELD_VERSION (FB_INTERFACE_VERSION + 3) + +class CharUserField : public UserField +{ +public: + virtual const char* FB_CARG get() = 0; + virtual void FB_CARG set(const char* newValue) = 0; +}; +#define FB_AUTH_CHAR_USER_VERSION (FB_USER_FIELD_VERSION + 2) + +class IntUserField : public UserField +{ +public: + virtual int FB_CARG get() = 0; + virtual void FB_CARG set(int newValue) = 0; +}; +#define FB_AUTH_INT_USER_VERSION (FB_USER_FIELD_VERSION + 2) + +class User : public Firebird::Interface +{ +public: + virtual int FB_CARG operation() = 0; + + virtual CharUserField* FB_CARG userName() = 0; + virtual CharUserField* FB_CARG password() = 0; + + virtual CharUserField* FB_CARG firstName() = 0; + virtual CharUserField* FB_CARG lastName() = 0; + virtual CharUserField* FB_CARG middleName() = 0; + virtual CharUserField* FB_CARG groupName() = 0; + + virtual IntUserField* FB_CARG uid() = 0; + virtual IntUserField* FB_CARG gid() = 0; + virtual IntUserField* FB_CARG admin() = 0; + + virtual void FB_CARG clear() = 0; +}; +#define FB_AUTH_USER_VERSION (FB_INTERFACE_VERSION + 11) + +class ListUsers : public Firebird::Interface +{ +public: + virtual void FB_CARG list(User* user) = 0; +}; +#define FB_AUTH_LIST_USERS_VERSION (FB_INTERFACE_VERSION + 1) + +class LogonInfo : public Firebird::Interface +{ +public: + virtual const char* FB_CARG name() = 0; + virtual const char* FB_CARG role() = 0; + virtual int FB_CARG forceAdmin() = 0; + virtual const char* FB_CARG networkProtocol() = 0; + virtual const char* FB_CARG remoteAddress() = 0; +}; +#define FB_AUTH_LOGON_INFO_VERSION (FB_INTERFACE_VERSION + 5) + class Management : public Firebird::Plugin { public: - // work in progress - we must avoid both internal_user_data and callback function - virtual int FB_CARG execLine(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) = 0; + virtual void FB_CARG start(Firebird::Status* status, LogonInfo* logonInfo) = 0; + virtual int FB_CARG execute(Firebird::Status* status, User* user, ListUsers* callback) = 0; + virtual void FB_CARG commit(Firebird::Status* status) = 0; + virtual void FB_CARG rollback(Firebird::Status* status) = 0; }; -#define FB_AUTH_MANAGE_VERSION (FB_PLUGIN_VERSION + 1) +#define FB_AUTH_MANAGE_VERSION (FB_PLUGIN_VERSION + 4) } // namespace Auth Modified: firebird/trunk/src/auth/SecurityDatabase/LegacyManagement.epp =================================================================== --- firebird/trunk/src/auth/SecurityDatabase/LegacyManagement.epp 2011-03-02 12:25:11 UTC (rev 52491) +++ firebird/trunk/src/auth/SecurityDatabase/LegacyManagement.epp 2011-03-02 13:42:56 UTC (rev 52492) @@ -29,7 +29,7 @@ #include <ctype.h> #include "../common/common.h" #include "../jrd/ibase.h" -#include "../auth/SecurityDatabase/jrd_pwd.h" +#include "../auth/SecurityDatabase/LegacyServer.h" #include "../common/enc_proto.h" #include "../yvalve/gds_proto.h" #include "../common/isc_proto.h" @@ -42,34 +42,34 @@ #include "FirebirdPluginApi.h" // Here we use version-independent symbolic link (or copy) of actual database -DATABASE DB = STATIC FILENAME "security.fdb"; +DATABASE database = STATIC FILENAME "security.fdb"; static Firebird::GlobalPtr<Firebird::Mutex> execLineMutex; // protects various gpre generated structures -static bool grantRevokeAdmin(ISC_STATUS* isc_status, FB_API_HANDLE DB, FB_API_HANDLE trans, - const internal_user_data* io_user_data) +static bool grantRevokeAdmin(ISC_STATUS* isc_status, FB_API_HANDLE database, FB_API_HANDLE trans, + Auth::User* user) { - if (!io_user_data->admin_entered) + if (!user->admin()->entered()) { return true; } Firebird::string sql; - sql.printf((io_user_data->admin ? "GRANT %s TO \"%s\"" : "REVOKE %s FROM \"%s\""), - "RDB$ADMIN", io_user_data->user_name); - isc_dsql_execute_immediate(isc_status, &DB, &trans, sql.length(), sql.c_str(), SQL_DIALECT_V6, NULL); + sql.printf((user->admin()->get() ? "GRANT %s TO \"%s\"" : "REVOKE %s FROM \"%s\""), + "RDB$ADMIN", user->userName()->get()); + isc_dsql_execute_immediate(isc_status, &database, &trans, sql.length(), sql.c_str(), SQL_DIALECT_V6, NULL); - if (isc_status[1] && io_user_data->admin == 0) + if (isc_status[1] && user->admin()->get() == 0) { isc_req_handle request = 0; FOR (TRANSACTION_HANDLE trans REQUEST_HANDLE request) R IN RDB$USER_PRIVILEGES - WITH R.RDB$USER EQ io_user_data->user_name + WITH R.RDB$USER EQ user->userName()->get() AND R.RDB$RELATION_NAME EQ 'RDB$ADMIN' AND R.RDB$PRIVILEGE EQ 'M' sql.printf("REVOKE RDB$ADMIN FROM \"%s\" GRANTED BY \"%s\"", - io_user_data->user_name, R.RDB$GRANTOR); + user->userName()->get(), R.RDB$GRANTOR); END_FOR if (request) @@ -81,20 +81,20 @@ } } - isc_dsql_execute_immediate(isc_status, &DB, &trans, sql.length(), sql.c_str(), SQL_DIALECT_V6, NULL); + isc_dsql_execute_immediate(isc_status, &database, &trans, sql.length(), sql.c_str(), SQL_DIALECT_V6, NULL); } return isc_status[1] == 0; } /* -static bool storePasswd(ISC_STATUS* isc_status, FB_API_HANDLE DB, FB_API_HANDLE trans, +static bool storePasswd(ISC_STATUS* isc_status, FB_API_HANDLE database, 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)) + if (!blob.create(database, trans, blobId, sizeof(blob_desc), blob_desc)) { return false; } @@ -108,15 +108,143 @@ } */ -// work in progress - we must avoid both internal_user_data and callback function -int Auth::SecurityDatabaseManagement::execLine(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) +const static unsigned int INIT_KEY = ((~0) - 1); +static unsigned int secDbKey = INIT_KEY; + +namespace Auth { + +SecurityDatabaseManagement::SecurityDatabaseManagement(Firebird::IFactoryParameter* par) + : config(par->getFirebirdConf()), database(0), transaction(0), userName(getPool()) { + config->release(); +} + +void FB_CARG SecurityDatabaseManagement::start(Firebird::Status* st, LogonInfo* logonInfo) +{ + try + { + st->init(); + + if (secDbKey == INIT_KEY) + { + secDbKey = config->getKey("SecurityDatabase"); + } + const char* secDbName = config->asString(secDbKey); + + if (!(secDbName && secDbName[0])) + { + (Firebird::Arg::Gds(isc_random) << "Error getting security database name").raise(); + } + + Firebird::ClumpletWriter dpb(Firebird::ClumpletReader::dpbList, MAX_DPB_SIZE); + dpb.insertByte(isc_dpb_gsec_attach, TRUE); + + const char* str = logonInfo->name(); + if (str && str[0]) + { + dpb.insertString(isc_dpb_trusted_auth, str, strlen(str)); + userName = str; + } + else + { + userName = "<Unknown>"; + } + + str = logonInfo->role(); + if (str && str[0]) + dpb.insertString(isc_dpb_sql_role_name, str, strlen(str)); + else if (logonInfo->forceAdmin()) + dpb.insertString(isc_dpb_trusted_role, ADMIN_ROLE, strlen(ADMIN_ROLE)); + + // Work in progress - should put remote data to DPB !!! + + ISC_STATUS_ARRAY status; + if (isc_attach_database(status, 0, secDbName, &database, + dpb.getBufferLength(), reinterpret_cast<const char*>(dpb.getBuffer()))) + { + Firebird::status_exception::raise(status); + } + + if (isc_start_transaction(status, &transaction, 1, &database, 0, NULL)) + { + Firebird::status_exception::raise(status); + } + } + catch (const Firebird::Exception& ex) + { + ex.stuffException(st); + } +} + +void FB_CARG SecurityDatabaseManagement::commit(Firebird::Status* st) +{ + try + { + st->init(); + + ISC_STATUS_ARRAY status; + if (transaction) + { + if (isc_commit_transaction(status, &transaction)) + { + Firebird::status_exception::raise(status); + } + } + } + catch (const Firebird::Exception& ex) + { + ex.stuffException(st); + } +} + +void FB_CARG SecurityDatabaseManagement::rollback(Firebird::Status* st) +{ + try + { + st->init(); + + ISC_STATUS_ARRAY status; + if (transaction) + { + if (isc_rollback_transaction(status, &transaction)) + { + Firebird::status_exception::raise(status); + } + } + } + catch (const Firebird::Exception& ex) + { + ex.stuffException(st); + } +} + +int FB_CARG SecurityDatabaseManagement::release() +{ + if (--refCounter == 0) + { + ISC_STATUS_ARRAY status; + if (transaction) + isc_rollback_transaction(status, &transaction); + if (database) + isc_detach_database(status, &database); + + delete this; + return 0; + } + + return 1; +} + +#define STR_STORE(to, from) strStore(to, from, sizeof(to)) + +static inline void strStore(char* to, const char* from, size_t len) +{ + to[--len] = '\0'; + strncpy(to, from, len); +} + +int FB_CARG SecurityDatabaseManagement::execute(Firebird::Status* st, User* user, ListUsers* callback) +{ /************************************* * * S E C U R I T Y _ e x e c _ l i n e @@ -177,380 +305,346 @@ * -lname <lastname> * **************************************/ - Firebird::MutexLockGuard guard(execLineMutex); - - SCHAR encrypted1[Auth::MAX_PASSWORD_LENGTH + 2]; - Firebird::string encrypted2; - bool found; int ret = 0; - // check for non-printable characters in user name - for (const TEXT* p = io_user_data->user_name; *p; p++) + try { - if (! isprint(*p)) { - return GsecMsg75; // Add special error message for this case ? - } - } + ISC_STATUS_ARRAY isc_status; + fb_utils::init_status(isc_status); + st->init(); - isc_req_handle request = 0; - isc_req_handle request2 = 0; + Firebird::MutexLockGuard guard(execLineMutex); - switch (io_user_data->operation) - { - case MAP_DROP_OPER: - case MAP_SET_OPER: - if (realUser) + SCHAR encrypted1[MAX_PASSWORD_LENGTH + 2]; + Firebird::string encrypted2; + bool found; + + // check for non-printable characters in user name + for (const TEXT* p = user->userName()->get(); *p; p++) { - 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"); - isc_dsql_execute_immediate(isc_status, &DB, &trans, sql.length(), sql.c_str(), 1, NULL); - if (isc_status[1] != 0) + if (!isprint(*p)) { - ret = GsecMsg97; + return GsecMsg75; // Add special error message for this case ? } } - break; - case ADD_OPER: - if (realUser) + + isc_req_handle request = 0; + isc_req_handle request2 = 0; + + switch (user->operation()) { - 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 PLG$USERS USING - strcpy(U.PLG$USER_NAME, io_user_data->user_name); - if (io_user_data->uid_entered) + case MAP_DROP_OPER: + case MAP_SET_OPER: { - U.PLG$UID = io_user_data->uid; - U.PLG$UID.NULL = ISC_FALSE; + Firebird::string sql; + sql.printf("ALTER ROLE RDB$ADMIN %s AUTO ADMIN MAPPING", + user->operation() == MAP_SET_OPER ? "SET" : "DROP"); + isc_dsql_execute_immediate(isc_status, &database, &transaction, sql.length(), sql.c_str(), 1, NULL); + if (isc_status[1] != 0) + { + ret = GsecMsg97; + } } - else - U.PLG$UID.NULL = ISC_TRUE; - if (io_user_data->gid_entered) - { - U.PLG$GID = io_user_data->gid; - U.PLG$GID.NULL = ISC_FALSE; - } - else - U.PLG$GID.NULL = ISC_TRUE; - if (io_user_data->group_name_entered) - { - strcpy(U.PLG$GROUP_NAME, io_user_data->group_name); - U.PLG$GROUP_NAME.NULL = ISC_FALSE; - } - else - U.PLG$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.PLG$PASSWD, encrypted2.c_str()); - U.PLG$PASSWD.NULL = ISC_FALSE; - } - else - U.PLG$PASSWD.NULL = ISC_TRUE; - if (io_user_data->first_name_entered) - { - strcpy(U.PLG$FIRST_NAME, io_user_data->first_name); - U.PLG$FIRST_NAME.NULL = ISC_FALSE; - } - else - U.PLG$FIRST_NAME.NULL = ISC_TRUE; - if (io_user_data->middle_name_entered) - { - strcpy(U.PLG$MIDDLE_NAME, io_user_data->middle_name); - U.PLG$MIDDLE_NAME.NULL = ISC_FALSE; - } - else - U.PLG$MIDDLE_NAME.NULL = ISC_TRUE; - if (io_user_data->last_name_entered) - { - strcpy(U.PLG$LAST_NAME, io_user_data->last_name); - U.PLG$LAST_NAME.NULL = ISC_FALSE; - } - else - U.PLG$LAST_NAME.NULL = ISC_TRUE; - END_STORE - ON_ERROR - ret = GsecMsg19; // gsec - add record error - END_ERROR; - if (ret == 0 && !grantRevokeAdmin(isc_status, DB, trans, io_user_data)) - { - ret = GsecMsg19; // gsec - add record error - } - 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 + case ADD_OPER: + // this checks the "entered" flags for each parameter (except the name) + // and makes all non-entered parameters null valued - found = false; - FOR (TRANSACTION_HANDLE trans REQUEST_HANDLE request) U IN PLG$USERS - WITH U.PLG$USER_NAME EQ io_user_data->user_name - found = true; - MODIFY U USING - if (io_user_data->uid_entered) + STORE (TRANSACTION_HANDLE transaction REQUEST_HANDLE request) U IN PLG$VIEW_USERS USING + STR_STORE(U.PLG$USER_NAME, user->userName()->get()); + if (user->uid()->entered()) { - U.PLG$UID = io_user_data->uid; + U.PLG$UID = user->uid()->get(); U.PLG$UID.NULL = ISC_FALSE; } - else if (io_user_data->uid_specified) + else U.PLG$UID.NULL = ISC_TRUE; - if (io_user_data->gid_entered) + if (user->gid()->entered()) { - U.PLG$GID = io_user_data->gid; + U.PLG$GID = user->gid()->get(); U.PLG$GID.NULL = ISC_FALSE; } - else if (io_user_data->gid_specified) + else U.PLG$GID.NULL = ISC_TRUE; - if (io_user_data->group_name_entered) + if (user->groupName()->entered()) { - strcpy(U.PLG$GROUP_NAME, io_user_data->group_name); + STR_STORE(U.PLG$GROUP_NAME, user->groupName()->get()); U.PLG$GROUP_NAME.NULL = ISC_FALSE; } - else if (io_user_data->group_name_specified) + else U.PLG$GROUP_NAME.NULL = ISC_TRUE; - if (io_user_data->password_entered) + if (user->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.PLG$PASSWD, encrypted2.c_str()); + ENC_crypt(encrypted1, sizeof encrypted1, user->password()->get(), PASSWORD_SALT); + SecurityDatabase::hash(encrypted2, user->userName()->get(), &encrypted1[2]); + STR_STORE(U.PLG$PASSWD, encrypted2.c_str()); U.PLG$PASSWD.NULL = ISC_FALSE; } - else if (io_user_data->password_specified) + else U.PLG$PASSWD.NULL = ISC_TRUE; - if (io_user_data->first_name_entered) + if (user->firstName()->entered()) { - strcpy(U.PLG$FIRST_NAME, io_user_data->first_name); + STR_STORE(U.PLG$FIRST_NAME, user->firstName()->get()); U.PLG$FIRST_NAME.NULL = ISC_FALSE; } - else if (io_user_data->first_name_specified) + else U.PLG$FIRST_NAME.NULL = ISC_TRUE; - if (io_user_data->middle_name_entered) + if (user->middleName()->entered()) { - strcpy(U.PLG$MIDDLE_NAME, io_user_data->middle_name); + STR_STORE(U.PLG$MIDDLE_NAME, user->middleName()->get()); U.PLG$MIDDLE_NAME.NULL = ISC_FALSE; } - else if (io_user_data->middle_name_specified) + else U.PLG$MIDDLE_NAME.NULL = ISC_TRUE; - if (io_user_data->last_name_entered) + if (user->lastName()->entered()) { - strcpy(U.PLG$LAST_NAME, io_user_data->last_name); + STR_STORE(U.PLG$LAST_NAME, user->lastName()->get()); U.PLG$LAST_NAME.NULL = ISC_FALSE; } - else if (io_user_data->last_name_specified) + else U.PLG$LAST_NAME.NULL = ISC_TRUE; - END_MODIFY + END_STORE ON_ERROR - ret = GsecMsg20; + ret = GsecMsg19; // gsec - add record error END_ERROR; - END_FOR - ON_ERROR - ret = GsecMsg21; - END_ERROR; - if (!ret && !found) - ret = GsecMsg22; - if (ret == 0 && !grantRevokeAdmin(isc_status, DB, trans, io_user_data)) - { - ret = GsecMsg21; - } - break; - - case DEL_OPER: - if (realUser) - { - ret = GsecMsg104; + if (ret == 0 && !grantRevokeAdmin(isc_status, database, transaction, user)) + { + ret = GsecMsg19; // gsec - add record error + } break; - } - // looks up the specified user record and deletes it + case MOD_OPER: + // 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; - // Do not allow SYSDBA user to be deleted - if (!fb_utils::stricmp(io_user_data->user_name, SYSDBA_USER_NAME)) - ret = GsecMsg23; - else - { - FOR (TRANSACTION_HANDLE trans REQUEST_HANDLE request) U IN PLG$USERS - WITH U.PLG$USER_NAME EQ io_user_data->user_name + found = false; + FOR (TRANSACTION_HANDLE transaction REQUEST_HANDLE request) U IN PLG$VIEW_USERS + WITH U.PLG$USER_NAME EQ user->userName()->get() found = true; - ERASE U + MODIFY U USING + if (user->uid()->entered()) + { + U.PLG$UID = user->uid()->get(); + U.PLG$UID.NULL = ISC_FALSE; + } + else if (user->uid()->specified()) + U.PLG$UID.NULL = ISC_TRUE; + if (user->gid()->entered()) + { + U.PLG$GID = user->gid()->get(); + U.PLG$GID.NULL = ISC_FALSE; + } + else if (user->gid()->specified()) + U.PLG$GID.NULL = ISC_TRUE; + if (user->groupName()->entered()) + { + STR_STORE(U.PLG$GROUP_NAME, user->groupName()->get()); + U.PLG$GROUP_NAME.NULL = ISC_FALSE; + } + else if (user->groupName()->specified()) + U.PLG$GROUP_NAME.NULL = ISC_TRUE; + if (user->password()->entered()) + { + ENC_crypt(encrypted1, sizeof encrypted1, user->password()->get(), PASSWORD_SALT); + SecurityDatabase::hash(encrypted2, user->userName()->get(), &encrypted1[2]); + STR_STORE(U.PLG$PASSWD, encrypted2.c_str()); + U.PLG$PASSWD.NULL = ISC_FALSE; + } + else if (user->password()->specified()) + U.PLG$PASSWD.NULL = ISC_TRUE; + if (user->firstName()->entered()) + { + STR_STORE(U.PLG$FIRST_NAME, user->firstName()->get()); + U.PLG$FIRST_NAME.NULL = ISC_FALSE; + } + else if (user->firstName()->specified()) + U.PLG$FIRST_NAME.NULL = ISC_TRUE; + if (user->middleName()->entered()) + { + STR_STORE(U.PLG$MIDDLE_NAME, user->middleName()->get()); + U.PLG$MIDDLE_NAME.NULL = ISC_FALSE; + } + else if (user->middleName()->specified()) + U.PLG$MIDDLE_NAME.NULL = ISC_TRUE; + if (user->lastName()->entered()) + { + STR_STORE(U.PLG$LAST_NAME, user->lastName()->get()); + U.PLG$LAST_NAME.NULL = ISC_FALSE; + } + else if (user->lastName()->specified()) + U.PLG$LAST_NAME.NULL = ISC_TRUE; + END_MODIFY ON_ERROR - ret = GsecMsg23; // gsec - delete record error + ret = GsecMsg20; END_ERROR; END_FOR ON_ERROR - ret = GsecMsg24; // gsec - find/delete record error + ret = GsecMsg21; END_ERROR; - } + if (!ret && !found) + ret = GsecMsg22; + if (ret == 0 && !grantRevokeAdmin(isc_status, database, transaction, user)) + { + ret = GsecMsg21; + } + break; - if (!ret && !found) - ret = GsecMsg22; // gsec - record not found for user: + case DEL_OPER: + // looks up the specified user record and deletes it - io_user_data->admin = 0; - io_user_data->admin_entered = true; - if (ret == 0 && ! grantRevokeAdmin(isc_status, DB, trans, io_user_data)) - { - ret = GsecMsg24; - } - break; - - case DIS_OPER: - case OLD_DIS_OPER: - if (realUser) - { - if (io_user_data->user_name_entered && strcmp(realUser, io_user_data->user_name)) + found = false; + // Do not allow SYSDBA user to be deleted + if (!fb_utils::stricmp(user->userName()->get(), SYSDBA_USER_NAME)) + ret = GsecMsg23; + else { - ret = GsecMsg104; - break; + FOR (TRANSACTION_HANDLE transaction REQUEST_HANDLE request) U IN PLG$VIEW_USERS + WITH U.PLG$USER_NAME EQ user->userName()->get() + found = true; + ERASE U + ON_ERROR + ret = GsecMsg23; // gsec - delete record error + END_ERROR; + END_FOR + ON_ERROR + ret = GsecMsg24; // gsec - find/delete record error + END_ERROR; } - if (!io_user_data->user_name_entered) + + if (!ret && !found) + ret = GsecMsg22; // gsec - record not found for user: + + user->admin()->set(0); + user->admin()->setEntered(1); + if (ret == 0 && !grantRevokeAdmin(isc_status, database, transaction, user)) { - 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; + ret = GsecMsg24; } - } + break; - // gets either the desired record, or all records, and displays them + case DIS_OPER: + case OLD_DIS_OPER: + // 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 PLG$USERS - io_user_data->uid = U.PLG$UID; - io_user_data->uid_entered = !U.PLG$UID.NULL; - io_user_data->gid = U.PLG$GID; - io_user_data->gid_entered = !U.PLG$GID.NULL; - strcpy(io_user_data->user_name, U.PLG$USER_NAME); - io_user_data->user_name_entered = !U.PLG$USER_NAME.NULL; - strcpy(io_user_data->group_name, U.PLG$GROUP_NAME); - io_user_data->group_name_entered = !U.PLG$GROUP_NAME.NULL; - io_user_data->password[0] = 0; - io_user_data->password_entered = false; - strcpy(io_user_data->first_name, U.PLG$FIRST_NAME); - io_user_data->first_name_entered = !U.PLG$FIRST_NAME.NULL; - strcpy(io_user_data->middle_name, U.PLG$MIDDLE_NAME); - io_user_data->middle_name_entered = !U.PLG$MIDDLE_NAME.NULL; - strcpy(io_user_data->last_name, U.PLG$LAST_NAME); - io_user_data->last_name_entered = !U.PLG$LAST_NAME.NULL; + found = false; + if (!user->userName()->entered()) + { + FOR (TRANSACTION_HANDLE transaction REQUEST_HANDLE request) U IN PLG$VIEW_USERS + user->uid()->set(U.PLG$UID); + user->uid()->setEntered(U.PLG$UID.NULL ? 0 : 1); + user->gid()->set(U.PLG$GID); + user->gid()->setEntered(U.PLG$GID.NULL ? 0 : 1); + user->userName()->set(U.PLG$USER_NAME); + user->userName()->setEntered(U.PLG$USER_NAME.NULL ? 0 : 1); + user->groupName()->set(U.PLG$GROUP_NAME); + user->groupName()->setEntered(U.PLG$GROUP_NAME.NULL ? 0 : 1); + user->password()->set(""); + user->password()->setEntered(0); + user->firstName()->set(U.PLG$FIRST_NAME); + user->firstName()->setEntered(U.PLG$FIRST_NAME.NULL ? 0 : 1); + user->middleName()->set(U.PLG$MIDDLE_NAME); + user->middleName()->setEntered(U.PLG$MIDDLE_NAME.NULL ? 0 : 1); + user->lastName()->set(U.PLG$LAST_NAME); + user->lastName()->setEntered(U.PLG$LAST_NAME.NULL ? 0 : 1); - io_user_data->admin = 0; - FOR (TRANSACTION_HANDLE trans REQUEST_HANDLE request2) P IN RDB$USER_PRIVILEGES - WITH P.RDB$USER EQ U.PLG$USER_NAME - AND P.RDB$RELATION_NAME EQ 'RDB$ADMIN' - AND P.RDB$PRIVILEGE EQ 'M' - io_user_data->admin = 1; + user->admin()->set(0); + FOR (TRANSACTION_HANDLE transaction REQUEST_HANDLE request2) P IN RDB$USER_PRIVILEGES + WITH P.RDB$USER EQ U.PLG$USER_NAME + AND P.RDB$RELATION_NAME EQ 'RDB$ADMIN' + AND P.RDB$PRIVILEGE EQ 'M' + user->admin()->set(1); + END_FOR + + callback->list(user); + + found = true; END_FOR + ON_ERROR + ret = GsecMsg28; // gsec - find/display record error + END_ERROR; + } + else + { + FOR (TRANSACTION_HANDLE transaction REQUEST_HANDLE request) U IN PLG$VIEW_USERS + WITH U.PLG$USER_NAME EQ user->userName()->get() + user->uid()->set(U.PLG$UID); + user->uid()->setEntered(U.PLG$UID.NULL ? 0 : 1); + user->gid()->set(U.PLG$GID); + user->gid()->setEntered(U.PLG$GID.NULL ? 0 : 1); + user->userName()->set(U.PLG$USER_NAME); + user->userName()->setEntered(U.PLG$USER_NAME.NULL ? 0 : 1); + user->groupName()->set(U.PLG$GROUP_NAME); + user->groupName()->setEntered(U.PLG$GROUP_NAME.NULL ? 0 : 1); + user->password()->set(""); + user->password()->setEntered(0); + user->firstName()->set(U.PLG$FIRST_NAME); + user->firstName()->setEntered(U.PLG$FIRST_NAME.NULL ? 0 : 1); + user->middleName()->set(U.PLG$MIDDLE_NAME); + user->middleName()->setEntered(U.PLG$MIDDLE_NAME.NULL ? 0 : 1); + user->lastName()->set(U.PLG$LAST_NAME); + user->lastName()->setEntered(U.PLG$LAST_NAME.NULL ? 0 : 1); - display_func(callback_arg, io_user_data, !found); + user->admin()->set(0); + FOR (TRANSACTION_HANDLE transaction REQUEST_HANDLE request2) P IN RDB$USER_PRIVILEGES + WITH P.RDB$USER EQ U.PLG$USER_NAME + AND P.RDB$RELATION_NAME EQ 'RDB$ADMIN' + AND P.RDB$PRIVILEGE EQ 'M' + user->admin()->set(1); + END_FOR - found = true; - END_FOR - ON_ERROR - ret = GsecMsg28; // gsec - find/display record error - END_ERROR; - } - else - { - FOR (TRANSACTION_HANDLE trans REQUEST_HANDLE request) U IN PLG$USERS - WITH U.PLG$USER_NAME EQ io_user_data->user_name - io_user_data->uid = U.PLG$UID; - io_user_data->uid_entered = !U.PLG$UID.NULL; - io_user_data->gid = U.PLG$GID; - io_user_data->gid_entered = !U.PLG$GID.NULL; - strcpy(io_user_data->user_name, U.PLG$USER_NAME); - io_user_data->user_name_entered = !U.PLG$USER_NAME.NULL; - strcpy(io_user_data->group_name, U.PLG$GROUP_NAME); - io_user_data->group_name_entered = !U.PLG$GROUP_NAME.NULL; - io_user_data->password[0] = 0; - io_user_data->password_entered = false; - strcpy(io_user_data->first_name, U.PLG$FIRST_NAME); - io_user_data->first_name_entered = !U.PLG$FIRST_NAME.NULL; - strcpy(io_user_data->middle_name, U.PLG$MIDDLE_NAME); - io_user_data->middle_name_entered = !U.PLG$MIDDLE_NAME.NULL; - strcpy(io_user_data->last_name, U.PLG$LAST_NAME); - io_user_data->last_name_entered = !U.PLG$LAST_NAME.NULL; + callback->list(user); - io_user_data->admin = 0; - FOR (TRANSACTION_HANDLE trans REQUEST_HANDLE request2) P IN RDB$USER_PRIVILEGES - WITH P.RDB$USER EQ U.PLG$USER_NAME - AND P.RDB$RELATION_NAME EQ 'RDB$ADMIN' - AND P.RDB$PRIVILEGE EQ 'M' - io_user_data->admin = 1; + found = true; END_FOR + ON_ERROR + ret = GsecMsg28; // gsec - find/display record error + END_ERROR; + } + break; - display_func(callback_arg, io_user_data, !found); - - found = true; - END_FOR - ON_ERROR - ret = GsecMsg28; // gsec - find/display record error - END_ERROR; + default: + ret = GsecMsg16; // gsec - error in switch specifications + break; } - break; - default: - ret = GsecMsg16; // gsec - error in switch specifications - break; - } - - if (request) - { - ISC_STATUS_ARRAY s; - if (isc_release_request(s, &request) != FB_SUCCESS) + if (request) { - if (! ret) + ISC_STATUS_ARRAY s; + if (isc_release_request(s, &request) != FB_SUCCESS) { - ret = GsecMsg94; // error releasing request in security database + if (! ret) + { + ret = GsecMsg94; // error releasing request in security database + } } } - } - if (request2) - { - ISC_STATUS_ARRAY s; - if (isc_release_request(s, &request2) != FB_SUCCESS) + if (request2) { - if (! ret) + ISC_STATUS_ARRAY s; + if (isc_release_request(s, &request2) != FB_SUCCESS) { - ret = GsecMsg94; // error releasing request in security database + if (! ret) + { + ret = GsecMsg94; // error releasing request in security database + } } } + + st->set(isc_status); } + catch (const Firebird::Exception& ex) + { + ex.stuffException(st); + } return ret; } -int Auth::SecurityDatabaseManagement::release() -{ - if (--refCounter == 0) - { - delete this; - return 0; - } +} // namespace Auth - return 1; -} - // register plugin static Firebird::SimpleFactory<Auth::SecurityDatabaseManagement> factory; Modified: firebird/trunk/src/auth/SecurityDatabase/LegacyManagement.h =================================================================== --- firebird/trunk/src/auth/SecurityDatabase/LegacyManagement.h 2011-03-02 12:25:11 UTC (rev 52491) +++ firebird/trunk/src/auth/SecurityDatabase/LegacyManagement.h 2011-03-02 13:42:56 UTC (rev 52492) @@ -36,17 +36,19 @@ class SecurityDatabaseManagement : public Firebird::StdPlugin<Management, FB_AUTH_MANAGE_VERSION> { public: - explicit SecurityDatabaseManagement(Firebird::IFactoryParameter*) - { - } + explicit SecurityDatabaseManagement(Firebird::IFactoryParameter* par); - // work in progress - we must avoid both internal_user_data and callback function - int FB_CARG execLine(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); + void FB_CARG start(Firebird::Status* status, LogonInfo* logonInfo); + int FB_CARG execute(Firebird::Status* status, User* user, ListUsers* callback); + void FB_CARG commit(Firebird::Status* status); + void FB_CARG rollback(Firebird::Status* status); int FB_CARG release(); + +private: + Firebird::RefPtr<Firebird::IFirebirdConf> config; + FB_API_HANDLE database, transaction; + Firebird::string userName; }; } // namespace Auth Copied: firebird/trunk/src/auth/SecurityDatabase/LegacyServer.cpp (from rev 52312, firebird/trunk/src/auth/SecurityDatabase/pwd.cpp) =================================================================== --- firebird/trunk/src/auth/SecurityDatabase/LegacyServer.cpp (rev 0) +++ firebird/trunk/src/auth/SecurityDatabase/LegacyServer.cpp 2011-03-02 13:42:56 UTC (rev 52492) @@ -0,0 +1,577 @@ +/* + * PROGRAM: JRD Access Method + * MODULE: pwd.cpp + * DESCRIPTION: User information database access + * + * The contents of this file are subject to the Interbase 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.Inprise.com/IPL.html + * + * Software distributed under the License is distributed on an + * "AS IS" basis, 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 Inprise Corporation + * and its predecessors. Portions created by Inprise Corporation are + * Copyright (C) Inprise Corporation. + * + * All Rights Reserved. + * Contributor(s): ______________________________________. + * + * 2003.02.02 Dmitry Yemanov: Implemented cached security database connection + */ + +#include "firebird.h" +#include <string.h> +#include <stdlib.h> +#include <time.h> +#include "../common/common.h" +#include "../jrd/ibase.h" +#include "../jrd/jrd.h" +#include "../auth/SecurityDatabase/LegacyServer.h" +#include "../common/enc_proto.h" +#include "../jrd/err_proto.h" +#include "../yvalve/gds_proto.h" +#include "../common/isc_proto.h" +#include "../jrd/thread_proto.h" +#include "../jrd/jrd_proto.h" +#include "../jrd/scl.h" +#include "../common/config/config.h" +#include "../common/classes/objects_array.h" +#include "../common/classes/init.h" +#include "../common/classes/ImplementHelper.h" + +using namespace Firebird; + +namespace { + +// temporal implementation of timer + +GlobalPtr<Mutex> timerMutex; +FPTR_VOID_PTR toRun = 0; +unsigned int cnt = 0; + +int active = 0; + +int stopTimer(const int, const int mask, void*) +{ + switch(mask) + { + case fb_shut_preproviders: + active = 2; + break; + case fb_shut_finish: + while (active == 2) + { + THREAD_SLEEP(10); + } + break; + } + + return 0; +} + +THREAD_ENTRY_DECLARE threadTimer(THREAD_ENTRY_PARAM) +{ + while (active == 1) + { + { // scope + MutexLockGuard g(timerMutex); + if (cnt == 0) + { + if (toRun) + { + toRun(0); + toRun = 0; + } + } + else + { + --cnt; + } + } + + THREAD_SLEEP(100); + } + + active = 3; + return 0; +} + +int fb_alloc_timer() +{ + if (! active) + { + active = 1; + Thread::start(threadTimer, 0, 0); + fb_shutdown_callback(0, stopTimer, fb_shut_preproviders | fb_shut_finish, 0); + } + + return 1; +} + +void fb_thread_timer(int, int delay, FPTR_VOID_PTR function, void*) +{ + MutexLockGuard g(timerMutex); + + cnt = delay / 100; + if (! cnt) + { + cnt = 1; + } + + toRun = function; +} + +// BLR to search database for user name record + +const UCHAR PWD_REQUEST[] = +{ + blr_version5, + blr_begin, + blr_message, 1, 4, 0, + blr_long, 0, + blr_long, 0, + blr_short, 0, + blr_text, BLR_WORD(Auth::MAX_PASSWORD_LENGTH + 2), + blr_message, 0, 1, 0, + blr_cstring, 129, 0, + blr_receive, 0, + blr_begin, + blr_for, + blr_rse, 1, + blr_relation, 9, 'P', 'L', 'G', '$', 'U', 'S', 'E', 'R', 'S', 0, + blr_first, + blr_literal, blr_short, 0, 1, 0, + blr_boolean, + blr_eql, + blr_field, 0, 13, 'P', 'L', 'G', '$', 'U', 'S', 'E', 'R', '_', 'N', 'A', 'M', 'E', + blr_parameter, 0, 0, 0, + blr_end, + blr_send, 1, + blr_begin, + blr_assignment, + blr_field, 0, 7, 'P', 'L', 'G', '$', 'G', 'I', 'D', + blr_parameter, 1, 0, 0, + blr_assignment, + blr_field, 0, 7, 'P', 'L', 'G', '$', 'U', 'I', 'D', + blr_parameter, 1, 1, 0, + blr_assignment, + blr_literal, blr_short, 0, 1, 0, + blr_parameter, 1, 2, 0, + blr_assignment, + blr_field, 0, 10, 'P', 'L', 'G', '$', 'P', 'A', 'S', 'S', 'W', 'D', + blr_parameter, 1, 3, 0, + blr_end, + blr_send, 1, + blr_assignment, + blr_literal, blr_short, 0, 0, 0, + blr_parameter, 1, 2, 0, + blr_end, + blr_end, + blr_eoc +}; + +// Returns data in the following format + +struct user_record +{ + SLONG gid; + SLONG uid; + SSHORT flag; + SCHAR password[Auth::MAX_PASSWORD_LENGTH + 2]; +}; + +// Transaction parameter buffer + +const UCHAR TPB[4] = +{ + isc_tpb_version1, + isc_tpb_read, + isc_tpb_concurrency, + isc_tpb_wait +}; + +int timer = 0; + +} // anonymous + +namespace Auth { + +/****************************************************************************** + * + * Private interface + */ + +void SecurityDatabase::fini() +{ + isc_db_handle tmp = 0; + + { // scope + MutexLockGuard guard(mutex); + + if (lookup_req) + { + isc_release_request(status, &lookup_req); + checkStatus("isc_release_request"); + } + + tmp = lookup_db; + lookup_db = 0; + } + + if (tmp) + { + isc_detach_database(status, &tmp); + checkStatus("isc_detach_database"); + } +} + +void SecurityDatabase::init() +{ + if (! timer) + { + timer = fb_alloc_timer(); + } +} + +bool SecurityDatabase::lookup_user(const char* user_name, char* pwd) +{ + bool found = false; // user found flag + char uname[129]; // user name buffer + user_record user; // user record + + // Start by clearing the output data + + if (pwd) + *pwd = '\0'; + + strncpy(uname, user_name, sizeof uname); + uname[sizeof uname - 1] = 0; + + MutexLockGuard guard(mutex); + + // Attach database and compile request + + prepare(); + + // Lookup + + isc_tr_handle lookup_trans = 0; + + isc_start_transaction(status, &lookup_trans, 1, &lookup_db, sizeof(TPB), TPB); + checkStatus("isc_start_transaction", isc_psw_start_trans); + + isc_start_and_send(status, &lookup_req, &lookup_trans, 0, sizeof(uname), uname, 0); + checkStatus("isc_start_and_send"); + + while (true) + { + isc_receive(status, &lookup_req, 1, sizeof(user), &user, 0); + checkStatus("isc_receive"); + + if (!user.flag || status[1]) + break; + + found = true; + + if (pwd) + { + strncpy(pwd, user.password, MAX_PASSWORD_LENGTH); + pwd[MAX_PASSWORD_LENGTH] = 0; + } + } + + isc_rollback_transaction(status, &lookup_trans); + checkStatus("isc_rollback_transaction"); + + return found; +} + +void SecurityDatabase::prepare() +{ + if (lookup_db) + { + return; + } + + init(); + + lookup_db = lookup_req = 0; + + // Perhaps build up a dpb + ClumpletWriter dpb(ClumpletReader::Tagged, MAX_DPB_SIZE, isc_dpb_version1); + + // Attachment is for the security database + dpb.insertByte(isc_dpb_sec_attach, TRUE); + + // Attach as SYSDBA + dpb.insertString(isc_dpb_trusted_auth, SYSDBA_USER_NAME, strlen(SYSDBA_USER_NAME)); + + isc_db_handle tempHandle = 0; + isc_attach_database(status, 0, secureDbName, &tempHandle, + dpb.getBufferLength(), reinterpret_cast<const char*>(dpb.getBuffer())); + checkStatus("isc_attach_database", isc_psw_attach); + lookup_db = tempHandle; + + isc_compile_request(status, &lookup_db, &lookup_req, sizeof(PWD_REQUEST), + reinterpret_cast<const char*>(PWD_REQUEST)); + if (status[1]) + { + ISC_STATUS_ARRAY localStatus; + // ignore status returned in order to keep first error + isc_detach_database(localStatus, &lookup_db); + } + + checkStatus("isc_compile_request", isc_psw_attach); +} + +/****************************************************************************** + * + * Public interface + */ + +Result SecurityDatabase::verify(WriterInterface* authBlock, + ClumpletReader& originalDpb) +{ + static AmCache useNative = AM_UNKNOWN; + + if (useNative == AM_UNKNOWN) + { + // We use PathName for string comparison using platform filename comparison + // rules (case-sensitive or case-insensitive). + const PathName authMethod(Config::getAuthMethod()); + useNative = (authMethod == AmNative || authMethod == AmMixed) ? AM_ENABLED : AM_DISABLED; + } + + if (useNative == AM_DISABLED) + { + return AUTH_CONTINUE; + } + + string login, password, passwordEnc; + + for (originalDpb.rewind(); !originalDpb.isEof(); originalDpb.moveNext()) + { + switch (originalDpb.getClumpTag()) + { + case isc_dpb_user_name: + originalDpb.getString(login); + break; + case isc_dpb_password: + originalDpb.getString(password); + break; + case isc_dpb_password_enc: + originalDpb.getString(passwordEnc); + break; + } + } + + if (login.hasData() && (password.hasData() || passwordEnc.hasData())) + { + login.upper(); + + // Look up the user name in the userinfo database and use the parameters + // found there. This means that another database must be accessed, and + // that means the current context must be saved and restored. + + char pw1[MAX_PASSWORD_LENGTH + 1]; + if (!lookup_user(login.c_str(), pw1)) + { + return AUTH_FAILED; + } + pw1[MAX_PASSWORD_LENGTH] = 0; + string storedHash(pw1, MAX_PASSWORD_LENGTH); + storedHash.rtrim(); + + if (!passwordEnc.hasData()) + { + char pwt[MAX_PASSWORD_LENGTH + 2]; + ENC_crypt(pwt, sizeof pwt, password.c_str(), PASSWORD_SALT); + passwordEnc.assign(&pwt[2]); + } + + string newHash; + hash(newHash, login, passwordEnc, storedHash); + if (newHash != storedHash) + { + bool legacyHash = Config::getLegacyHash(); + if (legacyHash) + { + newHash.resize(MAX_PASSWORD_LENGTH + 2); + ENC_crypt(newHash.begin(), newHash.length(), passwordEnc.c_str(), PASSWORD_SALT); + newHash.recalculate_length(); + newHash.erase(0, 2); + legacyHash = newHash == storedHash; + } + if (!legacyHash) + { + return AUTH_FAILED; + } + } + + authBlock->add(login.c_str(), "SecDB", secureDbName); + return AUTH_SUCCESS; + } + + return AUTH_CONTINUE; +} + +void SecurityDatabase::checkStatus(const char* callName, ISC_STATUS userError) +{ + if (status[1] == 0) + { + return; + } + +#ifdef DEV_BUILD + // throw original status error + status_exception::raise(status); +#else + string message; + message.printf("Error in %s() API call when working with security database", callName); + iscLogStatus(message.c_str(), status); + + // showing real problems with security database to users is not good idea + // from security POV - therefore some generic message is used + Arg::Gds(userError).raise(); +#endif +} + +// TODO - avoid races between timer thread and auth thread +// TODO - account for too old instances and cleanup them +// WHEN - when timer interface is ready +typedef HalfStaticArray<SecurityDatabase*, 4> InstancesArray; +GlobalPtr<InstancesArray> instances; +GlobalPtr<Mutex> instancesMutex; + +void SecurityDatabase::shutdown(void*) +{ + try + { + MutexLockGuard g(instancesMutex); + InstancesArray& curInstances(instances); + for (unsigned int i = 0; i < curInstances.getCount(); ++i) + { + if (curInstances[i]) + { + curInstances[i]->fini(); + delete curInstances[i]; + curInstances[i] = NULL; + } + } + curInstances.clear(); + } + catch (Exception &ex) + { + ISC_STATUS_ARRAY status; + ex.stuff_exception(status); + if (status[0] == 1 && status[1] != isc_att_shutdown) + { + iscLogStatus("Legacy security database shutdown", status); + } + } +} + +const static unsigned int INIT_KEY = ((~0) - 1); +static unsigned int secDbKey = INIT_KEY; + +Result SecurityDatabaseServer::startAuthentication(Firebird::Status* status, + bool isService, const char*, + const unsigned char* dpb, unsigned int dpbSize, + WriterInterface* writerInterface) +{ + status->init(); + + try + { + PathName secDbName; + { // config scope + RefPtr<IFirebirdConf> config(iParameter->getFirebirdConf()); + config->release(); + + if (secDbKey == INIT_KEY) + { + secDbKey = config->getKey("SecurityDatabase"); + } + const char* tmp = config->asString(secDbKey); + if (!tmp) + { + (Arg::Gds(isc_random) << "Error getting security database name").raise(); + } + + secDbName = tmp; + } + + SecurityDatabase* instance = 0; + + fb_thread_timer(timer, 10000, SecurityDatabase::shutdown, 0); + { // guard scope + MutexLockGuard g(instancesMutex); + InstancesArray& curInstances(instances); + for (unsigned int i = 0; i < curInstances.getCount(); ++i) + { + if (secDbName == curInstances[i]->secureDbName) + { + instance = curInstances[i]; + break; + } + } + + if (!instance) + { + instance = new SecurityDatabase; + secDbName.copyTo(instance->secureDbName, sizeof(instance->secureDbName)); + curInstances.add(instance); + } + } + + fb_assert(instance); + + ClumpletReader rdr(isService ? ClumpletReader::spbList : ClumpletReader::dpbList, dpb, dpbSize); + return instance->verify(writerInterface, rdr); + } + catch (const Firebird::Exception& ex) + { + ex.stuffException(status); + return AUTH_FAILED; + } +} + +Result SecurityDatabaseServer::contAuthentication(Firebird::Status*, + WriterInterface* /*writerInterface*/, + const unsigned char* /*data*/, unsigned int /*size*/) +{ + return AUTH_FAILED; +} + +void SecurityDatabaseServer::getData(const unsigned char** data, unsigned short* dataSize) +{ + *data = NULL; + *dataSize = 0; +} + +int SecurityDatabaseServer::release() +{ + if (--refCounter == 0) + { + delete this; + return 0; + } + + return 1; +} + +namespace { + Firebird::SimpleFactory<SecurityDatabaseServer> factory; +} + +void registerLegacyServer(Firebird::IPlugin* iPlugin) +{ + factory->addRef(); + iPlugin->registerPlugin(Firebird::PluginType::AuthServer, "Legacy_Auth", &factory); +} + +} // namespace Auth Property changes on: firebird/trunk/src/auth/SecurityDatabase/LegacyServer.cpp ___________________________________________________________________ Added: svn:mime-type + text/plain Added: svn:eol-style + native Copied: firebird/trunk/src/auth/SecurityDatabase/LegacyServer.h (from rev 52312, firebird/trunk/src/auth/SecurityDatabase/jrd_pwd.h) =================================================================== --- firebird/trunk/src/auth/SecurityDatabase/LegacyServer.h (rev 0) +++ firebird/trunk/src/auth/SecurityDatabase/LegacyServer.h 2011-03-02 13:42:56 UTC (rev 52492) @@ -0,0 +1,130 @@ +/* + * PROGRAM: JRD Access Method + * MODULE: jrd_pwd.h + * DESCRIPTION: User information database name + * + * The contents of this file are subject to the Interbase 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.Inprise.com/IPL.html + * + * Software distributed under the License is distributed on an + * "AS IS" basis, 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 Inprise Corporation + * and its predecessors. Portions created by Inprise Corporation are + * Copyright (C) Inprise Corporation. + * + * All Rights Reserved. + * Contributor(s): ______________________________________. + * + * 2002.10.29 Sean Leyne - Removed obsolete "Netware" port + * 2003.02.02 Dmitry Yemanov: Implemented cached security database connection + */ + +#ifndef AUTH_LEGACY_SERVER_H +#define AUTH_LEGACY_SERVER_H + +#include "../jrd/ibase.h" +#include "../common/utils_proto.h" +#include "../common/sha.h" +#include "gen/iberror.h" +#include "../common/classes/ClumpletWriter.h" +#include "../common/classes/ImplementHelper.h" + +#include "../auth/AuthInterface.h" + +#ifdef HAVE_STDLIB_H +#include <stdlib.h> +#endif +#include <time.h> + +namespace Auth { + +const size_t MAX_PASSWORD_LENGTH = 64; // used to store passwords internally +static const char* const PASSWORD_SALT = "9z"; // for old ENC_crypt() +const size_t SALT_LENGTH = 12; // measured after base64 coding + +class SecurityDatabase : public Firebird::GlobalStorage +{ +public: + Result verify(WriterInterface* authBlock, + Firebird::ClumpletReader& originalDpb); + + static void shutdown(void*); + + static void hash(Firebird::string& h, const Firebird::string& userName, const TEXT* passwd) + { + Firebird::string salt; + Jrd::CryptSupport::random(salt, SALT_LENGTH); + hash(h, userName, passwd, salt); + } + + static void hash(Firebird::string& h, + const Firebird::string& userName, + const Firebird::string& passwd, + const Firebird::string& oldHash) + { + Firebird::string salt(oldHash); + salt.resize(SALT_LENGTH, '='); + Firebird::string allData(salt); + allData += userName; + allData += passwd; + Jrd::CryptSupport::hash(h, allData); + h = salt + h; + } + + char secureDbName[MAXPATHLEN]; + + SecurityDatabase() + : lookup_db(0), lookup_req(0) + { + } + +private: + Firebird::Mutex mutex; + + ISC_STATUS_ARRAY status; + + isc_db_handle lookup_db; + isc_req_handle lookup_req; + + void init(); + void fini(); + bool lookup_user(const char*, char*); + void prepare(); + void checkStatus(const char* callName, ISC_STATUS userError = isc_psw_db_error); +}; + +class SecurityDatabaseServerFactory : public Firebird::StdIface<Firebird::PluginsFactory, FB_PLUGINS_FACTORY_VERSION> +{ +public: + Firebird::Plugin* FB_CARG createPlugin(const char* name, const char* configFile); +}; + +class SecurityDatabaseServer : public Firebird::StdPlugin<Server, FB_AUTH_SERVER_VERSION> +{ +public: + explicit SecurityDatabaseServer(Firebird::IFactoryParameter* p) + : iParameter(p) + { } + + Result FB_CARG startAuthentication(Firebird::Status* status, bool isService, const char* dbName, + const unsigned char* dpb, unsigned int dpbSize, + WriterInterface* writerInterface); + Result FB_CARG contAuthentication(Firebird::Status* status, WriterInterface* writerInterface, + const unsigned char* data, unsigned int size); + void FB_CARG getData(const unsigned char** data, unsigned short* dataSize); + int FB_CARG release(); + +private: + Firebird::RefPtr<Firebird::IFactoryParameter> iParameter; +}; + +void registerLegacyServer(Firebird::IPlugin* iPlugin); + +} // namespace Auth + +#endif // AUTH_LEGACY_SERVER_H Property changes on: firebird/trunk/src/auth/SecurityDatabase/LegacyServer.h ___________________________________________________________________ Added: svn:mime-type + text/plain Added: svn:eol-style + native Deleted: firebird/trunk/src/auth/SecurityDatabase/jrd_pwd.h =================================================================== --- firebird/trunk/src/auth/SecurityDatabase/jrd_pwd.h 2011-03-02 12:25:11 UTC (rev 52491) +++ firebird/trunk/src/auth/SecurityDatabase/jrd_pwd.h 2011-03-02 13:42:56 UTC (rev 52492) @@ -1,138 +0,0 @@ -/* - * PROGRAM: JRD Access Method - * MODULE: jrd_pwd.h - * DESCRIPTION: User information database name - * - * The contents of this file are subject to the Interbase 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.Inprise.com/IPL.html - * - * Software distributed under the License is distributed on an - * "AS IS" basis, 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 Inprise Corporation - * and its predecessors. Portions created by Inprise Corporation are - * Copyright (C) Inprise Corporation. - * - * All Rights Reserved. - * Contributor(s): ______________________________________. - * - * 2002.10.29 Sean Leyne - Removed obsolete "Netware" port - * 2003.02.02 Dmitry Yemanov: Implemented cached security database connection - */ - -#ifndef JRD_PWD_H -#define JRD_PWD_H - -#include "../jrd/ibase.h" -#include "../common/utils_proto.h" -#include "../common/sha.h" -#include "gen/iberror.h" -#include "../common/classes/ClumpletWriter.h" -#include "../common/classes/ImplementHelper.h" - -#include "../auth/AuthInterface.h" - -#ifdef HAVE_STDLIB_H -#include <stdlib.h> -#endif -#include <time.h> - -namespace Auth { - -const size_t MAX_PASSWORD_ENC_LENGTH = 12; // passed by remote protocol -const size_t MAX_PASSWORD_LENGTH = 64; // used to store passwords internally -static const char* const PASSWORD_SALT = "9z"; // for old ENC_crypt() -const size_t SALT_LENGTH = 12; // measured after base64 coding - -class SecurityDatabase -{ -public: - static void getPath(char* path_buffer) - { - static const char* USER_INFO_NAME = "security3.fdb"; - Firebird::PathName name = fb_utils::getPrefix(fb_utils::FB_DIR_SECDB, USER_INFO_NAME); - name.copyTo(path_buffer, MAXPATHLEN); - } - - static Result verify(WriterInterface* authBlock, - Firebird::ClumpletReader& originalDpb); - - static void shutdown(void*); - - static void hash(Firebird::string& h, const Firebird::string& userName, const TEXT* passwd) - { - Firebird::string salt; - Jrd::CryptSupport::random(salt, SALT_LENGTH); - hash(h, userName, passwd, salt); - } - - static void hash(Firebird::string& h, - const Firebird::string& userName, - const Firebird::string& passwd, - const Firebird::string& oldHash) - { - Firebird::string salt(oldHash); - salt.resize(SALT_LENGTH, '='); - Firebird::string allData(salt); - allData += userName; - allData += passwd; - Jrd::CryptSupport::hash(h, allData); - h = salt + h; - } - -private: - Firebird::Mutex mutex; - - ISC_STATUS_ARRAY status; - - isc_db_handle lookup_db; - isc_req_handle lookup_req; - - int timer; - char user_info_name[MAXPATHLEN]; - - void init(); - void fini(); - bool lookup_user(const char*, char*); - void prepare(); - void checkStatus(const char* callName, ISC_STATUS userError = isc_psw_db_error); - - static SecurityDatabase instance; - - SecurityDatabase() - : lookup_db(0), lookup_req(0), timer(0) - { - } -}; - -class SecurityDatabaseServerFactory : public Firebird::StdIface<Firebird::PluginsFactory, FB_PLUGINS_FACTORY_VERSION> -{ -public: - Firebird::Plugin* FB_CARG createPlugin(const char* name, const char* configFile); -}; - -class SecurityDatabaseServer : public Firebird::StdPlugin<Server, FB_AUTH_SERVER_VERSION> -{ -public: - explicit SecurityDatabaseServer(Firebird::IFactoryParameter*) - { - } - - Result FB_CARG startAuthentication(Firebird::Status* status, bool isService, const char* dbName, - const unsigned char* dpb, unsigned int dpbSize, - WriterInterface* writerInterface); - Result FB_CARG contAuthentication(Firebird::Status* status, WriterInterface* writerInterface, - const unsigned char* data, unsigned int size); - void FB_CARG getData(const unsigned char** data, unsigned short* dataSize); - int FB_CARG release(); -}; - -void registerLegacyServer(Firebird::IPlugin* iPlugin); - -} // namespace Auth - -#endif // JRD_PWD_H Deleted: firebird/trunk/src/auth/SecurityDatabase/pwd.cpp =================================================================== --- firebird/trunk/src/auth/SecurityDatabase/pwd.cpp 2011-03-02 12:25:11 UTC (rev 52491) +++ firebird/trunk/src/auth/SecurityDatabase/pwd.cpp 2011-03-02 13:42:56 UTC (rev 52492) @@ -1,516 +0,0 @@ -/* - * PROGRAM: JRD Access Method - * MODULE: pwd.cpp - * DESCRIPTION: User information database access - * - * The contents of this file are subject to the Interbase 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.Inprise.com/IPL.html - * - * Software distributed under the License is distributed on an - * "AS IS" basis, 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 Inprise Corporation - * and its predecessors. Portions created by Inprise Corporation are - * Copyright (C) Inprise Corporation. - * - * All Rights Reserved. - * Contributor(s): ______________________________________. - * - * 2003.02.02 Dmitry Yemanov: Implemented cached security database connection - */ - -#include "firebird.h" -#include <string.h> -#include <stdlib.h> -#include <time.h> -#include "../common/common.h" -#include "../jrd/ibase.h" -#include "../jrd/jrd.h" -#include "../auth/SecurityDatabase/jrd_pwd.h" -#include "../common/enc_proto.h" -#include "../jrd/err_proto.h" -#include "../yvalve/gds_proto.h" -#include "../common/isc_proto.h" -#include "../jrd/thread_proto.h" -#include "../jrd/jrd_proto.h" -#include "../jrd/scl.h" -#include "../common/config/config.h" -#include "../common/classes/objects_array.h" -#include "../common/classes/init.h" -#include "../common/classes/ImplementHelper.h" - -using namespace Firebird; - -namespace { - -// temporal implementation of timer - -GlobalPtr<Mutex> timerMutex; -FPTR_VOID_PTR toRun = 0; -unsigned int cnt = 0; - -int active = 0; - -int stopTimer(const int, const int mask, void*) -{ - switch(mask) - { - case fb_shut_preproviders: - active = 2; - break; - case fb_shut_finish: - while (active == 2) - { - THREAD_SLEEP(10); - } - break; - } - ... [truncated message content] |