8
0
mirror of https://github.com/FirebirdSQL/firebird.git synced 2025-01-23 16:03:02 +01:00

backported fix for CORE-1421: SuperServer can't shutdown immediately after shutdown request after failed login attempt

This commit is contained in:
alexpeshkoff 2008-02-27 12:56:57 +00:00
parent f712b3a460
commit 86367ced07
3 changed files with 133 additions and 109 deletions

View File

@ -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);
}

View File

@ -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 */

View File

@ -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();
}