aboutsummaryrefslogtreecommitdiff
path: root/src/server/authserver/Server/BattlenetSession.cpp
diff options
context:
space:
mode:
authorShauren <shauren.trinity@gmail.com>2014-10-18 17:03:30 +0200
committerShauren <shauren.trinity@gmail.com>2014-10-18 17:03:30 +0200
commit8936723291985d1759a4903901c7a29cc54fdcbf (patch)
tree2ca2331742863ef6318697075aad5ff3f8e76715 /src/server/authserver/Server/BattlenetSession.cpp
parent3ee9961ecce2a745134eeefa45b29109a276e49f (diff)
parent4a0be2bffc21e30624122ec5f36d6c8479f83385 (diff)
Merge branch '4.3.4' of https://github.com/TrinityCore/TrinityCore into 6.x
Conflicts: dep/PackageList.txt src/server/bnetserver/Packets/WoWRealmPackets.cpp src/server/bnetserver/Server/Session.cpp
Diffstat (limited to 'src/server/authserver/Server/BattlenetSession.cpp')
-rw-r--r--src/server/authserver/Server/BattlenetSession.cpp1041
1 files changed, 0 insertions, 1041 deletions
diff --git a/src/server/authserver/Server/BattlenetSession.cpp b/src/server/authserver/Server/BattlenetSession.cpp
deleted file mode 100644
index 860c557b46a..00000000000
--- a/src/server/authserver/Server/BattlenetSession.cpp
+++ /dev/null
@@ -1,1041 +0,0 @@
-/*
- * Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/>
- *
- * 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 <http://www.gnu.org/licenses/>.
- */
-
-#include "AuthCodes.h"
-#include "BattlenetBitStream.h"
-#include "BattlenetSessionManager.h"
-#include "Database/DatabaseEnv.h"
-#include "HmacHash.h"
-#include "Log.h"
-#include "RealmList.h"
-#include "SHA256.h"
-#include <map>
-#include <boost/asio/write.hpp>
-
-std::map<Battlenet::PacketHeader, Battlenet::Session::PacketHandler> InitHandlers()
-{
- std::map<Battlenet::PacketHeader, Battlenet::Session::PacketHandler> handlers;
-
- handlers[Battlenet::PacketHeader(Battlenet::Authentication::CMSG_LOGON_REQUEST_3, Battlenet::AUTHENTICATION)] = &Battlenet::Session::HandleLogonRequest;
- handlers[Battlenet::PacketHeader(Battlenet::Authentication::CMSG_RESUME_REQUEST, Battlenet::AUTHENTICATION)] = &Battlenet::Session::HandleResumeRequest;
- handlers[Battlenet::PacketHeader(Battlenet::Authentication::CMSG_PROOF_RESPONSE, Battlenet::AUTHENTICATION)] = &Battlenet::Session::HandleProofResponse;
-
- handlers[Battlenet::PacketHeader(Battlenet::Connection::CMSG_PING, Battlenet::CONNECTION)] = &Battlenet::Session::HandlePing;
- handlers[Battlenet::PacketHeader(Battlenet::Connection::CMSG_ENABLE_ENCRYPTION, Battlenet::CONNECTION)] = &Battlenet::Session::HandleEnableEncryption;
- handlers[Battlenet::PacketHeader(Battlenet::Connection::CMSG_LOGOUT_REQUEST, Battlenet::CONNECTION)] = &Battlenet::Session::HandleLogoutRequest;
-
- handlers[Battlenet::PacketHeader(Battlenet::WoWRealm::CMSG_LIST_SUBSCRIBE_REQUEST, Battlenet::WOWREALM)] = &Battlenet::Session::HandleListSubscribeRequest;
- handlers[Battlenet::PacketHeader(Battlenet::WoWRealm::CMSG_JOIN_REQUEST_V2, Battlenet::WOWREALM)] = &Battlenet::Session::HandleJoinRequestV2;
-
- return handlers;
-}
-
-std::map<Battlenet::PacketHeader, Battlenet::Session::PacketHandler> 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), _gameAccountName(), _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()
-{
- sBattlenetSessionMgr.RemoveSession(this);
- 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::HandleLogonRequest(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 ip_address = GetRemoteIpAddress().to_string();
- PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_IP_BANNED);
- stmt->setString(0, ip_address);
- if (PreparedQueryResult result = LoginDatabase.Query(stmt))
- {
- Authentication::LogonResponse* complete = new Authentication::LogonResponse();
- 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;
- }
-
- Authentication::LogonRequest3 info(header, packet);
- info.Read();
-
- if (info.Program != "WoW")
- {
- Authentication::LogonResponse* complete = new Authentication::LogonResponse();
- complete->SetAuthResult(AUTH_INVALID_PROGRAM);
- AsyncWrite(complete);
- return true;
- }
-
- if (!sBattlenetMgr->HasPlatform(info.Platform))
- {
- Authentication::LogonResponse* complete = new Authentication::LogonResponse();
- complete->SetAuthResult(AUTH_INVALID_OS);
- AsyncWrite(complete);
- return true;
- }
-
- if (!sBattlenetMgr->HasPlatform(info.Locale))
- {
- Authentication::LogonResponse* complete = new Authentication::LogonResponse();
- complete->SetAuthResult(AUTH_UNSUPPORTED_LANGUAGE);
- AsyncWrite(complete);
- return true;
- }
-
- for (Component const& component : info.Components)
- {
- if (!sBattlenetMgr->HasComponent(&component))
- {
- Authentication::LogonResponse* complete = new Authentication::LogonResponse();
- 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)
- {
- Authentication::LogonResponse* complete = new Authentication::LogonResponse();
- 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)
- {
- Authentication::LogonResponse* complete = new Authentication::LogonResponse();
- 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)
- {
- Authentication::LogonResponse* complete = new Authentication::LogonResponse();
- 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())
- {
- Authentication::LogonResponse* complete = new Authentication::LogonResponse();
- 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
- {
- Authentication::LogonResponse* complete = new Authentication::LogonResponse();
- 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);
-
- Authentication::ProofRequest* request = new Authentication::ProofRequest();
- request->Modules.push_back(password);
- // if has authenticator, send Token module
- request->Modules.push_back(thumbprint);
- AsyncWrite(request);
- return true;
-}
-
-bool Battlenet::Session::HandleResumeRequest(PacketHeader& header, BitStream& packet)
-{
- Authentication::ResumeRequest 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;
-
- Utf8ToUpperOnlyLatin(_accountName);
- PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_BNET_RECONNECT_INFO);
- stmt->setString(0, _accountName);
- stmt->setString(1, reconnect.GameAccountName);
- PreparedQueryResult result = LoginDatabase.Query(stmt);
- if (!result)
- {
- Authentication::ResumeResponse* resume = new Authentication::ResumeResponse();
- 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();
- _gameAccountName = reconnect.GameAccountName;
-
- 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);
-
- Authentication::ProofRequest* request = new Authentication::ProofRequest();
- request->Modules.push_back(thumbprint);
- request->Modules.push_back(resume);
- AsyncWrite(request);
- return true;
-}
-
-bool Battlenet::Session::HandleProofResponse(PacketHeader& header, BitStream& packet)
-{
- Authentication::ProofResponse proof(header, packet);
- proof.Read();
-
- if (_modulesWaitingForData.size() < proof.Modules.size())
- {
- Authentication::LogonResponse* complete = new Authentication::LogonResponse();
- 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 Authentication::LogonResponse();
- static_cast<Authentication::LogonResponse*>(response)->SetAuthResult(AUTH_INTERNAL_ERROR);
- }
-
- AsyncWrite(response);
- return true;
-}
-
-bool Battlenet::Session::HandlePing(PacketHeader& /*header*/, BitStream& /*packet*/)
-{
- AsyncWrite(new Connection::Pong());
- return true;
-}
-
-bool Battlenet::Session::HandleEnableEncryption(PacketHeader& /*header*/, BitStream& /*packet*/)
-{
- _crypt.Init(&K);
- return true;
-}
-
-bool Battlenet::Session::HandleLogoutRequest(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::HandleListSubscribeRequest(PacketHeader& /*header*/, BitStream& /*packet*/)
-{
- sRealmList->UpdateIfNeed();
-
- WoWRealm::ListSubscribeResponse* counts = new WoWRealm::ListSubscribeResponse();
-
- 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;
-
- WoWRealm::ListUpdate* update = new WoWRealm::ListUpdate();
- 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(GetRemoteIpAddress());
- 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 WoWRealm::ListComplete());
-
- AsyncWrite(counts);
- return true;
-}
-
-bool Battlenet::Session::HandleJoinRequestV2(PacketHeader& header, BitStream& packet)
-{
- WoWRealm::JoinRequestV2 join(header, packet);
- join.Read();
-
- WoWRealm::JoinResponseV2* result = new WoWRealm::JoinResponseV2();
- Realm const* realm = sRealmList->GetRealm(join.Realm);
- if (!realm || realm->flag & (REALM_FLAG_INVALID | REALM_FLAG_OFFLINE))
- {
- result->Response = WoWRealm::JoinResponseV2::FAILURE;
- 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(), GetRemoteIpAddress().to_string().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::ReadHandler()
-{
- BitStream packet(std::move(GetReadBuffer()));
- _crypt.DecryptRecv(packet.GetBuffer(), packet.GetSize());
-
- while (!packet.IsRead())
- {
- try
- {
- PacketHeader header;
- header.Opcode = packet.Read<uint32>(6);
- if (packet.Read<bool>(1))
- header.Channel = packet.Read<int32>(4);
-
- if (header.Channel != AUTHENTICATION && !_authed)
- {
- TC_LOG_DEBUG("server.battlenet", "Battlenet::Session::ReadDataHandler Received not allowed packet %s", header.ToString().c_str());
- CloseSocket();
- return;
- }
-
- TC_LOG_TRACE("server.battlenet", "Battlenet::Session::ReadDataHandler %s", header.ToString().c_str());
- std::map<PacketHeader, PacketHandler>::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::ReadDataHandler Unhandled opcode %s", header.ToString().c_str());
- break;
- }
-
- packet.AlignToNextByte();
- }
- catch (BitStreamPositionException const& e)
- {
- TC_LOG_ERROR("server.battlenet", "Battlenet::Session::ReadDataHandler Exception: %s", e.what());
- CloseSocket();
- return;
- }
- }
-
- GetReadBuffer().Resize(size_t(BufferSizes::Read));
- AsyncRead();
-}
-
-void Battlenet::Session::Start()
-{
- TC_LOG_TRACE("server.battlenet", "Battlenet::Session::Start");
- AsyncRead();
-}
-
-void Battlenet::Session::AsyncWrite(ServerPacket* packet)
-{
- if (!IsOpen())
- {
- delete packet;
- return;
- }
-
- TC_LOG_TRACE("server.battlenet", "Battlenet::Session::AsyncWrite %s", packet->ToString().c_str());
-
- packet->Write();
-
- MessageBuffer buffer;
- buffer.Write(packet->GetData(), packet->GetSize());
- delete packet;
-
- std::unique_lock<std::mutex> guard(_writeLock);
-
- _crypt.EncryptSend(buffer.GetReadPointer(), buffer.GetActiveSize());
-
- QueuePacket(std::move(buffer), guard);
-}
-
-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)
- {
- Authentication::LogonResponse* complete = new Authentication::LogonResponse();
- complete->SetAuthResult(AUTH_CORRUPTED_MODULE);
- ReplaceResponse(response, complete);
- return false;
- }
-
- if (dataStream->Read<uint8>(8) != 2) // State
- {
- Authentication::LogonResponse* complete = new Authentication::LogonResponse();
- 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())
- {
- Authentication::LogonResponse* complete = new Authentication::LogonResponse();
- 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))
- {
- PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_BNET_FAILED_LOGINS);
- stmt->setString(0, _accountName);
- LoginDatabase.Execute(stmt);
-
- Authentication::LogonResponse* complete = new Authentication::LogonResponse();
- 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)
- {
- Authentication::LogonResponse* noAccounts = new Authentication::LogonResponse();
- 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);
-
- Authentication::ProofRequest* request = new Authentication::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;
- std::string originalName = fields[1].GetString();
- if (originalName.find('#') != std::string::npos)
- name << "WoW" << uint32(fields[0].GetUInt8());
- else
- name << originalName;
-
- 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;
-
- Authentication::LogonResponse* complete = new Authentication::LogonResponse();
- 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!", GetRemoteIpAddress().to_string().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!", GetRemoteIpAddress().to_string().c_str(), GetRemotePort(), _accountName.c_str());
- }
-
- ReplaceResponse(response, complete);
- return false;
- }
-
- _gameAccountId = fields[0].GetUInt32();
- _gameAccountName = fields[1].GetString();
-
- 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<uint8>(8) != 1)
- {
- Authentication::LogonResponse* complete = new Authentication::LogonResponse();
- complete->SetAuthResult(AUTH_CORRUPTED_MODULE);
- ReplaceResponse(response, complete);
- return false;
- }
-
- dataStream->Read<uint8>(8);
- std::string account = dataStream->ReadString(8);
- if (account.empty())
- {
- Authentication::LogonResponse* complete = new Authentication::LogonResponse();
- complete->SetAuthResult(LOGIN_NO_GAME_ACCOUNT);
- ReplaceResponse(response, complete);
- return false;
- }
-
- PreparedStatement* stmt;
- if (account.substr(0, 3) != "WoW")
- {
- stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_BNET_GAME_ACCOUNT);
- stmt->setString(0, account);
- }
- else
- {
- stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_BNET_GAME_ACCOUNT_UNNAMED);
- stmt->setUInt8(0, atol(account.substr(3).c_str()));
- }
-
- stmt->setUInt32(1, _accountId);
- PreparedQueryResult result = LoginDatabase.Query(stmt);
- if (!result)
- {
- Authentication::LogonResponse* complete = new Authentication::LogonResponse();
- complete->SetAuthResult(LOGIN_NO_GAME_ACCOUNT);
- ReplaceResponse(response, complete);
- return false;
- }
-
- Field* fields = result->Fetch();
- if (fields[4].GetBool())
- {
- Authentication::LogonResponse* complete = new Authentication::LogonResponse();
- if (fields[2].GetUInt32() == fields[3].GetUInt32())
- {
- complete->SetAuthResult(LOGIN_BANNED);
- TC_LOG_DEBUG("server.battlenet", "'%s:%d' [Battlenet::SelectGameAccount] Banned account %s tried to login!", GetRemoteIpAddress().to_string().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!", GetRemoteIpAddress().to_string().c_str(), GetRemotePort(), _accountName.c_str());
- }
-
- ReplaceResponse(response, complete);
- return false;
- }
-
- _gameAccountId = fields[0].GetUInt32();
- _gameAccountName = fields[1].GetString();
-
- Authentication::ProofRequest* request = new Authentication::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)
-{
- Authentication::LogonResponse* complete = new Authentication::LogonResponse();
- if (dataStream->Read<uint8>(8) == 1)
- {
- complete->AccountId = _accountId;
- complete->GameAccountName = _gameAccountName;
- complete->GameAccountFlags = GAMEACCOUNT_FLAG_PROPASS_LOCK;
- PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_BNET_FAILED_LOGINS);
- stmt->setUInt32(0, _accountId);
- if (PreparedQueryResult failedLoginsResult = LoginDatabase.Query(stmt))
- complete->FailedLogins = (*failedLoginsResult)[0].GetUInt32();
-
- SQLTransaction trans = LoginDatabase.BeginTransaction();
-
- stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_BNET_LAST_LOGIN_INFO);
- stmt->setString(0, GetRemoteIpAddress().to_string());
- stmt->setUInt8(1, GetLocaleByName(_locale));
- stmt->setString(2, _os);
- stmt->setUInt32(3, _accountId);
- 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;
- sBattlenetSessionMgr.AddSession(this);
- }
- else
- complete->SetAuthResult(AUTH_BAD_VERSION_HASH);
-
- ReplaceResponse(response, complete);
- return true;
-}
-
-bool Battlenet::Session::HandleResumeModule(BitStream* dataStream, ServerPacket** response)
-{
- if (dataStream->Read<uint8>(8) != 1)
- {
- Authentication::ResumeResponse* complete = new Authentication::ResumeResponse();
- complete->SetAuthResult(AUTH_CORRUPTED_MODULE);
- ReplaceResponse(response, complete);
- return false;
- }
-
- static uint8 const ResumeClient = 0;
- static uint8 const ResumeServer = 1;
-
- std::unique_ptr<uint8[]> clientChallenge = dataStream->ReadBytes(16);
- std::unique_ptr<uint8[]> clientProof = dataStream->ReadBytes(32);
- std::unique_ptr<uint8[]> serverChallenge = _reconnectProof.AsByteArray(16);
- std::unique_ptr<uint8[]> sessionKey = K.AsByteArray(64);
-
- 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()))
- {
- PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_BNET_FAILED_LOGINS);
- stmt->setString(0, _accountName);
- LoginDatabase.Execute(stmt);
-
- TC_LOG_DEBUG("server.battlenet", "[Battlenet::Resume] Invalid proof!");
- Authentication::ResumeResponse* result = new Authentication::ResumeResponse();
- 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);
-
- Authentication::ResumeResponse* result = new Authentication::ResumeResponse();
- result->Modules.push_back(resume);
- ReplaceResponse(response, result);
- _authed = true;
- sBattlenetSessionMgr.AddSession(this);
- return true;
-}
-
-bool Battlenet::Session::UnhandledModule(BitStream* /*dataStream*/, ServerPacket** response)
-{
- Authentication::LogonResponse* complete = new Authentication::LogonResponse();
- complete->SetAuthResult(AUTH_CORRUPTED_MODULE);
- ReplaceResponse(response, complete);
- return false;
-}