aboutsummaryrefslogtreecommitdiff
path: root/src/server/bnetserver/Server
diff options
context:
space:
mode:
Diffstat (limited to 'src/server/bnetserver/Server')
-rw-r--r--src/server/bnetserver/Server/ComponentManager.cpp55
-rw-r--r--src/server/bnetserver/Server/ComponentManager.h55
-rw-r--r--src/server/bnetserver/Server/ModuleManager.cpp66
-rw-r--r--src/server/bnetserver/Server/ModuleManager.h91
-rw-r--r--src/server/bnetserver/Server/Session.cpp1309
-rw-r--r--src/server/bnetserver/Server/Session.h241
-rw-r--r--src/server/bnetserver/Server/SessionManager.cpp39
-rw-r--r--src/server/bnetserver/Server/SessionManager.h47
-rw-r--r--src/server/bnetserver/Server/SslContext.cpp45
-rw-r--r--src/server/bnetserver/Server/SslContext.h34
10 files changed, 618 insertions, 1364 deletions
diff --git a/src/server/bnetserver/Server/ComponentManager.cpp b/src/server/bnetserver/Server/ComponentManager.cpp
deleted file mode 100644
index 216c0603985..00000000000
--- a/src/server/bnetserver/Server/ComponentManager.cpp
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * Copyright (C) 2008-2016 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 "ComponentManager.h"
-#include "DatabaseEnv.h"
-
-Battlenet::ComponentMgr::~ComponentMgr()
-{
- for (Version::Record* component : _components)
- delete component;
-}
-
-void Battlenet::ComponentMgr::Load()
-{
- QueryResult result = LoginDatabase.Query("SELECT Program, Platform, Build FROM battlenet_components");
- if (result)
- {
- do
- {
- Field* fields = result->Fetch();
- Version::Record* component = new Version::Record();
- component->ProgramId = fields[0].GetString();
- component->Component = fields[1].GetString();
- component->Version = fields[2].GetUInt32();
-
- _components.insert(component);
- _programs.insert(component->ProgramId);
- _platforms.insert(component->Component);
-
- } while (result->NextRow());
- }
-}
-
-bool Battlenet::ComponentMgr::HasComponent(Battlenet::Version::Record const* component) const
-{
- for (Version::Record const* c : _components)
- if (component->ProgramId == c->ProgramId && component->Component == c->Component && component->Version == c->Version)
- return true;
-
- return false;
-}
diff --git a/src/server/bnetserver/Server/ComponentManager.h b/src/server/bnetserver/Server/ComponentManager.h
deleted file mode 100644
index 464ddbfcd89..00000000000
--- a/src/server/bnetserver/Server/ComponentManager.h
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * Copyright (C) 2008-2016 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/>.
- */
-
-#ifndef ComponentManager_h__
-#define ComponentManager_h__
-
-#include "Define.h"
-#include "PacketsCommon.h"
-#include <cstring>
-#include <string>
-#include <set>
-
-namespace Battlenet
-{
- class ComponentMgr
- {
- ComponentMgr() { }
- ~ComponentMgr();
-
- public:
- void Load();
- bool HasComponent(Version::Record const* component) const;
- bool HasProgram(std::string const& program) const { return _programs.count(program) != 0; }
- bool HasPlatform(std::string const& platform) const { return _platforms.count(platform) != 0; }
-
- static ComponentMgr* instance()
- {
- static ComponentMgr instance;
- return &instance;
- }
-
- private:
- std::set<Version::Record*> _components;
- std::set<std::string> _programs;
- std::set<std::string> _platforms;
- };
-}
-
-#define sComponentMgr Battlenet::ComponentMgr::instance()
-
-#endif // ComponentManager_h__
diff --git a/src/server/bnetserver/Server/ModuleManager.cpp b/src/server/bnetserver/Server/ModuleManager.cpp
deleted file mode 100644
index 2919dacf2ad..00000000000
--- a/src/server/bnetserver/Server/ModuleManager.cpp
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * Copyright (C) 2008-2016 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 "ModuleManager.h"
-#include "DatabaseEnv.h"
-
-Battlenet::ModuleManager::~ModuleManager()
-{
- for (auto const& m : _modules)
- delete m.second;
-}
-
-void Battlenet::ModuleManager::Load()
-{
- QueryResult result = LoginDatabase.Query("SELECT `Hash`, `Name`, `Type`, `System`, `Data` FROM battlenet_modules");
- if (result)
- {
- do
- {
- Field* fields = result->Fetch();
- ModuleInfo* module = new ModuleInfo();
- module->Handle.Type = fields[2].GetString();
- HexStrToByteArray(fields[0].GetString(), module->Handle.ModuleId);
- std::string data = fields[4].GetString();
- module->DataSize = data.length() / 2;
- if (module->DataSize)
- {
- module->Data = new uint8[data.length() / 2];
- HexStrToByteArray(data, module->Data);
- }
-
- _modules[{ fields[3].GetString(), fields[1].GetString() }] = module;
- } while (result->NextRow());
- }
-}
-
-Battlenet::ModuleInfo* Battlenet::ModuleManager::CreateModule(std::string const& os, std::string const& name) const
-{
- ModuleKey key { os, name };
- if (!_modules.count(key))
- return nullptr;
-
- return new ModuleInfo(*_modules.at(key));
-}
-
-std::string Battlenet::ModuleInfo::ToString() const
-{
- std::ostringstream stream;
- stream << "Battlenet::ModuleInput" << std::endl;
- APPEND_FIELD(stream, Handle);
- return stream.str();
-}
diff --git a/src/server/bnetserver/Server/ModuleManager.h b/src/server/bnetserver/Server/ModuleManager.h
deleted file mode 100644
index 457bae4573b..00000000000
--- a/src/server/bnetserver/Server/ModuleManager.h
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * Copyright (C) 2008-2016 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/>.
- */
-
-#ifndef ModuleManager_h__
-#define ModuleManager_h__
-
-#include "PacketsCommon.h"
-
-namespace Battlenet
-{
- struct ModuleKey
- {
- std::string Platform;
- std::string Name;
-
- bool operator<(ModuleKey const& right) const
- {
- int32 res = Platform.compare(right.Platform);
- if (res < 0)
- return true;
- else if (res > 0)
- return false;
-
- return Name < right.Name;
- }
- };
-
- struct ModuleInfo : public PrintableComponent
- {
- ModuleInfo() : DataSize(0), Data(nullptr) { Handle.Region = "EU"; }
- ModuleInfo(ModuleInfo const& right) : DataSize(right.DataSize), Data(nullptr)
- {
- Handle.Type = right.Handle.Type;
- Handle.Region = right.Handle.Region;
- memcpy(Handle.ModuleId, right.Handle.ModuleId, 32);
- if (DataSize)
- {
- Data = new uint8[DataSize];
- memcpy(Data, right.Data, DataSize);
- }
- }
-
- virtual ~ModuleInfo()
- {
- delete[] Data;
- }
-
- Cache::Handle Handle;
- uint32 DataSize;
- uint8* Data;
-
- std::string ToString() const override;
- };
-
- class ModuleManager
- {
- ModuleManager() { }
- ~ModuleManager();
-
- public:
- void Load();
- ModuleInfo* CreateModule(std::string const& os, std::string const& name) const;
-
- static ModuleManager* instance()
- {
- static ModuleManager instance;
- return &instance;
- }
-
- private:
- std::map<ModuleKey, ModuleInfo*> _modules;
- };
-}
-
-#define sModuleMgr Battlenet::ModuleManager::instance()
-
-#endif // ModuleManager_h__
diff --git a/src/server/bnetserver/Server/Session.cpp b/src/server/bnetserver/Server/Session.cpp
index 4d54562501f..66d55480796 100644
--- a/src/server/bnetserver/Server/Session.cpp
+++ b/src/server/bnetserver/Server/Session.cpp
@@ -15,30 +15,21 @@
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#include "AuthCodes.h"
-#include "BitStream.h"
-#include "PacketManager.h"
-#include "SessionManager.h"
+#include "Session.h"
+#include "BattlenetRpcErrorCodes.h"
+#include "ByteConverter.h"
#include "Database/DatabaseEnv.h"
-#include "HmacHash.h"
-#include "Log.h"
+#include "LoginRESTService.h"
+#include "ProtobufJSON.h"
#include "RealmList.h"
-#include "SHA256.h"
-#include <map>
+#include "ServiceDispatcher.h"
+#include "RealmList.pb.h"
+#include <zlib.h>
-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,
-};
-
-void Battlenet::AccountInfo::LoadResult(Field* fields)
+void Battlenet::Session::AccountInfo::LoadResult(PreparedQueryResult result)
{
// ba.id, ba.email, ba.locked, ba.lock_country, ba.last_ip, ba.failed_logins, bab.unbandate > UNIX_TIMESTAMP() OR bab.unbandate = bab.bandate, bab.unbandate = bab.bandate FROM battlenet_accounts ba LEFT JOIN battlenet_account_bans bab WHERE email = ?
+ Field* fields = result->Fetch();
Id = fields[0].GetUInt32();
Login = fields[1].GetString();
IsLockedToIP = fields[2].GetBool();
@@ -47,9 +38,17 @@ void Battlenet::AccountInfo::LoadResult(Field* fields)
FailedLogins = fields[5].GetUInt32();
IsBanned = fields[6].GetUInt64() != 0;
IsPermanenetlyBanned = fields[7].GetUInt64() != 0;
+
+ static uint32 const GameAccountFieldsOffset = 8;
+
+ do
+ {
+ GameAccounts[result->Fetch()[GameAccountFieldsOffset].GetUInt32()].LoadResult(result->Fetch() + GameAccountFieldsOffset);
+
+ } while (result->NextRow());
}
-void Battlenet::GameAccountInfo::LoadResult(Field* fields)
+void Battlenet::Session::GameAccountInfo::LoadResult(Field* fields)
{
// a.id, a.username, ab.unbandate > UNIX_TIMESTAMP() OR ab.unbandate = ab.bandate, ab.unbandate = ab.bandate, aa.gmlevel
Id = fields[0].GetUInt32();
@@ -65,204 +64,215 @@ void Battlenet::GameAccountInfo::LoadResult(Field* fields)
DisplayName = Name;
}
-Battlenet::Session::Session(tcp::socket&& socket) : Socket(std::move(socket)), _accountInfo(new AccountInfo()), _gameAccountInfo(nullptr), _locale(),
- _os(), _build(0), _ipCountry(), I(), s(), v(), b(), B(), K(),
- _reconnectProof(), _crypt(), _authed(false), _subscribedToRealmListUpdates(false), _toonOnline(false)
+Battlenet::Session::Session(tcp::socket&& socket) : BattlenetSocket(std::move(socket)), _accountInfo(new AccountInfo()), _gameAccountInfo(nullptr), _locale(),
+ _os(), _build(0), _ipCountry(), _authed(false), _requestToken(0)
{
- 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());
+ _headerLengthBuffer.Resize(2);
}
Battlenet::Session::~Session()
{
- if (_authed)
- sSessionMgr.RemoveSession(this);
-
- delete _accountInfo;
}
-void Battlenet::Session::_SetVSFields(std::string const& pstr)
+void Battlenet::Session::AsyncHandshake()
{
- s.SetRand(uint32(BufferSizes::SRP_6_S) * 8);
+ underlying_stream().async_handshake(ssl::stream_base::server, std::bind(&Session::HandshakeHandler, shared_from_this(), std::placeholders::_1));
+}
- BigNumber p;
- p.SetHexStr(pstr.c_str());
+void Battlenet::Session::Start()
+{
+ std::string ip_address = GetRemoteIpAddress().to_string();
+ TC_LOG_TRACE("session", "%s Accepted connection", GetClientInfo().c_str());
- SHA256Hash sha;
- sha.UpdateBigNumbers(&s, &p, NULL);
- sha.Finalize();
- BigNumber x;
- x.SetBinary(sha.GetDigest(), sha.GetLength());
- v = g.ModExp(x, N);
+ // Verify that this IP is not in the ip_banned table
+ LoginDatabase.Execute(LoginDatabase.GetPreparedStatement(LOGIN_DEL_EXPIRED_IP_BANS));
- PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_BNET_VS_FIELDS);
- stmt->setString(0, v.AsHexStr());
- stmt->setString(1, s.AsHexStr());
- stmt->setString(2, _accountInfo->Login);
+ PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_IP_INFO);
+ stmt->setString(0, ip_address);
+ stmt->setUInt32(1, inet_addr(ip_address.c_str()));
- LoginDatabase.Execute(stmt);
+ _queryCallback = std::bind(&Battlenet::Session::CheckIpCallback, this, std::placeholders::_1);
+ _queryFuture = LoginDatabase.AsyncQuery(stmt);
}
-void Battlenet::Session::LogUnhandledPacket(PacketHeader const& header)
+void Battlenet::Session::CheckIpCallback(PreparedQueryResult result)
{
- TC_LOG_DEBUG("session.packets", "%s Received unhandled packet %s", GetClientInfo().c_str(), sPacketManager.GetClientPacketName(header));
+ if (result)
+ {
+ bool banned = false;
+ do
+ {
+ Field* fields = result->Fetch();
+ if (fields[0].GetUInt64() != 0)
+ banned = true;
+
+ if (!fields[1].GetString().empty())
+ _ipCountry = fields[1].GetString();
+
+ } while (result->NextRow());
+
+ if (banned)
+ {
+ TC_LOG_DEBUG("session", "%s tries to log in using banned IP!", GetClientInfo().c_str());
+ CloseSocket();
+ return;
+ }
+ }
+
+ AsyncHandshake();
}
-void Battlenet::Session::HandleLogonRequest(Authentication::LogonRequest3 const& logonRequest)
+bool Battlenet::Session::Update()
{
- if (_queryCallback)
- {
- Authentication::LogonResponse* logonResponse = new Authentication::LogonResponse();
- logonResponse->SetAuthResult(AUTH_LOGON_TOO_FAST);
- AsyncWrite(logonResponse);
- TC_LOG_DEBUG("session", "[Battlenet::LogonRequest] %s attempted to log too quick after previous attempt!", GetClientInfo().c_str());
- return;
- }
+ if (!BattlenetSocket::Update())
+ return false;
- if (logonRequest.Common.Program != "WoW")
+ if (_queryFuture.valid() && _queryFuture.wait_for(std::chrono::seconds(0)) == std::future_status::ready)
{
- Authentication::LogonResponse* logonResponse = new Authentication::LogonResponse();
- logonResponse->SetAuthResult(AUTH_INVALID_PROGRAM);
- AsyncWrite(logonResponse);
- TC_LOG_DEBUG("session", "[Battlenet::LogonRequest] %s attempted to log in with game other than WoW (using %s)!", GetClientInfo().c_str(), logonRequest.Common.Program.c_str());
- return;
+ auto callback = std::move(_queryCallback);
+ _queryCallback = nullptr;
+ callback(_queryFuture.get());
}
- if (!sComponentMgr->HasPlatform(logonRequest.Common.Platform))
- {
- Authentication::LogonResponse* logonResponse = new Authentication::LogonResponse();
- logonResponse->SetAuthResult(AUTH_INVALID_OS);
- AsyncWrite(logonResponse);
- TC_LOG_DEBUG("session", "[Battlenet::LogonRequest] %s attempted to log in from an unsupported platform (using %s)!", GetClientInfo().c_str(), logonRequest.Common.Platform.c_str());
- return;
- }
+ return true;
+}
- if (!sComponentMgr->HasPlatform(logonRequest.Common.Locale))
- {
- Authentication::LogonResponse* logonResponse = new Authentication::LogonResponse();
- logonResponse->SetAuthResult(AUTH_UNSUPPORTED_LANGUAGE);
- AsyncWrite(logonResponse);
- TC_LOG_DEBUG("session", "[Battlenet::LogonRequest] %s attempted to log in with unsupported locale (using %s)!", GetClientInfo().c_str(), logonRequest.Common.Locale.c_str());
+void Battlenet::Session::AsyncWrite(MessageBuffer* packet)
+{
+ if (!IsOpen())
return;
- }
- for (Version::Record const& component : logonRequest.Common.Versions)
- {
- if (!sComponentMgr->HasComponent(&component))
- {
- Authentication::LogonResponse* logonResponse = new Authentication::LogonResponse();
- if (!sComponentMgr->HasProgram(component.ProgramId))
- {
- logonResponse->SetAuthResult(AUTH_INVALID_PROGRAM);
- TC_LOG_DEBUG("session", "[Battlenet::LogonRequest] %s is using unsupported component program %s!", GetClientInfo().c_str(), component.ProgramId.c_str());
- }
- else if (!sComponentMgr->HasPlatform(component.Component))
- {
- logonResponse->SetAuthResult(AUTH_INVALID_OS);
- TC_LOG_DEBUG("session", "[Battlenet::LogonRequest] %s is using unsupported component platform %s!", GetClientInfo().c_str(), component.Component.c_str());
- }
- else
- {
- if (component.ProgramId != "WoW" || AuthHelper::IsBuildSupportingBattlenet(component.Version))
- logonResponse->SetAuthResult(AUTH_REGION_BAD_VERSION);
- else
- logonResponse->SetAuthResult(AUTH_USE_GRUNT_LOGON);
+ QueuePacket(std::move(*packet));
+}
- TC_LOG_DEBUG("session", "[Battlenet::LogonRequest] %s is using unsupported component version %u!", GetClientInfo().c_str(), component.Version);
- }
+void Battlenet::Session::SendResponse(uint32 token, pb::Message const* response)
+{
+ Header header;
+ header.set_token(token);
+ header.set_service_id(0xFE);
+ header.set_size(response->ByteSize());
- AsyncWrite(logonResponse);
- return;
- }
+ uint16 headerSize = header.ByteSize();
+ EndianConvertReverse(headerSize);
- if (component.Component == "base")
- _build = component.Version;
- }
+ MessageBuffer packet;
+ packet.Write(&headerSize, sizeof(headerSize));
+ uint8* ptr = packet.GetWritePointer();
+ packet.WriteCompleted(header.ByteSize());
+ header.SerializeToArray(ptr, header.ByteSize());
+ ptr = packet.GetWritePointer();
+ packet.WriteCompleted(response->ByteSize());
+ response->SerializeToArray(ptr, response->ByteSize());
+
+ AsyncWrite(&packet);
+}
- std::string login = logonRequest.Account;
- _locale = logonRequest.Common.Locale;
- _os = logonRequest.Common.Platform;
+void Battlenet::Session::SendResponse(uint32 token, uint32 status)
+{
+ Header header;
+ header.set_token(token);
+ header.set_status(status);
+ header.set_service_id(0xFE);
- Utf8ToUpperOnlyLatin(login);
- PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_BNET_ACCOUNT_INFO);
- stmt->setString(0, login);
+ uint16 headerSize = header.ByteSize();
+ EndianConvertReverse(headerSize);
- _queryCallback = std::bind(&Battlenet::Session::HandleLogonRequestCallback, this, std::placeholders::_1);
- _queryFuture = LoginDatabase.AsyncQuery(stmt);
+ MessageBuffer packet;
+ packet.Write(&headerSize, sizeof(headerSize));
+ uint8* ptr = packet.GetWritePointer();
+ packet.WriteCompleted(header.ByteSize());
+ header.SerializeToArray(ptr, header.ByteSize());
+
+ AsyncWrite(&packet);
}
-void Battlenet::Session::HandleLogonRequestCallback(PreparedQueryResult result)
+void Battlenet::Session::SendRequest(uint32 serviceHash, uint32 methodId, pb::Message const* request)
{
- if (!result)
+ Header header;
+ header.set_service_id(0);
+ header.set_service_hash(serviceHash);
+ header.set_method_id(methodId);
+ header.set_size(request->ByteSize());
+ header.set_token(_requestToken++);
+
+ uint16 headerSize = header.ByteSize();
+ EndianConvertReverse(headerSize);
+
+ MessageBuffer packet;
+ packet.Write(&headerSize, sizeof(headerSize));
+ uint8* ptr = packet.GetWritePointer();
+ packet.WriteCompleted(header.ByteSize());
+ header.SerializeToArray(ptr, header.ByteSize());
+ ptr = packet.GetWritePointer();
+ packet.WriteCompleted(request->ByteSize());
+ request->SerializeToArray(ptr, request->ByteSize());
+
+ AsyncWrite(&packet);
+}
+
+uint32 Battlenet::Session::HandleLogon(authentication::v1::LogonRequest const* logonRequest)
+{
+ if (logonRequest->program() != "WoW")
{
- Authentication::LogonResponse* logonResponse = new Authentication::LogonResponse();
- logonResponse->SetAuthResult(AUTH_UNKNOWN_ACCOUNT);
- AsyncWrite(logonResponse);
- TC_LOG_DEBUG("session", "[Battlenet::LogonRequest] %s is trying to log in from unknown account!", GetClientInfo().c_str());
- return;
+ TC_LOG_DEBUG("session", "[Battlenet::LogonRequest] %s attempted to log in with game other than WoW (using %s)!", GetClientInfo().c_str(), logonRequest->program().c_str());
+ return ERROR_BAD_PROGRAM;
}
- Field* fields = result->Fetch();
- _accountInfo->LoadResult(fields);
-
- std::string pStr = fields[8].GetString();
- std::string databaseV = fields[9].GetString();
- std::string databaseS = fields[10].GetString();
+ if (logonRequest->platform() != "Win" && logonRequest->platform() != "Wn64" && logonRequest->platform() != "Mc64")
+ {
+ TC_LOG_DEBUG("session", "[Battlenet::LogonRequest] %s attempted to log in from an unsupported platform (using %s)!", GetClientInfo().c_str(), logonRequest->platform().c_str());
+ return ERROR_BAD_PLATFORM;
+ }
- _gameAccounts.resize(result->GetRowCount());
- uint32 i = 0;
- do
+ if (GetLocaleByName(logonRequest->locale()) == LOCALE_enUS && logonRequest->locale() != "enUS")
{
- _gameAccounts[i++].LoadResult(result->Fetch() + 11);
+ TC_LOG_DEBUG("session", "[Battlenet::LogonRequest] %s attempted to log in with unsupported locale (using %s)!", GetClientInfo().c_str(), logonRequest->locale().c_str());
+ return ERROR_BAD_LOCALE;
+ }
- } while (result->NextRow());
+ _locale = logonRequest->locale();
+ _os = logonRequest->platform();
+
+ ip::tcp::endpoint const& endpoint = sLoginService.GetAddressForClient(GetRemoteIpAddress());
+
+ challenge::v1::ChallengeExternalRequest externalChallenge;
+ externalChallenge.set_payload_type("web_auth_url");
+ externalChallenge.set_payload(Trinity::StringFormat("https://%s:%u/bnetserver/login/", endpoint.address().to_string().c_str(), endpoint.port()));
+ Service<challenge::v1::ChallengeListener>(this).OnExternalChallenge(&externalChallenge);
+ return ERROR_OK;
+}
+
+uint32 Battlenet::Session::HandleVerifyWebCredentials(authentication::v1::VerifyWebCredentialsRequest const* verifyWebCredentialsRequest)
+{
+ authentication::v1::LogonResult logonResult;
+ logonResult.set_error_code(0);
+ _accountInfo = sLoginService.VerifyLoginTicket(verifyWebCredentialsRequest->web_credentials());
+ if (!_accountInfo)
+ return ERROR_DENIED;
std::string ip_address = GetRemoteIpAddress().to_string();
+
// If the IP is 'locked', check that the player comes indeed from the correct IP address
if (_accountInfo->IsLockedToIP)
{
- TC_LOG_DEBUG("session", "[Battlenet::LogonRequest] Account '%s' is locked to IP - '%s' is logging in from '%s'", _accountInfo->Login.c_str(), _accountInfo->LastIP.c_str(), ip_address.c_str());
+ TC_LOG_DEBUG("session", "[Session::HandleVerifyWebCredentials] Account '%s' is locked to IP - '%s' is logging in from '%s'",
+ _accountInfo->Login.c_str(), _accountInfo->LastIP.c_str(), ip_address.c_str());
if (_accountInfo->LastIP != ip_address)
- {
- Authentication::LogonResponse* logonResponse = new Authentication::LogonResponse();
- logonResponse->SetAuthResult(AUTH_ACCOUNT_LOCKED);
- AsyncWrite(logonResponse);
- return;
- }
+ return ERROR_RISK_ACCOUNT_LOCKED;
}
else
{
- TC_LOG_DEBUG("session", "[Battlenet::LogonRequest] Account '%s' is not locked to ip", _accountInfo->Login.c_str());
+ TC_LOG_DEBUG("session", "[Session::HandleVerifyWebCredentials] Account '%s' is not locked to ip", _accountInfo->Login.c_str());
if (_accountInfo->LockCountry.empty() || _accountInfo->LockCountry == "00")
- TC_LOG_DEBUG("session", "[Battlenet::LogonRequest] Account '%s' is not locked to country", _accountInfo->Login.c_str());
+ TC_LOG_DEBUG("session", "[Session::HandleVerifyWebCredentials] Account '%s' is not locked to country", _accountInfo->Login.c_str());
else if (!_accountInfo->LockCountry.empty() && !_ipCountry.empty())
{
- TC_LOG_DEBUG("session", "[Battlenet::LogonRequest] Account '%s' is locked to country: '%s' Player country is '%s'", _accountInfo->Login.c_str(), _accountInfo->LockCountry.c_str(), _ipCountry.c_str());
+ TC_LOG_DEBUG("session", "[Session::HandleVerifyWebCredentials] Account '%s' is locked to country: '%s' Player country is '%s'",
+ _accountInfo->Login.c_str(), _accountInfo->LockCountry.c_str(), _ipCountry.c_str());
+
if (_ipCountry != _accountInfo->LockCountry)
- {
- Authentication::LogonResponse* logonResponse = new Authentication::LogonResponse();
- logonResponse->SetAuthResult(AUTH_ACCOUNT_LOCKED);
- AsyncWrite(logonResponse);
- return;
- }
+ return ERROR_RISK_ACCOUNT_LOCKED;
}
}
@@ -271,886 +281,391 @@ void Battlenet::Session::HandleLogonRequestCallback(PreparedQueryResult result)
{
if (_accountInfo->IsPermanenetlyBanned)
{
- Authentication::LogonResponse* logonResponse = new Authentication::LogonResponse();
- logonResponse->SetAuthResult(LOGIN_BANNED);
- AsyncWrite(logonResponse);
- TC_LOG_DEBUG("session", "'%s:%d' [Battlenet::LogonRequest] Banned account %s tried to login!", ip_address.c_str(), GetRemotePort(), _accountInfo->Login.c_str());
- return;
+ TC_LOG_DEBUG("session", "%s [Session::HandleVerifyWebCredentials] Banned account %s tried to login!", GetClientInfo().c_str(), _accountInfo->Login.c_str());
+ return ERROR_GAME_ACCOUNT_BANNED;
}
else
{
- Authentication::LogonResponse* logonResponse = new Authentication::LogonResponse();
- logonResponse->SetAuthResult(LOGIN_SUSPENDED);
- AsyncWrite(logonResponse);
- TC_LOG_DEBUG("session", "'%s:%d' [Battlenet::LogonRequest] Temporarily banned account %s tried to login!", ip_address.c_str(), GetRemotePort(), _accountInfo->Login.c_str());
- return;
+ TC_LOG_DEBUG("session", "%s [Session::HandleVerifyWebCredentials] Temporarily banned account %s tried to login!", GetClientInfo().c_str(), _accountInfo->Login.c_str());
+ return ERROR_GAME_ACCOUNT_SUSPENDED;
}
}
- SHA256Hash sha;
- sha.UpdateData(_accountInfo->Login);
- sha.Finalize();
-
- I.SetBinary(sha.GetDigest(), sha.GetLength());
-
- ModuleInfo* password = sModuleMgr->CreateModule(_os, "Password");
- ModuleInfo* thumbprint = sModuleMgr->CreateModule(_os, "Thumbprint");
-
- if (databaseV.size() != size_t(BufferSizes::SRP_6_V) * 2 || databaseS.size() != size_t(BufferSizes::SRP_6_S) * 2)
- _SetVSFields(pStr);
- else
+ logonResult.mutable_account_id()->set_low(_accountInfo->Id);
+ logonResult.mutable_account_id()->set_high(UI64LIT(0x100000000000000));
+ for (auto itr = _accountInfo->GameAccounts.begin(); itr != _accountInfo->GameAccounts.end(); ++itr)
{
- s.SetHexStr(databaseS.c_str());
- v.SetHexStr(databaseV.c_str());
+ if (!itr->second.IsBanned)
+ {
+ EntityId* gameAccountId = logonResult.add_game_account_id();
+ gameAccountId->set_low(itr->second.Id);
+ gameAccountId->set_high(UI64LIT(0x200000200576F57));
+ }
}
- 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* proofRequest = new Authentication::ProofRequest();
- proofRequest->Modules.push_back(password);
- // if has authenticator, send Token module
- proofRequest->Modules.push_back(thumbprint);
- AsyncWrite(proofRequest);
-}
+ if (!_ipCountry.empty())
+ logonResult.set_geoip_country(_ipCountry);
-void Battlenet::Session::HandleResumeRequest(Authentication::ResumeRequest const& resumeRequest)
-{
- if (_queryCallback)
- {
- Authentication::ResumeResponse* logonResponse = new Authentication::ResumeResponse();
- logonResponse->SetAuthResult(AUTH_LOGON_TOO_FAST);
- AsyncWrite(logonResponse);
- TC_LOG_DEBUG("session", "[Battlenet::ResumeRequest] %s attempted to log too quick after previous attempt!", GetClientInfo().c_str());
- return;
- }
-
- std::string login = resumeRequest.Account;
- _locale = resumeRequest.Common.Locale;
- _os = resumeRequest.Common.Platform;
- auto baseComponent = std::find_if(resumeRequest.Common.Versions.begin(), resumeRequest.Common.Versions.end(), [](Version::Record const& c) { return c.ProgramId == "base"; });
- if (baseComponent != resumeRequest.Common.Versions.end())
- _build = baseComponent->Version;
+ BigNumber k;
+ k.SetRand(8 * 64);
+ logonResult.set_session_key(k.AsByteArray(64).get(), 64);
- Utf8ToUpperOnlyLatin(login);
- PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_BNET_RECONNECT_INFO);
- stmt->setString(0, login);
- stmt->setString(1, resumeRequest.GameAccountName);
+ _authed = true;
- _queryCallback = std::bind(&Battlenet::Session::HandleResumeRequestCallback, this, std::placeholders::_1);
- _queryFuture = LoginDatabase.AsyncQuery(stmt);
+ Service<authentication::v1::AuthenticationListener>(this).OnLogonComplete(&logonResult);
+ return ERROR_OK;
}
-void Battlenet::Session::HandleResumeRequestCallback(PreparedQueryResult result)
+uint32 Battlenet::Session::HandleGetAccountState(account::v1::GetAccountStateRequest const* request, account::v1::GetAccountStateResponse* response)
{
- if (!result)
- {
- Authentication::ResumeResponse* resumeResponse = new Authentication::ResumeResponse();
- resumeResponse->SetAuthResult(AUTH_UNKNOWN_ACCOUNT);
- AsyncWrite(resumeResponse);
- return;
- }
-
- Field* fields = result->Fetch();
- _accountInfo->LoadResult(fields);
- K.SetHexStr(fields[8].GetString().c_str());
-
- _gameAccounts.resize(1);
- _gameAccountInfo = &_gameAccounts[0];
- _gameAccountInfo->LoadResult(fields + 9);
-
- ModuleInfo* thumbprint = sModuleMgr->CreateModule(_os, "Thumbprint");
- ModuleInfo* resume = sModuleMgr->CreateModule(_os, "Resume");
- BitStream resumeData;
- uint8 state = 0;
- _reconnectProof.SetRand(16 * 8);
+ if (!_authed)
+ return ERROR_DENIED;
- 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);
+ if (request->options().field_privacy_info())
+ {
+ response->mutable_state()->mutable_privacy_info()->set_is_using_rid(false);
+ response->mutable_state()->mutable_privacy_info()->set_is_real_id_visible_for_view_friends(false);
+ response->mutable_state()->mutable_privacy_info()->set_is_hidden_from_friend_finder(true);
- _modulesWaitingForData.push(MODULE_RESUME);
+ response->mutable_tags()->set_privacy_info_tag(0xD7CA834D);
+ }
- Authentication::ProofRequest* proofRequest = new Authentication::ProofRequest();
- proofRequest->Modules.push_back(thumbprint);
- proofRequest->Modules.push_back(resume);
- AsyncWrite(proofRequest);
+ return ERROR_OK;
}
-void Battlenet::Session::HandleProofResponse(Authentication::ProofResponse const& proofResponse)
+uint32 Battlenet::Session::HandleGetGameAccountState(account::v1::GetGameAccountStateRequest const* request, account::v1::GetGameAccountStateResponse* response)
{
- if (_modulesWaitingForData.size() < proofResponse.Response.size())
- {
- Authentication::LogonResponse* complete = new Authentication::LogonResponse();
- complete->SetAuthResult(AUTH_CORRUPTED_MODULE);
- AsyncWrite(complete);
- return;
- }
+ if (!_authed)
+ return ERROR_DENIED;
- ServerPacket* response = nullptr;
- for (size_t i = 0; i < proofResponse.Response.size(); ++i)
+ if (request->options().field_game_level_info())
{
- if (!(this->*(ModuleHandlers[_modulesWaitingForData.front()]))(proofResponse.Response[i], &response))
- break;
+ auto itr = _accountInfo->GameAccounts.find(request->game_account_id().low());
+ if (itr != _accountInfo->GameAccounts.end())
+ {
+ response->mutable_state()->mutable_game_level_info()->set_name(itr->second.DisplayName);
+ response->mutable_state()->mutable_game_level_info()->set_program(5730135); // WoW
+ }
- _modulesWaitingForData.pop();
+ response->mutable_tags()->set_game_level_info_tag(0x5C46D483);
}
- if (!response)
+ if (request->options().field_game_status())
{
- response = new Authentication::LogonResponse();
- static_cast<Authentication::LogonResponse*>(response)->SetAuthResult(AUTH_INTERNAL_ERROR);
- }
-
- AsyncWrite(response);
-}
-
-void Battlenet::Session::HandlePing(Connection::Ping const& /*ping*/)
-{
- AsyncWrite(new Connection::Pong());
-}
+ auto itr = _accountInfo->GameAccounts.find(request->game_account_id().low());
+ if (itr != _accountInfo->GameAccounts.end())
+ {
+ response->mutable_state()->mutable_game_status()->set_is_suspended(itr->second.IsBanned);
+ response->mutable_state()->mutable_game_status()->set_is_banned(itr->second.IsPermanenetlyBanned);
+ }
-void Battlenet::Session::HandleEnableEncryption(Connection::EnableEncryption& enableEncryption)
-{
- _crypt.Init(&K);
- _crypt.DecryptRecv(enableEncryption.GetRemainingData(), enableEncryption.GetRemainingSize());
-}
+ response->mutable_state()->mutable_game_status()->set_program(5730135); // WoW
+ response->mutable_tags()->set_game_status_tag(0x98B75F99);
+ }
-void Battlenet::Session::HandleLogoutRequest(Connection::LogoutRequest const& /*logoutRequest*/)
-{
- PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_BNET_SESSION_KEY);
- stmt->setString(0, "");
- stmt->setBool(1, false);
- stmt->setUInt32(2, _accountInfo->Id);
- LoginDatabase.Execute(stmt);
+ return ERROR_OK;
}
-void Battlenet::Session::HandleConnectionClosing(Connection::ConnectionClosing const& /*connectionClosing*/)
+std::unordered_map<std::string, Battlenet::Session::ClientRequestHandler> const Battlenet::Session::ClientRequestHandlers =
{
-}
+ { "Command_RealmListTicketRequest_v1_b9", &Battlenet::Session::GetRealmListTicket },
+ { "Command_LastCharPlayedRequest_v1_b9", &Battlenet::Session::GetLastCharPlayed },
+ { "Command_RealmListRequest_v1_b9", &Battlenet::Session::GetRealmList },
+ { "Command_RealmJoinRequest_v1_b9", &Battlenet::Session::JoinRealm },
+};
-void Battlenet::Session::HandleListSubscribeRequest(WoWRealm::ListSubscribeRequest const& /*listSubscribeRequest*/)
+uint32 Battlenet::Session::HandleProcessClientRequest(game_utilities::v1::ClientRequest const* request, game_utilities::v1::ClientResponse* response)
{
- if (_subscribedToRealmListUpdates || _queryCallback)
- return;
-
- PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_BNET_CHARACTER_COUNTS);
- stmt->setUInt32(0, _gameAccountInfo->Id);
-
- _queryCallback = std::bind(&Battlenet::Session::HandleListSubscribeRequestCallback, this, std::placeholders::_1);
- _queryFuture = LoginDatabase.AsyncQuery(stmt);
-}
+ if (!_authed)
+ return ERROR_DENIED;
-void Battlenet::Session::HandleListSubscribeRequestCallback(PreparedQueryResult result)
-{
- WoWRealm::ListSubscribeResponse* listSubscribeResponse = new WoWRealm::ListSubscribeResponse();
+ Attribute const* command = nullptr;
+ std::unordered_map<std::string, Variant const*> params;
- if (result)
+ for (int32 i = 0; i < request->attribute_size(); ++i)
{
- do
- {
- Field* fields = result->Fetch();
- listSubscribeResponse->ToonCounts.emplace_back(PrintableRealmHandle(fields[2].GetUInt8(), fields[3].GetUInt8(), fields[1].GetUInt32()), uint16(fields[0].GetUInt8()));
- } while (result->NextRow());
+ Attribute const& attr = request->attribute(i);
+ params[attr.name()] = &attr.value();
+ if (strstr(attr.name().c_str(), "Command_") == attr.name().c_str())
+ command = &attr;
}
- AsyncWrite(listSubscribeResponse);
-
- for (RealmList::RealmMap::value_type const& i : sRealmList->GetRealms())
- AsyncWrite(BuildListUpdate(&i.second));
-
- AsyncWrite(new WoWRealm::ListComplete());
-
- _subscribedToRealmListUpdates = true;
-}
-
-void Battlenet::Session::HandleListUnsubscribe(WoWRealm::ListUnsubscribe const& /*listUnsubscribe*/)
-{
- _subscribedToRealmListUpdates = false;
-}
-
-void Battlenet::Session::HandleJoinRequestV2(WoWRealm::JoinRequestV2 const& joinRequest)
-{
- WoWRealm::JoinResponseV2* joinResponse = new WoWRealm::JoinResponseV2();
- Realm const* realm = sRealmList->GetRealm(joinRequest.Id);
- if (!realm || realm->Flags & (REALM_FLAG_VERSION_MISMATCH | REALM_FLAG_OFFLINE) || realm->Build != _build)
+ if (!command)
{
- joinResponse->Type = WoWRealm::JoinResponseV2::FAILURE;
- AsyncWrite(joinResponse);
- return;
+ TC_LOG_ERROR("session.rpc", "%s sent ClientRequest with no command.", GetClientInfo().c_str());
+ return ERROR_RPC_MALFORMED_REQUEST;
}
- joinResponse->Success.ServerSalt = rand32();
-
- uint8 sessionKey[40];
- HmacSha1 hmac(K.GetNumBytes(), K.AsByteArray().get());
- hmac.UpdateData((uint8*)"WoW\0", 4);
- hmac.UpdateData((uint8*)&joinRequest.ClientSalt, 4);
- hmac.UpdateData((uint8*)&joinResponse->Success.ServerSalt, 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*)&joinResponse->Success.ServerSalt, 4);
- hmac2.UpdateData((uint8*)&joinRequest.ClientSalt, 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(), _gameAccountInfo->Id);
-
- joinResponse->Success.IPv4.push_back(realm->GetAddressForClient(GetRemoteIpAddress()));
-
- AsyncWrite(joinResponse);
-}
-
-void Battlenet::Session::HandleGetStreamItemsRequest(Cache::GetStreamItemsRequest const& getStreamItemsRequest)
-{
- if (getStreamItemsRequest.Stream.Type != Cache::GetStreamItemsRequest::StreamId::DESCRIPTION)
- return;
-
- if (ModuleInfo* module = sModuleMgr->CreateModule(getStreamItemsRequest.Locale, getStreamItemsRequest.Stream.Description.ItemName))
+ auto itr = ClientRequestHandlers.find(command->name());
+ if (itr == ClientRequestHandlers.end())
{
- Cache::GetStreamItemsResponse* getStreamItemsResponse = new Cache::GetStreamItemsResponse();
- getStreamItemsResponse->Token = getStreamItemsRequest.Token;
- getStreamItemsResponse->Items.push_back(module);
- AsyncWrite(getStreamItemsResponse);
+ TC_LOG_ERROR("session.rpc", "%s sent ClientRequest with unknown command %s.", GetClientInfo().c_str(), command->name().c_str());
+ return ERROR_RPC_NOT_IMPLEMENTED;
}
-}
-inline std::string PacketToStringHelper(Battlenet::ClientPacket const* packet)
-{
- if (sLog->ShouldLog("session.packets", LOG_LEVEL_TRACE))
- return packet->ToString();
-
- return sPacketManager.GetClientPacketName(packet->GetHeader());
+ return (this->*itr->second)(params, response);
}
-inline std::string PacketToStringHelper(Battlenet::ServerPacket const* packet)
+inline Variant const* GetParam(std::unordered_map<std::string, Variant const*> const& params, char const* paramName)
{
- if (sLog->ShouldLog("session.packets", LOG_LEVEL_TRACE))
- return packet->ToString();
-
- return sPacketManager.GetServerPacketName(packet->GetHeader());
+ auto itr = params.find(paramName);
+ return itr != params.end() ? itr->second : nullptr;
}
-void Battlenet::Session::ReadHandler()
+uint32 Battlenet::Session::GetRealmListTicket(std::unordered_map<std::string, Variant const*> const& params, game_utilities::v1::ClientResponse* response)
{
- BitStream stream(std::move(GetReadBuffer()));
- _crypt.DecryptRecv(stream.GetBuffer(), stream.GetSize());
-
- while (!stream.IsRead())
+ if (Variant const* identity = GetParam(params, "Param_Identity"))
{
- try
+ ::JSON::RealmList::RealmListTicketIdentity data;
+ std::size_t jsonStart = identity->blob_value().find(':');
+ if (jsonStart != std::string::npos && ::JSON::Deserialize(identity->blob_value().substr(jsonStart + 1), &data))
{
- PacketHeader header;
- header.Command = stream.Read<uint32>(6);
- if (stream.Read<bool>(1))
- header.Channel = stream.Read<int32>(4);
-
- if (header.Channel != AUTHENTICATION && (header.Channel != CONNECTION || header.Command != Connection::CMSG_PING) && !_authed)
- {
- TC_LOG_DEBUG("session.packets", "%s Received not allowed %s. Client has not authed yet.", GetClientInfo().c_str(), header.ToString().c_str());
- CloseSocket();
- return;
- }
+ auto itr = _accountInfo->GameAccounts.find(data.gameaccountid());
+ if (itr != _accountInfo->GameAccounts.end())
+ _gameAccountInfo = &itr->second;
+ }
+ }
- if (ClientPacket* packet = sPacketManager.CreateClientPacket(header, stream))
- {
- if (sPacketManager.IsHandled(header))
- TC_LOG_DEBUG("session.packets", "%s Received %s", GetClientInfo().c_str(), PacketToStringHelper(packet).c_str());
+ if (!_gameAccountInfo)
+ return ERROR_UTIL_SERVER_INVALID_IDENTITY_ARGS;
- packet->CallHandler(this);
- delete packet;
- }
- else if (sPacketManager.GetClientPacketName(header))
- {
- LogUnhandledPacket(header);
- break;
- }
- else
+ if (Variant const* clientInfo = GetParam(params, "Param_ClientInfo"))
+ {
+ ::JSON::RealmList::RealmListTicketClientInformation data;
+ std::size_t jsonStart = clientInfo->blob_value().find(':');
+ if (jsonStart != std::string::npos && ::JSON::Deserialize(clientInfo->blob_value().substr(jsonStart + 1), &data))
+ {
+ if (_clientSecret.size() == data.info().secret().size())
{
- TC_LOG_DEBUG("session.packets", "%s Received unknown %s", GetClientInfo().c_str(), header.ToString().c_str());
- break;
+ _build = data.info().version().versionbuild();
+ memcpy(_clientSecret.data(), data.info().secret().data(), _clientSecret.size());
}
-
- stream.AlignToNextByte();
- }
- catch (BitStreamPositionException const& e)
- {
- TC_LOG_ERROR("session.packets", "%s Exception thrown during packet processing %s", GetClientInfo().c_str(), e.what());
- CloseSocket();
- return;
}
}
- GetReadBuffer().Resize(size_t(BufferSizes::Read));
- AsyncRead();
-}
+ if (!_build)
+ return ERROR_WOW_SERVICES_DENIED_REALM_LIST_TICKET;
-void Battlenet::Session::Start()
-{
- std::string ip_address = GetRemoteIpAddress().to_string();
- TC_LOG_TRACE("session", "Accepted connection from %s", ip_address.c_str());
+ PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_BNET_LAST_LOGIN_INFO);
+ stmt->setString(0, GetRemoteIpAddress().to_string());
+ stmt->setUInt8(1, GetLocaleByName(_locale));
+ stmt->setString(2, _os);
+ stmt->setUInt32(3, _accountInfo->Id);
- PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_IP_INFO);
- stmt->setString(0, ip_address);
- stmt->setUInt32(1, inet_addr(ip_address.c_str()));
+ LoginDatabase.Execute(stmt);
- _queryCallback = std::bind(&Battlenet::Session::CheckIpCallback, this, std::placeholders::_1);
- _queryFuture = LoginDatabase.AsyncQuery(stmt);
+ Attribute* attribute = response->add_attribute();
+ attribute->set_name("Param_RealmListTicket");
+ attribute->mutable_value()->set_blob_value("AuthRealmListTicket");
+
+ return ERROR_OK;
}
-void Battlenet::Session::CheckIpCallback(PreparedQueryResult result)
+uint32 Battlenet::Session::GetLastCharPlayed(std::unordered_map<std::string, Variant const*> const& params, game_utilities::v1::ClientResponse* response)
{
- if (result)
+ if (Variant const* subRegion = GetParam(params, "Command_LastCharPlayedRequest_v1_b9"))
{
- bool banned = false;
- do
+ auto lastPlayerChar = _gameAccountInfo->LastPlayedCharacters.find(subRegion->string_value());
+ if (lastPlayerChar != _gameAccountInfo->LastPlayedCharacters.end())
{
- Field* fields = result->Fetch();
- if (fields[0].GetUInt64() != 0)
- banned = true;
+ std::vector<uint8> compressed = sRealmList->GetRealmEntryJSON(lastPlayerChar->second.RealmId, _build);
- if (!fields[1].GetString().empty())
- _ipCountry = fields[1].GetString();
+ if (compressed.empty())
+ return ERROR_UTIL_SERVER_FAILED_TO_SERIALIZE_RESPONSE;
- } while (result->NextRow());
+ Attribute* attribute = response->add_attribute();
+ attribute->set_name("Param_RealmEntry");
+ attribute->mutable_value()->set_blob_value(compressed.data(), compressed.size());
- if (banned)
- {
- Authentication::LogonResponse* logonResponse = new Authentication::LogonResponse();
- logonResponse->SetAuthResult(AUTH_INTERNAL_ERROR);
- AsyncWrite(logonResponse);
- TC_LOG_DEBUG("session", "[Battlenet::LogonRequest] Banned ip '%s:%d' tries to login!", GetRemoteIpAddress().to_string().c_str(), GetRemotePort());
- return;
+ attribute = response->add_attribute();
+ attribute->set_name("Param_CharacterName");
+ attribute->mutable_value()->set_string_value(lastPlayerChar->second.CharacterName);
+
+ attribute = response->add_attribute();
+ attribute->set_name("Param_CharacterGUID");
+ attribute->mutable_value()->set_blob_value(&lastPlayerChar->second.CharacterGUID, sizeof(lastPlayerChar->second.CharacterGUID));
+
+ attribute = response->add_attribute();
+ attribute->set_name("Param_LastPlayedTime");
+ attribute->mutable_value()->set_int_value(int32(lastPlayerChar->second.LastPlayedTime));
}
+
+ return ERROR_OK;
}
- AsyncRead();
+ return ERROR_UTIL_SERVER_UNKNOWN_REALM;
}
-bool Battlenet::Session::Update()
+uint32 Battlenet::Session::GetRealmList(std::unordered_map<std::string, Variant const*> const& params, game_utilities::v1::ClientResponse* response)
{
- EncryptableBuffer* queued;
- MessageBuffer buffer((std::size_t(BufferSizes::Read)));
- while (_bufferQueue.Dequeue(queued))
- {
- std::size_t packetSize = queued->Buffer.GetActiveSize();
- if (queued->Encrypt)
- _crypt.EncryptSend(queued->Buffer.GetReadPointer(), packetSize);
-
- if (buffer.GetRemainingSpace() < packetSize)
- {
- QueuePacket(std::move(buffer));
- buffer.Resize(std::size_t(BufferSizes::Read));
- }
+ if (!_gameAccountInfo)
+ return ERROR_USER_SERVER_BAD_WOW_ACCOUNT;
- if (buffer.GetRemainingSpace() >= packetSize)
- buffer.Write(queued->Buffer.GetReadPointer(), packetSize);
- else // single packet larger than 16384 bytes - client will reject.
- QueuePacket(std::move(queued->Buffer));
+ std::string subRegionId;
+ if (Variant const* subRegion = GetParam(params, "Command_RealmListRequest_v1_b9"))
+ subRegionId = subRegion->string_value();
- delete queued;
- }
+ std::vector<uint8> compressed = sRealmList->GetRealmList(_build, subRegionId);
- if (buffer.GetActiveSize() > 0)
- QueuePacket(std::move(buffer));
+ if (compressed.empty())
+ return ERROR_UTIL_SERVER_FAILED_TO_SERIALIZE_RESPONSE;
- if (!BattlenetSocket::Update())
- return false;
+ Attribute* attribute = response->add_attribute();
+ attribute->set_name("Param_RealmList");
+ attribute->mutable_value()->set_blob_value(compressed.data(), compressed.size());
- if (_queryFuture.valid() && _queryFuture.wait_for(std::chrono::seconds(0)) == std::future_status::ready)
+ ::JSON::RealmList::RealmCharacterCountList realmCharacterCounts;
+ for (auto const& characterCount : _gameAccountInfo->CharacterCounts)
{
- auto callback = _queryCallback;
- _queryCallback = nullptr;
- callback(_queryFuture.get());
+ ::JSON::RealmList::RealmCharacterCountEntry* countEntry = realmCharacterCounts.add_counts();
+ countEntry->set_wowrealmaddress(characterCount.first);
+ countEntry->set_count(characterCount.second);
}
- return true;
-}
-
-void Battlenet::Session::AsyncWrite(ServerPacket* packet)
-{
- if (!IsOpen())
- {
- delete packet;
- return;
- }
+ std::string json = "JSONRealmCharacterCountList:" + ::JSON::Serialize(realmCharacterCounts);
- TC_LOG_DEBUG("session.packets", "%s Sending %s", GetClientInfo().c_str(), PacketToStringHelper(packet).c_str());
+ uLongf compressedLength = compressBound(json.length());
+ compressed.resize(4 + compressedLength);
+ *reinterpret_cast<uint32*>(compressed.data()) = json.length() + 1;
- packet->Write();
+ if (compress(compressed.data() + 4, &compressedLength, reinterpret_cast<uint8 const*>(json.c_str()), json.length() + 1) != Z_OK)
+ return ERROR_UTIL_SERVER_FAILED_TO_SERIALIZE_RESPONSE;
- EncryptableBuffer* buffer = new EncryptableBuffer();
- buffer->Buffer.Write(packet->GetData(), packet->GetSize());
- buffer->Encrypt = _crypt.IsInitialized();
- delete packet;
-
- _bufferQueue.Enqueue(buffer);
+ attribute = response->add_attribute();
+ attribute->set_name("Param_CharacterCountList");
+ attribute->mutable_value()->set_blob_value(compressed.data(), compressedLength + 4);
+ return ERROR_OK;
}
-inline void ReplaceResponse(Battlenet::ServerPacket** oldResponse, Battlenet::ServerPacket* newResponse)
+uint32 Battlenet::Session::JoinRealm(std::unordered_map<std::string, Variant const*> const& params, game_utilities::v1::ClientResponse* response)
{
- if (*oldResponse)
- delete *oldResponse;
+ if (Variant const* realmAddress = GetParam(params, "Param_RealmAddress"))
+ return sRealmList->JoinRealm(realmAddress->uint_value(), _build, GetRemoteIpAddress(), _clientSecret, GetLocaleByName(_locale), _os, _gameAccountInfo->Name, response);
- *oldResponse = newResponse;
+ return ERROR_WOW_SERVICES_INVALID_JOIN_TICKET;
}
-bool Battlenet::Session::HandlePasswordModule(BitStream* dataStream, ServerPacket** response)
+uint32 Battlenet::Session::HandleGetAllValuesForAttribute(game_utilities::v1::GetAllValuesForAttributeRequest const* request, game_utilities::v1::GetAllValuesForAttributeResponse* response)
{
- if (dataStream->GetSize() != 1 + 128 + 32 + 128)
- {
- Authentication::LogonResponse* logonResponse = new Authentication::LogonResponse();
- logonResponse->SetAuthResult(AUTH_CORRUPTED_MODULE);
- ReplaceResponse(response, logonResponse);
- return false;
- }
+ if (!_authed)
+ return ERROR_DENIED;
- if (dataStream->Read<uint8>(8) != 2) // State
+ if (request->attribute_key() == "Command_RealmListRequest_v1_b9")
{
- Authentication::LogonResponse* logonResponse = new Authentication::LogonResponse();
- logonResponse->SetAuthResult(AUTH_CORRUPTED_MODULE);
- ReplaceResponse(response, logonResponse);
- return false;
+ sRealmList->WriteSubRegions(response);
+ return ERROR_OK;
}
- 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);
+ return ERROR_RPC_NOT_IMPLEMENTED;
+}
- if (A.IsZero())
+void Battlenet::Session::HandshakeHandler(boost::system::error_code const& error)
+{
+ if (error)
{
- Authentication::LogonResponse* logonResponse = new Authentication::LogonResponse();
- logonResponse->SetAuthResult(AUTH_CORRUPTED_MODULE);
- ReplaceResponse(response, logonResponse);
- return false;
+ TC_LOG_ERROR("session", "%s SSL Handshake failed %s", GetClientInfo().c_str(), error.message().c_str());
+ CloseSocket();
+ return;
}
- 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);
+ AsyncRead();
+}
- uint8 part1[64];
- uint8 part2[64];
+template<bool(Battlenet::Session::*processMethod)(), MessageBuffer Battlenet::Session::*outputBuffer>
+inline bool PartialProcessPacket(Battlenet::Session* session, MessageBuffer& inputBuffer)
+{
+ MessageBuffer& buffer = session->*outputBuffer;
- for (int i = 0; i < 64; ++i)
+ // We have full read header, now check the data payload
+ if (buffer.GetRemainingSpace() > 0)
{
- part1[i] = S_bytes[i * 2];
- part2[i] = S_bytes[i * 2 + 1];
+ // need more data in the payload
+ std::size_t readDataSize = std::min(inputBuffer.GetActiveSize(), buffer.GetRemainingSpace());
+ buffer.Write(inputBuffer.GetReadPointer(), readDataSize);
+ inputBuffer.ReadCompleted(readDataSize);
}
- 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)
+ if (buffer.GetRemainingSpace() > 0)
{
- 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, _accountInfo->Login);
- LoginDatabase.Execute(stmt);
-
- Authentication::LogonResponse* logonResponse = new Authentication::LogonResponse();
- logonResponse->SetAuthResult(AUTH_UNKNOWN_ACCOUNT);
- ReplaceResponse(response, logonResponse);
- TC_LOG_DEBUG("session", "[Battlenet::Password] %s attempted to log in with invalid password!", GetClientInfo().c_str());
+ // Couldn't receive the whole data this time.
+ ASSERT(inputBuffer.GetActiveSize() == 0);
return false;
}
- if (_gameAccounts.empty())
+ // just received fresh new payload
+ if (!(session->*processMethod)())
{
- Authentication::LogonResponse* logonResponse = new Authentication::LogonResponse();
- logonResponse->SetAuthResult(LOGIN_NO_GAME_ACCOUNT);
- ReplaceResponse(response, logonResponse);
- TC_LOG_DEBUG("session", "[Battlenet::Password] %s does not have any linked game accounts!", GetClientInfo().c_str());
+ session->CloseSocket();
return false;
}
- 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 = sModuleMgr->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* proofRequest = new Authentication::ProofRequest();
- proofRequest->Modules.push_back(password);
- if (_gameAccounts.size() > 1)
- {
- BitStream accounts;
- state = 0;
- accounts.WriteBytes(&state, 1);
- accounts.Write(_gameAccounts.size(), 8);
- for (GameAccountInfo const& gameAccount : _gameAccounts)
- {
- accounts.Write(2, 8);
- accounts.WriteString(gameAccount.DisplayName, 8);
- }
-
- ModuleInfo* selectGameAccount = sModuleMgr->CreateModule(_os, "SelectGameAccount");
- selectGameAccount->DataSize = accounts.GetSize();
- selectGameAccount->Data = new uint8[selectGameAccount->DataSize];
- memcpy(selectGameAccount->Data, accounts.GetBuffer(), selectGameAccount->DataSize);
- proofRequest->Modules.push_back(selectGameAccount);
- _modulesWaitingForData.push(MODULE_SELECT_GAME_ACCOUNT);
- }
- else
- {
- _gameAccountInfo = &_gameAccounts[0];
-
- if (_gameAccountInfo->IsBanned)
- {
- delete proofRequest;
-
- Authentication::LogonResponse* logonResponse = new Authentication::LogonResponse();
- if (_gameAccountInfo->IsPermanenetlyBanned)
- {
- logonResponse->SetAuthResult(LOGIN_BANNED);
- TC_LOG_DEBUG("session", "'%s:%d' [Battlenet::Password] Banned account %s tried to login!", GetRemoteIpAddress().to_string().c_str(), GetRemotePort(), _accountInfo->Login.c_str());
- }
- else
- {
- logonResponse->SetAuthResult(LOGIN_SUSPENDED);
- TC_LOG_DEBUG("session", "'%s:%d' [Battlenet::Password] Temporarily banned account %s tried to login!", GetRemoteIpAddress().to_string().c_str(), GetRemotePort(), _accountInfo->Login.c_str());
- }
-
- ReplaceResponse(response, logonResponse);
- return false;
- }
-
- proofRequest->Modules.push_back(sModuleMgr->CreateModule(_os, "RiskFingerprint"));
- _modulesWaitingForData.push(MODULE_RISK_FINGERPRINT);
- }
-
- ReplaceResponse(response, proofRequest);
return true;
}
-bool Battlenet::Session::HandleSelectGameAccountModule(BitStream* dataStream, ServerPacket** response)
+void Battlenet::Session::ReadHandler()
{
- if (dataStream->Read<uint8>(8) != 1)
- {
- Authentication::LogonResponse* logonResponse = new Authentication::LogonResponse();
- logonResponse->SetAuthResult(AUTH_CORRUPTED_MODULE);
- ReplaceResponse(response, logonResponse);
- return false;
- }
-
- dataStream->Read<uint8>(8);
- std::string account = dataStream->ReadString(8);
- if (account.empty())
- {
- Authentication::LogonResponse* logonResponse = new Authentication::LogonResponse();
- logonResponse->SetAuthResult(LOGIN_NO_GAME_ACCOUNT);
- ReplaceResponse(response, logonResponse);
- return false;
- }
+ if (!IsOpen())
+ return;
- for (std::size_t i = 0; i < _gameAccounts.size(); ++i)
+ MessageBuffer& packet = GetReadBuffer();
+ while (packet.GetActiveSize() > 0)
{
- if (_gameAccounts[i].DisplayName == account)
- {
- _gameAccountInfo = &_gameAccounts[i];
+ if (!PartialProcessPacket<&Battlenet::Session::ReadHeaderLengthHandler, &Battlenet::Session::_headerLengthBuffer>(this, packet))
break;
- }
- }
- if (!_gameAccountInfo)
- {
- Authentication::LogonResponse* complete = new Authentication::LogonResponse();
- complete->SetAuthResult(LOGIN_NO_GAME_ACCOUNT);
- ReplaceResponse(response, complete);
- TC_LOG_DEBUG("session", "[Battlenet::SelectGameAccount] %s attempted to log in with invalid game account name %s!", GetClientInfo().c_str(), account.c_str());
- return false;
- }
+ if (!PartialProcessPacket<&Battlenet::Session::ReadHeaderHandler, &Battlenet::Session::_headerBuffer>(this, packet))
+ break;
- if (_gameAccountInfo->IsBanned)
- {
- Authentication::LogonResponse* logonResponse = new Authentication::LogonResponse();
- if (_gameAccountInfo->IsPermanenetlyBanned)
- {
- logonResponse->SetAuthResult(LOGIN_BANNED);
- TC_LOG_DEBUG("session", "'%s:%d' [Battlenet::SelectGameAccount] Banned account %s tried to login!", GetRemoteIpAddress().to_string().c_str(), GetRemotePort(), _accountInfo->Login.c_str());
- }
- else
- {
- logonResponse->SetAuthResult(LOGIN_SUSPENDED);
- TC_LOG_DEBUG("session", "'%s:%d' [Battlenet::SelectGameAccount] Temporarily banned account %s tried to login!", GetRemoteIpAddress().to_string().c_str(), GetRemotePort(), _accountInfo->Login.c_str());
- }
+ if (!PartialProcessPacket<&Battlenet::Session::ReadDataHandler, &Battlenet::Session::_packetBuffer>(this, packet))
+ break;
- ReplaceResponse(response, logonResponse);
- return false;
+ _headerLengthBuffer.Reset();
+ _headerBuffer.Reset();
}
- Authentication::ProofRequest* proofRequest = new Authentication::ProofRequest();
- proofRequest->Modules.push_back(sModuleMgr->CreateModule(_os, "RiskFingerprint"));
- ReplaceResponse(response, proofRequest);
-
- _modulesWaitingForData.push(MODULE_RISK_FINGERPRINT);
- return true;
+ AsyncRead();
}
-bool Battlenet::Session::HandleRiskFingerprintModule(BitStream* dataStream, ServerPacket** response)
+bool Battlenet::Session::ReadHeaderLengthHandler()
{
- Authentication::LogonResponse* logonResponse = new Authentication::LogonResponse();
- if (dataStream->Read<uint8>(8) == 1 && _accountInfo && _gameAccountInfo)
- {
- logonResponse->Result.Success.AccountId = _accountInfo->Id;
- logonResponse->Result.Success.GameAccountName = _gameAccountInfo->Name;
- logonResponse->Result.Success.GameAccountFlags = GAMEACCOUNT_FLAG_PROPASS;
- logonResponse->Result.Success.LogonFailures = _accountInfo->FailedLogins;
-
- SQLTransaction trans = LoginDatabase.BeginTransaction();
-
- PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_BNET_LAST_LOGIN_INFO);
- stmt->setString(0, GetRemoteIpAddress().to_string());
- stmt->setUInt8(1, GetLocaleByName(_locale));
- stmt->setString(2, _os);
- stmt->setUInt32(3, _accountInfo->Id);
- trans->Append(stmt);
-
- stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_BNET_SESSION_KEY);
- stmt->setString(0, K.AsHexStr());
- stmt->setBool(1, true);
- stmt->setUInt32(2, _accountInfo->Id);
- trans->Append(stmt);
-
- LoginDatabase.CommitTransaction(trans);
-
- _authed = true;
- sSessionMgr.AddSession(this);
- }
- else
- logonResponse->SetAuthResult(AUTH_BAD_VERSION_HASH);
-
- ReplaceResponse(response, logonResponse);
+ uint16 len = *reinterpret_cast<uint16*>(_headerLengthBuffer.GetReadPointer());
+ EndianConvertReverse(len);
+ _headerBuffer.Resize(len);
return true;
}
-bool Battlenet::Session::HandleResumeModule(BitStream* dataStream, ServerPacket** response)
+bool Battlenet::Session::ReadHeaderHandler()
{
- if (dataStream->Read<uint8>(8) != 1)
- {
- Authentication::ResumeResponse* resumeResponse = new Authentication::ResumeResponse();
- resumeResponse->SetAuthResult(AUTH_CORRUPTED_MODULE);
- ReplaceResponse(response, resumeResponse);
- 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);
+ Header header;
+ if (!header.ParseFromArray(_headerBuffer.GetReadPointer(), _headerBuffer.GetActiveSize()))
+ return true;
- 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, _accountInfo->Login);
- LoginDatabase.Execute(stmt);
-
- TC_LOG_DEBUG("session", "[Battlenet::Resume] %s attempted to reconnect with invalid password!", GetClientInfo().c_str());
- Authentication::ResumeResponse* resumeResponse = new Authentication::ResumeResponse();
- resumeResponse->SetAuthResult(AUTH_UNKNOWN_ACCOUNT);
- ReplaceResponse(response, resumeResponse);
- return false;
- }
-
- PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_BNET_SESSION_KEY);
- stmt->setString(0, K.AsHexStr());
- stmt->setBool(1, true);
- stmt->setUInt32(2, _accountInfo->Id);
- 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 = sModuleMgr->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* resumeResponse = new Authentication::ResumeResponse();
- resumeResponse->Result.Success.FinalRequest.push_back(resume);
- ReplaceResponse(response, resumeResponse);
- _authed = true;
- sSessionMgr.AddSession(this);
+ _packetBuffer.Resize(header.size());
return true;
}
-bool Battlenet::Session::UnhandledModule(BitStream* /*dataStream*/, ServerPacket** response)
+bool Battlenet::Session::ReadDataHandler()
{
- TC_LOG_ERROR("session.packets", "Unhandled module.");
- Authentication::LogonResponse* logonResponse = new Authentication::LogonResponse();
- logonResponse->SetAuthResult(AUTH_CORRUPTED_MODULE);
- ReplaceResponse(response, logonResponse);
- return false;
-}
-
-void Battlenet::Session::UpdateRealms(std::vector<Realm const*>& realms, std::vector<RealmHandle>& deletedRealms)
-{
- for (Realm const* realm : realms)
- AsyncWrite(BuildListUpdate(realm));
+ Header header;
+ header.ParseFromArray(_headerBuffer.GetReadPointer(), _headerBuffer.GetActiveSize());
- for (RealmHandle& deleted : deletedRealms)
+ if (header.service_id() != 0xFE)
{
- WoWRealm::ListUpdate* listUpdate = new WoWRealm::ListUpdate();
- listUpdate->State.Type = WoWRealm::ListUpdate::StateType::DELETED;
- listUpdate->Id = deleted;
- AsyncWrite(listUpdate);
+ sServiceDispatcher.Dispatch(this, header.service_hash(), header.token(), header.method_id(), std::move(_packetBuffer));
}
-}
-
-Battlenet::WoWRealm::ListUpdate* Battlenet::Session::BuildListUpdate(Realm const* realm) const
-{
- uint32 flag = realm->Flags;
- if (realm->Build != _build)
- flag |= REALM_FLAG_VERSION_MISMATCH;
-
- WoWRealm::ListUpdate* listUpdate = new WoWRealm::ListUpdate();
- listUpdate->State.Update.Category = realm->Timezone;
- listUpdate->State.Update.Population = realm->PopulationLevel;
- listUpdate->State.Update.StateFlags = (realm->AllowedSecurityLevel > _gameAccountInfo->SecurityLevel) ? 1 : 0;
- listUpdate->State.Update.Type = realm->Type;
- listUpdate->State.Update.Name = realm->Name;
-
- if (_gameAccountInfo->SecurityLevel > SEC_PLAYER)
+ else
{
- listUpdate->State.Update.PrivilegedData = boost::in_place();
- std::ostringstream version;
- if (RealmBuildInfo const* buildInfo = AuthHelper::GetBuildInfo(realm->Build))
- version << buildInfo->MajorVersion << '.' << buildInfo->MinorVersion << '.' << buildInfo->BugfixVersion << '.' << buildInfo->Build;
+ auto itr = _responseCallbacks.find(header.token());
+ if (itr != _responseCallbacks.end())
+ {
+ itr->second(std::move(_packetBuffer));
+ _responseCallbacks.erase(header.token());
+ }
else
- version << "x.x.x." << realm->Build;
-
- listUpdate->State.Update.PrivilegedData->Version = version.str();
- listUpdate->State.Update.PrivilegedData->ConfigId = realm->GetConfigId();
- listUpdate->State.Update.PrivilegedData->Address = realm->GetAddressForClient(GetRemoteIpAddress());
+ _packetBuffer.Reset();
}
- listUpdate->State.Update.InfoFlags = flag;
- listUpdate->Id = realm->Id;
- return listUpdate;
+ return true;
}
std::string Battlenet::Session::GetClientInfo() const
diff --git a/src/server/bnetserver/Server/Session.h b/src/server/bnetserver/Server/Session.h
index 2443d694a80..4170cbc7826 100644
--- a/src/server/bnetserver/Server/Session.h
+++ b/src/server/bnetserver/Server/Session.h
@@ -18,140 +18,165 @@
#ifndef Session_h__
#define Session_h__
-#include "Packets.h"
-#include "BattlenetPacketCrypt.h"
+#include "Realm.h"
+#include "SslContext.h"
+#include "SslSocket.h"
#include "Socket.h"
#include "BigNumber.h"
#include "Callback.h"
-#include "MPSCQueue.h"
-#include <memory>
#include <boost/asio/ip/tcp.hpp>
+#include <boost/asio/ssl.hpp>
+#include <google/protobuf/message.h>
+#include <memory>
-struct Realm;
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
- };
+namespace pb = google::protobuf;
- enum class BufferSizes : uint32
+namespace bgs
+{
+ namespace protocol
{
- SRP_6_V = 0x80,
- SRP_6_S = 0x20,
- Read = 0x4000
- };
+ class Variant;
- struct AccountInfo
- {
- void LoadResult(Field* fields);
-
- uint32 Id;
- std::string Login;
- bool IsLockedToIP;
- std::string LockCountry;
- std::string LastIP;
- uint32 FailedLogins;
- bool IsBanned;
- bool IsPermanenetlyBanned;
- };
+ namespace account
+ {
+ namespace v1
+ {
+ class GetAccountStateRequest;
+ class GetAccountStateResponse;
+ class GetGameAccountStateRequest;
+ class GetGameAccountStateResponse;
+ }
+ }
+
+ namespace authentication
+ {
+ namespace v1
+ {
+ class LogonRequest;
+ class VerifyWebCredentialsRequest;
+ }
+ }
+
+ namespace game_utilities
+ {
+ namespace v1
+ {
+ class ClientRequest;
+ class ClientResponse;
+ class GetAllValuesForAttributeRequest;
+ class GetAllValuesForAttributeResponse;
+ }
+ }
+ }
+}
- struct GameAccountInfo
- {
- void LoadResult(Field* fields);
-
- uint32 Id;
- std::string Name;
- std::string DisplayName;
- bool IsBanned;
- bool IsPermanenetlyBanned;
- AccountTypes SecurityLevel;
- };
+using namespace bgs::protocol;
- class Session : public Socket<Session>
+namespace Battlenet
+{
+ class Session : public Socket<Session, SslSocket<SslContext>>
{
- typedef Socket<Session> BattlenetSocket;
+ typedef Socket<Session, SslSocket<SslContext>> BattlenetSocket;
public:
- explicit Session(tcp::socket&& socket);
- ~Session();
-
- void LogUnhandledPacket(PacketHeader const& header);
+ struct LastPlayedCharacterInfo
+ {
+ Battlenet::RealmHandle RealmId;
+ std::string CharacterName;
+ uint64 CharacterGUID;
+ uint32 LastPlayedTime;
+ };
- // Authentication
- void HandleLogonRequest(Authentication::LogonRequest3 const& logonRequest);
- void HandleResumeRequest(Authentication::ResumeRequest const& resumeRequest);
- void HandleProofResponse(Authentication::ProofResponse const& proofResponse);
+ struct GameAccountInfo
+ {
+ void LoadResult(Field* fields);
- // Connection
- void HandlePing(Connection::Ping const& ping);
- void HandleEnableEncryption(Connection::EnableEncryption& enableEncryption);
- void HandleLogoutRequest(Connection::LogoutRequest const& logoutRequest);
- void HandleConnectionClosing(Connection::ConnectionClosing const& connectionClosing);
+ uint32 Id;
+ std::string Name;
+ std::string DisplayName;
+ bool IsBanned;
+ bool IsPermanenetlyBanned;
+ AccountTypes SecurityLevel;
- // WoWRealm
- void HandleListSubscribeRequest(WoWRealm::ListSubscribeRequest const& listSubscribeRequest);
- void HandleListUnsubscribe(WoWRealm::ListUnsubscribe const& listUnsubscribe);
- void HandleJoinRequestV2(WoWRealm::JoinRequestV2 const& joinRequest);
+ std::unordered_map<uint32 /*realmAddress*/, uint8> CharacterCounts;
+ std::unordered_map<std::string /*subRegion*/, LastPlayedCharacterInfo> LastPlayedCharacters;
+ };
- // Friends
+ struct AccountInfo
+ {
+ void LoadResult(PreparedQueryResult result);
+
+ uint32 Id;
+ std::string Login;
+ bool IsLockedToIP;
+ std::string LockCountry;
+ std::string LastIP;
+ uint32 FailedLogins;
+ bool IsBanned;
+ bool IsPermanenetlyBanned;
+
+ std::unordered_map<uint32, GameAccountInfo> GameAccounts;
+ };
- // Cache
- void HandleGetStreamItemsRequest(Cache::GetStreamItemsRequest const& getStreamItemsRequest);
+ explicit Session(tcp::socket&& socket);
+ ~Session();
void Start() override;
bool Update() override;
- void UpdateRealms(std::vector<Realm const*>& realms, std::vector<RealmHandle>& deletedRealms);
-
uint32 GetAccountId() const { return _accountInfo->Id; }
uint32 GetGameAccountId() const { return _gameAccountInfo->Id; }
- bool IsToonOnline() const { return _toonOnline; }
- void SetToonOnline(bool online) { _toonOnline = online; }
+ void SendResponse(uint32 token, pb::Message const* response);
+ void SendResponse(uint32 token, uint32 status);
+
+ void SendRequest(uint32 serviceHash, uint32 methodId, pb::Message const* request, std::function<void(MessageBuffer)> callback)
+ {
+ _responseCallbacks[_requestToken] = std::move(callback);
+ SendRequest(serviceHash, methodId, request);
+ }
+
+ void SendRequest(uint32 serviceHash, uint32 methodId, pb::Message const* request);
- bool IsSubscribedToRealmListUpdates() const { return _subscribedToRealmListUpdates; }
+ uint32 HandleLogon(authentication::v1::LogonRequest const* logonRequest);
+ uint32 HandleVerifyWebCredentials(authentication::v1::VerifyWebCredentialsRequest const* verifyWebCredentialsRequest);
+ uint32 HandleGetAccountState(account::v1::GetAccountStateRequest const* request, account::v1::GetAccountStateResponse* response);
+ uint32 HandleGetGameAccountState(account::v1::GetGameAccountStateRequest const* request, account::v1::GetGameAccountStateResponse* response);
+ uint32 HandleProcessClientRequest(game_utilities::v1::ClientRequest const* request, game_utilities::v1::ClientResponse* response);
+ uint32 HandleGetAllValuesForAttribute(game_utilities::v1::GetAllValuesForAttributeRequest const* request, game_utilities::v1::GetAllValuesForAttributeResponse* response);
- void AsyncWrite(ServerPacket* packet);
+ std::string GetClientInfo() const;
protected:
+ void HandshakeHandler(boost::system::error_code const& error);
void ReadHandler() override;
+ bool ReadHeaderLengthHandler();
+ bool ReadHeaderHandler();
+ bool ReadDataHandler();
private:
- void _SetVSFields(std::string const& rI);
+ void AsyncWrite(MessageBuffer* packet);
- typedef bool(Session::*ModuleHandler)(BitStream* dataStream, ServerPacket** response);
- static ModuleHandler const ModuleHandlers[MODULE_COUNT];
+ void AsyncHandshake();
void CheckIpCallback(PreparedQueryResult result);
- void HandleLogonRequestCallback(PreparedQueryResult result);
- void HandleResumeRequestCallback(PreparedQueryResult result);
- void HandleListSubscribeRequestCallback(PreparedQueryResult result);
- 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);
+ typedef uint32(Session::*ClientRequestHandler)(std::unordered_map<std::string, Variant const*> const&, game_utilities::v1::ClientResponse*);
+ static std::unordered_map<std::string, ClientRequestHandler> const ClientRequestHandlers;
- WoWRealm::ListUpdate* BuildListUpdate(Realm const* realm) const;
- std::string GetClientInfo() const;
+ uint32 GetRealmListTicket(std::unordered_map<std::string, Variant const*> const& params, game_utilities::v1::ClientResponse* response);
+ uint32 GetLastCharPlayed(std::unordered_map<std::string, Variant const*> const& params, game_utilities::v1::ClientResponse* response);
+ uint32 GetRealmList(std::unordered_map<std::string, Variant const*> const& params, game_utilities::v1::ClientResponse* response);
+ uint32 JoinRealm(std::unordered_map<std::string, Variant const*> const& params, game_utilities::v1::ClientResponse* response);
+
+ MessageBuffer _headerLengthBuffer;
+ MessageBuffer _headerBuffer;
+ MessageBuffer _packetBuffer;
- AccountInfo* _accountInfo;
+ std::unique_ptr<AccountInfo> _accountInfo;
GameAccountInfo* _gameAccountInfo; // Points at selected game account (inside _gameAccounts)
- std::vector<GameAccountInfo> _gameAccounts;
std::string _locale;
std::string _os;
@@ -159,38 +184,16 @@ namespace Battlenet
std::string _ipCountry;
- BigNumber N;
- BigNumber g;
- BigNumber k;
-
- BigNumber I;
- BigNumber s;
- BigNumber v;
-
- BigNumber b;
- BigNumber B;
- BigNumber K; // session key
-
- BigNumber _reconnectProof;
-
- std::queue<ModuleType> _modulesWaitingForData;
+ std::array<uint8, 32> _clientSecret;
- struct EncryptableBuffer
- {
- MessageBuffer Buffer;
- bool Encrypt;
- };
-
- MPSCQueue<EncryptableBuffer> _bufferQueue;
- PacketCrypt _crypt;
bool _authed;
- bool _subscribedToRealmListUpdates;
- bool _toonOnline;
PreparedQueryResultFuture _queryFuture;
std::function<void(PreparedQueryResult)> _queryCallback;
- };
+ std::unordered_map<uint32, std::function<void(MessageBuffer)>> _responseCallbacks;
+ uint32 _requestToken;
+ };
}
#endif // Session_h__
diff --git a/src/server/bnetserver/Server/SessionManager.cpp b/src/server/bnetserver/Server/SessionManager.cpp
index ed36a3630e1..1920496ffff 100644
--- a/src/server/bnetserver/Server/SessionManager.cpp
+++ b/src/server/bnetserver/Server/SessionManager.cpp
@@ -37,41 +37,8 @@ void Battlenet::SessionManager::OnSocketAccept(tcp::socket&& sock, uint32 thread
sSessionMgr.OnSocketOpen(std::forward<tcp::socket>(sock), threadIndex);
}
-void Battlenet::SessionManager::AddSession(Session* session)
+Battlenet::SessionManager& Battlenet::SessionManager::Instance()
{
- std::unique_lock<boost::shared_mutex> lock(_sessionMutex);
- _sessions[{ session->GetAccountId(), session->GetGameAccountId() }] = session;
- _sessionsByAccountId[session->GetAccountId()].push_back(session);
-}
-
-void Battlenet::SessionManager::RemoveSession(Session* session)
-{
- std::unique_lock<boost::shared_mutex> lock(_sessionMutex);
- auto itr = _sessions.find({ session->GetAccountId(), session->GetGameAccountId() });
- // Remove old session only if it was not overwritten by reconnecting
- if (itr != _sessions.end() && itr->second == session)
- _sessions.erase(itr);
-
- _sessionsByAccountId[session->GetAccountId()].remove(session);
-}
-
-Battlenet::Session* Battlenet::SessionManager::GetSession(uint32 accountId, uint32 gameAccountId) const
-{
- boost::shared_lock<boost::shared_mutex> lock(_sessionMutex);
- auto itr = _sessions.find({ accountId, gameAccountId });
- if (itr != _sessions.end())
- return itr->second;
-
- return nullptr;
-}
-
-std::list<Battlenet::Session*> Battlenet::SessionManager::GetSessions(uint32 accountId) const
-{
- boost::shared_lock<boost::shared_mutex> lock(_sessionMutex);
- std::list<Session*> sessions;
- auto itr = _sessionsByAccountId.find(accountId);
- if (itr != _sessionsByAccountId.end())
- sessions = itr->second;
-
- return sessions;
+ static SessionManager instance;
+ return instance;
}
diff --git a/src/server/bnetserver/Server/SessionManager.h b/src/server/bnetserver/Server/SessionManager.h
index 701802056da..c1aa955812c 100644
--- a/src/server/bnetserver/Server/SessionManager.h
+++ b/src/server/bnetserver/Server/SessionManager.h
@@ -18,68 +18,25 @@
#ifndef SessionManager_h__
#define SessionManager_h__
-#include "Session.h"
#include "SocketMgr.h"
-#include <boost/thread/locks.hpp>
-#include <boost/thread/shared_mutex.hpp>
+#include "Session.h"
namespace Battlenet
{
-#pragma pack(push, 1)
-
- struct SessionInfo
- {
- uint32 AccountId;
- uint32 GameAccountId;
-
- bool operator<(SessionInfo const& right) const
- {
- return memcmp(this, &right, sizeof(SessionInfo)) < 0;
- }
- };
-
-#pragma pack(pop)
-
class SessionManager : public SocketMgr<Session>
{
typedef SocketMgr<Session> BaseSocketMgr;
- typedef std::map<SessionInfo, Session*> SessionMap;
- typedef std::map<uint32, std::list<Session*>> SessionByAccountMap;
public:
- static SessionManager& Instance()
- {
- static SessionManager instance;
- return instance;
- }
+ static SessionManager& Instance();
bool StartNetwork(boost::asio::io_service& service, std::string const& bindIp, uint16 port, int threadCount = 1) override;
- // noop for now, will be needed later to broadcast realmlist updates for example
- void AddSession(Session* /*session*/);
-
- void RemoveSession(Session* /*session*/);
-
- Session* GetSession(uint32 accountId, uint32 gameAccountId) const;
- std::list<Session*> GetSessions(uint32 accountId) const;
-
- template<typename Iterator>
- void LockedForEach(Iterator iterator) const
- {
- boost::shared_lock<boost::shared_mutex> lock(_sessionMutex);
- for (SessionMap::value_type const& pair : _sessions)
- iterator(pair.second);
- }
-
protected:
NetworkThread<Session>* CreateThreads() const override;
private:
static void OnSocketAccept(tcp::socket&& sock, uint32 threadIndex);
-
- SessionMap _sessions;
- SessionByAccountMap _sessionsByAccountId;
- mutable boost::shared_mutex _sessionMutex;
};
}
diff --git a/src/server/bnetserver/Server/SslContext.cpp b/src/server/bnetserver/Server/SslContext.cpp
new file mode 100644
index 00000000000..f1b2a185563
--- /dev/null
+++ b/src/server/bnetserver/Server/SslContext.cpp
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2008-2016 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 "SslContext.h"
+#include "Log.h"
+
+bool Battlenet::SslContext::Initialize()
+{
+ boost::system::error_code err;
+
+#define LOAD_CHECK(fn) do { fn; \
+ if (err) \
+ { \
+ TC_LOG_ERROR("server.ssl", #fn ## "failed: %s", err.message().c_str()); \
+ return false; \
+ } } while (0)
+
+ LOAD_CHECK(instance().set_options(boost::asio::ssl::context::no_sslv3, err));
+ LOAD_CHECK(instance().use_certificate_chain_file("bnetserver.cert.pem", err));
+ LOAD_CHECK(instance().use_private_key_file("bnetserver.key.pem", boost::asio::ssl::context::pem, err));
+
+#undef LOAD_CHECK
+
+ return true;
+}
+
+boost::asio::ssl::context& Battlenet::SslContext::instance()
+{
+ static boost::asio::ssl::context context(boost::asio::ssl::context::sslv23);
+ return context;
+}
diff --git a/src/server/bnetserver/Server/SslContext.h b/src/server/bnetserver/Server/SslContext.h
new file mode 100644
index 00000000000..5425ab46231
--- /dev/null
+++ b/src/server/bnetserver/Server/SslContext.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2008-2016 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/>.
+ */
+
+#ifndef SslContext_h__
+#define SslContext_h__
+
+#include <boost/asio/ssl/context.hpp>
+
+namespace Battlenet
+{
+ class SslContext
+ {
+ public:
+ static bool Initialize();
+
+ static boost::asio::ssl::context& instance();
+ };
+}
+
+#endif // SslContext_h__