diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 000000000..477e36d96 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "src/realmd"] + path = src/realmd + url = https://github.com/mangos/realmd.git diff --git a/src/realmd b/src/realmd new file mode 160000 index 000000000..548d6fca8 --- /dev/null +++ b/src/realmd @@ -0,0 +1 @@ +Subproject commit 548d6fca80a3fe3e276cf4e7d240eeb8fb99c6d6 diff --git a/src/realmd/AuthCodes.h b/src/realmd/AuthCodes.h deleted file mode 100644 index 13fb40082..000000000 --- a/src/realmd/AuthCodes.h +++ /dev/null @@ -1,97 +0,0 @@ -/** - * MaNGOS is a full featured server for World of Warcraft, supporting - * the following clients: 1.12.x, 2.4.3, 3.3.5a, 4.3.4a and 5.4.8 - * - * Copyright (C) 2005-2014 MaNGOS project - * - * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * World of Warcraft, and all World of Warcraft or Warcraft art, images, - * and lore are copyrighted by Blizzard Entertainment, Inc. - */ - -/** \file - \ingroup realmd -*/ - -#ifndef _AUTHCODES_H -#define _AUTHCODES_H - -enum eAuthCmd -{ - CMD_AUTH_LOGON_CHALLENGE = 0x00, - CMD_AUTH_LOGON_PROOF = 0x01, - CMD_AUTH_RECONNECT_CHALLENGE = 0x02, - CMD_AUTH_RECONNECT_PROOF = 0x03, - CMD_REALM_LIST = 0x10, - CMD_XFER_INITIATE = 0x30, - CMD_XFER_DATA = 0x31, - // these opcodes no longer exist in currently supported client - CMD_XFER_ACCEPT = 0x32, - CMD_XFER_RESUME = 0x33, - CMD_XFER_CANCEL = 0x34 -}; - -// not used by us currently -enum eAuthSrvCmd -{ - CMD_GRUNT_AUTH_CHALLENGE = 0x0, - CMD_GRUNT_AUTH_VERIFY = 0x2, - CMD_GRUNT_CONN_PING = 0x10, - CMD_GRUNT_CONN_PONG = 0x11, - CMD_GRUNT_HELLO = 0x20, - CMD_GRUNT_PROVESESSION = 0x21, - CMD_GRUNT_KICK = 0x24, - CMD_GRUNT_PCWARNING = 0x29, - CMD_GRUNT_STRINGS = 0x41, - CMD_GRUNT_SUNKENUPDATE = 0x44, - CMD_GRUNT_SUNKEN_ONLINE = 0x46 -}; - -enum AuthResult -{ - WOW_SUCCESS = 0x00, - WOW_FAIL_UNKNOWN0 = 0x01, ///< ? Unable to connect - WOW_FAIL_UNKNOWN1 = 0x02, ///< ? Unable to connect - WOW_FAIL_BANNED = 0x03, ///< This account has been closed and is no longer available for use. Please go to /banned.html for further information. - WOW_FAIL_UNKNOWN_ACCOUNT = 0x04, ///< The information you have entered is not valid. Please check the spelling of the account name and password. If you need help in retrieving a lost or stolen password, see for more information - WOW_FAIL_INCORRECT_PASSWORD = 0x05, ///< The information you have entered is not valid. Please check the spelling of the account name and password. If you need help in retrieving a lost or stolen password, see for more information - // client reject next login attempts after this error, so in code used WOW_FAIL_UNKNOWN_ACCOUNT for both cases - WOW_FAIL_ALREADY_ONLINE = 0x06, ///< This account is already logged into . Please check the spelling and try again. - WOW_FAIL_NO_TIME = 0x07, ///< You have used up your prepaid time for this account. Please purchase more to continue playing - WOW_FAIL_DB_BUSY = 0x08, ///< Could not log in to at this time. Please try again later. - WOW_FAIL_VERSION_INVALID = 0x09, ///< Unable to validate game version. This may be caused by file corruption or interference of another program. Please visit for more information and possible solutions to this issue. - WOW_FAIL_VERSION_UPDATE = 0x0A, ///< Downloading - WOW_FAIL_INVALID_SERVER = 0x0B, ///< Unable to connect - WOW_FAIL_SUSPENDED = 0x0C, ///< This account has been temporarily suspended. Please go to /banned.html for further information - WOW_FAIL_FAIL_NOACCESS = 0x0D, ///< Unable to connect - WOW_SUCCESS_SURVEY = 0x0E, ///< Connected. - WOW_FAIL_PARENTCONTROL = 0x0F, ///< Access to this account has been blocked by parental controls. Your settings may be changed in your account preferences at - WOW_FAIL_LOCKED_ENFORCED = 0x10, ///< You have applied a lock to your account. You can change your locked status by calling your account lock phone number. - WOW_FAIL_TRIAL_ENDED = 0x11, ///< Your trial subscription has expired. Please visit to upgrade your account. - WOW_FAIL_USE_BATTLENET = 0x12, ///< WOW_FAIL_OTHER This account is now attached to a Battle.net account. Please login with your Battle.net account email address and password. - // WOW_FAIL_OVERMIND_CONVERTED - // WOW_FAIL_ANTI_INDULGENCE - // WOW_FAIL_EXPIRED - // WOW_FAIL_NO_GAME_ACCOUNT - // WOW_FAIL_BILLING_LOCK - // WOW_FAIL_IGR_WITHOUT_BNET - // WOW_FAIL_AA_LOCK - // WOW_FAIL_UNLOCKABLE_LOCK - // WOW_FAIL_MUST_USE_BNET - // WOW_FAIL_OTHER -}; - -#endif diff --git a/src/realmd/AuthSocket.cpp b/src/realmd/AuthSocket.cpp deleted file mode 100644 index b8fe86b65..000000000 --- a/src/realmd/AuthSocket.cpp +++ /dev/null @@ -1,1107 +0,0 @@ -/** - * MaNGOS is a full featured server for World of Warcraft, supporting - * the following clients: 1.12.x, 2.4.3, 3.3.5a, 4.3.4a and 5.4.8 - * - * Copyright (C) 2005-2014 MaNGOS project - * - * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * World of Warcraft, and all World of Warcraft or Warcraft art, images, - * and lore are copyrighted by Blizzard Entertainment, Inc. - */ - -/** \file - \ingroup realmd -*/ - -#include "Common.h" -#include "Database/DatabaseEnv.h" -#include "Config/Config.h" -#include "Log.h" -#include "RealmList.h" -#include "AuthSocket.h" -#include "AuthCodes.h" -#include "PatchHandler.h" - -#include -//#include "Util.h" -- for commented utf8ToUpperOnlyLatin - -#include -#include -#include - -extern DatabaseType LoginDatabase; - -enum eStatus -{ - STATUS_CONNECTED = 0, - STATUS_AUTHED -}; - -enum AccountFlags -{ - ACCOUNT_FLAG_GM = 0x00000001, - ACCOUNT_FLAG_TRIAL = 0x00000008, - ACCOUNT_FLAG_PROPASS = 0x00800000, -}; - -// GCC have alternative #pragma pack(N) syntax and old gcc version not support pack(push,N), also any gcc version not support it at some paltform -#if defined( __GNUC__ ) -#pragma pack(1) -#else -#pragma pack(push,1) -#endif - -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 sAuthLogonChallenge_C sAuthReconnectChallenge_C; -/* -typedef struct -{ - uint8 cmd; - uint8 error; - uint8 unk2; - uint8 B[32]; - uint8 g_len; - uint8 g[1]; - uint8 N_len; - uint8 N[32]; - uint8 s[32]; - uint8 unk3[16]; -} sAuthLogonChallenge_S; -*/ - -typedef struct AUTH_LOGON_PROOF_C -{ - uint8 cmd; - uint8 A[32]; - uint8 M1[20]; - uint8 crc_hash[20]; - uint8 number_of_keys; - uint8 securityFlags; // 0x00-0x04 -} sAuthLogonProof_C; -/* -typedef struct -{ - uint16 unk1; - uint32 unk2; - uint8 unk3[4]; - uint16 unk4[20]; -} sAuthLogonProofKey_C; -*/ -typedef struct AUTH_LOGON_PROOF_S -{ - uint8 cmd; - uint8 error; - uint8 M2[20]; - uint32 accountFlags; // see enum AccountFlags - uint32 surveyId; // SurveyId - uint16 unkFlags; // some flags (AccountMsgAvailable = 0x01) -} sAuthLogonProof_S; - -typedef struct AUTH_LOGON_PROOF_S_BUILD_6005 -{ - uint8 cmd; - uint8 error; - uint8 M2[20]; - // uint32 unk1; - uint32 unk2; - // uint16 unk3; -} sAuthLogonProof_S_BUILD_6005; - -typedef struct AUTH_RECONNECT_PROOF_C -{ - uint8 cmd; - uint8 R1[16]; - uint8 R2[20]; - uint8 R3[20]; - uint8 number_of_keys; -} sAuthReconnectProof_C; - -typedef struct XFER_INIT -{ - uint8 cmd; // XFER_INITIATE - uint8 fileNameLen; // strlen(fileName); - uint8 fileName[5]; // fileName[fileNameLen] - uint64 file_size; // file size (bytes) - uint8 md5[MD5_DIGEST_LENGTH]; // MD5 -} XFER_INIT; - -typedef struct AuthHandler -{ - eAuthCmd cmd; - uint32 status; - bool (AuthSocket::*handler)(void); -} AuthHandler; - -// GCC have alternative #pragma pack() syntax and old gcc version not support pack(pop), also any gcc version not support it at some paltform -#if defined( __GNUC__ ) -#pragma pack() -#else -#pragma pack(pop) -#endif - -const AuthHandler table[] = -{ - { CMD_AUTH_LOGON_CHALLENGE, STATUS_CONNECTED, &AuthSocket::_HandleLogonChallenge }, - { CMD_AUTH_LOGON_PROOF, STATUS_CONNECTED, &AuthSocket::_HandleLogonProof }, - { CMD_AUTH_RECONNECT_CHALLENGE, STATUS_CONNECTED, &AuthSocket::_HandleReconnectChallenge}, - { CMD_AUTH_RECONNECT_PROOF, STATUS_CONNECTED, &AuthSocket::_HandleReconnectProof }, - { CMD_REALM_LIST, STATUS_AUTHED, &AuthSocket::_HandleRealmList }, - { CMD_XFER_ACCEPT, STATUS_CONNECTED, &AuthSocket::_HandleXferAccept }, - { CMD_XFER_RESUME, STATUS_CONNECTED, &AuthSocket::_HandleXferResume }, - { CMD_XFER_CANCEL, STATUS_CONNECTED, &AuthSocket::_HandleXferCancel } -}; - -#define AUTH_TOTAL_COMMANDS sizeof(table)/sizeof(AuthHandler) - -/// Constructor - set the N and g values for SRP6 -AuthSocket::AuthSocket() -{ - N.SetHexStr("894B645E89E1535BBDAD5B8B290650530801B18EBFBF5E8FAB3C82872A3E9BB7"); - g.SetDword(7); - _authed = false; - - _accountSecurityLevel = SEC_PLAYER; - - _build = 0; - patch_ = ACE_INVALID_HANDLE; -} - -/// Close patch file descriptor before leaving -AuthSocket::~AuthSocket() -{ - if (patch_ != ACE_INVALID_HANDLE) - ACE_OS::close(patch_); -} - -/// Accept the connection and set the s random value for SRP6 -void AuthSocket::OnAccept() -{ - BASIC_LOG("Accepting connection from '%s'", get_remote_address().c_str()); -} - -/// Read the packet from the client -void AuthSocket::OnRead() -{ - uint8 _cmd; - while (1) - { - if (!recv_soft((char*)&_cmd, 1)) - return; - - size_t i; - - ///- Circle through known commands and call the correct command handler - for (i = 0; i < AUTH_TOTAL_COMMANDS; ++i) - { - if ((uint8)table[i].cmd == _cmd && - (table[i].status == STATUS_CONNECTED || - (_authed && table[i].status == STATUS_AUTHED))) - { - DEBUG_LOG("[Auth] got data for cmd %u recv length %u", - (uint32)_cmd, (uint32)recv_len()); - - if (!(*this.*table[i].handler)()) - { - DEBUG_LOG("Command handler failed for cmd %u recv length %u", - (uint32)_cmd, (uint32)recv_len()); - - return; - } - break; - } - } - - ///- Report unknown commands in the debug log - if (i == AUTH_TOTAL_COMMANDS) - { - DEBUG_LOG("[Auth] got unknown packet %u", (uint32)_cmd); - return; - } - } -} - -/// Make the SRP6 calculation from hash in dB -void AuthSocket::_SetVSFields(const std::string& rI) -{ - s.SetRand(s_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(), I.GetNumBytes()); - - std::reverse(mDigest, mDigest + SHA_DIGEST_LENGTH); - - Sha1Hash sha; - sha.UpdateData(s.AsByteArray(), 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) - const char* v_hex, *s_hex; - v_hex = v.AsHexStr(); - s_hex = s.AsHexStr(); - LoginDatabase.PExecute("UPDATE account SET v = '%s', s = '%s' WHERE username = '%s'", v_hex, s_hex, _safelogin.c_str()); - OPENSSL_free((void*)v_hex); - OPENSSL_free((void*)s_hex); -} - -void AuthSocket::SendProof(Sha1Hash sha) -{ - switch (_build) - { - case 5875: // 1.12.1 - case 6005: // 1.12.2 - case 6141: // 1.12.3 - { - sAuthLogonProof_S_BUILD_6005 proof; - memcpy(proof.M2, sha.GetDigest(), 20); - proof.cmd = CMD_AUTH_LOGON_PROOF; - proof.error = 0; - proof.unk2 = 0x00; - - send((char*)&proof, sizeof(proof)); - break; - } - case 8606: // 2.4.3 - case 10505: // 3.2.2a - case 11159: // 3.3.0a - case 11403: // 3.3.2 - case 11723: // 3.3.3a - case 12340: // 3.3.5a - case 13623: // 4.0.6a - case 15050: // 4.3.0 - case 15595: // 4.3.4 - default: // or later - { - sAuthLogonProof_S proof; - memcpy(proof.M2, sha.GetDigest(), 20); - proof.cmd = CMD_AUTH_LOGON_PROOF; - proof.error = 0; - proof.accountFlags = ACCOUNT_FLAG_PROPASS; - proof.surveyId = 0x00000000; - proof.unkFlags = 0x0000; - - send((char*)&proof, sizeof(proof)); - break; - } - } -} - -/// Logon Challenge command handler -bool AuthSocket::_HandleLogonChallenge() -{ - DEBUG_LOG("Entering _HandleLogonChallenge"); - if (recv_len() < sizeof(sAuthLogonChallenge_C)) - return false; - - ///- Read the first 4 bytes (header) to get the length of the remaining of the packet - std::vector buf; - buf.resize(4); - - recv((char*)&buf[0], 4); - - EndianConvert(*((uint16*)(buf[0]))); - uint16 remaining = ((sAuthLogonChallenge_C*)&buf[0])->size; - DEBUG_LOG("[AuthChallenge] got header, body is %#04x bytes", remaining); - - if ((remaining < sizeof(sAuthLogonChallenge_C) - buf.size()) || (recv_len() < remaining)) - return false; - - // No big fear of memory outage (size is int16, i.e. < 65536) - buf.resize(remaining + buf.size() + 1); - buf[buf.size() - 1] = 0; - sAuthLogonChallenge_C* ch = (sAuthLogonChallenge_C*)&buf[0]; - - ///- Read the remaining of the packet - recv((char*)&buf[4], remaining); - DEBUG_LOG("[AuthChallenge] got full packet, %#04x bytes", ch->size); - DEBUG_LOG("[AuthChallenge] name(%d): '%s'", ch->I_len, ch->I); - - // BigEndian code, nop in little endian case - // size already converted - EndianConvert(*((uint32*)(&ch->gamename[0]))); - EndianConvert(ch->build); - EndianConvert(*((uint32*)(&ch->platform[0]))); - EndianConvert(*((uint32*)(&ch->os[0]))); - EndianConvert(*((uint32*)(&ch->country[0]))); - EndianConvert(ch->timezone_bias); - EndianConvert(ch->ip); - - ByteBuffer pkt; - - _login = (const char*)ch->I; - _build = ch->build; - - ///- Normalize account name - // utf8ToUpperOnlyLatin(_login); -- client already send account in expected form - - // Escape the user login to avoid further SQL injection - // Memory will be freed on AuthSocket object destruction - _safelogin = _login; - LoginDatabase.escape_string(_safelogin); - - pkt << (uint8) CMD_AUTH_LOGON_CHALLENGE; - pkt << (uint8) 0x00; - - ///- Verify that this IP is not in the ip_banned table - // No SQL injection possible (paste the IP address as passed by the socket) - std::string address = get_remote_address(); - LoginDatabase.escape_string(address); - QueryResult* result = LoginDatabase.PQuery("SELECT unbandate FROM ip_banned WHERE " - // permanent still banned - "(unbandate = bandate OR unbandate > UNIX_TIMESTAMP()) AND ip = '%s'", address.c_str()); - if (result) - { - pkt << (uint8)WOW_FAIL_BANNED; - BASIC_LOG("[AuthChallenge] Banned ip %s tries to login!", get_remote_address().c_str()); - delete result; - } - else - { - ///- Get the account details from the account table - // No SQL injection (escaped user name) - - result = LoginDatabase.PQuery("SELECT sha_pass_hash,id,locked,last_ip,gmlevel,v,s FROM account WHERE username = '%s'", _safelogin.c_str()); - if (result) - { - ///- If the IP is 'locked', check that the player comes indeed from the correct IP address - bool locked = false; - if ((*result)[2].GetUInt8() == 1) // if ip is locked - { - DEBUG_LOG("[AuthChallenge] Account '%s' is locked to IP - '%s'", _login.c_str(), (*result)[3].GetString()); - DEBUG_LOG("[AuthChallenge] Player address is '%s'", get_remote_address().c_str()); - if (strcmp((*result)[3].GetString(), get_remote_address().c_str())) - { - DEBUG_LOG("[AuthChallenge] Account IP differs"); - pkt << (uint8) WOW_FAIL_SUSPENDED; - locked = true; - } - else - { - DEBUG_LOG("[AuthChallenge] Account IP matches"); - } - } - else - { - DEBUG_LOG("[AuthChallenge] Account '%s' is not locked to ip", _login.c_str()); - } - - if (!locked) - { - ///- If the account is banned, reject the logon attempt - QueryResult* banresult = LoginDatabase.PQuery("SELECT bandate,unbandate FROM account_banned WHERE " - "id = %u AND active = 1 AND (unbandate > UNIX_TIMESTAMP() OR unbandate = bandate)", (*result)[1].GetUInt32()); - if (banresult) - { - if ((*banresult)[0].GetUInt64() == (*banresult)[1].GetUInt64()) - { - pkt << (uint8) WOW_FAIL_BANNED; - BASIC_LOG("[AuthChallenge] Banned account %s tries to login!", _login.c_str()); - } - else - { - pkt << (uint8) WOW_FAIL_SUSPENDED; - BASIC_LOG("[AuthChallenge] Temporarily banned account %s tries to login!", _login.c_str()); - } - - delete banresult; - } - else - { - ///- Get the password from the account table, upper it, and make the SRP6 calculation - std::string rI = (*result)[0].GetCppString(); - - ///- Don't calculate (v, s) if there are already some in the database - std::string databaseV = (*result)[5].GetCppString(); - std::string databaseS = (*result)[6].GetCppString(); - - DEBUG_LOG("database authentication values: v='%s' s='%s'", databaseV.c_str(), databaseS.c_str()); - - // multiply with 2, bytes are stored as hexstring - if (databaseV.size() != s_BYTE_SIZE * 2 || databaseS.size() != s_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; - - MANGOS_ASSERT(gmod.GetNumBytes() <= 32); - - BigNumber unk3; - unk3.SetRand(16 * 8); - - ///- Fill the response packet with the result - pkt << uint8(WOW_SUCCESS); - - // B may be calculated < 32B so we force minimal length to 32B - pkt.append(B.AsByteArray(32), 32); // 32 bytes - pkt << uint8(1); - pkt.append(g.AsByteArray(), 1); - pkt << uint8(32); - pkt.append(N.AsByteArray(32), 32); - pkt.append(s.AsByteArray(), s.GetNumBytes());// 32 bytes - pkt.append(unk3.AsByteArray(16), 16); - uint8 securityFlags = 0; - 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 = (*result)[4].GetUInt8(); - _accountSecurityLevel = secLevel <= SEC_ADMINISTRATOR ? AccountTypes(secLevel) : SEC_ADMINISTRATOR; - - _localizationName.resize(4); - for (int i = 0; i < 4; ++i) - _localizationName[i] = ch->country[4 - i - 1]; - - BASIC_LOG("[AuthChallenge] account %s is using '%c%c%c%c' locale (%u)", _login.c_str(), ch->country[3], ch->country[2], ch->country[1], ch->country[0], GetLocaleByName(_localizationName)); - } - } - delete result; - } - else // no account - { - pkt << (uint8) WOW_FAIL_UNKNOWN_ACCOUNT; - } - } - send((char const*)pkt.contents(), pkt.size()); - return true; -} - -/// Logon Proof command handler -bool AuthSocket::_HandleLogonProof() -{ - DEBUG_LOG("Entering _HandleLogonProof"); - ///- Read the packet - sAuthLogonProof_C lp; - if (!recv((char*)&lp, sizeof(sAuthLogonProof_C))) - return false; - - ///- Check if the client has one of the expected version numbers - bool valid_version = FindBuildInfo(_build) != NULL; - - ///
  • If the client has no valid version - if (!valid_version) - { - if (this->patch_ != ACE_INVALID_HANDLE) - return false; - - ///- Check if we have the apropriate patch on the disk - // file looks like: 65535enGB.mpq - char tmp[64]; - - snprintf(tmp, 24, "./patches/%d%s.mpq", _build, _localizationName.c_str()); - - char filename[PATH_MAX]; - if (ACE_OS::realpath(tmp, filename) != NULL) - { - patch_ = ACE_OS::open(filename, GENERIC_READ | FILE_FLAG_SEQUENTIAL_SCAN); - } - - if (patch_ == ACE_INVALID_HANDLE) - { - // no patch found - ByteBuffer pkt; - pkt << (uint8) CMD_AUTH_LOGON_CHALLENGE; - pkt << (uint8) 0x00; - pkt << (uint8) WOW_FAIL_VERSION_INVALID; - DEBUG_LOG("[AuthChallenge] %u is not a valid client version!", _build); - DEBUG_LOG("[AuthChallenge] Patch %s not found", tmp); - send((char const*)pkt.contents(), pkt.size()); - return true; - } - - XFER_INIT xferh; - - ACE_OFF_T file_size = ACE_OS::filesize(this->patch_); - - if (file_size == -1) - { - close_connection(); - return false; - } - - if (!PatchCache::instance()->GetHash(tmp, (uint8*)&xferh.md5)) - { - // calculate patch md5, happens if patch was added while realmd was running - PatchCache::instance()->LoadPatchMD5(tmp); - PatchCache::instance()->GetHash(tmp, (uint8*)&xferh.md5); - } - - uint8 data[2] = { CMD_AUTH_LOGON_PROOF, WOW_FAIL_VERSION_UPDATE}; - send((const char*)data, sizeof(data)); - - memcpy(&xferh, "0\x05Patch", 7); - xferh.cmd = CMD_XFER_INITIATE; - xferh.file_size = file_size; - - send((const char*)&xferh, sizeof(xferh)); - return true; - } - ///
- - ///- Continue the SRP6 calculation based on data received from the client - BigNumber A; - - A.SetBinary(lp.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), 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(), lp.M1, 20)) - { - BASIC_LOG("User '%s' successfully authenticated", _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(); - LoginDatabase.PExecute("UPDATE account SET sessionkey = '%s', last_ip = '%s', last_login = NOW(), locale = '%u', failed_logins = 0 WHERE username = '%s'", K_hex, get_remote_address().c_str(), GetLocaleByName(_localizationName), _safelogin.c_str()); - 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(); - - SendProof(sha); - - ///- Set _authed to true! - _authed = true; - } - else - { - if (_build > 6005) // > 1.12.2 - { - char data[4] = { CMD_AUTH_LOGON_PROOF, WOW_FAIL_UNKNOWN_ACCOUNT, 3, 0}; - send(data, sizeof(data)); - } - else - { - // 1.x not react incorrectly at 4-byte message use 3 as real error - char data[2] = { CMD_AUTH_LOGON_PROOF, WOW_FAIL_UNKNOWN_ACCOUNT}; - send(data, sizeof(data)); - } - BASIC_LOG("[AuthChallenge] account %s tried to login with wrong password!", _login.c_str()); - - uint32 MaxWrongPassCount = sConfig.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 - LoginDatabase.PExecute("UPDATE account SET failed_logins = failed_logins + 1 WHERE username = '%s'", _safelogin.c_str()); - - if (QueryResult* loginfail = LoginDatabase.PQuery("SELECT id, failed_logins FROM account WHERE username = '%s'", _safelogin.c_str())) - { - Field* fields = loginfail->Fetch(); - uint32 failed_logins = fields[1].GetUInt32(); - - if (failed_logins >= MaxWrongPassCount) - { - uint32 WrongPassBanTime = sConfig.GetIntDefault("WrongPass.BanTime", 600); - bool WrongPassBanType = sConfig.GetBoolDefault("WrongPass.BanType", false); - - if (WrongPassBanType) - { - uint32 acc_id = fields[0].GetUInt32(); - LoginDatabase.PExecute("INSERT INTO account_banned VALUES ('%u',UNIX_TIMESTAMP(),UNIX_TIMESTAMP()+'%u','MaNGOS realmd','Failed login autoban',1)", - acc_id, WrongPassBanTime); - BASIC_LOG("[AuthChallenge] account %s got banned for '%u' seconds because it failed to authenticate '%u' times", - _login.c_str(), WrongPassBanTime, failed_logins); - } - else - { - std::string current_ip = get_remote_address(); - LoginDatabase.escape_string(current_ip); - LoginDatabase.PExecute("INSERT INTO ip_banned VALUES ('%s',UNIX_TIMESTAMP(),UNIX_TIMESTAMP()+'%u','MaNGOS realmd','Failed login autoban')", - current_ip.c_str(), WrongPassBanTime); - BASIC_LOG("[AuthChallenge] IP %s got banned for '%u' seconds because account %s failed to authenticate '%u' times", - current_ip.c_str(), WrongPassBanTime, _login.c_str(), failed_logins); - } - } - delete loginfail; - } - } - } - return true; -} - -/// Reconnect Challenge command handler -bool AuthSocket::_HandleReconnectChallenge() -{ - DEBUG_LOG("Entering _HandleReconnectChallenge"); - if (recv_len() < sizeof(sAuthLogonChallenge_C)) - return false; - - ///- Read the first 4 bytes (header) to get the length of the remaining of the packet - std::vector buf; - buf.resize(4); - - recv((char*)&buf[0], 4); - - EndianConvert(*((uint16*)(buf[0]))); - uint16 remaining = ((sAuthLogonChallenge_C*)&buf[0])->size; - DEBUG_LOG("[ReconnectChallenge] got header, body is %#04x bytes", remaining); - - if ((remaining < sizeof(sAuthLogonChallenge_C) - buf.size()) || (recv_len() < remaining)) - return false; - - // No big fear of memory outage (size is int16, i.e. < 65536) - buf.resize(remaining + buf.size() + 1); - buf[buf.size() - 1] = 0; - sAuthLogonChallenge_C* ch = (sAuthLogonChallenge_C*)&buf[0]; - - ///- Read the remaining of the packet - recv((char*)&buf[4], remaining); - DEBUG_LOG("[ReconnectChallenge] got full packet, %#04x bytes", ch->size); - DEBUG_LOG("[ReconnectChallenge] name(%d): '%s'", ch->I_len, ch->I); - - _login = (const char*)ch->I; - - _safelogin = _login; - LoginDatabase.escape_string(_safelogin); - - EndianConvert(ch->build); - _build = ch->build; - - QueryResult* result = LoginDatabase.PQuery("SELECT sessionkey FROM account WHERE username = '%s'", _safelogin.c_str()); - - // Stop if the account is not found - if (!result) - { - sLog.outError("[ERROR] user %s tried to login and we cannot find his session key in the database.", _login.c_str()); - close_connection(); - return false; - } - - Field* fields = result->Fetch(); - K.SetHexStr(fields[0].GetString()); - delete result; - - ///- Sending response - ByteBuffer pkt; - pkt << (uint8) CMD_AUTH_RECONNECT_CHALLENGE; - pkt << (uint8) 0x00; - _reconnectProof.SetRand(16 * 8); - pkt.append(_reconnectProof.AsByteArray(16), 16); // 16 bytes random - pkt << (uint64) 0x00 << (uint64) 0x00; // 16 bytes zeros - send((char const*)pkt.contents(), pkt.size()); - return true; -} - -/// Reconnect Proof command handler -bool AuthSocket::_HandleReconnectProof() -{ - DEBUG_LOG("Entering _HandleReconnectProof"); - ///- Read the packet - sAuthReconnectProof_C lp; - if (!recv((char*)&lp, sizeof(sAuthReconnectProof_C))) - return false; - - if (_login.empty() || !_reconnectProof.GetNumBytes() || !K.GetNumBytes()) - return false; - - BigNumber t1; - t1.SetBinary(lp.R1, 16); - - Sha1Hash sha; - sha.Initialize(); - sha.UpdateData(_login); - sha.UpdateBigNumbers(&t1, &_reconnectProof, &K, NULL); - sha.Finalize(); - - if (!memcmp(sha.GetDigest(), lp.R2, SHA_DIGEST_LENGTH)) - { - ///- Sending response - ByteBuffer pkt; - pkt << (uint8) CMD_AUTH_RECONNECT_PROOF; - pkt << (uint8) 0x00; - if (_build > 6141) // Last vanilla, 1.12.3 - pkt << (uint16) 0x00; // 2 bytes zeros - send((char const*)pkt.contents(), pkt.size()); - - ///- Set _authed to true! - _authed = true; - - return true; - } - else - { - sLog.outError("[ERROR] user %s tried to login, but session invalid.", _login.c_str()); - close_connection(); - return false; - } -} - -/// %Realm List command handler -bool AuthSocket::_HandleRealmList() -{ - DEBUG_LOG("Entering _HandleRealmList"); - if (recv_len() < 5) - return false; - - recv_skip(5); - - ///- Get the user id (else close the connection) - // No SQL injection (escaped user name) - - QueryResult* result = LoginDatabase.PQuery("SELECT id,sha_pass_hash FROM account WHERE username = '%s'", _safelogin.c_str()); - if (!result) - { - sLog.outError("[ERROR] user %s tried to login and we cannot find him in the database.", _login.c_str()); - close_connection(); - return false; - } - - uint32 id = (*result)[0].GetUInt32(); - std::string rI = (*result)[1].GetCppString(); - delete result; - - ///- 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; - LoadRealmlist(pkt, id); - - ByteBuffer hdr; - hdr << (uint8) CMD_REALM_LIST; - hdr << (uint16)pkt.size(); - hdr.append(pkt); - - send((char const*)hdr.contents(), hdr.size()); - - return true; -} - -void AuthSocket::LoadRealmlist(ByteBuffer& pkt, uint32 acctid) -{ - switch (_build) - { - case 5875: // 1.12.1 - case 6005: // 1.12.2 - case 6141: // 1.12.3 - { - pkt << uint32(0); // unused value - pkt << uint8(sRealmList.size()); - - for (RealmList::RealmMap::const_iterator i = sRealmList.begin(); i != sRealmList.end(); ++i) - { - uint8 AmountOfCharacters; - - // No SQL injection. id of realm is controlled by the database. - QueryResult* result = LoginDatabase.PQuery("SELECT numchars FROM realmcharacters WHERE realmid = '%d' AND acctid='%u'", i->second.m_ID, acctid); - if (result) - { - Field* fields = result->Fetch(); - AmountOfCharacters = fields[0].GetUInt8(); - delete result; - } - else - AmountOfCharacters = 0; - - bool ok_build = std::find(i->second.realmbuilds.begin(), i->second.realmbuilds.end(), _build) != i->second.realmbuilds.end(); - - RealmBuildInfo const* buildInfo = ok_build ? FindBuildInfo(_build) : NULL; - if (!buildInfo) - buildInfo = &i->second.realmBuildInfo; - - RealmFlags realmflags = i->second.realmflags; - - // 1.x clients not support explicitly REALM_FLAG_SPECIFYBUILD, so manually form similar name as show in more recent clients - std::string name = i->first; - if (realmflags & REALM_FLAG_SPECIFYBUILD) - { - char buf[20]; - snprintf(buf, 20, " (%u,%u,%u)", buildInfo->major_version, buildInfo->minor_version, buildInfo->bugfix_version); - name += buf; - } - - // Show offline state for unsupported client builds and locked realms (1.x clients not support locked state show) - if (!ok_build || (i->second.allowedSecurityLevel > _accountSecurityLevel)) - realmflags = RealmFlags(realmflags | REALM_FLAG_OFFLINE); - - pkt << uint32(i->second.icon); // realm type - pkt << uint8(realmflags); // realmflags - pkt << name; // name - pkt << i->second.address; // address - pkt << float(i->second.populationLevel); - pkt << uint8(AmountOfCharacters); - pkt << uint8(i->second.timezone); // realm category - pkt << uint8(0x00); // unk, may be realm number/id? - } - - pkt << uint16(0x0002); // unused value (why 2?) - break; - } - - case 8606: // 2.4.3 - case 10505: // 3.2.2a - case 11159: // 3.3.0a - case 11403: // 3.3.2 - case 11723: // 3.3.3a - case 12340: // 3.3.5a - case 13623: // 4.0.6a - case 15050: // 4.3.0 - case 15595: // 4.3.4 - default: // and later - { - pkt << uint32(0); // unused value - pkt << uint16(sRealmList.size()); - - for (RealmList::RealmMap::const_iterator i = sRealmList.begin(); i != sRealmList.end(); ++i) - { - uint8 AmountOfCharacters; - - // No SQL injection. id of realm is controlled by the database. - QueryResult* result = LoginDatabase.PQuery("SELECT numchars FROM realmcharacters WHERE realmid = '%d' AND acctid='%u'", i->second.m_ID, acctid); - if (result) - { - Field* fields = result->Fetch(); - AmountOfCharacters = fields[0].GetUInt8(); - delete result; - } - else - AmountOfCharacters = 0; - - bool ok_build = std::find(i->second.realmbuilds.begin(), i->second.realmbuilds.end(), _build) != i->second.realmbuilds.end(); - - RealmBuildInfo const* buildInfo = ok_build ? FindBuildInfo(_build) : NULL; - if (!buildInfo) - buildInfo = &i->second.realmBuildInfo; - - uint8 lock = (i->second.allowedSecurityLevel > _accountSecurityLevel) ? 1 : 0; - - RealmFlags realmFlags = i->second.realmflags; - - // Show offline state for unsupported client builds - if (!ok_build) - realmFlags = RealmFlags(realmFlags | REALM_FLAG_OFFLINE); - - if (!buildInfo) - realmFlags = RealmFlags(realmFlags & ~REALM_FLAG_SPECIFYBUILD); - - pkt << uint8(i->second.icon); // realm type (this is second column in Cfg_Configs.dbc) - pkt << uint8(lock); // flags, if 0x01, then realm locked - pkt << uint8(realmFlags); // see enum RealmFlags - pkt << i->first; // name - pkt << i->second.address; // address - pkt << float(i->second.populationLevel); - pkt << uint8(AmountOfCharacters); - pkt << uint8(i->second.timezone); // realm category (Cfg_Categories.dbc) - pkt << uint8(0x2C); // unk, may be realm number/id? - - if (realmFlags & REALM_FLAG_SPECIFYBUILD) - { - pkt << uint8(buildInfo->major_version); - pkt << uint8(buildInfo->minor_version); - pkt << uint8(buildInfo->bugfix_version); - pkt << uint16(_build); - } - } - - pkt << uint16(0x0010); // unused value (why 10?) - break; - } - } -} - -/// Resume patch transfer -bool AuthSocket::_HandleXferResume() -{ - DEBUG_LOG("Entering _HandleXferResume"); - - if (recv_len() < 9) - return false; - - recv_skip(1); - - uint64 start_pos; - recv((char*)&start_pos, 8); - - if (patch_ == ACE_INVALID_HANDLE) - { - close_connection(); - return false; - } - - ACE_OFF_T file_size = ACE_OS::filesize(patch_); - - if (file_size == -1 || start_pos >= (uint64)file_size) - { - close_connection(); - return false; - } - - if (ACE_OS::lseek(patch_, start_pos, SEEK_SET) == -1) - { - close_connection(); - return false; - } - - InitPatch(); - - return true; -} - -/// Cancel patch transfer -bool AuthSocket::_HandleXferCancel() -{ - DEBUG_LOG("Entering _HandleXferCancel"); - - recv_skip(1); - close_connection(); - - return true; -} - -/// Accept patch transfer -bool AuthSocket::_HandleXferAccept() -{ - DEBUG_LOG("Entering _HandleXferAccept"); - - recv_skip(1); - - InitPatch(); - - return true; -} - -void AuthSocket::InitPatch() -{ - PatchHandler* handler = new PatchHandler(ACE_OS::dup(get_handle()), patch_); - - patch_ = ACE_INVALID_HANDLE; - - if (handler->open() == -1) - { - handler->close(); - close_connection(); - } -} - diff --git a/src/realmd/AuthSocket.h b/src/realmd/AuthSocket.h deleted file mode 100644 index 0453e393d..000000000 --- a/src/realmd/AuthSocket.h +++ /dev/null @@ -1,89 +0,0 @@ -/** - * MaNGOS is a full featured server for World of Warcraft, supporting - * the following clients: 1.12.x, 2.4.3, 3.3.5a, 4.3.4a and 5.4.8 - * - * Copyright (C) 2005-2014 MaNGOS project - * - * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * World of Warcraft, and all World of Warcraft or Warcraft art, images, - * and lore are copyrighted by Blizzard Entertainment, Inc. - */ - -/// \addtogroup realmd -/// @{ -/// \file - -#ifndef _AUTHSOCKET_H -#define _AUTHSOCKET_H - -#include "Common.h" -#include "Auth/BigNumber.h" -#include "Auth/Sha1.h" -#include "ByteBuffer.h" - -#include "BufferedSocket.h" - -/// Handle login commands -class AuthSocket: public BufferedSocket -{ - public: - const static int s_BYTE_SIZE = 32; - - AuthSocket(); - ~AuthSocket(); - - void OnAccept() override; - void OnRead() override; - void SendProof(Sha1Hash sha); - void LoadRealmlist(ByteBuffer& pkt, uint32 acctid); - - bool _HandleLogonChallenge(); - bool _HandleLogonProof(); - bool _HandleReconnectChallenge(); - bool _HandleReconnectProof(); - bool _HandleRealmList(); - // data transfer handle for patch - - bool _HandleXferResume(); - bool _HandleXferCancel(); - bool _HandleXferAccept(); - - void _SetVSFields(const std::string& rI); - - private: - - BigNumber N, s, g, v; - BigNumber b, B; - BigNumber K; - BigNumber _reconnectProof; - - bool _authed; - - std::string _login; - std::string _safelogin; - - // Since GetLocaleByName() is _NOT_ bijective, we have to store the locale as a string. Otherwise we can't differ - // between enUS and enGB, which is important for the patch system - std::string _localizationName; - uint16 _build; - AccountTypes _accountSecurityLevel; - - ACE_HANDLE patch_; - - void InitPatch(); -}; -#endif -/// @} diff --git a/src/realmd/BufferedSocket.cpp b/src/realmd/BufferedSocket.cpp deleted file mode 100644 index ca3361aa3..000000000 --- a/src/realmd/BufferedSocket.cpp +++ /dev/null @@ -1,274 +0,0 @@ -/** - * MaNGOS is a full featured server for World of Warcraft, supporting - * the following clients: 1.12.x, 2.4.3, 3.3.5a, 4.3.4a and 5.4.8 - * - * Copyright (C) 2005-2014 MaNGOS project - * - * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * World of Warcraft, and all World of Warcraft or Warcraft art, images, - * and lore are copyrighted by Blizzard Entertainment, Inc. - */ - -/** \file - \ingroup realmd - */ - -#include "Common.h" -#include "BufferedSocket.h" - -#include -#include -#include - -#ifndef MSG_NOSIGNAL -#define MSG_NOSIGNAL 0 -#endif - -BufferedSocket::BufferedSocket(void): - input_buffer_(4096), - remote_address_("") -{ -} - -/*virtual*/ BufferedSocket::~BufferedSocket(void) -{ -} - -/*virtual*/ int BufferedSocket::open(void* arg) -{ - if (Base::open(arg) == -1) - return -1; - - ACE_INET_Addr addr; - - if (peer().get_remote_addr(addr) == -1) - return -1; - - char address[1024]; - - addr.get_host_addr(address, 1024); - - this->remote_address_ = address; - - this->OnAccept(); - - return 0; -} - -const std::string& BufferedSocket::get_remote_address(void) const -{ - return this->remote_address_; -} - -size_t BufferedSocket::recv_len(void) const -{ - return this->input_buffer_.length(); -} - -bool BufferedSocket::recv_soft(char* buf, size_t len) -{ - if (this->input_buffer_.length() < len) - return false; - - ACE_OS::memcpy(buf, this->input_buffer_.rd_ptr(), len); - - return true; -} - -bool BufferedSocket::recv(char* buf, size_t len) -{ - bool ret = this->recv_soft(buf, len); - - if (ret) - this->recv_skip(len); - - return ret; -} - -void BufferedSocket::recv_skip(size_t len) -{ - this->input_buffer_.rd_ptr(len); -} - -ssize_t BufferedSocket::noblk_send(ACE_Message_Block& message_block) -{ - const size_t len = message_block.length(); - - if (len == 0) - return -1; - - // Try to send the message directly. - ssize_t n = this->peer().send(message_block.rd_ptr(), len, MSG_NOSIGNAL); - - if (n < 0) - { - if (errno == EWOULDBLOCK) - // Blocking signal - return 0; - else - // Error - return -1; - } - else if (n == 0) - { - // Can this happen ? - return -1; - } - - // return bytes transmitted - return n; -} - -bool BufferedSocket::send(const char* buf, size_t len) -{ - if (buf == NULL || len == 0) - return true; - - ACE_Data_Block db( - len, - ACE_Message_Block::MB_DATA, - (const char*)buf, - 0, - 0, - ACE_Message_Block::DONT_DELETE, - 0); - - ACE_Message_Block message_block( - &db, - ACE_Message_Block::DONT_DELETE, - 0); - - message_block.wr_ptr(len); - - if (this->msg_queue()->is_empty()) - { - // Try to send it directly. - ssize_t n = this->noblk_send(message_block); - - if (n < 0) - return false; - else if (n == len) - return true; - - // adjust how much bytes we sent - message_block.rd_ptr((size_t)n); - - // fall down - } - - // enqueue the message, note: clone is needed cause we cant enqueue stuff on the stack - ACE_Message_Block* mb = message_block.clone(); - - if (this->msg_queue()->enqueue_tail(mb, (ACE_Time_Value*) &ACE_Time_Value::zero) == -1) - { - mb->release(); - return false; - } - - // tell reactor to call handle_output() when we can send more data - if (this->reactor()->schedule_wakeup(this, ACE_Event_Handler::WRITE_MASK) == -1) - return false; - - return true; -} - -/*virtual*/ int BufferedSocket::handle_output(ACE_HANDLE /*= ACE_INVALID_HANDLE*/) -{ - ACE_Message_Block* mb = 0; - - if (this->msg_queue()->is_empty()) - { - // if no more data to send, then cancel notification - this->reactor()->cancel_wakeup(this, ACE_Event_Handler::WRITE_MASK); - return 0; - } - - if (this->msg_queue()->dequeue_head(mb, (ACE_Time_Value*) &ACE_Time_Value::zero) == -1) - return -1; - - ssize_t n = this->noblk_send(*mb); - - if (n < 0) - { - mb->release(); - return -1; - } - else if (n == mb->length()) - { - mb->release(); - return 1; - } - else - { - mb->rd_ptr(n); - - if (this->msg_queue()->enqueue_head(mb, (ACE_Time_Value*) &ACE_Time_Value::zero) == -1) - { - mb->release(); - return -1; - } - - return 0; - } - - ACE_NOTREACHED(return -1); -} - -/*virtual*/ int BufferedSocket::handle_input(ACE_HANDLE /*= ACE_INVALID_HANDLE*/) -{ - const ssize_t space = this->input_buffer_.space(); - - ssize_t n = this->peer().recv(this->input_buffer_.wr_ptr(), space); - - if (n < 0) - { - // blocking signal or error - return errno == EWOULDBLOCK ? 0 : -1; - } - else if (n == 0) - { - // EOF - return -1; - } - - this->input_buffer_.wr_ptr((size_t)n); - - this->OnRead(); - - // move data in the buffer to the beginning of the buffer - this->input_buffer_.crunch(); - - // return 1 in case there might be more data to read from OS - return n == space ? 1 : 0; -} - -/*virtual*/ int BufferedSocket::handle_close(ACE_HANDLE h, ACE_Reactor_Mask m) -{ - this->OnClose(); - - Base::handle_close(); - - return 0; -} - -void BufferedSocket::close_connection(void) -{ - this->peer().close_reader(); - this->peer().close_writer(); - - reactor()->remove_handler(this, ACE_Event_Handler::DONT_CALL | ACE_Event_Handler::ALL_EVENTS_MASK); -} - diff --git a/src/realmd/BufferedSocket.h b/src/realmd/BufferedSocket.h deleted file mode 100644 index 3b237be60..000000000 --- a/src/realmd/BufferedSocket.h +++ /dev/null @@ -1,84 +0,0 @@ -/** - * MaNGOS is a full featured server for World of Warcraft, supporting - * the following clients: 1.12.x, 2.4.3, 3.3.5a, 4.3.4a and 5.4.8 - * - * Copyright (C) 2005-2014 MaNGOS project - * - * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * World of Warcraft, and all World of Warcraft or Warcraft art, images, - * and lore are copyrighted by Blizzard Entertainment, Inc. - */ - -/** \file - \ingroup realmd - */ - -#ifndef _BUFFEREDSOCKET_H_ -#define _BUFFEREDSOCKET_H_ - -#include -#include -#include -#include -#include -#include - -#include - -class BufferedSocket: public ACE_Svc_Handler -{ - protected: - typedef ACE_Svc_Handler Base; - - virtual void OnRead(void) { } - virtual void OnAccept(void) { } - virtual void OnClose(void) { } - - public: - BufferedSocket(void); - virtual ~BufferedSocket(void); - - size_t recv_len(void) const; - bool recv_soft(char* buf, size_t len); - bool recv(char* buf, size_t len); - void recv_skip(size_t len); - - bool send(const char* buf, size_t len); - - const std::string& get_remote_address(void) const; - - virtual int open(void*) override; - - void close_connection(void); - - virtual int handle_input(ACE_HANDLE = ACE_INVALID_HANDLE) override; - virtual int handle_output(ACE_HANDLE = ACE_INVALID_HANDLE) override; - - virtual int handle_close(ACE_HANDLE = ACE_INVALID_HANDLE, - ACE_Reactor_Mask = ACE_Event_Handler::ALL_EVENTS_MASK); - - private: - ssize_t noblk_send(ACE_Message_Block& message_block); - - private: - ACE_Message_Block input_buffer_; - - protected: - std::string remote_address_; -}; - -#endif /* _BUFFEREDSOCKET_H_ */ - diff --git a/src/realmd/CMakeLists.txt b/src/realmd/CMakeLists.txt deleted file mode 100644 index 485ccc403..000000000 --- a/src/realmd/CMakeLists.txt +++ /dev/null @@ -1,101 +0,0 @@ -# This code is part of MaNGOS. Contributor & Copyright details are in AUTHORS/THANKS. -# -# 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, write to the Free Software -# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -set(EXECUTABLE_NAME realmd) - -set(EXECUTABLE_SRCS - AuthCodes.h - AuthSocket.cpp - AuthSocket.h - BufferedSocket.cpp - BufferedSocket.h - Main.cpp - PatchHandler.cpp - PatchHandler.h - RealmList.cpp - RealmList.h - ) - -if(WIN32) - # add resource file to windows build - set(EXECUTABLE_SRCS ${EXECUTABLE_SRCS} realmd.rc) -endif() - -include_directories( - ${CMAKE_SOURCE_DIR}/src/shared - ${CMAKE_SOURCE_DIR}/src/framework - ${CMAKE_BINARY_DIR} - ${CMAKE_BINARY_DIR}/src/shared - ${MYSQL_INCLUDE_DIR} - ${ACE_INCLUDE_DIR} -) - -add_executable(${EXECUTABLE_NAME} - ${EXECUTABLE_SRCS} -) - -add_dependencies(${EXECUTABLE_NAME} revision.h) -if(NOT ACE_USE_EXTERNAL) - add_dependencies(${EXECUTABLE_NAME} ACE_Project) -# add_dependencies(${EXECUTABLE_NAME} ace) -endif() - -target_link_libraries(${EXECUTABLE_NAME} - shared - framework - ${ACE_LIBRARIES} -) - -if(WIN32) - target_link_libraries(${EXECUTABLE_NAME} - optimized ${MYSQL_LIBRARY} - optimized ${OPENSSL_LIBRARIES} - debug ${MYSQL_DEBUG_LIBRARY} - debug ${OPENSSL_DEBUG_LIBRARIES} - ) - if(PLATFORM MATCHES X86) - target_link_libraries(${EXECUTABLE_NAME}) - endif() -endif() - -if(UNIX) - target_link_libraries(${EXECUTABLE_NAME} - ${MYSQL_LIBRARY} - ${OPENSSL_LIBRARIES} - ${OPENSSL_EXTRA_LIBRARIES} - ) -endif() - -set(EXECUTABLE_LINK_FLAGS "") - -if(UNIX) - set(EXECUTABLE_LINK_FLAGS "-pthread ${EXECUTABLE_LINK_FLAGS}") -endif() - -if(APPLE) - set(EXECUTABLE_LINK_FLAGS "-framework Carbon ${EXECUTABLE_LINK_FLAGS}") -endif() - -set_target_properties(${EXECUTABLE_NAME} PROPERTIES LINK_FLAGS - "${EXECUTABLE_LINK_FLAGS}" -) - -install(TARGETS ${EXECUTABLE_NAME} DESTINATION ${BIN_DIR}) -install(FILES realmd.conf.dist.in DESTINATION ${CONF_DIR} RENAME realmd.conf.dist) - -if(WIN32 AND MSVC) - install(FILES ${CMAKE_CURRENT_BINARY_DIR}/\${BUILD_TYPE}/${EXECUTABLE_NAME}.pdb DESTINATION ${BIN_DIR} CONFIGURATIONS Debug) -endif() diff --git a/src/realmd/Main.cpp b/src/realmd/Main.cpp deleted file mode 100644 index e68085a9d..000000000 --- a/src/realmd/Main.cpp +++ /dev/null @@ -1,435 +0,0 @@ -/** - * MaNGOS is a full featured server for World of Warcraft, supporting - * the following clients: 1.12.x, 2.4.3, 3.3.5a, 4.3.4a and 5.4.8 - * - * Copyright (C) 2005-2014 MaNGOS project - * - * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * World of Warcraft, and all World of Warcraft or Warcraft art, images, - * and lore are copyrighted by Blizzard Entertainment, Inc. - */ - -/// \addtogroup realmd Realm Daemon -/// @{ -/// \file - -#include "Common.h" -#include "Database/DatabaseEnv.h" -#include "RealmList.h" - -#include "Config/Config.h" -#include "Log.h" -#include "AuthSocket.h" -#include "SystemConfig.h" -#include "revision.h" -#include "revision_nr.h" -#include "revision_sql.h" -#include "Util.h" -#include -#include - -#include -#include -#include -#include -#include -#include - -#ifdef WIN32 -#include "ServiceWin32.h" -char serviceName[] = "realmd"; -char serviceLongName[] = "MaNGOS realmd service"; -char serviceDescription[] = "Massive Network Game Object Server"; -/* - * -1 - not in service mode - * 0 - stopped - * 1 - running - * 2 - paused - */ -int m_ServiceStatus = -1; -#else -#include "PosixDaemon.h" -#endif - -bool StartDB(); -void UnhookSignals(); -void HookSignals(); - -bool stopEvent = false; ///< Setting it to true stops the server - -DatabaseType LoginDatabase; ///< Accessor to the realm server database - -/// Print out the usage string for this program on the console. -void usage(const char* prog) -{ - sLog.outString("Usage: \n %s []\n" - " -v, --version print version and exist\n\r" - " -c config_file use config_file as configuration file\n\r" -#ifdef WIN32 - " Running as service functions:\n\r" - " -s run run as service\n\r" - " -s install install service\n\r" - " -s uninstall uninstall service\n\r" -#else - " Running as daemon functions:\n\r" - " -s run run as daemon\n\r" - " -s stop stop daemon\n\r" -#endif - , prog); -} - -/// Launch the realm server -extern int main(int argc, char** argv) -{ - ///- Command line parsing - char const* cfg_file = REALMD_CONFIG_LOCATION; - - char const* options = ":c:s:"; - - ACE_Get_Opt cmd_opts(argc, argv, options); - cmd_opts.long_option("version", 'v'); - - char serviceDaemonMode = '\0'; - - int option; - while ((option = cmd_opts()) != EOF) - { - switch (option) - { - case 'c': - cfg_file = cmd_opts.opt_arg(); - break; - case 'v': - printf("%s\n", MANGOS_FULLVERSION(REVISION_DATE, REVISION_TIME, REVISION_NR, REVISION_ID)); - return 0; - - case 's': - { - const char* mode = cmd_opts.opt_arg(); - - if (!strcmp(mode, "run")) - serviceDaemonMode = 'r'; -#ifdef WIN32 - else if (!strcmp(mode, "install")) - serviceDaemonMode = 'i'; - else if (!strcmp(mode, "uninstall")) - serviceDaemonMode = 'u'; -#else - else if (!strcmp(mode, "stop")) - serviceDaemonMode = 's'; -#endif - else - { - sLog.outError("Runtime-Error: -%c unsupported argument %s", cmd_opts.opt_opt(), mode); - usage(argv[0]); - Log::WaitBeforeContinueIfNeed(); - return 1; - } - break; - } - case ':': - sLog.outError("Runtime-Error: -%c option requires an input argument", cmd_opts.opt_opt()); - usage(argv[0]); - Log::WaitBeforeContinueIfNeed(); - return 1; - default: - sLog.outError("Runtime-Error: bad format of commandline arguments"); - usage(argv[0]); - Log::WaitBeforeContinueIfNeed(); - return 1; - } - } - -#ifdef WIN32 // windows service command need execute before config read - switch (serviceDaemonMode) - { - case 'i': - if (WinServiceInstall()) - sLog.outString("Installing service"); - return 1; - case 'u': - if (WinServiceUninstall()) - sLog.outString("Uninstalling service"); - return 1; - case 'r': - WinServiceRun(); - break; - } -#endif - - if (!sConfig.SetSource(cfg_file)) - { - sLog.outError("Could not find configuration file %s.", cfg_file); - Log::WaitBeforeContinueIfNeed(); - return 1; - } - -#ifndef WIN32 // posix daemon commands need apply after config read - switch (serviceDaemonMode) - { - case 'r': - startDaemon(); - break; - case 's': - stopDaemon(); - break; - } -#endif - - sLog.Initialize(); - - sLog.outString("%s [realm-daemon]", MANGOS_FULLVERSION(REVISION_DATE, REVISION_TIME, REVISION_NR, REVISION_ID)); - sLog.outString(" to stop.\n"); - sLog.outString("Using configuration file %s.", cfg_file); - - ///- Check the version of the configuration file - uint32 confVersion = sConfig.GetIntDefault("ConfVersion", 0); - if (confVersion < REALMD_CONFIG_VERSION) - { - sLog.outError("*****************************************************************************"); - sLog.outError(" WARNING: Your realmd.conf version indicates your conf file is out of date!"); - sLog.outError(" Please check for updates, as your current default values may cause"); - sLog.outError(" strange behavior."); - sLog.outError("*****************************************************************************"); - Log::WaitBeforeContinueIfNeed(); - } - - DETAIL_LOG("%s (Library: %s)", OPENSSL_VERSION_TEXT, SSLeay_version(SSLEAY_VERSION)); - if (SSLeay() < 0x009080bfL) - { - DETAIL_LOG("WARNING: Outdated version of OpenSSL lib. Logins to server may not work!"); - DETAIL_LOG("WARNING: Minimal required version [OpenSSL 0.9.8k]"); - } - - DETAIL_LOG("Using ACE: %s", ACE_VERSION); - -#if defined (ACE_HAS_EVENT_POLL) || defined (ACE_HAS_DEV_POLL) - ACE_Reactor::instance(new ACE_Reactor(new ACE_Dev_Poll_Reactor(ACE::max_handles(), 1), 1), true); -#else - ACE_Reactor::instance(new ACE_Reactor(new ACE_TP_Reactor(), true), true); -#endif - - sLog.outBasic("Max allowed open files is %d", ACE::max_handles()); - - /// realmd PID file creation - std::string pidfile = sConfig.GetStringDefault("PidFile", ""); - if (!pidfile.empty()) - { - uint32 pid = CreatePIDFile(pidfile); - if (!pid) - { - sLog.outError("Cannot create PID file %s.\n", pidfile.c_str()); - Log::WaitBeforeContinueIfNeed(); - return 1; - } - - sLog.outString("Daemon PID: %u\n", pid); - } - - ///- Initialize the database connection - if (!StartDB()) - { - Log::WaitBeforeContinueIfNeed(); - return 1; - } - - ///- Get the list of realms for the server - sRealmList.Initialize(sConfig.GetIntDefault("RealmsStateUpdateDelay", 20)); - if (sRealmList.size() == 0) - { - sLog.outError("No valid realms specified."); - Log::WaitBeforeContinueIfNeed(); - return 1; - } - - // cleanup query - // set expired bans to inactive - LoginDatabase.BeginTransaction(); - LoginDatabase.Execute("UPDATE account_banned SET active = 0 WHERE unbandate<=UNIX_TIMESTAMP() AND unbandate<>bandate"); - LoginDatabase.Execute("DELETE FROM ip_banned WHERE unbandate<=UNIX_TIMESTAMP() AND unbandate<>bandate"); - LoginDatabase.CommitTransaction(); - - ///- Launch the listening network socket - ACE_Acceptor acceptor; - - uint16 rmport = sConfig.GetIntDefault("RealmServerPort", DEFAULT_REALMSERVER_PORT); - std::string bind_ip = sConfig.GetStringDefault("BindIP", "0.0.0.0"); - - ACE_INET_Addr bind_addr(rmport, bind_ip.c_str()); - - if (acceptor.open(bind_addr, ACE_Reactor::instance(), ACE_NONBLOCK) == -1) - { - sLog.outError("MaNGOS realmd can not bind to %s:%d", bind_ip.c_str(), rmport); - Log::WaitBeforeContinueIfNeed(); - return 1; - } - - ///- Catch termination signals - HookSignals(); - - ///- Handle affinity for multiple processors and process priority on Windows -#ifdef WIN32 - { - HANDLE hProcess = GetCurrentProcess(); - - uint32 Aff = sConfig.GetIntDefault("UseProcessors", 0); - if (Aff > 0) - { - ULONG_PTR appAff; - ULONG_PTR sysAff; - - if (GetProcessAffinityMask(hProcess, &appAff, &sysAff)) - { - ULONG_PTR curAff = Aff & appAff; // remove non accessible processors - - if (!curAff) - { - sLog.outError("Processors marked in UseProcessors bitmask (hex) %x not accessible for realmd. Accessible processors bitmask (hex): %x", Aff, appAff); - } - else - { - if (SetProcessAffinityMask(hProcess, curAff)) - sLog.outString("Using processors (bitmask, hex): %x", curAff); - else - sLog.outError("Can't set used processors (hex): %x", curAff); - } - } - sLog.outString(); - } - - bool Prio = sConfig.GetBoolDefault("ProcessPriority", false); - - if (Prio) - { - if (SetPriorityClass(hProcess, HIGH_PRIORITY_CLASS)) - sLog.outString("realmd process priority class set to HIGH"); - else - sLog.outError("Can't set realmd process priority class."); - sLog.outString(); - } - } -#endif - - // server has started up successfully => enable async DB requests - LoginDatabase.AllowAsyncTransactions(); - - // maximum counter for next ping - uint32 numLoops = (sConfig.GetIntDefault("MaxPingTime", 30) * (MINUTE * 1000000 / 100000)); - uint32 loopCounter = 0; - -#ifndef WIN32 - detachDaemon(); -#endif - ///- Wait for termination signal - while (!stopEvent) - { - // dont move this outside the loop, the reactor will modify it - ACE_Time_Value interval(0, 100000); - - if (ACE_Reactor::instance()->run_reactor_event_loop(interval) == -1) - break; - - if ((++loopCounter) == numLoops) - { - loopCounter = 0; - DETAIL_LOG("Ping MySQL to keep connection alive"); - LoginDatabase.Ping(); - } -#ifdef WIN32 - if (m_ServiceStatus == 0) stopEvent = true; - while (m_ServiceStatus == 2) Sleep(1000); -#endif - } - - ///- Wait for the delay thread to exit - LoginDatabase.HaltDelayThread(); - - ///- Remove signal handling before leaving - UnhookSignals(); - - sLog.outString("Halting process..."); - return 0; -} - -/// Handle termination signals -/** Put the global variable stopEvent to 'true' if a termination signal is caught **/ -void OnSignal(int s) -{ - switch (s) - { - case SIGINT: - case SIGTERM: - stopEvent = true; - break; -#ifdef _WIN32 - case SIGBREAK: - stopEvent = true; - break; -#endif - } - - signal(s, OnSignal); -} - -/// Initialize connection to the database -bool StartDB() -{ - std::string dbstring = sConfig.GetStringDefault("LoginDatabaseInfo", ""); - if (dbstring.empty()) - { - sLog.outError("Database not specified"); - return false; - } - - sLog.outString("Login Database total connections: %i", 1 + 1); - - if (!LoginDatabase.Initialize(dbstring.c_str())) - { - sLog.outError("Cannot connect to database"); - return false; - } - - if (!LoginDatabase.CheckRequiredField("realmd_db_version", REVISION_DB_REALMD)) - { - ///- Wait for already started DB delay threads to end - LoginDatabase.HaltDelayThread(); - return false; - } - - return true; -} - -/// Define hook 'OnSignal' for all termination signals -void HookSignals() -{ - signal(SIGINT, OnSignal); - signal(SIGTERM, OnSignal); -#ifdef _WIN32 - signal(SIGBREAK, OnSignal); -#endif -} - -/// Unhook the signals before leaving -void UnhookSignals() -{ - signal(SIGINT, 0); - signal(SIGTERM, 0); -#ifdef _WIN32 - signal(SIGBREAK, 0); -#endif -} - -/// @} diff --git a/src/realmd/PatchHandler.cpp b/src/realmd/PatchHandler.cpp deleted file mode 100644 index adaa2cedc..000000000 --- a/src/realmd/PatchHandler.cpp +++ /dev/null @@ -1,221 +0,0 @@ -/** - * MaNGOS is a full featured server for World of Warcraft, supporting - * the following clients: 1.12.x, 2.4.3, 3.3.5a, 4.3.4a and 5.4.8 - * - * Copyright (C) 2005-2014 MaNGOS project - * - * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * World of Warcraft, and all World of Warcraft or Warcraft art, images, - * and lore are copyrighted by Blizzard Entertainment, Inc. - */ - -/** \file - \ingroup realmd - */ - -#include "Common.h" -#include "PatchHandler.h" -#include "AuthCodes.h" -#include "Log.h" - -#include -#include -#include -#include - -#include - -#ifndef MSG_NOSIGNAL -#define MSG_NOSIGNAL 0 -#endif - -#if defined( __GNUC__ ) -#pragma pack(1) -#else -#pragma pack(push,1) -#endif - -struct Chunk -{ - ACE_UINT8 cmd; - ACE_UINT16 data_size; - ACE_UINT8 data[4096]; // 4096 - page size on most arch -}; - -#if defined( __GNUC__ ) -#pragma pack() -#else -#pragma pack(pop) -#endif - -PatchHandler::PatchHandler(ACE_HANDLE socket, ACE_HANDLE patch) -{ - reactor(NULL); - set_handle(socket); - patch_fd_ = patch; -} - -PatchHandler::~PatchHandler() -{ - if (patch_fd_ != ACE_INVALID_HANDLE) - ACE_OS::close(patch_fd_); -} - -int PatchHandler::open(void*) -{ - if (get_handle() == ACE_INVALID_HANDLE || patch_fd_ == ACE_INVALID_HANDLE) - return -1; - - int nodelay = 0; - if (-1 == peer().set_option(ACE_IPPROTO_TCP, - TCP_NODELAY, - &nodelay, - sizeof(nodelay))) - { - return -1; - } - -#if defined(TCP_CORK) - int cork = 1; - if (-1 == peer().set_option(ACE_IPPROTO_TCP, - TCP_CORK, - &cork, - sizeof(cork))) - { - return -1; - } -#endif // TCP_CORK - - (void) peer().disable(ACE_NONBLOCK); - - return activate(THR_NEW_LWP | THR_DETACHED | THR_INHERIT_SCHED); -} - -int PatchHandler::svc(void) -{ - // Do 1 second sleep, similar to the one in game/WorldSocket.cpp - // Seems client have problems with too fast sends. - ACE_OS::sleep(1); - - int flags = MSG_NOSIGNAL; - - Chunk data; - data.cmd = CMD_XFER_DATA; - - ssize_t r; - - while ((r = ACE_OS::read(patch_fd_, data.data, sizeof(data.data))) > 0) - { - data.data_size = (ACE_UINT16)r; - - if (peer().send((const char*)&data, - ((size_t) r) + sizeof(data) - sizeof(data.data), - flags) == -1) - { - return -1; - } - } - - if (r == -1) - { - return -1; - } - - return 0; -} - -PatchCache::~PatchCache() -{ - for (Patches::iterator i = patches_.begin(); i != patches_.end(); ++i) - delete i->second; -} - -PatchCache::PatchCache() -{ - LoadPatchesInfo(); -} - -PatchCache* PatchCache::instance() -{ - return ACE_Singleton::instance(); -} - -void PatchCache::LoadPatchMD5(const char* szFileName) -{ - // Try to open the patch file - std::string path = "./patches/"; - path += szFileName; - FILE* pPatch = fopen(path.c_str(), "rb"); - sLog.outDebug("Loading patch info from %s", path.c_str()); - - if (!pPatch) - return; - - // Calculate the MD5 hash - MD5_CTX ctx; - MD5_Init(&ctx); - - const size_t check_chunk_size = 4 * 1024; - - ACE_UINT8 buf[check_chunk_size]; - - while (!feof(pPatch)) - { - size_t read = fread(buf, 1, check_chunk_size, pPatch); - MD5_Update(&ctx, buf, read); - } - - fclose(pPatch); - - // Store the result in the internal patch hash map - patches_[path] = new PATCH_INFO; - MD5_Final((ACE_UINT8*) & patches_[path]->md5, &ctx); -} - -bool PatchCache::GetHash(const char* pat, ACE_UINT8 mymd5[MD5_DIGEST_LENGTH]) -{ - for (Patches::iterator i = patches_.begin(); i != patches_.end(); ++i) - if (!stricmp(pat, i->first.c_str())) - { - memcpy(mymd5, i->second->md5, MD5_DIGEST_LENGTH); - return true; - } - - return false; -} - -void PatchCache::LoadPatchesInfo() -{ - ACE_DIR* dirp = ACE_OS::opendir(ACE_TEXT("./patches/")); - - if (!dirp) - return; - - ACE_DIRENT* dp; - - while ((dp = ACE_OS::readdir(dirp)) != NULL) - { - int l = strlen(dp->d_name); - if (l < 8) - continue; - - if (!memcmp(&dp->d_name[l - 4], ".mpq", 4)) - LoadPatchMD5(dp->d_name); - } - - ACE_OS::closedir(dirp); -} - diff --git a/src/realmd/PatchHandler.h b/src/realmd/PatchHandler.h deleted file mode 100644 index d8ec3defa..000000000 --- a/src/realmd/PatchHandler.h +++ /dev/null @@ -1,98 +0,0 @@ -/** - * MaNGOS is a full featured server for World of Warcraft, supporting - * the following clients: 1.12.x, 2.4.3, 3.3.5a, 4.3.4a and 5.4.8 - * - * Copyright (C) 2005-2014 MaNGOS project - * - * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * World of Warcraft, and all World of Warcraft or Warcraft art, images, - * and lore are copyrighted by Blizzard Entertainment, Inc. - */ - -/** \file - \ingroup realmd - */ - -#ifndef _PATCHHANDLER_H_ -#define _PATCHHANDLER_H_ - -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -/** - * @brief Caches MD5 hash of client patches present on the server - */ -class PatchCache -{ - public: - ~PatchCache(); - PatchCache(); - - static PatchCache* instance(); - - struct PATCH_INFO - { - ACE_UINT8 md5[MD5_DIGEST_LENGTH]; - }; - - typedef std::map Patches; - - Patches::const_iterator begin() const - { - return patches_.begin(); - } - - Patches::const_iterator end() const - { - return patches_.end(); - } - - void LoadPatchMD5(const char*); - bool GetHash(const char* pat, ACE_UINT8 mymd5[MD5_DIGEST_LENGTH]); - - private: - void LoadPatchesInfo(); - Patches patches_; -}; - -class PatchHandler: public ACE_Svc_Handler -{ - protected: - typedef ACE_Svc_Handler Base; - - public: - PatchHandler(ACE_HANDLE socket, ACE_HANDLE patch); - virtual ~PatchHandler(); - - int open(void* = 0) override; - - protected: - virtual int svc(void) override; - - private: - ACE_HANDLE patch_fd_; -}; - -#endif /* _BK_PATCHHANDLER_H__ */ - diff --git a/src/realmd/RealmList.cpp b/src/realmd/RealmList.cpp deleted file mode 100644 index 984991e58..000000000 --- a/src/realmd/RealmList.cpp +++ /dev/null @@ -1,187 +0,0 @@ -/** - * MaNGOS is a full featured server for World of Warcraft, supporting - * the following clients: 1.12.x, 2.4.3, 3.3.5a, 4.3.4a and 5.4.8 - * - * Copyright (C) 2005-2014 MaNGOS project - * - * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * World of Warcraft, and all World of Warcraft or Warcraft art, images, - * and lore are copyrighted by Blizzard Entertainment, Inc. - */ - -/** \file - \ingroup realmd -*/ - -#include "Common.h" -#include "RealmList.h" -#include "AuthCodes.h" -#include "Util.h" // for Tokens typedef -#include "Policies/Singleton.h" -#include "Database/DatabaseEnv.h" - -INSTANTIATE_SINGLETON_1(RealmList); - -extern DatabaseType LoginDatabase; - -// will only support WoW 1.12.1/1.12.2/1.12.3, WoW:TBC 2.4.3, WoW:WotLK 3.3.5a and official release for WoW:Cataclysm and later, client builds 15595, 10505, 8606, 6005, 5875 -// if you need more from old build then add it in cases in realmd sources code -// list sorted from high to low build and first build used as low bound for accepted by default range (any > it will accepted by realmd at least) - -static RealmBuildInfo ExpectedRealmdClientBuilds[] = -{ - {15595, 4, 3, 4, ' '}, // highest supported build, also auto accept all above for simplify future supported builds testing - {15050, 4, 3, 0, ' '}, - {13623, 4, 0, 6, 'a'}, - {12340, 3, 3, 5, 'a'}, - {11723, 3, 3, 3, 'a'}, - {11403, 3, 3, 2, ' '}, - {11159, 3, 3, 0, 'a'}, - {10505, 3, 2, 2, 'a'}, - {8606, 2, 4, 3, ' '}, - {6141, 1, 12, 3, ' '}, - {6005, 1, 12, 2, ' '}, - {5875, 1, 12, 1, ' '}, - {0, 0, 0, 0, ' '} // terminator -}; - -RealmBuildInfo const* FindBuildInfo(uint16 _build) -{ - // first build is low bound of always accepted range - if (_build >= ExpectedRealmdClientBuilds[0].build) - return &ExpectedRealmdClientBuilds[0]; - - // continue from 1 with explicit equal check - for (int i = 1; ExpectedRealmdClientBuilds[i].build; ++i) - if (_build == ExpectedRealmdClientBuilds[i].build) - return &ExpectedRealmdClientBuilds[i]; - - // none appropriate build - return NULL; -} - -RealmList::RealmList() : m_UpdateInterval(0), m_NextUpdateTime(time(NULL)) -{ -} - -RealmList& sRealmList -{ - static RealmList realmlist; - return realmlist; -} - -/// Load the realm list from the database -void RealmList::Initialize(uint32 updateInterval) -{ - m_UpdateInterval = updateInterval; - - ///- Get the content of the realmlist table in the database - UpdateRealms(true); -} - -void RealmList::UpdateRealm(uint32 ID, const std::string& name, const std::string& address, uint32 port, uint8 icon, RealmFlags realmflags, uint8 timezone, AccountTypes allowedSecurityLevel, float popu, const std::string& builds) -{ - ///- Create new if not exist or update existed - Realm& realm = m_realms[name]; - - realm.m_ID = ID; - realm.icon = icon; - realm.realmflags = realmflags; - realm.timezone = timezone; - realm.allowedSecurityLevel = allowedSecurityLevel; - realm.populationLevel = popu; - - Tokens tokens = StrSplit(builds, " "); - Tokens::iterator iter; - - for (iter = tokens.begin(); iter != tokens.end(); ++iter) - { - uint32 build = atol((*iter).c_str()); - realm.realmbuilds.insert(build); - } - - uint16 first_build = !realm.realmbuilds.empty() ? *realm.realmbuilds.begin() : 0; - - realm.realmBuildInfo.build = first_build; - realm.realmBuildInfo.major_version = 0; - realm.realmBuildInfo.minor_version = 0; - realm.realmBuildInfo.bugfix_version = 0; - realm.realmBuildInfo.hotfix_version = ' '; - - if (first_build) - if (RealmBuildInfo const* bInfo = FindBuildInfo(first_build)) - if (bInfo->build == first_build) - realm.realmBuildInfo = *bInfo; - - ///- Append port to IP address. - std::ostringstream ss; - ss << address << ":" << port; - realm.address = ss.str(); -} - -void RealmList::UpdateIfNeed() -{ - // maybe disabled or updated recently - if (!m_UpdateInterval || m_NextUpdateTime > time(NULL)) - return; - - m_NextUpdateTime = time(NULL) + m_UpdateInterval; - - // Clears Realm list - m_realms.clear(); - - // Get the content of the realmlist table in the database - UpdateRealms(false); -} - -void RealmList::UpdateRealms(bool init) -{ - DETAIL_LOG("Updating Realm List..."); - - //// 0 1 2 3 4 5 6 7 8 9 - QueryResult* result = LoginDatabase.Query("SELECT id, name, address, port, icon, realmflags, timezone, allowedSecurityLevel, population, realmbuilds FROM realmlist WHERE (realmflags & 1) = 0 ORDER BY name"); - - ///- Circle through results and add them to the realm map - if (result) - { - do - { - Field* fields = result->Fetch(); - - uint32 Id = fields[0].GetUInt32(); - std::string name = fields[1].GetCppString(); - uint8 realmflags = fields[5].GetUInt8(); - uint8 allowedSecurityLevel = fields[7].GetUInt8(); - - if (realmflags & ~(REALM_FLAG_OFFLINE | REALM_FLAG_NEW_PLAYERS | REALM_FLAG_RECOMMENDED | REALM_FLAG_SPECIFYBUILD)) - { - sLog.outError("Realm (id %u, name '%s') can only be flagged as OFFLINE (mask 0x02), NEWPLAYERS (mask 0x20), RECOMMENDED (mask 0x40), or SPECIFICBUILD (mask 0x04) in DB", Id, name.c_str()); - realmflags &= (REALM_FLAG_OFFLINE | REALM_FLAG_NEW_PLAYERS | REALM_FLAG_RECOMMENDED | REALM_FLAG_SPECIFYBUILD); - } - - UpdateRealm( - Id, name, fields[2].GetCppString(), fields[3].GetUInt32(), - fields[4].GetUInt8(), RealmFlags(realmflags), fields[6].GetUInt8(), - (allowedSecurityLevel <= SEC_ADMINISTRATOR ? AccountTypes(allowedSecurityLevel) : SEC_ADMINISTRATOR), - fields[8].GetFloat(), fields[9].GetCppString()); - - if (init) - sLog.outString("Added realm id %u, name '%s'", Id, name.c_str()); - } - while (result->NextRow()); - delete result; - } -} diff --git a/src/realmd/RealmList.h b/src/realmd/RealmList.h deleted file mode 100644 index 6909d088c..000000000 --- a/src/realmd/RealmList.h +++ /dev/null @@ -1,91 +0,0 @@ -/** - * MaNGOS is a full featured server for World of Warcraft, supporting - * the following clients: 1.12.x, 2.4.3, 3.3.5a, 4.3.4a and 5.4.8 - * - * Copyright (C) 2005-2014 MaNGOS project - * - * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * World of Warcraft, and all World of Warcraft or Warcraft art, images, - * and lore are copyrighted by Blizzard Entertainment, Inc. - */ - -/// \addtogroup realmd -/// @{ -/// \file - -#ifndef _REALMLIST_H -#define _REALMLIST_H - -#include "Common.h" - -struct RealmBuildInfo -{ - int build; - int major_version; - int minor_version; - int bugfix_version; - int hotfix_version; -}; - -RealmBuildInfo const* FindBuildInfo(uint16 _build); - -typedef std::set RealmBuilds; - -/// Storage object for a realm -struct Realm -{ - std::string address; - uint8 icon; - RealmFlags realmflags; // realmflags - uint8 timezone; - uint32 m_ID; - AccountTypes allowedSecurityLevel; // current allowed join security level (show as locked for not fit accounts) - float populationLevel; - RealmBuilds realmbuilds; // list of supported builds (updated in DB by mangosd) - RealmBuildInfo realmBuildInfo; // build info for show version in list -}; - -/// Storage object for the list of realms on the server -class RealmList -{ - public: - typedef std::map RealmMap; - - static RealmList& Instance(); - - RealmList(); - ~RealmList() {} - - void Initialize(uint32 updateInterval); - - void UpdateIfNeed(); - - RealmMap::const_iterator begin() const { return m_realms.begin(); } - RealmMap::const_iterator end() const { return m_realms.end(); } - uint32 size() const { return m_realms.size(); } - private: - void UpdateRealms(bool init); - void UpdateRealm(uint32 ID, const std::string& name, const std::string& address, uint32 port, uint8 icon, RealmFlags realmflags, uint8 timezone, AccountTypes allowedSecurityLevel, float popu, const std::string& builds); - private: - RealmMap m_realms; ///< Internal map of realms - uint32 m_UpdateInterval; - time_t m_NextUpdateTime; -}; - -#define sRealmList RealmList::Instance() - -#endif -/// @} diff --git a/src/realmd/realmd.conf.dist.in b/src/realmd/realmd.conf.dist.in deleted file mode 100644 index 903a6b995..000000000 --- a/src/realmd/realmd.conf.dist.in +++ /dev/null @@ -1,128 +0,0 @@ -############################################ -# MaNGOS realmd configuration file # -############################################ - -[RealmdConf] -ConfVersion=2010062001 - -################################################################################################################### -# REALMD SETTINGS -# -# LoginDatabaseInfo -# Database connection settings for the realm server. -# Default: hostname;port;username;password;database -# .;somenumber;username;password;database - use named pipes at Windows -# Named pipes: mySQL required adding "enable-named-pipe" to [mysqld] section my.ini -# .;/path/to/unix_socket;username;password;database - use Unix sockets at Unix/Linux -# Unix sockets: experimental, not tested -# -# LogsDir -# Logs directory setting. -# Important: Logs dir must exists, or all logs be disable -# Default: "" - no log directory prefix. if used log names aren't absolute paths -# then logs will be stored in the current directory of the running program. -# -# MaxPingTime -# Settings for maximum database-ping interval (minutes between pings) -# -# RealmServerPort -# Port on which the server will listen -# -# BindIP -# Bind Realm Server to IP/hostname -# This option is useful for running multiple worldd/realmd instances -# on different IP addresses using default ports. -# DO NOT CHANGE THIS UNLESS YOU _REALLY_ KNOW WHAT YOU'RE DOING -# -# PidFile -# Realmd daemon PID file -# Default: "" - do not create PID file -# "./realmd.pid" - create PID file (recommended name) -# -# LogLevel -# Server console level of logging -# 0 = Minimum; 1 = Error; 2 = Detail; 3 = Full/Debug -# Default: 0 -# -# LogTime -# Include time in server console output [hh:mm:ss] -# Default: 0 (no time) -# 1 (print time) -# -# LogFile -# Logfile name -# Default: "Realmd.log" -# "" - empty name disable creating log file -# -# LogTimestamp -# Logfile with timestamp of server start in name -# Default: 0 - no timestamp in name -# 1 - add timestamp in name in form Logname_YYYY-MM-DD_HH-MM-SS.Ext for Logname.Ext -# -# LogFileLevel -# Server file level of logging -# 0 = Minimum; 1 = Error; 2 = Detail; 3 = Full/Debug -# Default: 0 -# -# LogColors -# Color for messages (format "normal_color details_color debug_color error_color) -# Colors: 0 - BLACK, 1 - RED, 2 - GREEN, 3 - BROWN, 4 - BLUE, 5 - MAGENTA, 6 - CYAN, 7 - GREY, -# 8 - YELLOW, 9 - LRED, 10 - LGREEN, 11 - LBLUE, 12 - LMAGENTA, 13 - LCYAN, 14 - WHITE -# Default: "" - none colors -# "13 7 11 9" - for example :) -# -# UseProcessors -# Used processors mask for multi-processors system (Used only at Windows) -# Default: 0 (selected by OS) -# number (bitmask value of selected processors) -# -# ProcessPriority -# Process proirity setting (Used only at Windows) -# Default: 1 (HIGH) -# 0 (Normal) -# -# WaitAtStartupError -# After startup error report wait or some time before continue (and possible close console window) -# -1 (wait until press) -# Default: 0 (not wait) -# N (>0, wait N secs) -# -# RealmsStateUpdateDelay -# Realm list Update up delay (updated at realm list request if delay expired). -# Default: 20 -# 0 (Disabled) -# -# WrongPass.MaxCount -# Number of login attemps with wrong password before the account or IP is banned -# Default: 0 (Never ban) -# -# WrongPass.BanTime -# Duration of the ban in seconds (0 means permanent ban) -# Default: 600 -# -# WrongPass.BanType -# Ban the IP or account on which login is attempted -# Default: 0 (Ban IP) -# 1 (Ban Account) -# -################################################################################################################### - -LoginDatabaseInfo = "127.0.0.1;3306;mangos;mangos;realmd" -LogsDir = "" -MaxPingTime = 30 -RealmServerPort = 3724 -BindIP = "0.0.0.0" -PidFile = "" -LogLevel = 0 -LogTime = 0 -LogFile = "Realmd.log" -LogTimestamp = 0 -LogFileLevel = 0 -LogColors = "" -UseProcessors = 0 -ProcessPriority = 1 -WaitAtStartupError = 0 -RealmsStateUpdateDelay = 20 -WrongPass.MaxCount = 0 -WrongPass.BanTime = 600 -WrongPass.BanType = 0 diff --git a/src/realmd/realmd.ico b/src/realmd/realmd.ico deleted file mode 100644 index bd17ee278..000000000 Binary files a/src/realmd/realmd.ico and /dev/null differ diff --git a/src/realmd/realmd.rc b/src/realmd/realmd.rc deleted file mode 100644 index e22a1eb1a..000000000 --- a/src/realmd/realmd.rc +++ /dev/null @@ -1,25 +0,0 @@ -/* - * MaNGOS is a full featured server for World of Warcraft, supporting - * the following clients: 1.12.x, 2.4.3, 3.3.5a, 4.3.4a and 5.4.8 - * - * Copyright (C) 2005-2014 MaNGOS project - * - * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * World of Warcraft, and all World of Warcraft or Warcraft art, images, - * and lore are copyrighted by Blizzard Entertainment, Inc. - */ - -IDI_APPICON ICON DISCARDABLE "realmd.ico"