diff options
Diffstat (limited to 'src')
18 files changed, 1003 insertions, 73 deletions
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<AuthSocket> acceptor; + RealmAcceptor<Battlenet::Socket> 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 <http://www.trinitycore.org/> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef __BATTLENETBITSTREAM_H__ +#define __BATTLENETBITSTREAM_H__ + +#include "ByteConverter.h" +#include <exception> +#include <string> +#include <vector> + +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<uint32>(bitCount) + baseLength; + AlignToNextByte(); + std::string str(reinterpret_cast<char*>(&_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<uint32>(32); + return *reinterpret_cast<float*>(&val); + } + + std::string ReadFourCC() + { + uint32 fcc = Read<uint32>(32); + EndianConvertReverse(fcc); + size_t len = 4; + while (!(fcc & 0xFF)) + { + fcc >>= 8; + --len; + } + + return std::string(reinterpret_cast<char*>(&fcc), len); + } + + template<typename T> + 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<T>((uint64)(_buffer[_readPos >> 3] >> bitPos & (uint32)((uint8)(1 << bitsLeftInByte) - 1)) << bitCount); + _readPos += bitsLeftInByte; + } + return ret; + } + + //WriteString + + template<typename T> + 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<typename T> + 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<uint8> _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 <http://www.trinitycore.org/> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "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 <http://www.trinitycore.org/> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef __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 <http://www.trinitycore.org/> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "Common.h" +#include "BattlenetBitStream.h" +#include "BattlenetPackets.h" +#include "Util.h" +#include <limits> +#include <sstream> + +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<uint32>(6)); + for (size_t i = 0; i < Components.size(); ++i) + { + Component& component = Components[i]; + component.Program = _stream.ReadFourCC(); + component.Platform = _stream.ReadFourCC(); + component.Build = _stream.Read<uint32>(32); + } + + if (_stream.Read<uint32>(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<uint32>(3)); + for (size_t i = 0; i < Modules.size(); ++i) + { + ModuleData& data = Modules[i]; + data.Size = _stream.Read<uint32>(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<int32>::min(), 32); + _stream.Write(1, 1); + // if written == 1 + { + _stream.Write(1, 1); + // if written == 1 + { + _stream.Write(Threshold, 32); + _stream.Write(Rate, 32); + } + } + + // 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 <http://www.trinitycore.org/> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef __BATTLENETPACKETS_H__ +#define __BATTLENETPACKETS_H__ + +#include "Define.h" +#include "Errors.h" +#include <string> + +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<Component> 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<ModuleInfo> 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<ModuleData> 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<ModuleInfo> 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 <http://www.trinitycore.org/> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "AuthCodes.h" +#include "BattlenetBitStream.h" +#include "BattlenetPackets.h" +#include "BattlenetSocket.h" +#include <map> + +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<Battlenet::PacketHeader, Battlenet::Socket::PacketHandler> InitHandlers() +{ + std::map<Battlenet::PacketHeader, Battlenet::Socket::PacketHandler> handlers; + + handlers[Battlenet::PacketHeader(Battlenet::CMSG_AUTH_CHALLENGE, Battlenet::AUTHENTICATION)] = &Battlenet::Socket::HandleAuthChallenge; + handlers[Battlenet::PacketHeader(Battlenet::CMSG_AUTH_PROOF_RESPONSE, Battlenet::AUTHENTICATION)] = &Battlenet::Socket::HandleAuthProofResponse; + + return handlers; +} + +std::map<Battlenet::PacketHeader, Battlenet::Socket::PacketHandler> 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<uint32>(6); + if (packet.Read<uint32>(1)) + _currentChannel = header.Channel = packet.Read<int32>(4); + + printf("Battlenet::Socket::OnRead %s\n", header.ToString().c_str()); + std::map<PacketHeader, PacketHandler>::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 <http://www.trinitycore.org/> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef _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 LoginType> class RealmAcceptor : public ACE_Acceptor<RealmSocket, ACE_SOCK_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 <http://www.gnu.org/licenses/>. */ -#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<uint32>(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/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 <http://www.trinitycore.org/> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "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/AuthCrypt.h b/src/server/shared/Cryptography/Authentication/PacketCrypt.h index 8fa150068a2..36f3b81fb53 100644 --- a/src/server/shared/Cryptography/Authentication/AuthCrypt.h +++ b/src/server/shared/Cryptography/Authentication/PacketCrypt.h @@ -1,6 +1,5 @@ /* * Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/> - * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/> * * 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 @@ -16,27 +15,29 @@ * with this program. If not, see <http://www.gnu.org/licenses/>. */ -#ifndef _AUTHCRYPT_H -#define _AUTHCRYPT_H +#ifndef _PACKETCRYPT_H +#define _PACKETCRYPT_H #include "Cryptography/ARC4.h" class BigNumber; -class AuthCrypt +class PacketCrypt { public: - AuthCrypt(); + PacketCrypt(uint32 rc4InitSize); + virtual ~PacketCrypt() { } - void Init(BigNumber* K); - void DecryptRecv(uint8 *, size_t); - void EncryptSend(uint8 *, size_t); + 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; } - private: + protected: ARC4 _clientDecrypt; ARC4 _serverEncrypt; bool _initialized; }; -#endif + +#endif // _PACKETCRYPT_H diff --git a/src/server/shared/Cryptography/Authentication/AuthCrypt.cpp b/src/server/shared/Cryptography/Authentication/WorldPacketCrypt.cpp index ff94f307254..c6b283d9961 100644 --- a/src/server/shared/Cryptography/Authentication/AuthCrypt.cpp +++ b/src/server/shared/Cryptography/Authentication/WorldPacketCrypt.cpp @@ -16,58 +16,36 @@ * with this program. If not, see <http://www.gnu.org/licenses/>. */ -#include "AuthCrypt.h" -#include "Cryptography/HMACSHA1.h" +#include "WorldPacketCrypt.h" +#include "Cryptography/HmacHash.h" #include "Cryptography/BigNumber.h" -AuthCrypt::AuthCrypt() : - _clientDecrypt(SHA_DIGEST_LENGTH), _serverEncrypt(SHA_DIGEST_LENGTH), - _initialized(false) -{ } +WorldPacketCrypt::WorldPacketCrypt() : PacketCrypt(SHA_DIGEST_LENGTH) +{ +} -void AuthCrypt::Init(BigNumber* K) +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); + 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); + HmacHash clientDecryptHmac(SEED_KEY_SIZE, (uint8*)ServerDecryptionKey, EVP_sha1(), SHA_DIGEST_LENGTH); 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/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 <http://www.trinitycore.org/> + * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef _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/HmacHash.cpp index 2148a3b8a7b..7a365ade457 100644 --- a/src/server/shared/Cryptography/HMACSHA1.cpp +++ b/src/server/shared/Cryptography/HmacHash.cpp @@ -16,42 +16,44 @@ * with this program. If not, see <http://www.gnu.org/licenses/>. */ -#include "HMACSHA1.h" +#include "HmacHash.h" #include "BigNumber.h" #include "Common.h" -HmacHash::HmacHash(uint32 len, uint8 *seed) +HmacHash::HmacHash(uint32 len, uint8 *seed, EVP_MD const* hasher, uint32 digestLength) { - HMAC_CTX_init(&m_ctx); - HMAC_Init_ex(&m_ctx, seed, len, EVP_sha1(), NULL); - memset(m_digest, 0, sizeof(m_digest)); + 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(&m_ctx); + HMAC_CTX_cleanup(&_ctx); + delete[] _digest; } void HmacHash::UpdateData(const std::string &str) { - HMAC_Update(&m_ctx, (uint8 const*)str.c_str(), str.length()); + HMAC_Update(&_ctx, (uint8 const*)str.c_str(), str.length()); } void HmacHash::UpdateData(const uint8* data, size_t len) { - HMAC_Update(&m_ctx, data, len); + HMAC_Update(&_ctx, data, len); } void HmacHash::Finalize() { uint32 length = 0; - HMAC_Final(&m_ctx, (uint8*)m_digest, &length); - ASSERT(length == SHA_DIGEST_LENGTH); + HMAC_Final(&_ctx, _digest, &length); + ASSERT(length == _digestLength); } -uint8 *HmacHash::ComputeHash(BigNumber* bn) +uint8* HmacHash::ComputeHash(BigNumber* bn) { - HMAC_Update(&m_ctx, bn->AsByteArray().get(), bn->GetNumBytes()); + HMAC_Update(&_ctx, bn->AsByteArray().get(), bn->GetNumBytes()); Finalize(); - return (uint8*)m_digest; + return _digest; } diff --git a/src/server/shared/Cryptography/HMACSHA1.h b/src/server/shared/Cryptography/HmacHash.h index de1556d3c98..cf59e16f08e 100644 --- a/src/server/shared/Cryptography/HMACSHA1.h +++ b/src/server/shared/Cryptography/HmacHash.h @@ -31,17 +31,18 @@ class BigNumber; class HmacHash { public: - HmacHash(uint32 len, uint8 *seed); + 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 (uint8*)m_digest; } + uint8* ComputeHash(BigNumber* bn); + uint8* GetDigest() { return _digest; } int GetLength() const { return SHA_DIGEST_LENGTH; } private: - HMAC_CTX m_ctx; - uint8 m_digest[SHA_DIGEST_LENGTH]; + HMAC_CTX _ctx; + uint8* _digest; + uint32 _digestLength; }; -#endif +#endif |