diff options
author | Shauren <shauren.trinity@gmail.com> | 2015-06-20 00:59:31 +0200 |
---|---|---|
committer | Shauren <shauren.trinity@gmail.com> | 2015-06-20 00:59:31 +0200 |
commit | 0e49eefe85790ac365c90202a2e22ce6b266ac31 (patch) | |
tree | a1e906d6fb3cf0f0da4fcdf19cd9ed7fab509b28 /src | |
parent | cec05ff07d1751649b6eecff07f23f52ca5443cd (diff) |
Core/DBLayer: Sprinkle some async magic on worldserver auth/session load process
* Implemented base for loading account wide data
Diffstat (limited to 'src')
-rw-r--r-- | src/server/bnetserver/Server/Session.cpp | 4 | ||||
-rw-r--r-- | src/server/game/Accounts/RBAC.cpp | 22 | ||||
-rw-r--r-- | src/server/game/Accounts/RBAC.h | 2 | ||||
-rw-r--r-- | src/server/game/Server/WorldSession.cpp | 131 | ||||
-rw-r--r-- | src/server/game/Server/WorldSession.h | 12 | ||||
-rw-r--r-- | src/server/game/Server/WorldSocket.cpp | 322 | ||||
-rw-r--r-- | src/server/game/Server/WorldSocket.h | 17 | ||||
-rw-r--r-- | src/server/game/World/World.cpp | 22 | ||||
-rw-r--r-- | src/server/shared/Database/Implementation/CharacterDatabase.cpp | 4 | ||||
-rw-r--r-- | src/server/shared/Database/Implementation/LoginDatabase.cpp | 21 | ||||
-rw-r--r-- | src/server/shared/Database/Implementation/LoginDatabase.h | 2 |
11 files changed, 388 insertions, 171 deletions
diff --git a/src/server/bnetserver/Server/Session.cpp b/src/server/bnetserver/Server/Session.cpp index 89818873335..822a90b5222 100644 --- a/src/server/bnetserver/Server/Session.cpp +++ b/src/server/bnetserver/Server/Session.cpp @@ -677,8 +677,8 @@ bool Battlenet::Session::Update() if (_queryFuture.valid() && _queryFuture.wait_for(std::chrono::seconds(0)) == std::future_status::ready) { - _queryCallback(_queryFuture.get()); - _queryCallback = nullptr; + auto callback = std::move(_queryCallback); + callback(_queryFuture.get()); } return true; diff --git a/src/server/game/Accounts/RBAC.cpp b/src/server/game/Accounts/RBAC.cpp index 74ff060636e..3f5cd6b38cf 100644 --- a/src/server/game/Accounts/RBAC.cpp +++ b/src/server/game/Accounts/RBAC.cpp @@ -180,7 +180,24 @@ void RBACData::LoadFromDB() stmt->setUInt32(0, GetId()); stmt->setInt32(1, GetRealmId()); - PreparedQueryResult result = LoginDatabase.Query(stmt); + LoadFromDBCallback(LoginDatabase.Query(stmt)); +} + +PreparedQueryResultFuture RBACData::LoadFromDBAsync() +{ + ClearData(); + + TC_LOG_DEBUG("rbac", "RBACData::LoadFromDB [Id: %u Name: %s]: Loading permissions", GetId(), GetName().c_str()); + // Load account permissions (granted and denied) that affect current realm + PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_RBAC_ACCOUNT_PERMISSIONS); + stmt->setUInt32(0, GetId()); + stmt->setInt32(1, GetRealmId()); + + return LoginDatabase.AsyncQuery(stmt); +} + +void RBACData::LoadFromDBCallback(PreparedQueryResult result) +{ if (result) { do @@ -190,8 +207,7 @@ void RBACData::LoadFromDB() GrantPermission(fields[0].GetUInt32()); else DenyPermission(fields[0].GetUInt32()); - } - while (result->NextRow()); + } while (result->NextRow()); } // Add default permissions diff --git a/src/server/game/Accounts/RBAC.h b/src/server/game/Accounts/RBAC.h index 6d56774e447..78110d83726 100644 --- a/src/server/game/Accounts/RBAC.h +++ b/src/server/game/Accounts/RBAC.h @@ -907,6 +907,8 @@ class RBACData /// Loads all permissions assigned to current account void LoadFromDB(); + PreparedQueryResultFuture LoadFromDBAsync(); + void LoadFromDBCallback(PreparedQueryResult result); /// Sets security level void SetSecurityLevel(uint8 id) diff --git a/src/server/game/Server/WorldSession.cpp b/src/server/game/Server/WorldSession.cpp index 650e100f514..9e89f4f1380 100644 --- a/src/server/game/Server/WorldSession.cpp +++ b/src/server/game/Server/WorldSession.cpp @@ -104,7 +104,7 @@ bool WorldSessionFilter::Process(WorldPacket* packet) } /// WorldSession constructor -WorldSession::WorldSession(uint32 id, uint32 battlenetAccountId, std::shared_ptr<WorldSocket> sock, AccountTypes sec, uint8 expansion, time_t mute_time, LocaleConstant locale, uint32 recruiter, bool isARecruiter): +WorldSession::WorldSession(uint32 id, std::string&& name, uint32 battlenetAccountId, std::shared_ptr<WorldSocket> sock, AccountTypes sec, uint8 expansion, time_t mute_time, LocaleConstant locale, uint32 recruiter, bool isARecruiter): m_muteTime(mute_time), m_timeOutTime(0), AntiDOS(this), @@ -112,6 +112,7 @@ WorldSession::WorldSession(uint32 id, uint32 battlenetAccountId, std::shared_ptr _player(NULL), _security(sec), _accountId(id), + _accountName(std::move(name)), _battlenetAccountId(battlenetAccountId), m_expansion(expansion), _warden(NULL), @@ -711,13 +712,6 @@ void WorldSession::SendConnectToInstance(WorldPackets::Auth::ConnectToSerial ser SendPacket(connectTo.Write()); } -void WorldSession::LoadGlobalAccountData() -{ - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_ACCOUNT_DATA); - stmt->setUInt32(0, GetAccountId()); - LoadAccountData(CharacterDatabase.Query(stmt), GLOBAL_CACHE_MASK); -} - void WorldSession::LoadAccountData(PreparedQueryResult result, uint32 mask) { for (uint32 i = 0; i < NUM_ACCOUNT_DATA_TYPES; ++i) @@ -780,13 +774,11 @@ void WorldSession::SetAccountData(AccountDataType type, uint32 time, std::string _accountData[type].Data = data; } -void WorldSession::LoadTutorialsData() +void WorldSession::LoadTutorialsData(PreparedQueryResult result) { memset(_tutorials, 0, sizeof(uint32) * MAX_ACCOUNT_TUTORIAL_VALUES); - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_TUTORIALS); - stmt->setUInt32(0, GetAccountId()); - if (PreparedQueryResult result = CharacterDatabase.Query(stmt)) + if (result) for (uint8 i = 0; i < MAX_ACCOUNT_TUTORIAL_VALUES; ++i) _tutorials[i] = (*result)[i].GetUInt32(); @@ -959,6 +951,10 @@ void WorldSession::ProcessQueryCallbacks() { PreparedQueryResult result; + if (_realmAccountLoginCallback.valid() && _realmAccountLoginCallback.wait_for(std::chrono::seconds(0)) == std::future_status::ready && + _accountLoginCallback.valid() && _accountLoginCallback.wait_for(std::chrono::seconds(0)) == std::future_status::ready) + InitializeSessionCallback(_realmAccountLoginCallback.get(), _accountLoginCallback.get()); + //! HandleCharEnumOpcode and HandleCharUndeleteEnumOpcode if (_charEnumCallback.IsReady()) { @@ -1094,15 +1090,118 @@ void WorldSession::InitWarden(BigNumber* k, std::string const& os) void WorldSession::LoadPermissions() { uint32 id = GetAccountId(); - std::string name; - AccountMgr::GetName(id, name); uint8 secLevel = GetSecurity(); - _RBACData = new rbac::RBACData(id, name, realmHandle.Index, secLevel); + TC_LOG_DEBUG("rbac", "WorldSession::LoadPermissions [AccountId: %u, Name: %s, realmId: %d, secLevel: %u]", + id, _accountName.c_str(), realmHandle.Index, secLevel); + + _RBACData = new rbac::RBACData(id, _accountName, realmHandle.Index, secLevel); _RBACData->LoadFromDB(); +} + +PreparedQueryResultFuture WorldSession::LoadPermissionsAsync() +{ + uint32 id = GetAccountId(); + uint8 secLevel = GetSecurity(); TC_LOG_DEBUG("rbac", "WorldSession::LoadPermissions [AccountId: %u, Name: %s, realmId: %d, secLevel: %u]", - id, name.c_str(), realmHandle.Index, secLevel); + id, _accountName.c_str(), realmHandle.Index, secLevel); + + _RBACData = new rbac::RBACData(id, _accountName, realmHandle.Index, secLevel); + return _RBACData->LoadFromDBAsync(); +} + +class AccountInfoQueryHolderPerRealm : public SQLQueryHolder +{ +public: + enum + { + GLOBAL_ACCOUNT_DATA = 0, + TUTORIALS, + + MAX_QUERIES + }; + + AccountInfoQueryHolderPerRealm() { SetSize(MAX_QUERIES); } + + bool Initialize(uint32 accountId, uint32 /*battlenetAccountId*/) + { + bool ok = true; + + PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_ACCOUNT_DATA); + stmt->setUInt32(0, accountId); + ok = SetPreparedQuery(GLOBAL_ACCOUNT_DATA, stmt) && ok; + + stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_TUTORIALS); + stmt->setUInt32(0, accountId); + ok = SetPreparedQuery(TUTORIALS, stmt) && ok; + + return ok; + } +}; + +class AccountInfoQueryHolder : public SQLQueryHolder +{ +public: + enum + { + MAX_QUERIES + }; + + AccountInfoQueryHolder() { SetSize(MAX_QUERIES); } + + bool Initialize(uint32 /*accountId*/, uint32 /*battlenetAccountId*/) + { + bool ok = true; + + return ok; + } +}; + +void WorldSession::InitializeSession() +{ + AccountInfoQueryHolderPerRealm* realmHolder = new AccountInfoQueryHolderPerRealm(); + if (!realmHolder->Initialize(GetAccountId(), GetBattlenetAccountId())) + { + delete realmHolder; + SendAuthResponse(AUTH_SYSTEM_ERROR, false); + return; + } + + AccountInfoQueryHolder* holder = new AccountInfoQueryHolder(); + if (!holder->Initialize(GetAccountId(), GetBattlenetAccountId())) + { + delete realmHolder; + delete holder; + SendAuthResponse(AUTH_SYSTEM_ERROR, false); + return; + } + + _realmAccountLoginCallback = CharacterDatabase.DelayQueryHolder(realmHolder); + _accountLoginCallback = LoginDatabase.DelayQueryHolder(holder); +} + +void WorldSession::InitializeSessionCallback(SQLQueryHolder* realmHolder, SQLQueryHolder* holder) +{ + LoadAccountData(realmHolder->GetPreparedResult(AccountInfoQueryHolderPerRealm::GLOBAL_ACCOUNT_DATA), GLOBAL_CACHE_MASK); + LoadTutorialsData(realmHolder->GetPreparedResult(AccountInfoQueryHolderPerRealm::TUTORIALS)); + + if (!m_inQueue) + SendAuthResponse(AUTH_OK, false); + else + SendAuthWaitQue(0); + + SetInQueue(false); + ResetTimeOutTime(); + + SendSetTimeZoneInformation(); + SendFeatureSystemStatusGlueScreen(); + SendAddonsInfo(); + SendClientCacheVersion(sWorld->getIntConfig(CONFIG_CLIENTCACHE_VERSION)); + SendTutorialsData(); + + delete realmHolder; + delete holder; } rbac::RBACData* WorldSession::GetRBACData() diff --git a/src/server/game/Server/WorldSession.h b/src/server/game/Server/WorldSession.h index b46afe6378a..4ea97367d4b 100644 --- a/src/server/game/Server/WorldSession.h +++ b/src/server/game/Server/WorldSession.h @@ -743,7 +743,7 @@ struct PacketCounter class WorldSession { public: - WorldSession(uint32 id, uint32 battlenetAccountId, std::shared_ptr<WorldSocket> sock, AccountTypes sec, uint8 expansion, time_t mute_time, LocaleConstant locale, uint32 recruiter, bool isARecruiter); + WorldSession(uint32 id, std::string&& name, uint32 battlenetAccountId, std::shared_ptr<WorldSocket> sock, AccountTypes sec, uint8 expansion, time_t mute_time, LocaleConstant locale, uint32 recruiter, bool isARecruiter); ~WorldSession(); bool PlayerLoading() const { return !m_playerLoading.IsEmpty(); } @@ -768,9 +768,13 @@ class WorldSession void SendAuthResponse(uint8 code, bool queued, uint32 queuePos = 0); void SendClientCacheVersion(uint32 version); + void InitializeSession(); + void InitializeSessionCallback(SQLQueryHolder* realmHolder, SQLQueryHolder* holder); + rbac::RBACData* GetRBACData(); bool HasPermission(uint32 permissionId); void LoadPermissions(); + PreparedQueryResultFuture LoadPermissionsAsync(); void InvalidateRBACData(); // Used to force LoadPermissions at next HasPermission check AccountTypes GetSecurity() const { return _security; } @@ -853,10 +857,9 @@ class WorldSession // Account Data AccountData const* GetAccountData(AccountDataType type) const { return &_accountData[type]; } void SetAccountData(AccountDataType type, uint32 time, std::string const& data); - void LoadGlobalAccountData(); void LoadAccountData(PreparedQueryResult result, uint32 mask); - void LoadTutorialsData(); + void LoadTutorialsData(PreparedQueryResult result); void SendTutorialsData(); void SaveTutorialsData(SQLTransaction& trans); uint32 GetTutorialInt(uint8 index) const { return _tutorials[index]; } @@ -1537,6 +1540,8 @@ class WorldSession void InitializeQueryCallbackParameters(); void ProcessQueryCallbacks(); + QueryResultHolderFuture _realmAccountLoginCallback; + QueryResultHolderFuture _accountLoginCallback; PreparedQueryResultFuture _addIgnoreCallback; PreparedQueryResultFuture _stablePetCallback; QueryCallback<PreparedQueryResult, bool> _charEnumCallback; @@ -1610,6 +1615,7 @@ class WorldSession AccountTypes _security; uint32 _accountId; + std::string _accountName; uint32 _battlenetAccountId; uint8 m_expansion; diff --git a/src/server/game/Server/WorldSocket.cpp b/src/server/game/Server/WorldSocket.cpp index bc1306d73e1..15dc782a7de 100644 --- a/src/server/game/Server/WorldSocket.cpp +++ b/src/server/game/Server/WorldSocket.cpp @@ -72,6 +72,40 @@ WorldSocket::~WorldSocket() void WorldSocket::Start() { + std::string ip_address = GetRemoteIpAddress().to_string(); + PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_IP_INFO); + stmt->setString(0, ip_address); + stmt->setUInt32(1, inet_addr(ip_address.c_str())); + + _queryCallback = std::bind(&WorldSocket::CheckIpCallback, this, std::placeholders::_1); + _queryFuture = LoginDatabase.AsyncQuery(stmt); +} + +void WorldSocket::CheckIpCallback(PreparedQueryResult result) +{ + if (result) + { + bool banned = false; + do + { + Field* fields = result->Fetch(); + if (fields[0].GetUInt64() != 0) + banned = true; + + if (!fields[1].GetString().empty()) + _ipCountry = fields[1].GetString(); + + } while (result->NextRow()); + + if (banned) + { + SendAuthResponseError(AUTH_REJECT); + TC_LOG_ERROR("network", "WorldSocket::CheckIpCallback: Sent Auth Response (IP %s banned).", GetRemoteIpAddress().to_string().c_str()); + DelayedCloseSocket(); + return; + } + } + AsyncRead(); MessageBuffer initializer; @@ -84,6 +118,23 @@ void WorldSocket::Start() QueuePacket(std::move(initializer), guard); } +bool WorldSocket::Update() +{ + if (!BaseSocket::Update()) + return false; + + { + std::lock_guard<std::mutex> lock(_queryLock); + if (_queryFuture.valid() && _queryFuture.wait_for(std::chrono::seconds(0)) == std::future_status::ready) + { + auto callback = std::move(_queryCallback); + callback(_queryFuture.get()); + } + } + + return true; +} + void WorldSocket::HandleSendAuthSession() { _encryptSeed.SetRand(16 * 8); @@ -246,8 +297,8 @@ bool WorldSocket::ReadDataHandler() return false; } - WorldPackets::Auth::AuthSession authSession(std::move(packet)); - authSession.Read(); + std::shared_ptr<WorldPackets::Auth::AuthSession> authSession = std::make_shared<WorldPackets::Auth::AuthSession>(std::move(packet)); + authSession->Read(); HandleAuthSession(authSession); break; } @@ -262,8 +313,8 @@ bool WorldSocket::ReadDataHandler() return false; } - WorldPackets::Auth::AuthContinuedSession authSession(std::move(packet)); - authSession.Read(); + std::shared_ptr<WorldPackets::Auth::AuthContinuedSession> authSession = std::make_shared<WorldPackets::Auth::AuthContinuedSession>(std::move(packet)); + authSession->Read(); HandleAuthContinuedSession(authSession); break; } @@ -470,23 +521,83 @@ uint32 WorldSocket::CompressPacket(uint8* buffer, WorldPacket const& packet) return bufferSize - _compressionStream->avail_out; } -void WorldSocket::HandleAuthSession(WorldPackets::Auth::AuthSession& authSession) +struct AccountInfo { - uint8 security; - uint32 id; - LocaleConstant locale; - SHA1Hash sha; - BigNumber k; - bool wardenActive = sWorld->getBoolConfig(CONFIG_WARDEN_ENABLED); + struct + { + uint32 Id; + bool IsLockedToIP; + std::string LastIP; + LocaleConstant Locale; + std::string OS; + bool IsBanned; + + std::string LockCountry; + } BattleNet; + + struct + { + uint32 Id; + BigNumber SessionKey; + uint8 Expansion; + int64 MuteTime; + uint32 Recruiter; + bool IsRectuiter; + AccountTypes Security; + bool IsBanned; + } Game; + + bool IsBanned() const { return BattleNet.IsBanned || Game.IsBanned; } + + explicit AccountInfo(Field* fields) + { + // 0 1 2 3 4 5 6 7 8 9 10 + // SELECT a.id, a.sessionkey, ba.last_ip, ba.locked, a.expansion, a.mutetime, ba.locale, a.recruiter, ba.os, ba.id, aa.gmLevel, + // 11 12 13 + // bab.unbandate > UNIX_TIMESTAMP() OR bab.unbandate = bab.bandate, ab.unbandate > UNIX_TIMESTAMP() OR ab.unbandate = ab.bandate, r.id + // FROM account a LEFT JOIN battlenet_accounts ba ON a.battlenet_account = ba.id LEFT JOIN account_access aa ON a.id = aa.id AND aa.RealmID IN (-1, ?) + // LEFT JOIN battlenet_account_bans bab ON ba.id = bab.id LEFT JOIN account_banned ab ON a.id = ab.id LEFT JOIN account r ON a.id = r.recruiter + // WHERE a.username = ? ORDER BY aa.RealmID DESC LIMIT 1 + Game.Id = fields[0].GetUInt32(); + Game.SessionKey.SetHexStr(fields[1].GetCString()); + BattleNet.LastIP = fields[2].GetString(); + BattleNet.IsLockedToIP = fields[3].GetBool(); + Game.Expansion = fields[4].GetUInt8(); + Game.MuteTime = fields[5].GetInt64(); + BattleNet.Locale = LocaleConstant(fields[6].GetUInt8()); + Game.Recruiter = fields[7].GetUInt32(); + BattleNet.OS = fields[8].GetString(); + BattleNet.Id = fields[9].GetUInt32(); + Game.Security = AccountTypes(fields[10].GetUInt8()); + BattleNet.IsBanned = fields[11].GetUInt64() != 0; + Game.IsBanned = fields[12].GetUInt64() != 0; + Game.IsRectuiter = fields[13].GetUInt32() != 0; + + uint32 world_expansion = sWorld->getIntConfig(CONFIG_EXPANSION); + if (Game.Expansion > world_expansion) + Game.Expansion = world_expansion; + + if (BattleNet.Locale >= TOTAL_LOCALES) + BattleNet.Locale = LOCALE_enUS; + } +}; +void WorldSocket::HandleAuthSession(std::shared_ptr<WorldPackets::Auth::AuthSession> authSession) +{ // Get the account information from the auth database - // 0 1 2 3 4 5 6 7 8 - // SELECT id, sessionkey, last_ip, locked, expansion, mutetime, locale, recruiter, os FROM account WHERE username = ? PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_ACCOUNT_INFO_BY_NAME); - stmt->setString(0, authSession.Account); + stmt->setInt32(0, int32(realmHandle.Index)); + stmt->setString(1, authSession->Account); - PreparedQueryResult result = LoginDatabase.Query(stmt); + { + std::lock_guard<std::mutex> lock(_queryLock); + _queryCallback = std::bind(&WorldSocket::HandleAuthSessionCallback, this, authSession, std::placeholders::_1); + _queryFuture = LoginDatabase.AsyncQuery(stmt); + } +} +void WorldSocket::HandleAuthSessionCallback(std::shared_ptr<WorldPackets::Auth::AuthSession> authSession, PreparedQueryResult result) +{ // Stop if the account is not found if (!result) { @@ -497,32 +608,20 @@ void WorldSocket::HandleAuthSession(WorldPackets::Auth::AuthSession& authSession return; } - Field* fields = result->Fetch(); - - uint8 expansion = fields[4].GetUInt8(); - uint32 world_expansion = sWorld->getIntConfig(CONFIG_EXPANSION); - if (expansion > world_expansion) - expansion = world_expansion; + AccountInfo account(result->Fetch()); // For hook purposes, we get Remoteaddress at this point. std::string address = GetRemoteIpAddress().to_string(); // As we don't know if attempted login process by ip works, we update last_attempt_ip right away - stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_LAST_ATTEMPT_IP); - + PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_LAST_ATTEMPT_IP); stmt->setString(0, address); - stmt->setString(1, authSession.Account); - + stmt->setString(1, authSession->Account); LoginDatabase.Execute(stmt); // This also allows to check for possible "hack" attempts on account - // id has to be fetched at this point, so that first actual account response that fails can be logged - id = fields[0].GetUInt32(); - - k.SetHexStr(fields[1].GetCString()); - // even if auth credentials are bad, try using the session key we have - client cannot read auth response error without it - _authCrypt.Init(&k); + _authCrypt.Init(&account.Game.SessionKey); _headerBuffer.Resize(SizeOfClientHeader[1][1]); // First reject the connection if packet contains invalid data or realm state doesn't allow logging in @@ -534,7 +633,7 @@ void WorldSocket::HandleAuthSession(WorldPackets::Auth::AuthSession& authSession return; } - if (authSession.RealmID != realmHandle.Index) + if (authSession->RealmID != realmHandle.Index) { SendAuthResponseError(REALM_LIST_REALM_NOT_FOUND); TC_LOG_ERROR("network", "WorldSocket::HandleAuthSession: Sent Auth Response (bad realm)."); @@ -542,13 +641,20 @@ void WorldSocket::HandleAuthSession(WorldPackets::Auth::AuthSession& authSession return; } - std::string os = fields[8].GetString(); - // Must be done before WorldSession is created - if (wardenActive && os != "Win" && os != "OSX") + bool wardenActive = sWorld->getBoolConfig(CONFIG_WARDEN_ENABLED); + if (wardenActive && account.BattleNet.OS != "Win" && account.BattleNet.OS != "Wn64" && account.BattleNet.OS != "Mc64") + { + SendAuthResponseError(AUTH_REJECT); + TC_LOG_ERROR("network", "WorldSocket::HandleAuthSession: Client %s attempted to log in using invalid client OS (%s).", address.c_str(), account.BattleNet.OS.c_str()); + DelayedCloseSocket(); + return; + } + + if (!account.BattleNet.Id || authSession->LoginServerType != 1) { SendAuthResponseError(AUTH_REJECT); - TC_LOG_ERROR("network", "WorldSocket::HandleAuthSession: Client %s attempted to log in using invalid client OS (%s).", address.c_str(), os.c_str()); + TC_LOG_ERROR("network", "WorldSocket::HandleAuthSession: Client %s (%s) attempted to log in using deprecated login method (GRUNT).", authSession->Account.c_str(), address.c_str()); DelayedCloseSocket(); return; } @@ -556,151 +662,138 @@ void WorldSocket::HandleAuthSession(WorldPackets::Auth::AuthSession& authSession // Check that Key and account name are the same on client and server uint32 t = 0; - sha.UpdateData(authSession.Account); + SHA1Hash sha; + sha.UpdateData(authSession->Account); sha.UpdateData((uint8*)&t, 4); - sha.UpdateData((uint8*)&authSession.LocalChallenge, 4); + sha.UpdateData((uint8*)&authSession->LocalChallenge, 4); sha.UpdateData((uint8*)&_authSeed, 4); - sha.UpdateBigNumbers(&k, NULL); + sha.UpdateBigNumbers(&account.Game.SessionKey, NULL); sha.Finalize(); - if (memcmp(sha.GetDigest(), authSession.Digest, SHA_DIGEST_LENGTH) != 0) + if (memcmp(sha.GetDigest(), authSession->Digest, SHA_DIGEST_LENGTH) != 0) { SendAuthResponseError(AUTH_FAILED); - TC_LOG_ERROR("network", "WorldSocket::HandleAuthSession: Authentication failed for account: %u ('%s') address: %s", id, authSession.Account.c_str(), address.c_str()); + TC_LOG_ERROR("network", "WorldSocket::HandleAuthSession: Authentication failed for account: %u ('%s') address: %s", account.Game.Id, authSession->Account.c_str(), address.c_str()); DelayedCloseSocket(); return; } ///- Re-check ip locking (same check as in auth). - if (fields[3].GetUInt8() == 1) // if ip is locked + if (account.BattleNet.IsLockedToIP) + { + if (account.BattleNet.LastIP != address) + { + SendAuthResponseError(AUTH_FAILED); + TC_LOG_DEBUG("network", "WorldSocket::HandleAuthSession: Sent Auth Response (Account IP differs. Original IP: %s, new IP: %s).", account.BattleNet.LastIP.c_str(), address.c_str()); + // We could log on hook only instead of an additional db log, however action logger is config based. Better keep DB logging as well + sScriptMgr->OnFailedAccountLogin(account.Game.Id); + DelayedCloseSocket(); + return; + } + } + else if (!account.BattleNet.LockCountry.empty() && !_ipCountry.empty()) { - if (strcmp(fields[2].GetCString(), address.c_str()) != 0) + if (account.BattleNet.LockCountry != _ipCountry) { SendAuthResponseError(AUTH_FAILED); - TC_LOG_DEBUG("network", "WorldSocket::HandleAuthSession: Sent Auth Response (Account IP differs. Original IP: %s, new IP: %s).", fields[2].GetCString(), address.c_str()); + TC_LOG_DEBUG("network", "WorldSocket::HandleAuthSession: Sent Auth Response (Account country differs. Original country: %s, new country: %s).", account.BattleNet.LockCountry.c_str(), _ipCountry.c_str()); // We could log on hook only instead of an additional db log, however action logger is config based. Better keep DB logging as well - sScriptMgr->OnFailedAccountLogin(id); + sScriptMgr->OnFailedAccountLogin(account.Game.Id); DelayedCloseSocket(); return; } } - int64 mutetime = fields[5].GetInt64(); + int64 mutetime = account.Game.MuteTime; //! Negative mutetime indicates amount of seconds to be muted effective on next login - which is now. if (mutetime < 0) { mutetime = time(NULL) + llabs(mutetime); stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_MUTE_TIME_LOGIN); - stmt->setInt64(0, mutetime); - stmt->setUInt32(1, id); - + stmt->setUInt32(1, account.Game.Id); LoginDatabase.Execute(stmt); } - locale = LocaleConstant(fields[6].GetUInt8()); - if (locale >= TOTAL_LOCALES) - locale = LOCALE_enUS; - - uint32 recruiter = fields[7].GetUInt32(); - - uint32 battlenetAccountId = 0; - if (authSession.LoginServerType == 1) - battlenetAccountId = Battlenet::AccountMgr::GetIdByGameAccount(id); - - // Checks gmlevel per Realm - stmt = LoginDatabase.GetPreparedStatement(LOGIN_GET_GMLEVEL_BY_REALMID); - - stmt->setUInt32(0, id); - stmt->setInt32(1, int32(realmHandle.Index)); - - result = LoginDatabase.Query(stmt); - - if (!result) - security = 0; - else - { - fields = result->Fetch(); - security = fields[0].GetUInt8(); - } - - // Re-check account ban (same check as in auth) - stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_BANS); - - stmt->setUInt32(0, id); - stmt->setString(1, address); - - PreparedQueryResult banresult = LoginDatabase.Query(stmt); - - if (banresult) // if account banned + if (account.IsBanned()) { SendAuthResponseError(AUTH_BANNED); TC_LOG_ERROR("network", "WorldSocket::HandleAuthSession: Sent Auth Response (Account banned)."); - sScriptMgr->OnFailedAccountLogin(id); + sScriptMgr->OnFailedAccountLogin(account.Game.Id); DelayedCloseSocket(); return; } // Check locked state for server AccountTypes allowedAccountType = sWorld->GetPlayerSecurityLimit(); - TC_LOG_DEBUG("network", "Allowed Level: %u Player Level %u", allowedAccountType, AccountTypes(security)); - if (allowedAccountType > SEC_PLAYER && AccountTypes(security) < allowedAccountType) + TC_LOG_DEBUG("network", "Allowed Level: %u Player Level %u", allowedAccountType, account.Game.Security); + if (allowedAccountType > SEC_PLAYER && account.Game.Security < allowedAccountType) { SendAuthResponseError(AUTH_UNAVAILABLE); TC_LOG_DEBUG("network", "WorldSocket::HandleAuthSession: User tries to login but his security level is not enough"); - sScriptMgr->OnFailedAccountLogin(id); + sScriptMgr->OnFailedAccountLogin(account.Game.Id); DelayedCloseSocket(); return; } - TC_LOG_DEBUG("network", "WorldSocket::HandleAuthSession: Client '%s' authenticated successfully from %s.", - authSession.Account.c_str(), address.c_str()); - - // Check if this user is by any chance a recruiter - stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_ACCOUNT_RECRUITER); - - stmt->setUInt32(0, id); - - result = LoginDatabase.Query(stmt); - - bool isRecruiter = false; - if (result) - isRecruiter = true; + TC_LOG_DEBUG("network", "WorldSocket::HandleAuthSession: Client '%s' authenticated successfully from %s.", authSession->Account.c_str(), address.c_str()); // Update the last_ip in the database as it was successful for login stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_LAST_IP); stmt->setString(0, address); - stmt->setString(1, authSession.Account); + stmt->setString(1, authSession->Account); LoginDatabase.Execute(stmt); // At this point, we can safely hook a successful login - sScriptMgr->OnAccountLogin(id); + sScriptMgr->OnAccountLogin(account.Game.Id); _authed = true; - _worldSession = new WorldSession(id, battlenetAccountId, shared_from_this(), AccountTypes(security), expansion, mutetime, locale, recruiter, isRecruiter); - _worldSession->LoadGlobalAccountData(); - _worldSession->LoadTutorialsData(); - _worldSession->ReadAddonsInfo(authSession.AddonInfo); - _worldSession->LoadPermissions(); + _worldSession = new WorldSession(account.Game.Id, std::move(authSession->Account), account.BattleNet.Id, shared_from_this(), account.Game.Security, + account.Game.Expansion, mutetime, account.BattleNet.Locale, account.Game.Recruiter, account.Game.IsRectuiter); + _worldSession->ReadAddonsInfo(authSession->AddonInfo); // Initialize Warden system only if it is enabled by config if (wardenActive) - _worldSession->InitWarden(&k, os); + _worldSession->InitWarden(&account.Game.SessionKey, account.BattleNet.OS); + + _queryCallback = std::bind(&WorldSocket::LoadSessionPermissionsCallback, this, std::placeholders::_1); + _queryFuture = _worldSession->LoadPermissionsAsync(); +} + +void WorldSocket::LoadSessionPermissionsCallback(PreparedQueryResult result) +{ + // RBAC must be loaded before adding session to check for skip queue permission + _worldSession->GetRBACData()->LoadFromDBCallback(result); sWorld->AddSession(_worldSession); } -void WorldSocket::HandleAuthContinuedSession(WorldPackets::Auth::AuthContinuedSession& authSession) +void WorldSocket::HandleAuthContinuedSession(std::shared_ptr<WorldPackets::Auth::AuthContinuedSession> authSession) { - uint32 accountId = PAIR64_LOPART(authSession.Key); - _type = ConnectionType(PAIR64_HIPART(authSession.Key)); + _type = ConnectionType(PAIR64_HIPART(authSession->Key)); + if (_type != CONNECTION_TYPE_INSTANCE) + { + SendAuthResponseError(AUTH_UNKNOWN_ACCOUNT); + DelayedCloseSocket(); + return; + } + uint32 accountId = PAIR64_LOPART(authSession->Key); PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_ACCOUNT_INFO_CONTINUED_SESSION); stmt->setUInt32(0, accountId); - PreparedQueryResult result = LoginDatabase.Query(stmt); + + { + std::lock_guard<std::mutex> lock(_queryLock); + _queryCallback = std::bind(&WorldSocket::HandleAuthContinuedSessionCallback, this, authSession, std::placeholders::_1); + _queryFuture = LoginDatabase.AsyncQuery(stmt); + } +} + +void WorldSocket::HandleAuthContinuedSessionCallback(std::shared_ptr<WorldPackets::Auth::AuthContinuedSession> authSession, PreparedQueryResult result) +{ if (!result) { SendAuthResponseError(AUTH_UNKNOWN_ACCOUNT); @@ -708,6 +801,7 @@ void WorldSocket::HandleAuthContinuedSession(WorldPackets::Auth::AuthContinuedSe return; } + uint32 accountId = PAIR64_LOPART(authSession->Key); Field* fields = result->Fetch(); std::string login = fields[0].GetString(); BigNumber k; @@ -722,7 +816,7 @@ void WorldSocket::HandleAuthContinuedSession(WorldPackets::Auth::AuthContinuedSe sha.UpdateData((uint8*)&_authSeed, 4); sha.Finalize(); - if (memcmp(sha.GetDigest(), authSession.Digest, sha.GetLength())) + if (memcmp(sha.GetDigest(), authSession->Digest, sha.GetLength())) { SendAuthResponseError(AUTH_UNKNOWN_ACCOUNT); TC_LOG_ERROR("network", "WorldSocket::HandleAuthContinuedSession: Authentication failed for account: %u ('%s') address: %s", accountId, login.c_str(), GetRemoteIpAddress().to_string().c_str()); diff --git a/src/server/game/Server/WorldSocket.h b/src/server/game/Server/WorldSocket.h index b82029f88d5..bb4e3c3ee4a 100644 --- a/src/server/game/Server/WorldSocket.h +++ b/src/server/game/Server/WorldSocket.h @@ -72,6 +72,8 @@ class WorldSocket : public Socket<WorldSocket> static std::string const ClientConnectionInitialize; static uint32 const MinSizeForCompression; + typedef Socket<WorldSocket> BaseSocket; + public: WorldSocket(tcp::socket&& socket); ~WorldSocket(); @@ -80,6 +82,7 @@ public: WorldSocket& operator=(WorldSocket const& right) = delete; void Start() override; + bool Update() override; void SendPacket(WorldPacket const& packet); @@ -94,6 +97,8 @@ protected: bool ReadHeaderHandler(); bool ReadDataHandler(); private: + void CheckIpCallback(PreparedQueryResult result); + /// writes network.opcode log /// accessing WorldSession is not threadsafe, only do it when holding _worldSessionLock void LogOpcodeText(OpcodeClient opcode, std::unique_lock<std::mutex> const& guard) const; @@ -103,8 +108,11 @@ private: uint32 CompressPacket(uint8* buffer, WorldPacket const& packet); void HandleSendAuthSession(); - void HandleAuthSession(WorldPackets::Auth::AuthSession& authSession); - void HandleAuthContinuedSession(WorldPackets::Auth::AuthContinuedSession& authSession); + void HandleAuthSession(std::shared_ptr<WorldPackets::Auth::AuthSession> authSession); + void HandleAuthSessionCallback(std::shared_ptr<WorldPackets::Auth::AuthSession> authSession, PreparedQueryResult result); + void HandleAuthContinuedSession(std::shared_ptr<WorldPackets::Auth::AuthContinuedSession> authSession); + void HandleAuthContinuedSessionCallback(std::shared_ptr<WorldPackets::Auth::AuthContinuedSession> authSession, PreparedQueryResult result); + void LoadSessionPermissionsCallback(PreparedQueryResult result); void HandleConnectToFailed(WorldPackets::Auth::ConnectToFailed& connectToFailed); bool HandlePing(WorldPacket& recvPacket); @@ -131,6 +139,11 @@ private: z_stream_s* _compressionStream; bool _initialized; + + std::mutex _queryLock; + PreparedQueryResultFuture _queryFuture; + std::function<void(PreparedQueryResult)> _queryCallback; + std::string _ipCountry; }; #endif diff --git a/src/server/game/World/World.cpp b/src/server/game/World/World.cpp index 0e98eb265cc..54c926eea71 100644 --- a/src/server/game/World/World.cpp +++ b/src/server/game/World/World.cpp @@ -282,14 +282,7 @@ void World::AddSession_(WorldSession* s) return; } - s->SendAuthResponse(AUTH_OK, false); - - s->SendSetTimeZoneInformation(); - s->SendFeatureSystemStatusGlueScreen(); - - s->SendAddonsInfo(); - s->SendClientCacheVersion(sWorld->getIntConfig(CONFIG_CLIENTCACHE_VERSION)); - s->SendTutorialsData(); + s->InitializeSession(); UpdateMaxSessionCounters(); @@ -394,18 +387,7 @@ bool World::RemoveQueuedPlayer(WorldSession* sess) if ((!m_playerLimit || sessions < m_playerLimit) && !m_QueuedPlayer.empty()) { WorldSession* pop_sess = m_QueuedPlayer.front(); - pop_sess->SetInQueue(false); - pop_sess->ResetTimeOutTime(); - pop_sess->SendAuthWaitQue(0); - - pop_sess->SendSetTimeZoneInformation(); - pop_sess->SendFeatureSystemStatusGlueScreen(); - - pop_sess->SendAddonsInfo(); - - pop_sess->SendClientCacheVersion(sWorld->getIntConfig(CONFIG_CLIENTCACHE_VERSION)); - pop_sess->SendTutorialsData(); - + pop_sess->InitializeSession(); m_QueuedPlayer.pop_front(); // update iter to point first queued socket or end() if queue is empty now diff --git a/src/server/shared/Database/Implementation/CharacterDatabase.cpp b/src/server/shared/Database/Implementation/CharacterDatabase.cpp index 277ccd4569a..53fc0bba831 100644 --- a/src/server/shared/Database/Implementation/CharacterDatabase.cpp +++ b/src/server/shared/Database/Implementation/CharacterDatabase.cpp @@ -276,7 +276,7 @@ void CharacterDatabaseConnection::DoPrepareStatements() PrepareStatement(CHAR_DEL_PLAYER_CURRENCY, "DELETE FROM character_currency WHERE CharacterGuid = ?", CONNECTION_ASYNC); // Account data - PrepareStatement(CHAR_SEL_ACCOUNT_DATA, "SELECT type, time, data FROM account_data WHERE accountId = ?", CONNECTION_SYNCH); + PrepareStatement(CHAR_SEL_ACCOUNT_DATA, "SELECT type, time, data FROM account_data WHERE accountId = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_REP_ACCOUNT_DATA, "REPLACE INTO account_data (accountId, type, time, data) VALUES (?, ?, ?, ?)", CONNECTION_ASYNC); PrepareStatement(CHAR_DEL_ACCOUNT_DATA, "DELETE FROM account_data WHERE accountId = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_SEL_PLAYER_ACCOUNT_DATA, "SELECT type, time, data FROM character_account_data WHERE guid = ?", CONNECTION_ASYNC); @@ -284,7 +284,7 @@ void CharacterDatabaseConnection::DoPrepareStatements() PrepareStatement(CHAR_DEL_PLAYER_ACCOUNT_DATA, "DELETE FROM character_account_data WHERE guid = ?", CONNECTION_ASYNC); // Tutorials - PrepareStatement(CHAR_SEL_TUTORIALS, "SELECT tut0, tut1, tut2, tut3, tut4, tut5, tut6, tut7 FROM account_tutorial WHERE accountId = ?", CONNECTION_SYNCH); + PrepareStatement(CHAR_SEL_TUTORIALS, "SELECT tut0, tut1, tut2, tut3, tut4, tut5, tut6, tut7 FROM account_tutorial WHERE accountId = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_SEL_HAS_TUTORIALS, "SELECT 1 FROM account_tutorial WHERE accountId = ?", CONNECTION_SYNCH); PrepareStatement(CHAR_INS_TUTORIALS, "INSERT INTO account_tutorial(tut0, tut1, tut2, tut3, tut4, tut5, tut6, tut7, accountId) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)", CONNECTION_ASYNC); PrepareStatement(CHAR_UPD_TUTORIALS, "UPDATE account_tutorial SET tut0 = ?, tut1 = ?, tut2 = ?, tut3 = ?, tut4 = ?, tut5 = ?, tut6 = ?, tut7 = ? WHERE accountId = ?", CONNECTION_ASYNC); diff --git a/src/server/shared/Database/Implementation/LoginDatabase.cpp b/src/server/shared/Database/Implementation/LoginDatabase.cpp index 0b2967f8922..51a0217ac17 100644 --- a/src/server/shared/Database/Implementation/LoginDatabase.cpp +++ b/src/server/shared/Database/Implementation/LoginDatabase.cpp @@ -34,12 +34,17 @@ void LoginDatabaseConnection::DoPrepareStatements() PrepareStatement(LOGIN_SEL_ACCOUNT_BANNED_ALL, "SELECT account.id, username FROM account, account_banned WHERE account.id = account_banned.id AND active = 1 GROUP BY account.id", CONNECTION_SYNCH); PrepareStatement(LOGIN_SEL_ACCOUNT_BANNED_BY_USERNAME, "SELECT account.id, username FROM account, account_banned WHERE account.id = account_banned.id AND active = 1 AND username LIKE CONCAT('%%', ?, '%%') GROUP BY account.id", CONNECTION_SYNCH); PrepareStatement(LOGIN_DEL_ACCOUNT_BANNED, "DELETE FROM account_banned WHERE id = ?", CONNECTION_ASYNC); - PrepareStatement(LOGIN_SEL_ACCOUNT_INFO_CONTINUED_SESSION, "SELECT username, sessionkey FROM account WHERE id = ?", CONNECTION_SYNCH); + PrepareStatement(LOGIN_SEL_ACCOUNT_INFO_CONTINUED_SESSION, "SELECT username, sessionkey FROM account WHERE id = ?", CONNECTION_ASYNC); PrepareStatement(LOGIN_UPD_VS, "UPDATE account SET v = ?, s = ? WHERE username = ?", CONNECTION_ASYNC); PrepareStatement(LOGIN_SEL_LOGON_COUNTRY, "SELECT country FROM ip2nation WHERE ip < ? ORDER BY ip DESC LIMIT 0,1", CONNECTION_SYNCH); PrepareStatement(LOGIN_SEL_ACCOUNT_ID_BY_NAME, "SELECT id FROM account WHERE username = ?", CONNECTION_SYNCH); PrepareStatement(LOGIN_SEL_ACCOUNT_LIST_BY_NAME, "SELECT id, username FROM account WHERE username = ?", CONNECTION_SYNCH); - PrepareStatement(LOGIN_SEL_ACCOUNT_INFO_BY_NAME, "SELECT id, sessionkey, last_ip, locked, expansion, mutetime, locale, recruiter, os FROM account WHERE username = ?", CONNECTION_SYNCH); + PrepareStatement(LOGIN_SEL_ACCOUNT_INFO_BY_NAME, "SELECT a.id, a.sessionkey, ba.last_ip, ba.locked, a.expansion, a.mutetime, ba.locale, a.recruiter, ba.os, ba.id, aa.gmLevel, " + "bab.unbandate > UNIX_TIMESTAMP() OR bab.unbandate = bab.bandate, ab.unbandate > UNIX_TIMESTAMP() OR ab.unbandate = ab.bandate, r.id " + "FROM account a LEFT JOIN battlenet_accounts ba ON a.battlenet_account = ba.id LEFT JOIN account_access aa ON a.id = aa.id AND aa.RealmID IN (-1, ?) " + "LEFT JOIN battlenet_account_bans bab ON ba.id = bab.id LEFT JOIN account_banned ab ON a.id = ab.id LEFT JOIN account r ON a.id = r.recruiter " + "WHERE a.username = ? ORDER BY aa.RealmID DESC LIMIT 1", CONNECTION_ASYNC); + PrepareStatement(LOGIN_SEL_ACCOUNT_LIST_BY_EMAIL, "SELECT id, username FROM account WHERE email = ?", CONNECTION_SYNCH); PrepareStatement(LOGIN_SEL_ACCOUNT_BY_IP, "SELECT id, username FROM account WHERE last_ip = ?", CONNECTION_SYNCH); PrepareStatement(LOGIN_SEL_ACCOUNT_BY_ID, "SELECT 1 FROM account WHERE id = ?", CONNECTION_SYNCH); @@ -83,8 +88,6 @@ void LoginDatabaseConnection::DoPrepareStatements() PrepareStatement(LOGIN_SEL_ACCOUNT_INFO, "SELECT a.username, a.last_ip, aa.gmlevel, a.expansion FROM account a LEFT JOIN account_access aa ON (a.id = aa.id) WHERE a.id = ?", CONNECTION_SYNCH); PrepareStatement(LOGIN_SEL_ACCOUNT_ACCESS_GMLEVEL_TEST, "SELECT 1 FROM account_access WHERE id = ? AND gmlevel > ?", CONNECTION_SYNCH); PrepareStatement(LOGIN_SEL_ACCOUNT_ACCESS, "SELECT a.id, aa.gmlevel, aa.RealmID FROM account a LEFT JOIN account_access aa ON (a.id = aa.id) WHERE a.username = ?", CONNECTION_SYNCH); - PrepareStatement(LOGIN_SEL_ACCOUNT_RECRUITER, "SELECT 1 FROM account WHERE recruiter = ?", CONNECTION_SYNCH); - PrepareStatement(LOGIN_SEL_BANS, "SELECT 1 FROM account_banned WHERE id = ? AND active = 1 UNION SELECT 1 FROM ip_banned WHERE ip = ?", CONNECTION_SYNCH); PrepareStatement(LOGIN_SEL_ACCOUNT_WHOIS, "SELECT username, email, last_ip FROM account WHERE id = ?", CONNECTION_SYNCH); PrepareStatement(LOGIN_SEL_LAST_ATTEMPT_IP, "SELECT last_attempt_ip FROM account WHERE id = ?", CONNECTION_SYNCH); PrepareStatement(LOGIN_SEL_LAST_IP, "SELECT last_ip FROM account WHERE id = ?", CONNECTION_SYNCH); @@ -103,7 +106,7 @@ void LoginDatabaseConnection::DoPrepareStatements() PrepareStatement(LOGIN_INS_FALP_IP_LOGGING, "INSERT INTO logs_ip_actions (account_id,character_guid,type,ip,systemnote,unixtime,time) VALUES ((SELECT id FROM account WHERE username = ?), 0, 1, ?, ?, unix_timestamp(NOW()), NOW())", CONNECTION_ASYNC); PrepareStatement(LOGIN_SEL_ACCOUNT_ACCESS_BY_ID, "SELECT gmlevel, RealmID FROM account_access WHERE id = ? and (RealmID = ? OR RealmID = -1) ORDER BY gmlevel desc", CONNECTION_SYNCH); - PrepareStatement(LOGIN_SEL_RBAC_ACCOUNT_PERMISSIONS, "SELECT permissionId, granted FROM rbac_account_permissions WHERE accountId = ? AND (realmId = ? OR realmId = -1) ORDER BY permissionId, realmId", CONNECTION_SYNCH); + PrepareStatement(LOGIN_SEL_RBAC_ACCOUNT_PERMISSIONS, "SELECT permissionId, granted FROM rbac_account_permissions WHERE accountId = ? AND (realmId = ? OR realmId = -1) ORDER BY permissionId, realmId", CONNECTION_BOTH); PrepareStatement(LOGIN_INS_RBAC_ACCOUNT_PERMISSION, "INSERT INTO rbac_account_permissions (accountId, permissionId, granted, realmId) VALUES (?, ?, ?, ?) ON DUPLICATE KEY UPDATE granted = VALUES(granted)", CONNECTION_ASYNC); PrepareStatement(LOGIN_DEL_RBAC_ACCOUNT_PERMISSION, "DELETE FROM rbac_account_permissions WHERE accountId = ? AND permissionId = ? AND (realmId = ? OR realmId = -1)", CONNECTION_ASYNC); @@ -113,10 +116,14 @@ void LoginDatabaseConnection::DoPrepareStatements() #define BnetAccountInfo "ba.id, UPPER(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, " 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 = ?", CONNECTION_ASYNC); + PrepareStatement(LOGIN_SEL_BNET_ACCOUNT_INFO, "SELECT " BnetAccountInfo ", ba.sha_pass_hash, ba.v, ba.s, " 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 = ?", CONNECTION_ASYNC); 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 " 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_ASYNC); + 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_ASYNC); 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_ASYNC); diff --git a/src/server/shared/Database/Implementation/LoginDatabase.h b/src/server/shared/Database/Implementation/LoginDatabase.h index c0aa178f199..06d13f29da3 100644 --- a/src/server/shared/Database/Implementation/LoginDatabase.h +++ b/src/server/shared/Database/Implementation/LoginDatabase.h @@ -101,8 +101,6 @@ enum LoginDatabaseStatements LOGIN_SEL_ACCOUNT_INFO, LOGIN_SEL_ACCOUNT_ACCESS_GMLEVEL_TEST, LOGIN_SEL_ACCOUNT_ACCESS, - LOGIN_SEL_ACCOUNT_RECRUITER, - LOGIN_SEL_BANS, LOGIN_SEL_ACCOUNT_WHOIS, LOGIN_SEL_REALMLIST_SECURITY_LEVEL, LOGIN_DEL_ACCOUNT, |