diff options
Diffstat (limited to 'src/server/authserver/Server/BattlenetSocket.cpp')
-rw-r--r-- | src/server/authserver/Server/BattlenetSocket.cpp | 173 |
1 files changed, 169 insertions, 4 deletions
diff --git a/src/server/authserver/Server/BattlenetSocket.cpp b/src/server/authserver/Server/BattlenetSocket.cpp index 258ae371075..119fccd9abb 100644 --- a/src/server/authserver/Server/BattlenetSocket.cpp +++ b/src/server/authserver/Server/BattlenetSocket.cpp @@ -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(); |