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:
parent
f712b3a460
commit
86367ced07
141
src/jrd/jrd.cpp
141
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);
|
||||
}
|
||||
|
@ -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 */
|
||||
|
@ -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();
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user