From 86367ced07e5ff7fedaed189d3c808f1f200517d Mon Sep 17 00:00:00 2001 From: alexpeshkoff Date: Wed, 27 Feb 2008 12:56:57 +0000 Subject: [PATCH] backported fix for CORE-1421: SuperServer can't shutdown immediately after shutdown request after failed login attempt --- src/jrd/jrd.cpp | 141 ++++++++++++++++++++++++---------------------- src/jrd/jrd_pwd.h | 23 ++++++++ src/jrd/pwd.cpp | 78 ++++++++++++------------- 3 files changed, 133 insertions(+), 109 deletions(-) diff --git a/src/jrd/jrd.cpp b/src/jrd/jrd.cpp index 762a6886cf..2b381f90cb 100644 --- a/src/jrd/jrd.cpp +++ b/src/jrd/jrd.cpp @@ -425,6 +425,11 @@ namespace { enum vdnResult {vdnFail, vdnOk, vdnSecurity}; } static vdnResult verify_database_name(const Firebird::PathName&, ISC_STATUS*); +static ISC_STATUS unwindAttach(const std::exception& ex, + ISC_STATUS* userStatus, + thread_db* tdbb, + Attachment* attachment, + Database* dbb); #if defined (WIN_NT) #ifdef SERVER_SHUTDOWN static void ExtractDriveLetter(const TEXT*, ULONG*); @@ -1337,42 +1342,15 @@ ISC_STATUS GDS_ATTACH_DATABASE(ISC_STATUS* user_status, return return_success(tdbb); } // try + catch (const Jrd::DelayFailedLogin& ex) + { + ISC_STATUS s = unwindAttach(ex, user_status, tdbb, attachment, dbb); + ex.sleep(); + return s; + } catch (const std::exception& ex) { - ISC_STATUS_ARRAY temp_status; - try - { -#if defined(V4_THREADING) && !defined(SUPERSERVER) - if (initing_security) - { - V4_JRD_MUTEX_LOCK(dbb->dbb_mutexes + DBB_MUTX_init_fini); - } -#endif - tdbb->tdbb_status_vector = temp_status; - dbb->dbb_flags &= ~DBB_being_opened; - release_attachment(attachment); - - /* At this point, mutex dbb->dbb_mutexes [DBB_MUTX_init_fini] has been - unlocked and mutex databases_mutex has been locked. */ - if (MemoryPool::blk_type(dbb) == type_dbb) - { - if (!dbb->dbb_attachments) - { - shutdown_database(dbb, true); - } - else if (attachment) - { - delete attachment; - } - } -#if defined(V4_THREADING) && !defined(SUPERSERVER) - V4_JRD_MUTEX_UNLOCK(databases_mutex); -#endif - } // try - catch (const std::exception&) {} - tdbb->tdbb_status_vector = status; - JRD_SS_MUTEX_UNLOCK; - return error(user_status, ex); + return unwindAttach(ex, user_status, tdbb, attachment, dbb); } } @@ -2145,42 +2123,15 @@ ISC_STATUS GDS_CREATE_DATABASE(ISC_STATUS* user_status, return return_success(tdbb); } // try + catch (const Jrd::DelayFailedLogin& ex) + { + ISC_STATUS s = unwindAttach(ex, user_status, tdbb, attachment, dbb); + ex.sleep(); + return s; + } catch (const std::exception& ex) { - ISC_STATUS_ARRAY temp_status; - try - { -#if defined(V4_THREADING) && !defined(SUPERSERVER) - if (initing_security) - { - V4_JRD_MUTEX_LOCK(dbb->dbb_mutexes + DBB_MUTX_init_fini); - } -#endif - tdbb->tdbb_status_vector = temp_status; - dbb->dbb_flags &= ~DBB_being_opened; - release_attachment(attachment); - - /* At this point, mutex dbb->dbb_mutexes [DBB_MUTX_init_fini] has been - unlocked and mutex databases_mutex has been locked. */ - if (MemoryPool::blk_type(dbb) == type_dbb) - { - if (!dbb->dbb_attachments) - { - shutdown_database(dbb, true); - } - else if (attachment) - { - delete attachment; - } - } -#if defined(V4_THREADING) && !defined(SUPERSERVER) - V4_JRD_MUTEX_UNLOCK(databases_mutex); -#endif - } - catch (const std::exception&) {} - tdbb->tdbb_status_vector = status; - JRD_SS_MUTEX_UNLOCK; - return error(user_status, ex); + return unwindAttach(ex, user_status, tdbb, attachment, dbb); } } @@ -3484,6 +3435,13 @@ ISC_STATUS GDS_SERVICE_ATTACH(ISC_STATUS* user_status, { *svc_handle = SVC_attach(service_length, service_name, spb_length, spb); } + catch (const Jrd::DelayFailedLogin& ex) + { + JRD_SS_MUTEX_UNLOCK; + ISC_STATUS s = error(user_status, ex); + ex.sleep(); + return s; + } catch (const std::exception& ex) { JRD_SS_MUTEX_UNLOCK; @@ -6729,6 +6687,7 @@ static void getUserInfo(UserId& user, const DatabaseOptions& options) Firebird::string remote = options.dpb_network_protocol + (options.dpb_network_protocol.isEmpty() || options.dpb_remote_address.isEmpty() ? "" : "/") + options.dpb_remote_address; + SecurityDatabase::verifyUser(name, options.dpb_user_name.nullStr(), options.dpb_password.nullStr(), @@ -6777,3 +6736,49 @@ static void getUserInfo(UserId& user, const DatabaseOptions& options) user.usr_flags |= USR_locksmith; } } + +static ISC_STATUS unwindAttach(const std::exception& ex, + ISC_STATUS* userStatus, + thread_db* tdbb, + Attachment* attachment, + Database* dbb) +{ + ISC_STATUS_ARRAY temp_status; + ISC_STATUS* status = tdbb->tdbb_status_vector; + + try + { +#if defined(V4_THREADING) && !defined(SUPERSERVER) + if (initing_security) + { + V4_JRD_MUTEX_LOCK(dbb->dbb_mutexes + DBB_MUTX_init_fini); + } +#endif + tdbb->tdbb_status_vector = temp_status; + dbb->dbb_flags &= ~DBB_being_opened; + release_attachment(attachment); + + /* At this point, mutex dbb->dbb_mutexes [DBB_MUTX_init_fini] has been + unlocked and mutex databases_mutex has been locked. */ + if (MemoryPool::blk_type(dbb) == type_dbb) + { + if (!dbb->dbb_attachments) + { + shutdown_database(dbb, true); + } + else if (attachment) + { + delete attachment; + } + } +#if defined(V4_THREADING) && !defined(SUPERSERVER) + V4_JRD_MUTEX_UNLOCK(databases_mutex); +#endif + } + catch (const std::exception&) {} + + tdbb->tdbb_status_vector = status; + JRD_SS_MUTEX_UNLOCK; + + return error(userStatus, ex); +} diff --git a/src/jrd/jrd_pwd.h b/src/jrd/jrd_pwd.h index 8e69d71cc3..504e096267 100644 --- a/src/jrd/jrd_pwd.h +++ b/src/jrd/jrd_pwd.h @@ -121,4 +121,27 @@ private: } }; +namespace Jrd { + +class DelayFailedLogin : public Firebird::status_exception +{ +private: + int seconds; +public: + DelayFailedLogin(int sec) throw() + : Firebird::status_exception(), seconds(sec) + { + ISC_STATUS temp[] = {isc_arg_gds, + isc_login, + isc_arg_end}; + set_status(temp, false); + } + virtual const char* what() const throw() { return "Jrd::DelayFailedLogin"; } + static void raise(int sec); + void sleep() const; +}; + + +} // namespace Jrd + #endif /* JRD_PWD_H */ diff --git a/src/jrd/pwd.cpp b/src/jrd/pwd.cpp index 1c28b74202..dea3a06dcd 100644 --- a/src/jrd/pwd.cpp +++ b/src/jrd/pwd.cpp @@ -122,8 +122,10 @@ namespace { Firebird::string login; int failCount; time_t lastAttempt; - FailedLogin(Firebird::MemoryPool& p) - : login(p), failCount(0), lastAttempt(time(0)) {} + FailedLogin(const Firebird::string& l) + : login(l), failCount(1), lastAttempt(time(0)) {} + FailedLogin(Firebird::MemoryPool& p, const FailedLogin& fl) + : login(p, fl.login), failCount(fl.failCount), lastAttempt(fl.lastAttempt) {} static const Firebird::string* generate(const void* sender, const FailedLogin* f) { return &(f->login); @@ -152,44 +154,30 @@ namespace { void loginFail(const Firebird::string& login) { - //Firebird::MutexLockGuard(fullAccess); - fullAccess.enter(); - FailedLogin& l = get(login); - if (++l.failCount >= MAX_FAILED_ATTEMPTS) - { - sleepThread(); - l.failCount = 0; - } - fullAccess.leave(); - } + Firebird::MutexLockGuard guard(fullAccess); + + const time_t t = time(0); - void loginSuccess(const Firebird::string& login) - { - //Firebird::MutexLockGuard(fullAccess); - fullAccess.enter(); size_t pos; if (find(login, pos)) { - remove(pos); - } - fullAccess.leave(); - } - - private: - FailedLogin& get(const Firebird::string& login) + FailedLogin& l = (*this)[pos]; + if (t - l.lastAttempt >= FAILURE_DELAY) { - size_t pos; - if (find(login, pos)) + l.failCount = 0; + } + l.lastAttempt = t; + if (++l.failCount >= MAX_FAILED_ATTEMPTS) { - (*this)[pos].lastAttempt = time(0); - return (*this)[pos]; + l.failCount = 0; + Jrd::DelayFailedLogin::raise(FAILURE_DELAY); + } + return; } -checkForFreeSpace: if (getCount() >= MAX_CONCURRENT_FAILURES) { // try to perform old entries collection - const time_t t = time(0); for (iterator i = begin(); i != end(); ) { if (t - i->lastAttempt >= FAILURE_DELAY) @@ -205,23 +193,20 @@ checkForFreeSpace: if (getCount() >= MAX_CONCURRENT_FAILURES) { // it seems we are under attack - too many wrong logins !!! - // therefore sleep for a while and clear failures cache - sleepThread(); - goto checkForFreeSpace; + Jrd::DelayFailedLogin::raise(FAILURE_DELAY); } - FailedLogin& rc = add(); - rc.login = login; - return rc; + add(FailedLogin(login)); } - void sleepThread() + void loginSuccess(const Firebird::string& login) { - THREAD_EXIT(); - fullAccess.leave(); - THREAD_SLEEP(1000 * FAILURE_DELAY); - THREAD_ENTER(); - fullAccess.enter(); + Firebird::MutexLockGuard guard(fullAccess); + size_t pos; + if (find(login, pos)) + { + remove(pos); + } } }; #else //SUPERSERVER @@ -510,3 +495,14 @@ void SecurityDatabase::verifyUser(Firebird::string& name, *node_id = 0; } +void DelayFailedLogin::raise(int sec) +{ + throw DelayFailedLogin(sec); +} + +void DelayFailedLogin::sleep() const +{ + THREAD_EXIT(); + THREAD_SLEEP(1000 * seconds); + THREAD_ENTER(); +}