winix/functions/login.cpp

278 lines
5.9 KiB
C++
Executable File

/*
* This file is a part of Winix
* and is not publicly distributed
*
* Copyright (c) 2008-2012, Tomasz Sowa
* All rights reserved.
*
*/
#include "core/sessionmanager.h"
#include "login.h"
#include "utf8/utf8.h"
namespace Fun
{
Login::Login()
{
fun.url = L"login";
need_ssl = true;
}
void Login::ClearTmpStruct()
{
system->crypt.ClearString(pass_decrypted);
system->crypt.ClearString(pass_hashed);
system->crypt.ClearString(up.pass);
system->crypt.ClearString(up.pass_encrypted);
system->crypt.ClearString(up2.pass);
system->crypt.ClearString(up2.pass_encrypted);
}
bool Login::CheckPasswords(const std::wstring & password)
{
if( !up.pass_encrypted.empty() )
{
if( system->crypt.RSA(false, config->pass_rsa_private_key, up.pass_encrypted, pass_decrypted) )
{
PT::UTF8ToWide(pass_decrypted, up.pass);
}
else
{
log << log1 << "Login: I cannot decrypt a stored password, login failure" << logend;
return false;
}
}
pass_hashed = password;
up2.pass_type = up.pass_type;
up2.pass = password;
if( up.pass_hash_salted )
salt = config->pass_hash_salt;
else
salt.clear();
if( !system->crypt.PassHash(salt, up2) )
{
log << log1 << "Login: I cannot hash a password, login failure" << logend;
return false;
}
bool result = (up.pass == up2.pass);
if( !result )
log << log2 << "Login: incorrect login/password" << logend;
return result;
}
/*
this method is checking whether there is a person with that login and password
in the database
return true if it has found one and sets it user_id
*/
bool Login::CheckUserPass(const std::wstring & login, const std::wstring & password, long & user_id)
{
bool result;
if( db->GetUserPass(login, user_id, up) )
{
result = CheckPasswords(password);
}
else
{
log << log2 << "Login: there is no a user name: " << login << logend;
result = false;
}
ClearTmpStruct();
return result;
}
void Login::AddBanInfo()
{
IPBan * ip_ban = cur->session->ip_ban;
if( !ip_ban )
ip_ban = &session_manager->AddIPToBanList(cur->request->ip);
ip_ban->last_used = cur->request->start_time;
if( ip_ban->expires != 0 && cur->request->start_time >= ip_ban->expires )
{
// the 'ip block' has expired
ip_ban->ClearAfterRemovingBan();
log << log3 << "Login: removing the IP block for logging" << logend;
}
if( ip_ban->incorrect_login_events < config->incorrect_login_cannot_login_treshold )
ip_ban->incorrect_login_events += 1;
if( ip_ban->incorrect_login_events >= config->incorrect_login_cannot_login_treshold )
{
log << log2 << "Login: too many incorrect login attempts from this IP" << logend;
if( config->incorrect_login_cannot_login_mode == 0 )
{
// don't set WINIX_IPBAN_FLAG_ACTIVE here for IPBan::IsIPBanned() to return false (in CannotLoginFrom)
ip_ban->expires = cur->request->start_time + (time_t)config->incorrect_login_cannot_login_delay;
PT::Date date(ip_ban->expires);
log << log2 << "Login: logging from this IP address has been blocked until to: " << date << " UTC" << logend;
}
else
if( config->incorrect_login_cannot_login_mode == 1 )
{
ip_ban->SetFlag(WINIX_IPBAN_FLAG_ACTIVE);
ip_ban->AddNextBanLevel(cur->request->start_time + (time_t)config->ban_level_1_delay,
cur->request->start_time + (time_t)config->ban_level_2_delay,
cur->request->start_time + (time_t)config->ban_level_3_delay);
PT::Date date(ip_ban->expires);
log << log2 << "Login: this IP address has been banned until to: " << date << " UTC" << logend;
}
}
}
bool Login::ShouldUseCaptchaForCurrentIP()
{
if( cur->session->ip_ban )
return ShouldUseCaptchaFor(*cur->session->ip_ban);
return false;
}
bool Login::ShouldUseCaptchaFor(const IPBan & ipban)
{
if( ipban.expires != 0 && cur->request->start_time >= ipban.expires )
return false; // the 'ip block' has expired (but incorrect_login_events has the old value)
return ipban.incorrect_login_events >= config->incorrect_login_captcha_treshold;
}
bool Login::CannotLoginFromCurrentIP()
{
if( cur->session->ip_ban )
return CannotLoginFrom(*cur->session->ip_ban);
return false;
}
bool Login::CannotLoginFrom(const IPBan & ipban)
{
if( ipban.IsIPBanned() )
return true;
if( ipban.expires != 0 &&
cur->request->start_time < ipban.expires &&
ipban.incorrect_login_events >= config->incorrect_login_cannot_login_treshold )
return true;
return false;
}
bool Login::CheckAbuse()
{
time_t diff = (time_t)config->incorrect_login_min_time_between_get_post;
if( cur->session->last_time_get + diff > cur->request->start_time )
{
log << log2 << "Login: the minimum time between GET and POST have not passed" << logend;
return false;
}
if( ShouldUseCaptchaForCurrentIP() )
{
if( !system->rebus.CheckRebus() )
{
return false;
}
}
return true;
}
bool Login::LoginUser(const std::wstring & login, const std::wstring & password, bool remember_me, bool use_ses_log)
{
long user_id;
if( cur->session->id == 0 )
{
log << log2 << "Login: can't login in a temporary session (skipped)" << logend;
return false;
}
if( CannotLoginFromCurrentIP() )
{
log << log2 << "Login: you cannot login from this IP address" << logend;
return false;
}
if( login.empty() )
{
log << log3 << "Login: login is empty (skipping)" << logend;
return false;
}
if( !CheckAbuse() )
{
AddBanInfo();
return false;
}
if( CheckUserPass(login, password, user_id) )
{
if( system->users.LoginUser(user_id, remember_me, use_ses_log) )
{
if( cur->session->ip_ban )
cur->session->ip_ban->incorrect_login_events = 0;
return true;
}
}
else
{
AddBanInfo();
}
return false;
}
void Login::MakePost()
{
const std::wstring & login = cur->request->PostVar(L"login");
const std::wstring & pass = cur->request->PostVar(L"password");
const std::wstring & remem = cur->request->PostVar(L"rememberme");
if( LoginUser(login, pass, !remem.empty(), true) )
system->RedirectToLastItem();
}
void Login::MakeGet()
{
}
} // namespace