From 5a363ee0e1556b58ad1d16ce2b78ae5f92e065ea Mon Sep 17 00:00:00 2001 From: leak Date: Sat, 17 May 2014 20:27:39 +0200 Subject: Replace authserver ACE related code with Boost/C++11 --- src/server/authserver/Server/AuthSession.cpp | 915 +++++++++++++++++++++++++++ 1 file changed, 915 insertions(+) create mode 100644 src/server/authserver/Server/AuthSession.cpp (limited to 'src/server/authserver/Server/AuthSession.cpp') diff --git a/src/server/authserver/Server/AuthSession.cpp b/src/server/authserver/Server/AuthSession.cpp new file mode 100644 index 00000000000..cb78336f2d3 --- /dev/null +++ b/src/server/authserver/Server/AuthSession.cpp @@ -0,0 +1,915 @@ +/* +* 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 +#include +#include +#include +#include "ByteBuffer.h" +#include "AuthCodes.h" +#include "Database/DatabaseEnv.h" +#include "SHA1.h" +#include "openssl/crypto.h" +#include "Configuration/Config.h" +#include "RealmList.h" + +using boost::asio::ip::tcp; + +enum eAuthCmd +{ + AUTH_LOGON_CHALLENGE = 0x00, + AUTH_LOGON_PROOF = 0x01, + AUTH_RECONNECT_CHALLENGE = 0x02, + AUTH_RECONNECT_PROOF = 0x03, + REALM_LIST = 0x10, + XFER_INITIATE = 0x30, + XFER_DATA = 0x31, + XFER_ACCEPT = 0x32, + XFER_RESUME = 0x33, + XFER_CANCEL = 0x34 +}; + +enum eStatus +{ + STATUS_CONNECTED = 0, + STATUS_AUTHED +}; + +#pragma pack(push, 1) + +typedef struct AUTH_LOGON_CHALLENGE_C +{ + uint8 cmd; + uint8 error; + uint16 size; + uint8 gamename[4]; + uint8 version1; + uint8 version2; + uint8 version3; + uint16 build; + uint8 platform[4]; + uint8 os[4]; + uint8 country[4]; + uint32 timezone_bias; + uint32 ip; + uint8 I_len; + uint8 I[1]; +} sAuthLogonChallenge_C; + +typedef struct AUTH_LOGON_PROOF_C +{ + uint8 cmd; + uint8 A[32]; + uint8 M1[20]; + uint8 crc_hash[20]; + uint8 number_of_keys; + uint8 securityFlags; +} sAuthLogonProof_C; + +typedef struct AUTH_LOGON_PROOF_S +{ + uint8 cmd; + uint8 error; + uint8 M2[20]; + uint32 unk1; + uint32 unk2; + uint16 unk3; +} sAuthLogonProof_S; + +typedef struct AUTH_LOGON_PROOF_S_OLD +{ + uint8 cmd; + uint8 error; + uint8 M2[20]; + uint32 unk2; +} sAuthLogonProof_S_Old; + +typedef struct AUTH_RECONNECT_PROOF_C +{ + uint8 cmd; + uint8 R1[16]; + uint8 R2[20]; + uint8 R3[20]; + uint8 number_of_keys; +} sAuthReconnectProof_C; + +#pragma pack(pop) + + +typedef struct AuthHandler +{ + eAuthCmd cmd; + uint32 status; + size_t packetSize; + bool (AuthSession::*handler)(); +} AuthHandler; + +#define BYTE_SIZE 32 +#define REALMLIST_SKIP_PACKETS 5 + +const AuthHandler table[] = +{ + { AUTH_LOGON_CHALLENGE, STATUS_CONNECTED, sizeof(AUTH_LOGON_CHALLENGE_C), &AuthSession::_HandleLogonChallenge }, + { AUTH_LOGON_PROOF, STATUS_CONNECTED, sizeof(AUTH_LOGON_PROOF_C), &AuthSession::_HandleLogonProof }, + { AUTH_RECONNECT_CHALLENGE, STATUS_CONNECTED, sizeof(AUTH_LOGON_CHALLENGE_C), &AuthSession::_HandleReconnectChallenge }, + { AUTH_RECONNECT_PROOF, STATUS_CONNECTED, sizeof(AUTH_RECONNECT_PROOF_C), &AuthSession::_HandleReconnectProof }, + { REALM_LIST, STATUS_AUTHED, REALMLIST_SKIP_PACKETS, &AuthSession::_HandleRealmList } +}; + +void AuthSession::AsyncReadHeader() +{ + auto self(shared_from_this()); + + _socket.async_read_some(boost::asio::buffer(_readBuffer, 1), [this, self](boost::system::error_code error, size_t transferedBytes) + { + if (!error && transferedBytes == 1) + { + for (const AuthHandler& entry : table) + { + if ((uint8)entry.cmd == _readBuffer[0] && (entry.status == STATUS_CONNECTED || (_isAuthenticated && entry.status == STATUS_AUTHED))) + { + // Handle dynamic size packet + if (_readBuffer[0] == AUTH_LOGON_CHALLENGE) + { + _socket.read_some(boost::asio::buffer(&_readBuffer[1], sizeof(uint8) + sizeof(uint16))); //error + size + + AsyncReadData(entry.handler, (uint16)&_readBuffer[2], sizeof(uint8) + sizeof(uint8) + sizeof(uint16)); // cmd + error + size + } + else + { + AsyncReadData(entry.handler, entry.packetSize, sizeof(uint8)); + } + break; + } + } + } + else + { + _socket.close(); + } + }); +} + +void AuthSession::AsyncReadData(bool (AuthSession::*handler)(), size_t dataSize, size_t bufferOffSet) +{ + auto self(shared_from_this()); + + _socket.async_read_some(boost::asio::buffer(&_readBuffer[bufferOffSet], dataSize), [handler, this, self](boost::system::error_code error, size_t transferedBytes) + { + if (!error && transferedBytes > 0) + { + if (!(*this.*handler)()) + { + _socket.close(); + return; + } + + AsyncReadHeader(); + } + else + { + _socket.close(); + } + }); +} + +void AuthSession::AsyncWrite(std::size_t length) +{ + boost::asio::async_write(_socket, boost::asio::buffer(_writeBuffer, length), [this](boost::system::error_code error, std::size_t /*length*/) + { + if (error) + { + _socket.close(); + } + }); +} + +bool AuthSession::_HandleLogonChallenge() +{ + sAuthLogonChallenge_C *challenge = (sAuthLogonChallenge_C*)&_readBuffer; + + //TC_LOG_DEBUG("server.authserver", "[AuthChallenge] got full packet, %#04x bytes", challenge->size); + TC_LOG_DEBUG("server.authserver", "[AuthChallenge] name(%d): '%s'", challenge->I_len, challenge->I); + + ByteBuffer pkt; + + _login.assign((const char*)challenge->I, challenge->I_len); + _build = challenge->build; + _expversion = uint8(AuthHelper::IsPostBCAcceptedClientBuild(_build) ? POST_BC_EXP_FLAG : (AuthHelper::IsPreBCAcceptedClientBuild(_build) ? PRE_BC_EXP_FLAG : NO_VALID_EXP_FLAG)); + _os = (const char*)challenge->os; + + if (_os.size() > 4) + return false; + + // Restore string order as its byte order is reversed + std::reverse(_os.begin(), _os.end()); + + pkt << uint8(AUTH_LOGON_CHALLENGE); + pkt << uint8(0x00); + + // Verify that this IP is not in the ip_banned table + LoginDatabase.Execute(LoginDatabase.GetPreparedStatement(LOGIN_DEL_EXPIRED_IP_BANS)); + + std::string const& ipAddress = _socket.remote_endpoint().address().to_string(); + unsigned short port = _socket.remote_endpoint().port(); + + PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_IP_BANNED); + stmt->setString(0, ipAddress); + PreparedQueryResult result = LoginDatabase.Query(stmt); + if (result) + { + pkt << uint8(WOW_FAIL_BANNED); + TC_LOG_DEBUG("server.authserver", "'%s:%d' [AuthChallenge] Banned ip tries to login!", ipAddress.c_str(), port); + } + else + { + // Get the account details from the account table + // No SQL injection (prepared statement) + stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_LOGONCHALLENGE); + stmt->setString(0, _login); + + PreparedQueryResult res2 = LoginDatabase.Query(stmt); + if (res2) + { + Field* fields = res2->Fetch(); + + // If the IP is 'locked', check that the player comes indeed from the correct IP address + bool locked = false; + if (fields[2].GetUInt8() == 1) // if ip is locked + { + TC_LOG_DEBUG("server.authserver", "[AuthChallenge] Account '%s' is locked to IP - '%s'", _login.c_str(), fields[4].GetCString()); + TC_LOG_DEBUG("server.authserver", "[AuthChallenge] Player address is '%s'", ipAddress.c_str()); + + if (strcmp(fields[4].GetCString(), ipAddress.c_str()) != 0) + { + TC_LOG_DEBUG("server.authserver", "[AuthChallenge] Account IP differs"); + pkt << uint8(WOW_FAIL_LOCKED_ENFORCED); + locked = true; + } + else + TC_LOG_DEBUG("server.authserver", "[AuthChallenge] Account IP matches"); + } + else + { + TC_LOG_DEBUG("server.authserver", "[AuthChallenge] Account '%s' is not locked to ip", _login.c_str()); + std::string accountCountry = fields[3].GetString(); + if (accountCountry.empty() || accountCountry == "00") + TC_LOG_DEBUG("server.authserver", "[AuthChallenge] Account '%s' is not locked to country", _login.c_str()); + else if (!accountCountry.empty()) + { + uint32 ip = inet_addr(ipAddress.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.authserver", "[AuthChallenge] Account '%s' is locked to country: '%s' Player country is '%s'", _login.c_str(), + accountCountry.c_str(), loginCountry.c_str()); + + if (loginCountry != accountCountry) + { + TC_LOG_DEBUG("server.authserver", "[AuthChallenge] Account country differs."); + pkt << uint8(WOW_FAIL_UNLOCKABLE_LOCK); + locked = true; + } + else + TC_LOG_DEBUG("server.authserver", "[AuthChallenge] Account country matches"); + } + else + TC_LOG_DEBUG("server.authserver", "[AuthChallenge] IP2NATION Table empty"); + } + } + + if (!locked) + { + //set expired bans to inactive + LoginDatabase.DirectExecute(LoginDatabase.GetPreparedStatement(LOGIN_UPD_EXPIRED_ACCOUNT_BANS)); + + // If the account is banned, reject the logon attempt + stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_ACCOUNT_BANNED); + stmt->setUInt32(0, fields[1].GetUInt32()); + PreparedQueryResult banresult = LoginDatabase.Query(stmt); + if (banresult) + { + if ((*banresult)[0].GetUInt32() == (*banresult)[1].GetUInt32()) + { + pkt << uint8(WOW_FAIL_BANNED); + TC_LOG_DEBUG("server.authserver", "'%s:%d' [AuthChallenge] Banned account %s tried to login!", ipAddress.c_str(), + port, _login.c_str()); + } + else + { + pkt << uint8(WOW_FAIL_SUSPENDED); + TC_LOG_DEBUG("server.authserver", "'%s:%d' [AuthChallenge] Temporarily banned account %s tried to login!", + ipAddress.c_str(), port, _login.c_str()); + } + } + else + { + // Get the password from the account table, upper it, and make the SRP6 calculation + std::string rI = fields[0].GetString(); + + // Don't calculate (v, s) if there are already some in the database + std::string databaseV = fields[6].GetString(); + std::string databaseS = fields[7].GetString(); + + TC_LOG_DEBUG("network", "database authentication values: v='%s' s='%s'", databaseV.c_str(), databaseS.c_str()); + + // multiply with 2 since bytes are stored as hexstring + if (databaseV.size() != BYTE_SIZE * 2 || databaseS.size() != BYTE_SIZE * 2) + SetVSFields(rI); + else + { + s.SetHexStr(databaseS.c_str()); + v.SetHexStr(databaseV.c_str()); + } + + b.SetRand(19 * 8); + BigNumber gmod = g.ModExp(b, N); + B = ((v * 3) + gmod) % N; + + ASSERT(gmod.GetNumBytes() <= 32); + + BigNumber unk3; + unk3.SetRand(16 * 8); + + // Fill the response packet with the result + if (AuthHelper::IsAcceptedClientBuild(_build)) + pkt << uint8(WOW_SUCCESS); + else + pkt << uint8(WOW_FAIL_VERSION_INVALID); + + // B may be calculated < 32B so we force minimal length to 32B + pkt.append(B.AsByteArray(32).get(), 32); // 32 bytes + pkt << uint8(1); + pkt.append(g.AsByteArray().get(), 1); + pkt << uint8(32); + pkt.append(N.AsByteArray(32).get(), 32); + pkt.append(s.AsByteArray().get(), s.GetNumBytes()); // 32 bytes + pkt.append(unk3.AsByteArray(16).get(), 16); + uint8 securityFlags = 0; + + // Check if token is used + _tokenKey = fields[8].GetString(); + if (!_tokenKey.empty()) + securityFlags = 4; + + pkt << uint8(securityFlags); // security flags (0x0...0x04) + + if (securityFlags & 0x01) // PIN input + { + pkt << uint32(0); + pkt << uint64(0) << uint64(0); // 16 bytes hash? + } + + if (securityFlags & 0x02) // Matrix input + { + pkt << uint8(0); + pkt << uint8(0); + pkt << uint8(0); + pkt << uint8(0); + pkt << uint64(0); + } + + if (securityFlags & 0x04) // Security token input + pkt << uint8(1); + + uint8 secLevel = fields[5].GetUInt8(); + _accountSecurityLevel = secLevel <= SEC_ADMINISTRATOR ? AccountTypes(secLevel) : SEC_ADMINISTRATOR; + + _localizationName.resize(4); + for (int i = 0; i < 4; ++i) + _localizationName[i] = challenge->country[4 - i - 1]; + + TC_LOG_DEBUG("server.authserver", "'%s:%d' [AuthChallenge] account %s is using '%c%c%c%c' locale (%u)", + ipAddress.c_str(), port, _login.c_str(), + challenge->country[3], challenge->country[2], challenge->country[1], challenge->country[0], + GetLocaleByName(_localizationName) + ); + } + } + } + else //no account + pkt << uint8(WOW_FAIL_UNKNOWN_ACCOUNT); + } + + std::memcpy(_writeBuffer, (char const*)pkt.contents(), pkt.size()); + + AsyncWrite(pkt.size()); + + return true; +} + +// Logon Proof command handler +bool AuthSession::_HandleLogonProof() +{ + + TC_LOG_DEBUG("server.authserver", "Entering _HandleLogonProof"); + // Read the packet + sAuthLogonProof_C *logonProof = (sAuthLogonProof_C*)&_readBuffer; + + // If the client has no valid version + if (_expversion == NO_VALID_EXP_FLAG) + { + // Check if we have the appropriate patch on the disk + TC_LOG_DEBUG("network", "Client with invalid version, patching is not implemented"); + return false; + } + + // Continue the SRP6 calculation based on data received from the client + BigNumber A; + + A.SetBinary(logonProof->A, 32); + + // SRP safeguard: abort if A == 0 + if (A.isZero()) + { + return false; + } + + SHA1Hash sha; + sha.UpdateBigNumbers(&A, &B, NULL); + sha.Finalize(); + BigNumber u; + u.SetBinary(sha.GetDigest(), 20); + BigNumber S = (A * (v.ModExp(u, N))).ModExp(b, N); + + uint8 t[32]; + uint8 t1[16]; + uint8 vK[40]; + memcpy(t, S.AsByteArray(32).get(), 32); + + for (int i = 0; i < 16; ++i) + t1[i] = t[i * 2]; + + sha.Initialize(); + sha.UpdateData(t1, 16); + sha.Finalize(); + + for (int i = 0; i < 20; ++i) + vK[i * 2] = sha.GetDigest()[i]; + + for (int i = 0; i < 16; ++i) + t1[i] = t[i * 2 + 1]; + + sha.Initialize(); + sha.UpdateData(t1, 16); + sha.Finalize(); + + for (int i = 0; i < 20; ++i) + vK[i * 2 + 1] = sha.GetDigest()[i]; + + K.SetBinary(vK, 40); + + uint8 hash[20]; + + sha.Initialize(); + sha.UpdateBigNumbers(&N, NULL); + sha.Finalize(); + memcpy(hash, sha.GetDigest(), 20); + sha.Initialize(); + sha.UpdateBigNumbers(&g, NULL); + sha.Finalize(); + + for (int i = 0; i < 20; ++i) + hash[i] ^= sha.GetDigest()[i]; + + BigNumber t3; + t3.SetBinary(hash, 20); + + sha.Initialize(); + sha.UpdateData(_login); + sha.Finalize(); + uint8 t4[SHA_DIGEST_LENGTH]; + memcpy(t4, sha.GetDigest(), SHA_DIGEST_LENGTH); + + sha.Initialize(); + sha.UpdateBigNumbers(&t3, NULL); + sha.UpdateData(t4, SHA_DIGEST_LENGTH); + sha.UpdateBigNumbers(&s, &A, &B, &K, NULL); + sha.Finalize(); + BigNumber M; + M.SetBinary(sha.GetDigest(), 20); + + // Check if SRP6 results match (password is correct), else send an error + if (!memcmp(M.AsByteArray().get(), logonProof->M1, 20)) + { + TC_LOG_DEBUG("server.authserver", "'%s:%d' User '%s' successfully authenticated", GetRemoteIpAddress().c_str(), 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(1, GetRemoteIpAddress().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); + sha.Finalize(); + + // Check auth token + if ((logonProof->securityFlags & 0x04) || !_tokenKey.empty()) + { + // TODO To be fixed + + /* + uint8 size; + socket().recv((char*)&size, 1); + char* token = new char[size + 1]; + token[size] = '\0'; + socket().recv(token, size); + unsigned int validToken = TOTP::GenerateToken(_tokenKey.c_str()); + unsigned int incomingToken = atoi(token); + delete[] token; + if (validToken != incomingToken) + { + char data[] = { AUTH_LOGON_PROOF, WOW_FAIL_UNKNOWN_ACCOUNT, 3, 0 }; + socket().send(data, sizeof(data)); + return false; + }*/ + } + + if (_expversion & POST_BC_EXP_FLAG) // 2.x and 3.x clients + { + sAuthLogonProof_S proof; + 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.unk2 = 0x00; // SurveyId + proof.unk3 = 0x00; + + std::memcpy(_writeBuffer, (char *)&proof, sizeof(proof)); + AsyncWrite(sizeof(proof)); + } + else + { + sAuthLogonProof_S_Old proof; + memcpy(proof.M2, sha.GetDigest(), 20); + proof.cmd = AUTH_LOGON_PROOF; + proof.error = 0; + proof.unk2 = 0x00; + + std::memcpy(_writeBuffer, (char *)&proof, sizeof(proof)); + AsyncWrite(sizeof(proof)); + } + + _isAuthenticated = true; + } + else + { + char data[4] = { AUTH_LOGON_PROOF, WOW_FAIL_UNKNOWN_ACCOUNT, 3, 0 }; + + std::memcpy(_writeBuffer, data, sizeof(data)); + AsyncWrite(sizeof(data)); + + TC_LOG_DEBUG("server.authserver", "'%s:%d' [AuthChallenge] account %s tried to login with invalid password!", + GetRemoteIpAddress().c_str(), GetRemotePort(), _login.c_str()); + + uint32 MaxWrongPassCount = sConfigMgr->GetIntDefault("WrongPass.MaxCount", 0); + if (MaxWrongPassCount > 0) + { + //Increment number of failed logins by one and if it reaches the limit temporarily ban that account or IP + PreparedStatement *stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_FAILEDLOGINS); + stmt->setString(0, _login); + LoginDatabase.Execute(stmt); + + stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_FAILEDLOGINS); + stmt->setString(0, _login); + + if (PreparedQueryResult loginfail = LoginDatabase.Query(stmt)) + { + uint32 failed_logins = (*loginfail)[1].GetUInt32(); + + if (failed_logins >= MaxWrongPassCount) + { + uint32 WrongPassBanTime = sConfigMgr->GetIntDefault("WrongPass.BanTime", 600); + bool WrongPassBanType = sConfigMgr->GetBoolDefault("WrongPass.BanType", false); + + if (WrongPassBanType) + { + uint32 acc_id = (*loginfail)[0].GetUInt32(); + stmt = LoginDatabase.GetPreparedStatement(LOGIN_INS_ACCOUNT_AUTO_BANNED); + stmt->setUInt32(0, acc_id); + stmt->setUInt32(1, WrongPassBanTime); + LoginDatabase.Execute(stmt); + + TC_LOG_DEBUG("server.authserver", "'%s:%d' [AuthChallenge] account %s got banned for '%u' seconds because it failed to authenticate '%u' times", + GetRemoteIpAddress().c_str(), GetRemotePort(), _login.c_str(), WrongPassBanTime, failed_logins); + } + else + { + stmt = LoginDatabase.GetPreparedStatement(LOGIN_INS_IP_AUTO_BANNED); + stmt->setString(0, GetRemoteIpAddress()); + stmt->setUInt32(1, WrongPassBanTime); + LoginDatabase.Execute(stmt); + + TC_LOG_DEBUG("server.authserver", "'%s:%d' [AuthChallenge] IP got banned for '%u' seconds because account %s failed to authenticate '%u' times", + GetRemoteIpAddress().c_str(), GetRemotePort(), WrongPassBanTime, _login.c_str(), failed_logins); + } + } + } + } + } + + return true; +} + +bool AuthSession::_HandleReconnectChallenge() +{ + TC_LOG_DEBUG("server.authserver", "Entering _HandleReconnectChallenge"); + sAuthLogonChallenge_C *challenge = (sAuthLogonChallenge_C*)&_readBuffer; + + //TC_LOG_DEBUG("server.authserver", "[AuthChallenge] got full packet, %#04x bytes", challenge->size); + TC_LOG_DEBUG("server.authserver", "[AuthChallenge] name(%d): '%s'", challenge->I_len, challenge->I); + + _login.assign((const char*)challenge->I, challenge->I_len); + + PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_SESSIONKEY); + stmt->setString(0, _login); + PreparedQueryResult result = LoginDatabase.Query(stmt); + + // Stop if the account is not found + if (!result) + { + TC_LOG_ERROR("server.authserver", "'%s:%d' [ERROR] user %s tried to login and we cannot find his session key in the database.", + GetRemoteIpAddress().c_str(), GetRemotePort(), _login.c_str()); + return false; + } + + // Reinitialize build, expansion and the account securitylevel + _build = challenge->build; + _expversion = uint8(AuthHelper::IsPostBCAcceptedClientBuild(_build) ? POST_BC_EXP_FLAG : (AuthHelper::IsPreBCAcceptedClientBuild(_build) ? PRE_BC_EXP_FLAG : NO_VALID_EXP_FLAG)); + _os = (const char*)challenge->os; + + if (_os.size() > 4) + return false; + + // Restore string order as its byte order is reversed + std::reverse(_os.begin(), _os.end()); + + Field* fields = result->Fetch(); + uint8 secLevel = fields[2].GetUInt8(); + _accountSecurityLevel = secLevel <= SEC_ADMINISTRATOR ? AccountTypes(secLevel) : SEC_ADMINISTRATOR; + + K.SetHexStr((*result)[0].GetCString()); + + // Sending response + ByteBuffer pkt; + pkt << uint8(AUTH_RECONNECT_CHALLENGE); + pkt << uint8(0x00); + _reconnectProof.SetRand(16 * 8); + pkt.append(_reconnectProof.AsByteArray(16).get(), 16); // 16 bytes random + pkt << uint64(0x00) << uint64(0x00); // 16 bytes zeros + + std::memcpy(_writeBuffer, (char const*)pkt.contents(), pkt.size()); + AsyncWrite(pkt.size()); + + return true; +} +bool AuthSession::_HandleReconnectProof() +{ + TC_LOG_DEBUG("server.authserver", "Entering _HandleReconnectProof"); + sAuthReconnectProof_C *reconnectProof = (sAuthReconnectProof_C*)&_readBuffer; + + if (_login.empty() || !_reconnectProof.GetNumBytes() || !K.GetNumBytes()) + return false; + + BigNumber t1; + t1.SetBinary(reconnectProof->R1, 16); + + SHA1Hash sha; + sha.Initialize(); + sha.UpdateData(_login); + sha.UpdateBigNumbers(&t1, &_reconnectProof, &K, NULL); + sha.Finalize(); + + if (!memcmp(sha.GetDigest(), reconnectProof->R2, SHA_DIGEST_LENGTH)) + { + // Sending response + ByteBuffer pkt; + pkt << uint8(AUTH_RECONNECT_PROOF); + pkt << uint8(0x00); + pkt << uint16(0x00); // 2 bytes zeros + std::memcpy(_writeBuffer, (char const*)pkt.contents(), pkt.size()); + AsyncWrite(pkt.size()); + _isAuthenticated = true; + return true; + } + else + { + TC_LOG_ERROR("server.authserver", "'%s:%d' [ERROR] user %s tried to login, but session is invalid.", GetRemoteIpAddress().c_str(), + GetRemotePort(), _login.c_str()); + return false; + } +} + +ACE_INET_Addr const& 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 AuthSession::_HandleRealmList() +{ + TC_LOG_DEBUG("server.authserver", "Entering _HandleRealmList"); + + // Get the user id (else close the connection) + // No SQL injection (prepared statement) + PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_ACCOUNT_ID_BY_NAME); + stmt->setString(0, _login); + PreparedQueryResult result = LoginDatabase.Query(stmt); + if (!result) + { + TC_LOG_ERROR("server.authserver", "'%s:%d' [ERROR] user %s tried to login but we cannot find him in the database.", GetRemoteIpAddress().c_str(), + GetRemotePort(), _login.c_str()); + return false; + } + + Field* fields = result->Fetch(); + uint32 id = fields[0].GetUInt32(); + + // Update realm list if need + sRealmList->UpdateIfNeed(); + + // Circle through realms in the RealmList and construct the return packet (including # of user characters in each realm) + ByteBuffer pkt; + + size_t RealmListSize = 0; + for (RealmList::RealmMap::const_iterator i = sRealmList->begin(); i != sRealmList->end(); ++i) + { + const Realm &realm = i->second; + // don't work with realms which not compatible with the client + bool okBuild = ((_expversion & POST_BC_EXP_FLAG) && realm.gamebuild == _build) || ((_expversion & PRE_BC_EXP_FLAG) && !AuthHelper::IsPreBCAcceptedClientBuild(realm.gamebuild)); + + // No SQL injection. id of realm is controlled by the database. + uint32 flag = realm.flag; + RealmBuildInfo const* buildInfo = AuthHelper::GetBuildInfo(realm.gamebuild); + if (!okBuild) + { + 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; + + std::string name = i->first; + if (_expversion & PRE_BC_EXP_FLAG && flag & REALM_FLAG_SPECIFYBUILD) + { + std::ostringstream ss; + ss << name << " (" << buildInfo->MajorVersion << '.' << buildInfo->MinorVersion << '.' << buildInfo->BugfixVersion << ')'; + name = ss.str(); + } + + // We don't need the port number from which client connects with but the realm's port + ACE_INET_Addr clientAddr(realm.ExternalAddress.get_port_number(), GetRemoteIpAddress().c_str(), AF_INET); + + uint8 lock = (realm.allowedSecurityLevel > _accountSecurityLevel) ? 1 : 0; + + uint8 AmountOfCharacters = 0; + stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_NUM_CHARS_ON_REALM); + stmt->setUInt32(0, realm.m_ID); + stmt->setUInt32(1, id); + result = LoginDatabase.Query(stmt); + if (result) + AmountOfCharacters = (*result)[0].GetUInt8(); + + pkt << realm.icon; // realm type + if (_expversion & POST_BC_EXP_FLAG) // only 2.x and 3.x clients + pkt << lock; // if 1, then realm locked + pkt << uint8(flag); // RealmFlags + pkt << name; + pkt << GetAddressString(GetAddressForClient(realm, clientAddr)); + pkt << realm.populationLevel; + 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? + else + pkt << uint8(0x0); // 1.12.1 and 1.12.2 clients + + if (_expversion & POST_BC_EXP_FLAG && flag & REALM_FLAG_SPECIFYBUILD) + { + pkt << uint8(buildInfo->MajorVersion); + pkt << uint8(buildInfo->MinorVersion); + pkt << uint8(buildInfo->BugfixVersion); + pkt << uint16(buildInfo->Build); + } + + ++RealmListSize; + } + + if (_expversion & POST_BC_EXP_FLAG) // 2.x and 3.x clients + { + pkt << uint8(0x10); + pkt << uint8(0x00); + } + else // 1.12.1 and 1.12.2 clients + { + pkt << uint8(0x00); + pkt << uint8(0x02); + } + + // make a ByteBuffer which stores the RealmList's size + ByteBuffer RealmListSizeBuffer; + RealmListSizeBuffer << uint32(0); + if (_expversion & POST_BC_EXP_FLAG) // only 2.x and 3.x clients + RealmListSizeBuffer << uint16(RealmListSize); + else + RealmListSizeBuffer << uint32(RealmListSize); + + ByteBuffer hdr; + hdr << uint8(REALM_LIST); + hdr << uint16(pkt.size() + RealmListSizeBuffer.size()); + hdr.append(RealmListSizeBuffer); // append RealmList's size buffer + hdr.append(pkt); // append realms in the realmlist + + std::memcpy(_writeBuffer, (char const*)hdr.contents(), hdr.size()); + AsyncWrite(hdr.size()); + + return true; +} + +// Make the SRP6 calculation from hash in dB +void AuthSession::SetVSFields(const std::string& rI) +{ + s.SetRand(BYTE_SIZE * 8); + + BigNumber I; + I.SetHexStr(rI.c_str()); + + // In case of leading zeros in the rI hash, restore them + uint8 mDigest[SHA_DIGEST_LENGTH]; + memset(mDigest, 0, SHA_DIGEST_LENGTH); + if (I.GetNumBytes() <= SHA_DIGEST_LENGTH) + memcpy(mDigest, I.AsByteArray().get(), I.GetNumBytes()); + + std::reverse(mDigest, mDigest + SHA_DIGEST_LENGTH); + + SHA1Hash sha; + sha.UpdateData(s.AsByteArray().get(), s.GetNumBytes()); + sha.UpdateData(mDigest, SHA_DIGEST_LENGTH); + sha.Finalize(); + BigNumber x; + 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(2, _login); + LoginDatabase.Execute(stmt); + + OPENSSL_free(v_hex); + OPENSSL_free(s_hex); +} \ No newline at end of file -- cgit v1.2.3 From b520f7da018aa0d771e6589b58081e71643bf860 Mon Sep 17 00:00:00 2001 From: leak Date: Fri, 30 May 2014 15:46:17 +0200 Subject: Damn you VS default settings.. --- src/server/authserver/Main.cpp | 168 +-- src/server/authserver/Realms/RealmList.h | 20 +- src/server/authserver/Server/AuthServer.cpp | 18 +- src/server/authserver/Server/AuthServer.h | 18 +- src/server/authserver/Server/AuthSession.cpp | 1572 +++++++++++++------------- src/server/authserver/Server/AuthSession.h | 78 +- 6 files changed, 937 insertions(+), 937 deletions(-) (limited to 'src/server/authserver/Server/AuthSession.cpp') diff --git a/src/server/authserver/Main.cpp b/src/server/authserver/Main.cpp index c8be23ca524..27834f50814 100644 --- a/src/server/authserver/Main.cpp +++ b/src/server/authserver/Main.cpp @@ -67,28 +67,28 @@ using boost::asio::ip::tcp; void SignalHandler(const boost::system::error_code& error, int signalNumber) { - TC_LOG_ERROR("server.authserver", "SIGNAL HANDLER WORKING"); - if (!error) - { - switch (signalNumber) - { - case SIGINT: - case SIGTERM: - _ioService.stop(); - break; - } - } + TC_LOG_ERROR("server.authserver", "SIGNAL HANDLER WORKING"); + if (!error) + { + switch (signalNumber) + { + case SIGINT: + case SIGTERM: + _ioService.stop(); + break; + } + } } void KeepDatabaseAliveHandler(const boost::system::error_code& error) { - if (!error) - { - TC_LOG_INFO("server.authserver", "Ping MySQL to keep connection alive"); - LoginDatabase.KeepAlive(); + if (!error) + { + TC_LOG_INFO("server.authserver", "Ping MySQL to keep connection alive"); + LoginDatabase.KeepAlive(); - _dbPingTimer.expires_from_now(boost::posix_time::minutes(_dbPingInterval)); - } + _dbPingTimer.expires_from_now(boost::posix_time::minutes(_dbPingInterval)); + } } /// Print out the usage string for this program on the console. @@ -170,22 +170,22 @@ int main(int argc, char** argv) std::string bindIp = sConfigMgr->GetStringDefault("BindIP", "0.0.0.0"); - AuthServer authServer(_ioService, bindIp, port); + AuthServer authServer(_ioService, bindIp, port); - // Set signal handlers - boost::asio::signal_set signals(_ioService, SIGINT, SIGTERM); - signals.async_wait(SignalHandler); + // Set signal handlers + boost::asio::signal_set signals(_ioService, SIGINT, SIGTERM); + signals.async_wait(SignalHandler); - SetProcessPriority(); + SetProcessPriority(); - _dbPingInterval = sConfigMgr->GetIntDefault("MaxPingTime", 30); + _dbPingInterval = sConfigMgr->GetIntDefault("MaxPingTime", 30); - _dbPingTimer.expires_from_now(boost::posix_time::seconds(_dbPingInterval)); - _dbPingTimer.async_wait(KeepDatabaseAliveHandler); + _dbPingTimer.expires_from_now(boost::posix_time::seconds(_dbPingInterval)); + _dbPingTimer.async_wait(KeepDatabaseAliveHandler); - // Start the io service - _ioService.run(); + // Start the io service + _ioService.run(); // Close the Database Pool and library StopDB(); @@ -244,69 +244,69 @@ void SetProcessPriority() { #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); + ///- 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)) - TC_LOG_INFO("server.authserver", "Using processors (bitmask, hex): %x", currentAffinity); - else - TC_LOG_ERROR("server.authserver", "Can't set used processors (hex): %x", currentAffinity); - } - } - - if (highPriority) - { - if (SetPriorityClass(hProcess, HIGH_PRIORITY_CLASS)) - TC_LOG_INFO("server.authserver", "authserver process priority class set to HIGH"); - else - TC_LOG_ERROR("server.authserver", "Can't set authserver process priority class."); - } + 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)) + TC_LOG_INFO("server.authserver", "Using processors (bitmask, hex): %x", currentAffinity); + else + TC_LOG_ERROR("server.authserver", "Can't set used processors (hex): %x", currentAffinity); + } + } + + if (highPriority) + { + if (SetPriorityClass(hProcess, HIGH_PRIORITY_CLASS)) + TC_LOG_INFO("server.authserver", "authserver process priority class set to HIGH"); + else + TC_LOG_ERROR("server.authserver", "Can't set authserver process priority class."); + } #else // Linux - if (affinity > 0) - { - cpu_set_t mask; - CPU_ZERO(&mask); - - for (unsigned int i = 0; i < sizeof(affinity) * 8; ++i) - if (affinity & (1 << i)) - CPU_SET(i, &mask); - - if (sched_setaffinity(0, sizeof(mask), &mask)) - TC_LOG_ERROR("server.authserver", "Can't set used processors (hex): %x, error: %s", affinity, strerror(errno)); - else - { - CPU_ZERO(&mask); - sched_getaffinity(0, sizeof(mask), &mask); - TC_LOG_INFO("server.authserver", "Using processors (bitmask, hex): %lx", *(__cpu_mask*)(&mask)); - } - } - - if (highPriority) - { - if (setpriority(PRIO_PROCESS, 0, PROCESS_HIGH_PRIORITY)) - TC_LOG_ERROR("server.authserver", "Can't set authserver process priority class, error: %s", strerror(errno)); - else - TC_LOG_INFO("server.authserver", "authserver process priority class set to %i", getpriority(PRIO_PROCESS, 0)); - } + if (affinity > 0) + { + cpu_set_t mask; + CPU_ZERO(&mask); + + for (unsigned int i = 0; i < sizeof(affinity) * 8; ++i) + if (affinity & (1 << i)) + CPU_SET(i, &mask); + + if (sched_setaffinity(0, sizeof(mask), &mask)) + TC_LOG_ERROR("server.authserver", "Can't set used processors (hex): %x, error: %s", affinity, strerror(errno)); + else + { + CPU_ZERO(&mask); + sched_getaffinity(0, sizeof(mask), &mask); + TC_LOG_INFO("server.authserver", "Using processors (bitmask, hex): %lx", *(__cpu_mask*)(&mask)); + } + } + + if (highPriority) + { + if (setpriority(PRIO_PROCESS, 0, PROCESS_HIGH_PRIORITY)) + TC_LOG_ERROR("server.authserver", "Can't set authserver process priority class, error: %s", strerror(errno)); + else + TC_LOG_INFO("server.authserver", "authserver process priority class set to %i", getpriority(PRIO_PROCESS, 0)); + } #endif #endif -} \ No newline at end of file +} diff --git a/src/server/authserver/Realms/RealmList.h b/src/server/authserver/Realms/RealmList.h index 1d76c39e4f0..88da30ea963 100644 --- a/src/server/authserver/Realms/RealmList.h +++ b/src/server/authserver/Realms/RealmList.h @@ -26,15 +26,15 @@ enum RealmFlags { - REALM_FLAG_NONE = 0x00, - REALM_FLAG_INVALID = 0x01, - REALM_FLAG_OFFLINE = 0x02, - REALM_FLAG_SPECIFYBUILD = 0x04, - REALM_FLAG_UNK1 = 0x08, - REALM_FLAG_UNK2 = 0x10, - REALM_FLAG_RECOMMENDED = 0x20, - REALM_FLAG_NEW = 0x40, - REALM_FLAG_FULL = 0x80 + REALM_FLAG_NONE = 0x00, + REALM_FLAG_INVALID = 0x01, + REALM_FLAG_OFFLINE = 0x02, + REALM_FLAG_SPECIFYBUILD = 0x04, + REALM_FLAG_UNK1 = 0x08, + REALM_FLAG_UNK2 = 0x10, + REALM_FLAG_RECOMMENDED = 0x20, + REALM_FLAG_NEW = 0x40, + REALM_FLAG_FULL = 0x80 }; // Storage object for a realm @@ -73,7 +73,7 @@ public: uint32 size() const { return m_realms.size(); } private: - void UpdateRealms(bool init=false); + 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); RealmMap m_realms; diff --git a/src/server/authserver/Server/AuthServer.cpp b/src/server/authserver/Server/AuthServer.cpp index a699734be79..5c3ef247254 100644 --- a/src/server/authserver/Server/AuthServer.cpp +++ b/src/server/authserver/Server/AuthServer.cpp @@ -25,15 +25,15 @@ using boost::asio::ip::tcp; void AuthServer::AsyncAccept() { - _acceptor.async_accept(_socket, [this](boost::system::error_code error) - { - if (!error) - { - std::make_shared(std::move(_socket))->Start(); - } - - AsyncAccept(); - }); + _acceptor.async_accept(_socket, [this](boost::system::error_code error) + { + if (!error) + { + std::make_shared(std::move(_socket))->Start(); + } + + AsyncAccept(); + }); } diff --git a/src/server/authserver/Server/AuthServer.h b/src/server/authserver/Server/AuthServer.h index 0496326ee7b..985a48ad243 100644 --- a/src/server/authserver/Server/AuthServer.h +++ b/src/server/authserver/Server/AuthServer.h @@ -25,20 +25,20 @@ using boost::asio::ip::tcp; class AuthServer { public: - AuthServer(boost::asio::io_service& ioService, std::string bindIp, int port) : _socket(ioService), _acceptor(ioService, tcp::endpoint(tcp::v4(), port)) - { - tcp::endpoint endpoint(boost::asio::ip::address::from_string(bindIp), port); + AuthServer(boost::asio::io_service& ioService, std::string bindIp, int port) : _socket(ioService), _acceptor(ioService, tcp::endpoint(tcp::v4(), port)) + { + tcp::endpoint endpoint(boost::asio::ip::address::from_string(bindIp), port); - _acceptor = tcp::acceptor(ioService, endpoint); + _acceptor = tcp::acceptor(ioService, endpoint); - AsyncAccept(); - }; + AsyncAccept(); + }; private: - void AsyncAccept(); + void AsyncAccept(); - tcp::acceptor _acceptor; - tcp::socket _socket; + tcp::acceptor _acceptor; + tcp::socket _socket; }; #endif /* __AUTHSERVER_H__ */ diff --git a/src/server/authserver/Server/AuthSession.cpp b/src/server/authserver/Server/AuthSession.cpp index cb78336f2d3..6a3c145d08b 100644 --- a/src/server/authserver/Server/AuthSession.cpp +++ b/src/server/authserver/Server/AuthSession.cpp @@ -32,80 +32,80 @@ using boost::asio::ip::tcp; enum eAuthCmd { - AUTH_LOGON_CHALLENGE = 0x00, - AUTH_LOGON_PROOF = 0x01, - AUTH_RECONNECT_CHALLENGE = 0x02, - AUTH_RECONNECT_PROOF = 0x03, - REALM_LIST = 0x10, - XFER_INITIATE = 0x30, - XFER_DATA = 0x31, - XFER_ACCEPT = 0x32, - XFER_RESUME = 0x33, - XFER_CANCEL = 0x34 + AUTH_LOGON_CHALLENGE = 0x00, + AUTH_LOGON_PROOF = 0x01, + AUTH_RECONNECT_CHALLENGE = 0x02, + AUTH_RECONNECT_PROOF = 0x03, + REALM_LIST = 0x10, + XFER_INITIATE = 0x30, + XFER_DATA = 0x31, + XFER_ACCEPT = 0x32, + XFER_RESUME = 0x33, + XFER_CANCEL = 0x34 }; enum eStatus { - STATUS_CONNECTED = 0, - STATUS_AUTHED + STATUS_CONNECTED = 0, + STATUS_AUTHED }; #pragma pack(push, 1) typedef struct AUTH_LOGON_CHALLENGE_C { - uint8 cmd; - uint8 error; - uint16 size; - uint8 gamename[4]; - uint8 version1; - uint8 version2; - uint8 version3; - uint16 build; - uint8 platform[4]; - uint8 os[4]; - uint8 country[4]; - uint32 timezone_bias; - uint32 ip; - uint8 I_len; - uint8 I[1]; + uint8 cmd; + uint8 error; + uint16 size; + uint8 gamename[4]; + uint8 version1; + uint8 version2; + uint8 version3; + uint16 build; + uint8 platform[4]; + uint8 os[4]; + uint8 country[4]; + uint32 timezone_bias; + uint32 ip; + uint8 I_len; + uint8 I[1]; } sAuthLogonChallenge_C; typedef struct AUTH_LOGON_PROOF_C { - uint8 cmd; - uint8 A[32]; - uint8 M1[20]; - uint8 crc_hash[20]; - uint8 number_of_keys; - uint8 securityFlags; + uint8 cmd; + uint8 A[32]; + uint8 M1[20]; + uint8 crc_hash[20]; + uint8 number_of_keys; + uint8 securityFlags; } sAuthLogonProof_C; typedef struct AUTH_LOGON_PROOF_S { - uint8 cmd; - uint8 error; - uint8 M2[20]; - uint32 unk1; - uint32 unk2; - uint16 unk3; + uint8 cmd; + uint8 error; + uint8 M2[20]; + uint32 unk1; + uint32 unk2; + uint16 unk3; } sAuthLogonProof_S; typedef struct AUTH_LOGON_PROOF_S_OLD { - uint8 cmd; - uint8 error; - uint8 M2[20]; - uint32 unk2; + uint8 cmd; + uint8 error; + uint8 M2[20]; + uint32 unk2; } sAuthLogonProof_S_Old; typedef struct AUTH_RECONNECT_PROOF_C { - uint8 cmd; - uint8 R1[16]; - uint8 R2[20]; - uint8 R3[20]; - uint8 number_of_keys; + uint8 cmd; + uint8 R1[16]; + uint8 R2[20]; + uint8 R3[20]; + uint8 number_of_keys; } sAuthReconnectProof_C; #pragma pack(pop) @@ -113,10 +113,10 @@ typedef struct AUTH_RECONNECT_PROOF_C typedef struct AuthHandler { - eAuthCmd cmd; - uint32 status; - size_t packetSize; - bool (AuthSession::*handler)(); + eAuthCmd cmd; + uint32 status; + size_t packetSize; + bool (AuthSession::*handler)(); } AuthHandler; #define BYTE_SIZE 32 @@ -124,792 +124,792 @@ typedef struct AuthHandler const AuthHandler table[] = { - { AUTH_LOGON_CHALLENGE, STATUS_CONNECTED, sizeof(AUTH_LOGON_CHALLENGE_C), &AuthSession::_HandleLogonChallenge }, - { AUTH_LOGON_PROOF, STATUS_CONNECTED, sizeof(AUTH_LOGON_PROOF_C), &AuthSession::_HandleLogonProof }, - { AUTH_RECONNECT_CHALLENGE, STATUS_CONNECTED, sizeof(AUTH_LOGON_CHALLENGE_C), &AuthSession::_HandleReconnectChallenge }, - { AUTH_RECONNECT_PROOF, STATUS_CONNECTED, sizeof(AUTH_RECONNECT_PROOF_C), &AuthSession::_HandleReconnectProof }, - { REALM_LIST, STATUS_AUTHED, REALMLIST_SKIP_PACKETS, &AuthSession::_HandleRealmList } + { AUTH_LOGON_CHALLENGE, STATUS_CONNECTED, sizeof(AUTH_LOGON_CHALLENGE_C), &AuthSession::_HandleLogonChallenge }, + { AUTH_LOGON_PROOF, STATUS_CONNECTED, sizeof(AUTH_LOGON_PROOF_C), &AuthSession::_HandleLogonProof }, + { AUTH_RECONNECT_CHALLENGE, STATUS_CONNECTED, sizeof(AUTH_LOGON_CHALLENGE_C), &AuthSession::_HandleReconnectChallenge }, + { AUTH_RECONNECT_PROOF, STATUS_CONNECTED, sizeof(AUTH_RECONNECT_PROOF_C), &AuthSession::_HandleReconnectProof }, + { REALM_LIST, STATUS_AUTHED, REALMLIST_SKIP_PACKETS, &AuthSession::_HandleRealmList } }; void AuthSession::AsyncReadHeader() { - auto self(shared_from_this()); - - _socket.async_read_some(boost::asio::buffer(_readBuffer, 1), [this, self](boost::system::error_code error, size_t transferedBytes) - { - if (!error && transferedBytes == 1) - { - for (const AuthHandler& entry : table) - { - if ((uint8)entry.cmd == _readBuffer[0] && (entry.status == STATUS_CONNECTED || (_isAuthenticated && entry.status == STATUS_AUTHED))) - { - // Handle dynamic size packet - if (_readBuffer[0] == AUTH_LOGON_CHALLENGE) - { - _socket.read_some(boost::asio::buffer(&_readBuffer[1], sizeof(uint8) + sizeof(uint16))); //error + size - - AsyncReadData(entry.handler, (uint16)&_readBuffer[2], sizeof(uint8) + sizeof(uint8) + sizeof(uint16)); // cmd + error + size - } - else - { - AsyncReadData(entry.handler, entry.packetSize, sizeof(uint8)); - } - break; - } - } - } - else - { - _socket.close(); - } - }); + auto self(shared_from_this()); + + _socket.async_read_some(boost::asio::buffer(_readBuffer, 1), [this, self](boost::system::error_code error, size_t transferedBytes) + { + if (!error && transferedBytes == 1) + { + for (const AuthHandler& entry : table) + { + if ((uint8)entry.cmd == _readBuffer[0] && (entry.status == STATUS_CONNECTED || (_isAuthenticated && entry.status == STATUS_AUTHED))) + { + // Handle dynamic size packet + if (_readBuffer[0] == AUTH_LOGON_CHALLENGE) + { + _socket.read_some(boost::asio::buffer(&_readBuffer[1], sizeof(uint8) + sizeof(uint16))); //error + size + + AsyncReadData(entry.handler, (uint16)&_readBuffer[2], sizeof(uint8) + sizeof(uint8) + sizeof(uint16)); // cmd + error + size + } + else + { + AsyncReadData(entry.handler, entry.packetSize, sizeof(uint8)); + } + break; + } + } + } + else + { + _socket.close(); + } + }); } void AuthSession::AsyncReadData(bool (AuthSession::*handler)(), size_t dataSize, size_t bufferOffSet) { - auto self(shared_from_this()); - - _socket.async_read_some(boost::asio::buffer(&_readBuffer[bufferOffSet], dataSize), [handler, this, self](boost::system::error_code error, size_t transferedBytes) - { - if (!error && transferedBytes > 0) - { - if (!(*this.*handler)()) - { - _socket.close(); - return; - } - - AsyncReadHeader(); - } - else - { - _socket.close(); - } - }); + auto self(shared_from_this()); + + _socket.async_read_some(boost::asio::buffer(&_readBuffer[bufferOffSet], dataSize), [handler, this, self](boost::system::error_code error, size_t transferedBytes) + { + if (!error && transferedBytes > 0) + { + if (!(*this.*handler)()) + { + _socket.close(); + return; + } + + AsyncReadHeader(); + } + else + { + _socket.close(); + } + }); } void AuthSession::AsyncWrite(std::size_t length) { - boost::asio::async_write(_socket, boost::asio::buffer(_writeBuffer, length), [this](boost::system::error_code error, std::size_t /*length*/) - { - if (error) - { - _socket.close(); - } - }); + boost::asio::async_write(_socket, boost::asio::buffer(_writeBuffer, length), [this](boost::system::error_code error, std::size_t /*length*/) + { + if (error) + { + _socket.close(); + } + }); } bool AuthSession::_HandleLogonChallenge() { - sAuthLogonChallenge_C *challenge = (sAuthLogonChallenge_C*)&_readBuffer; - - //TC_LOG_DEBUG("server.authserver", "[AuthChallenge] got full packet, %#04x bytes", challenge->size); - TC_LOG_DEBUG("server.authserver", "[AuthChallenge] name(%d): '%s'", challenge->I_len, challenge->I); - - ByteBuffer pkt; - - _login.assign((const char*)challenge->I, challenge->I_len); - _build = challenge->build; - _expversion = uint8(AuthHelper::IsPostBCAcceptedClientBuild(_build) ? POST_BC_EXP_FLAG : (AuthHelper::IsPreBCAcceptedClientBuild(_build) ? PRE_BC_EXP_FLAG : NO_VALID_EXP_FLAG)); - _os = (const char*)challenge->os; - - if (_os.size() > 4) - return false; - - // Restore string order as its byte order is reversed - std::reverse(_os.begin(), _os.end()); - - pkt << uint8(AUTH_LOGON_CHALLENGE); - pkt << uint8(0x00); - - // Verify that this IP is not in the ip_banned table - LoginDatabase.Execute(LoginDatabase.GetPreparedStatement(LOGIN_DEL_EXPIRED_IP_BANS)); - - std::string const& ipAddress = _socket.remote_endpoint().address().to_string(); - unsigned short port = _socket.remote_endpoint().port(); - - PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_IP_BANNED); - stmt->setString(0, ipAddress); - PreparedQueryResult result = LoginDatabase.Query(stmt); - if (result) - { - pkt << uint8(WOW_FAIL_BANNED); - TC_LOG_DEBUG("server.authserver", "'%s:%d' [AuthChallenge] Banned ip tries to login!", ipAddress.c_str(), port); - } - else - { - // Get the account details from the account table - // No SQL injection (prepared statement) - stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_LOGONCHALLENGE); - stmt->setString(0, _login); - - PreparedQueryResult res2 = LoginDatabase.Query(stmt); - if (res2) - { - Field* fields = res2->Fetch(); - - // If the IP is 'locked', check that the player comes indeed from the correct IP address - bool locked = false; - if (fields[2].GetUInt8() == 1) // if ip is locked - { - TC_LOG_DEBUG("server.authserver", "[AuthChallenge] Account '%s' is locked to IP - '%s'", _login.c_str(), fields[4].GetCString()); - TC_LOG_DEBUG("server.authserver", "[AuthChallenge] Player address is '%s'", ipAddress.c_str()); - - if (strcmp(fields[4].GetCString(), ipAddress.c_str()) != 0) - { - TC_LOG_DEBUG("server.authserver", "[AuthChallenge] Account IP differs"); - pkt << uint8(WOW_FAIL_LOCKED_ENFORCED); - locked = true; - } - else - TC_LOG_DEBUG("server.authserver", "[AuthChallenge] Account IP matches"); - } - else - { - TC_LOG_DEBUG("server.authserver", "[AuthChallenge] Account '%s' is not locked to ip", _login.c_str()); - std::string accountCountry = fields[3].GetString(); - if (accountCountry.empty() || accountCountry == "00") - TC_LOG_DEBUG("server.authserver", "[AuthChallenge] Account '%s' is not locked to country", _login.c_str()); - else if (!accountCountry.empty()) - { - uint32 ip = inet_addr(ipAddress.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.authserver", "[AuthChallenge] Account '%s' is locked to country: '%s' Player country is '%s'", _login.c_str(), - accountCountry.c_str(), loginCountry.c_str()); - - if (loginCountry != accountCountry) - { - TC_LOG_DEBUG("server.authserver", "[AuthChallenge] Account country differs."); - pkt << uint8(WOW_FAIL_UNLOCKABLE_LOCK); - locked = true; - } - else - TC_LOG_DEBUG("server.authserver", "[AuthChallenge] Account country matches"); - } - else - TC_LOG_DEBUG("server.authserver", "[AuthChallenge] IP2NATION Table empty"); - } - } - - if (!locked) - { - //set expired bans to inactive - LoginDatabase.DirectExecute(LoginDatabase.GetPreparedStatement(LOGIN_UPD_EXPIRED_ACCOUNT_BANS)); - - // If the account is banned, reject the logon attempt - stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_ACCOUNT_BANNED); - stmt->setUInt32(0, fields[1].GetUInt32()); - PreparedQueryResult banresult = LoginDatabase.Query(stmt); - if (banresult) - { - if ((*banresult)[0].GetUInt32() == (*banresult)[1].GetUInt32()) - { - pkt << uint8(WOW_FAIL_BANNED); - TC_LOG_DEBUG("server.authserver", "'%s:%d' [AuthChallenge] Banned account %s tried to login!", ipAddress.c_str(), - port, _login.c_str()); - } - else - { - pkt << uint8(WOW_FAIL_SUSPENDED); - TC_LOG_DEBUG("server.authserver", "'%s:%d' [AuthChallenge] Temporarily banned account %s tried to login!", - ipAddress.c_str(), port, _login.c_str()); - } - } - else - { - // Get the password from the account table, upper it, and make the SRP6 calculation - std::string rI = fields[0].GetString(); - - // Don't calculate (v, s) if there are already some in the database - std::string databaseV = fields[6].GetString(); - std::string databaseS = fields[7].GetString(); - - TC_LOG_DEBUG("network", "database authentication values: v='%s' s='%s'", databaseV.c_str(), databaseS.c_str()); - - // multiply with 2 since bytes are stored as hexstring - if (databaseV.size() != BYTE_SIZE * 2 || databaseS.size() != BYTE_SIZE * 2) - SetVSFields(rI); - else - { - s.SetHexStr(databaseS.c_str()); - v.SetHexStr(databaseV.c_str()); - } - - b.SetRand(19 * 8); - BigNumber gmod = g.ModExp(b, N); - B = ((v * 3) + gmod) % N; - - ASSERT(gmod.GetNumBytes() <= 32); - - BigNumber unk3; - unk3.SetRand(16 * 8); - - // Fill the response packet with the result - if (AuthHelper::IsAcceptedClientBuild(_build)) - pkt << uint8(WOW_SUCCESS); - else - pkt << uint8(WOW_FAIL_VERSION_INVALID); - - // B may be calculated < 32B so we force minimal length to 32B - pkt.append(B.AsByteArray(32).get(), 32); // 32 bytes - pkt << uint8(1); - pkt.append(g.AsByteArray().get(), 1); - pkt << uint8(32); - pkt.append(N.AsByteArray(32).get(), 32); - pkt.append(s.AsByteArray().get(), s.GetNumBytes()); // 32 bytes - pkt.append(unk3.AsByteArray(16).get(), 16); - uint8 securityFlags = 0; - - // Check if token is used - _tokenKey = fields[8].GetString(); - if (!_tokenKey.empty()) - securityFlags = 4; - - pkt << uint8(securityFlags); // security flags (0x0...0x04) - - if (securityFlags & 0x01) // PIN input - { - pkt << uint32(0); - pkt << uint64(0) << uint64(0); // 16 bytes hash? - } - - if (securityFlags & 0x02) // Matrix input - { - pkt << uint8(0); - pkt << uint8(0); - pkt << uint8(0); - pkt << uint8(0); - pkt << uint64(0); - } - - if (securityFlags & 0x04) // Security token input - pkt << uint8(1); - - uint8 secLevel = fields[5].GetUInt8(); - _accountSecurityLevel = secLevel <= SEC_ADMINISTRATOR ? AccountTypes(secLevel) : SEC_ADMINISTRATOR; - - _localizationName.resize(4); - for (int i = 0; i < 4; ++i) - _localizationName[i] = challenge->country[4 - i - 1]; - - TC_LOG_DEBUG("server.authserver", "'%s:%d' [AuthChallenge] account %s is using '%c%c%c%c' locale (%u)", - ipAddress.c_str(), port, _login.c_str(), - challenge->country[3], challenge->country[2], challenge->country[1], challenge->country[0], - GetLocaleByName(_localizationName) - ); - } - } - } - else //no account - pkt << uint8(WOW_FAIL_UNKNOWN_ACCOUNT); - } - - std::memcpy(_writeBuffer, (char const*)pkt.contents(), pkt.size()); - - AsyncWrite(pkt.size()); - - return true; + sAuthLogonChallenge_C *challenge = (sAuthLogonChallenge_C*)&_readBuffer; + + //TC_LOG_DEBUG("server.authserver", "[AuthChallenge] got full packet, %#04x bytes", challenge->size); + TC_LOG_DEBUG("server.authserver", "[AuthChallenge] name(%d): '%s'", challenge->I_len, challenge->I); + + ByteBuffer pkt; + + _login.assign((const char*)challenge->I, challenge->I_len); + _build = challenge->build; + _expversion = uint8(AuthHelper::IsPostBCAcceptedClientBuild(_build) ? POST_BC_EXP_FLAG : (AuthHelper::IsPreBCAcceptedClientBuild(_build) ? PRE_BC_EXP_FLAG : NO_VALID_EXP_FLAG)); + _os = (const char*)challenge->os; + + if (_os.size() > 4) + return false; + + // Restore string order as its byte order is reversed + std::reverse(_os.begin(), _os.end()); + + pkt << uint8(AUTH_LOGON_CHALLENGE); + pkt << uint8(0x00); + + // Verify that this IP is not in the ip_banned table + LoginDatabase.Execute(LoginDatabase.GetPreparedStatement(LOGIN_DEL_EXPIRED_IP_BANS)); + + std::string const& ipAddress = _socket.remote_endpoint().address().to_string(); + unsigned short port = _socket.remote_endpoint().port(); + + PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_IP_BANNED); + stmt->setString(0, ipAddress); + PreparedQueryResult result = LoginDatabase.Query(stmt); + if (result) + { + pkt << uint8(WOW_FAIL_BANNED); + TC_LOG_DEBUG("server.authserver", "'%s:%d' [AuthChallenge] Banned ip tries to login!", ipAddress.c_str(), port); + } + else + { + // Get the account details from the account table + // No SQL injection (prepared statement) + stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_LOGONCHALLENGE); + stmt->setString(0, _login); + + PreparedQueryResult res2 = LoginDatabase.Query(stmt); + if (res2) + { + Field* fields = res2->Fetch(); + + // If the IP is 'locked', check that the player comes indeed from the correct IP address + bool locked = false; + if (fields[2].GetUInt8() == 1) // if ip is locked + { + TC_LOG_DEBUG("server.authserver", "[AuthChallenge] Account '%s' is locked to IP - '%s'", _login.c_str(), fields[4].GetCString()); + TC_LOG_DEBUG("server.authserver", "[AuthChallenge] Player address is '%s'", ipAddress.c_str()); + + if (strcmp(fields[4].GetCString(), ipAddress.c_str()) != 0) + { + TC_LOG_DEBUG("server.authserver", "[AuthChallenge] Account IP differs"); + pkt << uint8(WOW_FAIL_LOCKED_ENFORCED); + locked = true; + } + else + TC_LOG_DEBUG("server.authserver", "[AuthChallenge] Account IP matches"); + } + else + { + TC_LOG_DEBUG("server.authserver", "[AuthChallenge] Account '%s' is not locked to ip", _login.c_str()); + std::string accountCountry = fields[3].GetString(); + if (accountCountry.empty() || accountCountry == "00") + TC_LOG_DEBUG("server.authserver", "[AuthChallenge] Account '%s' is not locked to country", _login.c_str()); + else if (!accountCountry.empty()) + { + uint32 ip = inet_addr(ipAddress.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.authserver", "[AuthChallenge] Account '%s' is locked to country: '%s' Player country is '%s'", _login.c_str(), + accountCountry.c_str(), loginCountry.c_str()); + + if (loginCountry != accountCountry) + { + TC_LOG_DEBUG("server.authserver", "[AuthChallenge] Account country differs."); + pkt << uint8(WOW_FAIL_UNLOCKABLE_LOCK); + locked = true; + } + else + TC_LOG_DEBUG("server.authserver", "[AuthChallenge] Account country matches"); + } + else + TC_LOG_DEBUG("server.authserver", "[AuthChallenge] IP2NATION Table empty"); + } + } + + if (!locked) + { + //set expired bans to inactive + LoginDatabase.DirectExecute(LoginDatabase.GetPreparedStatement(LOGIN_UPD_EXPIRED_ACCOUNT_BANS)); + + // If the account is banned, reject the logon attempt + stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_ACCOUNT_BANNED); + stmt->setUInt32(0, fields[1].GetUInt32()); + PreparedQueryResult banresult = LoginDatabase.Query(stmt); + if (banresult) + { + if ((*banresult)[0].GetUInt32() == (*banresult)[1].GetUInt32()) + { + pkt << uint8(WOW_FAIL_BANNED); + TC_LOG_DEBUG("server.authserver", "'%s:%d' [AuthChallenge] Banned account %s tried to login!", ipAddress.c_str(), + port, _login.c_str()); + } + else + { + pkt << uint8(WOW_FAIL_SUSPENDED); + TC_LOG_DEBUG("server.authserver", "'%s:%d' [AuthChallenge] Temporarily banned account %s tried to login!", + ipAddress.c_str(), port, _login.c_str()); + } + } + else + { + // Get the password from the account table, upper it, and make the SRP6 calculation + std::string rI = fields[0].GetString(); + + // Don't calculate (v, s) if there are already some in the database + std::string databaseV = fields[6].GetString(); + std::string databaseS = fields[7].GetString(); + + TC_LOG_DEBUG("network", "database authentication values: v='%s' s='%s'", databaseV.c_str(), databaseS.c_str()); + + // multiply with 2 since bytes are stored as hexstring + if (databaseV.size() != BYTE_SIZE * 2 || databaseS.size() != BYTE_SIZE * 2) + SetVSFields(rI); + else + { + s.SetHexStr(databaseS.c_str()); + v.SetHexStr(databaseV.c_str()); + } + + b.SetRand(19 * 8); + BigNumber gmod = g.ModExp(b, N); + B = ((v * 3) + gmod) % N; + + ASSERT(gmod.GetNumBytes() <= 32); + + BigNumber unk3; + unk3.SetRand(16 * 8); + + // Fill the response packet with the result + if (AuthHelper::IsAcceptedClientBuild(_build)) + pkt << uint8(WOW_SUCCESS); + else + pkt << uint8(WOW_FAIL_VERSION_INVALID); + + // B may be calculated < 32B so we force minimal length to 32B + pkt.append(B.AsByteArray(32).get(), 32); // 32 bytes + pkt << uint8(1); + pkt.append(g.AsByteArray().get(), 1); + pkt << uint8(32); + pkt.append(N.AsByteArray(32).get(), 32); + pkt.append(s.AsByteArray().get(), s.GetNumBytes()); // 32 bytes + pkt.append(unk3.AsByteArray(16).get(), 16); + uint8 securityFlags = 0; + + // Check if token is used + _tokenKey = fields[8].GetString(); + if (!_tokenKey.empty()) + securityFlags = 4; + + pkt << uint8(securityFlags); // security flags (0x0...0x04) + + if (securityFlags & 0x01) // PIN input + { + pkt << uint32(0); + pkt << uint64(0) << uint64(0); // 16 bytes hash? + } + + if (securityFlags & 0x02) // Matrix input + { + pkt << uint8(0); + pkt << uint8(0); + pkt << uint8(0); + pkt << uint8(0); + pkt << uint64(0); + } + + if (securityFlags & 0x04) // Security token input + pkt << uint8(1); + + uint8 secLevel = fields[5].GetUInt8(); + _accountSecurityLevel = secLevel <= SEC_ADMINISTRATOR ? AccountTypes(secLevel) : SEC_ADMINISTRATOR; + + _localizationName.resize(4); + for (int i = 0; i < 4; ++i) + _localizationName[i] = challenge->country[4 - i - 1]; + + TC_LOG_DEBUG("server.authserver", "'%s:%d' [AuthChallenge] account %s is using '%c%c%c%c' locale (%u)", + ipAddress.c_str(), port, _login.c_str(), + challenge->country[3], challenge->country[2], challenge->country[1], challenge->country[0], + GetLocaleByName(_localizationName) + ); + } + } + } + else //no account + pkt << uint8(WOW_FAIL_UNKNOWN_ACCOUNT); + } + + std::memcpy(_writeBuffer, (char const*)pkt.contents(), pkt.size()); + + AsyncWrite(pkt.size()); + + return true; } // Logon Proof command handler bool AuthSession::_HandleLogonProof() { - TC_LOG_DEBUG("server.authserver", "Entering _HandleLogonProof"); - // Read the packet - sAuthLogonProof_C *logonProof = (sAuthLogonProof_C*)&_readBuffer; - - // If the client has no valid version - if (_expversion == NO_VALID_EXP_FLAG) - { - // Check if we have the appropriate patch on the disk - TC_LOG_DEBUG("network", "Client with invalid version, patching is not implemented"); - return false; - } - - // Continue the SRP6 calculation based on data received from the client - BigNumber A; - - A.SetBinary(logonProof->A, 32); - - // SRP safeguard: abort if A == 0 - if (A.isZero()) - { - return false; - } - - SHA1Hash sha; - sha.UpdateBigNumbers(&A, &B, NULL); - sha.Finalize(); - BigNumber u; - u.SetBinary(sha.GetDigest(), 20); - BigNumber S = (A * (v.ModExp(u, N))).ModExp(b, N); - - uint8 t[32]; - uint8 t1[16]; - uint8 vK[40]; - memcpy(t, S.AsByteArray(32).get(), 32); - - for (int i = 0; i < 16; ++i) - t1[i] = t[i * 2]; - - sha.Initialize(); - sha.UpdateData(t1, 16); - sha.Finalize(); - - for (int i = 0; i < 20; ++i) - vK[i * 2] = sha.GetDigest()[i]; - - for (int i = 0; i < 16; ++i) - t1[i] = t[i * 2 + 1]; - - sha.Initialize(); - sha.UpdateData(t1, 16); - sha.Finalize(); - - for (int i = 0; i < 20; ++i) - vK[i * 2 + 1] = sha.GetDigest()[i]; - - K.SetBinary(vK, 40); - - uint8 hash[20]; - - sha.Initialize(); - sha.UpdateBigNumbers(&N, NULL); - sha.Finalize(); - memcpy(hash, sha.GetDigest(), 20); - sha.Initialize(); - sha.UpdateBigNumbers(&g, NULL); - sha.Finalize(); - - for (int i = 0; i < 20; ++i) - hash[i] ^= sha.GetDigest()[i]; - - BigNumber t3; - t3.SetBinary(hash, 20); - - sha.Initialize(); - sha.UpdateData(_login); - sha.Finalize(); - uint8 t4[SHA_DIGEST_LENGTH]; - memcpy(t4, sha.GetDigest(), SHA_DIGEST_LENGTH); - - sha.Initialize(); - sha.UpdateBigNumbers(&t3, NULL); - sha.UpdateData(t4, SHA_DIGEST_LENGTH); - sha.UpdateBigNumbers(&s, &A, &B, &K, NULL); - sha.Finalize(); - BigNumber M; - M.SetBinary(sha.GetDigest(), 20); - - // Check if SRP6 results match (password is correct), else send an error - if (!memcmp(M.AsByteArray().get(), logonProof->M1, 20)) - { - TC_LOG_DEBUG("server.authserver", "'%s:%d' User '%s' successfully authenticated", GetRemoteIpAddress().c_str(), 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(1, GetRemoteIpAddress().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); - sha.Finalize(); - - // Check auth token - if ((logonProof->securityFlags & 0x04) || !_tokenKey.empty()) - { - // TODO To be fixed - - /* - uint8 size; - socket().recv((char*)&size, 1); - char* token = new char[size + 1]; - token[size] = '\0'; - socket().recv(token, size); - unsigned int validToken = TOTP::GenerateToken(_tokenKey.c_str()); - unsigned int incomingToken = atoi(token); - delete[] token; - if (validToken != incomingToken) - { - char data[] = { AUTH_LOGON_PROOF, WOW_FAIL_UNKNOWN_ACCOUNT, 3, 0 }; - socket().send(data, sizeof(data)); - return false; - }*/ - } - - if (_expversion & POST_BC_EXP_FLAG) // 2.x and 3.x clients - { - sAuthLogonProof_S proof; - 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.unk2 = 0x00; // SurveyId - proof.unk3 = 0x00; - - std::memcpy(_writeBuffer, (char *)&proof, sizeof(proof)); - AsyncWrite(sizeof(proof)); - } - else - { - sAuthLogonProof_S_Old proof; - memcpy(proof.M2, sha.GetDigest(), 20); - proof.cmd = AUTH_LOGON_PROOF; - proof.error = 0; - proof.unk2 = 0x00; - - std::memcpy(_writeBuffer, (char *)&proof, sizeof(proof)); - AsyncWrite(sizeof(proof)); - } - - _isAuthenticated = true; - } - else - { - char data[4] = { AUTH_LOGON_PROOF, WOW_FAIL_UNKNOWN_ACCOUNT, 3, 0 }; - - std::memcpy(_writeBuffer, data, sizeof(data)); - AsyncWrite(sizeof(data)); - - TC_LOG_DEBUG("server.authserver", "'%s:%d' [AuthChallenge] account %s tried to login with invalid password!", - GetRemoteIpAddress().c_str(), GetRemotePort(), _login.c_str()); - - uint32 MaxWrongPassCount = sConfigMgr->GetIntDefault("WrongPass.MaxCount", 0); - if (MaxWrongPassCount > 0) - { - //Increment number of failed logins by one and if it reaches the limit temporarily ban that account or IP - PreparedStatement *stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_FAILEDLOGINS); - stmt->setString(0, _login); - LoginDatabase.Execute(stmt); - - stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_FAILEDLOGINS); - stmt->setString(0, _login); - - if (PreparedQueryResult loginfail = LoginDatabase.Query(stmt)) - { - uint32 failed_logins = (*loginfail)[1].GetUInt32(); - - if (failed_logins >= MaxWrongPassCount) - { - uint32 WrongPassBanTime = sConfigMgr->GetIntDefault("WrongPass.BanTime", 600); - bool WrongPassBanType = sConfigMgr->GetBoolDefault("WrongPass.BanType", false); - - if (WrongPassBanType) - { - uint32 acc_id = (*loginfail)[0].GetUInt32(); - stmt = LoginDatabase.GetPreparedStatement(LOGIN_INS_ACCOUNT_AUTO_BANNED); - stmt->setUInt32(0, acc_id); - stmt->setUInt32(1, WrongPassBanTime); - LoginDatabase.Execute(stmt); - - TC_LOG_DEBUG("server.authserver", "'%s:%d' [AuthChallenge] account %s got banned for '%u' seconds because it failed to authenticate '%u' times", - GetRemoteIpAddress().c_str(), GetRemotePort(), _login.c_str(), WrongPassBanTime, failed_logins); - } - else - { - stmt = LoginDatabase.GetPreparedStatement(LOGIN_INS_IP_AUTO_BANNED); - stmt->setString(0, GetRemoteIpAddress()); - stmt->setUInt32(1, WrongPassBanTime); - LoginDatabase.Execute(stmt); - - TC_LOG_DEBUG("server.authserver", "'%s:%d' [AuthChallenge] IP got banned for '%u' seconds because account %s failed to authenticate '%u' times", - GetRemoteIpAddress().c_str(), GetRemotePort(), WrongPassBanTime, _login.c_str(), failed_logins); - } - } - } - } - } - - return true; + TC_LOG_DEBUG("server.authserver", "Entering _HandleLogonProof"); + // Read the packet + sAuthLogonProof_C *logonProof = (sAuthLogonProof_C*)&_readBuffer; + + // If the client has no valid version + if (_expversion == NO_VALID_EXP_FLAG) + { + // Check if we have the appropriate patch on the disk + TC_LOG_DEBUG("network", "Client with invalid version, patching is not implemented"); + return false; + } + + // Continue the SRP6 calculation based on data received from the client + BigNumber A; + + A.SetBinary(logonProof->A, 32); + + // SRP safeguard: abort if A == 0 + if (A.isZero()) + { + return false; + } + + SHA1Hash sha; + sha.UpdateBigNumbers(&A, &B, NULL); + sha.Finalize(); + BigNumber u; + u.SetBinary(sha.GetDigest(), 20); + BigNumber S = (A * (v.ModExp(u, N))).ModExp(b, N); + + uint8 t[32]; + uint8 t1[16]; + uint8 vK[40]; + memcpy(t, S.AsByteArray(32).get(), 32); + + for (int i = 0; i < 16; ++i) + t1[i] = t[i * 2]; + + sha.Initialize(); + sha.UpdateData(t1, 16); + sha.Finalize(); + + for (int i = 0; i < 20; ++i) + vK[i * 2] = sha.GetDigest()[i]; + + for (int i = 0; i < 16; ++i) + t1[i] = t[i * 2 + 1]; + + sha.Initialize(); + sha.UpdateData(t1, 16); + sha.Finalize(); + + for (int i = 0; i < 20; ++i) + vK[i * 2 + 1] = sha.GetDigest()[i]; + + K.SetBinary(vK, 40); + + uint8 hash[20]; + + sha.Initialize(); + sha.UpdateBigNumbers(&N, NULL); + sha.Finalize(); + memcpy(hash, sha.GetDigest(), 20); + sha.Initialize(); + sha.UpdateBigNumbers(&g, NULL); + sha.Finalize(); + + for (int i = 0; i < 20; ++i) + hash[i] ^= sha.GetDigest()[i]; + + BigNumber t3; + t3.SetBinary(hash, 20); + + sha.Initialize(); + sha.UpdateData(_login); + sha.Finalize(); + uint8 t4[SHA_DIGEST_LENGTH]; + memcpy(t4, sha.GetDigest(), SHA_DIGEST_LENGTH); + + sha.Initialize(); + sha.UpdateBigNumbers(&t3, NULL); + sha.UpdateData(t4, SHA_DIGEST_LENGTH); + sha.UpdateBigNumbers(&s, &A, &B, &K, NULL); + sha.Finalize(); + BigNumber M; + M.SetBinary(sha.GetDigest(), 20); + + // Check if SRP6 results match (password is correct), else send an error + if (!memcmp(M.AsByteArray().get(), logonProof->M1, 20)) + { + TC_LOG_DEBUG("server.authserver", "'%s:%d' User '%s' successfully authenticated", GetRemoteIpAddress().c_str(), 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(1, GetRemoteIpAddress().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); + sha.Finalize(); + + // Check auth token + if ((logonProof->securityFlags & 0x04) || !_tokenKey.empty()) + { + // TODO To be fixed + + /* + uint8 size; + socket().recv((char*)&size, 1); + char* token = new char[size + 1]; + token[size] = '\0'; + socket().recv(token, size); + unsigned int validToken = TOTP::GenerateToken(_tokenKey.c_str()); + unsigned int incomingToken = atoi(token); + delete[] token; + if (validToken != incomingToken) + { + char data[] = { AUTH_LOGON_PROOF, WOW_FAIL_UNKNOWN_ACCOUNT, 3, 0 }; + socket().send(data, sizeof(data)); + return false; + }*/ + } + + if (_expversion & POST_BC_EXP_FLAG) // 2.x and 3.x clients + { + sAuthLogonProof_S proof; + 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.unk2 = 0x00; // SurveyId + proof.unk3 = 0x00; + + std::memcpy(_writeBuffer, (char *)&proof, sizeof(proof)); + AsyncWrite(sizeof(proof)); + } + else + { + sAuthLogonProof_S_Old proof; + memcpy(proof.M2, sha.GetDigest(), 20); + proof.cmd = AUTH_LOGON_PROOF; + proof.error = 0; + proof.unk2 = 0x00; + + std::memcpy(_writeBuffer, (char *)&proof, sizeof(proof)); + AsyncWrite(sizeof(proof)); + } + + _isAuthenticated = true; + } + else + { + char data[4] = { AUTH_LOGON_PROOF, WOW_FAIL_UNKNOWN_ACCOUNT, 3, 0 }; + + std::memcpy(_writeBuffer, data, sizeof(data)); + AsyncWrite(sizeof(data)); + + TC_LOG_DEBUG("server.authserver", "'%s:%d' [AuthChallenge] account %s tried to login with invalid password!", + GetRemoteIpAddress().c_str(), GetRemotePort(), _login.c_str()); + + uint32 MaxWrongPassCount = sConfigMgr->GetIntDefault("WrongPass.MaxCount", 0); + if (MaxWrongPassCount > 0) + { + //Increment number of failed logins by one and if it reaches the limit temporarily ban that account or IP + PreparedStatement *stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_FAILEDLOGINS); + stmt->setString(0, _login); + LoginDatabase.Execute(stmt); + + stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_FAILEDLOGINS); + stmt->setString(0, _login); + + if (PreparedQueryResult loginfail = LoginDatabase.Query(stmt)) + { + uint32 failed_logins = (*loginfail)[1].GetUInt32(); + + if (failed_logins >= MaxWrongPassCount) + { + uint32 WrongPassBanTime = sConfigMgr->GetIntDefault("WrongPass.BanTime", 600); + bool WrongPassBanType = sConfigMgr->GetBoolDefault("WrongPass.BanType", false); + + if (WrongPassBanType) + { + uint32 acc_id = (*loginfail)[0].GetUInt32(); + stmt = LoginDatabase.GetPreparedStatement(LOGIN_INS_ACCOUNT_AUTO_BANNED); + stmt->setUInt32(0, acc_id); + stmt->setUInt32(1, WrongPassBanTime); + LoginDatabase.Execute(stmt); + + TC_LOG_DEBUG("server.authserver", "'%s:%d' [AuthChallenge] account %s got banned for '%u' seconds because it failed to authenticate '%u' times", + GetRemoteIpAddress().c_str(), GetRemotePort(), _login.c_str(), WrongPassBanTime, failed_logins); + } + else + { + stmt = LoginDatabase.GetPreparedStatement(LOGIN_INS_IP_AUTO_BANNED); + stmt->setString(0, GetRemoteIpAddress()); + stmt->setUInt32(1, WrongPassBanTime); + LoginDatabase.Execute(stmt); + + TC_LOG_DEBUG("server.authserver", "'%s:%d' [AuthChallenge] IP got banned for '%u' seconds because account %s failed to authenticate '%u' times", + GetRemoteIpAddress().c_str(), GetRemotePort(), WrongPassBanTime, _login.c_str(), failed_logins); + } + } + } + } + } + + return true; } bool AuthSession::_HandleReconnectChallenge() { - TC_LOG_DEBUG("server.authserver", "Entering _HandleReconnectChallenge"); - sAuthLogonChallenge_C *challenge = (sAuthLogonChallenge_C*)&_readBuffer; + TC_LOG_DEBUG("server.authserver", "Entering _HandleReconnectChallenge"); + sAuthLogonChallenge_C *challenge = (sAuthLogonChallenge_C*)&_readBuffer; - //TC_LOG_DEBUG("server.authserver", "[AuthChallenge] got full packet, %#04x bytes", challenge->size); - TC_LOG_DEBUG("server.authserver", "[AuthChallenge] name(%d): '%s'", challenge->I_len, challenge->I); + //TC_LOG_DEBUG("server.authserver", "[AuthChallenge] got full packet, %#04x bytes", challenge->size); + TC_LOG_DEBUG("server.authserver", "[AuthChallenge] name(%d): '%s'", challenge->I_len, challenge->I); - _login.assign((const char*)challenge->I, challenge->I_len); + _login.assign((const char*)challenge->I, challenge->I_len); - PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_SESSIONKEY); - stmt->setString(0, _login); - PreparedQueryResult result = LoginDatabase.Query(stmt); + PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_SESSIONKEY); + stmt->setString(0, _login); + PreparedQueryResult result = LoginDatabase.Query(stmt); - // Stop if the account is not found - if (!result) - { - TC_LOG_ERROR("server.authserver", "'%s:%d' [ERROR] user %s tried to login and we cannot find his session key in the database.", - GetRemoteIpAddress().c_str(), GetRemotePort(), _login.c_str()); - return false; - } + // Stop if the account is not found + if (!result) + { + TC_LOG_ERROR("server.authserver", "'%s:%d' [ERROR] user %s tried to login and we cannot find his session key in the database.", + GetRemoteIpAddress().c_str(), GetRemotePort(), _login.c_str()); + return false; + } - // Reinitialize build, expansion and the account securitylevel - _build = challenge->build; - _expversion = uint8(AuthHelper::IsPostBCAcceptedClientBuild(_build) ? POST_BC_EXP_FLAG : (AuthHelper::IsPreBCAcceptedClientBuild(_build) ? PRE_BC_EXP_FLAG : NO_VALID_EXP_FLAG)); - _os = (const char*)challenge->os; + // Reinitialize build, expansion and the account securitylevel + _build = challenge->build; + _expversion = uint8(AuthHelper::IsPostBCAcceptedClientBuild(_build) ? POST_BC_EXP_FLAG : (AuthHelper::IsPreBCAcceptedClientBuild(_build) ? PRE_BC_EXP_FLAG : NO_VALID_EXP_FLAG)); + _os = (const char*)challenge->os; - if (_os.size() > 4) - return false; + if (_os.size() > 4) + return false; - // Restore string order as its byte order is reversed - std::reverse(_os.begin(), _os.end()); + // Restore string order as its byte order is reversed + std::reverse(_os.begin(), _os.end()); - Field* fields = result->Fetch(); - uint8 secLevel = fields[2].GetUInt8(); - _accountSecurityLevel = secLevel <= SEC_ADMINISTRATOR ? AccountTypes(secLevel) : SEC_ADMINISTRATOR; + Field* fields = result->Fetch(); + uint8 secLevel = fields[2].GetUInt8(); + _accountSecurityLevel = secLevel <= SEC_ADMINISTRATOR ? AccountTypes(secLevel) : SEC_ADMINISTRATOR; - K.SetHexStr((*result)[0].GetCString()); + K.SetHexStr((*result)[0].GetCString()); - // Sending response - ByteBuffer pkt; - pkt << uint8(AUTH_RECONNECT_CHALLENGE); - pkt << uint8(0x00); - _reconnectProof.SetRand(16 * 8); - pkt.append(_reconnectProof.AsByteArray(16).get(), 16); // 16 bytes random - pkt << uint64(0x00) << uint64(0x00); // 16 bytes zeros + // Sending response + ByteBuffer pkt; + pkt << uint8(AUTH_RECONNECT_CHALLENGE); + pkt << uint8(0x00); + _reconnectProof.SetRand(16 * 8); + pkt.append(_reconnectProof.AsByteArray(16).get(), 16); // 16 bytes random + pkt << uint64(0x00) << uint64(0x00); // 16 bytes zeros - std::memcpy(_writeBuffer, (char const*)pkt.contents(), pkt.size()); - AsyncWrite(pkt.size()); + std::memcpy(_writeBuffer, (char const*)pkt.contents(), pkt.size()); + AsyncWrite(pkt.size()); - return true; + return true; } bool AuthSession::_HandleReconnectProof() { - TC_LOG_DEBUG("server.authserver", "Entering _HandleReconnectProof"); - sAuthReconnectProof_C *reconnectProof = (sAuthReconnectProof_C*)&_readBuffer; - - if (_login.empty() || !_reconnectProof.GetNumBytes() || !K.GetNumBytes()) - return false; - - BigNumber t1; - t1.SetBinary(reconnectProof->R1, 16); - - SHA1Hash sha; - sha.Initialize(); - sha.UpdateData(_login); - sha.UpdateBigNumbers(&t1, &_reconnectProof, &K, NULL); - sha.Finalize(); - - if (!memcmp(sha.GetDigest(), reconnectProof->R2, SHA_DIGEST_LENGTH)) - { - // Sending response - ByteBuffer pkt; - pkt << uint8(AUTH_RECONNECT_PROOF); - pkt << uint8(0x00); - pkt << uint16(0x00); // 2 bytes zeros - std::memcpy(_writeBuffer, (char const*)pkt.contents(), pkt.size()); - AsyncWrite(pkt.size()); - _isAuthenticated = true; - return true; - } - else - { - TC_LOG_ERROR("server.authserver", "'%s:%d' [ERROR] user %s tried to login, but session is invalid.", GetRemoteIpAddress().c_str(), - GetRemotePort(), _login.c_str()); - return false; - } + TC_LOG_DEBUG("server.authserver", "Entering _HandleReconnectProof"); + sAuthReconnectProof_C *reconnectProof = (sAuthReconnectProof_C*)&_readBuffer; + + if (_login.empty() || !_reconnectProof.GetNumBytes() || !K.GetNumBytes()) + return false; + + BigNumber t1; + t1.SetBinary(reconnectProof->R1, 16); + + SHA1Hash sha; + sha.Initialize(); + sha.UpdateData(_login); + sha.UpdateBigNumbers(&t1, &_reconnectProof, &K, NULL); + sha.Finalize(); + + if (!memcmp(sha.GetDigest(), reconnectProof->R2, SHA_DIGEST_LENGTH)) + { + // Sending response + ByteBuffer pkt; + pkt << uint8(AUTH_RECONNECT_PROOF); + pkt << uint8(0x00); + pkt << uint16(0x00); // 2 bytes zeros + std::memcpy(_writeBuffer, (char const*)pkt.contents(), pkt.size()); + AsyncWrite(pkt.size()); + _isAuthenticated = true; + return true; + } + else + { + TC_LOG_ERROR("server.authserver", "'%s:%d' [ERROR] user %s tried to login, but session is invalid.", GetRemoteIpAddress().c_str(), + GetRemotePort(), _login.c_str()); + return false; + } } ACE_INET_Addr const& 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; + // 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 AuthSession::_HandleRealmList() { - TC_LOG_DEBUG("server.authserver", "Entering _HandleRealmList"); - - // Get the user id (else close the connection) - // No SQL injection (prepared statement) - PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_ACCOUNT_ID_BY_NAME); - stmt->setString(0, _login); - PreparedQueryResult result = LoginDatabase.Query(stmt); - if (!result) - { - TC_LOG_ERROR("server.authserver", "'%s:%d' [ERROR] user %s tried to login but we cannot find him in the database.", GetRemoteIpAddress().c_str(), - GetRemotePort(), _login.c_str()); - return false; - } - - Field* fields = result->Fetch(); - uint32 id = fields[0].GetUInt32(); - - // Update realm list if need - sRealmList->UpdateIfNeed(); - - // Circle through realms in the RealmList and construct the return packet (including # of user characters in each realm) - ByteBuffer pkt; - - size_t RealmListSize = 0; - for (RealmList::RealmMap::const_iterator i = sRealmList->begin(); i != sRealmList->end(); ++i) - { - const Realm &realm = i->second; - // don't work with realms which not compatible with the client - bool okBuild = ((_expversion & POST_BC_EXP_FLAG) && realm.gamebuild == _build) || ((_expversion & PRE_BC_EXP_FLAG) && !AuthHelper::IsPreBCAcceptedClientBuild(realm.gamebuild)); - - // No SQL injection. id of realm is controlled by the database. - uint32 flag = realm.flag; - RealmBuildInfo const* buildInfo = AuthHelper::GetBuildInfo(realm.gamebuild); - if (!okBuild) - { - 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; - - std::string name = i->first; - if (_expversion & PRE_BC_EXP_FLAG && flag & REALM_FLAG_SPECIFYBUILD) - { - std::ostringstream ss; - ss << name << " (" << buildInfo->MajorVersion << '.' << buildInfo->MinorVersion << '.' << buildInfo->BugfixVersion << ')'; - name = ss.str(); - } - - // We don't need the port number from which client connects with but the realm's port - ACE_INET_Addr clientAddr(realm.ExternalAddress.get_port_number(), GetRemoteIpAddress().c_str(), AF_INET); - - uint8 lock = (realm.allowedSecurityLevel > _accountSecurityLevel) ? 1 : 0; - - uint8 AmountOfCharacters = 0; - stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_NUM_CHARS_ON_REALM); - stmt->setUInt32(0, realm.m_ID); - stmt->setUInt32(1, id); - result = LoginDatabase.Query(stmt); - if (result) - AmountOfCharacters = (*result)[0].GetUInt8(); - - pkt << realm.icon; // realm type - if (_expversion & POST_BC_EXP_FLAG) // only 2.x and 3.x clients - pkt << lock; // if 1, then realm locked - pkt << uint8(flag); // RealmFlags - pkt << name; - pkt << GetAddressString(GetAddressForClient(realm, clientAddr)); - pkt << realm.populationLevel; - 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? - else - pkt << uint8(0x0); // 1.12.1 and 1.12.2 clients - - if (_expversion & POST_BC_EXP_FLAG && flag & REALM_FLAG_SPECIFYBUILD) - { - pkt << uint8(buildInfo->MajorVersion); - pkt << uint8(buildInfo->MinorVersion); - pkt << uint8(buildInfo->BugfixVersion); - pkt << uint16(buildInfo->Build); - } - - ++RealmListSize; - } - - if (_expversion & POST_BC_EXP_FLAG) // 2.x and 3.x clients - { - pkt << uint8(0x10); - pkt << uint8(0x00); - } - else // 1.12.1 and 1.12.2 clients - { - pkt << uint8(0x00); - pkt << uint8(0x02); - } - - // make a ByteBuffer which stores the RealmList's size - ByteBuffer RealmListSizeBuffer; - RealmListSizeBuffer << uint32(0); - if (_expversion & POST_BC_EXP_FLAG) // only 2.x and 3.x clients - RealmListSizeBuffer << uint16(RealmListSize); - else - RealmListSizeBuffer << uint32(RealmListSize); - - ByteBuffer hdr; - hdr << uint8(REALM_LIST); - hdr << uint16(pkt.size() + RealmListSizeBuffer.size()); - hdr.append(RealmListSizeBuffer); // append RealmList's size buffer - hdr.append(pkt); // append realms in the realmlist - - std::memcpy(_writeBuffer, (char const*)hdr.contents(), hdr.size()); - AsyncWrite(hdr.size()); - - return true; + TC_LOG_DEBUG("server.authserver", "Entering _HandleRealmList"); + + // Get the user id (else close the connection) + // No SQL injection (prepared statement) + PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_ACCOUNT_ID_BY_NAME); + stmt->setString(0, _login); + PreparedQueryResult result = LoginDatabase.Query(stmt); + if (!result) + { + TC_LOG_ERROR("server.authserver", "'%s:%d' [ERROR] user %s tried to login but we cannot find him in the database.", GetRemoteIpAddress().c_str(), + GetRemotePort(), _login.c_str()); + return false; + } + + Field* fields = result->Fetch(); + uint32 id = fields[0].GetUInt32(); + + // Update realm list if need + sRealmList->UpdateIfNeed(); + + // Circle through realms in the RealmList and construct the return packet (including # of user characters in each realm) + ByteBuffer pkt; + + size_t RealmListSize = 0; + for (RealmList::RealmMap::const_iterator i = sRealmList->begin(); i != sRealmList->end(); ++i) + { + const Realm &realm = i->second; + // don't work with realms which not compatible with the client + bool okBuild = ((_expversion & POST_BC_EXP_FLAG) && realm.gamebuild == _build) || ((_expversion & PRE_BC_EXP_FLAG) && !AuthHelper::IsPreBCAcceptedClientBuild(realm.gamebuild)); + + // No SQL injection. id of realm is controlled by the database. + uint32 flag = realm.flag; + RealmBuildInfo const* buildInfo = AuthHelper::GetBuildInfo(realm.gamebuild); + if (!okBuild) + { + 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; + + std::string name = i->first; + if (_expversion & PRE_BC_EXP_FLAG && flag & REALM_FLAG_SPECIFYBUILD) + { + std::ostringstream ss; + ss << name << " (" << buildInfo->MajorVersion << '.' << buildInfo->MinorVersion << '.' << buildInfo->BugfixVersion << ')'; + name = ss.str(); + } + + // We don't need the port number from which client connects with but the realm's port + ACE_INET_Addr clientAddr(realm.ExternalAddress.get_port_number(), GetRemoteIpAddress().c_str(), AF_INET); + + uint8 lock = (realm.allowedSecurityLevel > _accountSecurityLevel) ? 1 : 0; + + uint8 AmountOfCharacters = 0; + stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_NUM_CHARS_ON_REALM); + stmt->setUInt32(0, realm.m_ID); + stmt->setUInt32(1, id); + result = LoginDatabase.Query(stmt); + if (result) + AmountOfCharacters = (*result)[0].GetUInt8(); + + pkt << realm.icon; // realm type + if (_expversion & POST_BC_EXP_FLAG) // only 2.x and 3.x clients + pkt << lock; // if 1, then realm locked + pkt << uint8(flag); // RealmFlags + pkt << name; + pkt << GetAddressString(GetAddressForClient(realm, clientAddr)); + pkt << realm.populationLevel; + 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? + else + pkt << uint8(0x0); // 1.12.1 and 1.12.2 clients + + if (_expversion & POST_BC_EXP_FLAG && flag & REALM_FLAG_SPECIFYBUILD) + { + pkt << uint8(buildInfo->MajorVersion); + pkt << uint8(buildInfo->MinorVersion); + pkt << uint8(buildInfo->BugfixVersion); + pkt << uint16(buildInfo->Build); + } + + ++RealmListSize; + } + + if (_expversion & POST_BC_EXP_FLAG) // 2.x and 3.x clients + { + pkt << uint8(0x10); + pkt << uint8(0x00); + } + else // 1.12.1 and 1.12.2 clients + { + pkt << uint8(0x00); + pkt << uint8(0x02); + } + + // make a ByteBuffer which stores the RealmList's size + ByteBuffer RealmListSizeBuffer; + RealmListSizeBuffer << uint32(0); + if (_expversion & POST_BC_EXP_FLAG) // only 2.x and 3.x clients + RealmListSizeBuffer << uint16(RealmListSize); + else + RealmListSizeBuffer << uint32(RealmListSize); + + ByteBuffer hdr; + hdr << uint8(REALM_LIST); + hdr << uint16(pkt.size() + RealmListSizeBuffer.size()); + hdr.append(RealmListSizeBuffer); // append RealmList's size buffer + hdr.append(pkt); // append realms in the realmlist + + std::memcpy(_writeBuffer, (char const*)hdr.contents(), hdr.size()); + AsyncWrite(hdr.size()); + + return true; } // Make the SRP6 calculation from hash in dB void AuthSession::SetVSFields(const std::string& rI) { - s.SetRand(BYTE_SIZE * 8); - - BigNumber I; - I.SetHexStr(rI.c_str()); - - // In case of leading zeros in the rI hash, restore them - uint8 mDigest[SHA_DIGEST_LENGTH]; - memset(mDigest, 0, SHA_DIGEST_LENGTH); - if (I.GetNumBytes() <= SHA_DIGEST_LENGTH) - memcpy(mDigest, I.AsByteArray().get(), I.GetNumBytes()); - - std::reverse(mDigest, mDigest + SHA_DIGEST_LENGTH); - - SHA1Hash sha; - sha.UpdateData(s.AsByteArray().get(), s.GetNumBytes()); - sha.UpdateData(mDigest, SHA_DIGEST_LENGTH); - sha.Finalize(); - BigNumber x; - 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(2, _login); - LoginDatabase.Execute(stmt); - - OPENSSL_free(v_hex); - OPENSSL_free(s_hex); -} \ No newline at end of file + s.SetRand(BYTE_SIZE * 8); + + BigNumber I; + I.SetHexStr(rI.c_str()); + + // In case of leading zeros in the rI hash, restore them + uint8 mDigest[SHA_DIGEST_LENGTH]; + memset(mDigest, 0, SHA_DIGEST_LENGTH); + if (I.GetNumBytes() <= SHA_DIGEST_LENGTH) + memcpy(mDigest, I.AsByteArray().get(), I.GetNumBytes()); + + std::reverse(mDigest, mDigest + SHA_DIGEST_LENGTH); + + SHA1Hash sha; + sha.UpdateData(s.AsByteArray().get(), s.GetNumBytes()); + sha.UpdateData(mDigest, SHA_DIGEST_LENGTH); + sha.Finalize(); + BigNumber x; + 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(2, _login); + LoginDatabase.Execute(stmt); + + OPENSSL_free(v_hex); + OPENSSL_free(s_hex); +} diff --git a/src/server/authserver/Server/AuthSession.h b/src/server/authserver/Server/AuthSession.h index 205300e806a..79b1e568aa6 100644 --- a/src/server/authserver/Server/AuthSession.h +++ b/src/server/authserver/Server/AuthSession.h @@ -34,52 +34,52 @@ const size_t bufferSize = 4096; class AuthSession : public std::enable_shared_from_this < AuthSession > { public: - AuthSession(tcp::socket socket) : _socket(std::move(socket)) - { - N.SetHexStr("894B645E89E1535BBDAD5B8B290650530801B18EBFBF5E8FAB3C82872A3E9BB7"); - g.SetDword(7); - } - - void Start() - { - AsyncReadHeader(); - } - - bool _HandleLogonChallenge(); - bool _HandleLogonProof(); - bool _HandleReconnectChallenge(); - bool _HandleReconnectProof(); - bool _HandleRealmList(); - - const std::string GetRemoteIpAddress() const { return _socket.remote_endpoint().address().to_string(); }; - unsigned short GetRemotePort() const { return _socket.remote_endpoint().port(); } + AuthSession(tcp::socket socket) : _socket(std::move(socket)) + { + N.SetHexStr("894B645E89E1535BBDAD5B8B290650530801B18EBFBF5E8FAB3C82872A3E9BB7"); + g.SetDword(7); + } + + void Start() + { + AsyncReadHeader(); + } + + bool _HandleLogonChallenge(); + bool _HandleLogonProof(); + bool _HandleReconnectChallenge(); + bool _HandleReconnectProof(); + bool _HandleRealmList(); + + const std::string GetRemoteIpAddress() const { return _socket.remote_endpoint().address().to_string(); }; + unsigned short GetRemotePort() const { return _socket.remote_endpoint().port(); } private: - void AsyncReadHeader(); - void AsyncReadData(bool (AuthSession::*handler)(), size_t dataSize, size_t bufferOffset); - void AsyncWrite(size_t length); + void AsyncReadHeader(); + void AsyncReadData(bool (AuthSession::*handler)(), size_t dataSize, size_t bufferOffset); + void AsyncWrite(size_t length); - void SetVSFields(const std::string& rI); + void SetVSFields(const std::string& rI); - BigNumber N, s, g, v; - BigNumber b, B; - BigNumber K; - BigNumber _reconnectProof; + BigNumber N, s, g, v; + BigNumber b, B; + BigNumber K; + BigNumber _reconnectProof; - tcp::socket _socket; - char _readBuffer[BUFFER_SIZE]; - char _writeBuffer[BUFFER_SIZE]; + tcp::socket _socket; + char _readBuffer[BUFFER_SIZE]; + char _writeBuffer[BUFFER_SIZE]; - bool _isAuthenticated; - std::string _tokenKey; - std::string _login; - std::string _localizationName; - std::string _os; - uint16 _build; - uint8 _expversion; + bool _isAuthenticated; + std::string _tokenKey; + std::string _login; + std::string _localizationName; + std::string _os; + uint16 _build; + uint8 _expversion; - AccountTypes _accountSecurityLevel; + AccountTypes _accountSecurityLevel; }; -#endif \ No newline at end of file +#endif -- cgit v1.2.3 From f05d5406585fe2d69796b93bff73a21e1cd41a23 Mon Sep 17 00:00:00 2001 From: leak Date: Sat, 31 May 2014 01:02:03 +0200 Subject: Restore PCH builds and make GCC happy --- src/server/authserver/PrecompiledHeaders/authPCH.h | 3 ++- src/server/authserver/Server/AuthSession.cpp | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) (limited to 'src/server/authserver/Server/AuthSession.cpp') diff --git a/src/server/authserver/PrecompiledHeaders/authPCH.h b/src/server/authserver/PrecompiledHeaders/authPCH.h index 5fc3b0a3416..0ec181d9c63 100644 --- a/src/server/authserver/PrecompiledHeaders/authPCH.h +++ b/src/server/authserver/PrecompiledHeaders/authPCH.h @@ -2,5 +2,6 @@ #include "Database/DatabaseEnv.h" #include "Log.h" #include "RealmList.h" -#include "RealmSocket.h" +#include "AuthServer.h" +#include "AuthSession.h" #include "Common.h" diff --git a/src/server/authserver/Server/AuthSession.cpp b/src/server/authserver/Server/AuthSession.cpp index 6a3c145d08b..a366f7d11f7 100644 --- a/src/server/authserver/Server/AuthSession.cpp +++ b/src/server/authserver/Server/AuthSession.cpp @@ -148,7 +148,7 @@ void AuthSession::AsyncReadHeader() { _socket.read_some(boost::asio::buffer(&_readBuffer[1], sizeof(uint8) + sizeof(uint16))); //error + size - AsyncReadData(entry.handler, (uint16)&_readBuffer[2], sizeof(uint8) + sizeof(uint8) + sizeof(uint16)); // cmd + error + size + AsyncReadData(entry.handler, *reinterpret_cast(&_readBuffer[2]), sizeof(uint8) + sizeof(uint8) + sizeof(uint16)); // cmd + error + size } else { -- cgit v1.2.3 From bf6e58b8d44d3a4b78e9473df029caac74c68220 Mon Sep 17 00:00:00 2001 From: leak Date: Sat, 31 May 2014 15:58:59 +0200 Subject: Ditched ACE_Singleton in favor of C++11 like Singleton --- src/server/authserver/Main.cpp | 5 +++-- src/server/authserver/Realms/RealmList.h | 16 ++++++++++------ src/server/authserver/Server/AuthSession.cpp | 4 ++-- 3 files changed, 15 insertions(+), 10 deletions(-) (limited to 'src/server/authserver/Server/AuthSession.cpp') diff --git a/src/server/authserver/Main.cpp b/src/server/authserver/Main.cpp index 27834f50814..2427c47a438 100644 --- a/src/server/authserver/Main.cpp +++ b/src/server/authserver/Main.cpp @@ -152,8 +152,9 @@ int main(int argc, char** argv) return 1; // Get the list of realms for the server - sRealmList->Initialize(sConfigMgr->GetIntDefault("RealmsStateUpdateDelay", 20)); - if (sRealmList->size() == 0) + sRealmList.Initialize(sConfigMgr->GetIntDefault("RealmsStateUpdateDelay", 20)); + + if (sRealmList.size() == 0) { TC_LOG_ERROR("server.authserver", "No valid realms specified."); return 1; diff --git a/src/server/authserver/Realms/RealmList.h b/src/server/authserver/Realms/RealmList.h index 88da30ea963..29b6aca07d3 100644 --- a/src/server/authserver/Realms/RealmList.h +++ b/src/server/authserver/Realms/RealmList.h @@ -19,8 +19,6 @@ #ifndef _REALMLIST_H #define _REALMLIST_H -#include -#include #include #include "Common.h" @@ -59,8 +57,11 @@ class RealmList public: typedef std::map RealmMap; - RealmList(); - ~RealmList() { } + static RealmList& instance() + { + static RealmList *instance = new RealmList(); + return *instance; + } void Initialize(uint32 updateInterval); @@ -73,13 +74,16 @@ public: uint32 size() const { return m_realms.size(); } private: + RealmList(); + 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); RealmMap m_realms; uint32 m_UpdateInterval; time_t m_NextUpdateTime; }; -#define sRealmList ACE_Singleton::instance() +#define sRealmList RealmList::instance() #endif diff --git a/src/server/authserver/Server/AuthSession.cpp b/src/server/authserver/Server/AuthSession.cpp index a366f7d11f7..627e1fc470d 100644 --- a/src/server/authserver/Server/AuthSession.cpp +++ b/src/server/authserver/Server/AuthSession.cpp @@ -772,13 +772,13 @@ bool AuthSession::_HandleRealmList() uint32 id = fields[0].GetUInt32(); // Update realm list if need - sRealmList->UpdateIfNeed(); + sRealmList.UpdateIfNeed(); // Circle through realms in the RealmList and construct the return packet (including # of user characters in each realm) ByteBuffer pkt; size_t RealmListSize = 0; - for (RealmList::RealmMap::const_iterator i = sRealmList->begin(); i != sRealmList->end(); ++i) + for (RealmList::RealmMap::const_iterator i = sRealmList.begin(); i != sRealmList.end(); ++i) { const Realm &realm = i->second; // don't work with realms which not compatible with the client -- cgit v1.2.3 From 35aa142f6aa748db1febe901b2446fe53b9abbe0 Mon Sep 17 00:00:00 2001 From: leak Date: Sat, 31 May 2014 18:31:53 +0200 Subject: Replaced ACE_INET_Addr with boost::asio::ip::address --- src/server/authserver/Realms/RealmList.cpp | 25 +++++++++-------- src/server/authserver/Realms/RealmList.h | 15 ++++++----- src/server/authserver/Server/AuthSession.cpp | 40 +++++++++++++++++----------- src/server/authserver/Server/AuthSession.h | 1 - 4 files changed, 48 insertions(+), 33 deletions(-) (limited to 'src/server/authserver/Server/AuthSession.cpp') diff --git a/src/server/authserver/Realms/RealmList.cpp b/src/server/authserver/Realms/RealmList.cpp index 4aeecfc0aaa..7ed9021dd21 100644 --- a/src/server/authserver/Realms/RealmList.cpp +++ b/src/server/authserver/Realms/RealmList.cpp @@ -16,10 +16,13 @@ * with this program. If not, see . */ +#include #include "Common.h" #include "RealmList.h" #include "Database/DatabaseEnv.h" +namespace boost { namespace asio { namespace ip { class address; } } } + RealmList::RealmList() : m_UpdateInterval(0), m_NextUpdateTime(time(NULL)) { } // Load the realm list from the database @@ -31,7 +34,8 @@ 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, ip::address const& address, ip::address const& localAddr, + ip::address const& localSubmask, uint16 port, uint8 icon, RealmFlags flag, uint8 timezone, AccountTypes allowedSecurityLevel, float population, uint32 build) { // Create new if not exist or update existed Realm& realm = m_realms[name]; @@ -42,12 +46,14 @@ void RealmList::UpdateRealm(uint32 id, const std::string& name, ACE_INET_Addr co realm.flag = flag; realm.timezone = timezone; realm.allowedSecurityLevel = allowedSecurityLevel; - realm.populationLevel = popu; + realm.populationLevel = population; // Append port to IP address. + realm.ExternalAddress = address; realm.LocalAddress = localAddr; realm.LocalSubnetMask = localSubmask; + realm.port = port; realm.gamebuild = build; } @@ -81,9 +87,9 @@ void RealmList::UpdateRealms(bool init) Field* fields = result->Fetch(); uint32 realmId = fields[0].GetUInt32(); std::string name = fields[1].GetString(); - std::string externalAddress = fields[2].GetString(); - std::string localAddress = fields[3].GetString(); - std::string localSubmask = fields[4].GetString(); + ip::address externalAddress = ip::address::from_string(fields[2].GetString()); + ip::address localAddress = ip::address::from_string(fields[3].GetString()); + ip::address localSubmask = ip::address::from_string(fields[4].GetString()); uint16 port = fields[5].GetUInt16(); uint8 icon = fields[6].GetUInt8(); RealmFlags flag = RealmFlags(fields[7].GetUInt8()); @@ -92,14 +98,11 @@ void RealmList::UpdateRealms(bool init) float pop = fields[10].GetFloat(); uint32 build = fields[11].GetUInt32(); - 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, externalAddress, localAddress, localSubmask, port, icon, flag, timezone, + (allowedSecurityLevel <= SEC_ADMINISTRATOR ? AccountTypes(allowedSecurityLevel) : SEC_ADMINISTRATOR), pop, build); if (init) - TC_LOG_INFO("server.authserver", "Added realm \"%s\" at %s:%u.", name.c_str(), m_realms[name].ExternalAddress.get_host_addr(), port); + TC_LOG_INFO("server.authserver", "Added realm \"%s\" at %s:%u.", name.c_str(), m_realms[name].ExternalAddress.to_string(), port); } while (result->NextRow()); } diff --git a/src/server/authserver/Realms/RealmList.h b/src/server/authserver/Realms/RealmList.h index 29b6aca07d3..b96d5523da9 100644 --- a/src/server/authserver/Realms/RealmList.h +++ b/src/server/authserver/Realms/RealmList.h @@ -19,9 +19,11 @@ #ifndef _REALMLIST_H #define _REALMLIST_H -#include +#include #include "Common.h" +using namespace boost::asio; + enum RealmFlags { REALM_FLAG_NONE = 0x00, @@ -38,9 +40,10 @@ enum RealmFlags // Storage object for a realm struct Realm { - ACE_INET_Addr ExternalAddress; - ACE_INET_Addr LocalAddress; - ACE_INET_Addr LocalSubnetMask; + ip::address ExternalAddress; + ip::address LocalAddress; + ip::address LocalSubnetMask; + uint16 port; std::string name; uint8 icon; RealmFlags flag; @@ -77,8 +80,8 @@ private: RealmList(); 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, ip::address const& address, ip::address const& localAddr, + ip::address const& localSubmask, uint16 port, uint8 icon, RealmFlags flag, uint8 timezone, AccountTypes allowedSecurityLevel, float population, uint32 build); RealmMap m_realms; uint32 m_UpdateInterval; diff --git a/src/server/authserver/Server/AuthSession.cpp b/src/server/authserver/Server/AuthSession.cpp index 627e1fc470d..304d593fa3d 100644 --- a/src/server/authserver/Server/AuthSession.cpp +++ b/src/server/authserver/Server/AuthSession.cpp @@ -18,6 +18,7 @@ #include #include +#include #include #include #include "ByteBuffer.h" @@ -729,29 +730,41 @@ bool AuthSession::_HandleReconnectProof() } } -ACE_INET_Addr const& GetAddressForClient(Realm const& realm, ACE_INET_Addr const& clientAddr) +tcp::endpoint const GetAddressForClient(Realm const& realm, ip::address const& clientAddr) { + ip::address realmIp; + // 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; + realmIp = clientAddr; + else + { + // Assume that user connecting from the machine that authserver is located on + // has all realms available in his local network + realmIp = realm.LocalAddress; + } + } + else + { + if (clientAddr.is_v4() && + (clientAddr.to_v4().to_ulong() & realm.LocalSubnetMask.to_v4().to_ulong()) == + (realm.LocalAddress.to_v4().to_ulong() & realm.LocalSubnetMask.to_v4().to_ulong())) + { + realmIp = realm.LocalAddress; + } + else + realmIp = realm.ExternalAddress; } - // Check if connecting client is in the same network - if (IsIPAddrInNetwork(realm.LocalAddress, clientAddr, realm.LocalSubnetMask)) - return realm.LocalAddress; + tcp::endpoint endpoint(realmIp, realm.port); // Return external IP - return realm.ExternalAddress; + return endpoint; } - bool AuthSession::_HandleRealmList() { TC_LOG_DEBUG("server.authserver", "Entering _HandleRealmList"); @@ -806,9 +819,6 @@ bool AuthSession::_HandleRealmList() name = ss.str(); } - // We don't need the port number from which client connects with but the realm's port - ACE_INET_Addr clientAddr(realm.ExternalAddress.get_port_number(), GetRemoteIpAddress().c_str(), AF_INET); - uint8 lock = (realm.allowedSecurityLevel > _accountSecurityLevel) ? 1 : 0; uint8 AmountOfCharacters = 0; @@ -824,7 +834,7 @@ bool AuthSession::_HandleRealmList() pkt << lock; // if 1, then realm locked pkt << uint8(flag); // RealmFlags pkt << name; - pkt << GetAddressString(GetAddressForClient(realm, clientAddr)); + pkt << boost::lexical_cast(GetAddressForClient(realm, _socket.remote_endpoint().address())); pkt << realm.populationLevel; pkt << AmountOfCharacters; pkt << realm.timezone; // realm category diff --git a/src/server/authserver/Server/AuthSession.h b/src/server/authserver/Server/AuthSession.h index 79b1e568aa6..32e81d5240e 100644 --- a/src/server/authserver/Server/AuthSession.h +++ b/src/server/authserver/Server/AuthSession.h @@ -21,7 +21,6 @@ #include #include - #include "Common.h" #include "BigNumber.h" -- cgit v1.2.3 From a20ac4c25bc25ddf8de1d9c5b810d332f5287d33 Mon Sep 17 00:00:00 2001 From: leak Date: Tue, 24 Jun 2014 17:41:43 +0200 Subject: Compile fix for recently added coding accessing socket information --- src/server/authserver/Server/AuthSession.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/server/authserver/Server/AuthSession.cpp') diff --git a/src/server/authserver/Server/AuthSession.cpp b/src/server/authserver/Server/AuthSession.cpp index 5b56a99d640..ba31573cb4e 100644 --- a/src/server/authserver/Server/AuthSession.cpp +++ b/src/server/authserver/Server/AuthSession.cpp @@ -599,7 +599,7 @@ bool AuthSession::_HandleLogonProof() { PreparedStatement* logstmt = LoginDatabase.GetPreparedStatement(LOGIN_INS_FALP_IP_LOGGING); logstmt->setString(0, _login); - logstmt->setString(1, socket().getRemoteAddress()); + logstmt->setString(1, GetRemoteIpAddress()); logstmt->setString(2, "Logged on failed AccountLogin due wrong password"); LoginDatabase.Execute(logstmt); -- cgit v1.2.3 From 2874014443cff95e34a75ffa3bfe816ed7143803 Mon Sep 17 00:00:00 2001 From: Subv Date: Wed, 2 Jul 2014 11:50:03 -0500 Subject: Cleaned up the authserver includes a bit. Fixed authserver pch build --- src/server/authserver/Main.cpp | 2 -- src/server/authserver/PrecompiledHeaders/authPCH.h | 1 - src/server/authserver/Realms/RealmList.cpp | 1 - src/server/authserver/Realms/RealmList.h | 2 +- src/server/authserver/Server/AuthSession.cpp | 2 +- src/server/authserver/Server/AuthSession.h | 2 +- src/server/worldserver/WorldThread/WorldRunnable.h | 2 +- 7 files changed, 4 insertions(+), 8 deletions(-) (limited to 'src/server/authserver/Server/AuthSession.cpp') diff --git a/src/server/authserver/Main.cpp b/src/server/authserver/Main.cpp index 988ee901139..1fdd01ad968 100644 --- a/src/server/authserver/Main.cpp +++ b/src/server/authserver/Main.cpp @@ -28,8 +28,6 @@ #include #include #include -#include -#include #include #include "Common.h" diff --git a/src/server/authserver/PrecompiledHeaders/authPCH.h b/src/server/authserver/PrecompiledHeaders/authPCH.h index 61059ae91b0..ef757a656d5 100644 --- a/src/server/authserver/PrecompiledHeaders/authPCH.h +++ b/src/server/authserver/PrecompiledHeaders/authPCH.h @@ -3,5 +3,4 @@ #include "Database/DatabaseEnv.h" #include "Log.h" #include "RealmList.h" -#include "AuthServer.h" #include "AuthSession.h" diff --git a/src/server/authserver/Realms/RealmList.cpp b/src/server/authserver/Realms/RealmList.cpp index 94d52fb3138..bf097abff9a 100644 --- a/src/server/authserver/Realms/RealmList.cpp +++ b/src/server/authserver/Realms/RealmList.cpp @@ -16,7 +16,6 @@ * with this program. If not, see . */ -#include #include "Common.h" #include "RealmList.h" #include "Database/DatabaseEnv.h" diff --git a/src/server/authserver/Realms/RealmList.h b/src/server/authserver/Realms/RealmList.h index b96d5523da9..e8e94376c20 100644 --- a/src/server/authserver/Realms/RealmList.h +++ b/src/server/authserver/Realms/RealmList.h @@ -19,7 +19,7 @@ #ifndef _REALMLIST_H #define _REALMLIST_H -#include +#include #include "Common.h" using namespace boost::asio; diff --git a/src/server/authserver/Server/AuthSession.cpp b/src/server/authserver/Server/AuthSession.cpp index ba31573cb4e..6646f1203b5 100644 --- a/src/server/authserver/Server/AuthSession.cpp +++ b/src/server/authserver/Server/AuthSession.cpp @@ -17,8 +17,8 @@ */ #include -#include #include +#include #include #include #include "ByteBuffer.h" diff --git a/src/server/authserver/Server/AuthSession.h b/src/server/authserver/Server/AuthSession.h index 32e81d5240e..3aef4262786 100644 --- a/src/server/authserver/Server/AuthSession.h +++ b/src/server/authserver/Server/AuthSession.h @@ -20,7 +20,7 @@ #define __AUTHSESSION_H__ #include -#include +#include #include "Common.h" #include "BigNumber.h" diff --git a/src/server/worldserver/WorldThread/WorldRunnable.h b/src/server/worldserver/WorldThread/WorldRunnable.h index 3e2c07b8842..c6d00d269e7 100644 --- a/src/server/worldserver/WorldThread/WorldRunnable.h +++ b/src/server/worldserver/WorldThread/WorldRunnable.h @@ -23,7 +23,7 @@ #ifndef __WORLDRUNNABLE_H #define __WORLDRUNNABLE_H -#include +#include void WorldThread(boost::asio::io_service& ioService); -- cgit v1.2.3 From 4f2f9e08f80f46149dbbe8e5ca469267f39ae438 Mon Sep 17 00:00:00 2001 From: leak Date: Fri, 4 Jul 2014 15:20:23 +0200 Subject: Fixed compilation and some copy paste error --- src/server/authserver/Server/AuthSession.cpp | 2 +- src/server/game/World/World.cpp | 2 -- src/server/shared/Configuration/Config.cpp | 2 +- 3 files changed, 2 insertions(+), 4 deletions(-) (limited to 'src/server/authserver/Server/AuthSession.cpp') diff --git a/src/server/authserver/Server/AuthSession.cpp b/src/server/authserver/Server/AuthSession.cpp index 6646f1203b5..f518dc7593b 100644 --- a/src/server/authserver/Server/AuthSession.cpp +++ b/src/server/authserver/Server/AuthSession.cpp @@ -595,7 +595,7 @@ bool AuthSession::_HandleLogonProof() uint32 MaxWrongPassCount = sConfigMgr->GetIntDefault("WrongPass.MaxCount", 0); // We can not include the failed account login hook. However, this is a workaround to still log this. - if (sConfigMgr->GetBoolDefault("Additional.IP.Based.Login.Logging", false)) + if (sConfigMgr->GetBoolDefault("Wrong.Password.Login.Logging", false)) { PreparedStatement* logstmt = LoginDatabase.GetPreparedStatement(LOGIN_INS_FALP_IP_LOGGING); logstmt->setString(0, _login); diff --git a/src/server/game/World/World.cpp b/src/server/game/World/World.cpp index 48dd6565f95..ad23e016e32 100644 --- a/src/server/game/World/World.cpp +++ b/src/server/game/World/World.cpp @@ -1259,8 +1259,6 @@ void World::LoadConfigSettings(bool reload) m_bool_configs[CONFIG_IP_BASED_ACTION_LOGGING] = sConfigMgr->GetBoolDefault("Allow.IP.Based.Action.Logging", false); - m_bool_configs[CONFIG_IP_BASED_LOGIN_LOGGING] = sConfigMgr->GetBoolDefault("Wrong.Password.Login.Logging", false); - // call ScriptMgr if we're reloading the configuration if (reload) sScriptMgr->OnConfigLoad(reload); diff --git a/src/server/shared/Configuration/Config.cpp b/src/server/shared/Configuration/Config.cpp index aea9d4c1366..fe61cde5594 100644 --- a/src/server/shared/Configuration/Config.cpp +++ b/src/server/shared/Configuration/Config.cpp @@ -42,7 +42,7 @@ bool ConfigMgr::LoadInitial(char const* file) return false; // Since we're using only one section per config file, we skip the section and have direct property access - _config = fullTree.begin().second; + _config = fullTree.begin()->second; } catch (std::exception const& /*ex*/) { -- cgit v1.2.3 From 77caf33debab6153da46da11ff8aff5142b42b2a Mon Sep 17 00:00:00 2001 From: Subv Date: Sun, 6 Jul 2014 17:03:54 -0500 Subject: Removed some unneeded boost dependencies. Ensure that the correct packet sizes are read in the authserver. Added some try catch to the authserver to deal with boost exceptions (this part is not finished) --- cmake/macros/ConfigureBoost.cmake | 4 ++- src/server/authserver/Realms/RealmList.cpp | 46 ++++++++++++++++------------ src/server/authserver/Server/AuthSession.cpp | 7 +++-- src/server/game/World/World.cpp | 2 +- 4 files changed, 35 insertions(+), 24 deletions(-) (limited to 'src/server/authserver/Server/AuthSession.cpp') diff --git a/cmake/macros/ConfigureBoost.cmake b/cmake/macros/ConfigureBoost.cmake index 8ade7a0db5b..0e654ada86d 100644 --- a/cmake/macros/ConfigureBoost.cmake +++ b/cmake/macros/ConfigureBoost.cmake @@ -27,7 +27,9 @@ if(WIN32) add_definitions(-D_WIN32_WINNT=${ver}) endif() -find_package(Boost 1.55 REQUIRED atomic chrono date_time exception regex system thread) +find_package(Boost 1.55 REQUIRED system thread) +add_definitions(-DBOOST_DATE_TIME_NO_LIB) +add_definitions(-DBOOST_REGEX_NO_LIB) if(Boost_FOUND) include_directories(${Boost_INCLUDE_DIRS}) diff --git a/src/server/authserver/Realms/RealmList.cpp b/src/server/authserver/Realms/RealmList.cpp index bf097abff9a..392d86b5621 100644 --- a/src/server/authserver/Realms/RealmList.cpp +++ b/src/server/authserver/Realms/RealmList.cpp @@ -83,25 +83,33 @@ void RealmList::UpdateRealms(bool init) { do { - Field* fields = result->Fetch(); - uint32 realmId = fields[0].GetUInt32(); - std::string name = fields[1].GetString(); - ip::address externalAddress = ip::address::from_string(fields[2].GetString()); - ip::address localAddress = ip::address::from_string(fields[3].GetString()); - ip::address localSubmask = ip::address::from_string(fields[4].GetString()); - uint16 port = fields[5].GetUInt16(); - uint8 icon = fields[6].GetUInt8(); - RealmFlags flag = RealmFlags(fields[7].GetUInt8()); - uint8 timezone = fields[8].GetUInt8(); - uint8 allowedSecurityLevel = fields[9].GetUInt8(); - float pop = fields[10].GetFloat(); - uint32 build = fields[11].GetUInt32(); - - UpdateRealm(realmId, name, externalAddress, localAddress, localSubmask, port, icon, flag, timezone, - (allowedSecurityLevel <= SEC_ADMINISTRATOR ? AccountTypes(allowedSecurityLevel) : SEC_ADMINISTRATOR), pop, build); - - if (init) - TC_LOG_INFO("server.authserver", "Added realm \"%s\" at %s:%u.", name.c_str(), m_realms[name].ExternalAddress.to_string().c_str(), port); + try + { + Field* fields = result->Fetch(); + uint32 realmId = fields[0].GetUInt32(); + std::string name = fields[1].GetString(); + ip::address externalAddress = ip::address::from_string(fields[2].GetString()); + ip::address localAddress = ip::address::from_string(fields[3].GetString()); + ip::address localSubmask = ip::address::from_string(fields[4].GetString()); + uint16 port = fields[5].GetUInt16(); + uint8 icon = fields[6].GetUInt8(); + RealmFlags flag = RealmFlags(fields[7].GetUInt8()); + uint8 timezone = fields[8].GetUInt8(); + uint8 allowedSecurityLevel = fields[9].GetUInt8(); + float pop = fields[10].GetFloat(); + uint32 build = fields[11].GetUInt32(); + + UpdateRealm(realmId, name, externalAddress, localAddress, localSubmask, port, icon, flag, timezone, + (allowedSecurityLevel <= SEC_ADMINISTRATOR ? AccountTypes(allowedSecurityLevel) : SEC_ADMINISTRATOR), pop, build); + + if (init) + TC_LOG_INFO("server.authserver", "Added realm \"%s\" at %s:%u.", name.c_str(), m_realms[name].ExternalAddress.to_string().c_str(), port); + } + catch (std::exception& ex) + { + TC_LOG_ERROR("server.authserver", "Realmlist::UpdateRealms has thrown an exception: %s", ex.what()); + ASSERT(false); + } } while (result->NextRow()); } diff --git a/src/server/authserver/Server/AuthSession.cpp b/src/server/authserver/Server/AuthSession.cpp index f518dc7593b..df90339222d 100644 --- a/src/server/authserver/Server/AuthSession.cpp +++ b/src/server/authserver/Server/AuthSession.cpp @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include "ByteBuffer.h" @@ -136,7 +137,7 @@ void AuthSession::AsyncReadHeader() { auto self(shared_from_this()); - _socket.async_read_some(boost::asio::buffer(_readBuffer, 1), [this, self](boost::system::error_code error, size_t transferedBytes) + boost::asio::async_read(_socket, boost::asio::buffer(_readBuffer, 1), [this, self](boost::system::error_code error, size_t transferedBytes) { if (!error && transferedBytes == 1) { @@ -147,7 +148,7 @@ void AuthSession::AsyncReadHeader() // Handle dynamic size packet if (_readBuffer[0] == AUTH_LOGON_CHALLENGE) { - _socket.read_some(boost::asio::buffer(&_readBuffer[1], sizeof(uint8) + sizeof(uint16))); //error + size + boost::asio::read(_socket, boost::asio::buffer(&_readBuffer[1], sizeof(uint8) + sizeof(uint16))); //error + size AsyncReadData(entry.handler, *reinterpret_cast(&_readBuffer[2]), sizeof(uint8) + sizeof(uint8) + sizeof(uint16)); // cmd + error + size } @@ -170,7 +171,7 @@ void AuthSession::AsyncReadData(bool (AuthSession::*handler)(), size_t dataSize, { auto self(shared_from_this()); - _socket.async_read_some(boost::asio::buffer(&_readBuffer[bufferOffSet], dataSize), [handler, this, self](boost::system::error_code error, size_t transferedBytes) + boost::asio::async_read(_socket, boost::asio::buffer(&_readBuffer[bufferOffSet], dataSize), [handler, this, self](boost::system::error_code error, size_t transferedBytes) { if (!error && transferedBytes > 0) { diff --git a/src/server/game/World/World.cpp b/src/server/game/World/World.cpp index ad23e016e32..741b12f30dc 100644 --- a/src/server/game/World/World.cpp +++ b/src/server/game/World/World.cpp @@ -1316,7 +1316,7 @@ void World::SetInitialWorldSettings() ///- Update the realm entry in the database with the realm type from the config file //No SQL injection as values are treated as integers - + // not send custom type REALM_FFA_PVP to realm list uint32 server_type = IsFFAPvPRealm() ? uint32(REALM_TYPE_PVP) : getIntConfig(CONFIG_GAME_TYPE); uint32 realm_zone = getIntConfig(CONFIG_REALM_ZONE); -- cgit v1.2.3 From 110396447f2f414f8834c1b86c764d97704537b7 Mon Sep 17 00:00:00 2001 From: Subv Date: Mon, 7 Jul 2014 14:25:17 -0500 Subject: Fixed the authserver not accepting clients. Fixed using hostnames in the realmlist table. --- src/server/authserver/Main.cpp | 2 +- src/server/authserver/Realms/RealmList.cpp | 45 ++++++++++++++++++++++++---- src/server/authserver/Realms/RealmList.h | 7 ++++- src/server/authserver/Server/AuthSession.cpp | 7 ++--- 4 files changed, 50 insertions(+), 11 deletions(-) (limited to 'src/server/authserver/Server/AuthSession.cpp') diff --git a/src/server/authserver/Main.cpp b/src/server/authserver/Main.cpp index 39ad4b60dfe..1286e261a47 100644 --- a/src/server/authserver/Main.cpp +++ b/src/server/authserver/Main.cpp @@ -109,7 +109,7 @@ int main(int argc, char** argv) return 1; // Get the list of realms for the server - sRealmList.Initialize(sConfigMgr->GetIntDefault("RealmsStateUpdateDelay", 20)); + sRealmList.Initialize(_ioService, sConfigMgr->GetIntDefault("RealmsStateUpdateDelay", 20)); if (sRealmList.size() == 0) { diff --git a/src/server/authserver/Realms/RealmList.cpp b/src/server/authserver/Realms/RealmList.cpp index 392d86b5621..4dd2ab96dd9 100644 --- a/src/server/authserver/Realms/RealmList.cpp +++ b/src/server/authserver/Realms/RealmList.cpp @@ -16,17 +16,23 @@ * with this program. If not, see . */ +#include #include "Common.h" #include "RealmList.h" #include "Database/DatabaseEnv.h" namespace boost { namespace asio { namespace ip { class address; } } } -RealmList::RealmList() : m_UpdateInterval(0), m_NextUpdateTime(time(NULL)) { } +RealmList::RealmList() : m_UpdateInterval(0), m_NextUpdateTime(time(NULL)), _resolver(nullptr) { } +RealmList::~RealmList() +{ + delete _resolver; +} // Load the realm list from the database -void RealmList::Initialize(uint32 updateInterval) +void RealmList::Initialize(boost::asio::io_service& ioService, uint32 updateInterval) { + _resolver = new boost::asio::ip::tcp::resolver(ioService); m_UpdateInterval = updateInterval; // Get the content of the realmlist table in the database @@ -85,12 +91,41 @@ void RealmList::UpdateRealms(bool init) { try { + boost::asio::ip::tcp::resolver::iterator end; + Field* fields = result->Fetch(); uint32 realmId = fields[0].GetUInt32(); std::string name = fields[1].GetString(); - ip::address externalAddress = ip::address::from_string(fields[2].GetString()); - ip::address localAddress = ip::address::from_string(fields[3].GetString()); - ip::address localSubmask = ip::address::from_string(fields[4].GetString()); + boost::asio::ip::tcp::resolver::query externalAddressQuery(fields[2].GetString(), ""); + boost::asio::ip::tcp::resolver::iterator endPoint = _resolver->resolve(externalAddressQuery); + if (endPoint == end) + { + TC_LOG_ERROR("server.authserver", "Could not resolve address %s", fields[2].GetString().c_str()); + return; + } + + ip::address externalAddress = (*endPoint).endpoint().address(); + + boost::asio::ip::tcp::resolver::query localAddressQuery(fields[3].GetString(), ""); + endPoint = _resolver->resolve(localAddressQuery); + if (endPoint == end) + { + TC_LOG_ERROR("server.authserver", "Could not resolve address %s", fields[3].GetString().c_str()); + return; + } + + ip::address localAddress = (*endPoint).endpoint().address(); + + boost::asio::ip::tcp::resolver::query localSubmaskQuery(fields[4].GetString(), ""); + endPoint = _resolver->resolve(localSubmaskQuery); + if (endPoint == end) + { + TC_LOG_ERROR("server.authserver", "Could not resolve address %s", fields[4].GetString().c_str()); + return; + } + + ip::address localSubmask = (*endPoint).endpoint().address(); + uint16 port = fields[5].GetUInt16(); uint8 icon = fields[6].GetUInt8(); RealmFlags flag = RealmFlags(fields[7].GetUInt8()); diff --git a/src/server/authserver/Realms/RealmList.h b/src/server/authserver/Realms/RealmList.h index e8e94376c20..b1c77d5a4b5 100644 --- a/src/server/authserver/Realms/RealmList.h +++ b/src/server/authserver/Realms/RealmList.h @@ -20,6 +20,8 @@ #define _REALMLIST_H #include +#include +#include #include "Common.h" using namespace boost::asio; @@ -65,8 +67,10 @@ public: static RealmList *instance = new RealmList(); return *instance; } + + ~RealmList(); - void Initialize(uint32 updateInterval); + void Initialize(boost::asio::io_service& ioService, uint32 updateInterval); void UpdateIfNeed(); @@ -86,6 +90,7 @@ private: RealmMap m_realms; uint32 m_UpdateInterval; time_t m_NextUpdateTime; + boost::asio::ip::tcp::resolver* _resolver; }; #define sRealmList RealmList::instance() diff --git a/src/server/authserver/Server/AuthSession.cpp b/src/server/authserver/Server/AuthSession.cpp index df90339222d..f518dc7593b 100644 --- a/src/server/authserver/Server/AuthSession.cpp +++ b/src/server/authserver/Server/AuthSession.cpp @@ -19,7 +19,6 @@ #include #include #include -#include #include #include #include "ByteBuffer.h" @@ -137,7 +136,7 @@ void AuthSession::AsyncReadHeader() { auto self(shared_from_this()); - boost::asio::async_read(_socket, boost::asio::buffer(_readBuffer, 1), [this, self](boost::system::error_code error, size_t transferedBytes) + _socket.async_read_some(boost::asio::buffer(_readBuffer, 1), [this, self](boost::system::error_code error, size_t transferedBytes) { if (!error && transferedBytes == 1) { @@ -148,7 +147,7 @@ void AuthSession::AsyncReadHeader() // Handle dynamic size packet if (_readBuffer[0] == AUTH_LOGON_CHALLENGE) { - boost::asio::read(_socket, boost::asio::buffer(&_readBuffer[1], sizeof(uint8) + sizeof(uint16))); //error + size + _socket.read_some(boost::asio::buffer(&_readBuffer[1], sizeof(uint8) + sizeof(uint16))); //error + size AsyncReadData(entry.handler, *reinterpret_cast(&_readBuffer[2]), sizeof(uint8) + sizeof(uint8) + sizeof(uint16)); // cmd + error + size } @@ -171,7 +170,7 @@ void AuthSession::AsyncReadData(bool (AuthSession::*handler)(), size_t dataSize, { auto self(shared_from_this()); - boost::asio::async_read(_socket, boost::asio::buffer(&_readBuffer[bufferOffSet], dataSize), [handler, this, self](boost::system::error_code error, size_t transferedBytes) + _socket.async_read_some(boost::asio::buffer(&_readBuffer[bufferOffSet], dataSize), [handler, this, self](boost::system::error_code error, size_t transferedBytes) { if (!error && transferedBytes > 0) { -- cgit v1.2.3