From 0bcc92d90020d0c4f7d3086189cc94e4990517b1 Mon Sep 17 00:00:00 2001 From: Shauren Date: Sat, 19 Jul 2014 17:03:32 +0200 Subject: Part 3: Merge branch 'master' of https://github.com/TrinityCore/TrinityCore into 4.3.4 --- src/server/authserver/Main.cpp | 4 +- .../authserver/Server/BattlenetBitStream.cpp | 24 + src/server/authserver/Server/BattlenetBitStream.h | 27 +- src/server/authserver/Server/BattlenetManager.h | 14 +- src/server/authserver/Server/BattlenetPackets.cpp | 39 +- src/server/authserver/Server/BattlenetPackets.h | 9 +- src/server/authserver/Server/BattlenetSession.cpp | 1024 ++++++++++++++++++++ src/server/authserver/Server/BattlenetSession.h | 130 +++ src/server/authserver/Server/BattlenetSocket.cpp | 1014 ------------------- src/server/authserver/Server/BattlenetSocket.h | 120 --- src/server/game/Accounts/BattlenetAccountMgr.cpp | 3 +- src/server/game/Accounts/BattlenetAccountMgr.h | 1 - src/server/game/Entities/Item/Item.h | 2 +- src/server/game/Entities/Player/Player.cpp | 2 +- src/server/game/Entities/Player/Player.h | 4 +- src/server/scripts/Spells/spell_dk.cpp | 2 +- src/server/scripts/Spells/spell_mage.cpp | 2 +- src/server/scripts/Spells/spell_shaman.cpp | 2 +- 18 files changed, 1240 insertions(+), 1183 deletions(-) create mode 100644 src/server/authserver/Server/BattlenetBitStream.cpp create mode 100644 src/server/authserver/Server/BattlenetSession.cpp create mode 100644 src/server/authserver/Server/BattlenetSession.h delete mode 100644 src/server/authserver/Server/BattlenetSocket.cpp delete mode 100644 src/server/authserver/Server/BattlenetSocket.h (limited to 'src') diff --git a/src/server/authserver/Main.cpp b/src/server/authserver/Main.cpp index 732ed58a19c..9fe6fb276a8 100644 --- a/src/server/authserver/Main.cpp +++ b/src/server/authserver/Main.cpp @@ -33,6 +33,8 @@ #include "AsyncAcceptor.h" #include "AuthSession.h" +#include "BattlenetManager.h" +#include "BattlenetSession.h" #include "Common.h" #include "Configuration/Config.h" #include "Database/DatabaseEnv.h" @@ -117,7 +119,7 @@ int main(int argc, char** argv) std::string bindIp = sConfigMgr->GetStringDefault("BindIP", "0.0.0.0"); AsyncAcceptor authServer(_ioService, bindIp, port); - AsyncAcceptor bnetServer(_ioService, bindIp, 1119); + AsyncAcceptor bnetServer(_ioService, bindIp, 1119); // Set signal handlers boost::asio::signal_set signals(_ioService, SIGINT, SIGTERM); diff --git a/src/server/authserver/Server/BattlenetBitStream.cpp b/src/server/authserver/Server/BattlenetBitStream.cpp new file mode 100644 index 00000000000..906d7802631 --- /dev/null +++ b/src/server/authserver/Server/BattlenetBitStream.cpp @@ -0,0 +1,24 @@ +/* + * Copyright (C) 2008-2014 TrinityCore + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ + +#include "BattlenetBitStream.h" + +template<> +bool Battlenet::BitStream::Read(uint32 /*bitCount*/) +{ + return Read(1) != 0; +} diff --git a/src/server/authserver/Server/BattlenetBitStream.h b/src/server/authserver/Server/BattlenetBitStream.h index 3d1d2d5f67d..e108f810e2b 100644 --- a/src/server/authserver/Server/BattlenetBitStream.h +++ b/src/server/authserver/Server/BattlenetBitStream.h @@ -23,36 +23,24 @@ #include #include #include -#include -#include +#include namespace Battlenet { class BitStreamPositionException : public std::exception { - static uint32 const MessageSize = ACE_Stack_Trace::SYMBUFSIZ + 128; + static uint32 const MessageSize = 128; public: BitStreamPositionException(bool read, uint32 operationSize, uint32 position, uint32 streamSize) { memset(_message, 0, MessageSize); -#ifndef TRINITY_DEBUG - snprintf(_message, MessageSize, "Attempted to %s more bits (%u) %s stream than %s (%u)\nStack trace:\n", + snprintf(_message, MessageSize, "Attempted to %s more bits (%u) %s stream than %s (%u)\n", (read ? "read" : "write"), operationSize + position, (read ? "from" : "to"), (read ? "exist" : "allowed"), streamSize); -#else - ACE_Stack_Trace st(1); - snprintf(_message, MessageSize, "Attempted to %s more bits (%u) %s stream than %s (%u)\nStack trace:\n%s", - (read ? "read" : "write"), - operationSize + position, - (read ? "from" : "to"), - (read ? "exist" : "allowed"), - streamSize, - st.c_str()); -#endif } char const* what() const throw() @@ -67,7 +55,7 @@ namespace Battlenet class BitStream { public: - static uint32 const MaxSize = 0x1000; + static uint32 const MaxSize = 0x4000; // length : The maximum number of bytes to read BitStream(uint32 length) : _numBits(length * 8), _readPos(0), _writePos(0) @@ -95,13 +83,13 @@ namespace Battlenet return str; } - ACE_Auto_Array_Ptr ReadBytes(uint32 count) + std::unique_ptr ReadBytes(uint32 count) { AlignToNextByte(); if (_readPos + count * 8 > _numBits) throw BitStreamPositionException(true, count * 8, _readPos, _numBits); - ACE_Auto_Array_Ptr buf(new uint8[count]); + std::unique_ptr buf(new uint8[count]); memcpy(buf.get(), &_buffer[_readPos >> 3], count); _readPos += count * 8; return buf; @@ -243,4 +231,7 @@ namespace Battlenet }; } +template<> +bool Battlenet::BitStream::Read(uint32 bitCount); + #endif // __BATTLENETBITSTREAM_H__ diff --git a/src/server/authserver/Server/BattlenetManager.h b/src/server/authserver/Server/BattlenetManager.h index 3b8a145f4e9..adef3b49d13 100644 --- a/src/server/authserver/Server/BattlenetManager.h +++ b/src/server/authserver/Server/BattlenetManager.h @@ -19,7 +19,6 @@ #define __BATTLENETMANAGER_H__ #include "Define.h" -#include #include #include #include @@ -85,17 +84,22 @@ namespace Battlenet class BattlenetMgr { - friend class ACE_Singleton; BattlenetMgr() { } ~BattlenetMgr(); public: void Load(); bool HasComponent(Battlenet::Component const* component) const; - bool HasProgram(std::string const& program) const { return _programs.count(program); } - bool HasPlatform(std::string const& platform) const { return _platforms.count(platform); } + bool HasProgram(std::string const& program) const { return _programs.count(program) != 0; } + bool HasPlatform(std::string const& platform) const { return _platforms.count(platform) != 0; } Battlenet::ModuleInfo* CreateModule(std::string const& os, std::string const& name) const; + static BattlenetMgr* instance() + { + static BattlenetMgr instance; + return &instance; + } + private: void LoadComponents(); void LoadModules(); @@ -106,6 +110,6 @@ private: std::map _modules; }; -#define sBattlenetMgr ACE_Singleton::instance() +#define sBattlenetMgr BattlenetMgr::instance() #endif // __BATTLENETMANAGER_H__ diff --git a/src/server/authserver/Server/BattlenetPackets.cpp b/src/server/authserver/Server/BattlenetPackets.cpp index 6a8e09090ef..25a2c6cd9a5 100644 --- a/src/server/authserver/Server/BattlenetPackets.cpp +++ b/src/server/authserver/Server/BattlenetPackets.cpp @@ -20,6 +20,8 @@ #include "Util.h" #include #include +#include +#include std::string Battlenet::PacketHeader::ToString() const { @@ -374,13 +376,13 @@ void Battlenet::RealmUpdate::Write() _stream.WriteString(Version, 5); _stream.Write(Build, 32); - uint32 ip = Address.get_ip_address(); - uint16 port = Address.get_port_number(); + boost::asio::ip::address_v4::bytes_type ip = Address.address().to_v4().to_bytes(); + uint16 port = Address.port(); EndianConvertReverse(ip); EndianConvertReverse(port); - _stream.WriteBytes(&ip, 4); + _stream.WriteBytes(ip.data(), 4); _stream.WriteBytes(&port, 2); } @@ -423,17 +425,27 @@ void Battlenet::RealmJoinResult::Write() _stream.Write(0, 27); _stream.Write(0, 1); // Fail _stream.Write(ServerSeed, 32); - _stream.Write(0, 5); // IPv6 addresses + _stream.Write(IPv6.size(), 5); + for (tcp::endpoint const& addr : IPv6) + { + boost::asio::ip::address_v6::bytes_type ip = addr.address().to_v6().to_bytes(); + uint16 port = addr.port(); + + EndianConvertReverse(port); + + _stream.WriteBytes(ip.data(), 16); + _stream.WriteBytes(&port, 2); + } + _stream.Write(IPv4.size(), 5); - for (ACE_INET_Addr const& addr : IPv4) + for (ip::tcp::endpoint const& addr : IPv4) { - uint32 ip = addr.get_ip_address(); - uint16 port = addr.get_port_number(); + boost::asio::ip::address_v4::bytes_type ip = addr.address().to_v4().to_bytes(); + uint16 port = addr.port(); - EndianConvertReverse(ip); EndianConvertReverse(port); - _stream.WriteBytes(&ip, 4); + _stream.WriteBytes(ip.data(), 4); _stream.WriteBytes(&port, 2); } } @@ -441,9 +453,12 @@ void Battlenet::RealmJoinResult::Write() std::string Battlenet::RealmJoinResult::ToString() const { std::ostringstream stream; - stream << "Battlenet::RealmJoinResult ServerSeed " << ServerSeed << " IPv4 Addresses " << IPv4.size(); - for (ACE_INET_Addr const& addr : IPv4) - stream << std::endl << "Battlenet::RealmJoinResult::Address " << GetAddressString(addr); + stream << "Battlenet::RealmJoinResult ServerSeed " << ServerSeed << " IPv4 Addresses " << IPv4.size() << " IPv6 Addresses " << IPv6.size(); + for (ip::tcp::endpoint const& addr : IPv4) + stream << std::endl << "Battlenet::RealmJoinResult::Address " << boost::lexical_cast(addr); + + for (ip::tcp::endpoint const& addr : IPv6) + stream << std::endl << "Battlenet::RealmJoinResult::Address " << boost::lexical_cast(addr); return stream.str().c_str(); } diff --git a/src/server/authserver/Server/BattlenetPackets.h b/src/server/authserver/Server/BattlenetPackets.h index d9bfe8a4857..14ec80cdbaa 100644 --- a/src/server/authserver/Server/BattlenetPackets.h +++ b/src/server/authserver/Server/BattlenetPackets.h @@ -23,8 +23,10 @@ #include "BattlenetManager.h" #include "Define.h" #include "Errors.h" -#include #include +#include + +using boost::asio::ip::tcp; namespace Battlenet { @@ -315,7 +317,7 @@ namespace Battlenet uint32 Type; std::string Name; std::string Version; - ACE_INET_Addr Address; + ip::tcp::endpoint Address; uint8 Flags; uint8 Region; uint8 Battlegroup; @@ -361,7 +363,8 @@ namespace Battlenet std::string ToString() const override; uint32 ServerSeed; - std::vector IPv4; + std::vector IPv4; + std::vector IPv6; }; } diff --git a/src/server/authserver/Server/BattlenetSession.cpp b/src/server/authserver/Server/BattlenetSession.cpp new file mode 100644 index 00000000000..3725f5dbff8 --- /dev/null +++ b/src/server/authserver/Server/BattlenetSession.cpp @@ -0,0 +1,1024 @@ +/* + * Copyright (C) 2008-2014 TrinityCore + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ + +#include "AuthCodes.h" +#include "BattlenetBitStream.h" +#include "BattlenetSession.h" +#include "Database/DatabaseEnv.h" +#include "HmacHash.h" +#include "Log.h" +#include "RealmList.h" +#include "SHA256.h" +#include +#include + +std::map InitHandlers() +{ + std::map handlers; + + handlers[Battlenet::PacketHeader(Battlenet::CMSG_AUTH_CHALLENGE, Battlenet::AUTHENTICATION)] = &Battlenet::Session::HandleAuthChallenge; + handlers[Battlenet::PacketHeader(Battlenet::CMSG_AUTH_RECONNECT, Battlenet::AUTHENTICATION)] = &Battlenet::Session::HandleAuthReconnect; + handlers[Battlenet::PacketHeader(Battlenet::CMSG_AUTH_PROOF_RESPONSE, Battlenet::AUTHENTICATION)] = &Battlenet::Session::HandleAuthProofResponse; + + handlers[Battlenet::PacketHeader(Battlenet::CMSG_PING, Battlenet::CONNECTION)] = &Battlenet::Session::HandlePing; + handlers[Battlenet::PacketHeader(Battlenet::CMSG_ENABLE_ENCRYPTION, Battlenet::CONNECTION)] = &Battlenet::Session::HandleEnableEncryption; + handlers[Battlenet::PacketHeader(Battlenet::CMSG_DISCONNECT, Battlenet::CONNECTION)] = &Battlenet::Session::HandleDisconnect; + + handlers[Battlenet::PacketHeader(Battlenet::CMSG_REALM_UPDATE_SUBSCRIBE, Battlenet::WOW)] = &Battlenet::Session::HandleRealmUpdateSubscribe; + handlers[Battlenet::PacketHeader(Battlenet::CMSG_JOIN_REQUEST, Battlenet::WOW)] = &Battlenet::Session::HandleRealmJoinRequest; + + return handlers; +} + +std::map Handlers = InitHandlers(); + +Battlenet::Session::ModuleHandler const Battlenet::Session::ModuleHandlers[MODULE_COUNT] = +{ + &Battlenet::Session::HandlePasswordModule, + &Battlenet::Session::UnhandledModule, + &Battlenet::Session::UnhandledModule, + &Battlenet::Session::HandleSelectGameAccountModule, + &Battlenet::Session::HandleRiskFingerprintModule, + &Battlenet::Session::HandleResumeModule, +}; + +Battlenet::Session::Session(tcp::socket&& socket) : _socket(std::move(socket)), _accountId(0), _accountName(), _locale(), + _os(), _build(0), _gameAccountId(0), _gameAccountIndex(0), _accountSecurityLevel(SEC_PLAYER), I(), s(), v(), b(), B(), K(), + _reconnectProof(), _crypt(), _authed(false) +{ + static uint8 const N_Bytes[] = + { + 0xAB, 0x24, 0x43, 0x63, 0xA9, 0xC2, 0xA6, 0xC3, 0x3B, 0x37, 0xE4, 0x61, 0x84, 0x25, 0x9F, 0x8B, + 0x3F, 0xCB, 0x8A, 0x85, 0x27, 0xFC, 0x3D, 0x87, 0xBE, 0xA0, 0x54, 0xD2, 0x38, 0x5D, 0x12, 0xB7, + 0x61, 0x44, 0x2E, 0x83, 0xFA, 0xC2, 0x21, 0xD9, 0x10, 0x9F, 0xC1, 0x9F, 0xEA, 0x50, 0xE3, 0x09, + 0xA6, 0xE5, 0x5E, 0x23, 0xA7, 0x77, 0xEB, 0x00, 0xC7, 0xBA, 0xBF, 0xF8, 0x55, 0x8A, 0x0E, 0x80, + 0x2B, 0x14, 0x1A, 0xA2, 0xD4, 0x43, 0xA9, 0xD4, 0xAF, 0xAD, 0xB5, 0xE1, 0xF5, 0xAC, 0xA6, 0x13, + 0x1C, 0x69, 0x78, 0x64, 0x0B, 0x7B, 0xAF, 0x9C, 0xC5, 0x50, 0x31, 0x8A, 0x23, 0x08, 0x01, 0xA1, + 0xF5, 0xFE, 0x31, 0x32, 0x7F, 0xE2, 0x05, 0x82, 0xD6, 0x0B, 0xED, 0x4D, 0x55, 0x32, 0x41, 0x94, + 0x29, 0x6F, 0x55, 0x7D, 0xE3, 0x0F, 0x77, 0x19, 0xE5, 0x6C, 0x30, 0xEB, 0xDE, 0xF6, 0xA7, 0x86 + }; + + N.SetBinary(N_Bytes, sizeof(N_Bytes)); + g.SetDword(2); + + SHA256Hash sha; + sha.UpdateBigNumbers(&N, &g, NULL); + sha.Finalize(); + k.SetBinary(sha.GetDigest(), sha.GetLength()); +} + +Battlenet::Session::~Session() +{ + TC_LOG_TRACE("server.battlenet", "Battlenet::Session::OnClose"); +} + +void Battlenet::Session::_SetVSFields(std::string const& pstr) +{ + s.SetRand(uint32(BufferSizes::SRP_6_S) * 8); + + BigNumber p; + p.SetHexStr(pstr.c_str()); + + SHA256Hash sha; + sha.UpdateBigNumbers(&s, &p, NULL); + sha.Finalize(); + BigNumber x; + x.SetBinary(sha.GetDigest(), sha.GetLength()); + v = g.ModExp(x, N); + + PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_BNET_VS_FIELDS); + stmt->setString(0, v.AsHexStr()); + stmt->setString(1, s.AsHexStr()); + stmt->setString(2, _accountName); + + LoginDatabase.Execute(stmt); +} + +bool Battlenet::Session::HandleAuthChallenge(PacketHeader& header, BitStream& packet) +{ + // Verify that this IP is not in the ip_banned table + LoginDatabase.Execute(LoginDatabase.GetPreparedStatement(LOGIN_DEL_EXPIRED_IP_BANS)); + + std::string const& ip_address = GetRemoteAddress(); + PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_IP_BANNED); + stmt->setString(0, ip_address); + if (PreparedQueryResult result = LoginDatabase.Query(stmt)) + { + AuthComplete* complete = new AuthComplete(); + complete->SetAuthResult(LOGIN_BANNED); + AsyncWrite(complete); + TC_LOG_DEBUG("server.battlenet", "[Battlenet::AuthChallenge] Banned ip '%s:%d' tries to login!", ip_address.c_str(), GetRemotePort()); + return true; + } + + AuthChallenge info(header, packet); + info.Read(); + + if (info.Program != "WoW") + { + AuthComplete* complete = new AuthComplete(); + complete->SetAuthResult(AUTH_INVALID_PROGRAM); + AsyncWrite(complete); + return true; + } + + if (!sBattlenetMgr->HasPlatform(info.Platform)) + { + AuthComplete* complete = new AuthComplete(); + complete->SetAuthResult(AUTH_INVALID_OS); + AsyncWrite(complete); + return true; + } + + if (!sBattlenetMgr->HasPlatform(info.Locale)) + { + AuthComplete* complete = new AuthComplete(); + complete->SetAuthResult(AUTH_UNSUPPORTED_LANGUAGE); + AsyncWrite(complete); + return true; + } + + for (Component const& component : info.Components) + { + if (!sBattlenetMgr->HasComponent(&component)) + { + AuthComplete* complete = new AuthComplete(); + if (!sBattlenetMgr->HasProgram(component.Program)) + complete->SetAuthResult(AUTH_INVALID_PROGRAM); + else if (!sBattlenetMgr->HasPlatform(component.Platform)) + complete->SetAuthResult(AUTH_INVALID_OS); + else + { + if (component.Program != "WoW" || AuthHelper::IsBuildSupportingBattlenet(component.Build)) + complete->SetAuthResult(AUTH_REGION_BAD_VERSION); + else + complete->SetAuthResult(AUTH_USE_GRUNT_LOGON); + } + + AsyncWrite(complete); + return true; + } + + if (component.Platform == "base") + _build = component.Build; + } + + _accountName = info.Login; + _locale = info.Locale; + _os = info.Platform; + + Utf8ToUpperOnlyLatin(_accountName); + stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_BNET_ACCOUNT_INFO); + stmt->setString(0, _accountName); + + PreparedQueryResult result = LoginDatabase.Query(stmt); + if (!result) + { + AuthComplete* complete = new AuthComplete(); + complete->SetAuthResult(AUTH_UNKNOWN_ACCOUNT); + AsyncWrite(complete); + return true; + } + + Field* fields = result->Fetch(); + + _accountId = fields[1].GetUInt32(); + + // 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 + { + TC_LOG_DEBUG("server.battlenet", "[Battlenet::AuthChallenge] Account '%s' is locked to IP - '%s' is logging in from '%s'", _accountName.c_str(), fields[4].GetCString(), ip_address.c_str()); + + if (strcmp(fields[4].GetCString(), ip_address.c_str()) != 0) + { + AuthComplete* complete = new AuthComplete(); + complete->SetAuthResult(AUTH_ACCOUNT_LOCKED); + AsyncWrite(complete); + return true; + } + } + else + { + TC_LOG_DEBUG("server.battlenet", "[Battlenet::AuthChallenge] Account '%s' is not locked to ip", _accountName.c_str()); + std::string accountCountry = fields[3].GetString(); + if (accountCountry.empty() || accountCountry == "00") + TC_LOG_DEBUG("server.battlenet", "[Battlenet::AuthChallenge] Account '%s' is not locked to country", _accountName.c_str()); + else if (!accountCountry.empty()) + { + uint32 ip = inet_addr(ip_address.c_str()); + EndianConvertReverse(ip); + + stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_LOGON_COUNTRY); + stmt->setUInt32(0, ip); + if (PreparedQueryResult sessionCountryQuery = LoginDatabase.Query(stmt)) + { + std::string loginCountry = (*sessionCountryQuery)[0].GetString(); + TC_LOG_DEBUG("server.battlenet", "[Battlenet::AuthChallenge] Account '%s' is locked to country: '%s' Player country is '%s'", _accountName.c_str(), accountCountry.c_str(), loginCountry.c_str()); + if (loginCountry != accountCountry) + { + AuthComplete* complete = new AuthComplete(); + complete->SetAuthResult(AUTH_ACCOUNT_LOCKED); + AsyncWrite(complete); + return true; + } + } + } + } + + //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) + { + Field* fields = banresult->Fetch(); + if (fields[0].GetUInt32() == fields[1].GetUInt32()) + { + AuthComplete* complete = new AuthComplete(); + complete->SetAuthResult(LOGIN_BANNED); + AsyncWrite(complete); + TC_LOG_DEBUG("server.battlenet", "'%s:%d' [Battlenet::AuthChallenge] Banned account %s tried to login!", ip_address.c_str(), GetRemotePort(), _accountName.c_str()); + return true; + } + else + { + AuthComplete* complete = new AuthComplete(); + complete->SetAuthResult(LOGIN_SUSPENDED); + AsyncWrite(complete); + TC_LOG_DEBUG("server.battlenet", "'%s:%d' [Battlenet::AuthChallenge] Temporarily banned account %s tried to login!", ip_address.c_str(), GetRemotePort(), _accountName.c_str()); + return true; + } + } + + SHA256Hash sha; + sha.UpdateData(_accountName); + sha.Finalize(); + + I.SetBinary(sha.GetDigest(), sha.GetLength()); + + ModuleInfo* password = sBattlenetMgr->CreateModule(_os, "Password"); + ModuleInfo* thumbprint = sBattlenetMgr->CreateModule(_os, "Thumbprint"); + + std::string pStr = fields[0].GetString(); + + std::string databaseV = fields[5].GetString(); + std::string databaseS = fields[6].GetString(); + + if (databaseV.size() != size_t(BufferSizes::SRP_6_V) * 2 || databaseS.size() != size_t(BufferSizes::SRP_6_S) * 2) + _SetVSFields(pStr); + else + { + s.SetHexStr(databaseS.c_str()); + v.SetHexStr(databaseV.c_str()); + } + + b.SetRand(128 * 8); + B = ((v * k) + g.ModExp(b, N)) % N; + BigNumber unk; + unk.SetRand(128 * 8); + + BitStream passwordData; + uint8 state = 0; + passwordData.WriteBytes(&state, 1); + passwordData.WriteBytes(I.AsByteArray(32).get(), 32); + passwordData.WriteBytes(s.AsByteArray(32).get(), 32); + passwordData.WriteBytes(B.AsByteArray(128).get(), 128); + passwordData.WriteBytes(unk.AsByteArray(128).get(), 128); + + password->DataSize = passwordData.GetSize(); + password->Data = new uint8[password->DataSize]; + memcpy(password->Data, passwordData.GetBuffer(), password->DataSize); + + _modulesWaitingForData.push(MODULE_PASSWORD); + + ProofRequest* request = new ProofRequest(); + request->Modules.push_back(password); + // if has authenticator, send Token module + request->Modules.push_back(thumbprint); + AsyncWrite(request); + return true; +} + +bool Battlenet::Session::HandleAuthReconnect(PacketHeader& header, BitStream& packet) +{ + AuthResumeInfo reconnect(header, packet); + reconnect.Read(); + + TC_LOG_DEBUG("server.battlenet", "%s", reconnect.ToString().c_str()); + + _accountName = reconnect.Login; + _locale = reconnect.Locale; + _os = reconnect.Platform; + auto baseComponent = std::find_if(reconnect.Components.begin(), reconnect.Components.end(), [](Component const& c) { return c.Program == "base"; }); + if (baseComponent != reconnect.Components.end()) + _build = baseComponent->Build; + + uint8 accountIndex = atol(reconnect.GameAccountName.substr(reconnect.GameAccountName.find_last_of('#') + 1).c_str()); + + Utf8ToUpperOnlyLatin(_accountName); + PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_BNET_RECONNECT_INFO); + stmt->setString(0, _accountName); + stmt->setUInt8(1, accountIndex); + PreparedQueryResult result = LoginDatabase.Query(stmt); + if (!result) + { + AuthResume* resume = new AuthResume(); + resume->SetAuthResult(AUTH_UNKNOWN_ACCOUNT); + AsyncWrite(resume); + return false; + } + + Field* fields = result->Fetch(); + + _accountId = fields[0].GetUInt32(); + K.SetHexStr(fields[1].GetString().c_str()); + _gameAccountId = fields[2].GetUInt32(); + _gameAccountIndex = accountIndex; + + ModuleInfo* thumbprint = sBattlenetMgr->CreateModule(_os, "Thumbprint"); + ModuleInfo* resume = sBattlenetMgr->CreateModule(_os, "Resume"); + BitStream resumeData; + uint8 state = 0; + _reconnectProof.SetRand(16 * 8); + + resumeData.WriteBytes(&state, 1); + resumeData.WriteBytes(_reconnectProof.AsByteArray().get(), 16); + + resume->DataSize = resumeData.GetSize(); + resume->Data = new uint8[resume->DataSize]; + memcpy(resume->Data, resumeData.GetBuffer(), resume->DataSize); + + _modulesWaitingForData.push(MODULE_RESUME); + + ProofRequest* request = new ProofRequest(); + request->Modules.push_back(thumbprint); + request->Modules.push_back(resume); + AsyncWrite(request); + return true; +} + +bool Battlenet::Session::HandleAuthProofResponse(PacketHeader& header, BitStream& packet) +{ + ProofResponse proof(header, packet); + proof.Read(); + + if (_modulesWaitingForData.size() < proof.Modules.size()) + { + AuthComplete* complete = new AuthComplete(); + complete->SetAuthResult(AUTH_CORRUPTED_MODULE); + AsyncWrite(complete); + return true; + } + + ServerPacket* response = nullptr; + for (size_t i = 0; i < proof.Modules.size(); ++i) + { + if (!(this->*(ModuleHandlers[_modulesWaitingForData.front()]))(proof.Modules[i], &response)) + break; + + _modulesWaitingForData.pop(); + } + + if (!response) + { + response = new AuthComplete(); + static_cast(response)->SetAuthResult(AUTH_INTERNAL_ERROR); + } + + AsyncWrite(response); + return true; +} + +bool Battlenet::Session::HandlePing(PacketHeader& /*header*/, BitStream& /*packet*/) +{ + AsyncWrite(new Pong()); + return true; +} + +bool Battlenet::Session::HandleEnableEncryption(PacketHeader& /*header*/, BitStream& /*packet*/) +{ + _crypt.Init(&K); + return true; +} + +bool Battlenet::Session::HandleDisconnect(PacketHeader& /*header*/, BitStream& /*packet*/) +{ + PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_BNET_SESSION_KEY); + stmt->setString(0, ""); + stmt->setBool(1, false); + stmt->setUInt32(2, _accountId); + LoginDatabase.Execute(stmt); + return true; +} + +bool Battlenet::Session::HandleRealmUpdateSubscribe(PacketHeader& /*header*/, BitStream& /*packet*/) +{ + sRealmList.UpdateIfNeed(); + + RealmCharacterCounts* counts = new RealmCharacterCounts(); + + PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_BNET_CHARACTER_COUNTS); + stmt->setUInt32(0, _gameAccountId); + + if (PreparedQueryResult countResult = LoginDatabase.Query(stmt)) + { + do + { + Field* fields = countResult->Fetch(); + uint32 build = fields[4].GetUInt32(); + counts->CharacterCounts.push_back({ { fields[2].GetUInt8(), fields[3].GetUInt8(), fields[1].GetUInt32(), (_build != build ? build : 0) }, fields[0].GetUInt8() }); + } while (countResult->NextRow()); + } + + for (RealmList::RealmMap::const_iterator i = sRealmList.begin(); i != sRealmList.end(); ++i) + { + Realm const& realm = i->second; + + uint32 flag = realm.flag; + RealmBuildInfo const* buildInfo = AuthHelper::GetBuildInfo(realm.gamebuild); + if (realm.gamebuild != _build) + { + if (!buildInfo) + continue; + + flag |= REALM_FLAG_OFFLINE | REALM_FLAG_SPECIFYBUILD; // tell the client what build the realm is for + } + + if (!buildInfo) + flag &= ~REALM_FLAG_SPECIFYBUILD; + + RealmUpdate* update = new RealmUpdate(); + update->Timezone = realm.timezone; + update->Population = realm.populationLevel; + update->Lock = (realm.allowedSecurityLevel > _accountSecurityLevel) ? 1 : 0; + update->Type = realm.icon; + update->Name = realm.name; + + if (flag & REALM_FLAG_SPECIFYBUILD) + { + std::ostringstream version; + version << buildInfo->MajorVersion << '.' << buildInfo->MinorVersion << '.' << buildInfo->BugfixVersion << '.' << buildInfo->Build; + + update->Version = version.str(); + update->Address = realm.GetAddressForClient(_socket.remote_endpoint().address()); + update->Build = buildInfo->Build; + } + + update->Flags = flag; + update->Region = realm.Region; + update->Battlegroup = realm.Battlegroup; + update->Index = realm.m_ID; + + counts->RealmData.push_back(update); + } + + counts->RealmData.push_back(new RealmUpdateComplete()); + + AsyncWrite(counts); + return true; +} + +bool Battlenet::Session::HandleRealmJoinRequest(PacketHeader& header, BitStream& packet) +{ + RealmJoinRequest join(header, packet); + join.Read(); + + RealmJoinResult* result = new RealmJoinResult(); + Realm const* realm = sRealmList.GetRealm(join.Realm); + if (!realm || realm->flag & (REALM_FLAG_INVALID | REALM_FLAG_OFFLINE)) + { + AsyncWrite(result); + return true; + } + + result->ServerSeed = uint32(rand32()); + + uint8 sessionKey[40]; + HmacSha1 hmac(K.GetNumBytes(), K.AsByteArray().get()); + hmac.UpdateData((uint8*)"WoW\0", 4); + hmac.UpdateData((uint8*)&join.ClientSeed, 4); + hmac.UpdateData((uint8*)&result->ServerSeed, 4); + hmac.Finalize(); + + memcpy(sessionKey, hmac.GetDigest(), hmac.GetLength()); + + HmacSha1 hmac2(K.GetNumBytes(), K.AsByteArray().get()); + hmac2.UpdateData((uint8*)"WoW\0", 4); + hmac2.UpdateData((uint8*)&result->ServerSeed, 4); + hmac2.UpdateData((uint8*)&join.ClientSeed, 4); + hmac2.Finalize(); + + 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(), GetRemoteAddress().c_str(), GetLocaleByName(_locale), _os.c_str(), _gameAccountId); + + result->IPv4.emplace_back(realm->ExternalAddress, realm->port); + if (realm->ExternalAddress != realm->LocalAddress) + result->IPv4.emplace_back(realm->LocalAddress, realm->port); + + AsyncWrite(result); + return true; +} + +void Battlenet::Session::AsyncRead() +{ + auto self(shared_from_this()); + + _socket.async_read_some(boost::asio::buffer(_readBuffer, size_t(BufferSizes::Read)), [this, self](boost::system::error_code error, size_t transferedBytes) + { + if (error) + { + _socket.close(); + return; + } + + BitStream packet(transferedBytes); + std::memcpy(packet.GetBuffer(), _readBuffer, transferedBytes); + _crypt.DecryptRecv(packet.GetBuffer(), transferedBytes); + + while (!packet.IsRead()) + { + try + { + PacketHeader header; + header.Opcode = packet.Read(6); + if (packet.Read(1)) + header.Channel = packet.Read(4); + + if (header.Channel != AUTHENTICATION && !_authed) + { + TC_LOG_DEBUG("server.battlenet", "Battlenet::Session::AsyncRead Received not allowed packet %s", header.ToString().c_str()); + _socket.close(); + return; + } + + TC_LOG_TRACE("server.battlenet", "Battlenet::Session::AsyncRead %s", header.ToString().c_str()); + std::map::const_iterator itr = Handlers.find(header); + if (itr != Handlers.end()) + { + if ((this->*(itr->second))(header, packet)) + break; + } + else + { + TC_LOG_DEBUG("server.battlenet", "Battlenet::Session::AsyncRead Unhandled opcode %s", header.ToString().c_str()); + break; + } + + packet.AlignToNextByte(); + } + catch (BitStreamPositionException const& e) + { + TC_LOG_ERROR("server.battlenet", "Battlenet::Session::AsyncRead Exception: %s", e.what()); + _socket.close(); + return; + } + } + + AsyncRead(); + }); +} + +void Battlenet::Session::Start() +{ + TC_LOG_TRACE("server.battlenet", "Battlenet::Session::Start"); + AsyncRead(); +} + +void Battlenet::Session::AsyncWrite(ServerPacket* packet) +{ + TC_LOG_TRACE("server.battlenet", "Battlenet::Session::AsyncWrite %s", packet->ToString().c_str()); + + packet->Write(); + + _crypt.EncryptSend(const_cast(packet->GetData()), packet->GetSize()); + + auto self(shared_from_this()); + + boost::asio::async_write(_socket, boost::asio::buffer(packet->GetData(), packet->GetSize()), [this, self, packet](boost::system::error_code error, std::size_t /*length*/) + { + if (error) + _socket.close(); + + delete packet; + }); +} + +inline void ReplaceResponse(Battlenet::ServerPacket** oldResponse, Battlenet::ServerPacket* newResponse) +{ + if (*oldResponse) + delete *oldResponse; + + *oldResponse = newResponse; +} + +bool Battlenet::Session::HandlePasswordModule(BitStream* dataStream, ServerPacket** response) +{ + if (dataStream->GetSize() != 1 + 128 + 32 + 128) + { + AuthComplete* complete = new AuthComplete(); + complete->SetAuthResult(AUTH_CORRUPTED_MODULE); + ReplaceResponse(response, complete); + return false; + } + + if (dataStream->Read(8) != 2) // State + { + AuthComplete* complete = new AuthComplete(); + complete->SetAuthResult(AUTH_CORRUPTED_MODULE); + ReplaceResponse(response, complete); + return false; + } + + + BigNumber A, clientM1, clientChallenge; + A.SetBinary(dataStream->ReadBytes(128).get(), 128); + clientM1.SetBinary(dataStream->ReadBytes(32).get(), 32); + clientChallenge.SetBinary(dataStream->ReadBytes(128).get(), 128); + + if (A.isZero()) + { + AuthComplete* complete = new AuthComplete(); + complete->SetAuthResult(AUTH_CORRUPTED_MODULE); + ReplaceResponse(response, complete); + return false; + } + + SHA256Hash sha; + sha.UpdateBigNumbers(&A, &B, NULL); + sha.Finalize(); + + BigNumber u; + u.SetBinary(sha.GetDigest(), sha.GetLength()); + + BigNumber S = ((A * v.ModExp(u, N)) % N).ModExp(b, N); + + uint8 S_bytes[128]; + memcpy(S_bytes, S.AsByteArray(128).get(), 128); + + uint8 part1[64]; + uint8 part2[64]; + + for (int i = 0; i < 64; ++i) + { + part1[i] = S_bytes[i * 2]; + part2[i] = S_bytes[i * 2 + 1]; + } + + SHA256Hash part1sha, part2sha; + part1sha.UpdateData(part1, 64); + part1sha.Finalize(); + part2sha.UpdateData(part2, 64); + part2sha.Finalize(); + + uint8 sessionKey[SHA256_DIGEST_LENGTH * 2]; + for (int i = 0; i < SHA256_DIGEST_LENGTH; ++i) + { + sessionKey[i * 2] = part1sha.GetDigest()[i]; + sessionKey[i * 2 + 1] = part2sha.GetDigest()[i]; + } + + K.SetBinary(sessionKey, SHA256_DIGEST_LENGTH * 2); + + BigNumber M1; + + uint8 hash[SHA256_DIGEST_LENGTH]; + sha.Initialize(); + sha.UpdateBigNumbers(&N, NULL); + sha.Finalize(); + memcpy(hash, sha.GetDigest(), sha.GetLength()); + + sha.Initialize(); + sha.UpdateBigNumbers(&g, NULL); + sha.Finalize(); + + for (int i = 0; i < sha.GetLength(); ++i) + hash[i] ^= sha.GetDigest()[i]; + + SHA256Hash shaI; + shaI.UpdateData(ByteArrayToHexStr(I.AsByteArray().get(), 32)); + shaI.Finalize(); + + // Concat all variables for M1 hash + sha.Initialize(); + sha.UpdateData(hash, SHA256_DIGEST_LENGTH); + sha.UpdateData(shaI.GetDigest(), shaI.GetLength()); + sha.UpdateBigNumbers(&s, &A, &B, &K, NULL); + sha.Finalize(); + + M1.SetBinary(sha.GetDigest(), sha.GetLength()); + + if (memcmp(M1.AsByteArray().get(), clientM1.AsByteArray().get(), 32)) + { + AuthComplete* complete = new AuthComplete(); + complete->SetAuthResult(AUTH_UNKNOWN_ACCOUNT); + ReplaceResponse(response, complete); + 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(); + + if (!numAccounts) + { + AuthComplete* noAccounts = new AuthComplete(); + noAccounts->SetAuthResult(LOGIN_NO_GAME_ACCOUNT); + ReplaceResponse(response, noAccounts); + return false; + } + + Field* fields = result->Fetch(); + + //set expired game account bans to inactive + LoginDatabase.DirectExecute(LoginDatabase.GetPreparedStatement(LOGIN_UPD_EXPIRED_ACCOUNT_BANS)); + + BigNumber M; + sha.Initialize(); + sha.UpdateBigNumbers(&A, &M1, &K, NULL); + sha.Finalize(); + M.SetBinary(sha.GetDigest(), sha.GetLength()); + + BigNumber serverProof; + serverProof.SetRand(128 * 8); // just send garbage, server signature check is patched out in client + + BitStream stream; + ModuleInfo* password = sBattlenetMgr->CreateModule(_os, "Password"); + uint8 state = 3; + + stream.WriteBytes(&state, 1); + stream.WriteBytes(M.AsByteArray(32).get(), 32); + stream.WriteBytes(serverProof.AsByteArray(128).get(), 128); + + password->DataSize = stream.GetSize(); + password->Data = new uint8[password->DataSize]; + memcpy(password->Data, stream.GetBuffer(), password->DataSize); + + ProofRequest* request = new ProofRequest(); + request->Modules.push_back(password); + if (numAccounts > 1) + { + BitStream accounts; + state = 0; + accounts.WriteBytes(&state, 1); + accounts.Write(numAccounts, 8); + do + { + fields = result->Fetch(); + std::ostringstream name; + name << "WoW" << uint32(fields[0].GetUInt8()); + accounts.Write(2, 8); + accounts.WriteString(name.str(), 8); + } while (result->NextRow()); + + ModuleInfo* selectGameAccount = sBattlenetMgr->CreateModule(_os, "SelectGameAccount"); + selectGameAccount->DataSize = accounts.GetSize(); + selectGameAccount->Data = new uint8[selectGameAccount->DataSize]; + memcpy(selectGameAccount->Data, accounts.GetBuffer(), selectGameAccount->DataSize); + request->Modules.push_back(selectGameAccount); + _modulesWaitingForData.push(MODULE_SELECT_GAME_ACCOUNT); + } + else + { + if (fields[4].GetBool()) + { + delete request; + + AuthComplete* complete = new AuthComplete(); + if (fields[2].GetUInt32() == fields[3].GetUInt32()) + { + complete->SetAuthResult(LOGIN_BANNED); + TC_LOG_DEBUG("server.battlenet", "'%s:%d' [Battlenet::AuthChallenge] Banned account %s tried to login!", GetRemoteAddress().c_str(), GetRemotePort(), _accountName.c_str()); + } + else + { + complete->SetAuthResult(LOGIN_SUSPENDED); + TC_LOG_DEBUG("server.battlenet", "'%s:%d' [Battlenet::AuthChallenge] Temporarily banned account %s tried to login!", GetRemoteAddress().c_str(), GetRemotePort(), _accountName.c_str()); + } + + ReplaceResponse(response, complete); + return false; + } + + _gameAccountId = fields[1].GetUInt32(); + _gameAccountIndex = fields[0].GetUInt8(); + + request->Modules.push_back(sBattlenetMgr->CreateModule(_os, "RiskFingerprint")); + _modulesWaitingForData.push(MODULE_RISK_FINGERPRINT); + } + + ReplaceResponse(response, request); + return true; +} + +bool Battlenet::Session::HandleSelectGameAccountModule(BitStream* dataStream, ServerPacket** response) +{ + if (dataStream->Read(8) != 1) + { + AuthComplete* complete = new AuthComplete(); + complete->SetAuthResult(AUTH_CORRUPTED_MODULE); + ReplaceResponse(response, complete); + return false; + } + + dataStream->Read(8); + std::string account = dataStream->ReadString(8); + if (account.length() < 4) + { + AuthComplete* complete = new AuthComplete(); + complete->SetAuthResult(LOGIN_NO_GAME_ACCOUNT); + ReplaceResponse(response, complete); + return false; + } + + uint8 accountIndex = atol(account.substr(3).c_str()); + + PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_BNET_GAME_ACCOUNT); + stmt->setUInt8(0, accountIndex); + stmt->setUInt32(1, _accountId); + PreparedQueryResult result = LoginDatabase.Query(stmt); + if (!result) + { + AuthComplete* complete = new AuthComplete(); + complete->SetAuthResult(LOGIN_NO_GAME_ACCOUNT); + ReplaceResponse(response, complete); + return false; + } + + Field* fields = result->Fetch(); + if (fields[3].GetBool()) + { + AuthComplete* complete = new AuthComplete(); + if (fields[1].GetUInt32() == fields[2].GetUInt32()) + { + complete->SetAuthResult(LOGIN_BANNED); + TC_LOG_DEBUG("server.battlenet", "'%s:%d' [Battlenet::SelectGameAccount] Banned account %s tried to login!", GetRemoteAddress().c_str(), GetRemotePort(), _accountName.c_str()); + } + else + { + complete->SetAuthResult(LOGIN_SUSPENDED); + TC_LOG_DEBUG("server.battlenet", "'%s:%d' [Battlenet::SelectGameAccount] Temporarily banned account %s tried to login!", GetRemoteAddress().c_str(), GetRemotePort(), _accountName.c_str()); + } + + ReplaceResponse(response, complete); + return false; + } + + _gameAccountId = fields[0].GetUInt32(); + _gameAccountIndex = accountIndex; + + ProofRequest* request = new ProofRequest(); + request->Modules.push_back(sBattlenetMgr->CreateModule(_os, "RiskFingerprint")); + ReplaceResponse(response, request); + + _modulesWaitingForData.push(MODULE_RISK_FINGERPRINT); + return true; +} + +bool Battlenet::Session::HandleRiskFingerprintModule(BitStream* dataStream, ServerPacket** response) +{ + AuthComplete* complete = new AuthComplete(); + if (dataStream->Read(8) == 1) + { + std::ostringstream str; + str << _accountId << "#" << uint32(_gameAccountIndex); + + complete->AccountId = _accountId; + complete->GameAccountName = str.str(); + complete->GameAccountFlags = GAMEACCOUNT_FLAG_PROPASS_LOCK; + + SQLTransaction trans = LoginDatabase.BeginTransaction(); + + PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_BNET_LAST_LOGIN_INFO); + stmt->setString(0, GetRemoteAddress()); + stmt->setUInt8(1, GetLocaleByName(_locale)); + stmt->setString(2, _os); + stmt->setUInt32(3, _accountId); + trans->Append(stmt); + + stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_BNET_SESSION_KEY); + stmt->setString(0, K.AsHexStr()); + stmt->setBool(1, true); + stmt->setUInt32(2, _accountId); + trans->Append(stmt); + + LoginDatabase.CommitTransaction(trans); + + _authed = true; + } + else + complete->SetAuthResult(AUTH_BAD_VERSION_HASH); + + ReplaceResponse(response, complete); + return true; +} + +bool Battlenet::Session::HandleResumeModule(BitStream* dataStream, ServerPacket** response) +{ + if (dataStream->Read(8) != 1) + { + AuthResume* complete = new AuthResume(); + complete->SetAuthResult(AUTH_CORRUPTED_MODULE); + ReplaceResponse(response, complete); + return false; + } + + static uint8 const ResumeClient = 0; + static uint8 const ResumeServer = 1; + + std::unique_ptr clientChallenge = dataStream->ReadBytes(16); + std::unique_ptr clientProof = dataStream->ReadBytes(32); + std::unique_ptr serverChallenge = _reconnectProof.AsByteArray(); + std::unique_ptr sessionKey = K.AsByteArray(); + + HmacSha256 clientPart(64, sessionKey.get()); + clientPart.UpdateData(&ResumeClient, 1); + clientPart.UpdateData(clientChallenge.get(), 16); + clientPart.UpdateData(serverChallenge.get(), 16); + clientPart.Finalize(); + + HmacSha256 serverPart(64, sessionKey.get()); + serverPart.UpdateData(&ResumeServer, 1); + serverPart.UpdateData(serverChallenge.get(), 16); + serverPart.UpdateData(clientChallenge.get(), 16); + serverPart.Finalize(); + + uint8 newSessionKey[64]; + memcpy(&newSessionKey[0], clientPart.GetDigest(), clientPart.GetLength()); + memcpy(&newSessionKey[32], serverPart.GetDigest(), serverPart.GetLength()); + + K.SetBinary(newSessionKey, 64); + + HmacSha256 proof(64, newSessionKey); + proof.UpdateData(&ResumeClient, 1); + proof.UpdateData(clientChallenge.get(), 16); + proof.UpdateData(serverChallenge.get(), 16); + proof.Finalize(); + + if (memcmp(proof.GetDigest(), clientProof.get(), serverPart.GetLength())) + { + TC_LOG_DEBUG("server.battlenet", "[Battlenet::Resume] Invalid proof!"); + AuthResume* result = new AuthResume(); + result->SetAuthResult(AUTH_UNKNOWN_ACCOUNT); + ReplaceResponse(response, result); + return false; + } + + PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_BNET_SESSION_KEY); + stmt->setString(0, K.AsHexStr()); + stmt->setBool(1, true); + stmt->setUInt32(2, _accountId); + LoginDatabase.Execute(stmt); + + HmacSha256 serverProof(64, newSessionKey); + serverProof.UpdateData(&ResumeServer, 1); + serverProof.UpdateData(serverChallenge.get(), 16); + serverProof.UpdateData(clientChallenge.get(), 16); + serverProof.Finalize(); + + ModuleInfo* resume = sBattlenetMgr->CreateModule(_os, "Resume"); + + BitStream resumeData; + uint8 state = 2; + resumeData.WriteBytes(&state, 1); + resumeData.WriteBytes(serverProof.GetDigest(), serverProof.GetLength()); + + resume->DataSize = resumeData.GetSize(); + resume->Data = new uint8[resume->DataSize]; + memcpy(resume->Data, resumeData.GetBuffer(), resume->DataSize); + + AuthResume* result = new AuthResume(); + result->Modules.push_back(resume); + ReplaceResponse(response, result); + _authed = true; + return true; +} + +bool Battlenet::Session::UnhandledModule(BitStream* /*dataStream*/, ServerPacket** response) +{ + AuthComplete* complete = new AuthComplete(); + complete->SetAuthResult(AUTH_CORRUPTED_MODULE); + ReplaceResponse(response, complete); + return false; +} diff --git a/src/server/authserver/Server/BattlenetSession.h b/src/server/authserver/Server/BattlenetSession.h new file mode 100644 index 00000000000..ef3e8ae9214 --- /dev/null +++ b/src/server/authserver/Server/BattlenetSession.h @@ -0,0 +1,130 @@ +/* + * Copyright (C) 2008-2014 TrinityCore + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ + +#ifndef _BATTLENETSOCKET_H +#define _BATTLENETSOCKET_H + +#include "BattlenetPackets.h" +#include "BattlenetPacketCrypt.h" +#include "BigNumber.h" +#include +#include + +using boost::asio::ip::tcp; + +namespace Battlenet +{ + struct PacketHeader; + class BitStream; + + enum ModuleType + { + MODULE_PASSWORD, + MODULE_TOKEN, + MODULE_THUMBPRINT, + MODULE_SELECT_GAME_ACCOUNT, + MODULE_RISK_FINGERPRINT, + MODULE_RESUME, + + MODULE_COUNT + }; + + enum class BufferSizes : uint32 + { + SRP_6_V = 0x80, + SRP_6_S = 0x20, + Read = 0x4000 + }; + + class Session : public std::enable_shared_from_this + { + public: + + explicit Session(tcp::socket&& socket); + ~Session(); + + typedef bool(Session::*PacketHandler)(PacketHeader& socket, BitStream& packet); + + // Auth + bool HandleAuthChallenge(PacketHeader& header, BitStream& packet); + bool HandleAuthReconnect(PacketHeader& header, BitStream& packet); + bool HandleAuthProofResponse(PacketHeader& header, BitStream& packet); + + // Creep + bool HandlePing(PacketHeader& header, BitStream& packet); + bool HandleEnableEncryption(PacketHeader& header, BitStream& packet); + bool HandleDisconnect(PacketHeader& header, BitStream& packet); + + // WoW + bool HandleRealmUpdateSubscribe(PacketHeader& header, BitStream& packet); + bool HandleRealmJoinRequest(PacketHeader& header, BitStream& packet); + + void Start(); + void AsyncRead(); + + void AsyncWrite(ServerPacket* packet); + + private: + void _SetVSFields(std::string const& rI); + + typedef bool(Session::*ModuleHandler)(BitStream* dataStream, ServerPacket** response); + static ModuleHandler const ModuleHandlers[MODULE_COUNT]; + + bool HandlePasswordModule(BitStream* dataStream, ServerPacket** response); + bool HandleSelectGameAccountModule(BitStream* dataStream, ServerPacket** response); + bool HandleRiskFingerprintModule(BitStream* dataStream, ServerPacket** response); + bool HandleResumeModule(BitStream* dataStream, ServerPacket** response); + bool UnhandledModule(BitStream* dataStream, ServerPacket** response); + + std::string GetRemoteAddress() const { return _socket.remote_endpoint().address().to_string(); } + uint16 GetRemotePort() const { return _socket.remote_endpoint().port(); } + + tcp::socket _socket; + uint8 _readBuffer[BufferSizes::Read]; + + uint32 _accountId; + std::string _accountName; + std::string _locale; + std::string _os; + uint32 _build; + uint32 _gameAccountId; + uint8 _gameAccountIndex; + AccountTypes _accountSecurityLevel; + + BigNumber N; + BigNumber g; + BigNumber k; + + BigNumber I; + BigNumber s; + BigNumber v; + + BigNumber b; + BigNumber B; + BigNumber K; // session key + + BigNumber _reconnectProof; + + std::queue _modulesWaitingForData; + + PacketCrypt _crypt; + bool _authed; + }; + +} + +#endif // _BATTLENETSOCKET_H diff --git a/src/server/authserver/Server/BattlenetSocket.cpp b/src/server/authserver/Server/BattlenetSocket.cpp deleted file mode 100644 index 1c6951bc608..00000000000 --- a/src/server/authserver/Server/BattlenetSocket.cpp +++ /dev/null @@ -1,1014 +0,0 @@ -/* - * Copyright (C) 2008-2014 TrinityCore - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -#include "AuthCodes.h" -#include "BattlenetBitStream.h" -#include "BattlenetSocket.h" -#include "Database/DatabaseEnv.h" -#include "HmacHash.h" -#include "Log.h" -#include "RealmList.h" -#include "SHA256.h" -#include - -uint32 const Battlenet::Socket::SRP6_V_Size = 128; -uint32 const Battlenet::Socket::SRP6_S_Size = 32; - -std::map InitHandlers() -{ - std::map handlers; - - handlers[Battlenet::PacketHeader(Battlenet::CMSG_AUTH_CHALLENGE, Battlenet::AUTHENTICATION)] = &Battlenet::Socket::HandleAuthChallenge; - handlers[Battlenet::PacketHeader(Battlenet::CMSG_AUTH_RECONNECT, Battlenet::AUTHENTICATION)] = &Battlenet::Socket::HandleAuthReconnect; - handlers[Battlenet::PacketHeader(Battlenet::CMSG_AUTH_PROOF_RESPONSE, Battlenet::AUTHENTICATION)] = &Battlenet::Socket::HandleAuthProofResponse; - - handlers[Battlenet::PacketHeader(Battlenet::CMSG_PING, Battlenet::CONNECTION)] = &Battlenet::Socket::HandlePing; - handlers[Battlenet::PacketHeader(Battlenet::CMSG_ENABLE_ENCRYPTION, Battlenet::CONNECTION)] = &Battlenet::Socket::HandleEnableEncryption; - handlers[Battlenet::PacketHeader(Battlenet::CMSG_DISCONNECT, Battlenet::CONNECTION)] = &Battlenet::Socket::HandleDisconnect; - - handlers[Battlenet::PacketHeader(Battlenet::CMSG_REALM_UPDATE_SUBSCRIBE, Battlenet::WOW)] = &Battlenet::Socket::HandleRealmUpdateSubscribe; - handlers[Battlenet::PacketHeader(Battlenet::CMSG_JOIN_REQUEST, Battlenet::WOW)] = &Battlenet::Socket::HandleRealmJoinRequest; - - return handlers; -} - -std::map Handlers = InitHandlers(); - -Battlenet::Socket::ModuleHandler const Battlenet::Socket::ModuleHandlers[MODULE_COUNT] = -{ - &Battlenet::Socket::HandlePasswordModule, - &Battlenet::Socket::UnhandledModule, - &Battlenet::Socket::UnhandledModule, - &Battlenet::Socket::HandleSelectGameAccountModule, - &Battlenet::Socket::HandleRiskFingerprintModule, - &Battlenet::Socket::HandleResumeModule, -}; - -Battlenet::Socket::Socket(RealmSocket& socket) : _socket(socket), _accountId(0), _accountName(), _locale(), - _os(), _build(0), _gameAccountId(0), _gameAccountIndex(0), _accountSecurityLevel(SEC_PLAYER), I(), s(), v(), b(), B(), K(), - _reconnectProof(), _crypt(), _authed(false) -{ - static uint8 const N_Bytes[] = - { - 0xAB, 0x24, 0x43, 0x63, 0xA9, 0xC2, 0xA6, 0xC3, 0x3B, 0x37, 0xE4, 0x61, 0x84, 0x25, 0x9F, 0x8B, - 0x3F, 0xCB, 0x8A, 0x85, 0x27, 0xFC, 0x3D, 0x87, 0xBE, 0xA0, 0x54, 0xD2, 0x38, 0x5D, 0x12, 0xB7, - 0x61, 0x44, 0x2E, 0x83, 0xFA, 0xC2, 0x21, 0xD9, 0x10, 0x9F, 0xC1, 0x9F, 0xEA, 0x50, 0xE3, 0x09, - 0xA6, 0xE5, 0x5E, 0x23, 0xA7, 0x77, 0xEB, 0x00, 0xC7, 0xBA, 0xBF, 0xF8, 0x55, 0x8A, 0x0E, 0x80, - 0x2B, 0x14, 0x1A, 0xA2, 0xD4, 0x43, 0xA9, 0xD4, 0xAF, 0xAD, 0xB5, 0xE1, 0xF5, 0xAC, 0xA6, 0x13, - 0x1C, 0x69, 0x78, 0x64, 0x0B, 0x7B, 0xAF, 0x9C, 0xC5, 0x50, 0x31, 0x8A, 0x23, 0x08, 0x01, 0xA1, - 0xF5, 0xFE, 0x31, 0x32, 0x7F, 0xE2, 0x05, 0x82, 0xD6, 0x0B, 0xED, 0x4D, 0x55, 0x32, 0x41, 0x94, - 0x29, 0x6F, 0x55, 0x7D, 0xE3, 0x0F, 0x77, 0x19, 0xE5, 0x6C, 0x30, 0xEB, 0xDE, 0xF6, 0xA7, 0x86 - }; - - N.SetBinary(N_Bytes, sizeof(N_Bytes)); - g.SetDword(2); - - SHA256Hash sha; - sha.UpdateBigNumbers(&N, &g, NULL); - sha.Finalize(); - k.SetBinary(sha.GetDigest(), sha.GetLength()); -} - -void Battlenet::Socket::_SetVSFields(std::string const& pstr) -{ - s.SetRand(SRP6_S_Size * 8); - - BigNumber p; - p.SetHexStr(pstr.c_str()); - - SHA256Hash sha; - sha.UpdateBigNumbers(&s, &p, NULL); - sha.Finalize(); - BigNumber x; - x.SetBinary(sha.GetDigest(), sha.GetLength()); - v = g.ModExp(x, N); - - PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_BNET_VS_FIELDS); - stmt->setString(0, v.AsHexStr()); - stmt->setString(1, s.AsHexStr()); - stmt->setString(2, _accountName); - - LoginDatabase.Execute(stmt); -} - -bool Battlenet::Socket::HandleAuthChallenge(PacketHeader& header, BitStream& packet) -{ - // Verify that this IP is not in the ip_banned table - LoginDatabase.Execute(LoginDatabase.GetPreparedStatement(LOGIN_DEL_EXPIRED_IP_BANS)); - - std::string const& ip_address = _socket.getRemoteAddress(); - PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_IP_BANNED); - stmt->setString(0, ip_address); - if (PreparedQueryResult result = LoginDatabase.Query(stmt)) - { - AuthComplete complete; - complete.SetAuthResult(LOGIN_BANNED); - Send(complete); - TC_LOG_DEBUG("server.battlenet", "[Battlenet::AuthChallenge] Banned ip '%s:%d' tries to login!", _socket.getRemoteAddress().c_str(), _socket.getRemotePort()); - return true; - } - - AuthChallenge info(header, packet); - info.Read(); - - if (info.Program != "WoW") - { - AuthComplete complete; - complete.SetAuthResult(AUTH_INVALID_PROGRAM); - Send(complete); - return true; - } - - if (!sBattlenetMgr->HasPlatform(info.Platform)) - { - AuthComplete complete; - complete.SetAuthResult(AUTH_INVALID_OS); - Send(complete); - return true; - } - - if (!sBattlenetMgr->HasPlatform(info.Locale)) - { - AuthComplete complete; - complete.SetAuthResult(AUTH_UNSUPPORTED_LANGUAGE); - Send(complete); - return true; - } - - for (Component const& component : info.Components) - { - if (!sBattlenetMgr->HasComponent(&component)) - { - AuthComplete complete; - if (!sBattlenetMgr->HasProgram(component.Program)) - complete.SetAuthResult(AUTH_INVALID_PROGRAM); - else if (!sBattlenetMgr->HasPlatform(component.Platform)) - complete.SetAuthResult(AUTH_INVALID_OS); - else - { - if (component.Program != "WoW" || AuthHelper::IsBuildSupportingBattlenet(component.Build)) - complete.SetAuthResult(AUTH_REGION_BAD_VERSION); - else - complete.SetAuthResult(AUTH_USE_GRUNT_LOGON); - } - - Send(complete); - return true; - } - - if (component.Platform == "base") - _build = component.Build; - } - - _accountName = info.Login; - _locale = info.Locale; - _os = info.Platform; - - Utf8ToUpperOnlyLatin(_accountName); - stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_BNET_ACCOUNT_INFO); - stmt->setString(0, _accountName); - - PreparedQueryResult result = LoginDatabase.Query(stmt); - if (!result) - { - AuthComplete complete; - complete.SetAuthResult(AUTH_UNKNOWN_ACCOUNT); - Send(complete); - return true; - } - - Field* fields = result->Fetch(); - - _accountId = fields[1].GetUInt32(); - - // 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 - { - TC_LOG_DEBUG("server.battlenet", "[Battlenet::AuthChallenge] Account '%s' is locked to IP - '%s' is logging in from '%s'", _accountName.c_str(), fields[4].GetCString(), ip_address.c_str()); - - if (strcmp(fields[4].GetCString(), ip_address.c_str()) != 0) - { - AuthComplete complete; - complete.SetAuthResult(AUTH_ACCOUNT_LOCKED); - Send(complete); - return true; - } - } - else - { - TC_LOG_DEBUG("server.battlenet", "[Battlenet::AuthChallenge] Account '%s' is not locked to ip", _accountName.c_str()); - std::string accountCountry = fields[3].GetString(); - if (accountCountry.empty() || accountCountry == "00") - TC_LOG_DEBUG("server.battlenet", "[Battlenet::AuthChallenge] Account '%s' is not locked to country", _accountName.c_str()); - else if (!accountCountry.empty()) - { - uint32 ip = inet_addr(ip_address.c_str()); - EndianConvertReverse(ip); - - stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_LOGON_COUNTRY); - stmt->setUInt32(0, ip); - if (PreparedQueryResult sessionCountryQuery = LoginDatabase.Query(stmt)) - { - std::string loginCountry = (*sessionCountryQuery)[0].GetString(); - TC_LOG_DEBUG("server.battlenet", "[Battlenet::AuthChallenge] Account '%s' is locked to country: '%s' Player country is '%s'", _accountName.c_str(), accountCountry.c_str(), loginCountry.c_str()); - if (loginCountry != accountCountry) - { - AuthComplete complete; - complete.SetAuthResult(AUTH_ACCOUNT_LOCKED); - Send(complete); - return true; - } - } - } - } - - //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) - { - Field* fields = banresult->Fetch(); - if (fields[0].GetUInt32() == fields[1].GetUInt32()) - { - AuthComplete complete; - complete.SetAuthResult(LOGIN_BANNED); - Send(complete); - TC_LOG_DEBUG("server.battlenet", "'%s:%d' [Battlenet::AuthChallenge] Banned account %s tried to login!", _socket.getRemoteAddress().c_str(), _socket.getRemotePort(), _accountName.c_str()); - return true; - } - else - { - AuthComplete complete; - complete.SetAuthResult(LOGIN_SUSPENDED); - Send(complete); - TC_LOG_DEBUG("server.battlenet", "'%s:%d' [Battlenet::AuthChallenge] Temporarily banned account %s tried to login!", _socket.getRemoteAddress().c_str(), _socket.getRemotePort(), _accountName.c_str()); - return true; - } - } - - SHA256Hash sha; - sha.UpdateData(_accountName); - sha.Finalize(); - - I.SetBinary(sha.GetDigest(), sha.GetLength()); - - ModuleInfo* password = sBattlenetMgr->CreateModule(_os, "Password"); - ModuleInfo* thumbprint = sBattlenetMgr->CreateModule(_os, "Thumbprint"); - - std::string pStr = fields[0].GetString(); - - std::string databaseV = fields[5].GetString(); - std::string databaseS = fields[6].GetString(); - - if (databaseV.size() != SRP6_V_Size * 2 || databaseS.size() != SRP6_S_Size * 2) - _SetVSFields(pStr); - else - { - s.SetHexStr(databaseS.c_str()); - v.SetHexStr(databaseV.c_str()); - } - - b.SetRand(128 * 8); - B = ((v * k) + g.ModExp(b, N)) % N; - BigNumber unk; - unk.SetRand(128 * 8); - - BitStream passwordData; - uint8 state = 0; - passwordData.WriteBytes(&state, 1); - passwordData.WriteBytes(I.AsByteArray(32).get(), 32); - passwordData.WriteBytes(s.AsByteArray(32).get(), 32); - passwordData.WriteBytes(B.AsByteArray(128).get(), 128); - passwordData.WriteBytes(unk.AsByteArray(128).get(), 128); - - password->DataSize = passwordData.GetSize(); - password->Data = new uint8[password->DataSize]; - memcpy(password->Data, passwordData.GetBuffer(), password->DataSize); - - _modulesWaitingForData.push(MODULE_PASSWORD); - - ProofRequest request; - request.Modules.push_back(password); - // if has authenticator, send Token module - request.Modules.push_back(thumbprint); - Send(request); - return true; -} - -bool Battlenet::Socket::HandleAuthReconnect(PacketHeader& header, BitStream& packet) -{ - AuthResumeInfo reconnect(header, packet); - reconnect.Read(); - - TC_LOG_DEBUG("server.battlenet", "%s", reconnect.ToString().c_str()); - - _accountName = reconnect.Login; - _locale = reconnect.Locale; - _os = reconnect.Platform; - auto baseComponent = std::find_if(reconnect.Components.begin(), reconnect.Components.end(), [](Component const& c) { return c.Program == "base"; }); - if (baseComponent != reconnect.Components.end()) - _build = baseComponent->Build; - - uint8 accountIndex = atol(reconnect.GameAccountName.substr(reconnect.GameAccountName.find_last_of('#') + 1).c_str()); - - Utf8ToUpperOnlyLatin(_accountName); - PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_BNET_RECONNECT_INFO); - stmt->setString(0, _accountName); - stmt->setUInt8(1, accountIndex); - PreparedQueryResult result = LoginDatabase.Query(stmt); - if (!result) - { - AuthResume resume; - resume.SetAuthResult(AUTH_UNKNOWN_ACCOUNT); - Send(resume); - return false; - } - - Field* fields = result->Fetch(); - - _accountId = fields[0].GetUInt32(); - K.SetHexStr(fields[1].GetString().c_str()); - _gameAccountId = fields[2].GetUInt32(); - _gameAccountIndex = accountIndex; - - ModuleInfo* thumbprint = sBattlenetMgr->CreateModule(_os, "Thumbprint"); - ModuleInfo* resume = sBattlenetMgr->CreateModule(_os, "Resume"); - BitStream resumeData; - uint8 state = 0; - _reconnectProof.SetRand(16 * 8); - - resumeData.WriteBytes(&state, 1); - resumeData.WriteBytes(_reconnectProof.AsByteArray().get(), 16); - - resume->DataSize = resumeData.GetSize(); - resume->Data = new uint8[resume->DataSize]; - memcpy(resume->Data, resumeData.GetBuffer(), resume->DataSize); - - _modulesWaitingForData.push(MODULE_RESUME); - - ProofRequest request; - request.Modules.push_back(thumbprint); - request.Modules.push_back(resume); - Send(request); - return true; -} - -bool Battlenet::Socket::HandleAuthProofResponse(PacketHeader& header, BitStream& packet) -{ - ProofResponse proof(header, packet); - proof.Read(); - - if (_modulesWaitingForData.size() < proof.Modules.size()) - { - AuthComplete complete; - complete.SetAuthResult(AUTH_CORRUPTED_MODULE); - Send(complete); - return true; - } - - ServerPacket* response = nullptr; - for (size_t i = 0; i < proof.Modules.size(); ++i) - { - if (!(this->*(ModuleHandlers[_modulesWaitingForData.front()]))(proof.Modules[i], &response)) - break; - - _modulesWaitingForData.pop(); - } - - if (!response) - { - response = new AuthComplete(); - static_cast(response)->SetAuthResult(AUTH_INTERNAL_ERROR); - } - - Send(*response); - delete response; - return true; -} - -bool Battlenet::Socket::HandlePing(PacketHeader& /*header*/, BitStream& /*packet*/) -{ - Pong pong; - Send(pong); - return true; -} - -bool Battlenet::Socket::HandleEnableEncryption(PacketHeader& /*header*/, BitStream& /*packet*/) -{ - _crypt.Init(&K); - return true; -} - -bool Battlenet::Socket::HandleDisconnect(PacketHeader& /*header*/, BitStream& /*packet*/) -{ - PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_BNET_SESSION_KEY); - stmt->setString(0, ""); - stmt->setBool(1, false); - stmt->setUInt32(2, _accountId); - LoginDatabase.Execute(stmt); - return true; -} - -bool Battlenet::Socket::HandleRealmUpdateSubscribe(PacketHeader& /*header*/, BitStream& /*packet*/) -{ - sRealmList->UpdateIfNeed(); - - RealmCharacterCounts counts; - - ACE_INET_Addr clientAddr; - _socket.peer().get_remote_addr(clientAddr); - - PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_BNET_CHARACTER_COUNTS); - stmt->setUInt32(0, _gameAccountId); - - if (PreparedQueryResult countResult = LoginDatabase.Query(stmt)) - { - do - { - Field* fields = countResult->Fetch(); - uint32 build = fields[4].GetUInt32(); - counts.CharacterCounts.push_back({ { fields[2].GetUInt8(), fields[3].GetUInt8(), fields[1].GetUInt32(), (_build != build ? build : 0) }, fields[0].GetUInt8() }); - } while (countResult->NextRow()); - } - - for (RealmList::RealmMap::const_iterator i = sRealmList->begin(); i != sRealmList->end(); ++i) - { - Realm const& realm = i->second; - - uint32 flag = realm.flag; - RealmBuildInfo const* buildInfo = AuthHelper::GetBuildInfo(realm.gamebuild); - if (realm.gamebuild != _build) - { - if (!buildInfo) - continue; - - flag |= REALM_FLAG_OFFLINE | REALM_FLAG_SPECIFYBUILD; // tell the client what build the realm is for - } - - if (!buildInfo) - flag &= ~REALM_FLAG_SPECIFYBUILD; - - RealmUpdate* update = new RealmUpdate(); - update->Timezone = realm.timezone; - update->Population = realm.populationLevel; - update->Lock = (realm.allowedSecurityLevel > _accountSecurityLevel) ? 1 : 0; - update->Type = realm.icon; - update->Name = realm.name; - - if (flag & REALM_FLAG_SPECIFYBUILD) - { - std::ostringstream version; - version << buildInfo->MajorVersion << '.' << buildInfo->MinorVersion << '.' << buildInfo->BugfixVersion << '.' << buildInfo->Build; - - update->Version = version.str(); - update->Address = realm.GetAddressForClient(clientAddr); - update->Build = buildInfo->Build; - } - - update->Flags = flag; - update->Region = realm.Region; - update->Battlegroup = realm.Battlegroup; - update->Index = realm.m_ID; - - counts.RealmData.push_back(update); - } - - counts.RealmData.push_back(new RealmUpdateComplete()); - - Send(counts); - return true; -} - -bool Battlenet::Socket::HandleRealmJoinRequest(PacketHeader& header, BitStream& packet) -{ - RealmJoinRequest join(header, packet); - join.Read(); - - RealmJoinResult result; - Realm const* realm = sRealmList->GetRealm(join.Realm); - if (!realm || realm->flag & (REALM_FLAG_INVALID | REALM_FLAG_OFFLINE)) - { - Send(result); - return true; - } - - result.ServerSeed = uint32(rand32()); - - uint8 sessionKey[40]; - HmacSha1 hmac(K.GetNumBytes(), K.AsByteArray().get()); - hmac.UpdateData((uint8*)"WoW\0", 4); - hmac.UpdateData((uint8*)&join.ClientSeed, 4); - hmac.UpdateData((uint8*)&result.ServerSeed, 4); - hmac.Finalize(); - - memcpy(sessionKey, hmac.GetDigest(), hmac.GetLength()); - - HmacSha1 hmac2(K.GetNumBytes(), K.AsByteArray().get()); - hmac2.UpdateData((uint8*)"WoW\0", 4); - hmac2.UpdateData((uint8*)&result.ServerSeed, 4); - hmac2.UpdateData((uint8*)&join.ClientSeed, 4); - hmac2.Finalize(); - - 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(), _socket.getRemoteAddress().c_str(), GetLocaleByName(_locale), _os.c_str(), _gameAccountId); - - result.IPv4.push_back(realm->ExternalAddress); - if (realm->ExternalAddress != realm->LocalAddress) - result.IPv4.push_back(realm->LocalAddress); - - Send(result); - return true; -} - -void Battlenet::Socket::OnRead() -{ - size_t length = _socket.recv_len(); - if (!length) - return; - - BitStream packet(length); - if (!_socket.recv((char*)packet.GetBuffer(), length)) - return; - - _crypt.DecryptRecv(packet.GetBuffer(), length); - - while (!packet.IsRead()) - { - try - { - PacketHeader header; - header.Opcode = packet.Read(6); - if (packet.Read(1)) - header.Channel = packet.Read(4); - - if (header.Channel != AUTHENTICATION && !_authed) - { - TC_LOG_DEBUG("server.battlenet", "Battlenet::Socket::OnRead Received not allowed packet %s", header.ToString().c_str()); - _socket.shutdown(); - return; - } - - TC_LOG_TRACE("server.battlenet", "Battlenet::Socket::OnRead %s", header.ToString().c_str()); - std::map::const_iterator itr = Handlers.find(header); - if (itr != Handlers.end()) - { - if ((this->*(itr->second))(header, packet)) - break; - } - else - { - TC_LOG_DEBUG("server.battlenet", "Battlenet::Socket::OnRead Unhandled opcode %s", header.ToString().c_str()); - return; - } - - packet.AlignToNextByte(); - } - catch (BitStreamPositionException const& e) - { - TC_LOG_ERROR("server.battlenet", "Battlenet::Socket::OnRead Exception: %s", e.what()); - _socket.shutdown(); - return; - } - } -} - -void Battlenet::Socket::OnAccept() -{ - TC_LOG_TRACE("server.battlenet", "Battlenet::Socket::OnAccept"); -} - -void Battlenet::Socket::OnClose() -{ - TC_LOG_TRACE("server.battlenet", "Battlenet::Socket::OnClose"); -} - -void Battlenet::Socket::Send(ServerPacket& packet) -{ - TC_LOG_TRACE("server.battlenet", "Battlenet::Socket::Send %s", packet.ToString().c_str()); - - packet.Write(); - - _crypt.EncryptSend(const_cast(packet.GetData()), packet.GetSize()); - _socket.send(reinterpret_cast(packet.GetData()), packet.GetSize()); -} - -inline void ReplaceResponse(Battlenet::ServerPacket** oldResponse, Battlenet::ServerPacket* newResponse) -{ - if (*oldResponse) - delete *oldResponse; - - *oldResponse = newResponse; -} - -bool Battlenet::Socket::HandlePasswordModule(BitStream* dataStream, ServerPacket** response) -{ - if (dataStream->GetSize() != 1 + 128 + 32 + 128) - { - AuthComplete* complete = new AuthComplete(); - complete->SetAuthResult(AUTH_CORRUPTED_MODULE); - ReplaceResponse(response, complete); - return false; - } - - if (dataStream->Read(8) != 2) // State - { - AuthComplete* complete = new AuthComplete(); - complete->SetAuthResult(AUTH_CORRUPTED_MODULE); - ReplaceResponse(response, complete); - return false; - } - - - BigNumber A, clientM1, clientChallenge; - A.SetBinary(dataStream->ReadBytes(128).get(), 128); - clientM1.SetBinary(dataStream->ReadBytes(32).get(), 32); - clientChallenge.SetBinary(dataStream->ReadBytes(128).get(), 128); - - if (A.isZero()) - { - AuthComplete* complete = new AuthComplete(); - complete->SetAuthResult(AUTH_CORRUPTED_MODULE); - ReplaceResponse(response, complete); - return false; - } - - SHA256Hash sha; - sha.UpdateBigNumbers(&A, &B, NULL); - sha.Finalize(); - - BigNumber u; - u.SetBinary(sha.GetDigest(), sha.GetLength()); - - BigNumber S = ((A * v.ModExp(u, N)) % N).ModExp(b, N); - - uint8 S_bytes[128]; - memcpy(S_bytes, S.AsByteArray(128).get(), 128); - - uint8 part1[64]; - uint8 part2[64]; - - for (int i = 0; i < 64; ++i) - { - part1[i] = S_bytes[i * 2]; - part2[i] = S_bytes[i * 2 + 1]; - } - - SHA256Hash part1sha, part2sha; - part1sha.UpdateData(part1, 64); - part1sha.Finalize(); - part2sha.UpdateData(part2, 64); - part2sha.Finalize(); - - uint8 sessionKey[SHA256_DIGEST_LENGTH * 2]; - for (int i = 0; i < SHA256_DIGEST_LENGTH; ++i) - { - sessionKey[i * 2] = part1sha.GetDigest()[i]; - sessionKey[i * 2 + 1] = part2sha.GetDigest()[i]; - } - - K.SetBinary(sessionKey, SHA256_DIGEST_LENGTH * 2); - - BigNumber M1; - - uint8 hash[SHA256_DIGEST_LENGTH]; - sha.Initialize(); - sha.UpdateBigNumbers(&N, NULL); - sha.Finalize(); - memcpy(hash, sha.GetDigest(), sha.GetLength()); - - sha.Initialize(); - sha.UpdateBigNumbers(&g, NULL); - sha.Finalize(); - - for (int i = 0; i < sha.GetLength(); ++i) - hash[i] ^= sha.GetDigest()[i]; - - SHA256Hash shaI; - shaI.UpdateData(ByteArrayToHexStr(I.AsByteArray().get(), 32)); - shaI.Finalize(); - - // Concat all variables for M1 hash - sha.Initialize(); - sha.UpdateData(hash, SHA256_DIGEST_LENGTH); - sha.UpdateData(shaI.GetDigest(), shaI.GetLength()); - sha.UpdateBigNumbers(&s, &A, &B, &K, NULL); - sha.Finalize(); - - M1.SetBinary(sha.GetDigest(), sha.GetLength()); - - if (memcmp(M1.AsByteArray().get(), clientM1.AsByteArray().get(), 32)) - { - AuthComplete* complete = new AuthComplete(); - complete->SetAuthResult(AUTH_UNKNOWN_ACCOUNT); - ReplaceResponse(response, complete); - 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(); - - if (!numAccounts) - { - AuthComplete* noAccounts = new AuthComplete(); - noAccounts->SetAuthResult(LOGIN_NO_GAME_ACCOUNT); - ReplaceResponse(response, noAccounts); - return false; - } - - Field* fields = result->Fetch(); - - //set expired game account bans to inactive - LoginDatabase.DirectExecute(LoginDatabase.GetPreparedStatement(LOGIN_UPD_EXPIRED_ACCOUNT_BANS)); - - BigNumber M; - sha.Initialize(); - sha.UpdateBigNumbers(&A, &M1, &K, NULL); - sha.Finalize(); - M.SetBinary(sha.GetDigest(), sha.GetLength()); - - BigNumber serverProof; - serverProof.SetRand(128 * 8); // just send garbage, server signature check is patched out in client - - BitStream stream; - ModuleInfo* password = sBattlenetMgr->CreateModule(_os, "Password"); - uint8 state = 3; - - stream.WriteBytes(&state, 1); - stream.WriteBytes(M.AsByteArray(32).get(), 32); - stream.WriteBytes(serverProof.AsByteArray(128).get(), 128); - - password->DataSize = stream.GetSize(); - password->Data = new uint8[password->DataSize]; - memcpy(password->Data, stream.GetBuffer(), password->DataSize); - - ProofRequest* request = new ProofRequest(); - request->Modules.push_back(password); - if (numAccounts > 1) - { - BitStream accounts; - state = 0; - accounts.WriteBytes(&state, 1); - accounts.Write(numAccounts, 8); - do - { - fields = result->Fetch(); - std::ostringstream name; - name << "WoW" << uint32(fields[0].GetUInt8()); - accounts.Write(2, 8); - accounts.WriteString(name.str(), 8); - } while (result->NextRow()); - - ModuleInfo* selectGameAccount = sBattlenetMgr->CreateModule(_os, "SelectGameAccount"); - selectGameAccount->DataSize = accounts.GetSize(); - selectGameAccount->Data = new uint8[selectGameAccount->DataSize]; - memcpy(selectGameAccount->Data, accounts.GetBuffer(), selectGameAccount->DataSize); - request->Modules.push_back(selectGameAccount); - _modulesWaitingForData.push(MODULE_SELECT_GAME_ACCOUNT); - } - else - { - if (fields[4].GetBool()) - { - delete request; - - AuthComplete* complete = new AuthComplete(); - if (fields[2].GetUInt32() == fields[3].GetUInt32()) - { - complete->SetAuthResult(LOGIN_BANNED); - TC_LOG_DEBUG("server.battlenet", "'%s:%d' [Battlenet::AuthChallenge] Banned account %s tried to login!", _socket.getRemoteAddress().c_str(), _socket.getRemotePort(), _accountName.c_str()); - } - else - { - complete->SetAuthResult(LOGIN_SUSPENDED); - TC_LOG_DEBUG("server.battlenet", "'%s:%d' [Battlenet::AuthChallenge] Temporarily banned account %s tried to login!", _socket.getRemoteAddress().c_str(), _socket.getRemotePort(), _accountName.c_str()); - } - - ReplaceResponse(response, complete); - return false; - } - - _gameAccountId = fields[1].GetUInt32(); - _gameAccountIndex = fields[0].GetUInt8(); - - request->Modules.push_back(sBattlenetMgr->CreateModule(_os, "RiskFingerprint")); - _modulesWaitingForData.push(MODULE_RISK_FINGERPRINT); - } - - ReplaceResponse(response, request); - return true; -} - -bool Battlenet::Socket::HandleSelectGameAccountModule(BitStream* dataStream, ServerPacket** response) -{ - if (dataStream->Read(8) != 1) - { - AuthComplete* complete = new AuthComplete(); - complete->SetAuthResult(AUTH_CORRUPTED_MODULE); - ReplaceResponse(response, complete); - return false; - } - - dataStream->Read(8); - std::string account = dataStream->ReadString(8); - if (account.length() < 4) - { - AuthComplete* complete = new AuthComplete(); - complete->SetAuthResult(LOGIN_NO_GAME_ACCOUNT); - ReplaceResponse(response, complete); - return false; - } - - uint8 accountIndex = atol(account.substr(3).c_str()); - - PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_BNET_GAME_ACCOUNT); - stmt->setUInt8(0, accountIndex); - stmt->setUInt32(1, _accountId); - PreparedQueryResult result = LoginDatabase.Query(stmt); - if (!result) - { - AuthComplete* complete = new AuthComplete(); - complete->SetAuthResult(LOGIN_NO_GAME_ACCOUNT); - ReplaceResponse(response, complete); - return false; - } - - Field* fields = result->Fetch(); - if (fields[3].GetBool()) - { - AuthComplete* complete = new AuthComplete(); - if (fields[1].GetUInt32() == fields[2].GetUInt32()) - { - complete->SetAuthResult(LOGIN_BANNED); - TC_LOG_DEBUG("server.battlenet", "'%s:%d' [Battlenet::SelectGameAccount] Banned account %s tried to login!", _socket.getRemoteAddress().c_str(), _socket.getRemotePort(), _accountName.c_str()); - } - else - { - complete->SetAuthResult(LOGIN_SUSPENDED); - TC_LOG_DEBUG("server.battlenet", "'%s:%d' [Battlenet::SelectGameAccount] Temporarily banned account %s tried to login!", _socket.getRemoteAddress().c_str(), _socket.getRemotePort(), _accountName.c_str()); - } - - ReplaceResponse(response, complete); - return false; - } - - _gameAccountId = fields[0].GetUInt32(); - _gameAccountIndex = accountIndex; - - ProofRequest* request = new ProofRequest(); - request->Modules.push_back(sBattlenetMgr->CreateModule(_os, "RiskFingerprint")); - ReplaceResponse(response, request); - - _modulesWaitingForData.push(MODULE_RISK_FINGERPRINT); - return true; -} - -bool Battlenet::Socket::HandleRiskFingerprintModule(BitStream* dataStream, ServerPacket** response) -{ - AuthComplete* complete = new AuthComplete(); - if (dataStream->Read(8) == 1) - { - std::ostringstream str; - str << _accountId << "#" << uint32(_gameAccountIndex); - - complete->AccountId = _accountId; - complete->GameAccountName = str.str(); - complete->GameAccountFlags = GAMEACCOUNT_FLAG_PROPASS_LOCK; - - SQLTransaction trans = LoginDatabase.BeginTransaction(); - - PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_BNET_LAST_LOGIN_INFO); - stmt->setString(0, _socket.getRemoteAddress()); - stmt->setUInt8(1, GetLocaleByName(_locale)); - stmt->setString(2, _os); - stmt->setUInt32(3, _accountId); - trans->Append(stmt); - - stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_BNET_SESSION_KEY); - stmt->setString(0, K.AsHexStr()); - stmt->setBool(1, true); - stmt->setUInt32(2, _accountId); - trans->Append(stmt); - - LoginDatabase.CommitTransaction(trans); - - _authed = true; - } - else - complete->SetAuthResult(AUTH_BAD_VERSION_HASH); - - ReplaceResponse(response, complete); - return true; -} - -bool Battlenet::Socket::HandleResumeModule(BitStream* dataStream, ServerPacket** response) -{ - if (dataStream->Read(8) != 1) - { - AuthResume* complete = new AuthResume(); - complete->SetAuthResult(AUTH_CORRUPTED_MODULE); - ReplaceResponse(response, complete); - return false; - } - - static uint8 const ResumeClient = 0; - static uint8 const ResumeServer = 1; - - ACE_Auto_Array_Ptr&& clientChallenge = dataStream->ReadBytes(16); - ACE_Auto_Array_Ptr&& clientProof = dataStream->ReadBytes(32); - ACE_Auto_Array_Ptr&& serverChallenge = _reconnectProof.AsByteArray(); - ACE_Auto_Array_Ptr&& sessionKey = K.AsByteArray(); - - HmacSha256 clientPart(64, sessionKey.get()); - clientPart.UpdateData(&ResumeClient, 1); - clientPart.UpdateData(clientChallenge.get(), 16); - clientPart.UpdateData(serverChallenge.get(), 16); - clientPart.Finalize(); - - HmacSha256 serverPart(64, sessionKey.get()); - serverPart.UpdateData(&ResumeServer, 1); - serverPart.UpdateData(serverChallenge.get(), 16); - serverPart.UpdateData(clientChallenge.get(), 16); - serverPart.Finalize(); - - uint8 newSessionKey[64]; - memcpy(&newSessionKey[0], clientPart.GetDigest(), clientPart.GetLength()); - memcpy(&newSessionKey[32], serverPart.GetDigest(), serverPart.GetLength()); - - K.SetBinary(newSessionKey, 64); - - HmacSha256 proof(64, newSessionKey); - proof.UpdateData(&ResumeClient, 1); - proof.UpdateData(clientChallenge.get(), 16); - proof.UpdateData(serverChallenge.get(), 16); - proof.Finalize(); - - if (memcmp(proof.GetDigest(), clientProof.get(), serverPart.GetLength())) - { - TC_LOG_DEBUG("server.battlenet", "[Battlenet::Resume] Invalid proof!"); - AuthResume* result = new AuthResume(); - result->SetAuthResult(AUTH_UNKNOWN_ACCOUNT); - ReplaceResponse(response, result); - return false; - } - - PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_BNET_SESSION_KEY); - stmt->setString(0, K.AsHexStr()); - stmt->setBool(1, true); - stmt->setUInt32(2, _accountId); - LoginDatabase.Execute(stmt); - - HmacSha256 serverProof(64, newSessionKey); - serverProof.UpdateData(&ResumeServer, 1); - serverProof.UpdateData(serverChallenge.get(), 16); - serverProof.UpdateData(clientChallenge.get(), 16); - serverProof.Finalize(); - - ModuleInfo* resume = sBattlenetMgr->CreateModule(_os, "Resume"); - - BitStream resumeData; - uint8 state = 2; - resumeData.WriteBytes(&state, 1); - resumeData.WriteBytes(serverProof.GetDigest(), serverProof.GetLength()); - - resume->DataSize = resumeData.GetSize(); - resume->Data = new uint8[resume->DataSize]; - memcpy(resume->Data, resumeData.GetBuffer(), resume->DataSize); - - AuthResume* result = new AuthResume(); - result->Modules.push_back(resume); - ReplaceResponse(response, result); - _authed = true; - return true; -} - -bool Battlenet::Socket::UnhandledModule(BitStream* /*dataStream*/, ServerPacket** response) -{ - AuthComplete* complete = new AuthComplete(); - complete->SetAuthResult(AUTH_CORRUPTED_MODULE); - ReplaceResponse(response, complete); - return false; -} diff --git a/src/server/authserver/Server/BattlenetSocket.h b/src/server/authserver/Server/BattlenetSocket.h deleted file mode 100644 index ee399e26b09..00000000000 --- a/src/server/authserver/Server/BattlenetSocket.h +++ /dev/null @@ -1,120 +0,0 @@ -/* - * Copyright (C) 2008-2014 TrinityCore - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -#ifndef _BATTLENETSOCKET_H -#define _BATTLENETSOCKET_H - -#include "RealmSocket.h" -#include "BattlenetPackets.h" -#include "BattlenetPacketCrypt.h" -#include "BigNumber.h" - -class ACE_INET_Addr; - -namespace Battlenet -{ - struct PacketHeader; - class BitStream; - - enum ModuleType - { - MODULE_PASSWORD, - MODULE_TOKEN, - MODULE_THUMBPRINT, - MODULE_SELECT_GAME_ACCOUNT, - MODULE_RISK_FINGERPRINT, - MODULE_RESUME, - - MODULE_COUNT - }; - - class Socket : public RealmSocket::Session - { - public: - static uint32 const SRP6_V_Size; - static uint32 const SRP6_S_Size; - - explicit Socket(RealmSocket& socket); - - typedef bool(Socket::*PacketHandler)(PacketHeader& socket, BitStream& packet); - - // Auth - bool HandleAuthChallenge(PacketHeader& header, BitStream& packet); - bool HandleAuthReconnect(PacketHeader& header, BitStream& packet); - bool HandleAuthProofResponse(PacketHeader& header, BitStream& packet); - - // Creep - bool HandlePing(PacketHeader& header, BitStream& packet); - bool HandleEnableEncryption(PacketHeader& header, BitStream& packet); - bool HandleDisconnect(PacketHeader& header, BitStream& packet); - - // WoW - bool HandleRealmUpdateSubscribe(PacketHeader& header, BitStream& packet); - bool HandleRealmJoinRequest(PacketHeader& header, BitStream& packet); - - void OnRead() override; - void OnAccept() override; - void OnClose() override; - - void Send(ServerPacket& packet); - - private: - void _SetVSFields(std::string const& rI); - - typedef bool(Socket::*ModuleHandler)(BitStream* dataStream, ServerPacket** response); - static ModuleHandler const ModuleHandlers[MODULE_COUNT]; - - bool HandlePasswordModule(BitStream* dataStream, ServerPacket** response); - bool HandleSelectGameAccountModule(BitStream* dataStream, ServerPacket** response); - bool HandleRiskFingerprintModule(BitStream* dataStream, ServerPacket** response); - bool HandleResumeModule(BitStream* dataStream, ServerPacket** response); - bool UnhandledModule(BitStream* dataStream, ServerPacket** response); - - RealmSocket& _socket; - - uint32 _accountId; - std::string _accountName; - std::string _locale; - std::string _os; - uint32 _build; - uint32 _gameAccountId; - uint8 _gameAccountIndex; - AccountTypes _accountSecurityLevel; - - BigNumber N; - BigNumber g; - BigNumber k; - - BigNumber I; - BigNumber s; - BigNumber v; - - BigNumber b; - BigNumber B; - BigNumber K; // session key - - BigNumber _reconnectProof; - - std::queue _modulesWaitingForData; - - PacketCrypt _crypt; - bool _authed; - }; - -} - -#endif // _BATTLENETSOCKET_H diff --git a/src/server/game/Accounts/BattlenetAccountMgr.cpp b/src/server/game/Accounts/BattlenetAccountMgr.cpp index 5b419535c11..23c1b7cdd61 100644 --- a/src/server/game/Accounts/BattlenetAccountMgr.cpp +++ b/src/server/game/Accounts/BattlenetAccountMgr.cpp @@ -108,9 +108,8 @@ bool Battlenet::AccountMgr::CheckPassword(uint32 accountId, std::string password PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_BNET_CHECK_PASSWORD); stmt->setUInt32(0, accountId); stmt->setString(1, CalculateShaPassHash(username, password)); - PreparedQueryResult result = LoginDatabase.Query(stmt); - return !result.null(); + return LoginDatabase.Query(stmt) != nullptr; } std::string Battlenet::AccountMgr::CalculateShaPassHash(std::string const& name, std::string const& password) diff --git a/src/server/game/Accounts/BattlenetAccountMgr.h b/src/server/game/Accounts/BattlenetAccountMgr.h index 61bfd044b68..c41a54189e5 100644 --- a/src/server/game/Accounts/BattlenetAccountMgr.h +++ b/src/server/game/Accounts/BattlenetAccountMgr.h @@ -20,7 +20,6 @@ #include "Define.h" #include -#include enum class AccountOpResult : uint8; diff --git a/src/server/game/Entities/Item/Item.h b/src/server/game/Entities/Item/Item.h index 211b5beaf04..ebd66a64838 100644 --- a/src/server/game/Entities/Item/Item.h +++ b/src/server/game/Entities/Item/Item.h @@ -231,7 +231,7 @@ class Item : public Object void SetBinding(bool val) { ApplyModFlag(ITEM_FIELD_FLAGS, ITEM_FLAG_SOULBOUND, val); } bool IsSoulBound() const { return HasFlag(ITEM_FIELD_FLAGS, ITEM_FLAG_SOULBOUND); } bool IsBoundAccountWide() const { return (GetTemplate()->Flags & ITEM_PROTO_FLAG_BIND_TO_ACCOUNT) != 0; } - bool IsBattlenetAccountBound() const { return GetTemplate()->Flags2 & ITEM_FLAGS_EXTRA_BNET_ACCOUNT_BOUND; } + bool IsBattlenetAccountBound() const { return (GetTemplate()->Flags2 & ITEM_FLAGS_EXTRA_BNET_ACCOUNT_BOUND) != 0; } bool IsBindedNotWith(Player const* player) const; bool IsBoundByEnchant() const; virtual void SaveToDB(SQLTransaction& trans); diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index c4a6e1e473b..14149d7ca84 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -8320,7 +8320,7 @@ void Player::_ApplyWeaponDamage(uint8 slot, ItemTemplate const* proto, ScalingSt if (ssv) { float damageMultiplier = 0.0f; - extraDPS = ssv->GetDPSAndDamageMultiplier(proto->SubClass, proto->Flags2 & ITEM_FLAGS_EXTRA_CASTER_WEAPON, &damageMultiplier); + extraDPS = ssv->GetDPSAndDamageMultiplier(proto->SubClass, (proto->Flags2 & ITEM_FLAGS_EXTRA_CASTER_WEAPON) != 0, &damageMultiplier); if (extraDPS) { float average = extraDPS * proto->Delay / 1000.0f; diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h index 9d1dbcc9215..ef65558e13c 100644 --- a/src/server/game/Entities/Player/Player.h +++ b/src/server/game/Entities/Player/Player.h @@ -1663,8 +1663,8 @@ class Player : public Unit, public GridObject static bool LoadPositionFromDB(uint32& mapid, float& x, float& y, float& z, float& o, bool& in_flight, uint64 guid); static bool IsValidGender(uint8 Gender) { return Gender <= GENDER_FEMALE; } - static bool IsValidClass(uint8 Class) { return (1 << (Class - 1)) & CLASSMASK_ALL_PLAYABLE; } - static bool IsValidRace(uint8 Race) { return (1 << (Race - 1)) & RACEMASK_ALL_PLAYABLE; } + static bool IsValidClass(uint8 Class) { return ((1 << (Class - 1)) & CLASSMASK_ALL_PLAYABLE) != 0; } + static bool IsValidRace(uint8 Race) { return ((1 << (Race - 1)) & RACEMASK_ALL_PLAYABLE) != 0; } /*********************************************************/ /*** SAVE SYSTEM ***/ diff --git a/src/server/scripts/Spells/spell_dk.cpp b/src/server/scripts/Spells/spell_dk.cpp index 299be87833e..b75f5091ec2 100644 --- a/src/server/scripts/Spells/spell_dk.cpp +++ b/src/server/scripts/Spells/spell_dk.cpp @@ -619,7 +619,7 @@ class spell_dk_death_strike_enabler : public SpellScriptLoader bool CheckProc(ProcEventInfo& eventInfo) { - return eventInfo.GetDamageInfo(); + return eventInfo.GetDamageInfo() != nullptr; } void HandleProc(AuraEffect const* /*aurEff*/, ProcEventInfo& eventInfo) diff --git a/src/server/scripts/Spells/spell_mage.cpp b/src/server/scripts/Spells/spell_mage.cpp index a7a13b48d39..f72f6435b0c 100644 --- a/src/server/scripts/Spells/spell_mage.cpp +++ b/src/server/scripts/Spells/spell_mage.cpp @@ -825,7 +825,7 @@ class spell_mage_ignite : public SpellScriptLoader bool CheckProc(ProcEventInfo& eventInfo) { - return eventInfo.GetProcTarget(); + return eventInfo.GetProcTarget() != nullptr; } void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) diff --git a/src/server/scripts/Spells/spell_shaman.cpp b/src/server/scripts/Spells/spell_shaman.cpp index 94c304bf82e..486eec6f4df 100644 --- a/src/server/scripts/Spells/spell_shaman.cpp +++ b/src/server/scripts/Spells/spell_shaman.cpp @@ -648,7 +648,7 @@ class spell_sha_healing_stream_totem : public SpellScriptLoader bool Validate(SpellInfo const* /*spellInfo*/) override { - return sSpellMgr->GetSpellInfo(SPELL_SHAMAN_TOTEM_HEALING_STREAM_HEAL); + return sSpellMgr->GetSpellInfo(SPELL_SHAMAN_TOTEM_HEALING_STREAM_HEAL) != nullptr; } void HandleDummy(SpellEffIndex /* effIndex */) -- cgit v1.2.3