diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/server/bnetserver/Server/Session.cpp | 235 | ||||
| -rw-r--r-- | src/server/bnetserver/Server/Session.h | 41 | ||||
| -rw-r--r-- | src/server/bnetserver/Server/SessionManager.cpp | 2 | ||||
| -rw-r--r-- | src/server/bnetserver/Server/SessionManager.h | 4 | ||||
| -rw-r--r-- | src/server/shared/Database/Implementation/LoginDatabase.cpp | 16 | ||||
| -rw-r--r-- | src/server/shared/Database/Implementation/LoginDatabase.h | 5 |
6 files changed, 167 insertions, 136 deletions
diff --git a/src/server/bnetserver/Server/Session.cpp b/src/server/bnetserver/Server/Session.cpp index bb0a92740e0..4c6e179896f 100644 --- a/src/server/bnetserver/Server/Session.cpp +++ b/src/server/bnetserver/Server/Session.cpp @@ -36,8 +36,37 @@ Battlenet::Session::ModuleHandler const Battlenet::Session::ModuleHandlers[MODUL &Battlenet::Session::HandleResumeModule, }; -Battlenet::Session::Session(tcp::socket&& socket) : Socket(std::move(socket)), _accountId(0), _accountName(), _locale(), - _os(), _build(0), _gameAccountId(0), _gameAccountName(), _accountSecurityLevel(SEC_PLAYER), I(), s(), v(), b(), B(), K(), +void Battlenet::AccountInfo::LoadResult(Field* fields) +{ + // ba.id, ba.email, ba.locked, ba.lock_country, ba.last_ip, ba.failed_logins, bab.unbandate > UNIX_TIMESTAMP() OR bab.unbandate = bab.bandate, bab.unbandate = bab.bandate FROM battlenet_accounts ba LEFT JOIN battlenet_account_bans bab WHERE email = ? + Id = fields[0].GetUInt32(); + Login = fields[1].GetString(); + IsLockedToIP = fields[2].GetBool(); + LockCountry = fields[3].GetString(); + LastIP = fields[4].GetString(); + FailedLogins = fields[5].GetUInt32(); + IsBanned = fields[6].GetUInt64() != 0; + IsPermanenetlyBanned = fields[7].GetUInt64() != 0; +} + +void Battlenet::GameAccountInfo::LoadResult(Field* fields) +{ + // a.id, a.username, ab.unbandate > UNIX_TIMESTAMP() OR ab.unbandate = ab.bandate, ab.unbandate = ab.bandate, aa.gmlevel + Id = fields[0].GetUInt32(); + Name = fields[1].GetString(); + IsBanned = fields[2].GetUInt64() != 0; + IsPermanenetlyBanned = fields[3].GetUInt64() != 0; + SecurityLevel = AccountTypes(fields[4].GetUInt8()); + + std::size_t hashPos = Name.find('#'); + if (hashPos != std::string::npos) + DisplayName = std::string("WoW") + Name.substr(hashPos + 1); + else + DisplayName = Name; +} + +Battlenet::Session::Session(tcp::socket&& socket) : Socket(std::move(socket)), _accountInfo(new AccountInfo()), _gameAccountInfo(nullptr), _locale(), + _os(), _build(0), I(), s(), v(), b(), B(), K(), _reconnectProof(), _crypt(), _authed(false), _subscribedToRealmListUpdates(false), _toonOnline(false) { static uint8 const N_Bytes[] = @@ -63,6 +92,7 @@ Battlenet::Session::Session(tcp::socket&& socket) : Socket(std::move(socket)), _ Battlenet::Session::~Session() { + delete _accountInfo; sSessionMgr.RemoveSession(this); } @@ -83,7 +113,7 @@ void Battlenet::Session::_SetVSFields(std::string const& pstr) PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_BNET_VS_FIELDS); stmt->setString(0, v.AsHexStr()); stmt->setString(1, s.AsHexStr()); - stmt->setString(2, _accountName); + stmt->setString(2, _accountInfo->Login); LoginDatabase.Execute(stmt); } @@ -170,13 +200,13 @@ void Battlenet::Session::HandleLogonRequest(Authentication::LogonRequest3 const& _build = component.Build; } - _accountName = logonRequest.Login; + std::string login = logonRequest.Login; _locale = logonRequest.Locale; _os = logonRequest.Platform; - Utf8ToUpperOnlyLatin(_accountName); + Utf8ToUpperOnlyLatin(login); stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_BNET_ACCOUNT_INFO); - stmt->setString(0, _accountName); + stmt->setString(0, login); PreparedQueryResult result = LoginDatabase.Query(stmt); if (!result) @@ -189,15 +219,14 @@ void Battlenet::Session::HandleLogonRequest(Authentication::LogonRequest3 const& } Field* fields = result->Fetch(); - - _accountId = fields[1].GetUInt32(); + _accountInfo->LoadResult(fields); // If the IP is 'locked', check that the player comes indeed from the correct IP address - if (fields[2].GetUInt8() == 1) // if ip is locked + if (_accountInfo->IsLockedToIP) { - TC_LOG_DEBUG("session", "[Battlenet::LogonRequest] Account '%s' is locked to IP - '%s' is logging in from '%s'", _accountName.c_str(), fields[4].GetCString(), ip_address.c_str()); + TC_LOG_DEBUG("session", "[Battlenet::LogonRequest] Account '%s' is locked to IP - '%s' is logging in from '%s'", _accountInfo->Login.c_str(), _accountInfo->LastIP.c_str(), ip_address.c_str()); - if (strcmp(fields[4].GetCString(), ip_address.c_str()) != 0) + if (_accountInfo->LastIP != ip_address) { Authentication::LogonResponse* logonResponse = new Authentication::LogonResponse(); logonResponse->SetAuthResult(AUTH_ACCOUNT_LOCKED); @@ -207,11 +236,10 @@ void Battlenet::Session::HandleLogonRequest(Authentication::LogonRequest3 const& } else { - TC_LOG_DEBUG("session", "[Battlenet::LogonRequest] Account '%s' is not locked to ip", _accountName.c_str()); - std::string accountCountry = fields[3].GetString(); - if (accountCountry.empty() || accountCountry == "00") - TC_LOG_DEBUG("session", "[Battlenet::LogonRequest] Account '%s' is not locked to country", _accountName.c_str()); - else if (!accountCountry.empty()) + TC_LOG_DEBUG("session", "[Battlenet::LogonRequest] Account '%s' is not locked to ip", _accountInfo->Login.c_str()); + if (_accountInfo->LockCountry.empty() || _accountInfo->LockCountry == "00") + TC_LOG_DEBUG("session", "[Battlenet::LogonRequest] Account '%s' is not locked to country", _accountInfo->Login.c_str()); + else if (!_accountInfo->LockCountry.empty()) { uint32 ip = inet_addr(ip_address.c_str()); EndianConvertReverse(ip); @@ -221,8 +249,8 @@ void Battlenet::Session::HandleLogonRequest(Authentication::LogonRequest3 const& if (PreparedQueryResult sessionCountryQuery = LoginDatabase.Query(stmt)) { std::string loginCountry = (*sessionCountryQuery)[0].GetString(); - TC_LOG_DEBUG("session", "[Battlenet::LogonRequest] Account '%s' is locked to country: '%s' Player country is '%s'", _accountName.c_str(), accountCountry.c_str(), loginCountry.c_str()); - if (loginCountry != accountCountry) + TC_LOG_DEBUG("session", "[Battlenet::LogonRequest] Account '%s' is locked to country: '%s' Player country is '%s'", _accountInfo->Login.c_str(), _accountInfo->LockCountry.c_str(), loginCountry.c_str()); + if (loginCountry != _accountInfo->LockCountry) { Authentication::LogonResponse* logonResponse = new Authentication::LogonResponse(); logonResponse->SetAuthResult(AUTH_ACCOUNT_LOCKED); @@ -233,22 +261,15 @@ void Battlenet::Session::HandleLogonRequest(Authentication::LogonRequest3 const& } } - //set expired bans to inactive - LoginDatabase.DirectExecute(LoginDatabase.GetPreparedStatement(LOGIN_DEL_BNET_EXPIRED_BANS)); - // If the account is banned, reject the logon attempt - stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_BNET_ACTIVE_ACCOUNT_BAN); - stmt->setUInt32(0, _accountId); - PreparedQueryResult banresult = LoginDatabase.Query(stmt); - if (banresult) + if (_accountInfo->IsBanned) { - Field* fields = banresult->Fetch(); - if (fields[0].GetUInt32() == fields[1].GetUInt32()) + if (_accountInfo->IsPermanenetlyBanned) { Authentication::LogonResponse* logonResponse = new Authentication::LogonResponse(); logonResponse->SetAuthResult(LOGIN_BANNED); AsyncWrite(logonResponse); - TC_LOG_DEBUG("session", "'%s:%d' [Battlenet::LogonRequest] Banned account %s tried to login!", ip_address.c_str(), GetRemotePort(), _accountName.c_str()); + TC_LOG_DEBUG("session", "'%s:%d' [Battlenet::LogonRequest] Banned account %s tried to login!", ip_address.c_str(), GetRemotePort(), _accountInfo->Login.c_str()); return; } else @@ -256,13 +277,13 @@ void Battlenet::Session::HandleLogonRequest(Authentication::LogonRequest3 const& Authentication::LogonResponse* logonResponse = new Authentication::LogonResponse(); logonResponse->SetAuthResult(LOGIN_SUSPENDED); AsyncWrite(logonResponse); - TC_LOG_DEBUG("session", "'%s:%d' [Battlenet::LogonRequest] Temporarily banned account %s tried to login!", ip_address.c_str(), GetRemotePort(), _accountName.c_str()); + TC_LOG_DEBUG("session", "'%s:%d' [Battlenet::LogonRequest] Temporarily banned account %s tried to login!", ip_address.c_str(), GetRemotePort(), _accountInfo->Login.c_str()); return; } } SHA256Hash sha; - sha.UpdateData(_accountName); + sha.UpdateData(_accountInfo->Login); sha.Finalize(); I.SetBinary(sha.GetDigest(), sha.GetLength()); @@ -270,10 +291,10 @@ void Battlenet::Session::HandleLogonRequest(Authentication::LogonRequest3 const& ModuleInfo* password = sModuleMgr->CreateModule(_os, "Password"); ModuleInfo* thumbprint = sModuleMgr->CreateModule(_os, "Thumbprint"); - std::string pStr = fields[0].GetString(); + std::string pStr = fields[8].GetString(); - std::string databaseV = fields[5].GetString(); - std::string databaseS = fields[6].GetString(); + std::string databaseV = fields[9].GetString(); + std::string databaseS = fields[10].GetString(); if (databaseV.size() != size_t(BufferSizes::SRP_6_V) * 2 || databaseS.size() != size_t(BufferSizes::SRP_6_S) * 2) _SetVSFields(pStr); @@ -311,16 +332,16 @@ void Battlenet::Session::HandleLogonRequest(Authentication::LogonRequest3 const& void Battlenet::Session::HandleResumeRequest(Authentication::ResumeRequest const& resumeRequest) { - _accountName = resumeRequest.Login; + std::string login = resumeRequest.Login; _locale = resumeRequest.Locale; _os = resumeRequest.Platform; auto baseComponent = std::find_if(resumeRequest.Components.begin(), resumeRequest.Components.end(), [](Component const& c) { return c.Program == "base"; }); if (baseComponent != resumeRequest.Components.end()) _build = baseComponent->Build; - Utf8ToUpperOnlyLatin(_accountName); + Utf8ToUpperOnlyLatin(login); PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_BNET_RECONNECT_INFO); - stmt->setString(0, _accountName); + stmt->setString(0, login); stmt->setString(1, resumeRequest.GameAccountName); PreparedQueryResult result = LoginDatabase.Query(stmt); if (!result) @@ -332,11 +353,12 @@ void Battlenet::Session::HandleResumeRequest(Authentication::ResumeRequest const } Field* fields = result->Fetch(); + _accountInfo->LoadResult(fields); + K.SetHexStr(fields[8].GetString().c_str()); - _accountId = fields[0].GetUInt32(); - K.SetHexStr(fields[1].GetString().c_str()); - _gameAccountId = fields[2].GetUInt32(); - _gameAccountName = resumeRequest.GameAccountName; + _gameAccounts.resize(1); + _gameAccountInfo = &_gameAccounts[0]; + _gameAccountInfo->LoadResult(fields + 9); ModuleInfo* thumbprint = sModuleMgr->CreateModule(_os, "Thumbprint"); ModuleInfo* resume = sModuleMgr->CreateModule(_os, "Resume"); @@ -404,7 +426,7 @@ void Battlenet::Session::HandleLogoutRequest(Connection::LogoutRequest const& /* PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_BNET_SESSION_KEY); stmt->setString(0, ""); stmt->setBool(1, false); - stmt->setUInt32(2, _accountId); + stmt->setUInt32(2, _accountInfo->Id); LoginDatabase.Execute(stmt); } @@ -417,7 +439,7 @@ void Battlenet::Session::HandleListSubscribeRequest(WoWRealm::ListSubscribeReque WoWRealm::ListSubscribeResponse* listSubscribeResponse = new WoWRealm::ListSubscribeResponse(); PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_BNET_CHARACTER_COUNTS); - stmt->setUInt32(0, _gameAccountId); + stmt->setUInt32(0, _gameAccountInfo->Id); if (PreparedQueryResult countResult = LoginDatabase.Query(stmt)) { @@ -474,7 +496,7 @@ void Battlenet::Session::HandleJoinRequestV2(WoWRealm::JoinRequestV2 const& join memcpy(sessionKey + hmac.GetLength(), hmac2.GetDigest(), hmac2.GetLength()); LoginDatabase.DirectPExecute("UPDATE account SET sessionkey = '%s', last_ip = '%s', last_login = NOW(), locale = %u, failed_logins = 0, os = '%s' WHERE id = %u", - ByteArrayToHexStr(sessionKey, 40, true).c_str(), GetRemoteIpAddress().to_string().c_str(), GetLocaleByName(_locale), _os.c_str(), _gameAccountId); + ByteArrayToHexStr(sessionKey, 40, true).c_str(), GetRemoteIpAddress().to_string().c_str(), GetLocaleByName(_locale), _os.c_str(), _gameAccountInfo->Id); joinResponse->IPv4.emplace_back(realm->ExternalAddress, realm->Port); if (realm->ExternalAddress != realm->LocalAddress) @@ -600,6 +622,23 @@ void Battlenet::Session::AsyncWrite(ServerPacket* packet) QueuePacket(std::move(buffer), guard); } +void Battlenet::Session::LoadGameAccountData() +{ + PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_BNET_GAME_ACCOUNTS); + stmt->setUInt32(0, _accountInfo->Id); + PreparedQueryResult result = LoginDatabase.Query(stmt); + if (!result) + return; + + _gameAccounts.resize(result->GetRowCount()); + uint32 i = 0; + do + { + _gameAccounts[i++].LoadResult(result->Fetch()); + + } while (result->NextRow()); +} + inline void ReplaceResponse(Battlenet::ServerPacket** oldResponse, Battlenet::ServerPacket* newResponse) { if (*oldResponse) @@ -626,7 +665,6 @@ bool Battlenet::Session::HandlePasswordModule(BitStream* dataStream, ServerPacke return false; } - BigNumber A, clientM1, clientChallenge; A.SetBinary(dataStream->ReadBytes(128).get(), 128); clientM1.SetBinary(dataStream->ReadBytes(32).get(), 32); @@ -707,7 +745,7 @@ bool Battlenet::Session::HandlePasswordModule(BitStream* dataStream, ServerPacke if (memcmp(M1.AsByteArray().get(), clientM1.AsByteArray().get(), 32)) { PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_BNET_FAILED_LOGINS); - stmt->setString(0, _accountName); + stmt->setString(0, _accountInfo->Login); LoginDatabase.Execute(stmt); Authentication::LogonResponse* logonResponse = new Authentication::LogonResponse(); @@ -717,14 +755,9 @@ bool Battlenet::Session::HandlePasswordModule(BitStream* dataStream, ServerPacke return false; } - uint64 numAccounts = 0; - PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_BNET_GAME_ACCOUNTS); - stmt->setUInt32(0, _accountId); - PreparedQueryResult result = LoginDatabase.Query(stmt); - if (result) - numAccounts = result->GetRowCount(); + LoadGameAccountData(); - if (!numAccounts) + if (_gameAccounts.empty()) { Authentication::LogonResponse* logonResponse = new Authentication::LogonResponse(); logonResponse->SetAuthResult(LOGIN_NO_GAME_ACCOUNT); @@ -733,10 +766,8 @@ bool Battlenet::Session::HandlePasswordModule(BitStream* dataStream, ServerPacke return false; } - Field* fields = result->Fetch(); - //set expired game account bans to inactive - LoginDatabase.DirectExecute(LoginDatabase.GetPreparedStatement(LOGIN_UPD_EXPIRED_ACCOUNT_BANS)); + LoginDatabase.Execute(LoginDatabase.GetPreparedStatement(LOGIN_UPD_EXPIRED_ACCOUNT_BANS)); BigNumber M; sha.Initialize(); @@ -761,26 +792,17 @@ bool Battlenet::Session::HandlePasswordModule(BitStream* dataStream, ServerPacke Authentication::ProofRequest* proofRequest = new Authentication::ProofRequest(); proofRequest->Modules.push_back(password); - if (numAccounts > 1) + if (_gameAccounts.size() > 1) { BitStream accounts; state = 0; accounts.WriteBytes(&state, 1); - accounts.Write(numAccounts, 8); - do + accounts.Write(_gameAccounts.size(), 8); + for (GameAccountInfo const& gameAccount : _gameAccounts) { - fields = result->Fetch(); - std::ostringstream name; - std::string originalName = fields[1].GetString(); - std::size_t hashPos = originalName.find('#'); - if (hashPos != std::string::npos) - name << "WoW" << originalName.substr(hashPos + 1); - else - name << originalName; - accounts.Write(2, 8); - accounts.WriteString(name.str(), 8); - } while (result->NextRow()); + accounts.WriteString(gameAccount.DisplayName, 8); + } ModuleInfo* selectGameAccount = sModuleMgr->CreateModule(_os, "SelectGameAccount"); selectGameAccount->DataSize = accounts.GetSize(); @@ -791,29 +813,28 @@ bool Battlenet::Session::HandlePasswordModule(BitStream* dataStream, ServerPacke } else { - if (fields[4].GetBool()) + _gameAccountInfo = &_gameAccounts[0]; + + if (_gameAccountInfo->IsBanned) { delete proofRequest; Authentication::LogonResponse* logonResponse = new Authentication::LogonResponse(); - if (fields[2].GetUInt32() == fields[3].GetUInt32()) + if (_gameAccountInfo->IsPermanenetlyBanned) { logonResponse->SetAuthResult(LOGIN_BANNED); - TC_LOG_DEBUG("session", "'%s:%d' [Battlenet::Password] Banned account %s tried to login!", GetRemoteIpAddress().to_string().c_str(), GetRemotePort(), _accountName.c_str()); + TC_LOG_DEBUG("session", "'%s:%d' [Battlenet::Password] Banned account %s tried to login!", GetRemoteIpAddress().to_string().c_str(), GetRemotePort(), _accountInfo->Login.c_str()); } else { logonResponse->SetAuthResult(LOGIN_SUSPENDED); - TC_LOG_DEBUG("session", "'%s:%d' [Battlenet::Password] Temporarily banned account %s tried to login!", GetRemoteIpAddress().to_string().c_str(), GetRemotePort(), _accountName.c_str()); + TC_LOG_DEBUG("session", "'%s:%d' [Battlenet::Password] Temporarily banned account %s tried to login!", GetRemoteIpAddress().to_string().c_str(), GetRemotePort(), _accountInfo->Login.c_str()); } ReplaceResponse(response, logonResponse); return false; } - _gameAccountId = fields[0].GetUInt32(); - _gameAccountName = fields[1].GetString(); - proofRequest->Modules.push_back(sModuleMgr->CreateModule(_os, "RiskFingerprint")); _modulesWaitingForData.push(MODULE_RISK_FINGERPRINT); } @@ -842,21 +863,16 @@ bool Battlenet::Session::HandleSelectGameAccountModule(BitStream* dataStream, Se return false; } - PreparedStatement* stmt; - if (account.substr(0, 3) != "WoW") + for (std::size_t i = 0; i < _gameAccounts.size(); ++i) { - stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_BNET_GAME_ACCOUNT); - stmt->setString(0, account); - } - else - { - stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_BNET_GAME_ACCOUNT_UNNAMED); - stmt->setUInt8(0, atol(account.substr(3).c_str())); + if (_gameAccounts[i].DisplayName == account) + { + _gameAccountInfo = &_gameAccounts[i]; + break; + } } - stmt->setUInt32(1, _accountId); - PreparedQueryResult result = LoginDatabase.Query(stmt); - if (!result) + if (!_gameAccountInfo) { Authentication::LogonResponse* complete = new Authentication::LogonResponse(); complete->SetAuthResult(LOGIN_NO_GAME_ACCOUNT); @@ -865,28 +881,24 @@ bool Battlenet::Session::HandleSelectGameAccountModule(BitStream* dataStream, Se return false; } - Field* fields = result->Fetch(); - if (fields[4].GetBool()) + if (_gameAccountInfo->IsBanned) { Authentication::LogonResponse* logonResponse = new Authentication::LogonResponse(); - if (fields[2].GetUInt32() == fields[3].GetUInt32()) + if (_gameAccountInfo->IsPermanenetlyBanned) { logonResponse->SetAuthResult(LOGIN_BANNED); - TC_LOG_DEBUG("session", "'%s:%d' [Battlenet::SelectGameAccount] Banned account %s tried to login!", GetRemoteIpAddress().to_string().c_str(), GetRemotePort(), _accountName.c_str()); + TC_LOG_DEBUG("session", "'%s:%d' [Battlenet::SelectGameAccount] Banned account %s tried to login!", GetRemoteIpAddress().to_string().c_str(), GetRemotePort(), _accountInfo->Login.c_str()); } else { logonResponse->SetAuthResult(LOGIN_SUSPENDED); - TC_LOG_DEBUG("session", "'%s:%d' [Battlenet::SelectGameAccount] Temporarily banned account %s tried to login!", GetRemoteIpAddress().to_string().c_str(), GetRemotePort(), _accountName.c_str()); + TC_LOG_DEBUG("session", "'%s:%d' [Battlenet::SelectGameAccount] Temporarily banned account %s tried to login!", GetRemoteIpAddress().to_string().c_str(), GetRemotePort(), _accountInfo->Login.c_str()); } ReplaceResponse(response, logonResponse); return false; } - _gameAccountId = fields[0].GetUInt32(); - _gameAccountName = fields[1].GetString(); - Authentication::ProofRequest* proofRequest = new Authentication::ProofRequest(); proofRequest->Modules.push_back(sModuleMgr->CreateModule(_os, "RiskFingerprint")); ReplaceResponse(response, proofRequest); @@ -898,29 +910,26 @@ bool Battlenet::Session::HandleSelectGameAccountModule(BitStream* dataStream, Se bool Battlenet::Session::HandleRiskFingerprintModule(BitStream* dataStream, ServerPacket** response) { Authentication::LogonResponse* logonResponse = new Authentication::LogonResponse(); - if (dataStream->Read<uint8>(8) == 1) + if (dataStream->Read<uint8>(8) == 1 && _accountInfo && _gameAccountInfo) { - logonResponse->AccountId = _accountId; - logonResponse->GameAccountName = _gameAccountName; + logonResponse->AccountId = _accountInfo->Id; + logonResponse->GameAccountName = _gameAccountInfo->Name; logonResponse->GameAccountFlags = GAMEACCOUNT_FLAG_PROPASS_LOCK; - PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_BNET_FAILED_LOGINS); - stmt->setUInt32(0, _accountId); - if (PreparedQueryResult failedLoginsResult = LoginDatabase.Query(stmt)) - logonResponse->FailedLogins = (*failedLoginsResult)[0].GetUInt32(); + logonResponse->FailedLogins = _accountInfo->FailedLogins; SQLTransaction trans = LoginDatabase.BeginTransaction(); - stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_BNET_LAST_LOGIN_INFO); + PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_BNET_LAST_LOGIN_INFO); stmt->setString(0, GetRemoteIpAddress().to_string()); stmt->setUInt8(1, GetLocaleByName(_locale)); stmt->setString(2, _os); - stmt->setUInt32(3, _accountId); + stmt->setUInt32(3, _accountInfo->Id); trans->Append(stmt); stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_BNET_SESSION_KEY); stmt->setString(0, K.AsHexStr()); stmt->setBool(1, true); - stmt->setUInt32(2, _accountId); + stmt->setUInt32(2, _accountInfo->Id); trans->Append(stmt); LoginDatabase.CommitTransaction(trans); @@ -980,7 +989,7 @@ bool Battlenet::Session::HandleResumeModule(BitStream* dataStream, ServerPacket* if (memcmp(proof.GetDigest(), clientProof.get(), serverPart.GetLength())) { PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_BNET_FAILED_LOGINS); - stmt->setString(0, _accountName); + stmt->setString(0, _accountInfo->Login); LoginDatabase.Execute(stmt); TC_LOG_DEBUG("session", "[Battlenet::Resume] %s attempted to reconnect with invalid password!", GetClientInfo().c_str()); @@ -993,7 +1002,7 @@ bool Battlenet::Session::HandleResumeModule(BitStream* dataStream, ServerPacket* PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_BNET_SESSION_KEY); stmt->setString(0, K.AsHexStr()); stmt->setBool(1, true); - stmt->setUInt32(2, _accountId); + stmt->setUInt32(2, _accountInfo->Id); LoginDatabase.Execute(stmt); HmacSha256 serverProof(64, newSessionKey); @@ -1058,7 +1067,7 @@ Battlenet::WoWRealm::ListUpdate* Battlenet::Session::BuildListUpdate(Realm const WoWRealm::ListUpdate* listUpdate = new WoWRealm::ListUpdate(); listUpdate->Timezone = realm->Timezone; listUpdate->Population = realm->PopulationLevel; - listUpdate->Lock = (realm->AllowedSecurityLevel > _accountSecurityLevel) ? 1 : 0; + listUpdate->Lock = (realm->AllowedSecurityLevel > _gameAccountInfo->SecurityLevel) ? 1 : 0; listUpdate->Type = realm->Type; listUpdate->Name = realm->Name; @@ -1080,11 +1089,11 @@ std::string Battlenet::Session::GetClientInfo() const { std::ostringstream stream; stream << '[' << GetRemoteIpAddress() << ':' << GetRemotePort(); - if (!_accountName.empty()) - stream << ", Account: " << _accountName; + if (_accountInfo && !_accountInfo->Login.empty()) + stream << ", Account: " << _accountInfo->Login; - if (!_gameAccountName.empty()) - stream << ", Game account: " << _gameAccountName; + if (_gameAccountInfo) + stream << ", Game account: " << _gameAccountInfo->Name; stream << ']'; diff --git a/src/server/bnetserver/Server/Session.h b/src/server/bnetserver/Server/Session.h index 37dcb5ef4f1..12286ece255 100644 --- a/src/server/bnetserver/Server/Session.h +++ b/src/server/bnetserver/Server/Session.h @@ -52,6 +52,32 @@ namespace Battlenet Read = 0x4000 }; + struct AccountInfo + { + void LoadResult(Field* fields); + + uint32 Id; + std::string Login; + bool IsLockedToIP; + std::string LockCountry; + std::string LastIP; + uint32 FailedLogins; + bool IsBanned; + bool IsPermanenetlyBanned; + }; + + struct GameAccountInfo + { + void LoadResult(Field* fields); + + uint32 Id; + std::string Name; + std::string DisplayName; + bool IsBanned; + bool IsPermanenetlyBanned; + AccountTypes SecurityLevel; + }; + class Session : public Socket<Session> { typedef Socket<Session> BattlenetSocket; @@ -88,8 +114,8 @@ namespace Battlenet void UpdateRealms(std::vector<Realm const*>& realms, std::vector<RealmId>& deletedRealms); - uint32 GetAccountId() const { return _accountId; } - uint32 GetGameAccountId() const { return _gameAccountId; } + uint32 GetAccountId() const { return _accountInfo->Id; } + uint32 GetGameAccountId() const { return _gameAccountInfo->Id; } bool IsToonOnline() const { return _toonOnline; } void SetToonOnline(bool online) { _toonOnline = online; } @@ -107,6 +133,8 @@ namespace Battlenet typedef bool(Session::*ModuleHandler)(BitStream* dataStream, ServerPacket** response); static ModuleHandler const ModuleHandlers[MODULE_COUNT]; + void LoadGameAccountData(); + bool HandlePasswordModule(BitStream* dataStream, ServerPacket** response); bool HandleSelectGameAccountModule(BitStream* dataStream, ServerPacket** response); bool HandleRiskFingerprintModule(BitStream* dataStream, ServerPacket** response); @@ -116,14 +144,13 @@ namespace Battlenet WoWRealm::ListUpdate* BuildListUpdate(Realm const* realm) const; std::string GetClientInfo() const; - uint32 _accountId; - std::string _accountName; + AccountInfo* _accountInfo; + GameAccountInfo* _gameAccountInfo; // Points at selected game account (inside _gameAccounts) + std::vector<GameAccountInfo> _gameAccounts; + std::string _locale; std::string _os; uint32 _build; - uint32 _gameAccountId; - std::string _gameAccountName; - AccountTypes _accountSecurityLevel; BigNumber N; BigNumber g; diff --git a/src/server/bnetserver/Server/SessionManager.cpp b/src/server/bnetserver/Server/SessionManager.cpp index b5d4f5e11cc..d56e1f92f06 100644 --- a/src/server/bnetserver/Server/SessionManager.cpp +++ b/src/server/bnetserver/Server/SessionManager.cpp @@ -56,6 +56,7 @@ void Battlenet::SessionManager::RemoveSession(Session* session) Battlenet::Session* Battlenet::SessionManager::GetSession(uint32 accountId, uint32 gameAccountId) const { + boost::shared_lock<boost::shared_mutex> lock(_sessionMutex); auto itr = _sessions.find({ accountId, gameAccountId }); if (itr != _sessions.end()) return itr->second; @@ -65,6 +66,7 @@ Battlenet::Session* Battlenet::SessionManager::GetSession(uint32 accountId, uint std::list<Battlenet::Session*> Battlenet::SessionManager::GetSessions(uint32 accountId) const { + boost::shared_lock<boost::shared_mutex> lock(_sessionMutex); std::list<Session*> sessions; auto itr = _sessionsByAccountId.find(accountId); if (itr != _sessionsByAccountId.end()) diff --git a/src/server/bnetserver/Server/SessionManager.h b/src/server/bnetserver/Server/SessionManager.h index 3ede9eb0ff6..3944e7db510 100644 --- a/src/server/bnetserver/Server/SessionManager.h +++ b/src/server/bnetserver/Server/SessionManager.h @@ -64,7 +64,7 @@ namespace Battlenet std::list<Session*> GetSessions(uint32 accountId) const; template<typename Iterator> - void LockedForEach(Iterator iterator) + void LockedForEach(Iterator iterator) const { boost::shared_lock<boost::shared_mutex> lock(_sessionMutex); for (SessionMap::value_type const& pair : _sessions) @@ -79,7 +79,7 @@ namespace Battlenet SessionMap _sessions; SessionByAccountMap _sessionsByAccountId; - boost::shared_mutex _sessionMutex; + mutable boost::shared_mutex _sessionMutex; }; } diff --git a/src/server/shared/Database/Implementation/LoginDatabase.cpp b/src/server/shared/Database/Implementation/LoginDatabase.cpp index ad3eb2c577f..dd7ff38298c 100644 --- a/src/server/shared/Database/Implementation/LoginDatabase.cpp +++ b/src/server/shared/Database/Implementation/LoginDatabase.cpp @@ -24,7 +24,7 @@ void LoginDatabaseConnection::DoPrepareStatements() PrepareStatement(LOGIN_SEL_REALMLIST, "SELECT id, name, address, localAddress, localSubnetMask, port, icon, flag, timezone, allowedSecurityLevel, population, gamebuild, Region, Battlegroup FROM realmlist WHERE flag <> 3 ORDER BY name", CONNECTION_SYNCH); PrepareStatement(LOGIN_DEL_EXPIRED_IP_BANS, "DELETE FROM ip_banned WHERE unbandate<>bandate AND unbandate<=UNIX_TIMESTAMP()", CONNECTION_ASYNC); - PrepareStatement(LOGIN_UPD_EXPIRED_ACCOUNT_BANS, "UPDATE account_banned SET active = 0 WHERE active = 1 AND unbandate<>bandate AND unbandate<=UNIX_TIMESTAMP()", CONNECTION_SYNCH); + PrepareStatement(LOGIN_UPD_EXPIRED_ACCOUNT_BANS, "UPDATE account_banned SET active = 0 WHERE active = 1 AND unbandate<>bandate AND unbandate<=UNIX_TIMESTAMP()", CONNECTION_ASYNC); PrepareStatement(LOGIN_SEL_IP_BANNED, "SELECT * FROM ip_banned WHERE ip = ?", CONNECTION_SYNCH); PrepareStatement(LOGIN_INS_IP_AUTO_BANNED, "INSERT INTO ip_banned (ip, bandate, unbandate, bannedby, banreason) VALUES (?, UNIX_TIMESTAMP(), UNIX_TIMESTAMP()+?, 'Trinity Auth', 'Failed login autoban')", CONNECTION_ASYNC); PrepareStatement(LOGIN_SEL_IP_BANNED_ALL, "SELECT ip, bandate, unbandate, bannedby, banreason FROM ip_banned WHERE (bandate = unbandate OR unbandate > UNIX_TIMESTAMP()) ORDER BY unbandate", CONNECTION_SYNCH); @@ -108,16 +108,14 @@ void LoginDatabaseConnection::DoPrepareStatements() PrepareStatement(LOGIN_INS_ACCOUNT_MUTE, "INSERT INTO account_muted VALUES (?, UNIX_TIMESTAMP(), ?, ?, ?)", CONNECTION_ASYNC); PrepareStatement(LOGIN_SEL_ACCOUNT_MUTE_INFO, "SELECT mutedate, mutetime, mutereason, mutedby FROM account_muted WHERE guid = ? ORDER BY mutedate ASC", CONNECTION_SYNCH); - PrepareStatement(LOGIN_SEL_BNET_ACCOUNT_INFO, "SELECT sha_pass_hash, id, locked, lock_country, last_ip, v, s FROM battlenet_accounts WHERE email = ?", CONNECTION_SYNCH); - PrepareStatement(LOGIN_DEL_BNET_EXPIRED_BANS, "UPDATE battlenet_account_bans SET active = 0 WHERE active = 1 AND unbandate <> bandate AND unbandate <= UNIX_TIMESTAMP()", CONNECTION_SYNCH); - PrepareStatement(LOGIN_SEL_BNET_ACTIVE_ACCOUNT_BAN, "SELECT bandate, unbandate FROM battlenet_account_bans WHERE id = ? AND active = 1", CONNECTION_SYNCH); +#define BnetAccountInfo "ba.id, ba.email, ba.locked, ba.lock_country, ba.last_ip, ba.failed_logins, bab.unbandate > UNIX_TIMESTAMP() OR bab.unbandate = bab.bandate, bab.unbandate = bab.bandate" +#define BnetGameAccountInfo "a.id, a.username, ab.unbandate > UNIX_TIMESTAMP() OR ab.unbandate = ab.bandate, ab.unbandate = ab.bandate, aa.gmlevel" + + PrepareStatement(LOGIN_SEL_BNET_ACCOUNT_INFO, "SELECT " BnetAccountInfo ", ba.sha_pass_hash, ba.v, ba.s FROM battlenet_accounts ba LEFT JOIN battlenet_account_bans bab ON ba.id = bab.id WHERE ba.email = ?", CONNECTION_SYNCH); PrepareStatement(LOGIN_UPD_BNET_VS_FIELDS, "UPDATE battlenet_accounts SET v = ?, s = ? WHERE email = ?", CONNECTION_ASYNC); PrepareStatement(LOGIN_UPD_BNET_SESSION_KEY, "UPDATE battlenet_accounts SET sessionKey = ?, online = ? WHERE id = ?", CONNECTION_ASYNC); - PrepareStatement(LOGIN_SEL_BNET_RECONNECT_INFO, "SELECT ba.id, ba.sessionKey, a.id FROM battlenet_accounts ba LEFT JOIN account a ON ba.id = a.battlenet_account WHERE ba.email = ? AND a.username = ?", CONNECTION_SYNCH); - PrepareStatement(LOGIN_SEL_BNET_GAME_ACCOUNTS, "SELECT a.id, a.username, ab.bandate, ab.unbandate, ab.active FROM account a LEFT JOIN account_banned ab ON a.id = ab.id WHERE battlenet_account = ?", CONNECTION_SYNCH); - PrepareStatement(LOGIN_SEL_BNET_GAME_ACCOUNT, "SELECT a.id, a.username, ab.bandate, ab.unbandate, ab.active FROM account a LEFT JOIN account_banned ab ON a.id = ab.id WHERE username = ? AND battlenet_account = ?", CONNECTION_SYNCH); - PrepareStatement(LOGIN_SEL_BNET_GAME_ACCOUNT_UNNAMED, "SELECT a.id, a.username, ab.bandate, ab.unbandate, ab.active FROM account a LEFT JOIN account_banned ab ON a.id = ab.id WHERE battlenet_index = ? AND battlenet_account = ?", CONNECTION_SYNCH); - PrepareStatement(LOGIN_SEL_BNET_FAILED_LOGINS, "SELECT failed_logins FROM battlenet_accounts WHERE id = ?", CONNECTION_SYNCH); + PrepareStatement(LOGIN_SEL_BNET_RECONNECT_INFO, "SELECT " BnetAccountInfo ", ba.sessionKey, " BnetGameAccountInfo " FROM battlenet_accounts ba LEFT JOIN battlenet_account_bans bab ON ba.id = bab.id LEFT JOIN account a ON ba.id = a.battlenet_account LEFT JOIN account_banned ab ON a.id = ab.id LEFT JOIN account_access aa ON a.id = aa.id AND aa.RealmID = -1 WHERE ba.email = ? AND a.username = ?", CONNECTION_SYNCH); + PrepareStatement(LOGIN_SEL_BNET_GAME_ACCOUNTS, "SELECT " BnetGameAccountInfo " FROM account a LEFT JOIN account_banned ab ON a.id = ab.id LEFT JOIN account_access aa ON a.id = aa.id AND aa.RealmID = -1 WHERE battlenet_account = ? ORDER BY a.id", CONNECTION_SYNCH); PrepareStatement(LOGIN_UPD_BNET_FAILED_LOGINS, "UPDATE battlenet_accounts SET failed_logins = failed_logins + 1 WHERE email = ?", CONNECTION_ASYNC); PrepareStatement(LOGIN_UPD_BNET_LAST_LOGIN_INFO, "UPDATE battlenet_accounts SET last_ip = ?, last_login = NOW(), locale = ?, failed_logins = 0, os = ? WHERE id = ?", CONNECTION_ASYNC); PrepareStatement(LOGIN_SEL_BNET_CHARACTER_COUNTS, "SELECT rc.numchars, r.id, r.Region, r.Battlegroup, r.gamebuild FROM realmcharacters rc INNER JOIN realmlist r ON rc.realmid = r.id WHERE rc.acctid = ?", CONNECTION_SYNCH); diff --git a/src/server/shared/Database/Implementation/LoginDatabase.h b/src/server/shared/Database/Implementation/LoginDatabase.h index 727482ff533..56367846644 100644 --- a/src/server/shared/Database/Implementation/LoginDatabase.h +++ b/src/server/shared/Database/Implementation/LoginDatabase.h @@ -125,15 +125,10 @@ enum LoginDatabaseStatements LOGIN_SEL_ACCOUNT_MUTE_INFO, LOGIN_SEL_BNET_ACCOUNT_INFO, - LOGIN_DEL_BNET_EXPIRED_BANS, - LOGIN_SEL_BNET_ACTIVE_ACCOUNT_BAN, LOGIN_UPD_BNET_VS_FIELDS, LOGIN_UPD_BNET_SESSION_KEY, LOGIN_SEL_BNET_RECONNECT_INFO, LOGIN_SEL_BNET_GAME_ACCOUNTS, - LOGIN_SEL_BNET_GAME_ACCOUNT, - LOGIN_SEL_BNET_GAME_ACCOUNT_UNNAMED, - LOGIN_SEL_BNET_FAILED_LOGINS, LOGIN_UPD_BNET_FAILED_LOGINS, LOGIN_UPD_BNET_LAST_LOGIN_INFO, LOGIN_SEL_BNET_CHARACTER_COUNTS, |
