Core/Battle.net: Implemented reconnects

This commit is contained in:
Shauren
2014-06-01 13:56:36 +02:00
parent dc5c5ef636
commit bdd6e9aa8a
8 changed files with 375 additions and 27 deletions
+6 -1
View File
@@ -176,6 +176,7 @@ CREATE TABLE `battlenet_accounts` (
`sha_pass_hash` varchar(64) NOT NULL DEFAULT '',
`v` varchar(256) NOT NULL DEFAULT '',
`s` varchar(64) NOT NULL DEFAULT '',
`sessionKey` varchar(128) NOT NULL DEFAULT '',
`joindate` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
`last_ip` varchar(15) NOT NULL DEFAULT '127.0.0.1',
`failed_logins` int(10) unsigned NOT NULL DEFAULT '0',
@@ -272,7 +273,11 @@ INSERT INTO `battlenet_modules` VALUES
('b37136b39add83cfdbafa81857de3dd8f15b34e0135ec6cd9c3131d3a578d8c2','Thumbprint','auth','Mc64','E716F4F0A01EB9C032A6C1393356A4F766F067949D71023C0CFC0613718966EF814E65CC6EE70C432A7F8AFD8A062B52603A2697E851D231D72C0277614181D713369B1E8E4BEEAB72045A9AAD45F319DB918ECDDB83C8EF8B7510600D391D45E7FEC0BEEAE904A5F9FA620F1CCDAD699D84A4739CE669B5A551831E396214E13B4C88F573F5CDC784CD01530C086B674C03BEB66403A0F87ED17ABBB403DE54CF31BE828A20C566C22E4D4263AA77220B0644D99245345BCAC276EA06925EB984D664725C3CB757140AFE12E27CB996F17159B1057E9B58B78BBB5A139C9FF6215A0D250B75FC9DD435655DDEADCD6CFD84800792C146B3633188ECEB53D2038C185E0BD51A9E6C70FD38ADF530F8DF50FB62053C5E894897AB7DD65C7AC80665F18E7989BE6E30F15E939751123D6D8A44F033175301D15AAAD2AEA06FAC60BA4065846AE938F32B1CB15F16DC0E76792A7332346896048065D17C059899E1D2300E402BD0EA74265DA6A42B1C854E2470D7B21AE4A2DAE90E602A759B2CA0EE610B50D5389DB89335D5451FE76DD85B09FD5297D6F9EFB6C34CE885007F7DF20D6A524E0C3E772FA04B3DD2E014D3A337A790943DAD523CBB5453F4FDF8E74DFE361BD5F25AB31952B478148B570DF5762643F32B994FEC99A747E4A265A66EE84A53509EC285C84679606049314FC526C61B537AC8061C788F8B86F52208'),
('c0f38d05aa1b83065e839c9bd96c831e9f7e42477085138752657a6a9bb9c520','RiskFingerprint','auth','Mac',NULL),
('c3a1ac0694979e709c3b5486927e558af1e2be02ca96e5615c5a65aacc829226','Thumbprint','auth','Wn64','E716F4F0A01EB9C032A6C1393356A4F766F067949D71023C0CFC0613718966EF814E65CC6EE70C432A7F8AFD8A062B52603A2697E851D231D72C0277614181D713369B1E8E4BEEAB72045A9AAD45F319DB918ECDDB83C8EF8B7510600D391D45E7FEC0BEEAE904A5F9FA620F1CCDAD699D84A4739CE669B5A551831E396214E13B4C88F573F5CDC784CD01530C086B674C03BEB66403A0F87ED17ABBB403DE54CF31BE828A20C566C22E4D4263AA77220B0644D99245345BCAC276EA06925EB984D664725C3CB757140AFE12E27CB996F17159B1057E9B58B78BBB5A139C9FF6215A0D250B75FC9DD435655DDEADCD6CFD84800792C146B3633188ECEB53D2038C185E0BD51A9E6C70FD38ADF530F8DF50FB62053C5E894897AB7DD65C7AC80665F18E7989BE6E30F15E939751123D6D8A44F033175301D15AAAD2AEA06FAC60BA4065846AE938F32B1CB15F16DC0E76792A7332346896048065D17C059899E1D2300E402BD0EA74265DA6A42B1C854E2470D7B21AE4A2DAE90E602A759B2CA0EE610B50D5389DB89335D5451FE76DD85B09FD5297D6F9EFB6C34CE885007F7DF20D6A524E0C3E772FA04B3DD2E014D3A337A790943DAD523CBB5453F4FDF8E74DFE361BD5F25AB31952B478148B570DF5762643F32B994FEC99A747E4A265A66EE84A53509EC285C84679606049314FC526C61B537AC8061C788F8B86F52208'),
('fbe675a99fb5f4b7fb3eb5e5a22add91a4cabf83e3c5930c6659ad13c457ba18','Token','auth','Win',NULL);
('fbe675a99fb5f4b7fb3eb5e5a22add91a4cabf83e3c5930c6659ad13c457ba18','Token','auth','Win',NULL),
('bfe4ceb47700aa872e815e007e27df955d4cd4bc1fe731039ee6498ce209f368','Resume','auth','Win',NULL),
('00ffd88a437afbb88d7d4b74be2e3b43601605ee229151aa9f4bebb29ef66280','Resume','auth','Mac',NULL),
('898166926805f897804bdbbf40662c9d768590a51a0b26c40dbcdf332ba11974','Resume','auth','Wn64',NULL),
('304627d437c38500c0b5ca0c6220eeade91390e52a2b005ff3f7754afa1f93cd','Resume','auth','Mc64',NULL);
/*!40000 ALTER TABLE `battlenet_modules` ENABLE KEYS */;
UNLOCK TABLES;
@@ -0,0 +1,8 @@
ALTER TABLE `battlenet_accounts` ADD `sessionKey` VARCHAR(128) NOT NULL DEFAULT '' AFTER `s`;
DELETE FROM `battlenet_modules` WHERE `Name`='Resume';
INSERT INTO `battlenet_modules` VALUES
('bfe4ceb47700aa872e815e007e27df955d4cd4bc1fe731039ee6498ce209f368','Resume','auth','Win',NULL),
('00ffd88a437afbb88d7d4b74be2e3b43601605ee229151aa9f4bebb29ef66280','Resume','auth','Mac',NULL),
('898166926805f897804bdbbf40662c9d768590a51a0b26c40dbcdf332ba11974','Resume','auth','Wn64',NULL),
('304627d437c38500c0b5ca0c6220eeade91390e52a2b005ff3f7754afa1f93cd','Resume','auth','Mc64',NULL);
+131 -18
View File
@@ -57,9 +57,6 @@ void Battlenet::AuthChallenge::Read()
if (_stream.Read<uint32>(1))
Login = _stream.ReadString(9, 3);
if (GetHeader().Opcode == CMSG_AUTH_CHALLENGE_NEW)
_stream.FinishReading();
}
std::string Battlenet::AuthChallenge::ToString() const
@@ -75,6 +72,40 @@ std::string Battlenet::AuthChallenge::ToString() const
return stream.str();
}
void Battlenet::AuthResumeInfo::Read()
{
Program = _stream.ReadFourCC();
Platform = _stream.ReadFourCC();
Locale = _stream.ReadFourCC();
Components.resize(_stream.Read<uint32>(6));
for (size_t i = 0; i < Components.size(); ++i)
{
Component& component = Components[i];
component.Program = _stream.ReadFourCC();
component.Platform = _stream.ReadFourCC();
component.Build = _stream.Read<uint32>(32);
}
Login = _stream.ReadString(9, 3);
Region = _stream.Read<uint8>(8);
GameAccountName = _stream.ReadString(5, 1);
}
std::string Battlenet::AuthResumeInfo::ToString() const
{
std::ostringstream stream;
stream << "Battlenet::AuthReconnect Program: " << Program << ", Platform: " << Platform << ", Locale: " << Locale;
for (Component const& component : Components)
stream << std::endl << "Battlenet::Component Program: " << component.Program << ", Platform: " << component.Platform << ", Build: " << component.Build;
stream << std::endl << "Battlenet::AuthReconnect Login: " << Login;
stream << std::endl << "Battlenet::AuthReconnect Region: " << uint32(Region);
stream << std::endl << "Battlenet::AuthReconnect GameAccountName: " << GameAccountName;
return stream.str();
}
Battlenet::ProofRequest::~ProofRequest()
{
for (size_t i = 0; i < Modules.size(); ++i)
@@ -134,6 +165,12 @@ std::string Battlenet::ProofResponse::ToString() const
return stream.str();
}
Battlenet::AuthComplete::~AuthComplete()
{
for (ModuleInfo* m : Modules)
delete m;
}
void Battlenet::AuthComplete::Write()
{
_stream.Write(Result != 0, 1);
@@ -142,12 +179,12 @@ void Battlenet::AuthComplete::Write()
_stream.Write(Modules.size(), 3);
for (size_t i = 0; i < Modules.size(); ++i)
{
ModuleInfo& info = Modules[i];
_stream.WriteBytes(info.Type.c_str(), 4);
_stream.WriteFourCC(info.Region);
_stream.WriteBytes(info.ModuleId, 32);
_stream.Write(info.DataSize, 10);
_stream.WriteBytes(info.Data, info.DataSize);
ModuleInfo* info = Modules[i];
_stream.WriteBytes(info->Type.c_str(), 4);
_stream.WriteFourCC(info->Region);
_stream.WriteBytes(info->ModuleId, 32);
_stream.Write(info->DataSize, 10);
_stream.WriteBytes(info->Data, info->DataSize);
}
_stream.Write(PingTimeout + std::numeric_limits<int32>::min(), 32);
@@ -168,10 +205,10 @@ void Battlenet::AuthComplete::Write()
_stream.Write(GameAccountId, 32);
_stream.Write(2, 8);
_stream.Write(0, 64);
_stream.Write(2, 8);
_stream.Write(2, 8);
_stream.WriteString(GameAccountName, 5, -1);
_stream.Write(AccountFlags, 64);
_stream.Write(GameAccountFlags, 64);
_stream.Write(0, 32);
}
@@ -180,12 +217,10 @@ void Battlenet::AuthComplete::Write()
_stream.Write(!Modules.empty(), 1);
if (!Modules.empty())
{
ModuleInfo& info = Modules[0];
_stream.WriteBytes(info.Type.c_str(), 4);
_stream.WriteFourCC(info.Region);
_stream.WriteBytes(info.ModuleId, 32);
_stream.Write(info.DataSize, 10);
_stream.WriteBytes(info.Data, info.DataSize);
ModuleInfo* info = Modules[0];
_stream.WriteBytes(info->Type.c_str(), 4);
_stream.WriteFourCC(info->Region);
_stream.WriteBytes(info->ModuleId, 32);
}
_stream.Write(ErrorType, 2);
@@ -199,7 +234,15 @@ void Battlenet::AuthComplete::Write()
std::string Battlenet::AuthComplete::ToString() const
{
return "Battlenet::AuthComplete";
std::ostringstream stream;
stream << "Battlenet::AuthComplete AuthResult " << Result << " PingTimeout " << PingTimeout << " Threshold " << Threshold << " Rate " << Rate
<< " FirstName " << FirstName << " LastName " << LastName << " GameAccountId " << GameAccountId << " GameAccountName " << GameAccountName
<< " GameAccountFlags " << GameAccountFlags << " Modules " << Modules.size();
for (ModuleInfo const* module : Modules)
stream << std::endl << "Battlenet::ModuleInfo Locale " << module->Region.c_str() << ", ModuleId " << ByteArrayToHexStr(module->ModuleId, 32) << ", DataSize " << module->DataSize << ", Data " << ByteArrayToHexStr(module->Data, module->DataSize);
return stream.str();
}
void Battlenet::AuthComplete::SetAuthResult(AuthResult result)
@@ -208,6 +251,76 @@ void Battlenet::AuthComplete::SetAuthResult(AuthResult result)
Result = result;
}
Battlenet::AuthResume::~AuthResume()
{
for (ModuleInfo* m : Modules)
delete m;
}
void Battlenet::AuthResume::Write()
{
_stream.Write(Result != 0, 1);
if (Result == 0)
{
_stream.Write(Modules.size(), 3);
for (size_t i = 0; i < Modules.size(); ++i)
{
ModuleInfo* info = Modules[i];
_stream.WriteBytes(info->Type.c_str(), 4);
_stream.WriteFourCC(info->Region);
_stream.WriteBytes(info->ModuleId, 32);
_stream.Write(info->DataSize, 10);
_stream.WriteBytes(info->Data, info->DataSize);
}
_stream.Write(PingTimeout + std::numeric_limits<int32>::min(), 32);
_stream.Write(1, 1);
// if written == 1
{
_stream.Write(1, 1);
// if written == 1
{
_stream.Write(Threshold, 32);
_stream.Write(Rate, 32);
}
}
}
else
{
_stream.Write(!Modules.empty(), 1);
if (!Modules.empty())
{
ModuleInfo* info = Modules[0];
_stream.WriteBytes(info->Type.c_str(), 4);
_stream.WriteFourCC(info->Region);
_stream.WriteBytes(info->ModuleId, 32);
}
_stream.Write(ErrorType, 2);
if (ErrorType == 1)
{
_stream.Write(Result, 16);
_stream.Write(0x80000000, 32);
}
}
}
std::string Battlenet::AuthResume::ToString() const
{
std::ostringstream stream;
stream << "Battlenet::AuthResume AuthResult " << Result << " PingTimeout " << PingTimeout << " Threshold " << Threshold << " Rate " << Rate << " Modules " << Modules.size();
for (ModuleInfo const* module : Modules)
stream << std::endl << "Battlenet::ModuleInfo Locale " << module->Region.c_str() << ", ModuleId " << ByteArrayToHexStr(module->ModuleId, 32) << ", DataSize " << module->DataSize << ", Data " << ByteArrayToHexStr(module->Data, module->DataSize);
return stream.str();
}
void Battlenet::AuthResume::SetAuthResult(AuthResult result)
{
ErrorType = result != AUTH_OK ? 1 : 0;
Result = result;
}
Battlenet::RealmCharacterCounts::~RealmCharacterCounts()
{
for (ServerPacket* realmData : RealmData)
@@ -41,9 +41,9 @@ namespace Battlenet
CMSG_AUTH_CHALLENGE = 0x0,
CMSG_AUTH_RECONNECT = 0x1,
CMSG_AUTH_PROOF_RESPONSE = 0x2,
CMSG_AUTH_CHALLENGE_NEW = 0x9, // MoP
SMSG_AUTH_COMPLETE = 0x0,
SMSG_AUTH_RESUME = 0x1,
SMSG_AUTH_PROOF_REQUEST = 0x2
};
@@ -51,6 +51,7 @@ namespace Battlenet
{
CMSG_PING = 0x0,
CMSG_ENABLE_ENCRYPTION = 0x5,
CMSG_DISCONNECT = 0x6,
CMSG_INVALID_PACKET = 0x9,
SMSG_PONG = 0x0
@@ -141,7 +142,7 @@ namespace Battlenet
public:
AuthChallenge(PacketHeader const& header, BitStream& stream) : ClientPacket(header, stream)
{
ASSERT(header.Channel == AUTHENTICATION && (header.Opcode == CMSG_AUTH_CHALLENGE || header.Opcode == CMSG_AUTH_CHALLENGE_NEW) && "Invalid packet header for AuthChallenge");
ASSERT(header == PacketHeader(CMSG_AUTH_CHALLENGE, AUTHENTICATION) && "Invalid packet header for AuthChallenge");
}
void Read() override;
@@ -154,6 +155,26 @@ namespace Battlenet
std::string Login;
};
class AuthResumeInfo final : public ClientPacket
{
public:
AuthResumeInfo(PacketHeader const& header, BitStream& stream) : ClientPacket(header, stream)
{
ASSERT(header == PacketHeader(CMSG_AUTH_RECONNECT, AUTHENTICATION) && "Invalid packet header for AuthResumeInfo");
}
void Read() override;
std::string ToString() const override;
std::string Program;
std::string Platform;
std::string Locale;
std::vector<Component> Components;
std::string Login;
uint8 Region;
std::string GameAccountName;
};
class ProofRequest final : public ServerPacket
{
public:
@@ -191,10 +212,12 @@ namespace Battlenet
{
}
~AuthComplete();
void Write() override;
std::string ToString() const override;
std::vector<ModuleInfo> Modules;
std::vector<ModuleInfo*> Modules;
void SetAuthResult(AuthResult result);
AuthResult Result;
uint32 ErrorType;
@@ -206,7 +229,30 @@ namespace Battlenet
std::string LastName;
uint32 GameAccountId;
std::string GameAccountName;
uint64 AccountFlags;
uint64 GameAccountFlags;
};
class AuthResume final : public ServerPacket
{
public:
AuthResume() : ServerPacket(PacketHeader(SMSG_AUTH_RESUME, AUTHENTICATION)),
Result(AUTH_OK), ErrorType(0), PingTimeout(120000), Threshold(25000000), Rate(1000)
{
}
~AuthResume();
void Write() override;
std::string ToString() const override;
std::vector<ModuleInfo*> Modules;
void SetAuthResult(AuthResult result);
AuthResult Result;
uint32 ErrorType;
int32 PingTimeout;
uint32 Threshold;
uint32 Rate;
};
class Pong final : public ServerPacket
@@ -33,11 +33,12 @@ std::map<Battlenet::PacketHeader, Battlenet::Socket::PacketHandler> InitHandlers
std::map<Battlenet::PacketHeader, Battlenet::Socket::PacketHandler> handlers;
handlers[Battlenet::PacketHeader(Battlenet::CMSG_AUTH_CHALLENGE, Battlenet::AUTHENTICATION)] = &Battlenet::Socket::HandleAuthChallenge;
handlers[Battlenet::PacketHeader(Battlenet::CMSG_AUTH_CHALLENGE_NEW, Battlenet::AUTHENTICATION)] = &Battlenet::Socket::HandleAuthChallenge;
handlers[Battlenet::PacketHeader(Battlenet::CMSG_AUTH_RECONNECT, Battlenet::AUTHENTICATION)] = &Battlenet::Socket::HandleAuthReconnect;
handlers[Battlenet::PacketHeader(Battlenet::CMSG_AUTH_PROOF_RESPONSE, Battlenet::AUTHENTICATION)] = &Battlenet::Socket::HandleAuthProofResponse;
handlers[Battlenet::PacketHeader(Battlenet::CMSG_PING, Battlenet::CREEP)] = &Battlenet::Socket::HandlePing;
handlers[Battlenet::PacketHeader(Battlenet::CMSG_ENABLE_ENCRYPTION, Battlenet::CREEP)] = &Battlenet::Socket::HandleEnableEncryption;
handlers[Battlenet::PacketHeader(Battlenet::CMSG_DISCONNECT, Battlenet::CREEP)] = &Battlenet::Socket::HandleDisconnect;
handlers[Battlenet::PacketHeader(Battlenet::CMSG_REALM_UPDATE_SUBSCRIBE, Battlenet::WOW)] = &Battlenet::Socket::HandleRealmUpdateSubscribe;
handlers[Battlenet::PacketHeader(Battlenet::CMSG_JOIN_REQUEST, Battlenet::WOW)] = &Battlenet::Socket::HandleRealmJoinRequest;
@@ -54,10 +55,12 @@ Battlenet::Socket::ModuleHandler const Battlenet::Socket::ModuleHandlers[MODULE_
&Battlenet::Socket::UnhandledModule,
&Battlenet::Socket::HandleSelectGameAccountModule,
&Battlenet::Socket::HandleRiskFingerprintModule,
&Battlenet::Socket::HandleResumeModule,
};
Battlenet::Socket::Socket(RealmSocket& socket) : _socket(socket), _accountId(0), _accountName(), _locale(),
_os(), _build(0), _gameAccountId(0), _accountSecurityLevel(SEC_PLAYER)
_os(), _build(0), _gameAccountId(0), _accountSecurityLevel(SEC_PLAYER), I(), s(), v(), b(), B(), K(),
_reconnectProof(), _crypt(), _authed(false)
{
static uint8 const N_Bytes[] =
{
@@ -304,6 +307,61 @@ bool Battlenet::Socket::HandleAuthChallenge(PacketHeader& header, BitStream& pac
return true;
}
bool Battlenet::Socket::HandleAuthReconnect(PacketHeader& header, BitStream& packet)
{
AuthResumeInfo reconnect(header, packet);
reconnect.Read();
TC_LOG_DEBUG("server.battlenet", "%s", reconnect.ToString().c_str());
_accountName = reconnect.Login;
_locale = reconnect.Locale;
_os = reconnect.Platform;
auto baseComponent = std::find_if(reconnect.Components.begin(), reconnect.Components.end(), [](Component const& c) { return c.Program == "base"; });
if (baseComponent != reconnect.Components.end())
_build = baseComponent->Build;
Utf8ToUpperOnlyLatin(_accountName);
PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_BNET_RECONNECT_INFO);
stmt->setString(0, _accountName);
stmt->setString(1, reconnect.GameAccountName.c_str());
PreparedQueryResult result = LoginDatabase.Query(stmt);
if (!result)
{
AuthResume resume;
resume.SetAuthResult(AUTH_UNKNOWN_ACCOUNT);
Send(resume);
return false;
}
Field* fields = result->Fetch();
_accountId = fields[0].GetUInt32();
K.SetHexStr(fields[1].GetString().c_str());
_gameAccountId = fields[2].GetUInt32();
ModuleInfo* thumbprint = sBattlenetMgr->CreateModule(_os, "Thumbprint");
ModuleInfo* resume = sBattlenetMgr->CreateModule(_os, "Resume");
BitStream resumeData;
uint8 state = 0;
_reconnectProof.SetRand(16 * 8);
resumeData.WriteBytes(&state, 1);
resumeData.WriteBytes(_reconnectProof.AsByteArray().get(), 16);
resume->DataSize = resumeData.GetSize();
resume->Data = new uint8[resume->DataSize];
memcpy(resume->Data, resumeData.GetBuffer(), resume->DataSize);
_modulesWaitingForData.push(MODULE_RESUME);
ProofRequest request;
request.Modules.push_back(thumbprint);
request.Modules.push_back(resume);
Send(request);
return true;
}
bool Battlenet::Socket::HandleAuthProofResponse(PacketHeader& header, BitStream& packet)
{
ProofResponse proof(header, packet);
@@ -350,6 +408,15 @@ bool Battlenet::Socket::HandleEnableEncryption(PacketHeader& /*header*/, BitStre
return true;
}
bool Battlenet::Socket::HandleDisconnect(PacketHeader& /*header*/, BitStream& /*packet*/)
{
PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_BNET_SESSION_KEY);
stmt->setString(0, "");
stmt->setUInt32(1, _accountId);
LoginDatabase.Execute(stmt);
return true;
}
bool Battlenet::Socket::HandleRealmUpdateSubscribe(PacketHeader& /*header*/, BitStream& /*packet*/)
{
sRealmList->UpdateIfNeed();
@@ -484,6 +551,13 @@ void Battlenet::Socket::OnRead()
if (packet.Read<bool>(1))
header.Channel = packet.Read<int32>(4);
if (header.Channel != AUTHENTICATION && !_authed)
{
TC_LOG_DEBUG("server.battlenet", "Battlenet::Socket::OnRead Received not allowed packet %s", header.ToString().c_str());
_socket.shutdown();
return;
}
TC_LOG_TRACE("server.battlenet", "Battlenet::Socket::OnRead %s", header.ToString().c_str());
std::map<PacketHeader, PacketHandler>::const_iterator itr = Handlers.find(header);
if (itr != Handlers.end())
@@ -796,14 +870,25 @@ bool Battlenet::Socket::HandleRiskFingerprintModule(BitStream* dataStream, Serve
complete->GameAccountId = _gameAccountId;
complete->GameAccountName = str.str();
complete->AccountFlags = 0x800000; // 0x1 IsGMAccount, 0x8 IsTrialAccount, 0x800000 IsProPassAccount
complete->GameAccountFlags = 1;
SQLTransaction trans = LoginDatabase.BeginTransaction();
PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_BNET_LAST_LOGIN_INFO);
stmt->setString(0, _socket.getRemoteAddress());
stmt->setUInt8(1, GetLocaleByName(_locale));
stmt->setString(2, _os);
stmt->setUInt32(3, _accountId);
LoginDatabase.Execute(stmt);
trans->Append(stmt);
stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_BNET_SESSION_KEY);
stmt->setString(0, K.AsHexStr());
stmt->setUInt32(1, _accountId);
trans->Append(stmt);
LoginDatabase.CommitTransaction(trans);
_authed = true;
}
else
complete->SetAuthResult(AUTH_BAD_VERSION_HASH);
@@ -812,6 +897,86 @@ bool Battlenet::Socket::HandleRiskFingerprintModule(BitStream* dataStream, Serve
return true;
}
bool Battlenet::Socket::HandleResumeModule(BitStream* dataStream, ServerPacket** response)
{
if (dataStream->Read<uint8>(8) != 1)
{
AuthResume* complete = new AuthResume();
complete->SetAuthResult(AUTH_CORRUPTED_MODULE);
ReplaceResponse(response, complete);
return false;
}
static uint8 const ResumeClient = 0;
static uint8 const ResumeServer = 1;
ACE_Auto_Array_Ptr<uint8>&& clientChallenge = dataStream->ReadBytes(16);
ACE_Auto_Array_Ptr<uint8>&& clientProof = dataStream->ReadBytes(32);
ACE_Auto_Array_Ptr<uint8>&& serverChallenge = _reconnectProof.AsByteArray();
ACE_Auto_Array_Ptr<uint8>&& sessionKey = K.AsByteArray();
HmacHash clientPart(64, sessionKey.get(), EVP_sha256(), SHA256_DIGEST_LENGTH);
clientPart.UpdateData(&ResumeClient, 1);
clientPart.UpdateData(clientChallenge.get(), 16);
clientPart.UpdateData(serverChallenge.get(), 16);
clientPart.Finalize();
HmacHash serverPart(64, sessionKey.get(), EVP_sha256(), SHA256_DIGEST_LENGTH);
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);
HmacHash proof(64, newSessionKey, EVP_sha256(), SHA256_DIGEST_LENGTH);
proof.UpdateData(&ResumeClient, 1);
proof.UpdateData(clientChallenge.get(), 16);
proof.UpdateData(serverChallenge.get(), 16);
proof.Finalize();
if (memcmp(proof.GetDigest(), clientProof.get(), serverPart.GetLength()))
{
TC_LOG_DEBUG("server.battlenet", "[Battlenet::Resume] Invalid proof!");
AuthResume* result = new AuthResume();
result->SetAuthResult(AUTH_UNKNOWN_ACCOUNT);
ReplaceResponse(response, result);
return false;
}
PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_BNET_SESSION_KEY);
stmt->setString(0, K.AsHexStr());
stmt->setUInt32(1, _accountId);
LoginDatabase.Execute(stmt);
HmacHash serverProof(64, newSessionKey, EVP_sha256(), SHA256_DIGEST_LENGTH);
serverProof.UpdateData(&ResumeServer, 1);
serverProof.UpdateData(serverChallenge.get(), 16);
serverProof.UpdateData(clientChallenge.get(), 16);
serverProof.Finalize();
ModuleInfo* resume = sBattlenetMgr->CreateModule(_os, "Resume");
BitStream resumeData;
uint8 state = 2;
resumeData.WriteBytes(&state, 1);
resumeData.WriteBytes(serverProof.GetDigest(), serverProof.GetLength());
resume->DataSize = resumeData.GetSize();
resume->Data = new uint8[resume->DataSize];
memcpy(resume->Data, resumeData.GetBuffer(), resume->DataSize);
AuthResume* result = new AuthResume();
result->Modules.push_back(resume);
ReplaceResponse(response, result);
_authed = true;
return true;
}
bool Battlenet::Socket::UnhandledModule(BitStream* /*dataStream*/, ServerPacket** response)
{
AuthComplete* complete = new AuthComplete();
@@ -37,6 +37,7 @@ namespace Battlenet
MODULE_THUMBPRINT,
MODULE_SELECT_GAME_ACCOUNT,
MODULE_RISK_FINGERPRINT,
MODULE_RESUME,
MODULE_COUNT
};
@@ -53,11 +54,13 @@ namespace Battlenet
// Auth
bool HandleAuthChallenge(PacketHeader& header, BitStream& packet);
bool HandleAuthReconnect(PacketHeader& header, BitStream& packet);
bool HandleAuthProofResponse(PacketHeader& header, BitStream& packet);
// Creep
bool HandlePing(PacketHeader& header, BitStream& packet);
bool HandleEnableEncryption(PacketHeader& header, BitStream& packet);
bool HandleDisconnect(PacketHeader& header, BitStream& packet);
// WoW
bool HandleRealmUpdateSubscribe(PacketHeader& header, BitStream& packet);
@@ -78,6 +81,7 @@ namespace Battlenet
bool HandlePasswordModule(BitStream* dataStream, ServerPacket** response);
bool HandleSelectGameAccountModule(BitStream* dataStream, ServerPacket** response);
bool HandleRiskFingerprintModule(BitStream* dataStream, ServerPacket** response);
bool HandleResumeModule(BitStream* dataStream, ServerPacket** response);
bool UnhandledModule(BitStream* dataStream, ServerPacket** response);
RealmSocket& _socket;
@@ -102,9 +106,12 @@ namespace Battlenet
BigNumber B;
BigNumber K; // session key
BigNumber _reconnectProof;
std::queue<ModuleType> _modulesWaitingForData;
PacketCrypt _crypt;
bool _authed;
};
}
@@ -107,6 +107,8 @@ void LoginDatabaseConnection::DoPrepareStatements()
PrepareStatement(LOGIN_DEL_BNET_EXPIRED_BANS, "UPDATE battlenet_account_bans SET active = 0 WHERE active = 1 AND unbandate <> bandate AND unbandate <= UNIX_TIMESTAMP()", CONNECTION_SYNCH);
PrepareStatement(LOGIN_SEL_BNET_ACTIVE_ACCOUNT_BAN, "SELECT bandate, unbandate FROM battlenet_account_bans WHERE id = ? AND active = 1", CONNECTION_SYNCH);
PrepareStatement(LOGIN_UPD_BNET_VS_FIELDS, "UPDATE battlenet_accounts SET v = ?, s = ? WHERE email = ?", CONNECTION_ASYNC);
PrepareStatement(LOGIN_UPD_BNET_SESSION_KEY, "UPDATE battlenet_accounts SET sessionKey = ? WHERE id = ?", CONNECTION_ASYNC);
PrepareStatement(LOGIN_SEL_BNET_RECONNECT_INFO, "SELECT ba.id, ba.sessionKey, a.id FROM battlenet_accounts ba LEFT JOIN account a ON ba.id = a.battlenet_account WHERE ba.email = ? AND a.id = SUBSTRING_INDEX(?, '#', 1)", CONNECTION_SYNCH);
PrepareStatement(LOGIN_SEL_BNET_GAME_ACCOUNTS, "SELECT a.username, a.id, ab.bandate, ab.unbandate, ab.active FROM account a LEFT JOIN account_banned ab ON a.id = ab.id WHERE battlenet_account = ?", CONNECTION_SYNCH);
PrepareStatement(LOGIN_SEL_BNET_GAME_ACCOUNT, "SELECT a.id, ab.bandate, ab.unbandate, ab.active FROM account a LEFT JOIN account_banned ab ON a.id = ab.id WHERE username = ? AND battlenet_account = ?", CONNECTION_SYNCH);
PrepareStatement(LOGIN_UPD_BNET_LAST_LOGIN_INFO, "UPDATE battlenet_accounts SET last_ip = ?, last_login = NOW(), locale = ?, failed_logins = 0, os = ? WHERE id = ?", CONNECTION_ASYNC);
@@ -126,6 +126,8 @@ enum LoginDatabaseStatements
LOGIN_DEL_BNET_EXPIRED_BANS,
LOGIN_SEL_BNET_ACTIVE_ACCOUNT_BAN,
LOGIN_UPD_BNET_VS_FIELDS,
LOGIN_UPD_BNET_SESSION_KEY,
LOGIN_SEL_BNET_RECONNECT_INFO,
LOGIN_SEL_BNET_GAME_ACCOUNTS,
LOGIN_SEL_BNET_GAME_ACCOUNT,
LOGIN_UPD_BNET_LAST_LOGIN_INFO,