From a142eb9f7a9683f98fe1e9153f6958f80d374c9d Mon Sep 17 00:00:00 2001 From: Shauren Date: Wed, 30 Apr 2014 20:16:08 +0200 Subject: Core/Auth: Battle.net stuff --- src/server/authserver/Authentication/AuthCodes.h | 51 ++++++ src/server/authserver/Main.cpp | 26 ++- src/server/authserver/Server/BattlenetBitStream.h | 189 +++++++++++++++++++ .../authserver/Server/BattlenetPacketCrypt.cpp | 39 ++++ .../authserver/Server/BattlenetPacketCrypt.h | 36 ++++ src/server/authserver/Server/BattlenetPackets.cpp | 170 +++++++++++++++++ src/server/authserver/Server/BattlenetPackets.h | 202 +++++++++++++++++++++ src/server/authserver/Server/BattlenetSocket.cpp | 124 +++++++++++++ src/server/authserver/Server/BattlenetSocket.h | 54 ++++++ src/server/authserver/Server/RealmAcceptor.h | 4 +- src/server/game/Server/WorldSocket.h | 4 +- src/server/game/Warden/WardenWin.cpp | 4 +- .../Cryptography/Authentication/AuthCrypt.cpp | 73 -------- .../shared/Cryptography/Authentication/AuthCrypt.h | 42 ----- .../Cryptography/Authentication/PacketCrypt.cpp | 39 ++++ .../Cryptography/Authentication/PacketCrypt.h | 43 +++++ .../Authentication/WorldPacketCrypt.cpp | 51 ++++++ .../Cryptography/Authentication/WorldPacketCrypt.h | 34 ++++ src/server/shared/Cryptography/HMACSHA1.cpp | 57 ------ src/server/shared/Cryptography/HMACSHA1.h | 47 ----- src/server/shared/Cryptography/HmacHash.cpp | 59 ++++++ src/server/shared/Cryptography/HmacHash.h | 48 +++++ 22 files changed, 1163 insertions(+), 233 deletions(-) create mode 100644 src/server/authserver/Server/BattlenetBitStream.h create mode 100644 src/server/authserver/Server/BattlenetPacketCrypt.cpp create mode 100644 src/server/authserver/Server/BattlenetPacketCrypt.h create mode 100644 src/server/authserver/Server/BattlenetPackets.cpp create mode 100644 src/server/authserver/Server/BattlenetPackets.h create mode 100644 src/server/authserver/Server/BattlenetSocket.cpp create mode 100644 src/server/authserver/Server/BattlenetSocket.h delete mode 100644 src/server/shared/Cryptography/Authentication/AuthCrypt.cpp delete mode 100644 src/server/shared/Cryptography/Authentication/AuthCrypt.h create mode 100644 src/server/shared/Cryptography/Authentication/PacketCrypt.cpp create mode 100644 src/server/shared/Cryptography/Authentication/PacketCrypt.h create mode 100644 src/server/shared/Cryptography/Authentication/WorldPacketCrypt.cpp create mode 100644 src/server/shared/Cryptography/Authentication/WorldPacketCrypt.h delete mode 100644 src/server/shared/Cryptography/HMACSHA1.cpp delete mode 100644 src/server/shared/Cryptography/HMACSHA1.h create mode 100644 src/server/shared/Cryptography/HmacHash.cpp create mode 100644 src/server/shared/Cryptography/HmacHash.h (limited to 'src') diff --git a/src/server/authserver/Authentication/AuthCodes.h b/src/server/authserver/Authentication/AuthCodes.h index 5e6522f8981..e844863e4b1 100644 --- a/src/server/authserver/Authentication/AuthCodes.h +++ b/src/server/authserver/Authentication/AuthCodes.h @@ -70,6 +70,57 @@ enum LoginResult LOGIN_LOCKED_ENFORCED = 0x10 }; +namespace Battlenet +{ + enum AuthResult + { + AUTH_OK = 0, + AUTH_BAD_SERVER_PROOF = 103, + AUTH_UNKNOWN_ACCOUNT = 104, + AUTH_CLOSED = 105, + AUTH_LOGIN_TIMEOUT = 106, + AUTH_NO_GAME_ACCOUNTS = 107, + AUTH_INVALID_TOKEN = 108, + AUTH_INVALID_PROGRAM = 109, + AUTH_INVALID_OS = 110, + AUTH_UNSUPPORTED_LANGUAGE = 111, + AUTH_REGION_BAD_VERSION = 112, + AUTH_TEMP_OUTAGE = 113, + AUTH_CANT_DOWNLOAD_MODULE = 114, + AUTH_DUPLICATE_LOGON = 115, + AUTH_BAD_CREDENTIALS_2 = 116, + AUTH_VERSION_CHECK_SUCCEEDED = 117, + AUTH_BAD_VERSION_HASH = 118, + AUTH_CANT_RETRIEVE_PORTAL_LIST = 119, + AUTH_DARK_PORTAL_DOES_NOT_EXIST = 120, + AUTH_DARK_PORTAL_FILE_CORRUPTED = 121, + AUTH_BATTLENET_MAINTENANCE = 122, + AUTH_LOGON_TOO_FAST = 123, + AUTH_USE_GRUNT_LOGON = 124, + + LOGIN_NO_GAME_ACCOUNT = 201, + LOGIN_BANNED = 202, + LOGIN_SUSPENDED = 203, + LOGIN_GAME_ACCOUNT_LOCKED = 204, + LOGIN_ALREADY_ONLINE = 205, + LOGIN_NOTIME = 206, + LOGIN_EXPIRED = 207, + LOGIN_EXPIRED_2 = 208, + LOGIN_PARENTALCONTROL = 209, + LOGIN_TRIAL_EXPIRED = 210, + LOGIN_ANTI_INDULGENCE = 211, + LOGIN_INCORRECT_REGION = 212, + LOGIN_CHARGEBACK = 213, + LOGIN_IGR_WITHOUT_BNET = 214, + LOGIN_LOCKED_ENFORCED = 215, + LOGIN_UNLOCKABLE_LOCK = 216, + LOGIN_IGR_REQUIRED = 217, + LOGIN_PAYMENT_CHANGED = 218, + LOGIN_INVALID_PAYMENT = 219, + LOGIN_INVALID_ACCOUNT_STATE = 220 + }; +} + enum ExpansionFlags { POST_BC_EXP_FLAG = 0x2, diff --git a/src/server/authserver/Main.cpp b/src/server/authserver/Main.cpp index d1b2b614037..0e23dd99ba8 100644 --- a/src/server/authserver/Main.cpp +++ b/src/server/authserver/Main.cpp @@ -151,7 +151,8 @@ extern int main(int argc, char** argv) } // Launch the listening network socket - RealmAcceptor acceptor; + RealmAcceptor acceptor; + RealmAcceptor bnetacceptor; int32 rmport = sConfigMgr->GetIntDefault("RealmServerPort", 3724); if (rmport < 0 || rmport > 0xFFFF) @@ -170,6 +171,13 @@ extern int main(int argc, char** argv) return 1; } + bind_addr.set_port_number(1119); + if (bnetacceptor.open(bind_addr, ACE_Reactor::instance(), ACE_NONBLOCK) == -1) + { + TC_LOG_ERROR("server.authserver", "Auth server can not bind to %s:%d", bind_ip.c_str(), 1119); + return 1; + } + // Initialize the signal handlers AuthServerSignalHandler SignalINT, SignalTERM; @@ -179,24 +187,24 @@ extern int main(int argc, char** argv) Handler.register_handler(SIGTERM, &SignalTERM); #if defined(_WIN32) || defined(__linux__) - + ///- Handle affinity for multiple processors and process priority uint32 affinity = sConfigMgr->GetIntDefault("UseProcessors", 0); bool highPriority = sConfigMgr->GetBoolDefault("ProcessPriority", false); #ifdef _WIN32 // Windows - + HANDLE hProcess = GetCurrentProcess(); if (affinity > 0) { ULONG_PTR appAff; ULONG_PTR sysAff; - + if (GetProcessAffinityMask(hProcess, &appAff, &sysAff)) { // remove non accessible processors ULONG_PTR currentAffinity = affinity & appAff; - + if (!currentAffinity) TC_LOG_ERROR("server.authserver", "Processors marked in UseProcessors bitmask (hex) %x are not accessible for the authserver. Accessible processors bitmask (hex): %x", affinity, appAff); else if (SetProcessAffinityMask(hProcess, currentAffinity)) @@ -205,7 +213,7 @@ extern int main(int argc, char** argv) TC_LOG_ERROR("server.authserver", "Can't set used processors (hex): %x", currentAffinity); } } - + if (highPriority) { if (SetPriorityClass(hProcess, HIGH_PRIORITY_CLASS)) @@ -213,9 +221,9 @@ extern int main(int argc, char** argv) else TC_LOG_ERROR("server.authserver", "Can't set authserver process priority class."); } - + #else // Linux - + if (affinity > 0) { cpu_set_t mask; @@ -242,7 +250,7 @@ extern int main(int argc, char** argv) else TC_LOG_INFO("server.authserver", "authserver process priority class set to %i", getpriority(PRIO_PROCESS, 0)); } - + #endif #endif diff --git a/src/server/authserver/Server/BattlenetBitStream.h b/src/server/authserver/Server/BattlenetBitStream.h new file mode 100644 index 00000000000..fa09b24b204 --- /dev/null +++ b/src/server/authserver/Server/BattlenetBitStream.h @@ -0,0 +1,189 @@ +/* + * Copyright (C) 2008-2014 TrinityCore + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ + +#ifndef __BATTLENETBITSTREAM_H__ +#define __BATTLENETBITSTREAM_H__ + +#include "ByteConverter.h" +#include +#include +#include + +namespace Battlenet +{ + class BitStreamPositionException : public std::exception + { + public: + char const* what() const + { + return ""; + } + }; + + class BitStream + { + public: + static uint32 const MaxSize = 0x1000; + + // length : The maximum number of bytes to read + BitStream(uint32 length) : _numBits(length * 8), _readPos(0), _writePos(0) + { + _buffer.resize(length, 0); + } + + BitStream() : _numBits(0), _readPos(0), _writePos(0) + { + _buffer.reserve(0x1000); + } + + void AlignToNextByte() + { + _readPos = (_readPos + 7) & ~7; + _writePos = (_writePos + 7) & ~7; + } + + std::string ReadString(uint32 bitCount, uint32 baseLength = 0) + { + uint32 len = Read(bitCount) + baseLength; + AlignToNextByte(); + std::string str(reinterpret_cast(&_buffer[_readPos >> 3]), len); + _readPos += len * 8; + return str; + } + + uint8* ReadBytes(uint32 count) + { + AlignToNextByte(); + if (_readPos + count * 8 > _numBits) + throw BitStreamPositionException(); + + uint8* buf = new uint8[count]; + memcpy(buf, &_buffer[_readPos >> 3], count); + _readPos += count * 8; + return buf; + } + + float ReadFloat() + { + uint32 val = Read(32); + return *reinterpret_cast(&val); + } + + std::string ReadFourCC() + { + uint32 fcc = Read(32); + EndianConvertReverse(fcc); + size_t len = 4; + while (!(fcc & 0xFF)) + { + fcc >>= 8; + --len; + } + + return std::string(reinterpret_cast(&fcc), len); + } + + template + T Read(uint32 bitCount) + { + T ret = 0; + while (bitCount != 0) + { + uint32 bitPos = (_readPos & 7); + uint32 bitsLeftInByte = 8 - bitPos; + if (bitsLeftInByte >= bitCount) + bitsLeftInByte = bitCount; + + bitCount -= bitsLeftInByte; + ret |= static_cast((uint64)(_buffer[_readPos >> 3] >> bitPos & (uint32)((uint8)(1 << bitsLeftInByte) - 1)) << bitCount); + _readPos += bitsLeftInByte; + } + return ret; + } + + //WriteString + + template + void WriteBytes(T* data, uint32 count) + { + AlignToNextByte(); + if (_writePos + 8 * count > MaxSize) + throw BitStreamPositionException(); + + _buffer.resize(_buffer.size() + count); + memcpy(&_buffer[_writePos >> 3], data, count); + _writePos += count * 8; + } + + //WriteFloat + void WriteFourCC(char const* fcc) + { + uint32 intVal = *(uint32*)fcc; + EndianConvertReverse(intVal); + Write(intVal, 32); + } + + template + void Write(T value, uint32 bitCount) + { + if (_writePos + bitCount >= 8 * MaxSize) + throw BitStreamPositionException(); + + while (bitCount != 0) + { + uint32 bitPos = (_writePos & 7); + uint32 bitsLeftInByte = 8 - bitPos; + if (bitsLeftInByte >= bitCount) + bitsLeftInByte = bitCount; + + bitCount -= bitsLeftInByte; + + uint8 firstHalf = (uint8)(~(((uint8)(1 << bitsLeftInByte) - 1) << bitPos)); + uint8 secondHalf = (uint8)((((uint8)(1 << bitsLeftInByte) - 1) & (uint8)(value >> bitCount)) << bitPos); + + if (_buffer.size() > (_writePos >> 3)) + _buffer[_writePos >> 3] = (uint8)(_buffer[_writePos >> 3] & firstHalf | secondHalf); + else + _buffer.push_back(secondHalf); + + _writePos += bitsLeftInByte; + } + } + + void SetReadPos(uint32 bits) + { + if (bits >= _numBits) + throw BitStreamPositionException(); + + _readPos = bits; + } + + bool IsRead() const { return _readPos >= _numBits; } + + uint8* GetBuffer() { return _buffer.data(); } + + size_t GetSize() const { return _buffer.size(); } + + private: + std::vector _buffer; + uint32 _numBits; + uint32 _readPos; + uint32 _writePos; + }; +} + +#endif // __BATTLENETBITSTREAM_H__ diff --git a/src/server/authserver/Server/BattlenetPacketCrypt.cpp b/src/server/authserver/Server/BattlenetPacketCrypt.cpp new file mode 100644 index 00000000000..10aa684e10a --- /dev/null +++ b/src/server/authserver/Server/BattlenetPacketCrypt.cpp @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2008-2014 TrinityCore + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ + +#include "BattlenetPacketCrypt.h" +#include "Cryptography/HmacHash.h" +#include "Cryptography/BigNumber.h" + +Battlenet::PacketCrypt::PacketCrypt() : ::PacketCrypt(SHA256_DIGEST_LENGTH) +{ +} + +void Battlenet::PacketCrypt::Init(BigNumber* K) +{ + uint8 ServerEncryptionKey[SEED_KEY_SIZE] = { 0x68, 0xE0, 0xC7, 0x2E, 0xDD, 0xD6, 0xD2, 0xF3, 0x1E, 0x5A, 0xB1, 0x55, 0xB1, 0x8B, 0x63, 0x1E }; + HmacHash serverEncryptHmac(SEED_KEY_SIZE, ServerEncryptionKey, EVP_sha256(), SHA256_DIGEST_LENGTH); + uint8 *encryptHash = serverEncryptHmac.ComputeHash(K); + + uint8 ClientDecryptionKey[SEED_KEY_SIZE] = { 0xDE, 0xA9, 0x65, 0xAE, 0x54, 0x3A, 0x1E, 0x93, 0x9E, 0x69, 0x0C, 0xAA, 0x68, 0xDE, 0x78, 0x39 }; + HmacHash clientDecryptHmac(SEED_KEY_SIZE, ClientDecryptionKey, EVP_sha256(), SHA256_DIGEST_LENGTH); + uint8 *decryptHash = clientDecryptHmac.ComputeHash(K); + + _clientDecrypt.Init(decryptHash); + _serverEncrypt.Init(encryptHash); + _initialized = true; +} diff --git a/src/server/authserver/Server/BattlenetPacketCrypt.h b/src/server/authserver/Server/BattlenetPacketCrypt.h new file mode 100644 index 00000000000..dde687651d3 --- /dev/null +++ b/src/server/authserver/Server/BattlenetPacketCrypt.h @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2008-2014 TrinityCore + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ + +#ifndef __BATTLENETPACKETCRYPT_H__ +#define __BATTLENETPACKETCRYPT_H__ + +#include "PacketCrypt.h" + +class BigNumber; + +namespace Battlenet +{ + class PacketCrypt : public ::PacketCrypt + { + public: + PacketCrypt(); + + void Init(BigNumber* K) override; + }; +} + +#endif // __BATTLENETPACKETCRYPT_H__ diff --git a/src/server/authserver/Server/BattlenetPackets.cpp b/src/server/authserver/Server/BattlenetPackets.cpp new file mode 100644 index 00000000000..37040fa6d6e --- /dev/null +++ b/src/server/authserver/Server/BattlenetPackets.cpp @@ -0,0 +1,170 @@ +/* + * Copyright (C) 2008-2014 TrinityCore + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ + +#include "Common.h" +#include "BattlenetBitStream.h" +#include "BattlenetPackets.h" +#include "Util.h" +#include +#include + +std::string Battlenet::PacketHeader::ToString() const +{ + std::ostringstream stream; + stream << "Battlenet::PacketHeader opcode: " << Opcode << ", channel: " << Channel; + return stream.str(); +} + +Battlenet::ServerPacket::ServerPacket(PacketHeader const& header) : Packet(header, *new BitStream()) +{ + _stream.Write(header.Opcode, 6); + _stream.Write(1, 1); + _stream.Write(header.Channel, 4); +} + +Battlenet::ServerPacket::~ServerPacket() +{ + delete &_stream; +} + +void Battlenet::AuthChallenge::Read() +{ + Program = _stream.ReadFourCC(); + Platform = _stream.ReadFourCC(); + Locale = _stream.ReadFourCC(); + + Components.resize(_stream.Read(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(32); + } + + if (_stream.Read(1)) + Login = _stream.ReadString(9, 3); +} + +std::string Battlenet::AuthChallenge::ToString() const +{ + std::ostringstream stream; + stream << "Battlenet::AuthChallenge Program: " << Program << ", Platform: " << Platform << ", Locale: " << Locale; + for (uint32 i = 0; i < Components.size(); ++i) + stream << std::endl << "Battlenet::AuthChallenge::Component Program: " << Components[i].Program << ", Platform: " << Components[i].Platform << ", Build: " << Components[i].Build; + + if (!Login.empty()) + stream << std::endl << "Battlenet::AuthChallenge Login: " << Login; + + return stream.str(); +} + +void Battlenet::ProofRequest::Write() +{ + _stream.Write(Modules.size(), 3); + for (size_t i = 0; i < Modules.size(); ++i) + { + ModuleInfo& info = Modules[i]; + _stream.WriteBytes(info.AuthString.c_str(), 4); + _stream.WriteFourCC(info.Locale.c_str()); + _stream.WriteBytes(info.ModuleId, 32); + _stream.Write(info.BlobSize, 10); + _stream.WriteBytes(info.Blob, info.BlobSize); + } +} + +Battlenet::ProofResponse::~ProofResponse() +{ + for (size_t i = 0; i < Modules.size(); ++i) + delete[] Modules[i].Data; +} + +void Battlenet::ProofResponse::Read() +{ + Modules.resize(_stream.Read(3)); + for (size_t i = 0; i < Modules.size(); ++i) + { + ModuleData& data = Modules[i]; + data.Size = _stream.Read(10); + data.Data = _stream.ReadBytes(data.Size); + } +} + +std::string Battlenet::ProofResponse::ToString() const +{ + std::ostringstream stream; + stream << "Battlenet::ProofResponse Modules " << Modules.size(); + for (size_t i = 0; i < Modules.size(); ++i) + { + std::string hexStr = ByteArrayToHexStr(Modules[i].Data, Modules[i].Size); + stream << std::endl << "Battlenet::ProofResponse::ModuleData Size: " << Modules[i].Size << ", Data: " << hexStr; + } + + return stream.str(); +} + +void Battlenet::AuthComplete::Write() +{ + _stream.Write(AuthResult != 0, 1); + if (AuthResult == 0) + { + _stream.Write(Modules.size(), 3); + for (size_t i = 0; i < Modules.size(); ++i) + { + ModuleInfo& info = Modules[i]; + _stream.WriteBytes(info.AuthString.c_str(), 4); + _stream.WriteFourCC(info.Locale.c_str()); + _stream.WriteBytes(info.ModuleId, 32); + _stream.Write(info.BlobSize, 10); + _stream.WriteBytes(info.Blob, info.BlobSize); + } + + _stream.Write(PingTimeout + std::numeric_limits::min(), 32); + _stream.Write(1, 1); + // if written == 1 + { + _stream.Write(1, 1); + // if written == 1 + { + _stream.Write(Threshold, 32); + _stream.Write(Rate, 32); + } + } + + // todo more + } + else + { + _stream.Write(!Modules.empty(), 1); + if (!Modules.empty()) + { + ModuleInfo& info = Modules[0]; + _stream.WriteBytes(info.AuthString.c_str(), 4); + _stream.WriteFourCC(info.Locale.c_str()); + _stream.WriteBytes(info.ModuleId, 32); + _stream.Write(info.BlobSize, 10); + _stream.WriteBytes(info.Blob, info.BlobSize); + } + + _stream.Write(ErrorType, 2); + if (ErrorType == 1) + { + _stream.Write(AuthResult, 16); + _stream.Write(0, 32); + } + } +} diff --git a/src/server/authserver/Server/BattlenetPackets.h b/src/server/authserver/Server/BattlenetPackets.h new file mode 100644 index 00000000000..23625e30d2b --- /dev/null +++ b/src/server/authserver/Server/BattlenetPackets.h @@ -0,0 +1,202 @@ +/* + * Copyright (C) 2008-2014 TrinityCore + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ + +#ifndef __BATTLENETPACKETS_H__ +#define __BATTLENETPACKETS_H__ + +#include "Define.h" +#include "Errors.h" +#include + +namespace Battlenet +{ + class BitStream; + + enum Channel + { + NOT_SPECIFIED = -1, + + AUTHENTICATION = 0, + CREEP = 1, + WOW = 2 + }; + + enum AuthOpcode + { + CMSG_AUTH_CHALLENGE = 0x0, + CMSG_AUTH_PROOF_RESPONSE = 0x2, + + SMSG_AUTH_COMPLETE = 0x0, + SMSG_AUTH_PROOF_REQUEST = 0x2, + }; + + struct PacketHeader + { + PacketHeader(uint32 opcode, uint32 channel) : Opcode(opcode), Channel(channel) { } + PacketHeader() : Opcode(0), Channel(NOT_SPECIFIED) { } + + uint32 Opcode; + int32 Channel; + + bool operator<(PacketHeader const& right) const + { + return Opcode < right.Opcode || Channel < right.Channel; + } + + bool operator==(PacketHeader const& right) const + { + return Opcode == right.Opcode && Channel == right.Channel; + } + + std::string ToString() const; + }; + + class Packet + { + public: + Packet(PacketHeader const& header, BitStream& stream) : _header(header), _stream(stream) { } + virtual ~Packet() { } + + PacketHeader const& GetHeader() const { return _header; } + + virtual void Write() = 0; + virtual void Read() = 0; + + virtual std::string ToString() const = 0; + + protected: + PacketHeader _header; + BitStream& _stream; + + private: + Packet(Packet const& right); + Packet& operator=(Packet const& right); + }; + + class ClientPacket : public Packet + { + public: + ClientPacket(PacketHeader const& header, BitStream& stream) : Packet(header, stream) { } + + void Write() override { ASSERT(!"Write not implemented for this packet."); } + + virtual std::string ToString() const override { return "Battenet::ClientPacket"; }; + }; + + class ServerPacket : public Packet + { + public: + ServerPacket(PacketHeader const& header); + ~ServerPacket(); + + void Read() override { ASSERT(!"Read not implemented for server packets."); } + + virtual std::string ToString() const override { return "Battenet::ServerPacket"; }; + + uint8 const* GetData() const { return _stream.GetBuffer(); } + size_t GetSize() const { return _stream.GetSize(); } + }; + + class AuthChallenge final : public ClientPacket + { + public: + AuthChallenge(PacketHeader const& header, BitStream& stream) : ClientPacket(header, stream) + { + ASSERT(header == PacketHeader(CMSG_AUTH_CHALLENGE, AUTHENTICATION) && "Invalid packet header for AuthChallenge"); + } + + struct Component + { + std::string Program; + std::string Platform; + uint32 Build; + }; + + void Read() override; + std::string ToString() const override; + + std::string Program; + std::string Platform; + std::string Locale; + std::vector Components; + std::string Login; + }; + + struct ModuleInfo + { + std::string AuthString; + std::string Locale; + uint8 ModuleId[32]; + uint32 BlobSize; + uint8* Blob; + }; + + class ProofRequest final : public ServerPacket + { + public: + ProofRequest() : ServerPacket(PacketHeader(SMSG_AUTH_PROOF_REQUEST, AUTHENTICATION)) { } + + void Write() override; + + std::vector Modules; + }; + + class ProofResponse final : public ClientPacket + { + public: + ProofResponse(PacketHeader const& header, BitStream& stream) : ClientPacket(header, stream) + { + ASSERT(header == PacketHeader(CMSG_AUTH_PROOF_RESPONSE, AUTHENTICATION) && "Invalid packet header for ProofResponse"); + } + + ~ProofResponse(); + + struct ModuleData + { + uint32 Size; + uint8* Data; + }; + + void Read() override; + std::string ToString() const override; + + std::vector Modules; + }; + + class AuthComplete final : public ServerPacket + { + public: + AuthComplete() : ServerPacket(PacketHeader(SMSG_AUTH_COMPLETE, AUTHENTICATION)), + AuthResult(0), ErrorType(0), PingTimeout(120000), Threshold(1000000), Rate(1000) + { + } + + void Write() override; + + uint32 AuthResult; + std::vector Modules; + uint32 ErrorType; + + int32 PingTimeout; + uint32 Threshold; + uint32 Rate; + std::string FirstName; + std::string LastName; + }; +} + +#endif // __BATTLENETPACKETS_H__ diff --git a/src/server/authserver/Server/BattlenetSocket.cpp b/src/server/authserver/Server/BattlenetSocket.cpp new file mode 100644 index 00000000000..fb9ca008e8b --- /dev/null +++ b/src/server/authserver/Server/BattlenetSocket.cpp @@ -0,0 +1,124 @@ +/* + * Copyright (C) 2008-2014 TrinityCore + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ + +#include "AuthCodes.h" +#include "BattlenetBitStream.h" +#include "BattlenetPackets.h" +#include "BattlenetSocket.h" +#include + +bool Battlenet::Socket::HandleAuthChallenge(PacketHeader& header, BitStream& packet) +{ + AuthChallenge info(header, packet); + info.Read(); + + printf("%s\n", info.ToString().c_str()); + + _accountName = info.Login; + + ProofRequest request; + request.Write(); + _socket.send((char const*)request.GetData(), request.GetSize()); + return true; +} + +bool Battlenet::Socket::HandleAuthProofResponse(PacketHeader& header, BitStream& packet) +{ + ProofResponse response(header, packet); + response.Read(); + + printf("%s\n", response.ToString().c_str()); + + AuthComplete complete; + complete.ErrorType = 1; + complete.AuthResult = AUTH_USE_GRUNT_LOGON; + complete.Write(); + _socket.send((char const*)complete.GetData(), complete.GetSize()); + return true; +} + +std::map InitHandlers() +{ + std::map handlers; + + handlers[Battlenet::PacketHeader(Battlenet::CMSG_AUTH_CHALLENGE, Battlenet::AUTHENTICATION)] = &Battlenet::Socket::HandleAuthChallenge; + handlers[Battlenet::PacketHeader(Battlenet::CMSG_AUTH_PROOF_RESPONSE, Battlenet::AUTHENTICATION)] = &Battlenet::Socket::HandleAuthProofResponse; + + return handlers; +} + +std::map Handlers = InitHandlers(); + +Battlenet::Socket::Socket(RealmSocket& socket) : _socket(socket), _currentChannel(0) +{ +} + +void Battlenet::Socket::OnRead() +{ + while (1) + { + size_t length = _socket.recv_len(); + if (!length) + return; + + BitStream packet(length); + if (!_socket.recv((char*)packet.GetBuffer(), length)) + return; + + while (!packet.IsRead()) + { + try + { + PacketHeader header; + header.Opcode = packet.Read(6); + if (packet.Read(1)) + _currentChannel = header.Channel = packet.Read(4); + + printf("Battlenet::Socket::OnRead %s\n", header.ToString().c_str()); + std::map::const_iterator itr = Handlers.find(header); + if (itr != Handlers.end()) + { + if (!(this->*(itr->second))(header, packet)) + { + _socket.shutdown(); + return; + } + } + else + printf("Battlenet::Socket::OnRead Unhandled opcode %s\n", header.ToString().c_str()); + + packet.AlignToNextByte(); + } + catch (BitStreamPositionException const& e) + { + printf("Battlenet::Socket::OnRead Exception: %s\n", e.what()); + _socket.shutdown(); + return; + } + } + } +} + +void Battlenet::Socket::OnAccept() +{ + printf("Battlenet::Socket::OnAccept\n"); +} + +void Battlenet::Socket::OnClose() +{ + printf("Battlenet::Socket::OnClose\n"); +} diff --git a/src/server/authserver/Server/BattlenetSocket.h b/src/server/authserver/Server/BattlenetSocket.h new file mode 100644 index 00000000000..f7cc59d7e97 --- /dev/null +++ b/src/server/authserver/Server/BattlenetSocket.h @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2008-2014 TrinityCore + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ + +#ifndef _BATTLENETSOCKET_H +#define _BATTLENETSOCKET_H + +#include "RealmSocket.h" +#include "BattlenetPacketCrypt.h" + +namespace Battlenet +{ + struct PacketHeader; + class BitStream; + + class Socket : public RealmSocket::Session + { + public: + Socket(RealmSocket& socket); + + typedef bool(Socket::*PacketHandler)(PacketHeader& socket, BitStream& packet); + + bool HandleAuthChallenge(PacketHeader& header, BitStream& packet); + bool HandleAuthProofResponse(PacketHeader& header, BitStream& packet); + + void OnRead() override; + void OnAccept() override; + void OnClose() override; + + private: + RealmSocket& _socket; + uint32 _currentChannel; + + std::string _accountName; + + PacketCrypt _crypt; + }; + +} + +#endif // _BATTLENETSOCKET_H diff --git a/src/server/authserver/Server/RealmAcceptor.h b/src/server/authserver/Server/RealmAcceptor.h index e89135c4896..2089b0c7a22 100644 --- a/src/server/authserver/Server/RealmAcceptor.h +++ b/src/server/authserver/Server/RealmAcceptor.h @@ -24,7 +24,9 @@ #include "RealmSocket.h" #include "AuthSocket.h" +#include "BattlenetSocket.h" +template class RealmAcceptor : public ACE_Acceptor { public: @@ -42,7 +44,7 @@ protected: ACE_NEW_RETURN(sh, RealmSocket, -1); sh->reactor(reactor()); - sh->set_session(new AuthSocket(*sh)); + sh->set_session(new LoginType(*sh)); return 0; } diff --git a/src/server/game/Server/WorldSocket.h b/src/server/game/Server/WorldSocket.h index 4ccacd05c7e..306a50c083a 100644 --- a/src/server/game/Server/WorldSocket.h +++ b/src/server/game/Server/WorldSocket.h @@ -39,7 +39,7 @@ #endif /* ACE_LACKS_PRAGMA_ONCE */ #include "Common.h" -#include "AuthCrypt.h" +#include "WorldPacketCrypt.h" class ACE_Message_Block; class WorldPacket; @@ -176,7 +176,7 @@ class WorldSocket : public WorldHandler std::string m_Address; /// Class used for managing encryption of the headers - AuthCrypt m_Crypt; + WorldPacketCrypt m_Crypt; /// Mutex lock to protect m_Session LockType m_SessionLock; diff --git a/src/server/game/Warden/WardenWin.cpp b/src/server/game/Warden/WardenWin.cpp index 18bf2897358..3014fcfb993 100644 --- a/src/server/game/Warden/WardenWin.cpp +++ b/src/server/game/Warden/WardenWin.cpp @@ -16,7 +16,7 @@ * with this program. If not, see . */ -#include "Cryptography/HMACSHA1.h" +#include "Cryptography/HmacHash.h" #include "Cryptography/WardenKeyGeneration.h" #include "Common.h" #include "WorldPacket.h" @@ -283,7 +283,7 @@ void WardenWin::RequestData() { uint32 seed = static_cast(rand32()); buff << uint32(seed); - HmacHash hmac(4, (uint8*)&seed); + HmacHash hmac(4, (uint8*)&seed, EVP_sha1(), SHA_DIGEST_LENGTH); hmac.UpdateData(wd->Str); hmac.Finalize(); buff.append(hmac.GetDigest(), hmac.GetLength()); diff --git a/src/server/shared/Cryptography/Authentication/AuthCrypt.cpp b/src/server/shared/Cryptography/Authentication/AuthCrypt.cpp deleted file mode 100644 index ff94f307254..00000000000 --- a/src/server/shared/Cryptography/Authentication/AuthCrypt.cpp +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright (C) 2008-2014 TrinityCore - * Copyright (C) 2005-2009 MaNGOS - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -#include "AuthCrypt.h" -#include "Cryptography/HMACSHA1.h" -#include "Cryptography/BigNumber.h" - -AuthCrypt::AuthCrypt() : - _clientDecrypt(SHA_DIGEST_LENGTH), _serverEncrypt(SHA_DIGEST_LENGTH), - _initialized(false) -{ } - -void AuthCrypt::Init(BigNumber* K) -{ - uint8 ServerEncryptionKey[SEED_KEY_SIZE] = { 0xCC, 0x98, 0xAE, 0x04, 0xE8, 0x97, 0xEA, 0xCA, 0x12, 0xDD, 0xC0, 0x93, 0x42, 0x91, 0x53, 0x57 }; - HmacHash serverEncryptHmac(SEED_KEY_SIZE, (uint8*)ServerEncryptionKey); - uint8 *encryptHash = serverEncryptHmac.ComputeHash(K); - - uint8 ServerDecryptionKey[SEED_KEY_SIZE] = { 0xC2, 0xB3, 0x72, 0x3C, 0xC6, 0xAE, 0xD9, 0xB5, 0x34, 0x3C, 0x53, 0xEE, 0x2F, 0x43, 0x67, 0xCE }; - HmacHash clientDecryptHmac(SEED_KEY_SIZE, (uint8*)ServerDecryptionKey); - uint8 *decryptHash = clientDecryptHmac.ComputeHash(K); - - //ARC4 _serverDecrypt(encryptHash); - _clientDecrypt.Init(decryptHash); - _serverEncrypt.Init(encryptHash); - //ARC4 _clientEncrypt(decryptHash); - - // Drop first 1024 bytes, as WoW uses ARC4-drop1024. - uint8 syncBuf[1024]; - memset(syncBuf, 0, 1024); - - _serverEncrypt.UpdateData(1024, syncBuf); - //_clientEncrypt.UpdateData(1024, syncBuf); - - memset(syncBuf, 0, 1024); - - //_serverDecrypt.UpdateData(1024, syncBuf); - _clientDecrypt.UpdateData(1024, syncBuf); - - _initialized = true; -} - -void AuthCrypt::DecryptRecv(uint8 *data, size_t len) -{ - if (!_initialized) - return; - - _clientDecrypt.UpdateData(len, data); -} - -void AuthCrypt::EncryptSend(uint8 *data, size_t len) -{ - if (!_initialized) - return; - - _serverEncrypt.UpdateData(len, data); -} - diff --git a/src/server/shared/Cryptography/Authentication/AuthCrypt.h b/src/server/shared/Cryptography/Authentication/AuthCrypt.h deleted file mode 100644 index 8fa150068a2..00000000000 --- a/src/server/shared/Cryptography/Authentication/AuthCrypt.h +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (C) 2008-2014 TrinityCore - * Copyright (C) 2005-2009 MaNGOS - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -#ifndef _AUTHCRYPT_H -#define _AUTHCRYPT_H - -#include "Cryptography/ARC4.h" - -class BigNumber; - -class AuthCrypt -{ - public: - AuthCrypt(); - - void Init(BigNumber* K); - void DecryptRecv(uint8 *, size_t); - void EncryptSend(uint8 *, size_t); - - bool IsInitialized() const { return _initialized; } - - private: - ARC4 _clientDecrypt; - ARC4 _serverEncrypt; - bool _initialized; -}; -#endif diff --git a/src/server/shared/Cryptography/Authentication/PacketCrypt.cpp b/src/server/shared/Cryptography/Authentication/PacketCrypt.cpp new file mode 100644 index 00000000000..7fac311b8a2 --- /dev/null +++ b/src/server/shared/Cryptography/Authentication/PacketCrypt.cpp @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2008-2014 TrinityCore + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ + +#include "PacketCrypt.h" + +PacketCrypt::PacketCrypt(uint32 rc4InitSize) + : _clientDecrypt(rc4InitSize), _serverEncrypt(rc4InitSize), _initialized(false) +{ +} + +void PacketCrypt::DecryptRecv(uint8* data, size_t len) +{ + if (!_initialized) + return; + + _clientDecrypt.UpdateData(len, data); +} + +void PacketCrypt::EncryptSend(uint8* data, size_t len) +{ + if (!_initialized) + return; + + _serverEncrypt.UpdateData(len, data); +} diff --git a/src/server/shared/Cryptography/Authentication/PacketCrypt.h b/src/server/shared/Cryptography/Authentication/PacketCrypt.h new file mode 100644 index 00000000000..36f3b81fb53 --- /dev/null +++ b/src/server/shared/Cryptography/Authentication/PacketCrypt.h @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2008-2014 TrinityCore + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ + +#ifndef _PACKETCRYPT_H +#define _PACKETCRYPT_H + +#include "Cryptography/ARC4.h" + +class BigNumber; + +class PacketCrypt +{ + public: + PacketCrypt(uint32 rc4InitSize); + virtual ~PacketCrypt() { } + + virtual void Init(BigNumber* K) = 0; + void DecryptRecv(uint8* data, size_t length); + void EncryptSend(uint8* data, size_t length); + + bool IsInitialized() const { return _initialized; } + + protected: + ARC4 _clientDecrypt; + ARC4 _serverEncrypt; + bool _initialized; +}; + +#endif // _PACKETCRYPT_H diff --git a/src/server/shared/Cryptography/Authentication/WorldPacketCrypt.cpp b/src/server/shared/Cryptography/Authentication/WorldPacketCrypt.cpp new file mode 100644 index 00000000000..c6b283d9961 --- /dev/null +++ b/src/server/shared/Cryptography/Authentication/WorldPacketCrypt.cpp @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2008-2014 TrinityCore + * Copyright (C) 2005-2009 MaNGOS + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ + +#include "WorldPacketCrypt.h" +#include "Cryptography/HmacHash.h" +#include "Cryptography/BigNumber.h" + +WorldPacketCrypt::WorldPacketCrypt() : PacketCrypt(SHA_DIGEST_LENGTH) +{ +} + +void WorldPacketCrypt::Init(BigNumber* K) +{ + uint8 ServerEncryptionKey[SEED_KEY_SIZE] = { 0xCC, 0x98, 0xAE, 0x04, 0xE8, 0x97, 0xEA, 0xCA, 0x12, 0xDD, 0xC0, 0x93, 0x42, 0x91, 0x53, 0x57 }; + HmacHash serverEncryptHmac(SEED_KEY_SIZE, (uint8*)ServerEncryptionKey, EVP_sha1(), SHA_DIGEST_LENGTH); + uint8 *encryptHash = serverEncryptHmac.ComputeHash(K); + + uint8 ServerDecryptionKey[SEED_KEY_SIZE] = { 0xC2, 0xB3, 0x72, 0x3C, 0xC6, 0xAE, 0xD9, 0xB5, 0x34, 0x3C, 0x53, 0xEE, 0x2F, 0x43, 0x67, 0xCE }; + HmacHash clientDecryptHmac(SEED_KEY_SIZE, (uint8*)ServerDecryptionKey, EVP_sha1(), SHA_DIGEST_LENGTH); + uint8 *decryptHash = clientDecryptHmac.ComputeHash(K); + + _clientDecrypt.Init(decryptHash); + _serverEncrypt.Init(encryptHash); + + // Drop first 1024 bytes, as WoW uses ARC4-drop1024. + uint8 syncBuf[1024]; + memset(syncBuf, 0, 1024); + + _serverEncrypt.UpdateData(1024, syncBuf); + + memset(syncBuf, 0, 1024); + + _clientDecrypt.UpdateData(1024, syncBuf); + + _initialized = true; +} diff --git a/src/server/shared/Cryptography/Authentication/WorldPacketCrypt.h b/src/server/shared/Cryptography/Authentication/WorldPacketCrypt.h new file mode 100644 index 00000000000..7ccca11f09d --- /dev/null +++ b/src/server/shared/Cryptography/Authentication/WorldPacketCrypt.h @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2008-2014 TrinityCore + * Copyright (C) 2005-2009 MaNGOS + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ + +#ifndef _WORLDPACKETCRYPT_H +#define _WORLDPACKETCRYPT_H + +#include "PacketCrypt.h" + +class BigNumber; + +class WorldPacketCrypt : public PacketCrypt +{ + public: + WorldPacketCrypt(); + + void Init(BigNumber* K) override; +}; + +#endif // _WORLDPACKETCRYPT_H diff --git a/src/server/shared/Cryptography/HMACSHA1.cpp b/src/server/shared/Cryptography/HMACSHA1.cpp deleted file mode 100644 index 2148a3b8a7b..00000000000 --- a/src/server/shared/Cryptography/HMACSHA1.cpp +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright (C) 2008-2014 TrinityCore - * Copyright (C) 2005-2009 MaNGOS - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -#include "HMACSHA1.h" -#include "BigNumber.h" -#include "Common.h" - -HmacHash::HmacHash(uint32 len, uint8 *seed) -{ - HMAC_CTX_init(&m_ctx); - HMAC_Init_ex(&m_ctx, seed, len, EVP_sha1(), NULL); - memset(m_digest, 0, sizeof(m_digest)); -} - -HmacHash::~HmacHash() -{ - HMAC_CTX_cleanup(&m_ctx); -} - -void HmacHash::UpdateData(const std::string &str) -{ - HMAC_Update(&m_ctx, (uint8 const*)str.c_str(), str.length()); -} - -void HmacHash::UpdateData(const uint8* data, size_t len) -{ - HMAC_Update(&m_ctx, data, len); -} - -void HmacHash::Finalize() -{ - uint32 length = 0; - HMAC_Final(&m_ctx, (uint8*)m_digest, &length); - ASSERT(length == SHA_DIGEST_LENGTH); -} - -uint8 *HmacHash::ComputeHash(BigNumber* bn) -{ - HMAC_Update(&m_ctx, bn->AsByteArray().get(), bn->GetNumBytes()); - Finalize(); - return (uint8*)m_digest; -} diff --git a/src/server/shared/Cryptography/HMACSHA1.h b/src/server/shared/Cryptography/HMACSHA1.h deleted file mode 100644 index de1556d3c98..00000000000 --- a/src/server/shared/Cryptography/HMACSHA1.h +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright (C) 2008-2014 TrinityCore - * Copyright (C) 2005-2009 MaNGOS - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -#ifndef _AUTH_HMAC_H -#define _AUTH_HMAC_H - -#include "Define.h" -#include -#include -#include - -class BigNumber; - -#define SEED_KEY_SIZE 16 - -class HmacHash -{ - public: - HmacHash(uint32 len, uint8 *seed); - ~HmacHash(); - void UpdateData(const std::string &str); - void UpdateData(const uint8* data, size_t len); - void Finalize(); - uint8 *ComputeHash(BigNumber* bn); - uint8 *GetDigest() { return (uint8*)m_digest; } - int GetLength() const { return SHA_DIGEST_LENGTH; } - private: - HMAC_CTX m_ctx; - uint8 m_digest[SHA_DIGEST_LENGTH]; -}; -#endif - diff --git a/src/server/shared/Cryptography/HmacHash.cpp b/src/server/shared/Cryptography/HmacHash.cpp new file mode 100644 index 00000000000..7a365ade457 --- /dev/null +++ b/src/server/shared/Cryptography/HmacHash.cpp @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2008-2014 TrinityCore + * Copyright (C) 2005-2009 MaNGOS + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ + +#include "HmacHash.h" +#include "BigNumber.h" +#include "Common.h" + +HmacHash::HmacHash(uint32 len, uint8 *seed, EVP_MD const* hasher, uint32 digestLength) +{ + HMAC_CTX_init(&_ctx); + HMAC_Init_ex(&_ctx, seed, len, hasher, NULL); + _digest = new uint8[digestLength]; + memset(_digest, 0, digestLength); +} + +HmacHash::~HmacHash() +{ + HMAC_CTX_cleanup(&_ctx); + delete[] _digest; +} + +void HmacHash::UpdateData(const std::string &str) +{ + HMAC_Update(&_ctx, (uint8 const*)str.c_str(), str.length()); +} + +void HmacHash::UpdateData(const uint8* data, size_t len) +{ + HMAC_Update(&_ctx, data, len); +} + +void HmacHash::Finalize() +{ + uint32 length = 0; + HMAC_Final(&_ctx, _digest, &length); + ASSERT(length == _digestLength); +} + +uint8* HmacHash::ComputeHash(BigNumber* bn) +{ + HMAC_Update(&_ctx, bn->AsByteArray().get(), bn->GetNumBytes()); + Finalize(); + return _digest; +} diff --git a/src/server/shared/Cryptography/HmacHash.h b/src/server/shared/Cryptography/HmacHash.h new file mode 100644 index 00000000000..cf59e16f08e --- /dev/null +++ b/src/server/shared/Cryptography/HmacHash.h @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2008-2014 TrinityCore + * Copyright (C) 2005-2009 MaNGOS + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ + +#ifndef _AUTH_HMAC_H +#define _AUTH_HMAC_H + +#include "Define.h" +#include +#include +#include + +class BigNumber; + +#define SEED_KEY_SIZE 16 + +class HmacHash +{ + public: + HmacHash(uint32 len, uint8 *seed, EVP_MD const* hasher, uint32 digestLength); + ~HmacHash(); + void UpdateData(const std::string &str); + void UpdateData(const uint8* data, size_t len); + void Finalize(); + uint8* ComputeHash(BigNumber* bn); + uint8* GetDigest() { return _digest; } + int GetLength() const { return SHA_DIGEST_LENGTH; } + private: + HMAC_CTX _ctx; + uint8* _digest; + uint32 _digestLength; +}; + +#endif -- cgit v1.2.3 From fea9d275fa0ed8f5b43dc54979cdd5a58afc993b Mon Sep 17 00:00:00 2001 From: Shauren Date: Wed, 30 Apr 2014 23:02:01 +0200 Subject: Verify received components --- src/server/authserver/Main.cpp | 2 + src/server/authserver/Server/BattlenetBitStream.h | 2 + src/server/authserver/Server/BattlenetManager.cpp | 61 ++++++++++++++++++++++ src/server/authserver/Server/BattlenetManager.h | 62 +++++++++++++++++++++++ src/server/authserver/Server/BattlenetPackets.cpp | 43 ++++++++++++---- src/server/authserver/Server/BattlenetPackets.h | 20 ++++---- src/server/authserver/Server/BattlenetSocket.cpp | 36 ++++++++++--- src/server/authserver/Server/BattlenetSocket.h | 3 ++ 8 files changed, 202 insertions(+), 27 deletions(-) create mode 100644 src/server/authserver/Server/BattlenetManager.cpp create mode 100644 src/server/authserver/Server/BattlenetManager.h (limited to 'src') diff --git a/src/server/authserver/Main.cpp b/src/server/authserver/Main.cpp index 0e23dd99ba8..be2e6a11d4f 100644 --- a/src/server/authserver/Main.cpp +++ b/src/server/authserver/Main.cpp @@ -254,6 +254,8 @@ extern int main(int argc, char** argv) #endif #endif + sBattlenetMgr->Load(); + // maximum counter for next ping uint32 numLoops = (sConfigMgr->GetIntDefault("MaxPingTime", 30) * (MINUTE * 1000000 / 100000)); uint32 loopCounter = 0; diff --git a/src/server/authserver/Server/BattlenetBitStream.h b/src/server/authserver/Server/BattlenetBitStream.h index fa09b24b204..4b6c7f882d4 100644 --- a/src/server/authserver/Server/BattlenetBitStream.h +++ b/src/server/authserver/Server/BattlenetBitStream.h @@ -178,6 +178,8 @@ namespace Battlenet size_t GetSize() const { return _buffer.size(); } + void FinishReading() { _readPos = _numBits; } + private: std::vector _buffer; uint32 _numBits; diff --git a/src/server/authserver/Server/BattlenetManager.cpp b/src/server/authserver/Server/BattlenetManager.cpp new file mode 100644 index 00000000000..b7df889809e --- /dev/null +++ b/src/server/authserver/Server/BattlenetManager.cpp @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2008-2014 TrinityCore + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ + +#include "BattlenetManager.h" +#include "DatabaseEnv.h" + +void BattlenetMgr::Load() +{ + LoadComponents(); + LoadModules(); +} + +void BattlenetMgr::LoadComponents() +{ + QueryResult result = LoginDatabase.Query("SELECT Program, Platform, Build FROM battlenet_components"); + if (result) + { + do + { + Field* fields = result->Fetch(); + Battlenet::Component* component = new Battlenet::Component(); + component->Program = fields[0].GetString(); + component->Platform = fields[1].GetString(); + component->Build = fields[2].GetUInt32(); + + _components.insert(component); + _programs.insert(component->Program); + _platforms.insert(component->Platform); + _builds.insert(component->Build); + + } while (result->NextRow()); + } +} + +void BattlenetMgr::LoadModules() +{ + +} + +bool BattlenetMgr::HasComponent(Battlenet::Component const* component) const +{ + for (Battlenet::Component const* c : _components) + if (component->Program == c->Program && component->Platform == c->Platform && component->Build == c->Build) + return true; + + return false; +} diff --git a/src/server/authserver/Server/BattlenetManager.h b/src/server/authserver/Server/BattlenetManager.h new file mode 100644 index 00000000000..d3962a32c0d --- /dev/null +++ b/src/server/authserver/Server/BattlenetManager.h @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2008-2014 TrinityCore + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ + +#ifndef __BATTLENETMANAGER_H__ +#define __BATTLENETMANAGER_H__ + +#include "Define.h" +#include +#include +#include +#include + +namespace Battlenet +{ + struct Component + { + std::string Program; + std::string Platform; + uint32 Build; + }; +} + +class BattlenetMgr +{ + friend class ACE_Singleton; + BattlenetMgr() { } + ~BattlenetMgr() { } + +public: + void Load(); + bool HasComponent(Battlenet::Component const* component) const; + bool HasProgram(std::string const& program) const { return _programs.count(program); } + bool HasPlatform(std::string const& platform) const { return _platforms.count(platform); } + bool HasBuild(uint32 build) const { return _builds.count(build); } + +private: + void LoadComponents(); + void LoadModules(); + + std::set _components; + std::set _programs; + std::set _platforms; + std::set _builds; +}; + +#define sBattlenetMgr ACE_Singleton::instance() + +#endif // __BATTLENETMANAGER_H__ diff --git a/src/server/authserver/Server/BattlenetPackets.cpp b/src/server/authserver/Server/BattlenetPackets.cpp index 37040fa6d6e..80213a0ba33 100644 --- a/src/server/authserver/Server/BattlenetPackets.cpp +++ b/src/server/authserver/Server/BattlenetPackets.cpp @@ -15,9 +15,8 @@ * with this program. If not, see . */ -#include "Common.h" -#include "BattlenetBitStream.h" #include "BattlenetPackets.h" +#include "Common.h" #include "Util.h" #include #include @@ -58,14 +57,17 @@ void Battlenet::AuthChallenge::Read() if (_stream.Read(1)) Login = _stream.ReadString(9, 3); + + if (GetHeader().Opcode == CMSG_AUTH_CHALLENGE_NEW) + _stream.FinishReading(); } std::string Battlenet::AuthChallenge::ToString() const { std::ostringstream stream; stream << "Battlenet::AuthChallenge Program: " << Program << ", Platform: " << Platform << ", Locale: " << Locale; - for (uint32 i = 0; i < Components.size(); ++i) - stream << std::endl << "Battlenet::AuthChallenge::Component Program: " << Components[i].Program << ", Platform: " << Components[i].Platform << ", Build: " << Components[i].Build; + for (Component const& component : Components) + stream << std::endl << "Battlenet::AuthChallenge::Component Program: " << component.Program << ", Platform: " << component.Platform << ", Build: " << component.Build; if (!Login.empty()) stream << std::endl << "Battlenet::AuthChallenge Login: " << Login; @@ -87,6 +89,16 @@ void Battlenet::ProofRequest::Write() } } +std::string Battlenet::ProofRequest::ToString() const +{ + std::ostringstream stream; + stream << "Battlenet::ProofRequest modules " << Modules.size(); + for (ModuleInfo const& module : Modules) + stream << std::endl << "Locale " << module.Locale << "ModuleId " << ByteArrayToHexStr(module.ModuleId, 32) << "BlobSize " << module.BlobSize; + + return stream.str(); +} + Battlenet::ProofResponse::~ProofResponse() { for (size_t i = 0; i < Modules.size(); ++i) @@ -108,10 +120,10 @@ std::string Battlenet::ProofResponse::ToString() const { std::ostringstream stream; stream << "Battlenet::ProofResponse Modules " << Modules.size(); - for (size_t i = 0; i < Modules.size(); ++i) + for (ModuleData const& module : Modules) { - std::string hexStr = ByteArrayToHexStr(Modules[i].Data, Modules[i].Size); - stream << std::endl << "Battlenet::ProofResponse::ModuleData Size: " << Modules[i].Size << ", Data: " << hexStr; + std::string hexStr = ByteArrayToHexStr(module.Data, module.Size); + stream << std::endl << "Battlenet::ProofResponse::ModuleData Size: " << module.Size << ", Data: " << hexStr; } return stream.str(); @@ -119,8 +131,8 @@ std::string Battlenet::ProofResponse::ToString() const void Battlenet::AuthComplete::Write() { - _stream.Write(AuthResult != 0, 1); - if (AuthResult == 0) + _stream.Write(Result != 0, 1); + if (Result == 0) { _stream.Write(Modules.size(), 3); for (size_t i = 0; i < Modules.size(); ++i) @@ -163,8 +175,19 @@ void Battlenet::AuthComplete::Write() _stream.Write(ErrorType, 2); if (ErrorType == 1) { - _stream.Write(AuthResult, 16); + _stream.Write(Result, 16); _stream.Write(0, 32); } } } + +std::string Battlenet::AuthComplete::ToString() const +{ + return "Battlenet::AuthComplete"; +} + +void Battlenet::AuthComplete::SetAuthResult(AuthResult result) +{ + ErrorType = result != AUTH_OK ? 1 : 0; + Result = result; +} diff --git a/src/server/authserver/Server/BattlenetPackets.h b/src/server/authserver/Server/BattlenetPackets.h index 23625e30d2b..86dcb99a4da 100644 --- a/src/server/authserver/Server/BattlenetPackets.h +++ b/src/server/authserver/Server/BattlenetPackets.h @@ -18,6 +18,9 @@ #ifndef __BATTLENETPACKETS_H__ #define __BATTLENETPACKETS_H__ +#include "AuthCodes.h" +#include "BattlenetBitStream.h" +#include "BattlenetManager.h" #include "Define.h" #include "Errors.h" #include @@ -39,6 +42,7 @@ namespace Battlenet { CMSG_AUTH_CHALLENGE = 0x0, CMSG_AUTH_PROOF_RESPONSE = 0x2, + CMSG_AUTH_CHALLENGE_NEW = 0x9, // MoP SMSG_AUTH_COMPLETE = 0x0, SMSG_AUTH_PROOF_REQUEST = 0x2, @@ -116,16 +120,9 @@ namespace Battlenet public: AuthChallenge(PacketHeader const& header, BitStream& stream) : ClientPacket(header, stream) { - ASSERT(header == PacketHeader(CMSG_AUTH_CHALLENGE, AUTHENTICATION) && "Invalid packet header for AuthChallenge"); + ASSERT(header.Channel == AUTHENTICATION && (header.Opcode == CMSG_AUTH_CHALLENGE || header.Opcode == CMSG_AUTH_CHALLENGE_NEW) && "Invalid packet header for AuthChallenge"); } - struct Component - { - std::string Program; - std::string Platform; - uint32 Build; - }; - void Read() override; std::string ToString() const override; @@ -151,6 +148,7 @@ namespace Battlenet ProofRequest() : ServerPacket(PacketHeader(SMSG_AUTH_PROOF_REQUEST, AUTHENTICATION)) { } void Write() override; + std::string ToString() const override; std::vector Modules; }; @@ -181,14 +179,16 @@ namespace Battlenet { public: AuthComplete() : ServerPacket(PacketHeader(SMSG_AUTH_COMPLETE, AUTHENTICATION)), - AuthResult(0), ErrorType(0), PingTimeout(120000), Threshold(1000000), Rate(1000) + Result(AUTH_OK), ErrorType(0), PingTimeout(120000), Threshold(1000000), Rate(1000) { } void Write() override; + std::string ToString() const override; - uint32 AuthResult; std::vector Modules; + void SetAuthResult(AuthResult result); + AuthResult Result; uint32 ErrorType; int32 PingTimeout; diff --git a/src/server/authserver/Server/BattlenetSocket.cpp b/src/server/authserver/Server/BattlenetSocket.cpp index fb9ca008e8b..04005e30878 100644 --- a/src/server/authserver/Server/BattlenetSocket.cpp +++ b/src/server/authserver/Server/BattlenetSocket.cpp @@ -17,7 +17,6 @@ #include "AuthCodes.h" #include "BattlenetBitStream.h" -#include "BattlenetPackets.h" #include "BattlenetSocket.h" #include @@ -26,13 +25,29 @@ bool Battlenet::Socket::HandleAuthChallenge(PacketHeader& header, BitStream& pac AuthChallenge info(header, packet); info.Read(); + for (Component const& component : info.Components) + { + if (!sBattlenetMgr->HasComponent(&component)) + { + AuthComplete complete; + if (!sBattlenetMgr->HasProgram(component.Program)) + complete.SetAuthResult(AUTH_INVALID_PROGRAM); + else if (!sBattlenetMgr->HasPlatform(component.Platform)) + complete.SetAuthResult(AUTH_INVALID_OS); + else if (!sBattlenetMgr->HasBuild(component.Build)) + complete.SetAuthResult(AUTH_REGION_BAD_VERSION); + + Send(complete); + return true; + } + } + printf("%s\n", info.ToString().c_str()); _accountName = info.Login; ProofRequest request; - request.Write(); - _socket.send((char const*)request.GetData(), request.GetSize()); + Send(request); return true; } @@ -44,10 +59,8 @@ bool Battlenet::Socket::HandleAuthProofResponse(PacketHeader& header, BitStream& printf("%s\n", response.ToString().c_str()); AuthComplete complete; - complete.ErrorType = 1; - complete.AuthResult = AUTH_USE_GRUNT_LOGON; - complete.Write(); - _socket.send((char const*)complete.GetData(), complete.GetSize()); + complete.SetAuthResult(AUTH_USE_GRUNT_LOGON); + Send(complete); return true; } @@ -56,6 +69,7 @@ std::map InitHandlers std::map 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_PROOF_RESPONSE, Battlenet::AUTHENTICATION)] = &Battlenet::Socket::HandleAuthProofResponse; return handlers; @@ -122,3 +136,11 @@ void Battlenet::Socket::OnClose() { printf("Battlenet::Socket::OnClose\n"); } + +void Battlenet::Socket::Send(ServerPacket& packet) +{ + printf("Battlenet::Socket::Send %s\n", packet.ToString().c_str()); + + packet.Write(); + _socket.send(reinterpret_cast(packet.GetData()), packet.GetSize()); +} diff --git a/src/server/authserver/Server/BattlenetSocket.h b/src/server/authserver/Server/BattlenetSocket.h index f7cc59d7e97..7507f090a7f 100644 --- a/src/server/authserver/Server/BattlenetSocket.h +++ b/src/server/authserver/Server/BattlenetSocket.h @@ -19,6 +19,7 @@ #define _BATTLENETSOCKET_H #include "RealmSocket.h" +#include "BattlenetPackets.h" #include "BattlenetPacketCrypt.h" namespace Battlenet @@ -40,6 +41,8 @@ namespace Battlenet void OnAccept() override; void OnClose() override; + void Send(ServerPacket& packet); + private: RealmSocket& _socket; uint32 _currentChannel; -- cgit v1.2.3 From 6955d7c9ad0e55480aa97d9cafd878c6bc3dc426 Mon Sep 17 00:00:00 2001 From: Shauren Date: Fri, 2 May 2014 02:55:10 +0200 Subject: Core/Battle.net * Fixed AuthResult codes * Fixed BitStream::WriteBytes size check * Fixed comparison operator for packet header * Fixed channel for client packets without channel * Implemented loading modules from database --- src/server/authserver/Authentication/AuthCodes.h | 9 +++-- src/server/authserver/Server/BattlenetBitStream.h | 12 +++++- src/server/authserver/Server/BattlenetManager.cpp | 38 +++++++++++++++++- src/server/authserver/Server/BattlenetManager.h | 47 +++++++++++++++++++++-- src/server/authserver/Server/BattlenetPackets.cpp | 33 ++++++++-------- src/server/authserver/Server/BattlenetPackets.h | 18 ++++----- src/server/authserver/Server/BattlenetSocket.cpp | 34 ++++++++++++++-- src/server/authserver/Server/BattlenetSocket.h | 2 + src/server/shared/Utilities/Util.cpp | 25 ++++++++++++ src/server/shared/Utilities/Util.h | 1 + 10 files changed, 179 insertions(+), 40 deletions(-) (limited to 'src') diff --git a/src/server/authserver/Authentication/AuthCodes.h b/src/server/authserver/Authentication/AuthCodes.h index e844863e4b1..12c2a810abb 100644 --- a/src/server/authserver/Authentication/AuthCodes.h +++ b/src/server/authserver/Authentication/AuthCodes.h @@ -97,7 +97,10 @@ namespace Battlenet AUTH_BATTLENET_MAINTENANCE = 122, AUTH_LOGON_TOO_FAST = 123, AUTH_USE_GRUNT_LOGON = 124, + AUTH_NO_GAME_ACCOUNTS_IN_REGION = 140, + AUTH_ACCOUNT_LOCKED = 141, + LOGIN_SERVER_BUSY = 200, LOGIN_NO_GAME_ACCOUNT = 201, LOGIN_BANNED = 202, LOGIN_SUSPENDED = 203, @@ -110,9 +113,9 @@ namespace Battlenet LOGIN_TRIAL_EXPIRED = 210, LOGIN_ANTI_INDULGENCE = 211, LOGIN_INCORRECT_REGION = 212, - LOGIN_CHARGEBACK = 213, - LOGIN_IGR_WITHOUT_BNET = 214, - LOGIN_LOCKED_ENFORCED = 215, + LOGIN_LOCKED_ENFORCED = 213, + LOGIN_CHARGEBACK = 214, + LOGIN_IGR_WITHOUT_BNET = 215, LOGIN_UNLOCKABLE_LOCK = 216, LOGIN_IGR_REQUIRED = 217, LOGIN_PAYMENT_CHANGED = 218, diff --git a/src/server/authserver/Server/BattlenetBitStream.h b/src/server/authserver/Server/BattlenetBitStream.h index 4b6c7f882d4..d372e0933c2 100644 --- a/src/server/authserver/Server/BattlenetBitStream.h +++ b/src/server/authserver/Server/BattlenetBitStream.h @@ -22,16 +22,21 @@ #include #include #include +#include namespace Battlenet { class BitStreamPositionException : public std::exception { public: + BitStreamPositionException() : st(1) { } + char const* what() const { - return ""; + return st.c_str(); } + + ACE_Stack_Trace st; }; class BitStream @@ -121,7 +126,10 @@ namespace Battlenet void WriteBytes(T* data, uint32 count) { AlignToNextByte(); - if (_writePos + 8 * count > MaxSize) + if (!count || !data) + return; + + if (_writePos + count > MaxSize) throw BitStreamPositionException(); _buffer.resize(_buffer.size() + count); diff --git a/src/server/authserver/Server/BattlenetManager.cpp b/src/server/authserver/Server/BattlenetManager.cpp index b7df889809e..a43512e612e 100644 --- a/src/server/authserver/Server/BattlenetManager.cpp +++ b/src/server/authserver/Server/BattlenetManager.cpp @@ -18,6 +18,15 @@ #include "BattlenetManager.h" #include "DatabaseEnv.h" +BattlenetMgr::~BattlenetMgr() +{ + for (Battlenet::Component* component : _components) + delete component; + + for (auto const& m : _modules) + delete m.second; +} + void BattlenetMgr::Load() { LoadComponents(); @@ -40,7 +49,6 @@ void BattlenetMgr::LoadComponents() _components.insert(component); _programs.insert(component->Program); _platforms.insert(component->Platform); - _builds.insert(component->Build); } while (result->NextRow()); } @@ -48,7 +56,27 @@ void BattlenetMgr::LoadComponents() void BattlenetMgr::LoadModules() { + QueryResult result = LoginDatabase.Query("SELECT `Hash`, `Name`, `Type`, `System`, `Data` FROM battlenet_modules"); + if (result) + { + do + { + Field* fields = result->Fetch(); + Battlenet::ModuleInfo* module = new Battlenet::ModuleInfo(); + module->Type = fields[2].GetString(); + module->Region.assign("\0\0EU", 4); + HexStrToByteArray(fields[0].GetString(), module->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()); + } } bool BattlenetMgr::HasComponent(Battlenet::Component const* component) const @@ -59,3 +87,11 @@ bool BattlenetMgr::HasComponent(Battlenet::Component const* component) const return false; } + +Battlenet::ModuleInfo const* BattlenetMgr::GetModule(Battlenet::ModuleKey const& key) const +{ + if (_modules.count(key)) + return _modules.at(key); + + return NULL; +} diff --git a/src/server/authserver/Server/BattlenetManager.h b/src/server/authserver/Server/BattlenetManager.h index d3962a32c0d..9fceb973770 100644 --- a/src/server/authserver/Server/BattlenetManager.h +++ b/src/server/authserver/Server/BattlenetManager.h @@ -32,20 +32,61 @@ namespace Battlenet std::string Platform; uint32 Build; }; + + 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 + { + ModuleInfo() : DataSize(0), Data(nullptr) { } + ModuleInfo(ModuleInfo const& right) : Type(right.Type), Region(right.Region), DataSize(right.DataSize), Data(nullptr) + { + memcpy(ModuleId, right.ModuleId, 32); + if (DataSize) + { + Data = new uint8[DataSize]; + memcpy(Data, right.Data, DataSize); + } + } + ~ModuleInfo() + { + delete Data; + } + + std::string Type; + std::string Region; + uint8 ModuleId[32]; + uint32 DataSize; + uint8* Data; + }; } class BattlenetMgr { friend class ACE_Singleton; BattlenetMgr() { } - ~BattlenetMgr() { } + ~BattlenetMgr(); public: void Load(); bool HasComponent(Battlenet::Component const* component) const; bool HasProgram(std::string const& program) const { return _programs.count(program); } bool HasPlatform(std::string const& platform) const { return _platforms.count(platform); } - bool HasBuild(uint32 build) const { return _builds.count(build); } + Battlenet::ModuleInfo const* GetModule(Battlenet::ModuleKey const& key) const; private: void LoadComponents(); @@ -54,7 +95,7 @@ private: std::set _components; std::set _programs; std::set _platforms; - std::set _builds; + std::map _modules; }; #define sBattlenetMgr ACE_Singleton::instance() diff --git a/src/server/authserver/Server/BattlenetPackets.cpp b/src/server/authserver/Server/BattlenetPackets.cpp index 80213a0ba33..68a602d8598 100644 --- a/src/server/authserver/Server/BattlenetPackets.cpp +++ b/src/server/authserver/Server/BattlenetPackets.cpp @@ -78,14 +78,13 @@ std::string Battlenet::AuthChallenge::ToString() const void Battlenet::ProofRequest::Write() { _stream.Write(Modules.size(), 3); - for (size_t i = 0; i < Modules.size(); ++i) + for (ModuleInfo const* info : Modules) { - ModuleInfo& info = Modules[i]; - _stream.WriteBytes(info.AuthString.c_str(), 4); - _stream.WriteFourCC(info.Locale.c_str()); - _stream.WriteBytes(info.ModuleId, 32); - _stream.Write(info.BlobSize, 10); - _stream.WriteBytes(info.Blob, info.BlobSize); + _stream.WriteBytes(info->Type.c_str(), 4); + _stream.WriteFourCC(info->Region.c_str()); + _stream.WriteBytes(info->ModuleId, 32); + _stream.Write(info->DataSize, 10); + _stream.WriteBytes(info->Data, info->DataSize); } } @@ -93,8 +92,8 @@ std::string Battlenet::ProofRequest::ToString() const { std::ostringstream stream; stream << "Battlenet::ProofRequest modules " << Modules.size(); - for (ModuleInfo const& module : Modules) - stream << std::endl << "Locale " << module.Locale << "ModuleId " << ByteArrayToHexStr(module.ModuleId, 32) << "BlobSize " << module.BlobSize; + for (ModuleInfo const* module : Modules) + stream << std::endl << "Locale " << module->Region << "ModuleId " << ByteArrayToHexStr(module->ModuleId, 32) << "BlobSize " << module->DataSize; return stream.str(); } @@ -138,11 +137,11 @@ void Battlenet::AuthComplete::Write() for (size_t i = 0; i < Modules.size(); ++i) { ModuleInfo& info = Modules[i]; - _stream.WriteBytes(info.AuthString.c_str(), 4); - _stream.WriteFourCC(info.Locale.c_str()); + _stream.WriteBytes(info.Type.c_str(), 4); + _stream.WriteFourCC(info.Region.c_str()); _stream.WriteBytes(info.ModuleId, 32); - _stream.Write(info.BlobSize, 10); - _stream.WriteBytes(info.Blob, info.BlobSize); + _stream.Write(info.DataSize, 10); + _stream.WriteBytes(info.Data, info.DataSize); } _stream.Write(PingTimeout + std::numeric_limits::min(), 32); @@ -165,11 +164,11 @@ void Battlenet::AuthComplete::Write() if (!Modules.empty()) { ModuleInfo& info = Modules[0]; - _stream.WriteBytes(info.AuthString.c_str(), 4); - _stream.WriteFourCC(info.Locale.c_str()); + _stream.WriteBytes(info.Type.c_str(), 4); + _stream.WriteFourCC(info.Region.c_str()); _stream.WriteBytes(info.ModuleId, 32); - _stream.Write(info.BlobSize, 10); - _stream.WriteBytes(info.Blob, info.BlobSize); + _stream.Write(info.DataSize, 10); + _stream.WriteBytes(info.Data, info.DataSize); } _stream.Write(ErrorType, 2); diff --git a/src/server/authserver/Server/BattlenetPackets.h b/src/server/authserver/Server/BattlenetPackets.h index 86dcb99a4da..3b02c0c602a 100644 --- a/src/server/authserver/Server/BattlenetPackets.h +++ b/src/server/authserver/Server/BattlenetPackets.h @@ -58,7 +58,12 @@ namespace Battlenet bool operator<(PacketHeader const& right) const { - return Opcode < right.Opcode || Channel < right.Channel; + if (Opcode < right.Opcode) + return true; + if (Opcode > right.Opcode) + return false; + + return Channel < right.Channel; } bool operator==(PacketHeader const& right) const @@ -133,15 +138,6 @@ namespace Battlenet std::string Login; }; - struct ModuleInfo - { - std::string AuthString; - std::string Locale; - uint8 ModuleId[32]; - uint32 BlobSize; - uint8* Blob; - }; - class ProofRequest final : public ServerPacket { public: @@ -150,7 +146,7 @@ namespace Battlenet void Write() override; std::string ToString() const override; - std::vector Modules; + std::vector Modules; }; class ProofResponse final : public ClientPacket diff --git a/src/server/authserver/Server/BattlenetSocket.cpp b/src/server/authserver/Server/BattlenetSocket.cpp index 04005e30878..edd73080270 100644 --- a/src/server/authserver/Server/BattlenetSocket.cpp +++ b/src/server/authserver/Server/BattlenetSocket.cpp @@ -25,6 +25,32 @@ bool Battlenet::Socket::HandleAuthChallenge(PacketHeader& header, BitStream& pac AuthChallenge info(header, packet); info.Read(); + printf("%s\n", info.ToString().c_str()); + + if (info.Program != "WoW") + { + AuthComplete complete; + complete.SetAuthResult(AUTH_INVALID_PROGRAM); + Send(complete); + return true; + } + + if (!sBattlenetMgr->HasPlatform(info.Platform)) + { + AuthComplete complete; + complete.SetAuthResult(AUTH_INVALID_OS); + Send(complete); + return true; + } + + if (!sBattlenetMgr->HasPlatform(info.Locale)) + { + AuthComplete complete; + complete.SetAuthResult(AUTH_UNSUPPORTED_LANGUAGE); + Send(complete); + return true; + } + for (Component const& component : info.Components) { if (!sBattlenetMgr->HasComponent(&component)) @@ -34,7 +60,7 @@ bool Battlenet::Socket::HandleAuthChallenge(PacketHeader& header, BitStream& pac complete.SetAuthResult(AUTH_INVALID_PROGRAM); else if (!sBattlenetMgr->HasPlatform(component.Platform)) complete.SetAuthResult(AUTH_INVALID_OS); - else if (!sBattlenetMgr->HasBuild(component.Build)) + else complete.SetAuthResult(AUTH_REGION_BAD_VERSION); Send(complete); @@ -42,9 +68,9 @@ bool Battlenet::Socket::HandleAuthChallenge(PacketHeader& header, BitStream& pac } } - printf("%s\n", info.ToString().c_str()); - _accountName = info.Login; + _locale = info.Locale; + _os = info.Platform; ProofRequest request; Send(request); @@ -101,6 +127,8 @@ void Battlenet::Socket::OnRead() header.Opcode = packet.Read(6); if (packet.Read(1)) _currentChannel = header.Channel = packet.Read(4); + else + header.Channel = _currentChannel; printf("Battlenet::Socket::OnRead %s\n", header.ToString().c_str()); std::map::const_iterator itr = Handlers.find(header); diff --git a/src/server/authserver/Server/BattlenetSocket.h b/src/server/authserver/Server/BattlenetSocket.h index 7507f090a7f..b4db6c46251 100644 --- a/src/server/authserver/Server/BattlenetSocket.h +++ b/src/server/authserver/Server/BattlenetSocket.h @@ -48,6 +48,8 @@ namespace Battlenet uint32 _currentChannel; std::string _accountName; + std::string _locale; + std::string _os; PacketCrypt _crypt; }; diff --git a/src/server/shared/Utilities/Util.cpp b/src/server/shared/Utilities/Util.cpp index f2a6f1b7622..004335422c0 100644 --- a/src/server/shared/Utilities/Util.cpp +++ b/src/server/shared/Utilities/Util.cpp @@ -547,3 +547,28 @@ std::string ByteArrayToHexStr(uint8 const* bytes, uint32 arrayLen, bool reverse return ss.str(); } + +void HexStrToByteArray(std::string const& str, uint8* out, bool reverse /*= false*/) +{ + // string must have even number of characters + if (str.length() & 1) + return; + + int32 init = 0; + int32 end = str.length(); + int8 op = 1; + + if (reverse) + { + init = str.length() - 2; + end = -1; + op = -1; + } + + uint32 j = 0; + for (int32 i = init; i != end; i += 2 * op) + { + char buffer[3] = { str[i], str[i + 1], '\0' }; + out[j++] = strtoul(buffer, NULL, 16); + } +} diff --git a/src/server/shared/Utilities/Util.h b/src/server/shared/Utilities/Util.h index 236670e5cf1..d1cfeadff64 100644 --- a/src/server/shared/Utilities/Util.h +++ b/src/server/shared/Utilities/Util.h @@ -355,6 +355,7 @@ std::string GetAddressString(ACE_INET_Addr const& addr); uint32 CreatePIDFile(const std::string& filename); std::string ByteArrayToHexStr(uint8 const* bytes, uint32 length, bool reverse = false); +void HexStrToByteArray(std::string const& str, uint8* out, bool reverse = false); #endif //handler for operations on large flags -- cgit v1.2.3 From 2654fd67f32ef8b10cb0f9fcdc5033de62ca9a78 Mon Sep 17 00:00:00 2001 From: Shauren Date: Fri, 2 May 2014 13:30:41 +0200 Subject: Core/Battle.net: Refactored FCC writing --- src/server/authserver/Server/BattlenetBitStream.h | 9 +++++++-- src/server/authserver/Server/BattlenetManager.cpp | 1 - src/server/authserver/Server/BattlenetManager.h | 2 +- src/server/authserver/Server/BattlenetPackets.cpp | 10 +++++----- 4 files changed, 13 insertions(+), 9 deletions(-) (limited to 'src') diff --git a/src/server/authserver/Server/BattlenetBitStream.h b/src/server/authserver/Server/BattlenetBitStream.h index d372e0933c2..9d5f4c85f0d 100644 --- a/src/server/authserver/Server/BattlenetBitStream.h +++ b/src/server/authserver/Server/BattlenetBitStream.h @@ -138,10 +138,15 @@ namespace Battlenet } //WriteFloat - void WriteFourCC(char const* fcc) + void WriteFourCC(std::string const& fcc) { - uint32 intVal = *(uint32*)fcc; + uint32 intVal = *(uint32*)fcc.c_str(); + size_t len = fcc.length(); EndianConvertReverse(intVal); + // Add padding + while (len++ < 4) + intVal >>= 8; + Write(intVal, 32); } diff --git a/src/server/authserver/Server/BattlenetManager.cpp b/src/server/authserver/Server/BattlenetManager.cpp index a43512e612e..f8ff5d8989e 100644 --- a/src/server/authserver/Server/BattlenetManager.cpp +++ b/src/server/authserver/Server/BattlenetManager.cpp @@ -64,7 +64,6 @@ void BattlenetMgr::LoadModules() Field* fields = result->Fetch(); Battlenet::ModuleInfo* module = new Battlenet::ModuleInfo(); module->Type = fields[2].GetString(); - module->Region.assign("\0\0EU", 4); HexStrToByteArray(fields[0].GetString(), module->ModuleId); std::string data = fields[4].GetString(); module->DataSize = data.length() / 2; diff --git a/src/server/authserver/Server/BattlenetManager.h b/src/server/authserver/Server/BattlenetManager.h index 9fceb973770..08c98645ebd 100644 --- a/src/server/authserver/Server/BattlenetManager.h +++ b/src/server/authserver/Server/BattlenetManager.h @@ -52,7 +52,7 @@ namespace Battlenet struct ModuleInfo { - ModuleInfo() : DataSize(0), Data(nullptr) { } + ModuleInfo() : Region("EU"), DataSize(0), Data(nullptr) { } ModuleInfo(ModuleInfo const& right) : Type(right.Type), Region(right.Region), DataSize(right.DataSize), Data(nullptr) { memcpy(ModuleId, right.ModuleId, 32); diff --git a/src/server/authserver/Server/BattlenetPackets.cpp b/src/server/authserver/Server/BattlenetPackets.cpp index 68a602d8598..bcb4f4e4898 100644 --- a/src/server/authserver/Server/BattlenetPackets.cpp +++ b/src/server/authserver/Server/BattlenetPackets.cpp @@ -67,7 +67,7 @@ std::string Battlenet::AuthChallenge::ToString() const std::ostringstream stream; stream << "Battlenet::AuthChallenge Program: " << Program << ", Platform: " << Platform << ", Locale: " << Locale; for (Component const& component : Components) - stream << std::endl << "Battlenet::AuthChallenge::Component Program: " << component.Program << ", Platform: " << component.Platform << ", Build: " << component.Build; + stream << std::endl << "Battlenet::Component Program: " << component.Program << ", Platform: " << component.Platform << ", Build: " << component.Build; if (!Login.empty()) stream << std::endl << "Battlenet::AuthChallenge Login: " << Login; @@ -81,7 +81,7 @@ void Battlenet::ProofRequest::Write() for (ModuleInfo const* info : Modules) { _stream.WriteBytes(info->Type.c_str(), 4); - _stream.WriteFourCC(info->Region.c_str()); + _stream.WriteFourCC(info->Region); _stream.WriteBytes(info->ModuleId, 32); _stream.Write(info->DataSize, 10); _stream.WriteBytes(info->Data, info->DataSize); @@ -93,7 +93,7 @@ std::string Battlenet::ProofRequest::ToString() const std::ostringstream stream; stream << "Battlenet::ProofRequest modules " << Modules.size(); for (ModuleInfo const* module : Modules) - stream << std::endl << "Locale " << module->Region << "ModuleId " << ByteArrayToHexStr(module->ModuleId, 32) << "BlobSize " << module->DataSize; + stream << std::endl << "Battlenet::ModuleInfo Locale " << module->Region.c_str() << ", ModuleId " << ByteArrayToHexStr(module->ModuleId, 32) << ", BlobSize " << module->DataSize; return stream.str(); } @@ -138,7 +138,7 @@ void Battlenet::AuthComplete::Write() { ModuleInfo& info = Modules[i]; _stream.WriteBytes(info.Type.c_str(), 4); - _stream.WriteFourCC(info.Region.c_str()); + _stream.WriteFourCC(info.Region); _stream.WriteBytes(info.ModuleId, 32); _stream.Write(info.DataSize, 10); _stream.WriteBytes(info.Data, info.DataSize); @@ -165,7 +165,7 @@ void Battlenet::AuthComplete::Write() { ModuleInfo& info = Modules[0]; _stream.WriteBytes(info.Type.c_str(), 4); - _stream.WriteFourCC(info.Region.c_str()); + _stream.WriteFourCC(info.Region); _stream.WriteBytes(info.ModuleId, 32); _stream.Write(info.DataSize, 10); _stream.WriteBytes(info.Data, info.DataSize); -- cgit v1.2.3 From b2180ef5b849bd81a6b85a99fa9391dd6e20d105 Mon Sep 17 00:00:00 2001 From: Shauren Date: Fri, 2 May 2014 13:31:23 +0200 Subject: Core/Cryptography: Added class to generate SHA256 hashes --- src/server/shared/Cryptography/SHA256.cpp | 66 +++++++++++++++++++++++++++++++ src/server/shared/Cryptography/SHA256.h | 49 +++++++++++++++++++++++ 2 files changed, 115 insertions(+) create mode 100644 src/server/shared/Cryptography/SHA256.cpp create mode 100644 src/server/shared/Cryptography/SHA256.h (limited to 'src') diff --git a/src/server/shared/Cryptography/SHA256.cpp b/src/server/shared/Cryptography/SHA256.cpp new file mode 100644 index 00000000000..b58c7db40c6 --- /dev/null +++ b/src/server/shared/Cryptography/SHA256.cpp @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2008-2014 TrinityCore + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ + +#include "SHA256.h" +#include "BigNumber.h" +#include + +SHA256Hash::SHA256Hash() +{ + SHA256_Init(&mC); + memset(mDigest, 0, SHA256_DIGEST_LENGTH * sizeof(uint8)); +} + +SHA256Hash::~SHA256Hash() +{ + SHA256_Init(&mC); +} + +void SHA256Hash::UpdateData(const uint8 *dta, int len) +{ + SHA256_Update(&mC, dta, len); +} + +void SHA256Hash::UpdateData(const std::string &str) +{ + UpdateData((uint8 const*)str.c_str(), str.length()); +} + +void SHA256Hash::UpdateBigNumbers(BigNumber* bn0, ...) +{ + va_list v; + BigNumber* bn; + + va_start(v, bn0); + bn = bn0; + while (bn) + { + UpdateData(bn->AsByteArray().get(), bn->GetNumBytes()); + bn = va_arg(v, BigNumber*); + } + va_end(v); +} + +void SHA256Hash::Initialize() +{ + SHA256_Init(&mC); +} + +void SHA256Hash::Finalize(void) +{ + SHA256_Final(mDigest, &mC); +} diff --git a/src/server/shared/Cryptography/SHA256.h b/src/server/shared/Cryptography/SHA256.h new file mode 100644 index 00000000000..78b3666dca8 --- /dev/null +++ b/src/server/shared/Cryptography/SHA256.h @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2008-2014 TrinityCore + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ + +#ifndef SHA256_h__ +#define SHA256_h__ + +#include "Define.h" +#include +#include + +class BigNumber; + +class SHA256Hash +{ + public: + SHA256Hash(); + ~SHA256Hash(); + + void UpdateBigNumbers(BigNumber* bn0, ...); + + void UpdateData(const uint8 *dta, int len); + void UpdateData(const std::string &str); + + void Initialize(); + void Finalize(); + + uint8 *GetDigest(void) { return mDigest; }; + int GetLength(void) const { return SHA256_DIGEST_LENGTH; }; + + private: + SHA256_CTX mC; + uint8 mDigest[SHA256_DIGEST_LENGTH]; +}; + +#endif // SHA256_h__ -- cgit v1.2.3 From 769fadd104978b8a45995dc652539b2c619b54f1 Mon Sep 17 00:00:00 2001 From: Shauren Date: Sun, 4 May 2014 00:59:24 +0200 Subject: Core/Battle.net * Extended AuthResult enum * Implemented WriteString in BitStream * Fixed HexStrToByteArray in reverse mode --- src/server/authserver/Authentication/AuthCodes.h | 2 ++ src/server/authserver/Server/BattlenetBitStream.h | 8 ++++++-- src/server/shared/Utilities/Util.cpp | 2 +- 3 files changed, 9 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/server/authserver/Authentication/AuthCodes.h b/src/server/authserver/Authentication/AuthCodes.h index 12c2a810abb..158029bcefc 100644 --- a/src/server/authserver/Authentication/AuthCodes.h +++ b/src/server/authserver/Authentication/AuthCodes.h @@ -75,6 +75,8 @@ namespace Battlenet enum AuthResult { AUTH_OK = 0, + AUTH_INTERNAL_ERROR = 100, + AUTH_CORRUPTED_MODULE = 102, AUTH_BAD_SERVER_PROOF = 103, AUTH_UNKNOWN_ACCOUNT = 104, AUTH_CLOSED = 105, diff --git a/src/server/authserver/Server/BattlenetBitStream.h b/src/server/authserver/Server/BattlenetBitStream.h index 9d5f4c85f0d..bff1bffb3ab 100644 --- a/src/server/authserver/Server/BattlenetBitStream.h +++ b/src/server/authserver/Server/BattlenetBitStream.h @@ -61,7 +61,7 @@ namespace Battlenet _writePos = (_writePos + 7) & ~7; } - std::string ReadString(uint32 bitCount, uint32 baseLength = 0) + std::string ReadString(uint32 bitCount, int32 baseLength = 0) { uint32 len = Read(bitCount) + baseLength; AlignToNextByte(); @@ -120,7 +120,11 @@ namespace Battlenet return ret; } - //WriteString + void WriteString(std::string const& str, uint32 bitCount, int32 baseLength = 0) + { + Write(str.length() + baseLength, bitCount); + WriteBytes(str.c_str(), str.length()); + } template void WriteBytes(T* data, uint32 count) diff --git a/src/server/shared/Utilities/Util.cpp b/src/server/shared/Utilities/Util.cpp index 004335422c0..05d5d2c0749 100644 --- a/src/server/shared/Utilities/Util.cpp +++ b/src/server/shared/Utilities/Util.cpp @@ -561,7 +561,7 @@ void HexStrToByteArray(std::string const& str, uint8* out, bool reverse /*= fals if (reverse) { init = str.length() - 2; - end = -1; + end = -2; op = -1; } -- cgit v1.2.3 From f0d6f87138a915825f9986fae80ccd1fb72c154c Mon Sep 17 00:00:00 2001 From: Shauren Date: Sun, 4 May 2014 11:49:32 +0200 Subject: Core/Battle.net: Fixed encryption --- src/server/authserver/Server/BattlenetPacketCrypt.cpp | 17 ++++++++++------- src/server/shared/Cryptography/HmacHash.cpp | 2 +- 2 files changed, 11 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/src/server/authserver/Server/BattlenetPacketCrypt.cpp b/src/server/authserver/Server/BattlenetPacketCrypt.cpp index 10aa684e10a..31fcfdd930a 100644 --- a/src/server/authserver/Server/BattlenetPacketCrypt.cpp +++ b/src/server/authserver/Server/BattlenetPacketCrypt.cpp @@ -26,14 +26,17 @@ Battlenet::PacketCrypt::PacketCrypt() : ::PacketCrypt(SHA256_DIGEST_LENGTH) void Battlenet::PacketCrypt::Init(BigNumber* K) { uint8 ServerEncryptionKey[SEED_KEY_SIZE] = { 0x68, 0xE0, 0xC7, 0x2E, 0xDD, 0xD6, 0xD2, 0xF3, 0x1E, 0x5A, 0xB1, 0x55, 0xB1, 0x8B, 0x63, 0x1E }; - HmacHash serverEncryptHmac(SEED_KEY_SIZE, ServerEncryptionKey, EVP_sha256(), SHA256_DIGEST_LENGTH); - uint8 *encryptHash = serverEncryptHmac.ComputeHash(K); - uint8 ClientDecryptionKey[SEED_KEY_SIZE] = { 0xDE, 0xA9, 0x65, 0xAE, 0x54, 0x3A, 0x1E, 0x93, 0x9E, 0x69, 0x0C, 0xAA, 0x68, 0xDE, 0x78, 0x39 }; - HmacHash clientDecryptHmac(SEED_KEY_SIZE, ClientDecryptionKey, EVP_sha256(), SHA256_DIGEST_LENGTH); - uint8 *decryptHash = clientDecryptHmac.ComputeHash(K); - _clientDecrypt.Init(decryptHash); - _serverEncrypt.Init(encryptHash); + HmacHash serverEncryptHmac(K->GetNumBytes(), K->AsByteArray().get(), EVP_sha256(), SHA256_DIGEST_LENGTH); + serverEncryptHmac.UpdateData(ServerEncryptionKey, SEED_KEY_SIZE); + serverEncryptHmac.Finalize(); + + HmacHash clientDecryptHmac(K->GetNumBytes(), K->AsByteArray().get(), EVP_sha256(), SHA256_DIGEST_LENGTH); + clientDecryptHmac.UpdateData(ClientDecryptionKey, SEED_KEY_SIZE); + clientDecryptHmac.Finalize(); + + _clientDecrypt.Init(clientDecryptHmac.GetDigest()); + _serverEncrypt.Init(serverEncryptHmac.GetDigest()); _initialized = true; } diff --git a/src/server/shared/Cryptography/HmacHash.cpp b/src/server/shared/Cryptography/HmacHash.cpp index 7a365ade457..71fc362ae5d 100644 --- a/src/server/shared/Cryptography/HmacHash.cpp +++ b/src/server/shared/Cryptography/HmacHash.cpp @@ -20,7 +20,7 @@ #include "BigNumber.h" #include "Common.h" -HmacHash::HmacHash(uint32 len, uint8 *seed, EVP_MD const* hasher, uint32 digestLength) +HmacHash::HmacHash(uint32 len, uint8 *seed, EVP_MD const* hasher, uint32 digestLength) : _digestLength(digestLength) { HMAC_CTX_init(&_ctx); HMAC_Init_ex(&_ctx, seed, len, hasher, NULL); -- cgit v1.2.3 From d9f1d6466dbb16fdbc792fe42a92c18ec29dfb48 Mon Sep 17 00:00:00 2001 From: Shauren Date: Tue, 6 May 2014 23:43:29 +0200 Subject: Core/Battle.net: Implemented authserver --- sql/base/auth_database.sql | 144 +++- sql/updates/auth/2014_xx_xx_00_auth_battlenet.sql | 144 ++++ src/server/authserver/Realms/RealmList.cpp | 22 +- src/server/authserver/Realms/RealmList.h | 10 +- src/server/authserver/Server/AuthSocket.cpp | 2 +- src/server/authserver/Server/BattlenetBitStream.h | 26 +- src/server/authserver/Server/BattlenetManager.h | 8 + src/server/authserver/Server/BattlenetPackets.cpp | 165 ++++- src/server/authserver/Server/BattlenetPackets.h | 139 +++- src/server/authserver/Server/BattlenetSocket.cpp | 762 +++++++++++++++++++-- src/server/authserver/Server/BattlenetSocket.h | 56 +- src/server/game/Accounts/AccountMgr.cpp | 81 +-- src/server/game/Accounts/AccountMgr.h | 6 +- src/server/game/Accounts/BattlenetAccountMgr.cpp | 133 ++++ src/server/game/Accounts/BattlenetAccountMgr.h | 45 ++ src/server/scripts/Commands/cs_account.cpp | 60 +- src/server/scripts/Commands/cs_ban.cpp | 6 +- src/server/scripts/Commands/cs_character.cpp | 2 +- src/server/scripts/Commands/cs_lookup.cpp | 3 +- src/server/scripts/Commands/cs_rbac.cpp | 2 +- .../Database/Implementation/LoginDatabase.cpp | 2 +- src/server/shared/Utilities/Util.cpp | 11 + src/server/shared/Utilities/Util.h | 1 + src/server/worldserver/RemoteAccess/RASocket.cpp | 6 +- 24 files changed, 1657 insertions(+), 179 deletions(-) create mode 100644 sql/updates/auth/2014_xx_xx_00_auth_battlenet.sql create mode 100644 src/server/game/Accounts/BattlenetAccountMgr.cpp create mode 100644 src/server/game/Accounts/BattlenetAccountMgr.h (limited to 'src') diff --git a/sql/base/auth_database.sql b/sql/base/auth_database.sql index 0a989cdcb92..f610bac2b6a 100644 --- a/sql/base/auth_database.sql +++ b/sql/base/auth_database.sql @@ -136,6 +136,146 @@ LOCK TABLES `autobroadcast` WRITE; /*!40000 ALTER TABLE `autobroadcast` ENABLE KEYS */; UNLOCK TABLES; +-- +-- Table structure for table `battlenet_account_bans` +-- + +DROP TABLE IF EXISTS `battlenet_account_bans`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `battlenet_account_bans` ( + `id` int(10) unsigned NOT NULL DEFAULT '0' COMMENT 'Account id', + `bandate` int(10) unsigned NOT NULL DEFAULT '0', + `unbandate` int(10) unsigned NOT NULL DEFAULT '0', + `bannedby` varchar(50) NOT NULL, + `banreason` varchar(255) NOT NULL, + `active` tinyint(3) unsigned NOT NULL DEFAULT '1', + PRIMARY KEY (`id`,`bandate`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Ban List'; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `battlenet_account_bans` +-- + +LOCK TABLES `battlenet_account_bans` WRITE; +/*!40000 ALTER TABLE `battlenet_account_bans` DISABLE KEYS */; +/*!40000 ALTER TABLE `battlenet_account_bans` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `battlenet_accounts` +-- + +DROP TABLE IF EXISTS `battlenet_accounts`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `battlenet_accounts` ( + `id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT 'Identifier', + `email` varchar(320) NOT NULL, + `sha_pass_hash` varchar(64) NOT NULL DEFAULT '', + `v` varchar(256) NOT NULL DEFAULT '', + `s` varchar(64) 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', + `locked` tinyint(3) unsigned NOT NULL DEFAULT '0', + `lock_country` varchar(2) NOT NULL DEFAULT '00', + `last_login` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00', + `online` tinyint(3) unsigned NOT NULL DEFAULT '0', + `locale` tinyint(3) unsigned NOT NULL DEFAULT '0', + `os` varchar(3) NOT NULL DEFAULT '', + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8 COMMENT='Account System'; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- Table structure for table `battlenet_components` +-- + +DROP TABLE IF EXISTS `battlenet_components`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `battlenet_components` ( + `Program` varchar(4) NOT NULL, + `Platform` varchar(4) NOT NULL, + `Build` int(11) unsigned NOT NULL, + PRIMARY KEY (`Program`,`Platform`,`Build`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `battlenet_components` +-- + +LOCK TABLES `battlenet_components` WRITE; +/*!40000 ALTER TABLE `battlenet_components` DISABLE KEYS */; +INSERT INTO `battlenet_components` VALUES +('Bnet','Cmp1',3), +('Bnet','Win',21719), +('Bnet','Win',26487), +('Bnet','Wn64',26487), +('Tool','Win',1569), +('Tool','Win',2736), +('WoW','base',12340), +('WoW','base',15595), +('WoW','enGB',12340), +('WoW','enGB',15595), +('WoW','enUS',12340), +('WoW','enUS',15595), +('WoW','Win',12340), +('WoW','Win',15595), +('WoW','Wn64',15595); +/*!40000 ALTER TABLE `battlenet_components` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `battlenet_modules` +-- + +DROP TABLE IF EXISTS `battlenet_modules`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `battlenet_modules` ( + `Hash` varchar(64) NOT NULL, + `Name` varchar(64) NOT NULL DEFAULT '', + `Type` varchar(8) NOT NULL, + `System` varchar(8) NOT NULL, + `Data` text, + PRIMARY KEY (`Hash`), + UNIQUE KEY `uk_name_type_system` (`Name`,`Type`,`System`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `battlenet_modules` +-- + +LOCK TABLES `battlenet_modules` WRITE; +/*!40000 ALTER TABLE `battlenet_modules` DISABLE KEYS */; +INSERT INTO `battlenet_modules` VALUES +('19c91b68752b7826df498bf73aca1103c86962a9a55a0a7033e5ad895f4d927c','Password','auth','Mc64',NULL), +('1af5418a448f8ad05451e3f7dbb2d9af9cb13458eea2368ebfc539476b954f1c','RiskFingerprint','auth','Mc64',NULL), +('207640724f4531d3b2a21532224d1486e8c4d2d805170381cbc3093264157960','SelectGameAccount','auth','Mac',NULL), +('2e6d53adab37a41542b38e01f62cd365eab8805ed0de73c307cc6d9d1dfe478c','Password','auth','Win',NULL), +('36b27cd911b33c61730a8b82c8b2495fd16e8024fc3b2dde08861c77a852941c','Thumbprint','auth','Win','E716F4F0A01EB9C032A6C1393356A4F766F067949D71023C0CFC0613718966EF814E65CC6EE70C432A7F8AFD8A062B52603A2697E851D231D72C0277614181D713369B1E8E4BEEAB72045A9AAD45F319DB918ECDDB83C8EF8B7510600D391D45E7FEC0BEEAE904A5F9FA620F1CCDAD699D84A4739CE669B5A551831E396214E13B4C88F573F5CDC784CD01530C086B674C03BEB66403A0F87ED17ABBB403DE54CF31BE828A20C566C22E4D4263AA77220B0644D99245345BCAC276EA06925EB984D664725C3CB757140AFE12E27CB996F17159B1057E9B58B78BBB5A139C9FF6215A0D250B75FC9DD435655DDEADCD6CFD84800792C146B3633188ECEB53D2038C185E0BD51A9E6C70FD38ADF530F8DF50FB62053C5E894897AB7DD65C7AC80665F18E7989BE6E30F15E939751123D6D8A44F033175301D15AAAD2AEA06FAC60BA4065846AE938F32B1CB15F16DC0E76792A7332346896048065D17C059899E1D2300E402BD0EA74265DA6A42B1C854E2470D7B21AE4A2DAE90E602A759B2CA0EE610B50D5389DB89335D5451FE76DD85B09FD5297D6F9EFB6C34CE885007F7DF20D6A524E0C3E772FA04B3DD2E014D3A337A790943DAD523CBB5453F4FDF8E74DFE361BD5F25AB31952B478148B570DF5762643F32B994FEC99A747E4A265A66EE84A53509EC285C84679606049314FC526C61B537AC8061C788F8B86F52208'), +('393ca8d75aff6f04f79532cf95a88b91e5743bc59121520ac31fc4508019fe60','Token','auth','Mac',NULL), +('3c2f63e5949aa6fd6cf330b109ca5b9adcd215beac846b7462ed3aa01d5ad6bb','Password','auth','Mac',NULL), +('52e2978db6468dfade7c61da89513f443c9225692b5085fbe956749870993703','SelectGameAccount','auth','Mc64',NULL), +('548b5ef9e0dd5c2f89f59c3e0979249b27505c51f0c77d2b27133726eaee0ad0','Thumbprint','auth','Mac','E716F4F0A01EB9C032A6C1393356A4F766F067949D71023C0CFC0613718966EF814E65CC6EE70C432A7F8AFD8A062B52603A2697E851D231D72C0277614181D713369B1E8E4BEEAB72045A9AAD45F319DB918ECDDB83C8EF8B7510600D391D45E7FEC0BEEAE904A5F9FA620F1CCDAD699D84A4739CE669B5A551831E396214E13B4C88F573F5CDC784CD01530C086B674C03BEB66403A0F87ED17ABBB403DE54CF31BE828A20C566C22E4D4263AA77220B0644D99245345BCAC276EA06925EB984D664725C3CB757140AFE12E27CB996F17159B1057E9B58B78BBB5A139C9FF6215A0D250B75FC9DD435655DDEADCD6CFD84800792C146B3633188ECEB53D2038C185E0BD51A9E6C70FD38ADF530F8DF50FB62053C5E894897AB7DD65C7AC80665F18E7989BE6E30F15E939751123D6D8A44F033175301D15AAAD2AEA06FAC60BA4065846AE938F32B1CB15F16DC0E76792A7332346896048065D17C059899E1D2300E402BD0EA74265DA6A42B1C854E2470D7B21AE4A2DAE90E602A759B2CA0EE610B50D5389DB89335D5451FE76DD85B09FD5297D6F9EFB6C34CE885007F7DF20D6A524E0C3E772FA04B3DD2E014D3A337A790943DAD523CBB5453F4FDF8E74DFE361BD5F25AB31952B478148B570DF5762643F32B994FEC99A747E4A265A66EE84A53509EC285C84679606049314FC526C61B537AC8061C788F8B86F52208'), +('5e298e530698af905e1247e51ef0b109b352ac310ce7802a1f63613db980ed17','RiskFingerprint','auth','Win',NULL), +('851c1d2ef926e9b9a345a460874e65517195129b9e3bdec7cc77710fa0b1fad6','Password','auth','Wn64',NULL), +('894d25d3219d97d085ea5a8b98e66df5bd9f460ec6f104455246a12b8921409d','SelectGameAccount','auth','Wn64',NULL), +('8c43bda10be33a32abbc09fb2279126c7f5953336391276cff588565332fcd40','RiskFingerprint','auth','Wn64',NULL), +('a1edab845d9e13e9c84531369be2f61b930a37c8e7a9c66d11ef8963380e178a','Token','auth','Mc64',NULL), +('a330f388b6687f8a42fe8fbb592a3df724b20b65fb0989342bb8261f2f452318','Token','auth','Wn64',NULL), +('abc6bb719a73ec1055296001910e26afa561f701ad9995b1ecd7f55f9d3ca37c','SelectGameAccount','auth','Win',NULL), +('b37136b39add83cfdbafa81857de3dd8f15b34e0135ec6cd9c3131d3a578d8c2','Thumbprint','auth','Mc64','E716F4F0A01EB9C032A6C1393356A4F766F067949D71023C0CFC0613718966EF814E65CC6EE70C432A7F8AFD8A062B52603A2697E851D231D72C0277614181D713369B1E8E4BEEAB72045A9AAD45F319DB918ECDDB83C8EF8B7510600D391D45E7FEC0BEEAE904A5F9FA620F1CCDAD699D84A4739CE669B5A551831E396214E13B4C88F573F5CDC784CD01530C086B674C03BEB66403A0F87ED17ABBB403DE54CF31BE828A20C566C22E4D4263AA77220B0644D99245345BCAC276EA06925EB984D664725C3CB757140AFE12E27CB996F17159B1057E9B58B78BBB5A139C9FF6215A0D250B75FC9DD435655DDEADCD6CFD84800792C146B3633188ECEB53D2038C185E0BD51A9E6C70FD38ADF530F8DF50FB62053C5E894897AB7DD65C7AC80665F18E7989BE6E30F15E939751123D6D8A44F033175301D15AAAD2AEA06FAC60BA4065846AE938F32B1CB15F16DC0E76792A7332346896048065D17C059899E1D2300E402BD0EA74265DA6A42B1C854E2470D7B21AE4A2DAE90E602A759B2CA0EE610B50D5389DB89335D5451FE76DD85B09FD5297D6F9EFB6C34CE885007F7DF20D6A524E0C3E772FA04B3DD2E014D3A337A790943DAD523CBB5453F4FDF8E74DFE361BD5F25AB31952B478148B570DF5762643F32B994FEC99A747E4A265A66EE84A53509EC285C84679606049314FC526C61B537AC8061C788F8B86F52208'), +('c0f38d05aa1b83065e839c9bd96c831e9f7e42477085138752657a6a9bb9c520','RiskFingerprint','auth','Mac',NULL), +('c3a1ac0694979e709c3b5486927e558af1e2be02ca96e5615c5a65aacc829226','Thumbprint','auth','Wn64','E716F4F0A01EB9C032A6C1393356A4F766F067949D71023C0CFC0613718966EF814E65CC6EE70C432A7F8AFD8A062B52603A2697E851D231D72C0277614181D713369B1E8E4BEEAB72045A9AAD45F319DB918ECDDB83C8EF8B7510600D391D45E7FEC0BEEAE904A5F9FA620F1CCDAD699D84A4739CE669B5A551831E396214E13B4C88F573F5CDC784CD01530C086B674C03BEB66403A0F87ED17ABBB403DE54CF31BE828A20C566C22E4D4263AA77220B0644D99245345BCAC276EA06925EB984D664725C3CB757140AFE12E27CB996F17159B1057E9B58B78BBB5A139C9FF6215A0D250B75FC9DD435655DDEADCD6CFD84800792C146B3633188ECEB53D2038C185E0BD51A9E6C70FD38ADF530F8DF50FB62053C5E894897AB7DD65C7AC80665F18E7989BE6E30F15E939751123D6D8A44F033175301D15AAAD2AEA06FAC60BA4065846AE938F32B1CB15F16DC0E76792A7332346896048065D17C059899E1D2300E402BD0EA74265DA6A42B1C854E2470D7B21AE4A2DAE90E602A759B2CA0EE610B50D5389DB89335D5451FE76DD85B09FD5297D6F9EFB6C34CE885007F7DF20D6A524E0C3E772FA04B3DD2E014D3A337A790943DAD523CBB5453F4FDF8E74DFE361BD5F25AB31952B478148B570DF5762643F32B994FEC99A747E4A265A66EE84A53509EC285C84679606049314FC526C61B537AC8061C788F8B86F52208'), +('fbe675a99fb5f4b7fb3eb5e5a22add91a4cabf83e3c5930c6659ad13c457ba18','Token','auth','Win',NULL); +/*!40000 ALTER TABLE `battlenet_modules` ENABLE KEYS */; +UNLOCK TABLES; + -- -- Table structure for table `ip2nation` -- @@ -390,6 +530,8 @@ CREATE TABLE `realmlist` ( `allowedSecurityLevel` tinyint(3) unsigned NOT NULL DEFAULT '0', `population` float unsigned NOT NULL DEFAULT '0', `gamebuild` int(10) unsigned NOT NULL DEFAULT '15595', + `Region` tinyint(3) unsigned NOT NULL DEFAULT '2', + `Battlegroup` tinyint(3) unsigned NOT NULL DEFAULT '1', PRIMARY KEY (`id`), UNIQUE KEY `idx_name` (`name`) ) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8 COMMENT='Realm System'; @@ -401,7 +543,7 @@ CREATE TABLE `realmlist` ( LOCK TABLES `realmlist` WRITE; /*!40000 ALTER TABLE `realmlist` DISABLE KEYS */; -INSERT INTO `realmlist` VALUES (1,'Trinity','127.0.0.1','127.0.0.1','255.255.255.0',8085,1,0,1,0,0,15595); +INSERT INTO `realmlist` VALUES (1,'Trinity','127.0.0.1','127.0.0.1','255.255.255.0',8085,1,0,1,0,0,15595,2,1); /*!40000 ALTER TABLE `realmlist` ENABLE KEYS */; UNLOCK TABLES; diff --git a/sql/updates/auth/2014_xx_xx_00_auth_battlenet.sql b/sql/updates/auth/2014_xx_xx_00_auth_battlenet.sql new file mode 100644 index 00000000000..141c21dde54 --- /dev/null +++ b/sql/updates/auth/2014_xx_xx_00_auth_battlenet.sql @@ -0,0 +1,144 @@ +ALTER TABLE `realmlist` + ADD `Region` tinyint(3) UNSIGNED NOT NULL DEFAULT 2 AFTER `gamebuild`, + ADD `Battlegroup` tinyint(3) UNSIGNED NOT NULL DEFAULT 0 AFTER `Region`; + +-- +-- Table structure for table `battlenet_account_bans` +-- + +DROP TABLE IF EXISTS `battlenet_account_bans`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `battlenet_account_bans` ( + `id` int(10) unsigned NOT NULL DEFAULT '0' COMMENT 'Account id', + `bandate` int(10) unsigned NOT NULL DEFAULT '0', + `unbandate` int(10) unsigned NOT NULL DEFAULT '0', + `bannedby` varchar(50) NOT NULL, + `banreason` varchar(255) NOT NULL, + `active` tinyint(3) unsigned NOT NULL DEFAULT '1', + PRIMARY KEY (`id`,`bandate`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Ban List'; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `battlenet_account_bans` +-- + +LOCK TABLES `battlenet_account_bans` WRITE; +/*!40000 ALTER TABLE `battlenet_account_bans` DISABLE KEYS */; +/*!40000 ALTER TABLE `battlenet_account_bans` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `battlenet_accounts` +-- + +DROP TABLE IF EXISTS `battlenet_accounts`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `battlenet_accounts` ( + `id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT 'Identifier', + `email` varchar(320) NOT NULL, + `sha_pass_hash` varchar(64) NOT NULL DEFAULT '', + `v` varchar(256) NOT NULL DEFAULT '', + `s` varchar(64) 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', + `locked` tinyint(3) unsigned NOT NULL DEFAULT '0', + `lock_country` varchar(2) NOT NULL DEFAULT '00', + `last_login` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00', + `online` tinyint(3) unsigned NOT NULL DEFAULT '0', + `locale` tinyint(3) unsigned NOT NULL DEFAULT '0', + `os` varchar(3) NOT NULL DEFAULT '', + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8 COMMENT='Account System'; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- Table structure for table `battlenet_components` +-- + +DROP TABLE IF EXISTS `battlenet_components`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `battlenet_components` ( + `Program` varchar(4) NOT NULL, + `Platform` varchar(4) NOT NULL, + `Build` int(11) unsigned NOT NULL, + PRIMARY KEY (`Program`,`Platform`,`Build`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `battlenet_components` +-- + +LOCK TABLES `battlenet_components` WRITE; +/*!40000 ALTER TABLE `battlenet_components` DISABLE KEYS */; +INSERT INTO `battlenet_components` VALUES +('Bnet','Cmp1',3), +('Bnet','Win',21719), +('Bnet','Win',26487), +('Bnet','Wn64',26487), +('Tool','Win',1569), +('Tool','Win',2736), +('WoW','base',12340), +('WoW','base',15595), +('WoW','enGB',12340), +('WoW','enGB',15595), +('WoW','enUS',12340), +('WoW','enUS',15595), +('WoW','Win',12340), +('WoW','Win',15595), +('WoW','Wn64',15595); +/*!40000 ALTER TABLE `battlenet_components` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `battlenet_modules` +-- + +DROP TABLE IF EXISTS `battlenet_modules`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `battlenet_modules` ( + `Hash` varchar(64) NOT NULL, + `Name` varchar(64) NOT NULL DEFAULT '', + `Type` varchar(8) NOT NULL, + `System` varchar(8) NOT NULL, + `Data` text, + PRIMARY KEY (`Hash`), + UNIQUE KEY `uk_name_type_system` (`Name`,`Type`,`System`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `battlenet_modules` +-- + +LOCK TABLES `battlenet_modules` WRITE; +/*!40000 ALTER TABLE `battlenet_modules` DISABLE KEYS */; +INSERT INTO `battlenet_modules` VALUES +('19c91b68752b7826df498bf73aca1103c86962a9a55a0a7033e5ad895f4d927c','Password','auth','Mc64',NULL), +('1af5418a448f8ad05451e3f7dbb2d9af9cb13458eea2368ebfc539476b954f1c','RiskFingerprint','auth','Mc64',NULL), +('207640724f4531d3b2a21532224d1486e8c4d2d805170381cbc3093264157960','SelectGameAccount','auth','Mac',NULL), +('2e6d53adab37a41542b38e01f62cd365eab8805ed0de73c307cc6d9d1dfe478c','Password','auth','Win',NULL), +('36b27cd911b33c61730a8b82c8b2495fd16e8024fc3b2dde08861c77a852941c','Thumbprint','auth','Win','E716F4F0A01EB9C032A6C1393356A4F766F067949D71023C0CFC0613718966EF814E65CC6EE70C432A7F8AFD8A062B52603A2697E851D231D72C0277614181D713369B1E8E4BEEAB72045A9AAD45F319DB918ECDDB83C8EF8B7510600D391D45E7FEC0BEEAE904A5F9FA620F1CCDAD699D84A4739CE669B5A551831E396214E13B4C88F573F5CDC784CD01530C086B674C03BEB66403A0F87ED17ABBB403DE54CF31BE828A20C566C22E4D4263AA77220B0644D99245345BCAC276EA06925EB984D664725C3CB757140AFE12E27CB996F17159B1057E9B58B78BBB5A139C9FF6215A0D250B75FC9DD435655DDEADCD6CFD84800792C146B3633188ECEB53D2038C185E0BD51A9E6C70FD38ADF530F8DF50FB62053C5E894897AB7DD65C7AC80665F18E7989BE6E30F15E939751123D6D8A44F033175301D15AAAD2AEA06FAC60BA4065846AE938F32B1CB15F16DC0E76792A7332346896048065D17C059899E1D2300E402BD0EA74265DA6A42B1C854E2470D7B21AE4A2DAE90E602A759B2CA0EE610B50D5389DB89335D5451FE76DD85B09FD5297D6F9EFB6C34CE885007F7DF20D6A524E0C3E772FA04B3DD2E014D3A337A790943DAD523CBB5453F4FDF8E74DFE361BD5F25AB31952B478148B570DF5762643F32B994FEC99A747E4A265A66EE84A53509EC285C84679606049314FC526C61B537AC8061C788F8B86F52208'), +('393ca8d75aff6f04f79532cf95a88b91e5743bc59121520ac31fc4508019fe60','Token','auth','Mac',NULL), +('3c2f63e5949aa6fd6cf330b109ca5b9adcd215beac846b7462ed3aa01d5ad6bb','Password','auth','Mac',NULL), +('52e2978db6468dfade7c61da89513f443c9225692b5085fbe956749870993703','SelectGameAccount','auth','Mc64',NULL), +('548b5ef9e0dd5c2f89f59c3e0979249b27505c51f0c77d2b27133726eaee0ad0','Thumbprint','auth','Mac','E716F4F0A01EB9C032A6C1393356A4F766F067949D71023C0CFC0613718966EF814E65CC6EE70C432A7F8AFD8A062B52603A2697E851D231D72C0277614181D713369B1E8E4BEEAB72045A9AAD45F319DB918ECDDB83C8EF8B7510600D391D45E7FEC0BEEAE904A5F9FA620F1CCDAD699D84A4739CE669B5A551831E396214E13B4C88F573F5CDC784CD01530C086B674C03BEB66403A0F87ED17ABBB403DE54CF31BE828A20C566C22E4D4263AA77220B0644D99245345BCAC276EA06925EB984D664725C3CB757140AFE12E27CB996F17159B1057E9B58B78BBB5A139C9FF6215A0D250B75FC9DD435655DDEADCD6CFD84800792C146B3633188ECEB53D2038C185E0BD51A9E6C70FD38ADF530F8DF50FB62053C5E894897AB7DD65C7AC80665F18E7989BE6E30F15E939751123D6D8A44F033175301D15AAAD2AEA06FAC60BA4065846AE938F32B1CB15F16DC0E76792A7332346896048065D17C059899E1D2300E402BD0EA74265DA6A42B1C854E2470D7B21AE4A2DAE90E602A759B2CA0EE610B50D5389DB89335D5451FE76DD85B09FD5297D6F9EFB6C34CE885007F7DF20D6A524E0C3E772FA04B3DD2E014D3A337A790943DAD523CBB5453F4FDF8E74DFE361BD5F25AB31952B478148B570DF5762643F32B994FEC99A747E4A265A66EE84A53509EC285C84679606049314FC526C61B537AC8061C788F8B86F52208'), +('5e298e530698af905e1247e51ef0b109b352ac310ce7802a1f63613db980ed17','RiskFingerprint','auth','Win',NULL), +('851c1d2ef926e9b9a345a460874e65517195129b9e3bdec7cc77710fa0b1fad6','Password','auth','Wn64',NULL), +('894d25d3219d97d085ea5a8b98e66df5bd9f460ec6f104455246a12b8921409d','SelectGameAccount','auth','Wn64',NULL), +('8c43bda10be33a32abbc09fb2279126c7f5953336391276cff588565332fcd40','RiskFingerprint','auth','Wn64',NULL), +('a1edab845d9e13e9c84531369be2f61b930a37c8e7a9c66d11ef8963380e178a','Token','auth','Mc64',NULL), +('a330f388b6687f8a42fe8fbb592a3df724b20b65fb0989342bb8261f2f452318','Token','auth','Wn64',NULL), +('abc6bb719a73ec1055296001910e26afa561f701ad9995b1ecd7f55f9d3ca37c','SelectGameAccount','auth','Win',NULL), +('b37136b39add83cfdbafa81857de3dd8f15b34e0135ec6cd9c3131d3a578d8c2','Thumbprint','auth','Mc64','E716F4F0A01EB9C032A6C1393356A4F766F067949D71023C0CFC0613718966EF814E65CC6EE70C432A7F8AFD8A062B52603A2697E851D231D72C0277614181D713369B1E8E4BEEAB72045A9AAD45F319DB918ECDDB83C8EF8B7510600D391D45E7FEC0BEEAE904A5F9FA620F1CCDAD699D84A4739CE669B5A551831E396214E13B4C88F573F5CDC784CD01530C086B674C03BEB66403A0F87ED17ABBB403DE54CF31BE828A20C566C22E4D4263AA77220B0644D99245345BCAC276EA06925EB984D664725C3CB757140AFE12E27CB996F17159B1057E9B58B78BBB5A139C9FF6215A0D250B75FC9DD435655DDEADCD6CFD84800792C146B3633188ECEB53D2038C185E0BD51A9E6C70FD38ADF530F8DF50FB62053C5E894897AB7DD65C7AC80665F18E7989BE6E30F15E939751123D6D8A44F033175301D15AAAD2AEA06FAC60BA4065846AE938F32B1CB15F16DC0E76792A7332346896048065D17C059899E1D2300E402BD0EA74265DA6A42B1C854E2470D7B21AE4A2DAE90E602A759B2CA0EE610B50D5389DB89335D5451FE76DD85B09FD5297D6F9EFB6C34CE885007F7DF20D6A524E0C3E772FA04B3DD2E014D3A337A790943DAD523CBB5453F4FDF8E74DFE361BD5F25AB31952B478148B570DF5762643F32B994FEC99A747E4A265A66EE84A53509EC285C84679606049314FC526C61B537AC8061C788F8B86F52208'), +('c0f38d05aa1b83065e839c9bd96c831e9f7e42477085138752657a6a9bb9c520','RiskFingerprint','auth','Mac',NULL), +('c3a1ac0694979e709c3b5486927e558af1e2be02ca96e5615c5a65aacc829226','Thumbprint','auth','Wn64','E716F4F0A01EB9C032A6C1393356A4F766F067949D71023C0CFC0613718966EF814E65CC6EE70C432A7F8AFD8A062B52603A2697E851D231D72C0277614181D713369B1E8E4BEEAB72045A9AAD45F319DB918ECDDB83C8EF8B7510600D391D45E7FEC0BEEAE904A5F9FA620F1CCDAD699D84A4739CE669B5A551831E396214E13B4C88F573F5CDC784CD01530C086B674C03BEB66403A0F87ED17ABBB403DE54CF31BE828A20C566C22E4D4263AA77220B0644D99245345BCAC276EA06925EB984D664725C3CB757140AFE12E27CB996F17159B1057E9B58B78BBB5A139C9FF6215A0D250B75FC9DD435655DDEADCD6CFD84800792C146B3633188ECEB53D2038C185E0BD51A9E6C70FD38ADF530F8DF50FB62053C5E894897AB7DD65C7AC80665F18E7989BE6E30F15E939751123D6D8A44F033175301D15AAAD2AEA06FAC60BA4065846AE938F32B1CB15F16DC0E76792A7332346896048065D17C059899E1D2300E402BD0EA74265DA6A42B1C854E2470D7B21AE4A2DAE90E602A759B2CA0EE610B50D5389DB89335D5451FE76DD85B09FD5297D6F9EFB6C34CE885007F7DF20D6A524E0C3E772FA04B3DD2E014D3A337A790943DAD523CBB5453F4FDF8E74DFE361BD5F25AB31952B478148B570DF5762643F32B994FEC99A747E4A265A66EE84A53509EC285C84679606049314FC526C61B537AC8061C788F8B86F52208'), +('fbe675a99fb5f4b7fb3eb5e5a22add91a4cabf83e3c5930c6659ad13c457ba18','Token','auth','Win',NULL); +/*!40000 ALTER TABLE `battlenet_modules` ENABLE KEYS */; +UNLOCK TABLES; + diff --git a/src/server/authserver/Realms/RealmList.cpp b/src/server/authserver/Realms/RealmList.cpp index 4aeecfc0aaa..bd856623faf 100644 --- a/src/server/authserver/Realms/RealmList.cpp +++ b/src/server/authserver/Realms/RealmList.cpp @@ -18,6 +18,7 @@ #include "Common.h" #include "RealmList.h" +#include "BattlenetManager.h" #include "Database/DatabaseEnv.h" RealmList::RealmList() : m_UpdateInterval(0), m_NextUpdateTime(time(NULL)) { } @@ -31,7 +32,7 @@ void RealmList::Initialize(uint32 updateInterval) UpdateRealms(true); } -void RealmList::UpdateRealm(uint32 id, const std::string& name, ACE_INET_Addr const& address, ACE_INET_Addr const& localAddr, ACE_INET_Addr const& localSubmask, uint8 icon, RealmFlags flag, uint8 timezone, AccountTypes allowedSecurityLevel, float popu, uint32 build) +void RealmList::UpdateRealm(uint32 id, const std::string& name, ACE_INET_Addr const& address, ACE_INET_Addr const& localAddr, ACE_INET_Addr const& localSubmask, uint8 icon, RealmFlags flag, uint8 timezone, AccountTypes allowedSecurityLevel, float popu, uint32 build, uint8 region, uint8 battlegroup) { // Create new if not exist or update existed Realm& realm = m_realms[name]; @@ -49,6 +50,8 @@ void RealmList::UpdateRealm(uint32 id, const std::string& name, ACE_INET_Addr co realm.LocalAddress = localAddr; realm.LocalSubnetMask = localSubmask; realm.gamebuild = build; + realm.Region = region; + realm.Battlegroup = battlegroup; } void RealmList::UpdateIfNeed() @@ -91,12 +94,14 @@ void RealmList::UpdateRealms(bool init) uint8 allowedSecurityLevel = fields[9].GetUInt8(); float pop = fields[10].GetFloat(); uint32 build = fields[11].GetUInt32(); + uint8 region = fields[12].GetUInt8(); + uint8 battlegroup = fields[13].GetUInt8(); ACE_INET_Addr externalAddr(port, externalAddress.c_str(), AF_INET); ACE_INET_Addr localAddr(port, localAddress.c_str(), AF_INET); ACE_INET_Addr submask(0, localSubmask.c_str(), AF_INET); - UpdateRealm(realmId, name, externalAddr, localAddr, submask, icon, flag, timezone, (allowedSecurityLevel <= SEC_ADMINISTRATOR ? AccountTypes(allowedSecurityLevel) : SEC_ADMINISTRATOR), pop, build); + UpdateRealm(realmId, name, externalAddr, localAddr, submask, icon, flag, timezone, (allowedSecurityLevel <= SEC_ADMINISTRATOR ? AccountTypes(allowedSecurityLevel) : SEC_ADMINISTRATOR), pop, build, region, battlegroup); if (init) TC_LOG_INFO("server.authserver", "Added realm \"%s\" at %s:%u.", name.c_str(), m_realms[name].ExternalAddress.get_host_addr(), port); @@ -104,3 +109,16 @@ void RealmList::UpdateRealms(bool init) while (result->NextRow()); } } + +Realm const* RealmList::GetRealm(Battlenet::RealmId const& id) const +{ + auto itr = std::find_if(m_realms.begin(), m_realms.end(), [id](RealmMap::value_type const& pair) + { + return pair.second.Region == id.Region && pair.second.Battlegroup == id.Battlegroup && pair.second.m_ID == id.Index; + }); + + if (itr != m_realms.end()) + return &itr->second; + + return NULL; +} diff --git a/src/server/authserver/Realms/RealmList.h b/src/server/authserver/Realms/RealmList.h index 1d76c39e4f0..ab453720827 100644 --- a/src/server/authserver/Realms/RealmList.h +++ b/src/server/authserver/Realms/RealmList.h @@ -51,8 +51,15 @@ struct Realm AccountTypes allowedSecurityLevel; float populationLevel; uint32 gamebuild; + uint8 Region; + uint8 Battlegroup; }; +namespace Battlenet +{ + struct RealmId; +} + /// Storage object for the list of realms on the server class RealmList { @@ -71,10 +78,11 @@ public: RealmMap::const_iterator begin() const { return m_realms.begin(); } RealmMap::const_iterator end() const { return m_realms.end(); } uint32 size() const { return m_realms.size(); } + Realm const* GetRealm(Battlenet::RealmId const& id) const; private: void UpdateRealms(bool init=false); - void UpdateRealm(uint32 id, const std::string& name, ACE_INET_Addr const& address, ACE_INET_Addr const& localAddr, ACE_INET_Addr const& localSubmask, uint8 icon, RealmFlags flag, uint8 timezone, AccountTypes allowedSecurityLevel, float popu, uint32 build); + void UpdateRealm(uint32 id, const std::string& name, ACE_INET_Addr const& address, ACE_INET_Addr const& localAddr, ACE_INET_Addr const& localSubmask, uint8 icon, RealmFlags flag, uint8 timezone, AccountTypes allowedSecurityLevel, float popu, uint32 build, uint8 region, uint8 battlegroup); RealmMap m_realms; uint32 m_UpdateInterval; diff --git a/src/server/authserver/Server/AuthSocket.cpp b/src/server/authserver/Server/AuthSocket.cpp index c7bb600024a..3afce0d77d9 100644 --- a/src/server/authserver/Server/AuthSocket.cpp +++ b/src/server/authserver/Server/AuthSocket.cpp @@ -986,7 +986,7 @@ bool AuthSocket::_HandleRealmList() pkt << AmountOfCharacters; pkt << realm.timezone; // realm category if (_expversion & POST_BC_EXP_FLAG) // 2.x and 3.x clients - pkt << uint8(0x2C); // unk, may be realm number/id? + pkt << uint8(realm.m_ID); else pkt << uint8(0x0); // 1.12.1 and 1.12.2 clients diff --git a/src/server/authserver/Server/BattlenetBitStream.h b/src/server/authserver/Server/BattlenetBitStream.h index bff1bffb3ab..a0bff314e8f 100644 --- a/src/server/authserver/Server/BattlenetBitStream.h +++ b/src/server/authserver/Server/BattlenetBitStream.h @@ -22,6 +22,8 @@ #include #include #include +#include +#include #include namespace Battlenet @@ -70,14 +72,14 @@ namespace Battlenet return str; } - uint8* ReadBytes(uint32 count) + ACE_Auto_Array_Ptr ReadBytes(uint32 count) { AlignToNextByte(); if (_readPos + count * 8 > _numBits) throw BitStreamPositionException(); - uint8* buf = new uint8[count]; - memcpy(buf, &_buffer[_readPos >> 3], count); + ACE_Auto_Array_Ptr buf(new uint8[count]); + memcpy(buf.get(), &_buffer[_readPos >> 3], count); _readPos += count * 8; return buf; } @@ -105,7 +107,9 @@ namespace Battlenet template T Read(uint32 bitCount) { - T ret = 0; + static_assert(std::is_integral::value || std::is_enum::value, "T must be an integer type"); + + uint64 ret = 0; while (bitCount != 0) { uint32 bitPos = (_readPos & 7); @@ -114,10 +118,11 @@ namespace Battlenet bitsLeftInByte = bitCount; bitCount -= bitsLeftInByte; - ret |= static_cast((uint64)(_buffer[_readPos >> 3] >> bitPos & (uint32)((uint8)(1 << bitsLeftInByte) - 1)) << bitCount); + ret |= (uint64)(_buffer[_readPos >> 3] >> bitPos & (uint32)((uint8)(1 << bitsLeftInByte) - 1)) << bitCount; _readPos += bitsLeftInByte; } - return ret; + + return static_cast(ret); } void WriteString(std::string const& str, uint32 bitCount, int32 baseLength = 0) @@ -141,7 +146,12 @@ namespace Battlenet _writePos += count * 8; } - //WriteFloat + void WriteFloat(float value) + { + uint32 intVal = *reinterpret_cast(&value); + Write(intVal, 32); + } + void WriteFourCC(std::string const& fcc) { uint32 intVal = *(uint32*)fcc.c_str(); @@ -157,6 +167,8 @@ namespace Battlenet template void Write(T value, uint32 bitCount) { + static_assert(std::is_integral::value || std::is_enum::value, "T must be an integer type"); + if (_writePos + bitCount >= 8 * MaxSize) throw BitStreamPositionException(); diff --git a/src/server/authserver/Server/BattlenetManager.h b/src/server/authserver/Server/BattlenetManager.h index 08c98645ebd..7bc12f94c62 100644 --- a/src/server/authserver/Server/BattlenetManager.h +++ b/src/server/authserver/Server/BattlenetManager.h @@ -73,6 +73,14 @@ namespace Battlenet uint32 DataSize; uint8* Data; }; + + struct RealmId + { + uint8 Region; + uint8 Battlegroup; + uint32 Index; + uint32 Build; + }; } class BattlenetMgr diff --git a/src/server/authserver/Server/BattlenetPackets.cpp b/src/server/authserver/Server/BattlenetPackets.cpp index bcb4f4e4898..6fca44234f9 100644 --- a/src/server/authserver/Server/BattlenetPackets.cpp +++ b/src/server/authserver/Server/BattlenetPackets.cpp @@ -75,6 +75,12 @@ std::string Battlenet::AuthChallenge::ToString() const return stream.str(); } +Battlenet::ProofRequest::~ProofRequest() +{ + for (size_t i = 0; i < Modules.size(); ++i) + delete Modules[i]; +} + void Battlenet::ProofRequest::Write() { _stream.Write(Modules.size(), 3); @@ -93,7 +99,7 @@ std::string Battlenet::ProofRequest::ToString() const std::ostringstream stream; stream << "Battlenet::ProofRequest modules " << Modules.size(); for (ModuleInfo const* module : Modules) - stream << std::endl << "Battlenet::ModuleInfo Locale " << module->Region.c_str() << ", ModuleId " << ByteArrayToHexStr(module->ModuleId, 32) << ", BlobSize " << module->DataSize; + 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(); } @@ -101,7 +107,7 @@ std::string Battlenet::ProofRequest::ToString() const Battlenet::ProofResponse::~ProofResponse() { for (size_t i = 0; i < Modules.size(); ++i) - delete[] Modules[i].Data; + delete Modules[i]; } void Battlenet::ProofResponse::Read() @@ -109,9 +115,9 @@ void Battlenet::ProofResponse::Read() Modules.resize(_stream.Read(3)); for (size_t i = 0; i < Modules.size(); ++i) { - ModuleData& data = Modules[i]; - data.Size = _stream.Read(10); - data.Data = _stream.ReadBytes(data.Size); + BitStream*& dataStream = Modules[i]; + dataStream = new BitStream(_stream.Read(10)); + memcpy(dataStream->GetBuffer(), _stream.ReadBytes(dataStream->GetSize()).get(), dataStream->GetSize()); } } @@ -119,10 +125,10 @@ std::string Battlenet::ProofResponse::ToString() const { std::ostringstream stream; stream << "Battlenet::ProofResponse Modules " << Modules.size(); - for (ModuleData const& module : Modules) + for (BitStream* module : Modules) { - std::string hexStr = ByteArrayToHexStr(module.Data, module.Size); - stream << std::endl << "Battlenet::ProofResponse::ModuleData Size: " << module.Size << ", Data: " << hexStr; + std::string hexStr = ByteArrayToHexStr(module->GetBuffer(), module->GetSize()); + stream << std::endl << "Battlenet::ProofResponse::ModuleData Size: " << module->GetSize() << ", Data: " << hexStr; } return stream.str(); @@ -156,7 +162,20 @@ void Battlenet::AuthComplete::Write() } } - // todo more + _stream.WriteString(FirstName, 8); // First name + _stream.WriteString(LastName, 8); // Last name - not set for WoW + + _stream.Write(GameAccountId, 32); + + _stream.Write(2, 8); + _stream.Write(0, 64); + _stream.Write(2, 8); + + _stream.WriteString(GameAccountName, 5, -1); + + _stream.Write(0, 64); // Account flags + _stream.Write(0, 32); + _stream.Write(0, 1); } else { @@ -174,8 +193,8 @@ void Battlenet::AuthComplete::Write() _stream.Write(ErrorType, 2); if (ErrorType == 1) { - _stream.Write(Result, 16); - _stream.Write(0, 32); + _stream.Write(Result, 16); + _stream.Write(0x80000000, 32); } } } @@ -190,3 +209,127 @@ void Battlenet::AuthComplete::SetAuthResult(AuthResult result) ErrorType = result != AUTH_OK ? 1 : 0; Result = result; } + +Battlenet::RealmCharacterCounts::~RealmCharacterCounts() +{ + for (ServerPacket* realmData : RealmData) + delete realmData; +} + +void Battlenet::RealmCharacterCounts::Write() +{ + _stream.Write(false, 1); // failure + _stream.Write(CharacterCounts.size(), 7); + for (CharacterCountEntry const& entry : CharacterCounts) + { + _stream.Write(entry.Realm.Region, 8); + _stream.Write(0, 12); + _stream.Write(entry.Realm.Battlegroup, 8); + _stream.Write(entry.Realm.Index, 32); + _stream.Write(entry.CharacterCount, 16); + } + + for (ServerPacket* realmData : RealmData) + { + realmData->Write(); + _stream.WriteBytes(realmData->GetData(), realmData->GetSize()); + } +} + +std::string Battlenet::RealmCharacterCounts::ToString() const +{ + std::ostringstream stream; + stream << "Battlenet::RealmCharacterCounts Realms " << CharacterCounts.size(); + + for (CharacterCountEntry const& entry : CharacterCounts) + stream << std::endl << "Region " << entry.Realm.Region << " Battlegroup " << entry.Realm.Region << " Index " << entry.Realm.Index << " Characters " << entry.CharacterCount; + + return stream.str().c_str(); +} + +void Battlenet::RealmUpdate::Write() +{ + _stream.Write(true, 1); // Success + _stream.Write(Timezone, 32); + _stream.WriteFloat(Population); + _stream.Write(Lock, 8); + _stream.Write(0, 19); + _stream.Write(Type + std::numeric_limits::min(), 32); + _stream.WriteString(Name, 10); + + _stream.Write(!Version.empty(), 1); + if (!Version.empty()) + { + _stream.WriteString(Version, 5); + _stream.Write(Build, 32); + + uint32 ip = Address.get_ip_address(); + uint16 port = Address.get_port_number(); + + EndianConvertReverse(ip); + EndianConvertReverse(port); + + _stream.WriteBytes(&ip, 4); + _stream.WriteBytes(&port, 2); + } + + _stream.Write(Flags, 8); + _stream.Write(Region, 8); + _stream.Write(0, 12); + _stream.Write(Battlegroup, 8); + _stream.Write(Index, 32); +} + +std::string Battlenet::RealmUpdate::ToString() const +{ + std::ostringstream stream; + stream << "Battlenet::RealmUpdate Timezone " << Timezone << " Population " << Population << " Lock " << Lock << " Type " << Type << " Name " << Name + << " Flags " << Flags << " Region " << Region << " Battlegroup " << Battlegroup << " Index " << Index; + + if (!Version.empty()) + stream << " Version " << Version; + + return stream.str().c_str(); +} + +void Battlenet::RealmJoinRequest::Read() +{ + ClientSeed = _stream.Read(32); + Unknown = _stream.Read(20); + Realm.Region = _stream.Read(8); + _stream.Read(12); + Realm.Battlegroup = _stream.Read(8); + Realm.Index = _stream.Read(32); +} + +std::string Battlenet::RealmJoinRequest::ToString() const +{ + std::ostringstream stream; + stream << "Battlenet::RealmJoinRequest ClientSeed" << ClientSeed << " Region " << Realm.Region << " Battlegroup " << Realm.Battlegroup << " Index " << Realm.Index; + return stream.str().c_str(); +} + +void Battlenet::RealmJoinResult::Write() +{ + _stream.Write(0, 1); // Fail + _stream.Write(ServerSeed, 32); + _stream.Write(IPv4.size(), 5); + for (ACE_INET_Addr const& addr : IPv4) + { + uint32 ip = addr.get_ip_address(); + uint16 port = addr.get_port_number(); + + EndianConvertReverse(ip); + EndianConvertReverse(port); + + _stream.WriteBytes(&ip, 4); + _stream.WriteBytes(&port, 2); + } + + _stream.Write(0, 5); // IPv6 addresses +} + +std::string Battlenet::RealmJoinResult::ToString() const +{ + return "Battlenet::RealmJoinResult"; +} diff --git a/src/server/authserver/Server/BattlenetPackets.h b/src/server/authserver/Server/BattlenetPackets.h index 3b02c0c602a..bea9b5649e5 100644 --- a/src/server/authserver/Server/BattlenetPackets.h +++ b/src/server/authserver/Server/BattlenetPackets.h @@ -31,8 +31,6 @@ namespace Battlenet enum Channel { - NOT_SPECIFIED = -1, - AUTHENTICATION = 0, CREEP = 1, WOW = 2 @@ -48,10 +46,29 @@ namespace Battlenet SMSG_AUTH_PROOF_REQUEST = 0x2, }; + enum CreepOpcodes + { + CMSG_PING = 0x0, + CMSG_ENABLE_ENCRYPTION = 0x5, + + SMSG_PONG = 0x0 + }; + + enum WoWOpcodes + { + CMSG_REALM_UPDATE = 0x0, + CMSG_JOIN_REQUEST = 0x8, + + SMSG_CHARACTER_COUNTS = 0x0, + SMSG_REALM_UPDATE = 0x2, + SMSG_REALM_UPDATE_END = 0x3, + SMSG_JOIN_RESULT = 0x8 + }; + struct PacketHeader { PacketHeader(uint32 opcode, uint32 channel) : Opcode(opcode), Channel(channel) { } - PacketHeader() : Opcode(0), Channel(NOT_SPECIFIED) { } + PacketHeader() : Opcode(0), Channel(AUTHENTICATION) { } uint32 Opcode; int32 Channel; @@ -142,11 +159,12 @@ namespace Battlenet { public: ProofRequest() : ServerPacket(PacketHeader(SMSG_AUTH_PROOF_REQUEST, AUTHENTICATION)) { } + ~ProofRequest(); void Write() override; std::string ToString() const override; - std::vector Modules; + std::vector Modules; }; class ProofResponse final : public ClientPacket @@ -159,23 +177,18 @@ namespace Battlenet ~ProofResponse(); - struct ModuleData - { - uint32 Size; - uint8* Data; - }; - void Read() override; std::string ToString() const override; - std::vector Modules; + std::vector Modules; }; class AuthComplete final : public ServerPacket { public: AuthComplete() : ServerPacket(PacketHeader(SMSG_AUTH_COMPLETE, AUTHENTICATION)), - Result(AUTH_OK), ErrorType(0), PingTimeout(120000), Threshold(1000000), Rate(1000) + Result(AUTH_OK), ErrorType(0), PingTimeout(120000), Threshold(25000000), Rate(1000), + FirstName(""), LastName(""), GameAccountId(0), GameAccountName("") { } @@ -192,6 +205,108 @@ namespace Battlenet uint32 Rate; std::string FirstName; std::string LastName; + uint32 GameAccountId; + std::string GameAccountName; + uint64 AccountFlags; + }; + + class Pong final : public ServerPacket + { + public: + Pong() : ServerPacket(PacketHeader(SMSG_PONG, CREEP)) + { + } + + void Write() override { } + std::string ToString() const override { return "Battlenet::Pong"; } + }; + + class RealmCharacterCounts final : public ServerPacket + { + public: + RealmCharacterCounts() : ServerPacket(PacketHeader(SMSG_CHARACTER_COUNTS, WOW)) + { + } + ~RealmCharacterCounts(); + + struct CharacterCountEntry + { + RealmId Realm; + uint32 CharacterCount; + }; + + void Write() override; + std::string ToString() const override; + + std::vector CharacterCounts; + std::vector RealmData; + }; + + class RealmUpdate final : public ServerPacket + { + public: + RealmUpdate() : ServerPacket(PacketHeader(SMSG_REALM_UPDATE, WOW)), + Timezone(0), Population(0.0f), Lock(0), Type(0), Name(""), Version(""), + Address(), Flags(0), Region(0), Battlegroup(0), Index(0), Build(0) + { + } + + void Write() override; + std::string ToString() const override; + + uint32 Timezone; + float Population; + uint8 Lock; + uint32 Type; + std::string Name; + std::string Version; + ACE_INET_Addr Address; + uint8 Flags; + uint8 Region; + uint8 Battlegroup; + uint32 Index; + uint32 Build; + }; + + class RealmUpdateComplete final : public ServerPacket + { + public: + RealmUpdateComplete() : ServerPacket(PacketHeader(SMSG_REALM_UPDATE_END, WOW)) + { + } + + void Write() override { } + std::string ToString() const override { return "Battlenet::RealmUpdateComplete"; } + }; + + class RealmJoinRequest final : public ClientPacket + { + public: + RealmJoinRequest(PacketHeader const& header, BitStream& stream) : ClientPacket(header, stream) + { + ASSERT(header == PacketHeader(CMSG_JOIN_REQUEST, WOW) && "Invalid packet header for RealmJoinRequest"); + } + + void Read() override; + std::string ToString() const override; + + uint32 ClientSeed; + uint32 Unknown; + RealmId Realm; + }; + + class RealmJoinResult final : public ServerPacket + { + public: + RealmJoinResult() : ServerPacket(PacketHeader(SMSG_JOIN_RESULT, WOW)), ServerSeed(0) + { + } + + void Write() override; + std::string ToString() const override; + + uint32 ServerSeed; + std::vector IPv4; }; } diff --git a/src/server/authserver/Server/BattlenetSocket.cpp b/src/server/authserver/Server/BattlenetSocket.cpp index edd73080270..65e12aa602d 100644 --- a/src/server/authserver/Server/BattlenetSocket.cpp +++ b/src/server/authserver/Server/BattlenetSocket.cpp @@ -18,15 +18,134 @@ #include "AuthCodes.h" #include "BattlenetBitStream.h" #include "BattlenetSocket.h" +#include "Database/DatabaseEnv.h" +#include "HmacHash.h" +#include "Log.h" +#include "RealmList.h" +#include "SHA256.h" #include +uint32 const Battlenet::Socket::SRP6_V_Size = 128; +uint32 const Battlenet::Socket::SRP6_S_Size = 32; + +std::map InitHandlers() +{ + std::map handlers; + + handlers[Battlenet::PacketHeader(Battlenet::CMSG_AUTH_CHALLENGE, Battlenet::AUTHENTICATION)] = &Battlenet::Socket::HandleAuthChallenge; + handlers[Battlenet::PacketHeader(Battlenet::CMSG_AUTH_CHALLENGE_NEW, Battlenet::AUTHENTICATION)] = &Battlenet::Socket::HandleAuthChallenge; + 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_REALM_UPDATE, Battlenet::WOW)] = &Battlenet::Socket::HandleRealmUpdate; + handlers[Battlenet::PacketHeader(Battlenet::CMSG_JOIN_REQUEST, Battlenet::WOW)] = &Battlenet::Socket::HandleRealmJoinRequest; + + return handlers; +} + +std::map Handlers = InitHandlers(); + +Battlenet::Socket::ModuleHandler const Battlenet::Socket::ModuleHandlers[MODULE_COUNT] = +{ + &Battlenet::Socket::HandlePasswordModule, + &Battlenet::Socket::UnhandledModule, + &Battlenet::Socket::UnhandledModule, + &Battlenet::Socket::HandleSelectGameAccountModule, + &Battlenet::Socket::HandleRiskFingerprintModule, +}; + +Battlenet::Socket::Socket(RealmSocket& socket) : _socket(socket), _accountId(0), _accountName(), _locale(), + _os(), _build(0), _gameAccountId(0), _accountSecurityLevel(SEC_PLAYER) +{ + static uint8 const N_Bytes[] = + { + 0xAB, 0x24, 0x43, 0x63, 0xA9, 0xC2, 0xA6, 0xC3, 0x3B, 0x37, 0xE4, 0x61, 0x84, 0x25, 0x9F, 0x8B, + 0x3F, 0xCB, 0x8A, 0x85, 0x27, 0xFC, 0x3D, 0x87, 0xBE, 0xA0, 0x54, 0xD2, 0x38, 0x5D, 0x12, 0xB7, + 0x61, 0x44, 0x2E, 0x83, 0xFA, 0xC2, 0x21, 0xD9, 0x10, 0x9F, 0xC1, 0x9F, 0xEA, 0x50, 0xE3, 0x09, + 0xA6, 0xE5, 0x5E, 0x23, 0xA7, 0x77, 0xEB, 0x00, 0xC7, 0xBA, 0xBF, 0xF8, 0x55, 0x8A, 0x0E, 0x80, + 0x2B, 0x14, 0x1A, 0xA2, 0xD4, 0x43, 0xA9, 0xD4, 0xAF, 0xAD, 0xB5, 0xE1, 0xF5, 0xAC, 0xA6, 0x13, + 0x1C, 0x69, 0x78, 0x64, 0x0B, 0x7B, 0xAF, 0x9C, 0xC5, 0x50, 0x31, 0x8A, 0x23, 0x08, 0x01, 0xA1, + 0xF5, 0xFE, 0x31, 0x32, 0x7F, 0xE2, 0x05, 0x82, 0xD6, 0x0B, 0xED, 0x4D, 0x55, 0x32, 0x41, 0x94, + 0x29, 0x6F, 0x55, 0x7D, 0xE3, 0x0F, 0x77, 0x19, 0xE5, 0x6C, 0x30, 0xEB, 0xDE, 0xF6, 0xA7, 0x86 + }; + + N.SetBinary(N_Bytes, sizeof(N_Bytes)); + g.SetDword(2); + + SHA256Hash sha; + sha.UpdateBigNumbers(&N, &g, NULL); + sha.Finalize(); + k.SetBinary(sha.GetDigest(), sha.GetLength()); +} + +void Battlenet::Socket::_SetVSFields(std::string const& pstr) +{ + s.SetRand(SRP6_S_Size * 8); + + BigNumber p; + p.SetHexStr(pstr.c_str()); + + SHA256Hash sha; + sha.UpdateBigNumbers(&s, &p, NULL); + sha.Finalize(); + BigNumber x; + x.SetBinary(sha.GetDigest(), sha.GetLength()); + v = g.ModExp(x, N); + + char* v_hex = v.AsHexStr(); + char* s_hex = s.AsHexStr(); + + LoginDatabase.PExecute("UPDATE battlenet_accounts SET s = '%s', v = '%s' WHERE email ='%s'", s_hex, v_hex, _accountName.c_str()); + + OPENSSL_free(v_hex); + OPENSSL_free(s_hex); +} + +ACE_INET_Addr const& Battlenet::Socket::GetAddressForClient(Realm const& realm, ACE_INET_Addr const& clientAddr) +{ + // Attempt to send best address for client + if (clientAddr.is_loopback()) + { + // Try guessing if realm is also connected locally + if (realm.LocalAddress.is_loopback() || realm.ExternalAddress.is_loopback()) + return clientAddr; + + // Assume that user connecting from the machine that authserver is located on + // has all realms available in his local network + return realm.LocalAddress; + } + + // Check if connecting client is in the same network + if (IsIPAddrInNetwork(realm.LocalAddress, clientAddr, realm.LocalSubnetMask)) + return realm.LocalAddress; + + // Return external IP + return realm.ExternalAddress; +} + bool Battlenet::Socket::HandleAuthChallenge(PacketHeader& header, BitStream& packet) { + + // Verify that this IP is not in the ip_banned table + LoginDatabase.Execute(LoginDatabase.GetPreparedStatement(LOGIN_DEL_EXPIRED_IP_BANS)); + + std::string const& ip_address = _socket.getRemoteAddress(); + PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_IP_BANNED); + stmt->setString(0, ip_address); + if (PreparedQueryResult result = LoginDatabase.Query(stmt)) + { + AuthComplete complete; + complete.SetAuthResult(LOGIN_BANNED); + Send(complete); + TC_LOG_DEBUG("server.battlenet", "[Battlenet::AuthChallenge] Banned ip '%s:%d' tries to login!", _socket.getRemoteAddress().c_str(), _socket.getRemotePort()); + return true; + } + AuthChallenge info(header, packet); info.Read(); - printf("%s\n", info.ToString().c_str()); - if (info.Program != "WoW") { AuthComplete complete; @@ -66,109 +185,642 @@ bool Battlenet::Socket::HandleAuthChallenge(PacketHeader& header, BitStream& pac Send(complete); return true; } + + if (component.Platform == "base") + _build = component.Build; } _accountName = info.Login; _locale = info.Locale; _os = info.Platform; + Utf8ToUpperOnlyLatin(_accountName); + LoginDatabase.EscapeString(_accountName); + // 0 1 2 3 4 5 6 + QueryResult result = LoginDatabase.PQuery("SELECT sha_pass_hash, id, locked, lock_country, last_ip, v, s FROM battlenet_accounts WHERE email = '%s'", _accountName.c_str()); + if (!result) + { + AuthComplete complete; + complete.SetAuthResult(AUTH_UNKNOWN_ACCOUNT); + Send(complete); + return true; + } + + Field* fields = result->Fetch(); + + _accountId = fields[1].GetUInt32(); + + // If the IP is 'locked', check that the player comes indeed from the correct IP address + if (fields[2].GetUInt8() == 1) // if ip is locked + { + TC_LOG_DEBUG("server.battlenet", "[Battlenet::AuthChallenge] Account '%s' is locked to IP - '%s' is logging in from '%s'", _accountName.c_str(), fields[4].GetCString(), ip_address.c_str()); + + if (strcmp(fields[4].GetCString(), ip_address.c_str()) != 0) + { + AuthComplete complete; + complete.SetAuthResult(AUTH_ACCOUNT_LOCKED); + Send(complete); + return true; + } + } + else + { + TC_LOG_DEBUG("server.battlenet", "[Battlenet::AuthChallenge] Account '%s' is not locked to ip", _accountName.c_str()); + std::string accountCountry = fields[3].GetString(); + if (accountCountry.empty() || accountCountry == "00") + TC_LOG_DEBUG("server.battlenet", "[Battlenet::AuthChallenge] Account '%s' is not locked to country", _accountName.c_str()); + else if (!accountCountry.empty()) + { + uint32 ip = inet_addr(ip_address.c_str()); + EndianConvertReverse(ip); + + stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_LOGON_COUNTRY); + stmt->setUInt32(0, ip); + if (PreparedQueryResult sessionCountryQuery = LoginDatabase.Query(stmt)) + { + std::string loginCountry = (*sessionCountryQuery)[0].GetString(); + TC_LOG_DEBUG("server.battlenet", "[Battlenet::AuthChallenge] Account '%s' is locked to country: '%s' Player country is '%s'", _accountName.c_str(), accountCountry.c_str(), loginCountry.c_str()); + if (loginCountry != accountCountry) + { + AuthComplete complete; + complete.SetAuthResult(AUTH_ACCOUNT_LOCKED); + Send(complete); + return true; + } + } + } + } + + //set expired bans to inactive + LoginDatabase.DirectExecute("UPDATE battlenet_account_bans SET active = 0 WHERE active = 1 AND unbandate <> bandate AND unbandate <= UNIX_TIMESTAMP()"); + + // If the account is banned, reject the logon attempt + QueryResult banresult = LoginDatabase.PQuery("SELECT bandate, unbandate FROM battlenet_account_bans WHERE id = %u AND active = 1", _accountId); + if (banresult) + { + Field* fields = banresult->Fetch(); + if (fields[0].GetUInt32() == fields[1].GetUInt32()) + { + AuthComplete complete; + complete.SetAuthResult(LOGIN_BANNED); + Send(complete); + TC_LOG_DEBUG("server.battlenet", "'%s:%d' [Battlenet::AuthChallenge] Banned account %s tried to login!", _socket.getRemoteAddress().c_str(), _socket.getRemotePort(), _accountName.c_str()); + return true; + } + else + { + AuthComplete complete; + complete.SetAuthResult(LOGIN_SUSPENDED); + Send(complete); + TC_LOG_DEBUG("server.battlenet", "'%s:%d' [Battlenet::AuthChallenge] Temporarily banned account %s tried to login!", _socket.getRemoteAddress().c_str(), _socket.getRemotePort(), _accountName.c_str()); + return true; + } + } + + SHA256Hash sha; + sha.UpdateData(_accountName); + sha.Finalize(); + + I.SetBinary(sha.GetDigest(), sha.GetLength()); + + ModuleInfo* password = new ModuleInfo(*sBattlenetMgr->GetModule({ _os, "Password" })); + ModuleInfo* thumbprint = new ModuleInfo(*sBattlenetMgr->GetModule({ _os, "Thumbprint" })); + + std::string pStr = fields[0].GetString(); + + std::string databaseV = fields[5].GetString(); + std::string databaseS = fields[6].GetString(); + + if (databaseV.size() != SRP6_V_Size * 2 || databaseS.size() != SRP6_S_Size * 2) + _SetVSFields(pStr); + else + { + s.SetHexStr(databaseS.c_str()); + v.SetHexStr(databaseV.c_str()); + } + + b.SetRand(128 * 8); + B = ((v * k) + g.ModExp(b, N)) % N; + + 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(b.AsByteArray(128).get(), 128); + + password->DataSize = passwordData.GetSize(); + password->Data = new uint8[password->DataSize]; + memcpy(password->Data, passwordData.GetBuffer(), password->DataSize); + + _modulesWaitingForData.push(MODULE_PASSWORD); + ProofRequest request; + request.Modules.push_back(password); + // if has authenticator, send Token module + request.Modules.push_back(thumbprint); Send(request); return true; } bool Battlenet::Socket::HandleAuthProofResponse(PacketHeader& header, BitStream& packet) { - ProofResponse response(header, packet); - response.Read(); + ProofResponse proof(header, packet); + proof.Read(); - printf("%s\n", response.ToString().c_str()); + if (_modulesWaitingForData.size() < proof.Modules.size()) + { + AuthComplete complete; + complete.SetAuthResult(AUTH_CORRUPTED_MODULE); + Send(complete); + return true; + } - AuthComplete complete; - complete.SetAuthResult(AUTH_USE_GRUNT_LOGON); - Send(complete); + ServerPacket* response = nullptr; + for (size_t i = 0; i < proof.Modules.size(); ++i) + { + if (!(this->*(ModuleHandlers[_modulesWaitingForData.front()]))(proof.Modules[i], &response)) + break; + + _modulesWaitingForData.pop(); + } + + if (!response) + { + response = new AuthComplete(); + static_cast(response)->SetAuthResult(AUTH_INTERNAL_ERROR); + } + + Send(*response); + delete response; return true; } -std::map InitHandlers() +bool Battlenet::Socket::HandlePing(PacketHeader& /*header*/, BitStream& /*packet*/) { - std::map 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_PROOF_RESPONSE, Battlenet::AUTHENTICATION)] = &Battlenet::Socket::HandleAuthProofResponse; + Pong pong; + Send(pong); + return true; +} - return handlers; +bool Battlenet::Socket::HandleEnableEncryption(PacketHeader& /*header*/, BitStream& packet) +{ + _crypt.Init(&K); + _crypt.DecryptRecv(packet.GetBuffer() + 2, packet.GetSize() - 2); + return false; } -std::map Handlers = InitHandlers(); +bool Battlenet::Socket::HandleRealmUpdate(PacketHeader& /*header*/, BitStream& /*packet*/) +{ + sRealmList->UpdateIfNeed(); + + RealmCharacterCounts counts; + + ACE_INET_Addr clientAddr; + _socket.peer().get_remote_addr(clientAddr); + + for (RealmList::RealmMap::const_iterator i = sRealmList->begin(); i != sRealmList->end(); ++i) + { + Realm const& realm = i->second; + + PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_NUM_CHARS_ON_REALM); + stmt->setUInt32(0, realm.m_ID); + stmt->setUInt32(1, _gameAccountId); + + if (PreparedQueryResult result = LoginDatabase.Query(stmt)) + counts.CharacterCounts.push_back({ { realm.Region, realm.Battlegroup, realm.m_ID, 0 }, (*result)[0].GetUInt8() }); + + uint32 flag = realm.flag; + RealmBuildInfo const* buildInfo = AuthHelper::GetBuildInfo(realm.gamebuild); + if (realm.gamebuild != _build) + { + if (!buildInfo) + continue; + + flag |= REALM_FLAG_OFFLINE | REALM_FLAG_SPECIFYBUILD; // tell the client what build the realm is for + } + + if (!buildInfo) + flag &= ~REALM_FLAG_SPECIFYBUILD; + + RealmUpdate* update = new RealmUpdate(); + update->Timezone = realm.timezone; + update->Population = realm.populationLevel; + update->Lock = (realm.allowedSecurityLevel > _accountSecurityLevel) ? 1 : 0; + update->Type = realm.icon; + update->Name = realm.name; + + if (flag & REALM_FLAG_SPECIFYBUILD) + { + std::ostringstream version; + version << buildInfo->MajorVersion << '.' << buildInfo->MinorVersion << '.' << buildInfo->BugfixVersion << '.' << buildInfo->HotfixVersion; + + update->Version = version.str(); + update->Address = GetAddressForClient(realm, clientAddr); + update->Build = realm.gamebuild; + } -Battlenet::Socket::Socket(RealmSocket& socket) : _socket(socket), _currentChannel(0) + update->Flags = flag; + update->Region = realm.Region; + update->Battlegroup = realm.Battlegroup; + update->Index = realm.m_ID; + + counts.RealmData.push_back(update); + } + + counts.RealmData.push_back(new RealmUpdateComplete()); + + Send(counts); + return true; +} + +bool Battlenet::Socket::HandleRealmJoinRequest(PacketHeader& header, BitStream& packet) { + RealmJoinRequest join(header, packet); + join.Read(); + + RealmJoinResult result; + Realm const* realm = sRealmList->GetRealm(join.Realm); + if (!realm) + { + Send(result); + return true; + } + + result.ServerSeed = uint32(rand32()); + + uint8 sessionKey[40]; + HmacHash hmac(K.GetNumBytes(), K.AsByteArray().get(), EVP_sha1(), SHA_DIGEST_LENGTH); + hmac.UpdateData((uint8*)"WoW\0", 4); + hmac.UpdateData((uint8*)&join.ClientSeed, 4); + hmac.UpdateData((uint8*)&result.ServerSeed, 4); + hmac.Finalize(); + + memcpy(sessionKey, hmac.GetDigest(), hmac.GetLength()); + + HmacHash hmac2(K.GetNumBytes(), K.AsByteArray().get(), EVP_sha1(), SHA_DIGEST_LENGTH); + hmac2.UpdateData((uint8*)"WoW\0", 4); + hmac2.UpdateData((uint8*)&result.ServerSeed, 4); + hmac2.UpdateData((uint8*)&join.ClientSeed, 4); + hmac2.Finalize(); + + memcpy(sessionKey + hmac.GetLength(), hmac2.GetDigest(), hmac2.GetLength()); + + LoginDatabase.DirectPExecute("UPDATE account SET sessionkey = '%s', last_ip = '%s', last_login = NOW(), locale = %u, failed_logins = 0, os = '%s' WHERE id = %u", + ByteArrayToHexStr(sessionKey, 40, true).c_str(), _socket.getRemoteAddress().c_str(), GetLocaleByName(_locale), _os.c_str(), _gameAccountId); + + result.IPv4.push_back(realm->ExternalAddress); + if (realm->ExternalAddress != realm->LocalAddress) + result.IPv4.push_back(realm->LocalAddress); + + Send(result); + return true; } void Battlenet::Socket::OnRead() { - while (1) - { - size_t length = _socket.recv_len(); - if (!length) - return; + size_t length = _socket.recv_len(); + if (!length) + return; - BitStream packet(length); - if (!_socket.recv((char*)packet.GetBuffer(), length)) - return; + BitStream packet(length); + if (!_socket.recv((char*)packet.GetBuffer(), length)) + return; - while (!packet.IsRead()) + _crypt.DecryptRecv(packet.GetBuffer(), length); + + while (!packet.IsRead()) + { + try { - try - { - PacketHeader header; - header.Opcode = packet.Read(6); - if (packet.Read(1)) - _currentChannel = header.Channel = packet.Read(4); - else - header.Channel = _currentChannel; - - printf("Battlenet::Socket::OnRead %s\n", header.ToString().c_str()); - std::map::const_iterator itr = Handlers.find(header); - if (itr != Handlers.end()) - { - if (!(this->*(itr->second))(header, packet)) - { - _socket.shutdown(); - return; - } - } - else - printf("Battlenet::Socket::OnRead Unhandled opcode %s\n", header.ToString().c_str()); + PacketHeader header; + header.Opcode = packet.Read(6); + if (packet.Read(1)) + header.Channel = packet.Read(4); - packet.AlignToNextByte(); + TC_LOG_TRACE("server.battlenet", "Battlenet::Socket::OnRead %s", header.ToString().c_str()); + std::map::const_iterator itr = Handlers.find(header); + if (itr != Handlers.end()) + { + if ((this->*(itr->second))(header, packet)) + break; } - catch (BitStreamPositionException const& e) + else { - printf("Battlenet::Socket::OnRead Exception: %s\n", e.what()); - _socket.shutdown(); + TC_LOG_DEBUG("server.battlenet", "Battlenet::Socket::OnRead Unhandled opcode %s", header.ToString().c_str()); return; } + + packet.AlignToNextByte(); + } + catch (BitStreamPositionException const& e) + { + TC_LOG_ERROR("server.battlenet", "Battlenet::Socket::OnRead Exception: %s", e.what()); + _socket.shutdown(); + return; } } } void Battlenet::Socket::OnAccept() { - printf("Battlenet::Socket::OnAccept\n"); + TC_LOG_TRACE("server.battlenet", "Battlenet::Socket::OnAccept"); } void Battlenet::Socket::OnClose() { - printf("Battlenet::Socket::OnClose\n"); + TC_LOG_TRACE("server.battlenet", "Battlenet::Socket::OnClose"); } void Battlenet::Socket::Send(ServerPacket& packet) { - printf("Battlenet::Socket::Send %s\n", packet.ToString().c_str()); - packet.Write(); + + _crypt.EncryptSend(const_cast(packet.GetData()), packet.GetSize()); _socket.send(reinterpret_cast(packet.GetData()), packet.GetSize()); } + +inline void ReplaceResponse(Battlenet::ServerPacket** oldResponse, Battlenet::ServerPacket* newResponse) +{ + if (*oldResponse) + delete *oldResponse; + + *oldResponse = newResponse; +} + +bool Battlenet::Socket::HandlePasswordModule(BitStream* dataStream, ServerPacket** response) +{ + if (dataStream->GetSize() != 1 + 128 + 32 + 128) + { + AuthComplete* complete = new AuthComplete(); + complete->SetAuthResult(AUTH_CORRUPTED_MODULE); + ReplaceResponse(response, complete); + return false; + } + + if (dataStream->Read(8) != 2) // State + { + AuthComplete* complete = new AuthComplete(); + complete->SetAuthResult(AUTH_CORRUPTED_MODULE); + ReplaceResponse(response, complete); + return false; + } + + + BigNumber A, clientM1, clientChallenge; + A.SetBinary(dataStream->ReadBytes(128).get(), 128); + clientM1.SetBinary(dataStream->ReadBytes(32).get(), 32); + clientChallenge.SetBinary(dataStream->ReadBytes(128).get(), 128); + + if (A.isZero()) + { + AuthComplete* complete = new AuthComplete(); + complete->SetAuthResult(AUTH_CORRUPTED_MODULE); + ReplaceResponse(response, complete); + return false; + } + + SHA256Hash sha; + sha.UpdateBigNumbers(&A, &B, NULL); + sha.Finalize(); + + BigNumber u; + u.SetBinary(sha.GetDigest(), sha.GetLength()); + + BigNumber S = ((A * v.ModExp(u, N)) % N).ModExp(b, N); + + uint8 S_bytes[128]; + memcpy(S_bytes, S.AsByteArray(128).get(), 128); + + uint8 part1[64]; + uint8 part2[64]; + + for (int i = 0; i < 64; ++i) + { + part1[i] = S_bytes[i * 2]; + part2[i] = S_bytes[i * 2 + 1]; + } + + SHA256Hash part1sha, part2sha; + part1sha.UpdateData(part1, 64); + part1sha.Finalize(); + part2sha.UpdateData(part2, 64); + part2sha.Finalize(); + + uint8 sessionKey[SHA256_DIGEST_LENGTH * 2]; + for (int i = 0; i < SHA256_DIGEST_LENGTH; ++i) + { + sessionKey[i * 2] = part1sha.GetDigest()[i]; + sessionKey[i * 2 + 1] = part2sha.GetDigest()[i]; + } + + K.SetBinary(sessionKey, SHA256_DIGEST_LENGTH * 2); + + BigNumber M1; + + uint8 hash[SHA256_DIGEST_LENGTH]; + sha.Initialize(); + sha.UpdateBigNumbers(&N, NULL); + sha.Finalize(); + memcpy(hash, sha.GetDigest(), sha.GetLength()); + + sha.Initialize(); + sha.UpdateBigNumbers(&g, NULL); + sha.Finalize(); + + for (int i = 0; i < sha.GetLength(); ++i) + hash[i] ^= sha.GetDigest()[i]; + + SHA256Hash shaI; + shaI.UpdateData(ByteArrayToHexStr(I.AsByteArray().get(), 32)); + shaI.Finalize(); + + // Concat all variables for M1 hash + sha.Initialize(); + sha.UpdateData(hash, SHA256_DIGEST_LENGTH); + sha.UpdateData(shaI.GetDigest(), shaI.GetLength()); + sha.UpdateBigNumbers(&s, &A, &B, &K, NULL); + sha.Finalize(); + + M1.SetBinary(sha.GetDigest(), sha.GetLength()); + + if (memcmp(M1.AsByteArray().get(), clientM1.AsByteArray().get(), 32)) + { + AuthComplete* complete = new AuthComplete(); + complete->SetAuthResult(AUTH_UNKNOWN_ACCOUNT); + ReplaceResponse(response, complete); + return false; + } + + uint64 numAccounts = 0; + QueryResult result = LoginDatabase.PQuery("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 = '%u'", _accountId); + if (result) + numAccounts = result->GetRowCount(); + + if (!numAccounts) + { + AuthComplete* noAccounts = new AuthComplete(); + noAccounts->SetAuthResult(LOGIN_NO_GAME_ACCOUNT); + ReplaceResponse(response, noAccounts); + return false; + } + + Field* fields = result->Fetch(); + + //set expired game account bans to inactive + LoginDatabase.DirectExecute(LoginDatabase.GetPreparedStatement(LOGIN_UPD_EXPIRED_ACCOUNT_BANS)); + + BigNumber M; + sha.Initialize(); + sha.UpdateBigNumbers(&A, &M1, &K, NULL); + sha.Finalize(); + M.SetBinary(sha.GetDigest(), sha.GetLength()); + + BitStream stream; + ModuleInfo* password = new ModuleInfo(*sBattlenetMgr->GetModule({ _os, "Password" })); + uint8 state = 3; + + stream.WriteBytes(&state, 1); + stream.WriteBytes(M.AsByteArray(32).get(), 32); + stream.WriteBytes(b.AsByteArray(128).get(), 128); + + password->DataSize = stream.GetSize(); + password->Data = new uint8[password->DataSize]; + memcpy(password->Data, stream.GetBuffer(), password->DataSize); + + ProofRequest* request = new ProofRequest(); + request->Modules.push_back(password); + if (numAccounts > 1) + { + BitStream accounts; + state = 0; + accounts.WriteBytes(&state, 1); + accounts.Write(numAccounts, 8); + do + { + fields = result->Fetch(); + accounts.Write(2, 8); + accounts.WriteString(fields[0].GetString(), 8); + } while (result->NextRow()); + + ModuleInfo* selectGameAccount = new ModuleInfo(*sBattlenetMgr->GetModule({ _os, "SelectGameAccount" })); + selectGameAccount->DataSize = accounts.GetSize(); + selectGameAccount->Data = new uint8[selectGameAccount->DataSize]; + memcpy(selectGameAccount->Data, accounts.GetBuffer(), selectGameAccount->DataSize); + request->Modules.push_back(selectGameAccount); + _modulesWaitingForData.push(MODULE_SELECT_GAME_ACCOUNT); + } + else + { + if (fields[4].GetBool()) + { + delete request; + + AuthComplete* complete = new AuthComplete(); + if (fields[2].GetUInt32() == fields[3].GetUInt32()) + { + complete->SetAuthResult(LOGIN_BANNED); + TC_LOG_DEBUG("server.battlenet", "'%s:%d' [Battlenet::AuthChallenge] Banned account %s tried to login!", _socket.getRemoteAddress().c_str(), _socket.getRemotePort(), _accountName.c_str()); + } + else + { + complete->SetAuthResult(LOGIN_SUSPENDED); + TC_LOG_DEBUG("server.battlenet", "'%s:%d' [Battlenet::AuthChallenge] Temporarily banned account %s tried to login!", _socket.getRemoteAddress().c_str(), _socket.getRemotePort(), _accountName.c_str()); + } + + ReplaceResponse(response, complete); + return true; + } + + _gameAccountId = (*result)[1].GetUInt32(); + + request->Modules.push_back(new ModuleInfo(*sBattlenetMgr->GetModule({ _os, "RiskFingerprint" }))); + _modulesWaitingForData.push(MODULE_RISK_FINGERPRINT); + } + + ReplaceResponse(response, request); + + return true; +} + +bool Battlenet::Socket::HandleSelectGameAccountModule(BitStream* dataStream, ServerPacket** response) +{ + if (dataStream->Read(8) != 1) + { + AuthComplete* complete = new AuthComplete(); + complete->SetAuthResult(AUTH_CORRUPTED_MODULE); + ReplaceResponse(response, complete); + return false; + } + + dataStream->Read(8); + std::string account = dataStream->ReadString(8); + + LoginDatabase.EscapeString(account); + QueryResult result = LoginDatabase.PQuery("SELECT a.id, ab.bandate, ab.unbandate, ab.active FROM account a LEFT JOIN account_banned ab ON a.id = ab.id WHERE username = '%s' AND battlenet_account = '%u'", account.c_str(), _accountId); + if (!result) + { + AuthComplete* complete = new AuthComplete(); + complete->SetAuthResult(LOGIN_NO_GAME_ACCOUNT); + ReplaceResponse(response, complete); + return false; + } + + Field* fields = result->Fetch(); + if (fields[3].GetBool()) + { + AuthComplete* complete = new AuthComplete(); + if (fields[1].GetUInt32() == fields[2].GetUInt32()) + { + complete->SetAuthResult(LOGIN_BANNED); + TC_LOG_DEBUG("server.battlenet", "'%s:%d' [Battlenet::AuthChallenge] Banned account %s tried to login!", _socket.getRemoteAddress().c_str(), _socket.getRemotePort(), _accountName.c_str()); + } + else + { + complete->SetAuthResult(LOGIN_SUSPENDED); + TC_LOG_DEBUG("server.battlenet", "'%s:%d' [Battlenet::AuthChallenge] Temporarily banned account %s tried to login!", _socket.getRemoteAddress().c_str(), _socket.getRemotePort(), _accountName.c_str()); + } + + ReplaceResponse(response, complete); + return true; + } + + _gameAccountId = fields[0].GetUInt32(); + + ProofRequest* request = new ProofRequest(); + request->Modules.push_back(new ModuleInfo(*sBattlenetMgr->GetModule({ _os, "RiskFingerprint" }))); + ReplaceResponse(response, request); + + _modulesWaitingForData.push(MODULE_RISK_FINGERPRINT); + return true; +} + +bool Battlenet::Socket::HandleRiskFingerprintModule(BitStream* dataStream, ServerPacket** response) +{ + AuthComplete* complete = new AuthComplete(); + if (dataStream->Read(8) == 1) + { + std::ostringstream str; + str << _gameAccountId << "#1"; + + complete->GameAccountId = _gameAccountId; + complete->GameAccountName = str.str(); + complete->AccountFlags = 0x800000; // 0x1 IsGMAccount, 0x8 IsTrialAccount, 0x800000 IsProPassAccount + + LoginDatabase.PExecute("UPDATE battlenet_accounts SET last_ip = '%s', last_login = NOW(), locale = %u, failed_logins = 0, os = '%s' WHERE id = %u", _socket.getRemoteAddress().c_str(), GetLocaleByName(_locale), _os.c_str(), _accountId); + } + else + complete->SetAuthResult(AUTH_BAD_VERSION_HASH); + + ReplaceResponse(response, complete); + return false; +} + +bool Battlenet::Socket::UnhandledModule(BitStream* /*dataStream*/, ServerPacket** response) +{ + AuthComplete* complete = new AuthComplete(); + complete->SetAuthResult(AUTH_CORRUPTED_MODULE); + ReplaceResponse(response, complete); + return false; +} diff --git a/src/server/authserver/Server/BattlenetSocket.h b/src/server/authserver/Server/BattlenetSocket.h index b4db6c46251..e8014e790a8 100644 --- a/src/server/authserver/Server/BattlenetSocket.h +++ b/src/server/authserver/Server/BattlenetSocket.h @@ -21,22 +21,48 @@ #include "RealmSocket.h" #include "BattlenetPackets.h" #include "BattlenetPacketCrypt.h" +#include "BigNumber.h" + +class ACE_INET_Addr; namespace Battlenet { struct PacketHeader; class BitStream; + enum ModuleType + { + MODULE_PASSWORD, + MODULE_TOKEN, + MODULE_THUMBPRINT, + MODULE_SELECT_GAME_ACCOUNT, + MODULE_RISK_FINGERPRINT, + + MODULE_COUNT + }; + class Socket : public RealmSocket::Session { public: + static uint32 const SRP6_V_Size; + static uint32 const SRP6_S_Size; + Socket(RealmSocket& socket); typedef bool(Socket::*PacketHandler)(PacketHeader& socket, BitStream& packet); + // Auth bool HandleAuthChallenge(PacketHeader& header, BitStream& packet); bool HandleAuthProofResponse(PacketHeader& header, BitStream& packet); + // Creep + bool HandlePing(PacketHeader& header, BitStream& packet); + bool HandleEnableEncryption(PacketHeader& header, BitStream& packet); + + // WoW + bool HandleRealmUpdate(PacketHeader& header, BitStream& packet); + bool HandleRealmJoinRequest(PacketHeader& header, BitStream& packet); + void OnRead() override; void OnAccept() override; void OnClose() override; @@ -44,12 +70,40 @@ namespace Battlenet void Send(ServerPacket& packet); private: + void _SetVSFields(std::string const& rI); + static ACE_INET_Addr const& GetAddressForClient(Realm const& realm, ACE_INET_Addr const& clientAddr); + + typedef bool(Socket::*ModuleHandler)(BitStream* dataStream, ServerPacket** response); + static ModuleHandler const ModuleHandlers[MODULE_COUNT]; + + bool HandlePasswordModule(BitStream* dataStream, ServerPacket** response); + bool HandleSelectGameAccountModule(BitStream* dataStream, ServerPacket** response); + bool HandleRiskFingerprintModule(BitStream* dataStream, ServerPacket** response); + bool UnhandledModule(BitStream* dataStream, ServerPacket** response); + RealmSocket& _socket; - uint32 _currentChannel; + uint32 _accountId; std::string _accountName; std::string _locale; std::string _os; + uint32 _build; + uint32 _gameAccountId; + AccountTypes _accountSecurityLevel; + + BigNumber N; + BigNumber g; + BigNumber k; + + BigNumber I; + BigNumber s; + BigNumber v; + + BigNumber b; + BigNumber B; + BigNumber K; // session key + + std::queue _modulesWaitingForData; PacketCrypt _crypt; }; diff --git a/src/server/game/Accounts/AccountMgr.cpp b/src/server/game/Accounts/AccountMgr.cpp index d8f61a22314..adb9c55a7ac 100644 --- a/src/server/game/Accounts/AccountMgr.cpp +++ b/src/server/game/Accounts/AccountMgr.cpp @@ -32,17 +32,17 @@ AccountMgr::~AccountMgr() ClearRBAC(); } -AccountOpResult AccountMgr::CreateAccount(std::string username, std::string password, std::string email = "") +AccountOpResult AccountMgr::CreateAccount(std::string username, std::string password, std::string email /*= ""*/) { if (utf8length(username) > MAX_ACCOUNT_STR) - return AOR_NAME_TOO_LONG; // username's too long + return AccountOpResult::AOR_NAME_TOO_LONG; // username's too long - normalizeString(username); - normalizeString(password); - normalizeString(email); + Utf8ToUpperOnlyLatin(username); + Utf8ToUpperOnlyLatin(password); + Utf8ToUpperOnlyLatin(email); if (GetId(username)) - return AOR_NAME_ALREADY_EXIST; // username does already exist + return AccountOpResult::AOR_NAME_ALREADY_EXIST; // username does already exist PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_INS_ACCOUNT); @@ -56,7 +56,7 @@ AccountOpResult AccountMgr::CreateAccount(std::string username, std::string pass stmt = LoginDatabase.GetPreparedStatement(LOGIN_INS_REALM_CHARACTERS_INIT); LoginDatabase.Execute(stmt); - return AOR_OK; // everything's fine + return AccountOpResult::AOR_OK; // everything's fine } AccountOpResult AccountMgr::DeleteAccount(uint32 accountId) @@ -67,7 +67,7 @@ AccountOpResult AccountMgr::DeleteAccount(uint32 accountId) PreparedQueryResult result = LoginDatabase.Query(stmt); if (!result) - return AOR_NAME_NOT_EXIST; + return AccountOpResult::AOR_NAME_NOT_EXIST; // Obtain accounts characters stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARS_BY_ACCOUNT_ID); @@ -128,7 +128,7 @@ AccountOpResult AccountMgr::DeleteAccount(uint32 accountId) LoginDatabase.CommitTransaction(trans); - return AOR_OK; + return AccountOpResult::AOR_OK; } AccountOpResult AccountMgr::ChangeUsername(uint32 accountId, std::string newUsername, std::string newPassword) @@ -139,16 +139,16 @@ AccountOpResult AccountMgr::ChangeUsername(uint32 accountId, std::string newUser PreparedQueryResult result = LoginDatabase.Query(stmt); if (!result) - return AOR_NAME_NOT_EXIST; + return AccountOpResult::AOR_NAME_NOT_EXIST; if (utf8length(newUsername) > MAX_ACCOUNT_STR) - return AOR_NAME_TOO_LONG; + return AccountOpResult::AOR_NAME_TOO_LONG; if (utf8length(newPassword) > MAX_ACCOUNT_STR) - return AOR_PASS_TOO_LONG; + return AccountOpResult::AOR_PASS_TOO_LONG; - normalizeString(newUsername); - normalizeString(newPassword); + Utf8ToUpperOnlyLatin(newUsername); + Utf8ToUpperOnlyLatin(newPassword); stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_USERNAME); @@ -158,7 +158,7 @@ AccountOpResult AccountMgr::ChangeUsername(uint32 accountId, std::string newUser LoginDatabase.Execute(stmt); - return AOR_OK; + return AccountOpResult::AOR_OK; } AccountOpResult AccountMgr::ChangePassword(uint32 accountId, std::string newPassword) @@ -166,13 +166,13 @@ AccountOpResult AccountMgr::ChangePassword(uint32 accountId, std::string newPass std::string username; if (!GetName(accountId, username)) - return AOR_NAME_NOT_EXIST; // account doesn't exist + return AccountOpResult::AOR_NAME_NOT_EXIST; // account doesn't exist if (utf8length(newPassword) > MAX_ACCOUNT_STR) - return AOR_PASS_TOO_LONG; + return AccountOpResult::AOR_PASS_TOO_LONG; - normalizeString(username); - normalizeString(newPassword); + Utf8ToUpperOnlyLatin(username); + Utf8ToUpperOnlyLatin(newPassword); PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_PASSWORD); @@ -189,7 +189,7 @@ AccountOpResult AccountMgr::ChangePassword(uint32 accountId, std::string newPass LoginDatabase.Execute(stmt); - return AOR_OK; + return AccountOpResult::AOR_OK; } AccountOpResult AccountMgr::ChangeEmail(uint32 accountId, std::string newEmail) @@ -197,13 +197,13 @@ AccountOpResult AccountMgr::ChangeEmail(uint32 accountId, std::string newEmail) std::string username; if (!GetName(accountId, username)) - return AOR_NAME_NOT_EXIST; // account doesn't exist + return AccountOpResult::AOR_NAME_NOT_EXIST; // account doesn't exist if (utf8length(newEmail) > MAX_EMAIL_STR) - return AOR_EMAIL_TOO_LONG; + return AccountOpResult::AOR_EMAIL_TOO_LONG; - normalizeString(username); - normalizeString(newEmail); + Utf8ToUpperOnlyLatin(username); + Utf8ToUpperOnlyLatin(newEmail); PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_EMAIL); @@ -212,7 +212,7 @@ AccountOpResult AccountMgr::ChangeEmail(uint32 accountId, std::string newEmail) LoginDatabase.Execute(stmt); - return AOR_OK; + return AccountOpResult::AOR_OK; } AccountOpResult AccountMgr::ChangeRegEmail(uint32 accountId, std::string newEmail) @@ -220,13 +220,13 @@ AccountOpResult AccountMgr::ChangeRegEmail(uint32 accountId, std::string newEmai std::string username; if (!GetName(accountId, username)) - return AOR_NAME_NOT_EXIST; // account doesn't exist + return AccountOpResult::AOR_NAME_NOT_EXIST; // account doesn't exist if (utf8length(newEmail) > MAX_EMAIL_STR) - return AOR_EMAIL_TOO_LONG; + return AccountOpResult::AOR_EMAIL_TOO_LONG; - normalizeString(username); - normalizeString(newEmail); + Utf8ToUpperOnlyLatin(username); + Utf8ToUpperOnlyLatin(newEmail); PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_REG_EMAIL); @@ -235,7 +235,7 @@ AccountOpResult AccountMgr::ChangeRegEmail(uint32 accountId, std::string newEmai LoginDatabase.Execute(stmt); - return AOR_OK; + return AccountOpResult::AOR_OK; } uint32 AccountMgr::GetId(std::string const& username) @@ -303,8 +303,8 @@ bool AccountMgr::CheckPassword(uint32 accountId, std::string password) if (!GetName(accountId, username)) return false; - normalizeString(username); - normalizeString(password); + Utf8ToUpperOnlyLatin(username); + Utf8ToUpperOnlyLatin(password); PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_CHECK_PASSWORD); stmt->setUInt32(0, accountId); @@ -322,8 +322,8 @@ bool AccountMgr::CheckEmail(uint32 accountId, std::string newEmail) if (!GetEmail(accountId, oldEmail)) return false; - normalizeString(oldEmail); - normalizeString(newEmail); + Utf8ToUpperOnlyLatin(oldEmail); + Utf8ToUpperOnlyLatin(newEmail); if (strcmp(oldEmail.c_str(), newEmail.c_str()) == 0) return true; @@ -341,19 +341,6 @@ uint32 AccountMgr::GetCharactersCount(uint32 accountId) return (result) ? (*result)[0].GetUInt64() : 0; } -bool AccountMgr::normalizeString(std::string& utf8String) -{ - wchar_t buffer[MAX_ACCOUNT_STR+1]; - - size_t maxLength = MAX_ACCOUNT_STR; - if (!Utf8toWStr(utf8String, buffer, maxLength)) - return false; - - std::transform(&buffer[0], buffer+maxLength, &buffer[0], wcharToUpperOnlyLatin); - - return WStrToUtf8(buffer, maxLength, utf8String); -} - std::string AccountMgr::CalculateShaPassHash(std::string const& name, std::string const& password) { SHA1Hash sha; diff --git a/src/server/game/Accounts/AccountMgr.h b/src/server/game/Accounts/AccountMgr.h index b3012ace177..f39873f0ebf 100644 --- a/src/server/game/Accounts/AccountMgr.h +++ b/src/server/game/Accounts/AccountMgr.h @@ -22,7 +22,7 @@ #include "RBAC.h" #include -enum AccountOpResult +enum class AccountOpResult : uint8 { AOR_OK, AOR_NAME_TOO_LONG, @@ -40,6 +40,7 @@ enum PasswordChangeSecurity PW_RBAC }; +#define MAX_PASS_STR 16 #define MAX_ACCOUNT_STR 16 #define MAX_EMAIL_STR 64 @@ -58,7 +59,7 @@ class AccountMgr ~AccountMgr(); public: - AccountOpResult CreateAccount(std::string username, std::string password, std::string email); + AccountOpResult CreateAccount(std::string username, std::string password, std::string email = ""); static AccountOpResult DeleteAccount(uint32 accountId); static AccountOpResult ChangeUsername(uint32 accountId, std::string newUsername, std::string newPassword); static AccountOpResult ChangePassword(uint32 accountId, std::string newPassword); @@ -75,7 +76,6 @@ class AccountMgr static uint32 GetCharactersCount(uint32 accountId); static std::string CalculateShaPassHash(std::string const& name, std::string const& password); - static bool normalizeString(std::string& utf8String); static bool IsPlayerAccount(uint32 gmlevel); static bool IsAdminAccount(uint32 gmlevel); static bool IsConsoleAccount(uint32 gmlevel); diff --git a/src/server/game/Accounts/BattlenetAccountMgr.cpp b/src/server/game/Accounts/BattlenetAccountMgr.cpp new file mode 100644 index 00000000000..d03e356a900 --- /dev/null +++ b/src/server/game/Accounts/BattlenetAccountMgr.cpp @@ -0,0 +1,133 @@ +/* + * Copyright (C) 2008-2014 TrinityCore + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ + +#include "AccountMgr.h" +#include "BattlenetAccountMgr.h" +#include "DatabaseEnv.h" +#include "Util.h" +#include "SHA256.h" + +AccountOpResult Battlenet::AccountMgr::CreateBattlenetAccount(std::string email, std::string password) +{ + if (utf8length(email) > 64) + return AccountOpResult::AOR_NAME_TOO_LONG; + + Utf8ToUpperOnlyLatin(email); + Utf8ToUpperOnlyLatin(password); + + if (GetId(email)) + return AccountOpResult::AOR_NAME_ALREADY_EXIST; + + LoginDatabase.EscapeString(email); + LoginDatabase.DirectPExecute("INSERT INTO battlenet_accounts (`email`,`sha_pass_hash`) VALUES ('%s', '%s')", email.c_str(), CalculateShaPassHash(email, password).c_str()); + + return AccountOpResult::AOR_OK; +} + +AccountOpResult Battlenet::AccountMgr::ChangeUsername(uint32 accountId, std::string newUsername, std::string newPassword) +{ + // Check if accounts exists + QueryResult result = LoginDatabase.PQuery("SELECT 1 FROM battlenet_accounts WHERE id = %u", accountId); + + if (!result) + return AccountOpResult::AOR_NAME_NOT_EXIST; + + if (utf8length(newUsername) > MAX_ACCOUNT_STR) + return AccountOpResult::AOR_NAME_TOO_LONG; + + if (utf8length(newPassword) > MAX_PASS_STR) + return AccountOpResult::AOR_PASS_TOO_LONG; + + Utf8ToUpperOnlyLatin(newUsername); + Utf8ToUpperOnlyLatin(newPassword); + + LoginDatabase.EscapeString(newUsername); + LoginDatabase.EscapeString(newPassword); + LoginDatabase.PExecute("UPDATE account SET v = '', s = '', username = '%s', sha_pass_hash = '%s' WHERE id = '%u'", + newUsername.c_str(), CalculateShaPassHash(newUsername, newPassword).c_str(), newPassword.c_str(), accountId); + + return AccountOpResult::AOR_OK; +} + +AccountOpResult Battlenet::AccountMgr::ChangePassword(uint32 accountId, std::string newPassword) +{ + std::string username; + if (!GetName(accountId, username)) + return AccountOpResult::AOR_NAME_NOT_EXIST; // account doesn't exist + + if (utf8length(newPassword) > MAX_PASS_STR) + return AccountOpResult::AOR_PASS_TOO_LONG; + + Utf8ToUpperOnlyLatin(username); + Utf8ToUpperOnlyLatin(newPassword); + + LoginDatabase.EscapeString(newPassword); + LoginDatabase.PExecute("UPDATE account SET v = '', s = '', sha_pass_hash = '%s' WHERE id = '%u'", + CalculateShaPassHash(username, newPassword).c_str(), newPassword.c_str(), accountId); + + return AccountOpResult::AOR_OK; +} + +uint32 Battlenet::AccountMgr::GetId(std::string const& username) +{ + QueryResult result = LoginDatabase.PQuery("SELECT id FROM battlenet_accounts WHERE email = '%s'", username.c_str()); + + return result ? (*result)[0].GetUInt32() : 0; +} + +bool Battlenet::AccountMgr::GetName(uint32 accountId, std::string& name) +{ + QueryResult result = LoginDatabase.PQuery("SELECT email FROM battlenet_accounts WHERE id = '%u'", accountId); + + if (result) + { + name = (*result)[0].GetString(); + return true; + } + + return false; +} + +bool Battlenet::AccountMgr::CheckPassword(uint32 accountId, std::string password) +{ + std::string username; + + if (!GetName(accountId, username)) + return false; + + Utf8ToUpperOnlyLatin(username); + Utf8ToUpperOnlyLatin(password); + + QueryResult result = LoginDatabase.PQuery("SELECT 1 FROM battlenet_accounts WHERE id = %u AND sha_pass_hash = '%s'", accountId, CalculateShaPassHash(username, password)); + + return (result) ? true : false; +} + +std::string Battlenet::AccountMgr::CalculateShaPassHash(std::string const& name, std::string const& password) +{ + SHA256Hash email; + email.UpdateData(name); + email.Finalize(); + + SHA256Hash sha; + sha.UpdateData(ByteArrayToHexStr(email.GetDigest(), email.GetLength())); + sha.UpdateData(":"); + sha.UpdateData(password); + sha.Finalize(); + + return ByteArrayToHexStr(sha.GetDigest(), sha.GetLength(), true); +} diff --git a/src/server/game/Accounts/BattlenetAccountMgr.h b/src/server/game/Accounts/BattlenetAccountMgr.h new file mode 100644 index 00000000000..07191d24313 --- /dev/null +++ b/src/server/game/Accounts/BattlenetAccountMgr.h @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2008-2014 TrinityCore + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ + +#ifndef BattlenetAccountMgr_h__ +#define BattlenetAccountMgr_h__ + +#include "Define.h" +#include +#include + +enum class AccountOpResult : uint8; + +#define MAX_BNET_EMAIL_STR 320 + +namespace Battlenet +{ + namespace AccountMgr + { + AccountOpResult CreateBattlenetAccount(std::string email, std::string password); + AccountOpResult ChangeUsername(uint32 accountId, std::string newUsername, std::string newPassword); + AccountOpResult ChangePassword(uint32 accountId, std::string newPassword); + bool CheckPassword(uint32 accountId, std::string password); + + uint32 GetId(std::string const& username); + bool GetName(uint32 accountId, std::string& name); + + std::string CalculateShaPassHash(std::string const& name, std::string const& password); + } +} + +#endif // BattlenetAccountMgr_h__ diff --git a/src/server/scripts/Commands/cs_account.cpp b/src/server/scripts/Commands/cs_account.cpp index 3c9714ca55a..a438cd995e7 100644 --- a/src/server/scripts/Commands/cs_account.cpp +++ b/src/server/scripts/Commands/cs_account.cpp @@ -23,6 +23,7 @@ Category: commandscripts EndScriptData */ #include "AccountMgr.h" +#include "BattlenetAccountMgr.h" #include "Chat.h" #include "Language.h" #include "Player.h" @@ -126,10 +127,15 @@ public: if (!accountName || !password) return false; - AccountOpResult result = sAccountMgr->CreateAccount(std::string(accountName), std::string(password), email); + AccountOpResult result; + if (strchr(accountName, '@')) + result = Battlenet::AccountMgr::CreateBattlenetAccount(std::string(accountName), std::string(password)); + else + result = sAccountMgr->CreateAccount(std::string(accountName), std::string(password), email); + switch (result) { - case AOR_OK: + case AccountOpResult::AOR_OK: handler->PSendSysMessage(LANG_ACCOUNT_CREATED, accountName); if (handler->GetSession()) { @@ -139,15 +145,15 @@ public: accountName, email.c_str()); } break; - case AOR_NAME_TOO_LONG: + case AccountOpResult::AOR_NAME_TOO_LONG: handler->SendSysMessage(LANG_ACCOUNT_TOO_LONG); handler->SetSentErrorMessage(true); return false; - case AOR_NAME_ALREADY_EXIST: + case AccountOpResult::AOR_NAME_ALREADY_EXIST: handler->SendSysMessage(LANG_ACCOUNT_ALREADY_EXIST); handler->SetSentErrorMessage(true); return false; - case AOR_DB_INTERNAL_ERROR: + case AccountOpResult::AOR_DB_INTERNAL_ERROR: handler->PSendSysMessage(LANG_ACCOUNT_NOT_CREATED_SQL_ERROR, accountName); handler->SetSentErrorMessage(true); return false; @@ -173,7 +179,7 @@ public: return false; std::string accountName = account; - if (!AccountMgr::normalizeString(accountName)) + if (!Utf8ToUpperOnlyLatin(accountName)) { handler->PSendSysMessage(LANG_ACCOUNT_NOT_EXIST, accountName.c_str()); handler->SetSentErrorMessage(true); @@ -197,14 +203,14 @@ public: AccountOpResult result = AccountMgr::DeleteAccount(accountId); switch (result) { - case AOR_OK: + case AccountOpResult::AOR_OK: handler->PSendSysMessage(LANG_ACCOUNT_DELETED, accountName.c_str()); break; - case AOR_NAME_NOT_EXIST: + case AccountOpResult::AOR_NAME_NOT_EXIST: handler->PSendSysMessage(LANG_ACCOUNT_NOT_EXIST, accountName.c_str()); handler->SetSentErrorMessage(true); return false; - case AOR_DB_INTERNAL_ERROR: + case AccountOpResult::AOR_DB_INTERNAL_ERROR: handler->PSendSysMessage(LANG_ACCOUNT_NOT_DELETED_SQL_ERROR, accountName.c_str()); handler->SetSentErrorMessage(true); return false; @@ -416,14 +422,14 @@ public: AccountOpResult result = AccountMgr::ChangeEmail(handler->GetSession()->GetAccountId(), std::string(email)); switch (result) { - case AOR_OK: + case AccountOpResult::AOR_OK: handler->SendSysMessage(LANG_COMMAND_EMAIL); TC_LOG_INFO("entities.player.character", "Account: %u (IP: %s) Character:[%s] (GUID: %u) Changed Email from [%s] to [%s].", handler->GetSession()->GetAccountId(), handler->GetSession()->GetRemoteAddress().c_str(), handler->GetSession()->GetPlayer()->GetName().c_str(), handler->GetSession()->GetPlayer()->GetGUIDLow(), oldEmail, email); break; - case AOR_EMAIL_TOO_LONG: + case AccountOpResult::AOR_EMAIL_TOO_LONG: handler->SendSysMessage(LANG_EMAIL_TOO_LONG); handler->SetSentErrorMessage(true); return false; @@ -501,13 +507,13 @@ public: AccountOpResult result = AccountMgr::ChangePassword(handler->GetSession()->GetAccountId(), std::string(newPassword)); switch (result) { - case AOR_OK: + case AccountOpResult::AOR_OK: handler->SendSysMessage(LANG_COMMAND_PASSWORD); TC_LOG_INFO("entities.player.character", "Account: %u (IP: %s) Character:[%s] (GUID: %u) Changed Password.", handler->GetSession()->GetAccountId(), handler->GetSession()->GetRemoteAddress().c_str(), handler->GetSession()->GetPlayer()->GetName().c_str(), handler->GetSession()->GetPlayer()->GetGUIDLow()); break; - case AOR_PASS_TOO_LONG: + case AccountOpResult::AOR_PASS_TOO_LONG: handler->SendSysMessage(LANG_PASSWORD_TOO_LONG); handler->SetSentErrorMessage(true); return false; @@ -586,7 +592,7 @@ public: { ///- Convert Account name to Upper Format accountName = account; - if (!AccountMgr::normalizeString(accountName)) + if (!Utf8ToUpperOnlyLatin(accountName)) { handler->PSendSysMessage(LANG_ACCOUNT_NOT_EXIST, accountName.c_str()); handler->SetSentErrorMessage(true); @@ -656,7 +662,7 @@ public: if (isAccountNameGiven) { targetAccountName = arg1; - if (!AccountMgr::normalizeString(targetAccountName)) + if (!Utf8ToUpperOnlyLatin(targetAccountName)) { handler->PSendSysMessage(LANG_ACCOUNT_NOT_EXIST, targetAccountName.c_str()); handler->SetSentErrorMessage(true); @@ -744,7 +750,7 @@ public: return false; std::string accountName = account; - if (!AccountMgr::normalizeString(accountName)) + if (!Utf8ToUpperOnlyLatin(accountName)) { handler->PSendSysMessage(LANG_ACCOUNT_NOT_EXIST, accountName.c_str()); handler->SetSentErrorMessage(true); @@ -775,14 +781,14 @@ public: switch (result) { - case AOR_OK: + case AccountOpResult::AOR_OK: handler->SendSysMessage(LANG_COMMAND_PASSWORD); break; - case AOR_NAME_NOT_EXIST: + case AccountOpResult::AOR_NAME_NOT_EXIST: handler->PSendSysMessage(LANG_ACCOUNT_NOT_EXIST, accountName.c_str()); handler->SetSentErrorMessage(true); return false; - case AOR_PASS_TOO_LONG: + case AccountOpResult::AOR_PASS_TOO_LONG: handler->SendSysMessage(LANG_PASSWORD_TOO_LONG); handler->SetSentErrorMessage(true); return false; @@ -813,7 +819,7 @@ public: } std::string accountName = account; - if (!AccountMgr::normalizeString(accountName)) + if (!Utf8ToUpperOnlyLatin(accountName)) { handler->PSendSysMessage(LANG_ACCOUNT_NOT_EXIST, accountName.c_str()); handler->SetSentErrorMessage(true); @@ -843,16 +849,16 @@ public: AccountOpResult result = AccountMgr::ChangeEmail(targetAccountId, email); switch (result) { - case AOR_OK: + case AccountOpResult::AOR_OK: handler->SendSysMessage(LANG_COMMAND_EMAIL); TC_LOG_INFO("entities.player.character", "ChangeEmail: Account %s [Id: %u] had it's email changed to %s.", accountName.c_str(), targetAccountId, email); break; - case AOR_NAME_NOT_EXIST: + case AccountOpResult::AOR_NAME_NOT_EXIST: handler->PSendSysMessage(LANG_ACCOUNT_NOT_EXIST, accountName.c_str()); handler->SetSentErrorMessage(true); return false; - case AOR_EMAIL_TOO_LONG: + case AccountOpResult::AOR_EMAIL_TOO_LONG: handler->SendSysMessage(LANG_EMAIL_TOO_LONG); handler->SetSentErrorMessage(true); return false; @@ -889,7 +895,7 @@ public: } std::string accountName = account; - if (!AccountMgr::normalizeString(accountName)) + if (!Utf8ToUpperOnlyLatin(accountName)) { handler->PSendSysMessage(LANG_ACCOUNT_NOT_EXIST, accountName.c_str()); handler->SetSentErrorMessage(true); @@ -919,16 +925,16 @@ public: AccountOpResult result = AccountMgr::ChangeRegEmail(targetAccountId, email); switch (result) { - case AOR_OK: + case AccountOpResult::AOR_OK: handler->SendSysMessage(LANG_COMMAND_EMAIL); TC_LOG_INFO("entities.player.character", "ChangeRegEmail: Account %s [Id: %u] had it's Registration Email changed to %s.", accountName.c_str(), targetAccountId, email); break; - case AOR_NAME_NOT_EXIST: + case AccountOpResult::AOR_NAME_NOT_EXIST: handler->PSendSysMessage(LANG_ACCOUNT_NOT_EXIST, accountName.c_str()); handler->SetSentErrorMessage(true); return false; - case AOR_EMAIL_TOO_LONG: + case AccountOpResult::AOR_EMAIL_TOO_LONG: handler->SendSysMessage(LANG_EMAIL_TOO_LONG); handler->SetSentErrorMessage(true); return false; diff --git a/src/server/scripts/Commands/cs_ban.cpp b/src/server/scripts/Commands/cs_ban.cpp index afaf5f651bc..ab962b69869 100644 --- a/src/server/scripts/Commands/cs_ban.cpp +++ b/src/server/scripts/Commands/cs_ban.cpp @@ -174,7 +174,7 @@ public: switch (mode) { case BAN_ACCOUNT: - if (!AccountMgr::normalizeString(nameOrIP)) + if (!Utf8ToUpperOnlyLatin(nameOrIP)) { handler->PSendSysMessage(LANG_ACCOUNT_NOT_EXIST, nameOrIP.c_str()); handler->SetSentErrorMessage(true); @@ -245,7 +245,7 @@ public: return false; std::string accountName = nameStr; - if (!AccountMgr::normalizeString(accountName)) + if (!Utf8ToUpperOnlyLatin(accountName)) { handler->PSendSysMessage(LANG_ACCOUNT_NOT_EXIST, accountName.c_str()); handler->SetSentErrorMessage(true); @@ -710,7 +710,7 @@ public: switch (mode) { case BAN_ACCOUNT: - if (!AccountMgr::normalizeString(nameOrIP)) + if (!Utf8ToUpperOnlyLatin(nameOrIP)) { handler->PSendSysMessage(LANG_ACCOUNT_NOT_EXIST, nameOrIP.c_str()); handler->SetSentErrorMessage(true); diff --git a/src/server/scripts/Commands/cs_character.cpp b/src/server/scripts/Commands/cs_character.cpp index ffdc9deeae3..0c6d495a360 100644 --- a/src/server/scripts/Commands/cs_character.cpp +++ b/src/server/scripts/Commands/cs_character.cpp @@ -858,7 +858,7 @@ public: return false; std::string accountName = accountStr; - if (!AccountMgr::normalizeString(accountName)) + if (!Utf8ToUpperOnlyLatin(accountName)) { handler->PSendSysMessage(LANG_ACCOUNT_NOT_EXIST, accountName.c_str()); handler->SetSentErrorMessage(true); diff --git a/src/server/scripts/Commands/cs_lookup.cpp b/src/server/scripts/Commands/cs_lookup.cpp index 15d065f127e..64829a46a05 100644 --- a/src/server/scripts/Commands/cs_lookup.cpp +++ b/src/server/scripts/Commands/cs_lookup.cpp @@ -1218,8 +1218,7 @@ public: char* limitStr = strtok(NULL, " "); int32 limit = limitStr ? atoi(limitStr) : -1; - if (!AccountMgr::normalizeString - (account)) + if (!Utf8ToUpperOnlyLatin(account)) return false; PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_ACCOUNT_LIST_BY_NAME); diff --git a/src/server/scripts/Commands/cs_rbac.cpp b/src/server/scripts/Commands/cs_rbac.cpp index 47fa01837f6..080e868a924 100644 --- a/src/server/scripts/Commands/cs_rbac.cpp +++ b/src/server/scripts/Commands/cs_rbac.cpp @@ -142,7 +142,7 @@ public: { accountName = param1; - if (AccountMgr::normalizeString(accountName)) + if (Utf8ToUpperOnlyLatin(accountName)) accountId = AccountMgr::GetId(accountName); if (!accountId) diff --git a/src/server/shared/Database/Implementation/LoginDatabase.cpp b/src/server/shared/Database/Implementation/LoginDatabase.cpp index de1e5b992e6..07158dfcbdb 100644 --- a/src/server/shared/Database/Implementation/LoginDatabase.cpp +++ b/src/server/shared/Database/Implementation/LoginDatabase.cpp @@ -22,7 +22,7 @@ void LoginDatabaseConnection::DoPrepareStatements() if (!m_reconnecting) m_stmts.resize(MAX_LOGINDATABASE_STATEMENTS); - PrepareStatement(LOGIN_SEL_REALMLIST, "SELECT id, name, address, localAddress, localSubnetMask, port, icon, flag, timezone, allowedSecurityLevel, population, gamebuild FROM realmlist WHERE flag <> 3 ORDER BY name", CONNECTION_SYNCH); + PrepareStatement(LOGIN_SEL_REALMLIST, "SELECT id, name, address, localAddress, localSubnetMask, port, icon, flag, timezone, allowedSecurityLevel, population, gamebuild, Region, Battlegroup FROM realmlist WHERE flag <> 3 ORDER BY name", CONNECTION_SYNCH); PrepareStatement(LOGIN_DEL_EXPIRED_IP_BANS, "DELETE FROM ip_banned WHERE unbandate<>bandate AND unbandate<=UNIX_TIMESTAMP()", CONNECTION_ASYNC); PrepareStatement(LOGIN_UPD_EXPIRED_ACCOUNT_BANS, "UPDATE account_banned SET active = 0 WHERE active = 1 AND unbandate<>bandate AND unbandate<=UNIX_TIMESTAMP()", CONNECTION_SYNCH); PrepareStatement(LOGIN_SEL_IP_BANNED, "SELECT * FROM ip_banned WHERE ip = ?", CONNECTION_SYNCH); diff --git a/src/server/shared/Utilities/Util.cpp b/src/server/shared/Utilities/Util.cpp index 05d5d2c0749..c26b981dab9 100644 --- a/src/server/shared/Utilities/Util.cpp +++ b/src/server/shared/Utilities/Util.cpp @@ -524,6 +524,17 @@ void vutf8printf(FILE* out, const char *str, va_list* ap) #endif } +bool Utf8ToUpperOnlyLatin(std::string& utf8String) +{ + std::wstring wstr; + if (!Utf8toWStr(utf8String, wstr)) + return false; + + std::transform(wstr.begin(), wstr.end(), wstr.begin(), wcharToUpperOnlyLatin); + + return WStrToUtf8(wstr, utf8String); +} + std::string ByteArrayToHexStr(uint8 const* bytes, uint32 arrayLen, bool reverse /* = false */) { int32 init = 0; diff --git a/src/server/shared/Utilities/Util.h b/src/server/shared/Utilities/Util.h index d1cfeadff64..0fa50c68203 100644 --- a/src/server/shared/Utilities/Util.h +++ b/src/server/shared/Utilities/Util.h @@ -343,6 +343,7 @@ bool consoleToUtf8(const std::string& conStr, std::string& utf8str); bool Utf8FitTo(const std::string& str, std::wstring search); void utf8printf(FILE* out, const char *str, ...); void vutf8printf(FILE* out, const char *str, va_list* ap); +bool Utf8ToUpperOnlyLatin(std::string& utf8String); bool IsIPAddress(char const* ipaddress); diff --git a/src/server/worldserver/RemoteAccess/RASocket.cpp b/src/server/worldserver/RemoteAccess/RASocket.cpp index 6e621ddfffe..f2c7a8e0f02 100644 --- a/src/server/worldserver/RemoteAccess/RASocket.cpp +++ b/src/server/worldserver/RemoteAccess/RASocket.cpp @@ -184,7 +184,7 @@ int RASocket::check_access_level(const std::string& user) { std::string safeUser = user; - AccountMgr::normalizeString(safeUser); + Utf8ToUpperOnlyLatin(safeUser); PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_ACCOUNT_ACCESS); stmt->setString(0, safeUser); @@ -215,10 +215,10 @@ int RASocket::check_access_level(const std::string& user) int RASocket::check_password(const std::string& user, const std::string& pass) { std::string safe_user = user; - AccountMgr::normalizeString(safe_user); + Utf8ToUpperOnlyLatin(safe_user); std::string safe_pass = pass; - AccountMgr::normalizeString(safe_pass); + Utf8ToUpperOnlyLatin(safe_pass); std::string hash = AccountMgr::CalculateShaPassHash(safe_user, safe_pass); -- cgit v1.2.3 From e67e8ecd36f1e36ca72da13f3de1cfa6a0362e5c Mon Sep 17 00:00:00 2001 From: Shauren Date: Wed, 7 May 2014 09:01:46 +0200 Subject: Core/Battle.net: Send account flags in auth complete --- src/server/authserver/Server/BattlenetPackets.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/server/authserver/Server/BattlenetPackets.cpp b/src/server/authserver/Server/BattlenetPackets.cpp index 6fca44234f9..56a088939a3 100644 --- a/src/server/authserver/Server/BattlenetPackets.cpp +++ b/src/server/authserver/Server/BattlenetPackets.cpp @@ -173,7 +173,7 @@ void Battlenet::AuthComplete::Write() _stream.WriteString(GameAccountName, 5, -1); - _stream.Write(0, 64); // Account flags + _stream.Write(AccountFlags, 64); _stream.Write(0, 32); _stream.Write(0, 1); } -- cgit v1.2.3 From e085f1d90952c1bcff24868ac739582186a7dc4a Mon Sep 17 00:00:00 2001 From: Shauren Date: Sat, 10 May 2014 12:50:27 +0200 Subject: Core/Battle.net: Downgrade packet structures to 4.3.4 --- src/server/authserver/Server/BattlenetPackets.cpp | 48 +++++++++++------------ src/server/authserver/Server/BattlenetPackets.h | 27 ++++++------- src/server/authserver/Server/BattlenetSocket.cpp | 6 ++- src/server/authserver/Server/BattlenetSocket.h | 2 +- 4 files changed, 42 insertions(+), 41 deletions(-) (limited to 'src') diff --git a/src/server/authserver/Server/BattlenetPackets.cpp b/src/server/authserver/Server/BattlenetPackets.cpp index 56a088939a3..404b490a485 100644 --- a/src/server/authserver/Server/BattlenetPackets.cpp +++ b/src/server/authserver/Server/BattlenetPackets.cpp @@ -166,16 +166,14 @@ void Battlenet::AuthComplete::Write() _stream.WriteString(LastName, 8); // Last name - not set for WoW _stream.Write(GameAccountId, 32); - _stream.Write(2, 8); _stream.Write(0, 64); _stream.Write(2, 8); _stream.WriteString(GameAccountName, 5, -1); - _stream.Write(AccountFlags, 64); + _stream.Write(0, 32); - _stream.Write(0, 1); } else { @@ -222,10 +220,9 @@ void Battlenet::RealmCharacterCounts::Write() _stream.Write(CharacterCounts.size(), 7); for (CharacterCountEntry const& entry : CharacterCounts) { - _stream.Write(entry.Realm.Region, 8); - _stream.Write(0, 12); _stream.Write(entry.Realm.Battlegroup, 8); _stream.Write(entry.Realm.Index, 32); + _stream.Write(entry.Realm.Region, 8); _stream.Write(entry.CharacterCount, 16); } @@ -242,7 +239,10 @@ std::string Battlenet::RealmCharacterCounts::ToString() const stream << "Battlenet::RealmCharacterCounts Realms " << CharacterCounts.size(); for (CharacterCountEntry const& entry : CharacterCounts) - stream << std::endl << "Region " << entry.Realm.Region << " Battlegroup " << entry.Realm.Region << " Index " << entry.Realm.Index << " Characters " << entry.CharacterCount; + stream << std::endl << "Region " << uint32(entry.Realm.Region) << " Battlegroup " << uint32(entry.Realm.Region) << " Index " << entry.Realm.Index << " Characters " << entry.CharacterCount; + + for (ServerPacket* realmData : RealmData) + stream << std::endl << realmData->ToString(); return stream.str().c_str(); } @@ -250,13 +250,11 @@ std::string Battlenet::RealmCharacterCounts::ToString() const void Battlenet::RealmUpdate::Write() { _stream.Write(true, 1); // Success - _stream.Write(Timezone, 32); + _stream.Write(Type + -std::numeric_limits::min(), 32); _stream.WriteFloat(Population); + _stream.Write(Flags, 8); _stream.Write(Lock, 8); - _stream.Write(0, 19); - _stream.Write(Type + std::numeric_limits::min(), 32); - _stream.WriteString(Name, 10); - + _stream.Write(Timezone, 32); _stream.Write(!Version.empty(), 1); if (!Version.empty()) { @@ -273,18 +271,18 @@ void Battlenet::RealmUpdate::Write() _stream.WriteBytes(&port, 2); } - _stream.Write(Flags, 8); - _stream.Write(Region, 8); - _stream.Write(0, 12); + _stream.WriteString(Name, 10); + _stream.Write(Battlegroup, 8); _stream.Write(Index, 32); + _stream.Write(Region, 8); } std::string Battlenet::RealmUpdate::ToString() const { std::ostringstream stream; - stream << "Battlenet::RealmUpdate Timezone " << Timezone << " Population " << Population << " Lock " << Lock << " Type " << Type << " Name " << Name - << " Flags " << Flags << " Region " << Region << " Battlegroup " << Battlegroup << " Index " << Index; + stream << "Battlenet::RealmUpdate Timezone " << Timezone << " Population " << Population << " Lock " << uint32(Lock) << " Type " << Type << " Name " << Name + << " Flags " << uint32(Flags) << " Region " << uint32(Region) << " Battlegroup " << uint32(Battlegroup) << " Index " << Index; if (!Version.empty()) stream << " Version " << Version; @@ -294,18 +292,16 @@ std::string Battlenet::RealmUpdate::ToString() const void Battlenet::RealmJoinRequest::Read() { - ClientSeed = _stream.Read(32); - Unknown = _stream.Read(20); - Realm.Region = _stream.Read(8); - _stream.Read(12); Realm.Battlegroup = _stream.Read(8); Realm.Index = _stream.Read(32); + Realm.Region = _stream.Read(8); + ClientSeed = _stream.Read(32); } std::string Battlenet::RealmJoinRequest::ToString() const { std::ostringstream stream; - stream << "Battlenet::RealmJoinRequest ClientSeed" << ClientSeed << " Region " << Realm.Region << " Battlegroup " << Realm.Battlegroup << " Index " << Realm.Index; + stream << "Battlenet::RealmJoinRequest ClientSeed " << ClientSeed << " Region " << uint32(Realm.Region) << " Battlegroup " << uint32(Realm.Battlegroup) << " Index " << Realm.Index; return stream.str().c_str(); } @@ -313,6 +309,7 @@ void Battlenet::RealmJoinResult::Write() { _stream.Write(0, 1); // Fail _stream.Write(ServerSeed, 32); + _stream.Write(0, 5); // IPv6 addresses _stream.Write(IPv4.size(), 5); for (ACE_INET_Addr const& addr : IPv4) { @@ -325,11 +322,14 @@ void Battlenet::RealmJoinResult::Write() _stream.WriteBytes(&ip, 4); _stream.WriteBytes(&port, 2); } - - _stream.Write(0, 5); // IPv6 addresses } std::string Battlenet::RealmJoinResult::ToString() const { - return "Battlenet::RealmJoinResult"; + std::ostringstream stream; + stream << "Battlenet::RealmJoinResult ServerSeed " << ServerSeed << " Addresses (IPv4)" << IPv4.size(); + for (ACE_INET_Addr const& addr : IPv4) + stream << std::endl << "Battlenet::RealmJoinResult::Address " << GetAddressString(addr); + + return stream.str().c_str(); } diff --git a/src/server/authserver/Server/BattlenetPackets.h b/src/server/authserver/Server/BattlenetPackets.h index bea9b5649e5..9acc707bd10 100644 --- a/src/server/authserver/Server/BattlenetPackets.h +++ b/src/server/authserver/Server/BattlenetPackets.h @@ -39,30 +39,33 @@ namespace Battlenet enum AuthOpcode { 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_PROOF_REQUEST = 0x2, + SMSG_AUTH_PROOF_REQUEST = 0x2 }; enum CreepOpcodes { CMSG_PING = 0x0, CMSG_ENABLE_ENCRYPTION = 0x5, + CMSG_INVALID_PACKET = 0x9, SMSG_PONG = 0x0 }; enum WoWOpcodes { - CMSG_REALM_UPDATE = 0x0, - CMSG_JOIN_REQUEST = 0x8, - - SMSG_CHARACTER_COUNTS = 0x0, - SMSG_REALM_UPDATE = 0x2, - SMSG_REALM_UPDATE_END = 0x3, - SMSG_JOIN_RESULT = 0x8 + CMSG_REALM_UPDATE_SUBSCRIBE = 0x0, + CMSG_REALM_UPDATE_UNSUBSCRIBE = 0x1, + CMSG_JOIN_REQUEST = 0x8, + + SMSG_CHARACTER_COUNTS = 0x0, + SMSG_REALM_UPDATE = 0x2, + SMSG_REALM_UPDATE_END = 0x3, + SMSG_JOIN_RESULT = 0x8 }; struct PacketHeader @@ -118,9 +121,7 @@ namespace Battlenet public: ClientPacket(PacketHeader const& header, BitStream& stream) : Packet(header, stream) { } - void Write() override { ASSERT(!"Write not implemented for this packet."); } - - virtual std::string ToString() const override { return "Battenet::ClientPacket"; }; + void Write() override final { ASSERT(!"Write not implemented for this packet."); } }; class ServerPacket : public Packet @@ -129,9 +130,7 @@ namespace Battlenet ServerPacket(PacketHeader const& header); ~ServerPacket(); - void Read() override { ASSERT(!"Read not implemented for server packets."); } - - virtual std::string ToString() const override { return "Battenet::ServerPacket"; }; + void Read() override final { ASSERT(!"Read not implemented for server packets."); } uint8 const* GetData() const { return _stream.GetBuffer(); } size_t GetSize() const { return _stream.GetSize(); } diff --git a/src/server/authserver/Server/BattlenetSocket.cpp b/src/server/authserver/Server/BattlenetSocket.cpp index 65e12aa602d..a0597dce2a0 100644 --- a/src/server/authserver/Server/BattlenetSocket.cpp +++ b/src/server/authserver/Server/BattlenetSocket.cpp @@ -39,7 +39,7 @@ std::map InitHandlers 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_REALM_UPDATE, Battlenet::WOW)] = &Battlenet::Socket::HandleRealmUpdate; + handlers[Battlenet::PacketHeader(Battlenet::CMSG_REALM_UPDATE_SUBSCRIBE, Battlenet::WOW)] = &Battlenet::Socket::HandleRealmUpdateSubscribe; handlers[Battlenet::PacketHeader(Battlenet::CMSG_JOIN_REQUEST, Battlenet::WOW)] = &Battlenet::Socket::HandleRealmJoinRequest; return handlers; @@ -371,7 +371,7 @@ bool Battlenet::Socket::HandleEnableEncryption(PacketHeader& /*header*/, BitStre return false; } -bool Battlenet::Socket::HandleRealmUpdate(PacketHeader& /*header*/, BitStream& /*packet*/) +bool Battlenet::Socket::HandleRealmUpdateSubscribe(PacketHeader& /*header*/, BitStream& /*packet*/) { sRealmList->UpdateIfNeed(); @@ -535,6 +535,8 @@ void Battlenet::Socket::OnClose() void Battlenet::Socket::Send(ServerPacket& packet) { + TC_LOG_TRACE("server.battlenet", "Battlenet::Socket::Send %s", packet.ToString().c_str()); + packet.Write(); _crypt.EncryptSend(const_cast(packet.GetData()), packet.GetSize()); diff --git a/src/server/authserver/Server/BattlenetSocket.h b/src/server/authserver/Server/BattlenetSocket.h index e8014e790a8..ef6157b022a 100644 --- a/src/server/authserver/Server/BattlenetSocket.h +++ b/src/server/authserver/Server/BattlenetSocket.h @@ -60,7 +60,7 @@ namespace Battlenet bool HandleEnableEncryption(PacketHeader& header, BitStream& packet); // WoW - bool HandleRealmUpdate(PacketHeader& header, BitStream& packet); + bool HandleRealmUpdateSubscribe(PacketHeader& header, BitStream& packet); bool HandleRealmJoinRequest(PacketHeader& header, BitStream& packet); void OnRead() override; -- cgit v1.2.3 From daa7fd0079c09c8a28b2866d54d6fadd20f625d3 Mon Sep 17 00:00:00 2001 From: Shauren Date: Sun, 11 May 2014 22:34:13 +0200 Subject: Core/Battle.net: Fixed RealmJoinResult structure for 4.3.4 --- src/server/authserver/Server/BattlenetPackets.cpp | 1 + 1 file changed, 1 insertion(+) (limited to 'src') diff --git a/src/server/authserver/Server/BattlenetPackets.cpp b/src/server/authserver/Server/BattlenetPackets.cpp index 404b490a485..99e3fa10b14 100644 --- a/src/server/authserver/Server/BattlenetPackets.cpp +++ b/src/server/authserver/Server/BattlenetPackets.cpp @@ -307,6 +307,7 @@ std::string Battlenet::RealmJoinRequest::ToString() const void Battlenet::RealmJoinResult::Write() { + _stream.Write(0, 27); _stream.Write(0, 1); // Fail _stream.Write(ServerSeed, 32); _stream.Write(0, 5); // IPv6 addresses -- cgit v1.2.3 From a842f2ef11339df7814cacf470fe99fadafbaa45 Mon Sep 17 00:00:00 2001 From: Shauren Date: Mon, 12 May 2014 17:57:35 +0200 Subject: Core/Battle.net: Changed HandleAuthSession to work with battle.net formatted account names --- src/server/game/Server/WorldSocket.cpp | 2 +- src/server/shared/Database/Implementation/LoginDatabase.cpp | 1 + src/server/shared/Database/Implementation/LoginDatabase.h | 1 + 3 files changed, 3 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/server/game/Server/WorldSocket.cpp b/src/server/game/Server/WorldSocket.cpp index 737a2f8cbf1..cc839b5281c 100644 --- a/src/server/game/Server/WorldSocket.cpp +++ b/src/server/game/Server/WorldSocket.cpp @@ -856,7 +856,7 @@ int WorldSocket::HandleAuthSession(WorldPacket& recvPacket) // Get the account information from the realmd database // 0 1 2 3 4 5 6 7 8 // SELECT id, sessionkey, last_ip, locked, expansion, mutetime, locale, recruiter, os FROM account WHERE username = ? - PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_ACCOUNT_INFO_BY_NAME); + PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(account.find('#') == std::string::npos ? LOGIN_SEL_ACCOUNT_INFO_BY_NAME : LOGIN_SEL_ACCOUNT_INFO_BY_BNET); stmt->setString(0, account); diff --git a/src/server/shared/Database/Implementation/LoginDatabase.cpp b/src/server/shared/Database/Implementation/LoginDatabase.cpp index 07158dfcbdb..e8bb1e75d2f 100644 --- a/src/server/shared/Database/Implementation/LoginDatabase.cpp +++ b/src/server/shared/Database/Implementation/LoginDatabase.cpp @@ -44,6 +44,7 @@ void LoginDatabaseConnection::DoPrepareStatements() PrepareStatement(LOGIN_SEL_ACCOUNT_ID_BY_NAME, "SELECT id FROM account WHERE username = ?", CONNECTION_SYNCH); PrepareStatement(LOGIN_SEL_ACCOUNT_LIST_BY_NAME, "SELECT id, username FROM account WHERE username = ?", CONNECTION_SYNCH); PrepareStatement(LOGIN_SEL_ACCOUNT_INFO_BY_NAME, "SELECT id, sessionkey, last_ip, locked, expansion, mutetime, locale, recruiter, os FROM account WHERE username = ?", CONNECTION_SYNCH); + PrepareStatement(LOGIN_SEL_ACCOUNT_INFO_BY_BNET, "SELECT id, sessionkey, last_ip, locked, expansion, mutetime, locale, recruiter, os FROM account WHERE id = SUBSTRING_INDEX(?, '#', 1)", CONNECTION_SYNCH); PrepareStatement(LOGIN_SEL_ACCOUNT_LIST_BY_EMAIL, "SELECT id, username FROM account WHERE email = ?", CONNECTION_SYNCH); PrepareStatement(LOGIN_SEL_NUM_CHARS_ON_REALM, "SELECT numchars FROM realmcharacters WHERE realmid = ? AND acctid= ?", CONNECTION_SYNCH); PrepareStatement(LOGIN_SEL_ACCOUNT_BY_IP, "SELECT id, username FROM account WHERE last_ip = ?", CONNECTION_SYNCH); diff --git a/src/server/shared/Database/Implementation/LoginDatabase.h b/src/server/shared/Database/Implementation/LoginDatabase.h index 01f9fd973b6..d8e6687f755 100644 --- a/src/server/shared/Database/Implementation/LoginDatabase.h +++ b/src/server/shared/Database/Implementation/LoginDatabase.h @@ -62,6 +62,7 @@ enum LoginDatabaseStatements LOGIN_SEL_ACCOUNT_ID_BY_NAME, LOGIN_SEL_ACCOUNT_LIST_BY_NAME, LOGIN_SEL_ACCOUNT_INFO_BY_NAME, + LOGIN_SEL_ACCOUNT_INFO_BY_BNET, LOGIN_SEL_ACCOUNT_LIST_BY_EMAIL, LOGIN_SEL_NUM_CHARS_ON_REALM, LOGIN_SEL_ACCOUNT_BY_IP, -- cgit v1.2.3 From 8ec0be28027f3eda55995ef13e6e522631e36dc1 Mon Sep 17 00:00:00 2001 From: Shauren Date: Tue, 13 May 2014 22:02:51 +0200 Subject: Core/Battle.net: Use prepared statements in Battlenet::Socket --- src/server/authserver/Server/BattlenetSocket.cpp | 50 +++++++++++++++------- .../Database/Implementation/LoginDatabase.cpp | 8 ++++ .../shared/Database/Implementation/LoginDatabase.h | 9 ++++ 3 files changed, 51 insertions(+), 16 deletions(-) (limited to 'src') diff --git a/src/server/authserver/Server/BattlenetSocket.cpp b/src/server/authserver/Server/BattlenetSocket.cpp index a0597dce2a0..6723024d868 100644 --- a/src/server/authserver/Server/BattlenetSocket.cpp +++ b/src/server/authserver/Server/BattlenetSocket.cpp @@ -195,9 +195,10 @@ bool Battlenet::Socket::HandleAuthChallenge(PacketHeader& header, BitStream& pac _os = info.Platform; Utf8ToUpperOnlyLatin(_accountName); - LoginDatabase.EscapeString(_accountName); - // 0 1 2 3 4 5 6 - QueryResult result = LoginDatabase.PQuery("SELECT sha_pass_hash, id, locked, lock_country, last_ip, v, s FROM battlenet_accounts WHERE email = '%s'", _accountName.c_str()); + stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_BNET_ACCOUNT_INFO); + stmt->setString(0, _accountName); + + PreparedQueryResult result = LoginDatabase.Query(stmt); if (!result) { AuthComplete complete; @@ -252,10 +253,12 @@ bool Battlenet::Socket::HandleAuthChallenge(PacketHeader& header, BitStream& pac } //set expired bans to inactive - LoginDatabase.DirectExecute("UPDATE battlenet_account_bans SET active = 0 WHERE active = 1 AND unbandate <> bandate AND unbandate <= UNIX_TIMESTAMP()"); + LoginDatabase.DirectExecute(LoginDatabase.GetPreparedStatement(LOGIN_DEL_BNET_EXPIRED_BANS)); // If the account is banned, reject the logon attempt - QueryResult banresult = LoginDatabase.PQuery("SELECT bandate, unbandate FROM battlenet_account_bans WHERE id = %u AND active = 1", _accountId); + stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_BNET_ACTIVE_ACCOUNT_BAN); + stmt->setUInt32(0, _accountId); + PreparedQueryResult banresult = LoginDatabase.Query(stmt); if (banresult) { Field* fields = banresult->Fetch(); @@ -380,17 +383,23 @@ bool Battlenet::Socket::HandleRealmUpdateSubscribe(PacketHeader& /*header*/, Bit ACE_INET_Addr clientAddr; _socket.peer().get_remote_addr(clientAddr); + PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_BNET_CHARACTER_COUNTS); + stmt->setUInt32(0, _gameAccountId); + + if (PreparedQueryResult countResult = LoginDatabase.Query(stmt)) + { + do + { + Field* fields = countResult->Fetch(); + uint32 build = fields[4].GetUInt32(); + counts.CharacterCounts.push_back({ { fields[2].GetUInt8(), fields[3].GetUInt8(), fields[1].GetUInt32(), (_build != build ? build : 0) }, fields[0].GetUInt8() }); + } while (countResult->NextRow()); + } + for (RealmList::RealmMap::const_iterator i = sRealmList->begin(); i != sRealmList->end(); ++i) { Realm const& realm = i->second; - PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_NUM_CHARS_ON_REALM); - stmt->setUInt32(0, realm.m_ID); - stmt->setUInt32(1, _gameAccountId); - - if (PreparedQueryResult result = LoginDatabase.Query(stmt)) - counts.CharacterCounts.push_back({ { realm.Region, realm.Battlegroup, realm.m_ID, 0 }, (*result)[0].GetUInt8() }); - uint32 flag = realm.flag; RealmBuildInfo const* buildInfo = AuthHelper::GetBuildInfo(realm.gamebuild); if (realm.gamebuild != _build) @@ -656,7 +665,9 @@ bool Battlenet::Socket::HandlePasswordModule(BitStream* dataStream, ServerPacket } uint64 numAccounts = 0; - QueryResult result = LoginDatabase.PQuery("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 = '%u'", _accountId); + PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_BNET_GAME_ACCOUNTS); + stmt->setUInt32(0, _accountId); + PreparedQueryResult result = LoginDatabase.Query(stmt); if (result) numAccounts = result->GetRowCount(); @@ -759,8 +770,10 @@ bool Battlenet::Socket::HandleSelectGameAccountModule(BitStream* dataStream, Ser dataStream->Read(8); std::string account = dataStream->ReadString(8); - LoginDatabase.EscapeString(account); - QueryResult result = LoginDatabase.PQuery("SELECT a.id, ab.bandate, ab.unbandate, ab.active FROM account a LEFT JOIN account_banned ab ON a.id = ab.id WHERE username = '%s' AND battlenet_account = '%u'", account.c_str(), _accountId); + PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_BNET_GAME_ACCOUNT); + stmt->setString(0, account); + stmt->setUInt32(1, _accountId); + PreparedQueryResult result = LoginDatabase.Query(stmt); if (!result) { AuthComplete* complete = new AuthComplete(); @@ -810,7 +823,12 @@ bool Battlenet::Socket::HandleRiskFingerprintModule(BitStream* dataStream, Serve complete->GameAccountName = str.str(); complete->AccountFlags = 0x800000; // 0x1 IsGMAccount, 0x8 IsTrialAccount, 0x800000 IsProPassAccount - LoginDatabase.PExecute("UPDATE battlenet_accounts SET last_ip = '%s', last_login = NOW(), locale = %u, failed_logins = 0, os = '%s' WHERE id = %u", _socket.getRemoteAddress().c_str(), GetLocaleByName(_locale), _os.c_str(), _accountId); + 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); } else complete->SetAuthResult(AUTH_BAD_VERSION_HASH); diff --git a/src/server/shared/Database/Implementation/LoginDatabase.cpp b/src/server/shared/Database/Implementation/LoginDatabase.cpp index e8bb1e75d2f..3ff0f923af8 100644 --- a/src/server/shared/Database/Implementation/LoginDatabase.cpp +++ b/src/server/shared/Database/Implementation/LoginDatabase.cpp @@ -102,4 +102,12 @@ void LoginDatabaseConnection::DoPrepareStatements() PrepareStatement(LOGIN_SEL_RBAC_ACCOUNT_PERMISSIONS, "SELECT permissionId, granted FROM rbac_account_permissions WHERE accountId = ? AND (realmId = ? OR realmId = -1) ORDER BY permissionId, realmId", CONNECTION_SYNCH); PrepareStatement(LOGIN_INS_RBAC_ACCOUNT_PERMISSION, "INSERT INTO rbac_account_permissions (accountId, permissionId, granted, realmId) VALUES (?, ?, ?, ?) ON DUPLICATE KEY UPDATE granted = VALUES(granted)", CONNECTION_ASYNC); PrepareStatement(LOGIN_DEL_RBAC_ACCOUNT_PERMISSION, "DELETE FROM rbac_account_permissions WHERE accountId = ? AND permissionId = ? AND (realmId = ? OR realmId = -1)", CONNECTION_ASYNC); + + PrepareStatement(LOGIN_SEL_BNET_ACCOUNT_INFO, "SELECT sha_pass_hash, id, locked, lock_country, last_ip, v, s FROM battlenet_accounts WHERE email = ?", CONNECTION_SYNCH); + 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_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); + PrepareStatement(LOGIN_SEL_BNET_CHARACTER_COUNTS, "SELECT rc.numchars, r.id, r.Region, r.Battlegroup, r.gamebuild FROM realmcharacters rc INNER JOIN realmlist r ON rc.realmid = r.id WHERE rc.acctid = ?", CONNECTION_SYNCH); } diff --git a/src/server/shared/Database/Implementation/LoginDatabase.h b/src/server/shared/Database/Implementation/LoginDatabase.h index d8e6687f755..2f1edab270b 100644 --- a/src/server/shared/Database/Implementation/LoginDatabase.h +++ b/src/server/shared/Database/Implementation/LoginDatabase.h @@ -121,6 +121,15 @@ enum LoginDatabaseStatements LOGIN_SEL_RBAC_ACCOUNT_PERMISSIONS, LOGIN_INS_RBAC_ACCOUNT_PERMISSION, LOGIN_DEL_RBAC_ACCOUNT_PERMISSION, + + LOGIN_SEL_BNET_ACCOUNT_INFO, + LOGIN_DEL_BNET_EXPIRED_BANS, + LOGIN_SEL_BNET_ACTIVE_ACCOUNT_BAN, + LOGIN_SEL_BNET_GAME_ACCOUNTS, + LOGIN_SEL_BNET_GAME_ACCOUNT, + LOGIN_UPD_BNET_LAST_LOGIN_INFO, + LOGIN_SEL_BNET_CHARACTER_COUNTS, + MAX_LOGINDATABASE_STATEMENTS }; -- cgit v1.2.3 From 81b8deef529517a1f13397ff2aa13154bccf86c9 Mon Sep 17 00:00:00 2001 From: Shauren Date: Tue, 13 May 2014 23:33:02 +0200 Subject: Core/Battle.net: Use prepared statements in Battlenet::AccountMgr --- src/server/game/Accounts/BattlenetAccountMgr.cpp | 57 +++++++++++++--------- .../Database/Implementation/LoginDatabase.cpp | 5 ++ .../shared/Database/Implementation/LoginDatabase.h | 5 ++ 3 files changed, 44 insertions(+), 23 deletions(-) (limited to 'src') diff --git a/src/server/game/Accounts/BattlenetAccountMgr.cpp b/src/server/game/Accounts/BattlenetAccountMgr.cpp index d03e356a900..8b73ba19a97 100644 --- a/src/server/game/Accounts/BattlenetAccountMgr.cpp +++ b/src/server/game/Accounts/BattlenetAccountMgr.cpp @@ -32,8 +32,10 @@ AccountOpResult Battlenet::AccountMgr::CreateBattlenetAccount(std::string email, if (GetId(email)) return AccountOpResult::AOR_NAME_ALREADY_EXIST; - LoginDatabase.EscapeString(email); - LoginDatabase.DirectPExecute("INSERT INTO battlenet_accounts (`email`,`sha_pass_hash`) VALUES ('%s', '%s')", email.c_str(), CalculateShaPassHash(email, password).c_str()); + PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_INS_BNET_ACCOUNT); + stmt->setString(0, email); + stmt->setString(1, CalculateShaPassHash(email, password)); + LoginDatabase.Execute(stmt); return AccountOpResult::AOR_OK; } @@ -41,24 +43,26 @@ AccountOpResult Battlenet::AccountMgr::CreateBattlenetAccount(std::string email, AccountOpResult Battlenet::AccountMgr::ChangeUsername(uint32 accountId, std::string newUsername, std::string newPassword) { // Check if accounts exists - QueryResult result = LoginDatabase.PQuery("SELECT 1 FROM battlenet_accounts WHERE id = %u", accountId); + PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_BNET_ACCOUNT_EMAIL_BY_ID); + stmt->setUInt32(0, accountId); + PreparedQueryResult result = LoginDatabase.Query(stmt); if (!result) return AccountOpResult::AOR_NAME_NOT_EXIST; + Utf8ToUpperOnlyLatin(newUsername); if (utf8length(newUsername) > MAX_ACCOUNT_STR) return AccountOpResult::AOR_NAME_TOO_LONG; + Utf8ToUpperOnlyLatin(newPassword); if (utf8length(newPassword) > MAX_PASS_STR) return AccountOpResult::AOR_PASS_TOO_LONG; - Utf8ToUpperOnlyLatin(newUsername); - Utf8ToUpperOnlyLatin(newPassword); - - LoginDatabase.EscapeString(newUsername); - LoginDatabase.EscapeString(newPassword); - LoginDatabase.PExecute("UPDATE account SET v = '', s = '', username = '%s', sha_pass_hash = '%s' WHERE id = '%u'", - newUsername.c_str(), CalculateShaPassHash(newUsername, newPassword).c_str(), newPassword.c_str(), accountId); + stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_BNET_PASSWORD); + stmt->setString(0, newUsername); + stmt->setString(1, CalculateShaPassHash(newUsername, newPassword)); + stmt->setUInt32(2, accountId); + LoginDatabase.Execute(stmt); return AccountOpResult::AOR_OK; } @@ -69,31 +73,35 @@ AccountOpResult Battlenet::AccountMgr::ChangePassword(uint32 accountId, std::str if (!GetName(accountId, username)) return AccountOpResult::AOR_NAME_NOT_EXIST; // account doesn't exist - if (utf8length(newPassword) > MAX_PASS_STR) - return AccountOpResult::AOR_PASS_TOO_LONG; - Utf8ToUpperOnlyLatin(username); Utf8ToUpperOnlyLatin(newPassword); + if (utf8length(newPassword) > MAX_PASS_STR) + return AccountOpResult::AOR_PASS_TOO_LONG; - LoginDatabase.EscapeString(newPassword); - LoginDatabase.PExecute("UPDATE account SET v = '', s = '', sha_pass_hash = '%s' WHERE id = '%u'", - CalculateShaPassHash(username, newPassword).c_str(), newPassword.c_str(), accountId); + PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_BNET_PASSWORD); + stmt->setString(0, username); + stmt->setString(1, CalculateShaPassHash(username, newPassword)); + stmt->setUInt32(2, accountId); + LoginDatabase.Execute(stmt); return AccountOpResult::AOR_OK; } uint32 Battlenet::AccountMgr::GetId(std::string const& username) { - QueryResult result = LoginDatabase.PQuery("SELECT id FROM battlenet_accounts WHERE email = '%s'", username.c_str()); + PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_BNET_ACCOUNT_ID_BY_EMAIL); + stmt->setString(0, username); + if (PreparedQueryResult result = LoginDatabase.Query(stmt)) + return (*result)[0].GetUInt32(); - return result ? (*result)[0].GetUInt32() : 0; + return 0; } bool Battlenet::AccountMgr::GetName(uint32 accountId, std::string& name) { - QueryResult result = LoginDatabase.PQuery("SELECT email FROM battlenet_accounts WHERE id = '%u'", accountId); - - if (result) + PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_BNET_ACCOUNT_EMAIL_BY_ID); + stmt->setUInt32(0, accountId); + if (PreparedQueryResult result = LoginDatabase.Query(stmt)) { name = (*result)[0].GetString(); return true; @@ -112,9 +120,12 @@ bool Battlenet::AccountMgr::CheckPassword(uint32 accountId, std::string password Utf8ToUpperOnlyLatin(username); Utf8ToUpperOnlyLatin(password); - QueryResult result = LoginDatabase.PQuery("SELECT 1 FROM battlenet_accounts WHERE id = %u AND sha_pass_hash = '%s'", accountId, CalculateShaPassHash(username, password)); + PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_BNET_CHECK_PASSWORD); + stmt->setUInt32(0, accountId); + stmt->setString(1, CalculateShaPassHash(username, password)); + PreparedQueryResult result = LoginDatabase.Query(stmt); - return (result) ? true : false; + return !result.null(); } std::string Battlenet::AccountMgr::CalculateShaPassHash(std::string const& name, std::string const& password) diff --git a/src/server/shared/Database/Implementation/LoginDatabase.cpp b/src/server/shared/Database/Implementation/LoginDatabase.cpp index 3ff0f923af8..208873448c6 100644 --- a/src/server/shared/Database/Implementation/LoginDatabase.cpp +++ b/src/server/shared/Database/Implementation/LoginDatabase.cpp @@ -110,4 +110,9 @@ void LoginDatabaseConnection::DoPrepareStatements() 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); PrepareStatement(LOGIN_SEL_BNET_CHARACTER_COUNTS, "SELECT rc.numchars, r.id, r.Region, r.Battlegroup, r.gamebuild FROM realmcharacters rc INNER JOIN realmlist r ON rc.realmid = r.id WHERE rc.acctid = ?", CONNECTION_SYNCH); + PrepareStatement(LOGIN_INS_BNET_ACCOUNT, "INSERT INTO battlenet_accounts (`email`,`sha_pass_hash`) VALUES (?, ?)", CONNECTION_ASYNC); + PrepareStatement(LOGIN_SEL_BNET_ACCOUNT_EMAIL_BY_ID, "SELECT email FROM battlenet_accounts WHERE id = ?", CONNECTION_SYNCH); + PrepareStatement(LOGIN_SEL_BNET_ACCOUNT_ID_BY_EMAIL, "SELECT id FROM battlenet_accounts WHERE email = ?", CONNECTION_SYNCH); + PrepareStatement(LOGIN_UPD_BNET_PASSWORD, "UPDATE account SET v = '', s = '', username = ?, sha_pass_hash = ? WHERE id = ?", CONNECTION_ASYNC); + PrepareStatement(LOGIN_SEL_BNET_CHECK_PASSWORD, "SELECT 1 FROM battlenet_accounts WHERE id = %u AND sha_pass_hash = ?", CONNECTION_ASYNC); } diff --git a/src/server/shared/Database/Implementation/LoginDatabase.h b/src/server/shared/Database/Implementation/LoginDatabase.h index 2f1edab270b..18f9110409d 100644 --- a/src/server/shared/Database/Implementation/LoginDatabase.h +++ b/src/server/shared/Database/Implementation/LoginDatabase.h @@ -129,6 +129,11 @@ enum LoginDatabaseStatements LOGIN_SEL_BNET_GAME_ACCOUNT, LOGIN_UPD_BNET_LAST_LOGIN_INFO, LOGIN_SEL_BNET_CHARACTER_COUNTS, + LOGIN_INS_BNET_ACCOUNT, + LOGIN_SEL_BNET_ACCOUNT_EMAIL_BY_ID, + LOGIN_SEL_BNET_ACCOUNT_ID_BY_EMAIL, + LOGIN_UPD_BNET_PASSWORD, + LOGIN_SEL_BNET_CHECK_PASSWORD, MAX_LOGINDATABASE_STATEMENTS }; -- cgit v1.2.3 From cc748e2ba49df81c3af41fad2526f9f71b2f0a61 Mon Sep 17 00:00:00 2001 From: Shauren Date: Sat, 31 May 2014 18:19:53 +0200 Subject: Core/Battle.net: Prevent joining invalid/offline realms --- src/server/authserver/Server/BattlenetSocket.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/server/authserver/Server/BattlenetSocket.cpp b/src/server/authserver/Server/BattlenetSocket.cpp index 6723024d868..ad589507a14 100644 --- a/src/server/authserver/Server/BattlenetSocket.cpp +++ b/src/server/authserver/Server/BattlenetSocket.cpp @@ -451,7 +451,7 @@ bool Battlenet::Socket::HandleRealmJoinRequest(PacketHeader& header, BitStream& RealmJoinResult result; Realm const* realm = sRealmList->GetRealm(join.Realm); - if (!realm) + if (!realm || realm->flag & (REALM_FLAG_INVALID | REALM_FLAG_OFFLINE)) { Send(result); return true; -- cgit v1.2.3 From 914d5d53669097ee3f7bf28a14094e4697a2b2bd Mon Sep 17 00:00:00 2001 From: Shauren Date: Sun, 1 Jun 2014 02:36:50 +0200 Subject: Core/Battle.net: Fixed size check in bit stream --- src/server/authserver/Server/BattlenetBitStream.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/server/authserver/Server/BattlenetBitStream.h b/src/server/authserver/Server/BattlenetBitStream.h index a0bff314e8f..a59150f5327 100644 --- a/src/server/authserver/Server/BattlenetBitStream.h +++ b/src/server/authserver/Server/BattlenetBitStream.h @@ -138,7 +138,7 @@ namespace Battlenet if (!count || !data) return; - if (_writePos + count > MaxSize) + if ((_writePos >> 3) + count > MaxSize) throw BitStreamPositionException(); _buffer.resize(_buffer.size() + count); -- cgit v1.2.3 From a860d5ca47031a7123da901c1c26a1107901dad0 Mon Sep 17 00:00:00 2001 From: Shauren Date: Sun, 1 Jun 2014 02:37:40 +0200 Subject: Core/Crypto: Fixed values returned by HmacHash::GetLength --- src/server/shared/Cryptography/HmacHash.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/server/shared/Cryptography/HmacHash.h b/src/server/shared/Cryptography/HmacHash.h index cf59e16f08e..bf82e39a526 100644 --- a/src/server/shared/Cryptography/HmacHash.h +++ b/src/server/shared/Cryptography/HmacHash.h @@ -38,7 +38,7 @@ class HmacHash void Finalize(); uint8* ComputeHash(BigNumber* bn); uint8* GetDigest() { return _digest; } - int GetLength() const { return SHA_DIGEST_LENGTH; } + uint32 GetLength() const { return _digestLength; } private: HMAC_CTX _ctx; uint8* _digest; -- cgit v1.2.3 From db2cb70120dde10ffa210ad5af8a973cc1644355 Mon Sep 17 00:00:00 2001 From: Shauren Date: Sun, 1 Jun 2014 02:39:55 +0200 Subject: Core/Battle.net: Refactored ModuleInfo creation --- src/server/authserver/Server/BattlenetManager.cpp | 8 +++---- src/server/authserver/Server/BattlenetManager.h | 2 +- src/server/authserver/Server/BattlenetSocket.cpp | 26 +++++++++++------------ 3 files changed, 17 insertions(+), 19 deletions(-) (limited to 'src') diff --git a/src/server/authserver/Server/BattlenetManager.cpp b/src/server/authserver/Server/BattlenetManager.cpp index f8ff5d8989e..f470c365b56 100644 --- a/src/server/authserver/Server/BattlenetManager.cpp +++ b/src/server/authserver/Server/BattlenetManager.cpp @@ -87,10 +87,10 @@ bool BattlenetMgr::HasComponent(Battlenet::Component const* component) const return false; } -Battlenet::ModuleInfo const* BattlenetMgr::GetModule(Battlenet::ModuleKey const& key) const +Battlenet::ModuleInfo* BattlenetMgr::CreateModule(std::string const& os, std::string const& name) const { - if (_modules.count(key)) - return _modules.at(key); + Battlenet::ModuleKey key { os, name }; + ASSERT(_modules.count(key)); - return NULL; + return new Battlenet::ModuleInfo(*_modules.at(key)); } diff --git a/src/server/authserver/Server/BattlenetManager.h b/src/server/authserver/Server/BattlenetManager.h index 7bc12f94c62..3b8a145f4e9 100644 --- a/src/server/authserver/Server/BattlenetManager.h +++ b/src/server/authserver/Server/BattlenetManager.h @@ -94,7 +94,7 @@ public: bool HasComponent(Battlenet::Component const* component) const; bool HasProgram(std::string const& program) const { return _programs.count(program); } bool HasPlatform(std::string const& platform) const { return _platforms.count(platform); } - Battlenet::ModuleInfo const* GetModule(Battlenet::ModuleKey const& key) const; + Battlenet::ModuleInfo* CreateModule(std::string const& os, std::string const& name) const; private: void LoadComponents(); diff --git a/src/server/authserver/Server/BattlenetSocket.cpp b/src/server/authserver/Server/BattlenetSocket.cpp index ad589507a14..12b02b5963e 100644 --- a/src/server/authserver/Server/BattlenetSocket.cpp +++ b/src/server/authserver/Server/BattlenetSocket.cpp @@ -286,8 +286,8 @@ bool Battlenet::Socket::HandleAuthChallenge(PacketHeader& header, BitStream& pac I.SetBinary(sha.GetDigest(), sha.GetLength()); - ModuleInfo* password = new ModuleInfo(*sBattlenetMgr->GetModule({ _os, "Password" })); - ModuleInfo* thumbprint = new ModuleInfo(*sBattlenetMgr->GetModule({ _os, "Thumbprint" })); + ModuleInfo* password = sBattlenetMgr->CreateModule(_os, "Password"); + ModuleInfo* thumbprint = sBattlenetMgr->CreateModule(_os, "Thumbprint"); std::string pStr = fields[0].GetString(); @@ -367,11 +367,10 @@ bool Battlenet::Socket::HandlePing(PacketHeader& /*header*/, BitStream& /*packet return true; } -bool Battlenet::Socket::HandleEnableEncryption(PacketHeader& /*header*/, BitStream& packet) +bool Battlenet::Socket::HandleEnableEncryption(PacketHeader& /*header*/, BitStream& /*packet*/) { _crypt.Init(&K); - _crypt.DecryptRecv(packet.GetBuffer() + 2, packet.GetSize() - 2); - return false; + return true; } bool Battlenet::Socket::HandleRealmUpdateSubscribe(PacketHeader& /*header*/, BitStream& /*packet*/) @@ -691,7 +690,7 @@ bool Battlenet::Socket::HandlePasswordModule(BitStream* dataStream, ServerPacket M.SetBinary(sha.GetDigest(), sha.GetLength()); BitStream stream; - ModuleInfo* password = new ModuleInfo(*sBattlenetMgr->GetModule({ _os, "Password" })); + ModuleInfo* password = sBattlenetMgr->CreateModule(_os, "Password"); uint8 state = 3; stream.WriteBytes(&state, 1); @@ -717,7 +716,7 @@ bool Battlenet::Socket::HandlePasswordModule(BitStream* dataStream, ServerPacket accounts.WriteString(fields[0].GetString(), 8); } while (result->NextRow()); - ModuleInfo* selectGameAccount = new ModuleInfo(*sBattlenetMgr->GetModule({ _os, "SelectGameAccount" })); + ModuleInfo* selectGameAccount = sBattlenetMgr->CreateModule(_os, "SelectGameAccount"); selectGameAccount->DataSize = accounts.GetSize(); selectGameAccount->Data = new uint8[selectGameAccount->DataSize]; memcpy(selectGameAccount->Data, accounts.GetBuffer(), selectGameAccount->DataSize); @@ -743,17 +742,16 @@ bool Battlenet::Socket::HandlePasswordModule(BitStream* dataStream, ServerPacket } ReplaceResponse(response, complete); - return true; + return false; } _gameAccountId = (*result)[1].GetUInt32(); - request->Modules.push_back(new ModuleInfo(*sBattlenetMgr->GetModule({ _os, "RiskFingerprint" }))); + request->Modules.push_back(sBattlenetMgr->CreateModule(_os, "RiskFingerprint")); _modulesWaitingForData.push(MODULE_RISK_FINGERPRINT); } ReplaceResponse(response, request); - return true; } @@ -789,22 +787,22 @@ bool Battlenet::Socket::HandleSelectGameAccountModule(BitStream* dataStream, Ser if (fields[1].GetUInt32() == fields[2].GetUInt32()) { complete->SetAuthResult(LOGIN_BANNED); - TC_LOG_DEBUG("server.battlenet", "'%s:%d' [Battlenet::AuthChallenge] Banned account %s tried to login!", _socket.getRemoteAddress().c_str(), _socket.getRemotePort(), _accountName.c_str()); + TC_LOG_DEBUG("server.battlenet", "'%s:%d' [Battlenet::SelectGameAccount] Banned account %s tried to login!", _socket.getRemoteAddress().c_str(), _socket.getRemotePort(), _accountName.c_str()); } else { complete->SetAuthResult(LOGIN_SUSPENDED); - TC_LOG_DEBUG("server.battlenet", "'%s:%d' [Battlenet::AuthChallenge] Temporarily banned account %s tried to login!", _socket.getRemoteAddress().c_str(), _socket.getRemotePort(), _accountName.c_str()); + TC_LOG_DEBUG("server.battlenet", "'%s:%d' [Battlenet::SelectGameAccount] Temporarily banned account %s tried to login!", _socket.getRemoteAddress().c_str(), _socket.getRemotePort(), _accountName.c_str()); } ReplaceResponse(response, complete); - return true; + return false; } _gameAccountId = fields[0].GetUInt32(); ProofRequest* request = new ProofRequest(); - request->Modules.push_back(new ModuleInfo(*sBattlenetMgr->GetModule({ _os, "RiskFingerprint" }))); + request->Modules.push_back(sBattlenetMgr->CreateModule(_os, "RiskFingerprint")); ReplaceResponse(response, request); _modulesWaitingForData.push(MODULE_RISK_FINGERPRINT); -- cgit v1.2.3 From dc5c5ef6361f3f4dbb5fc9b5a755951c83f954fa Mon Sep 17 00:00:00 2001 From: Shauren Date: Sun, 1 Jun 2014 13:03:30 +0200 Subject: Core/Authserver: Refactoring - moved GetAddressForClient to Realm structure, changed BigNumber string methods to return std::string, added missing prepared statement --- src/server/authserver/Realms/RealmList.cpp | 21 ++++++++++- src/server/authserver/Realms/RealmList.h | 2 + src/server/authserver/Server/AuthSocket.cpp | 43 ++-------------------- src/server/authserver/Server/AuthSocket.h | 2 - src/server/authserver/Server/BattlenetSocket.cpp | 39 ++++---------------- src/server/authserver/Server/BattlenetSocket.h | 3 +- src/server/shared/Cryptography/BigNumber.cpp | 14 +++++-- src/server/shared/Cryptography/BigNumber.h | 5 ++- .../Database/Implementation/LoginDatabase.cpp | 3 +- .../shared/Database/Implementation/LoginDatabase.h | 1 + 10 files changed, 51 insertions(+), 82 deletions(-) (limited to 'src') diff --git a/src/server/authserver/Realms/RealmList.cpp b/src/server/authserver/Realms/RealmList.cpp index bd856623faf..48b7a178c2d 100644 --- a/src/server/authserver/Realms/RealmList.cpp +++ b/src/server/authserver/Realms/RealmList.cpp @@ -20,8 +20,27 @@ #include "RealmList.h" #include "BattlenetManager.h" #include "Database/DatabaseEnv.h" +#include "Util.h" -RealmList::RealmList() : m_UpdateInterval(0), m_NextUpdateTime(time(NULL)) { } +ACE_INET_Addr const& Realm::GetAddressForClient(ACE_INET_Addr const& clientAddr) const +{ + // Attempt to send best address for client + if (clientAddr.is_loopback()) + // Assume that user connecting from the machine that authserver is located on + // has all realms available in his local network + return LocalAddress; + + // Check if connecting client is in the same network + if (IsIPAddrInNetwork(LocalAddress, clientAddr, LocalSubnetMask)) + return LocalAddress; + + // Return external IP + return ExternalAddress; +} + +RealmList::RealmList() : m_UpdateInterval(0), m_NextUpdateTime(time(NULL)) +{ +} // Load the realm list from the database void RealmList::Initialize(uint32 updateInterval) diff --git a/src/server/authserver/Realms/RealmList.h b/src/server/authserver/Realms/RealmList.h index ab453720827..c4a6b4eaa0b 100644 --- a/src/server/authserver/Realms/RealmList.h +++ b/src/server/authserver/Realms/RealmList.h @@ -53,6 +53,8 @@ struct Realm uint32 gamebuild; uint8 Region; uint8 Battlegroup; + + ACE_INET_Addr const& GetAddressForClient(ACE_INET_Addr const& clientAddr) const; }; namespace Battlenet diff --git a/src/server/authserver/Server/AuthSocket.cpp b/src/server/authserver/Server/AuthSocket.cpp index 3afce0d77d9..8180967a92e 100644 --- a/src/server/authserver/Server/AuthSocket.cpp +++ b/src/server/authserver/Server/AuthSocket.cpp @@ -293,19 +293,11 @@ void AuthSocket::_SetVSFields(const std::string& rI) x.SetBinary(sha.GetDigest(), sha.GetLength()); v = g.ModExp(x, N); - // No SQL injection (username escaped) - char *v_hex, *s_hex; - v_hex = v.AsHexStr(); - s_hex = s.AsHexStr(); - PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_VS); - stmt->setString(0, v_hex); - stmt->setString(1, s_hex); + stmt->setString(0, v.AsHexStr()); + stmt->setString(1, s.AsHexStr()); stmt->setString(2, _login); LoginDatabase.Execute(stmt); - - OPENSSL_free(v_hex); - OPENSSL_free(s_hex); } // Logon Challenge command handler @@ -650,19 +642,14 @@ bool AuthSocket::_HandleLogonProof() TC_LOG_DEBUG("server.authserver", "'%s:%d' User '%s' successfully authenticated", socket().getRemoteAddress().c_str(), socket().getRemotePort(), _login.c_str()); // Update the sessionkey, last_ip, last login time and reset number of failed logins in the account table for this account - // No SQL injection (escaped user name) and IP address as received by socket - const char *K_hex = K.AsHexStr(); - PreparedStatement *stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_LOGONPROOF); - stmt->setString(0, K_hex); + stmt->setString(0, K.AsHexStr()); stmt->setString(1, socket().getRemoteAddress().c_str()); stmt->setUInt32(2, GetLocaleByName(_localizationName)); stmt->setString(3, _os); stmt->setString(4, _login); LoginDatabase.DirectExecute(stmt); - OPENSSL_free((void*)K_hex); - // Finish SRP6 and send the final result to the client sha.Initialize(); sha.UpdateBigNumbers(&A, &M, &K, NULL); @@ -879,28 +866,6 @@ bool AuthSocket::_HandleReconnectProof() } } -ACE_INET_Addr const& AuthSocket::GetAddressForClient(Realm const& realm, ACE_INET_Addr const& clientAddr) -{ - // Attempt to send best address for client - if (clientAddr.is_loopback()) - { - // Try guessing if realm is also connected locally - if (realm.LocalAddress.is_loopback() || realm.ExternalAddress.is_loopback()) - return clientAddr; - - // Assume that user connecting from the machine that authserver is located on - // has all realms available in his local network - return realm.LocalAddress; - } - - // Check if connecting client is in the same network - if (IsIPAddrInNetwork(realm.LocalAddress, clientAddr, realm.LocalSubnetMask)) - return realm.LocalAddress; - - // Return external IP - return realm.ExternalAddress; -} - // Realm List command handler bool AuthSocket::_HandleRealmList() { @@ -981,7 +946,7 @@ bool AuthSocket::_HandleRealmList() pkt << lock; // if 1, then realm locked pkt << uint8(flag); // RealmFlags pkt << name; - pkt << GetAddressString(GetAddressForClient(realm, clientAddr)); + pkt << GetAddressString(realm.GetAddressForClient(clientAddr)); pkt << realm.populationLevel; pkt << AmountOfCharacters; pkt << realm.timezone; // realm category diff --git a/src/server/authserver/Server/AuthSocket.h b/src/server/authserver/Server/AuthSocket.h index 5e04d459ba1..e81944389ef 100644 --- a/src/server/authserver/Server/AuthSocket.h +++ b/src/server/authserver/Server/AuthSocket.h @@ -39,8 +39,6 @@ public: virtual void OnAccept(void); virtual void OnClose(void); - static ACE_INET_Addr const& GetAddressForClient(Realm const& realm, ACE_INET_Addr const& clientAddr); - bool _HandleLogonChallenge(); bool _HandleLogonProof(); bool _HandleReconnectChallenge(); diff --git a/src/server/authserver/Server/BattlenetSocket.cpp b/src/server/authserver/Server/BattlenetSocket.cpp index 12b02b5963e..258ae371075 100644 --- a/src/server/authserver/Server/BattlenetSocket.cpp +++ b/src/server/authserver/Server/BattlenetSocket.cpp @@ -94,35 +94,12 @@ void Battlenet::Socket::_SetVSFields(std::string const& pstr) x.SetBinary(sha.GetDigest(), sha.GetLength()); v = g.ModExp(x, N); - char* v_hex = v.AsHexStr(); - char* s_hex = s.AsHexStr(); + PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_BNET_VS_FIELDS); + stmt->setString(0, v.AsHexStr()); + stmt->setString(1, s.AsHexStr()); + stmt->setString(2, _accountName); - LoginDatabase.PExecute("UPDATE battlenet_accounts SET s = '%s', v = '%s' WHERE email ='%s'", s_hex, v_hex, _accountName.c_str()); - - OPENSSL_free(v_hex); - OPENSSL_free(s_hex); -} - -ACE_INET_Addr const& Battlenet::Socket::GetAddressForClient(Realm const& realm, ACE_INET_Addr const& clientAddr) -{ - // Attempt to send best address for client - if (clientAddr.is_loopback()) - { - // Try guessing if realm is also connected locally - if (realm.LocalAddress.is_loopback() || realm.ExternalAddress.is_loopback()) - return clientAddr; - - // Assume that user connecting from the machine that authserver is located on - // has all realms available in his local network - return realm.LocalAddress; - } - - // Check if connecting client is in the same network - if (IsIPAddrInNetwork(realm.LocalAddress, clientAddr, realm.LocalSubnetMask)) - return realm.LocalAddress; - - // Return external IP - return realm.ExternalAddress; + LoginDatabase.Execute(stmt); } bool Battlenet::Socket::HandleAuthChallenge(PacketHeader& header, BitStream& packet) @@ -425,7 +402,7 @@ bool Battlenet::Socket::HandleRealmUpdateSubscribe(PacketHeader& /*header*/, Bit version << buildInfo->MajorVersion << '.' << buildInfo->MinorVersion << '.' << buildInfo->BugfixVersion << '.' << buildInfo->HotfixVersion; update->Version = version.str(); - update->Address = GetAddressForClient(realm, clientAddr); + update->Address = realm.GetAddressForClient(clientAddr); update->Build = realm.gamebuild; } @@ -821,7 +798,7 @@ bool Battlenet::Socket::HandleRiskFingerprintModule(BitStream* dataStream, Serve complete->GameAccountName = str.str(); complete->AccountFlags = 0x800000; // 0x1 IsGMAccount, 0x8 IsTrialAccount, 0x800000 IsProPassAccount - PreparedStatement *stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_BNET_LAST_LOGIN_INFO); + PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_BNET_LAST_LOGIN_INFO); stmt->setString(0, _socket.getRemoteAddress()); stmt->setUInt8(1, GetLocaleByName(_locale)); stmt->setString(2, _os); @@ -832,7 +809,7 @@ bool Battlenet::Socket::HandleRiskFingerprintModule(BitStream* dataStream, Serve complete->SetAuthResult(AUTH_BAD_VERSION_HASH); ReplaceResponse(response, complete); - return false; + return true; } bool Battlenet::Socket::UnhandledModule(BitStream* /*dataStream*/, ServerPacket** response) diff --git a/src/server/authserver/Server/BattlenetSocket.h b/src/server/authserver/Server/BattlenetSocket.h index ef6157b022a..ff441b19cdd 100644 --- a/src/server/authserver/Server/BattlenetSocket.h +++ b/src/server/authserver/Server/BattlenetSocket.h @@ -47,7 +47,7 @@ namespace Battlenet static uint32 const SRP6_V_Size; static uint32 const SRP6_S_Size; - Socket(RealmSocket& socket); + explicit Socket(RealmSocket& socket); typedef bool(Socket::*PacketHandler)(PacketHeader& socket, BitStream& packet); @@ -71,7 +71,6 @@ namespace Battlenet private: void _SetVSFields(std::string const& rI); - static ACE_INET_Addr const& GetAddressForClient(Realm const& realm, ACE_INET_Addr const& clientAddr); typedef bool(Socket::*ModuleHandler)(BitStream* dataStream, ServerPacket** response); static ModuleHandler const ModuleHandlers[MODULE_COUNT]; diff --git a/src/server/shared/Cryptography/BigNumber.cpp b/src/server/shared/Cryptography/BigNumber.cpp index 1f3fc96e28d..1c82314bdba 100644 --- a/src/server/shared/Cryptography/BigNumber.cpp +++ b/src/server/shared/Cryptography/BigNumber.cpp @@ -190,13 +190,19 @@ ACE_Auto_Array_Ptr BigNumber::AsByteArray(int32 minSize, bool littleEndia return ret; } -char * BigNumber::AsHexStr() const +std::string BigNumber::AsHexStr() const { - return BN_bn2hex(_bn); + char* ch = BN_bn2hex(_bn); + std::string ret = ch; + OPENSSL_free(ch); + return ret; } -char * BigNumber::AsDecStr() const +std::string BigNumber::AsDecStr() const { - return BN_bn2dec(_bn); + char* ch = BN_bn2dec(_bn); + std::string ret = ch; + OPENSSL_free(ch); + return ret; } diff --git a/src/server/shared/Cryptography/BigNumber.h b/src/server/shared/Cryptography/BigNumber.h index dc553babec9..7de53b442ae 100644 --- a/src/server/shared/Cryptography/BigNumber.h +++ b/src/server/shared/Cryptography/BigNumber.h @@ -21,6 +21,7 @@ #include "Define.h" #include +#include struct bignum_st; @@ -89,8 +90,8 @@ class BigNumber ACE_Auto_Array_Ptr AsByteArray(int32 minSize = 0, bool littleEndian = true); - char * AsHexStr() const; - char * AsDecStr() const; + std::string AsHexStr() const; + std::string AsDecStr() const; private: struct bignum_st *_bn; diff --git a/src/server/shared/Database/Implementation/LoginDatabase.cpp b/src/server/shared/Database/Implementation/LoginDatabase.cpp index 208873448c6..a54557310e1 100644 --- a/src/server/shared/Database/Implementation/LoginDatabase.cpp +++ b/src/server/shared/Database/Implementation/LoginDatabase.cpp @@ -106,6 +106,7 @@ void LoginDatabaseConnection::DoPrepareStatements() PrepareStatement(LOGIN_SEL_BNET_ACCOUNT_INFO, "SELECT sha_pass_hash, id, locked, lock_country, last_ip, v, s FROM battlenet_accounts WHERE email = ?", CONNECTION_SYNCH); 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_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); @@ -114,5 +115,5 @@ void LoginDatabaseConnection::DoPrepareStatements() PrepareStatement(LOGIN_SEL_BNET_ACCOUNT_EMAIL_BY_ID, "SELECT email FROM battlenet_accounts WHERE id = ?", CONNECTION_SYNCH); PrepareStatement(LOGIN_SEL_BNET_ACCOUNT_ID_BY_EMAIL, "SELECT id FROM battlenet_accounts WHERE email = ?", CONNECTION_SYNCH); PrepareStatement(LOGIN_UPD_BNET_PASSWORD, "UPDATE account SET v = '', s = '', username = ?, sha_pass_hash = ? WHERE id = ?", CONNECTION_ASYNC); - PrepareStatement(LOGIN_SEL_BNET_CHECK_PASSWORD, "SELECT 1 FROM battlenet_accounts WHERE id = %u AND sha_pass_hash = ?", CONNECTION_ASYNC); + PrepareStatement(LOGIN_SEL_BNET_CHECK_PASSWORD, "SELECT 1 FROM battlenet_accounts WHERE id = ? AND sha_pass_hash = ?", CONNECTION_ASYNC); } diff --git a/src/server/shared/Database/Implementation/LoginDatabase.h b/src/server/shared/Database/Implementation/LoginDatabase.h index 18f9110409d..fff7a36766c 100644 --- a/src/server/shared/Database/Implementation/LoginDatabase.h +++ b/src/server/shared/Database/Implementation/LoginDatabase.h @@ -125,6 +125,7 @@ enum LoginDatabaseStatements LOGIN_SEL_BNET_ACCOUNT_INFO, LOGIN_DEL_BNET_EXPIRED_BANS, LOGIN_SEL_BNET_ACTIVE_ACCOUNT_BAN, + LOGIN_UPD_BNET_VS_FIELDS, LOGIN_SEL_BNET_GAME_ACCOUNTS, LOGIN_SEL_BNET_GAME_ACCOUNT, LOGIN_UPD_BNET_LAST_LOGIN_INFO, -- cgit v1.2.3 From bdd6e9aa8aeeda439a2a3a8f23bc21bb04699133 Mon Sep 17 00:00:00 2001 From: Shauren Date: Sun, 1 Jun 2014 13:56:36 +0200 Subject: Core/Battle.net: Implemented reconnects --- sql/base/auth_database.sql | 7 +- sql/updates/auth/2014_xx_xx_01_auth_battlenet.sql | 8 + src/server/authserver/Server/BattlenetPackets.cpp | 149 +++++++++++++++--- src/server/authserver/Server/BattlenetPackets.h | 54 ++++++- src/server/authserver/Server/BattlenetSocket.cpp | 173 ++++++++++++++++++++- src/server/authserver/Server/BattlenetSocket.h | 7 + .../Database/Implementation/LoginDatabase.cpp | 2 + .../shared/Database/Implementation/LoginDatabase.h | 2 + 8 files changed, 375 insertions(+), 27 deletions(-) create mode 100644 sql/updates/auth/2014_xx_xx_01_auth_battlenet.sql (limited to 'src') diff --git a/sql/base/auth_database.sql b/sql/base/auth_database.sql index f610bac2b6a..2d217dabe91 100644 --- a/sql/base/auth_database.sql +++ b/sql/base/auth_database.sql @@ -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; diff --git a/sql/updates/auth/2014_xx_xx_01_auth_battlenet.sql b/sql/updates/auth/2014_xx_xx_01_auth_battlenet.sql new file mode 100644 index 00000000000..ee88c91b323 --- /dev/null +++ b/sql/updates/auth/2014_xx_xx_01_auth_battlenet.sql @@ -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); diff --git a/src/server/authserver/Server/BattlenetPackets.cpp b/src/server/authserver/Server/BattlenetPackets.cpp index 99e3fa10b14..471a6128c4c 100644 --- a/src/server/authserver/Server/BattlenetPackets.cpp +++ b/src/server/authserver/Server/BattlenetPackets.cpp @@ -57,9 +57,6 @@ void Battlenet::AuthChallenge::Read() if (_stream.Read(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(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(32); + } + + Login = _stream.ReadString(9, 3); + Region = _stream.Read(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::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::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) diff --git a/src/server/authserver/Server/BattlenetPackets.h b/src/server/authserver/Server/BattlenetPackets.h index 9acc707bd10..d790760ea24 100644 --- a/src/server/authserver/Server/BattlenetPackets.h +++ b/src/server/authserver/Server/BattlenetPackets.h @@ -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 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 Modules; + std::vector 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 Modules; + void SetAuthResult(AuthResult result); + AuthResult Result; + uint32 ErrorType; + + int32 PingTimeout; + uint32 Threshold; + uint32 Rate; }; class Pong final : public ServerPacket 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 InitHandlers std::map 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(1)) header.Channel = packet.Read(4); + if (header.Channel != AUTHENTICATION && !_authed) + { + TC_LOG_DEBUG("server.battlenet", "Battlenet::Socket::OnRead Received not allowed packet %s", header.ToString().c_str()); + _socket.shutdown(); + return; + } + TC_LOG_TRACE("server.battlenet", "Battlenet::Socket::OnRead %s", header.ToString().c_str()); std::map::const_iterator itr = Handlers.find(header); if (itr != Handlers.end()) @@ -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(8) != 1) + { + AuthResume* complete = new AuthResume(); + complete->SetAuthResult(AUTH_CORRUPTED_MODULE); + ReplaceResponse(response, complete); + return false; + } + + static uint8 const ResumeClient = 0; + static uint8 const ResumeServer = 1; + + ACE_Auto_Array_Ptr&& clientChallenge = dataStream->ReadBytes(16); + ACE_Auto_Array_Ptr&& clientProof = dataStream->ReadBytes(32); + ACE_Auto_Array_Ptr&& serverChallenge = _reconnectProof.AsByteArray(); + ACE_Auto_Array_Ptr&& sessionKey = K.AsByteArray(); + + 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(); diff --git a/src/server/authserver/Server/BattlenetSocket.h b/src/server/authserver/Server/BattlenetSocket.h index ff441b19cdd..c634a81b517 100644 --- a/src/server/authserver/Server/BattlenetSocket.h +++ b/src/server/authserver/Server/BattlenetSocket.h @@ -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 _modulesWaitingForData; PacketCrypt _crypt; + bool _authed; }; } diff --git a/src/server/shared/Database/Implementation/LoginDatabase.cpp b/src/server/shared/Database/Implementation/LoginDatabase.cpp index a54557310e1..abe733e55e2 100644 --- a/src/server/shared/Database/Implementation/LoginDatabase.cpp +++ b/src/server/shared/Database/Implementation/LoginDatabase.cpp @@ -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); diff --git a/src/server/shared/Database/Implementation/LoginDatabase.h b/src/server/shared/Database/Implementation/LoginDatabase.h index fff7a36766c..64264984e29 100644 --- a/src/server/shared/Database/Implementation/LoginDatabase.h +++ b/src/server/shared/Database/Implementation/LoginDatabase.h @@ -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, -- cgit v1.2.3 From c98853ca1c0f325296f509fe187b5505e32d607f Mon Sep 17 00:00:00 2001 From: Shauren Date: Sun, 1 Jun 2014 15:03:22 +0200 Subject: Core/Authserver: Added game account flags --- src/server/authserver/Authentication/AuthCodes.h | 34 +++++++++++++++++++++++ src/server/authserver/Server/AuthSocket.cpp | 2 +- src/server/authserver/Server/BattlenetPackets.cpp | 4 +-- src/server/authserver/Server/BattlenetPackets.h | 4 ++- src/server/authserver/Server/BattlenetSocket.cpp | 6 ++-- 5 files changed, 43 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/server/authserver/Authentication/AuthCodes.h b/src/server/authserver/Authentication/AuthCodes.h index 158029bcefc..57db55c98a8 100644 --- a/src/server/authserver/Authentication/AuthCodes.h +++ b/src/server/authserver/Authentication/AuthCodes.h @@ -70,6 +70,40 @@ enum LoginResult LOGIN_LOCKED_ENFORCED = 0x10 }; +enum GameAccountFlags +{ + GAMEACCOUNT_FLAG_GM = 0x00000001, + GAMEACCOUNT_FLAG_NOKICK = 0x00000002, + GAMEACCOUNT_FLAG_COLLECTOR = 0x00000004, + GAMEACCOUNT_FLAG_WOW_TRIAL = 0x00000008, + GAMEACCOUNT_FLAG_CANCELLED = 0x00000010, + GAMEACCOUNT_FLAG_IGR = 0x00000020, + GAMEACCOUNT_FLAG_WHOLESALER = 0x00000040, + GAMEACCOUNT_FLAG_PRIVILEGED = 0x00000080, + GAMEACCOUNT_FLAG_EU_FORBID_ELV = 0x00000100, + GAMEACCOUNT_FLAG_EU_FORBID_BILLING = 0x00000200, + GAMEACCOUNT_FLAG_WOW_RESTRICTED = 0x00000400, + GAMEACCOUNT_FLAG_REFERRAL = 0x00000800, + GAMEACCOUNT_FLAG_BLIZZARD = 0x00001000, + GAMEACCOUNT_FLAG_RECURRING_BILLING = 0x00002000, + GAMEACCOUNT_FLAG_NOELECTUP = 0x00004000, + GAMEACCOUNT_FLAG_KR_CERTIFICATE = 0x00008000, + GAMEACCOUNT_FLAG_EXPANSION_COLLECTOR = 0x00010000, + GAMEACCOUNT_FLAG_DISABLE_VOICE = 0x00020000, + GAMEACCOUNT_FLAG_DISABLE_VOICE_SPEAK = 0x00040000, + GAMEACCOUNT_FLAG_REFERRAL_RESURRECT = 0x00080000, + GAMEACCOUNT_FLAG_EU_FORBID_CC = 0x00100000, + GAMEACCOUNT_FLAG_OPENBETA_DELL = 0x00200000, + GAMEACCOUNT_FLAG_PROPASS = 0x00400000, + GAMEACCOUNT_FLAG_PROPASS_LOCK = 0x00800000, + GAMEACCOUNT_FLAG_PENDING_UPGRADE = 0x01000000, + GAMEACCOUNT_FLAG_RETAIL_FROM_TRIAL = 0x02000000, + GAMEACCOUNT_FLAG_EXPANSION2_COLLECTOR = 0x04000000, + GAMEACCOUNT_FLAG_OVERMIND_LINKED = 0x08000000, + GAMEACCOUNT_FLAG_DEMOS = 0x10000000, + GAMEACCOUNT_FLAG_DEATH_KNIGHT_OK = 0x20000000, +}; + namespace Battlenet { enum AuthResult diff --git a/src/server/authserver/Server/AuthSocket.cpp b/src/server/authserver/Server/AuthSocket.cpp index 8180967a92e..32140f76ba4 100644 --- a/src/server/authserver/Server/AuthSocket.cpp +++ b/src/server/authserver/Server/AuthSocket.cpp @@ -680,7 +680,7 @@ bool AuthSocket::_HandleLogonProof() memcpy(proof.M2, sha.GetDigest(), 20); proof.cmd = AUTH_LOGON_PROOF; proof.error = 0; - proof.unk1 = 0x00800000; // Accountflags. 0x01 = GM, 0x08 = Trial, 0x00800000 = Pro pass (arena tournament) + proof.unk1 = GAMEACCOUNT_FLAG_PROPASS_LOCK; proof.unk2 = 0x00; // SurveyId proof.unk3 = 0x00; socket().send((char *)&proof, sizeof(proof)); diff --git a/src/server/authserver/Server/BattlenetPackets.cpp b/src/server/authserver/Server/BattlenetPackets.cpp index 471a6128c4c..9997ea8d259 100644 --- a/src/server/authserver/Server/BattlenetPackets.cpp +++ b/src/server/authserver/Server/BattlenetPackets.cpp @@ -203,10 +203,10 @@ void Battlenet::AuthComplete::Write() _stream.WriteString(LastName, 8); // Last name - not set for WoW _stream.Write(GameAccountId, 32); - _stream.Write(2, 8); + _stream.Write(Region, 8); _stream.Write(0, 64); - _stream.Write(2, 8); + _stream.Write(GameAccountRegion, 8); _stream.WriteString(GameAccountName, 5, -1); _stream.Write(GameAccountFlags, 64); diff --git a/src/server/authserver/Server/BattlenetPackets.h b/src/server/authserver/Server/BattlenetPackets.h index d790760ea24..3fa628c2ba3 100644 --- a/src/server/authserver/Server/BattlenetPackets.h +++ b/src/server/authserver/Server/BattlenetPackets.h @@ -208,7 +208,7 @@ namespace Battlenet public: AuthComplete() : ServerPacket(PacketHeader(SMSG_AUTH_COMPLETE, AUTHENTICATION)), Result(AUTH_OK), ErrorType(0), PingTimeout(120000), Threshold(25000000), Rate(1000), - FirstName(""), LastName(""), GameAccountId(0), GameAccountName("") + FirstName(""), LastName(""), Region(2), GameAccountId(0), GameAccountRegion(2), GameAccountName("") { } @@ -227,7 +227,9 @@ namespace Battlenet uint32 Rate; std::string FirstName; std::string LastName; + uint8 Region; uint32 GameAccountId; + uint8 GameAccountRegion; std::string GameAccountName; uint64 GameAccountFlags; }; diff --git a/src/server/authserver/Server/BattlenetSocket.cpp b/src/server/authserver/Server/BattlenetSocket.cpp index 119fccd9abb..db72cbf5e07 100644 --- a/src/server/authserver/Server/BattlenetSocket.cpp +++ b/src/server/authserver/Server/BattlenetSocket.cpp @@ -466,11 +466,11 @@ bool Battlenet::Socket::HandleRealmUpdateSubscribe(PacketHeader& /*header*/, Bit if (flag & REALM_FLAG_SPECIFYBUILD) { std::ostringstream version; - version << buildInfo->MajorVersion << '.' << buildInfo->MinorVersion << '.' << buildInfo->BugfixVersion << '.' << buildInfo->HotfixVersion; + version << buildInfo->MajorVersion << '.' << buildInfo->MinorVersion << '.' << buildInfo->BugfixVersion << '.' << buildInfo->Build; update->Version = version.str(); update->Address = realm.GetAddressForClient(clientAddr); - update->Build = realm.gamebuild; + update->Build = buildInfo->Build; } update->Flags = flag; @@ -870,7 +870,7 @@ bool Battlenet::Socket::HandleRiskFingerprintModule(BitStream* dataStream, Serve complete->GameAccountId = _gameAccountId; complete->GameAccountName = str.str(); - complete->GameAccountFlags = 1; + complete->GameAccountFlags = GAMEACCOUNT_FLAG_PROPASS_LOCK; SQLTransaction trans = LoginDatabase.BeginTransaction(); -- cgit v1.2.3 From 7a27492071d79b036343b90ecdf1678548f3c550 Mon Sep 17 00:00:00 2001 From: Shauren Date: Tue, 3 Jun 2014 18:15:35 +0200 Subject: Core/Crypto: Refactored HmacHash to make it easier to use with different hash algorithms --- .../authserver/Server/BattlenetPacketCrypt.cpp | 4 +-- src/server/authserver/Server/BattlenetSocket.cpp | 12 ++++----- src/server/game/Warden/WardenWin.cpp | 2 +- .../Authentication/WorldPacketCrypt.cpp | 4 +-- src/server/shared/Cryptography/HmacHash.cpp | 29 ++++++++++++++-------- src/server/shared/Cryptography/HmacHash.h | 17 ++++++++----- 6 files changed, 40 insertions(+), 28 deletions(-) (limited to 'src') diff --git a/src/server/authserver/Server/BattlenetPacketCrypt.cpp b/src/server/authserver/Server/BattlenetPacketCrypt.cpp index 31fcfdd930a..de4cf73f71c 100644 --- a/src/server/authserver/Server/BattlenetPacketCrypt.cpp +++ b/src/server/authserver/Server/BattlenetPacketCrypt.cpp @@ -28,11 +28,11 @@ void Battlenet::PacketCrypt::Init(BigNumber* K) uint8 ServerEncryptionKey[SEED_KEY_SIZE] = { 0x68, 0xE0, 0xC7, 0x2E, 0xDD, 0xD6, 0xD2, 0xF3, 0x1E, 0x5A, 0xB1, 0x55, 0xB1, 0x8B, 0x63, 0x1E }; uint8 ClientDecryptionKey[SEED_KEY_SIZE] = { 0xDE, 0xA9, 0x65, 0xAE, 0x54, 0x3A, 0x1E, 0x93, 0x9E, 0x69, 0x0C, 0xAA, 0x68, 0xDE, 0x78, 0x39 }; - HmacHash serverEncryptHmac(K->GetNumBytes(), K->AsByteArray().get(), EVP_sha256(), SHA256_DIGEST_LENGTH); + HmacSha256 serverEncryptHmac(K->GetNumBytes(), K->AsByteArray().get()); serverEncryptHmac.UpdateData(ServerEncryptionKey, SEED_KEY_SIZE); serverEncryptHmac.Finalize(); - HmacHash clientDecryptHmac(K->GetNumBytes(), K->AsByteArray().get(), EVP_sha256(), SHA256_DIGEST_LENGTH); + HmacSha256 clientDecryptHmac(K->GetNumBytes(), K->AsByteArray().get()); clientDecryptHmac.UpdateData(ClientDecryptionKey, SEED_KEY_SIZE); clientDecryptHmac.Finalize(); diff --git a/src/server/authserver/Server/BattlenetSocket.cpp b/src/server/authserver/Server/BattlenetSocket.cpp index db72cbf5e07..1cce8f2f94d 100644 --- a/src/server/authserver/Server/BattlenetSocket.cpp +++ b/src/server/authserver/Server/BattlenetSocket.cpp @@ -503,7 +503,7 @@ bool Battlenet::Socket::HandleRealmJoinRequest(PacketHeader& header, BitStream& result.ServerSeed = uint32(rand32()); uint8 sessionKey[40]; - HmacHash hmac(K.GetNumBytes(), K.AsByteArray().get(), EVP_sha1(), SHA_DIGEST_LENGTH); + HmacSha1 hmac(K.GetNumBytes(), K.AsByteArray().get()); hmac.UpdateData((uint8*)"WoW\0", 4); hmac.UpdateData((uint8*)&join.ClientSeed, 4); hmac.UpdateData((uint8*)&result.ServerSeed, 4); @@ -511,7 +511,7 @@ bool Battlenet::Socket::HandleRealmJoinRequest(PacketHeader& header, BitStream& memcpy(sessionKey, hmac.GetDigest(), hmac.GetLength()); - HmacHash hmac2(K.GetNumBytes(), K.AsByteArray().get(), EVP_sha1(), SHA_DIGEST_LENGTH); + HmacSha1 hmac2(K.GetNumBytes(), K.AsByteArray().get()); hmac2.UpdateData((uint8*)"WoW\0", 4); hmac2.UpdateData((uint8*)&result.ServerSeed, 4); hmac2.UpdateData((uint8*)&join.ClientSeed, 4); @@ -915,13 +915,13 @@ bool Battlenet::Socket::HandleResumeModule(BitStream* dataStream, ServerPacket** ACE_Auto_Array_Ptr&& serverChallenge = _reconnectProof.AsByteArray(); ACE_Auto_Array_Ptr&& sessionKey = K.AsByteArray(); - HmacHash clientPart(64, sessionKey.get(), EVP_sha256(), SHA256_DIGEST_LENGTH); + HmacSha256 clientPart(64, sessionKey.get()); 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); + HmacSha256 serverPart(64, sessionKey.get()); serverPart.UpdateData(&ResumeServer, 1); serverPart.UpdateData(serverChallenge.get(), 16); serverPart.UpdateData(clientChallenge.get(), 16); @@ -933,7 +933,7 @@ bool Battlenet::Socket::HandleResumeModule(BitStream* dataStream, ServerPacket** K.SetBinary(newSessionKey, 64); - HmacHash proof(64, newSessionKey, EVP_sha256(), SHA256_DIGEST_LENGTH); + HmacSha256 proof(64, newSessionKey); proof.UpdateData(&ResumeClient, 1); proof.UpdateData(clientChallenge.get(), 16); proof.UpdateData(serverChallenge.get(), 16); @@ -953,7 +953,7 @@ bool Battlenet::Socket::HandleResumeModule(BitStream* dataStream, ServerPacket** stmt->setUInt32(1, _accountId); LoginDatabase.Execute(stmt); - HmacHash serverProof(64, newSessionKey, EVP_sha256(), SHA256_DIGEST_LENGTH); + HmacSha256 serverProof(64, newSessionKey); serverProof.UpdateData(&ResumeServer, 1); serverProof.UpdateData(serverChallenge.get(), 16); serverProof.UpdateData(clientChallenge.get(), 16); diff --git a/src/server/game/Warden/WardenWin.cpp b/src/server/game/Warden/WardenWin.cpp index 3014fcfb993..3428708ed69 100644 --- a/src/server/game/Warden/WardenWin.cpp +++ b/src/server/game/Warden/WardenWin.cpp @@ -283,7 +283,7 @@ void WardenWin::RequestData() { uint32 seed = static_cast(rand32()); buff << uint32(seed); - HmacHash hmac(4, (uint8*)&seed, EVP_sha1(), SHA_DIGEST_LENGTH); + HmacSha1 hmac(4, (uint8*)&seed); hmac.UpdateData(wd->Str); hmac.Finalize(); buff.append(hmac.GetDigest(), hmac.GetLength()); diff --git a/src/server/shared/Cryptography/Authentication/WorldPacketCrypt.cpp b/src/server/shared/Cryptography/Authentication/WorldPacketCrypt.cpp index c6b283d9961..10403b84a1f 100644 --- a/src/server/shared/Cryptography/Authentication/WorldPacketCrypt.cpp +++ b/src/server/shared/Cryptography/Authentication/WorldPacketCrypt.cpp @@ -27,11 +27,11 @@ WorldPacketCrypt::WorldPacketCrypt() : PacketCrypt(SHA_DIGEST_LENGTH) void WorldPacketCrypt::Init(BigNumber* K) { uint8 ServerEncryptionKey[SEED_KEY_SIZE] = { 0xCC, 0x98, 0xAE, 0x04, 0xE8, 0x97, 0xEA, 0xCA, 0x12, 0xDD, 0xC0, 0x93, 0x42, 0x91, 0x53, 0x57 }; - HmacHash serverEncryptHmac(SEED_KEY_SIZE, (uint8*)ServerEncryptionKey, EVP_sha1(), SHA_DIGEST_LENGTH); + HmacSha1 serverEncryptHmac(SEED_KEY_SIZE, (uint8*)ServerEncryptionKey); uint8 *encryptHash = serverEncryptHmac.ComputeHash(K); uint8 ServerDecryptionKey[SEED_KEY_SIZE] = { 0xC2, 0xB3, 0x72, 0x3C, 0xC6, 0xAE, 0xD9, 0xB5, 0x34, 0x3C, 0x53, 0xEE, 0x2F, 0x43, 0x67, 0xCE }; - HmacHash clientDecryptHmac(SEED_KEY_SIZE, (uint8*)ServerDecryptionKey, EVP_sha1(), SHA_DIGEST_LENGTH); + HmacSha1 clientDecryptHmac(SEED_KEY_SIZE, (uint8*)ServerDecryptionKey); uint8 *decryptHash = clientDecryptHmac.ComputeHash(K); _clientDecrypt.Init(decryptHash); diff --git a/src/server/shared/Cryptography/HmacHash.cpp b/src/server/shared/Cryptography/HmacHash.cpp index 71fc362ae5d..2913b9fa79a 100644 --- a/src/server/shared/Cryptography/HmacHash.cpp +++ b/src/server/shared/Cryptography/HmacHash.cpp @@ -20,40 +20,47 @@ #include "BigNumber.h" #include "Common.h" -HmacHash::HmacHash(uint32 len, uint8 *seed, EVP_MD const* hasher, uint32 digestLength) : _digestLength(digestLength) +template +HmacHash::HmacHash(uint32 len, uint8 *seed) { HMAC_CTX_init(&_ctx); - HMAC_Init_ex(&_ctx, seed, len, hasher, NULL); - _digest = new uint8[digestLength]; - memset(_digest, 0, digestLength); + HMAC_Init_ex(&_ctx, seed, len, HashCreator(), NULL); + memset(_digest, 0, DigestLength); } -HmacHash::~HmacHash() +template +HmacHash::~HmacHash() { HMAC_CTX_cleanup(&_ctx); - delete[] _digest; } -void HmacHash::UpdateData(const std::string &str) +template +void HmacHash::UpdateData(const std::string &str) { HMAC_Update(&_ctx, (uint8 const*)str.c_str(), str.length()); } -void HmacHash::UpdateData(const uint8* data, size_t len) +template +void HmacHash::UpdateData(const uint8* data, size_t len) { HMAC_Update(&_ctx, data, len); } -void HmacHash::Finalize() +template +void HmacHash::Finalize() { uint32 length = 0; HMAC_Final(&_ctx, _digest, &length); - ASSERT(length == _digestLength); + ASSERT(length == DigestLength); } -uint8* HmacHash::ComputeHash(BigNumber* bn) +template +uint8* HmacHash::ComputeHash(BigNumber* bn) { HMAC_Update(&_ctx, bn->AsByteArray().get(), bn->GetNumBytes()); Finalize(); return _digest; } + +template class HmacHash; +template class HmacHash; diff --git a/src/server/shared/Cryptography/HmacHash.h b/src/server/shared/Cryptography/HmacHash.h index bf82e39a526..56ee55edda2 100644 --- a/src/server/shared/Cryptography/HmacHash.h +++ b/src/server/shared/Cryptography/HmacHash.h @@ -28,21 +28,26 @@ class BigNumber; #define SEED_KEY_SIZE 16 +typedef EVP_MD const* (*HashCreateFn)(); + +template class HmacHash { public: - HmacHash(uint32 len, uint8 *seed, EVP_MD const* hasher, uint32 digestLength); + HmacHash(uint32 len, uint8 *seed); ~HmacHash(); - void UpdateData(const std::string &str); - void UpdateData(const uint8* data, size_t len); + void UpdateData(std::string const& str); + void UpdateData(uint8 const* data, size_t len); void Finalize(); uint8* ComputeHash(BigNumber* bn); uint8* GetDigest() { return _digest; } - uint32 GetLength() const { return _digestLength; } + uint32 GetLength() const { return DigestLength; } private: HMAC_CTX _ctx; - uint8* _digest; - uint32 _digestLength; + uint8 _digest[DigestLength]; }; +typedef HmacHash HmacSha1; +typedef HmacHash HmacSha256; + #endif -- cgit v1.2.3 From 6eee75a4f76b1965708ee52fa785d8d7555c0a16 Mon Sep 17 00:00:00 2001 From: Shauren Date: Tue, 3 Jun 2014 19:15:12 +0200 Subject: Core/Battle.net: Removed sending "b", it's supposed to stay secret --- src/server/authserver/Server/BattlenetSocket.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/server/authserver/Server/BattlenetSocket.cpp b/src/server/authserver/Server/BattlenetSocket.cpp index 1cce8f2f94d..56744784167 100644 --- a/src/server/authserver/Server/BattlenetSocket.cpp +++ b/src/server/authserver/Server/BattlenetSocket.cpp @@ -284,6 +284,8 @@ bool Battlenet::Socket::HandleAuthChallenge(PacketHeader& header, BitStream& pac b.SetRand(128 * 8); B = ((v * k) + g.ModExp(b, N)) % N; + BigNumber unk; + unk.SetRand(128 * 8); BitStream passwordData; uint8 state = 0; @@ -291,7 +293,7 @@ bool Battlenet::Socket::HandleAuthChallenge(PacketHeader& header, BitStream& pac passwordData.WriteBytes(I.AsByteArray(32).get(), 32); passwordData.WriteBytes(s.AsByteArray(32).get(), 32); passwordData.WriteBytes(B.AsByteArray(128).get(), 128); - passwordData.WriteBytes(b.AsByteArray(128).get(), 128); + passwordData.WriteBytes(unk.AsByteArray(128).get(), 128); password->DataSize = passwordData.GetSize(); password->Data = new uint8[password->DataSize]; @@ -740,13 +742,16 @@ bool Battlenet::Socket::HandlePasswordModule(BitStream* dataStream, ServerPacket sha.Finalize(); M.SetBinary(sha.GetDigest(), sha.GetLength()); + BigNumber serverProof; + serverProof.SetRand(128 * 8); // just send garbage, server signature check is patched out in client + BitStream stream; ModuleInfo* password = sBattlenetMgr->CreateModule(_os, "Password"); uint8 state = 3; stream.WriteBytes(&state, 1); stream.WriteBytes(M.AsByteArray(32).get(), 32); - stream.WriteBytes(b.AsByteArray(128).get(), 128); + stream.WriteBytes(serverProof.AsByteArray(128).get(), 128); password->DataSize = stream.GetSize(); password->Data = new uint8[password->DataSize]; -- cgit v1.2.3 From 05c0524bf3d97ba29496fa13e93acd3b8d7d37a4 Mon Sep 17 00:00:00 2001 From: Shauren Date: Sun, 8 Jun 2014 14:54:37 +0200 Subject: Core/Battle.net: Refactored handling multiple game accounts --- sql/base/auth_database.sql | 2 ++ .../auth/2014_06_08_00_auth_account_434.sql | 3 +++ src/server/authserver/Server/BattlenetPackets.cpp | 6 ++--- src/server/authserver/Server/BattlenetPackets.h | 4 +-- src/server/authserver/Server/BattlenetSocket.cpp | 30 +++++++++++++++++----- src/server/authserver/Server/BattlenetSocket.h | 1 + src/server/game/Server/WorldSocket.cpp | 17 +++++++++--- .../Database/Implementation/LoginDatabase.cpp | 8 +++--- 8 files changed, 52 insertions(+), 19 deletions(-) create mode 100644 sql/updates/auth/2014_06_08_00_auth_account_434.sql (limited to 'src') diff --git a/sql/base/auth_database.sql b/sql/base/auth_database.sql index 7ab0c855f45..6dca9aa1e14 100644 --- a/sql/base/auth_database.sql +++ b/sql/base/auth_database.sql @@ -47,8 +47,10 @@ CREATE TABLE `account` ( `os` varchar(3) NOT NULL DEFAULT '', `recruiter` int(10) unsigned NOT NULL DEFAULT '0', `battlenet_account` int(10) unsigned DEFAULT NULL, + `battlenet_index` tinyint(3) unsigned DEFAULT NULL, PRIMARY KEY (`id`), UNIQUE KEY `idx_username` (`username`), + UNIQUE KEY `uk_bnet_acc` (`battlenet_account`, `battlenet_index`), CONSTRAINT `fk_bnet_acc` FOREIGN KEY (`battlenet_account`) REFERENCES `battlenet_accounts` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Account System'; /*!40101 SET character_set_client = @saved_cs_client */; diff --git a/sql/updates/auth/2014_06_08_00_auth_account_434.sql b/sql/updates/auth/2014_06_08_00_auth_account_434.sql new file mode 100644 index 00000000000..bc57136dc07 --- /dev/null +++ b/sql/updates/auth/2014_06_08_00_auth_account_434.sql @@ -0,0 +1,3 @@ +ALTER TABLE `account` + ADD `battlenet_index` tinyint(3) unsigned DEFAULT NULL AFTER `battlenet_account`, + ADD UNIQUE KEY `uk_bnet_acc` (`battlenet_account`, `battlenet_index`); diff --git a/src/server/authserver/Server/BattlenetPackets.cpp b/src/server/authserver/Server/BattlenetPackets.cpp index 9997ea8d259..6a8e09090ef 100644 --- a/src/server/authserver/Server/BattlenetPackets.cpp +++ b/src/server/authserver/Server/BattlenetPackets.cpp @@ -202,7 +202,7 @@ void Battlenet::AuthComplete::Write() _stream.WriteString(FirstName, 8); // First name _stream.WriteString(LastName, 8); // Last name - not set for WoW - _stream.Write(GameAccountId, 32); + _stream.Write(AccountId, 32); _stream.Write(Region, 8); _stream.Write(0, 64); @@ -236,7 +236,7 @@ std::string Battlenet::AuthComplete::ToString() const { std::ostringstream stream; stream << "Battlenet::AuthComplete AuthResult " << Result << " PingTimeout " << PingTimeout << " Threshold " << Threshold << " Rate " << Rate - << " FirstName " << FirstName << " LastName " << LastName << " GameAccountId " << GameAccountId << " GameAccountName " << GameAccountName + << " FirstName " << FirstName << " LastName " << LastName << " AccountId " << AccountId << " Region " << uint32(Region) << " GameAccountName " << GameAccountName << " GameAccountFlags " << GameAccountFlags << " Modules " << Modules.size(); for (ModuleInfo const* module : Modules) @@ -441,7 +441,7 @@ void Battlenet::RealmJoinResult::Write() std::string Battlenet::RealmJoinResult::ToString() const { std::ostringstream stream; - stream << "Battlenet::RealmJoinResult ServerSeed " << ServerSeed << " Addresses (IPv4)" << IPv4.size(); + stream << "Battlenet::RealmJoinResult ServerSeed " << ServerSeed << " IPv4 Addresses " << IPv4.size(); for (ACE_INET_Addr const& addr : IPv4) stream << std::endl << "Battlenet::RealmJoinResult::Address " << GetAddressString(addr); diff --git a/src/server/authserver/Server/BattlenetPackets.h b/src/server/authserver/Server/BattlenetPackets.h index 3fa628c2ba3..54fb50184a0 100644 --- a/src/server/authserver/Server/BattlenetPackets.h +++ b/src/server/authserver/Server/BattlenetPackets.h @@ -208,7 +208,7 @@ namespace Battlenet public: AuthComplete() : ServerPacket(PacketHeader(SMSG_AUTH_COMPLETE, AUTHENTICATION)), Result(AUTH_OK), ErrorType(0), PingTimeout(120000), Threshold(25000000), Rate(1000), - FirstName(""), LastName(""), Region(2), GameAccountId(0), GameAccountRegion(2), GameAccountName("") + FirstName(""), LastName(""), AccountId(0), Region(2), GameAccountRegion(2), GameAccountName("") { } @@ -227,8 +227,8 @@ namespace Battlenet uint32 Rate; std::string FirstName; std::string LastName; + uint32 AccountId; uint8 Region; - uint32 GameAccountId; uint8 GameAccountRegion; std::string GameAccountName; uint64 GameAccountFlags; diff --git a/src/server/authserver/Server/BattlenetSocket.cpp b/src/server/authserver/Server/BattlenetSocket.cpp index 56744784167..eb8dc1158f0 100644 --- a/src/server/authserver/Server/BattlenetSocket.cpp +++ b/src/server/authserver/Server/BattlenetSocket.cpp @@ -59,7 +59,7 @@ Battlenet::Socket::ModuleHandler const Battlenet::Socket::ModuleHandlers[MODULE_ }; Battlenet::Socket::Socket(RealmSocket& socket) : _socket(socket), _accountId(0), _accountName(), _locale(), - _os(), _build(0), _gameAccountId(0), _accountSecurityLevel(SEC_PLAYER), I(), s(), v(), b(), B(), K(), + _os(), _build(0), _gameAccountId(0), _gameAccountIndex(0), _accountSecurityLevel(SEC_PLAYER), I(), s(), v(), b(), B(), K(), _reconnectProof(), _crypt(), _authed(false) { static uint8 const N_Bytes[] = @@ -323,10 +323,12 @@ bool Battlenet::Socket::HandleAuthReconnect(PacketHeader& header, BitStream& pac if (baseComponent != reconnect.Components.end()) _build = baseComponent->Build; + uint8 accountIndex = atol(reconnect.GameAccountName.substr(reconnect.GameAccountName.find_last_of('#') + 1).c_str()); + Utf8ToUpperOnlyLatin(_accountName); PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_BNET_RECONNECT_INFO); stmt->setString(0, _accountName); - stmt->setString(1, reconnect.GameAccountName.c_str()); + stmt->setUInt8(1, accountIndex); PreparedQueryResult result = LoginDatabase.Query(stmt); if (!result) { @@ -341,6 +343,7 @@ bool Battlenet::Socket::HandleAuthReconnect(PacketHeader& header, BitStream& pac _accountId = fields[0].GetUInt32(); K.SetHexStr(fields[1].GetString().c_str()); _gameAccountId = fields[2].GetUInt32(); + _gameAccountIndex = accountIndex; ModuleInfo* thumbprint = sBattlenetMgr->CreateModule(_os, "Thumbprint"); ModuleInfo* resume = sBattlenetMgr->CreateModule(_os, "Resume"); @@ -768,8 +771,10 @@ bool Battlenet::Socket::HandlePasswordModule(BitStream* dataStream, ServerPacket do { fields = result->Fetch(); + std::ostringstream name; + name << "WoW" << uint32(fields[0].GetUInt8()); accounts.Write(2, 8); - accounts.WriteString(fields[0].GetString(), 8); + accounts.WriteString(name.str(), 8); } while (result->NextRow()); ModuleInfo* selectGameAccount = sBattlenetMgr->CreateModule(_os, "SelectGameAccount"); @@ -801,7 +806,8 @@ bool Battlenet::Socket::HandlePasswordModule(BitStream* dataStream, ServerPacket return false; } - _gameAccountId = (*result)[1].GetUInt32(); + _gameAccountId = fields[1].GetUInt32(); + _gameAccountIndex = fields[0].GetUInt8(); request->Modules.push_back(sBattlenetMgr->CreateModule(_os, "RiskFingerprint")); _modulesWaitingForData.push(MODULE_RISK_FINGERPRINT); @@ -823,9 +829,18 @@ bool Battlenet::Socket::HandleSelectGameAccountModule(BitStream* dataStream, Ser dataStream->Read(8); std::string account = dataStream->ReadString(8); + if (account.length() < 4) + { + AuthComplete* complete = new AuthComplete(); + complete->SetAuthResult(LOGIN_NO_GAME_ACCOUNT); + ReplaceResponse(response, complete); + return false; + } + + uint8 accountIndex = atol(account.substr(3).c_str()); PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_BNET_GAME_ACCOUNT); - stmt->setString(0, account); + stmt->setUInt8(0, accountIndex); stmt->setUInt32(1, _accountId); PreparedQueryResult result = LoginDatabase.Query(stmt); if (!result) @@ -856,6 +871,7 @@ bool Battlenet::Socket::HandleSelectGameAccountModule(BitStream* dataStream, Ser } _gameAccountId = fields[0].GetUInt32(); + _gameAccountIndex = accountIndex; ProofRequest* request = new ProofRequest(); request->Modules.push_back(sBattlenetMgr->CreateModule(_os, "RiskFingerprint")); @@ -871,9 +887,9 @@ bool Battlenet::Socket::HandleRiskFingerprintModule(BitStream* dataStream, Serve if (dataStream->Read(8) == 1) { std::ostringstream str; - str << _gameAccountId << "#1"; + str << _accountId << "#" << uint32(_gameAccountIndex); - complete->GameAccountId = _gameAccountId; + complete->AccountId = _accountId; complete->GameAccountName = str.str(); complete->GameAccountFlags = GAMEACCOUNT_FLAG_PROPASS_LOCK; diff --git a/src/server/authserver/Server/BattlenetSocket.h b/src/server/authserver/Server/BattlenetSocket.h index c634a81b517..ee399e26b09 100644 --- a/src/server/authserver/Server/BattlenetSocket.h +++ b/src/server/authserver/Server/BattlenetSocket.h @@ -92,6 +92,7 @@ namespace Battlenet std::string _os; uint32 _build; uint32 _gameAccountId; + uint8 _gameAccountIndex; AccountTypes _accountSecurityLevel; BigNumber N; diff --git a/src/server/game/Server/WorldSocket.cpp b/src/server/game/Server/WorldSocket.cpp index cc839b5281c..1a93e7ae1d5 100644 --- a/src/server/game/Server/WorldSocket.cpp +++ b/src/server/game/Server/WorldSocket.cpp @@ -856,9 +856,20 @@ int WorldSocket::HandleAuthSession(WorldPacket& recvPacket) // Get the account information from the realmd database // 0 1 2 3 4 5 6 7 8 // SELECT id, sessionkey, last_ip, locked, expansion, mutetime, locale, recruiter, os FROM account WHERE username = ? - PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(account.find('#') == std::string::npos ? LOGIN_SEL_ACCOUNT_INFO_BY_NAME : LOGIN_SEL_ACCOUNT_INFO_BY_BNET); - - stmt->setString(0, account); + size_t hashPos = account.find_last_of('#'); + PreparedStatement* stmt; + if (hashPos != std::string::npos) + { + Tokenizer tokens(account, '#', 2); + stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_ACCOUNT_INFO_BY_BNET); + stmt->setUInt32(0, atol(tokens[0])); + stmt->setUInt8(1, atol(tokens[1])); + } + else + { + stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_ACCOUNT_INFO_BY_NAME); + stmt->setString(0, account); + } PreparedQueryResult result = LoginDatabase.Query(stmt); diff --git a/src/server/shared/Database/Implementation/LoginDatabase.cpp b/src/server/shared/Database/Implementation/LoginDatabase.cpp index abe733e55e2..1da8088ed36 100644 --- a/src/server/shared/Database/Implementation/LoginDatabase.cpp +++ b/src/server/shared/Database/Implementation/LoginDatabase.cpp @@ -44,7 +44,7 @@ void LoginDatabaseConnection::DoPrepareStatements() PrepareStatement(LOGIN_SEL_ACCOUNT_ID_BY_NAME, "SELECT id FROM account WHERE username = ?", CONNECTION_SYNCH); PrepareStatement(LOGIN_SEL_ACCOUNT_LIST_BY_NAME, "SELECT id, username FROM account WHERE username = ?", CONNECTION_SYNCH); PrepareStatement(LOGIN_SEL_ACCOUNT_INFO_BY_NAME, "SELECT id, sessionkey, last_ip, locked, expansion, mutetime, locale, recruiter, os FROM account WHERE username = ?", CONNECTION_SYNCH); - PrepareStatement(LOGIN_SEL_ACCOUNT_INFO_BY_BNET, "SELECT id, sessionkey, last_ip, locked, expansion, mutetime, locale, recruiter, os FROM account WHERE id = SUBSTRING_INDEX(?, '#', 1)", CONNECTION_SYNCH); + PrepareStatement(LOGIN_SEL_ACCOUNT_INFO_BY_BNET, "SELECT id, sessionkey, last_ip, locked, expansion, mutetime, locale, recruiter, os FROM account WHERE battlenet_account = ? AND battlenet_index = ?", CONNECTION_SYNCH); PrepareStatement(LOGIN_SEL_ACCOUNT_LIST_BY_EMAIL, "SELECT id, username FROM account WHERE email = ?", CONNECTION_SYNCH); PrepareStatement(LOGIN_SEL_NUM_CHARS_ON_REALM, "SELECT numchars FROM realmcharacters WHERE realmid = ? AND acctid= ?", CONNECTION_SYNCH); PrepareStatement(LOGIN_SEL_ACCOUNT_BY_IP, "SELECT id, username FROM account WHERE last_ip = ?", CONNECTION_SYNCH); @@ -108,9 +108,9 @@ void LoginDatabaseConnection::DoPrepareStatements() 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_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.battlenet_index = ?", CONNECTION_SYNCH); + PrepareStatement(LOGIN_SEL_BNET_GAME_ACCOUNTS, "SELECT a.battlenet_index, 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 battlenet_index = ? 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); PrepareStatement(LOGIN_SEL_BNET_CHARACTER_COUNTS, "SELECT rc.numchars, r.id, r.Region, r.Battlegroup, r.gamebuild FROM realmcharacters rc INNER JOIN realmlist r ON rc.realmid = r.id WHERE rc.acctid = ?", CONNECTION_SYNCH); PrepareStatement(LOGIN_INS_BNET_ACCOUNT, "INSERT INTO battlenet_accounts (`email`,`sha_pass_hash`) VALUES (?, ?)", CONNECTION_ASYNC); -- cgit v1.2.3 From 9f69eda67f7fad50553f8d569851a5005437e677 Mon Sep 17 00:00:00 2001 From: Shauren Date: Sun, 8 Jun 2014 15:34:24 +0200 Subject: Core/Battle.net: Additional checks * Force grunt login for versions < 15595 * Force bn login if supported and game account is linked to bn account --- sql/base/auth_database.sql | 6 ------ sql/updates/auth/2014_06_08_01_auth_account_434.sql | 3 +++ src/server/authserver/Authentication/AuthCodes.cpp | 5 +++++ src/server/authserver/Authentication/AuthCodes.h | 1 + src/server/authserver/Server/AuthSocket.cpp | 4 +++- src/server/authserver/Server/BattlenetSocket.cpp | 8 ++++++-- src/server/shared/Database/Implementation/LoginDatabase.cpp | 2 +- 7 files changed, 19 insertions(+), 10 deletions(-) create mode 100644 sql/updates/auth/2014_06_08_01_auth_account_434.sql (limited to 'src') diff --git a/sql/base/auth_database.sql b/sql/base/auth_database.sql index 6dca9aa1e14..3ccbadbbda0 100644 --- a/sql/base/auth_database.sql +++ b/sql/base/auth_database.sql @@ -216,18 +216,12 @@ LOCK TABLES `battlenet_components` WRITE; /*!40000 ALTER TABLE `battlenet_components` DISABLE KEYS */; INSERT INTO `battlenet_components` VALUES ('Bnet','Cmp1',3), -('Bnet','Win',21719), ('Bnet','Win',26487), ('Bnet','Wn64',26487), -('Tool','Win',1569), ('Tool','Win',2736), -('WoW','base',12340), ('WoW','base',15595), -('WoW','enGB',12340), ('WoW','enGB',15595), -('WoW','enUS',12340), ('WoW','enUS',15595), -('WoW','Win',12340), ('WoW','Win',15595), ('WoW','Wn64',15595); /*!40000 ALTER TABLE `battlenet_components` ENABLE KEYS */; diff --git a/sql/updates/auth/2014_06_08_01_auth_account_434.sql b/sql/updates/auth/2014_06_08_01_auth_account_434.sql new file mode 100644 index 00000000000..dc05a98d17b --- /dev/null +++ b/sql/updates/auth/2014_06_08_01_auth_account_434.sql @@ -0,0 +1,3 @@ +DELETE FROM `battlenet_components` WHERE `Program`='WoW' AND `Build`=12340; +DELETE FROM `battlenet_components` WHERE `Program`='Tool' AND `Build`=1569; +DELETE FROM `battlenet_components` WHERE `Program`='Bnet' AND `Build`=21719; diff --git a/src/server/authserver/Authentication/AuthCodes.cpp b/src/server/authserver/Authentication/AuthCodes.cpp index bb278dd6653..7a4998f7028 100644 --- a/src/server/authserver/Authentication/AuthCodes.cpp +++ b/src/server/authserver/Authentication/AuthCodes.cpp @@ -79,4 +79,9 @@ namespace AuthHelper return NULL; } + + bool IsBuildSupportingBattlenet(int build) + { + return build >= 15595; + } }; diff --git a/src/server/authserver/Authentication/AuthCodes.h b/src/server/authserver/Authentication/AuthCodes.h index 57db55c98a8..a6113b0d26d 100644 --- a/src/server/authserver/Authentication/AuthCodes.h +++ b/src/server/authserver/Authentication/AuthCodes.h @@ -182,6 +182,7 @@ namespace AuthHelper bool IsAcceptedClientBuild(int build); bool IsPostBCAcceptedClientBuild(int build); bool IsPreBCAcceptedClientBuild(int build); + bool IsBuildSupportingBattlenet(int build); }; #endif diff --git a/src/server/authserver/Server/AuthSocket.cpp b/src/server/authserver/Server/AuthSocket.cpp index 32140f76ba4..7ca49b03b56 100644 --- a/src/server/authserver/Server/AuthSocket.cpp +++ b/src/server/authserver/Server/AuthSocket.cpp @@ -480,7 +480,9 @@ bool AuthSocket::_HandleLogonChallenge() unk3.SetRand(16 * 8); // Fill the response packet with the result - if (AuthHelper::IsAcceptedClientBuild(_build)) + if (fields[9].GetUInt32() && AuthHelper::IsBuildSupportingBattlenet(_build)) + pkt << uint8(WOW_FAIL_USE_BATTLENET); + else if (AuthHelper::IsAcceptedClientBuild(_build)) pkt << uint8(WOW_SUCCESS); else pkt << uint8(WOW_FAIL_VERSION_INVALID); diff --git a/src/server/authserver/Server/BattlenetSocket.cpp b/src/server/authserver/Server/BattlenetSocket.cpp index eb8dc1158f0..4ee3c8e9b3d 100644 --- a/src/server/authserver/Server/BattlenetSocket.cpp +++ b/src/server/authserver/Server/BattlenetSocket.cpp @@ -107,7 +107,6 @@ void Battlenet::Socket::_SetVSFields(std::string const& pstr) bool Battlenet::Socket::HandleAuthChallenge(PacketHeader& header, BitStream& packet) { - // Verify that this IP is not in the ip_banned table LoginDatabase.Execute(LoginDatabase.GetPreparedStatement(LOGIN_DEL_EXPIRED_IP_BANS)); @@ -160,7 +159,12 @@ bool Battlenet::Socket::HandleAuthChallenge(PacketHeader& header, BitStream& pac else if (!sBattlenetMgr->HasPlatform(component.Platform)) complete.SetAuthResult(AUTH_INVALID_OS); else - complete.SetAuthResult(AUTH_REGION_BAD_VERSION); + { + if (component.Program != "WoW" || AuthHelper::IsBuildSupportingBattlenet(component.Build)) + complete.SetAuthResult(AUTH_REGION_BAD_VERSION); + else + complete.SetAuthResult(AUTH_USE_GRUNT_LOGON); + } Send(complete); return true; diff --git a/src/server/shared/Database/Implementation/LoginDatabase.cpp b/src/server/shared/Database/Implementation/LoginDatabase.cpp index 1da8088ed36..bccbe41a6ec 100644 --- a/src/server/shared/Database/Implementation/LoginDatabase.cpp +++ b/src/server/shared/Database/Implementation/LoginDatabase.cpp @@ -37,7 +37,7 @@ void LoginDatabaseConnection::DoPrepareStatements() PrepareStatement(LOGIN_SEL_SESSIONKEY, "SELECT a.sessionkey, a.id, aa.gmlevel FROM account a LEFT JOIN account_access aa ON (a.id = aa.id) WHERE username = ?", CONNECTION_SYNCH); PrepareStatement(LOGIN_UPD_VS, "UPDATE account SET v = ?, s = ? WHERE username = ?", CONNECTION_ASYNC); PrepareStatement(LOGIN_UPD_LOGONPROOF, "UPDATE account SET sessionkey = ?, last_ip = ?, last_login = NOW(), locale = ?, failed_logins = 0, os = ? WHERE username = ?", CONNECTION_SYNCH); - PrepareStatement(LOGIN_SEL_LOGONCHALLENGE, "SELECT a.sha_pass_hash, a.id, a.locked, a.lock_country, a.last_ip, aa.gmlevel, a.v, a.s, a.token_key FROM account a LEFT JOIN account_access aa ON (a.id = aa.id) WHERE a.username = ?", CONNECTION_SYNCH); + PrepareStatement(LOGIN_SEL_LOGONCHALLENGE, "SELECT a.sha_pass_hash, a.id, a.locked, a.lock_country, a.last_ip, aa.gmlevel, a.v, a.s, a.token_key, a.battlenet_account FROM account a LEFT JOIN account_access aa ON (a.id = aa.id) WHERE a.username = ?", CONNECTION_SYNCH); PrepareStatement(LOGIN_SEL_LOGON_COUNTRY, "SELECT country FROM ip2nation WHERE ip < ? ORDER BY ip DESC LIMIT 0,1", CONNECTION_SYNCH); PrepareStatement(LOGIN_UPD_FAILEDLOGINS, "UPDATE account SET failed_logins = failed_logins + 1 WHERE username = ?", CONNECTION_ASYNC); PrepareStatement(LOGIN_SEL_FAILEDLOGINS, "SELECT id, failed_logins FROM account WHERE username = ?", CONNECTION_SYNCH); -- cgit v1.2.3