From 0299e10945facd0fd004fd74a4f8b7cf4727c35f Mon Sep 17 00:00:00 2001 From: Ovahlord Date: Mon, 30 Sep 2019 07:26:54 +0200 Subject: [PATCH] Core/Servers: nuke authserver --- cmake/options.cmake | 2 +- cmake/showoptions.cmake | 2 +- contrib/conf_merge/README | 2 +- doc/UnixInstall.txt | 2 +- src/server/CMakeLists.txt | 1 - .../authserver/Authentication/AuthCodes.cpp | 87 -- .../authserver/Authentication/AuthCodes.h | 132 --- src/server/authserver/Authentication/TOTP.cpp | 95 -- src/server/authserver/Authentication/TOTP.h | 29 - src/server/authserver/CMakeLists.txt | 90 -- src/server/authserver/Main.cpp | 344 ------- .../authserver/PrecompiledHeaders/authPCH.h | 23 - .../authserver/Realms/GruntRealmList.cpp | 190 ---- src/server/authserver/Realms/GruntRealmList.h | 77 -- src/server/authserver/Server/AuthSession.cpp | 924 ------------------ src/server/authserver/Server/AuthSession.h | 121 --- src/server/authserver/Server/AuthSocketMgr.h | 58 -- src/server/authserver/authserver.conf.dist | 359 ------- src/server/authserver/authserver.ico | Bin 136606 -> 0 bytes src/server/authserver/authserver.rc | 94 -- src/server/authserver/resource.h | 15 - src/server/bnetserver/bnetserver.conf.dist | 4 +- .../scripts/Commands/cs_battlenet_account.cpp | 2 +- src/server/worldserver/worldserver.conf.dist | 2 +- 24 files changed, 8 insertions(+), 2647 deletions(-) delete mode 100644 src/server/authserver/Authentication/AuthCodes.cpp delete mode 100644 src/server/authserver/Authentication/AuthCodes.h delete mode 100644 src/server/authserver/Authentication/TOTP.cpp delete mode 100644 src/server/authserver/Authentication/TOTP.h delete mode 100644 src/server/authserver/CMakeLists.txt delete mode 100644 src/server/authserver/Main.cpp delete mode 100644 src/server/authserver/PrecompiledHeaders/authPCH.h delete mode 100644 src/server/authserver/Realms/GruntRealmList.cpp delete mode 100644 src/server/authserver/Realms/GruntRealmList.h delete mode 100644 src/server/authserver/Server/AuthSession.cpp delete mode 100644 src/server/authserver/Server/AuthSession.h delete mode 100644 src/server/authserver/Server/AuthSocketMgr.h delete mode 100644 src/server/authserver/authserver.conf.dist delete mode 100644 src/server/authserver/authserver.ico delete mode 100644 src/server/authserver/authserver.rc delete mode 100644 src/server/authserver/resource.h diff --git a/cmake/options.cmake b/cmake/options.cmake index 0ef502e4102..6161c532cef 100644 --- a/cmake/options.cmake +++ b/cmake/options.cmake @@ -8,7 +8,7 @@ # WITHOUT ANY WARRANTY, to the extent permitted by law; without even the # implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -option(SERVERS "Build worldserver and authserver" 1) +option(SERVERS "Build worldserver and bnetserver" 1) set(SCRIPTS_AVAILABLE_OPTIONS none static dynamic minimal-static minimal-dynamic) diff --git a/cmake/showoptions.cmake b/cmake/showoptions.cmake index 7127c96bb06..830f98481d6 100644 --- a/cmake/showoptions.cmake +++ b/cmake/showoptions.cmake @@ -20,7 +20,7 @@ message("") if( SERVERS ) message("* Build world/auth : Yes (default)") else() - message("* Build world/authserver : No") + message("* Build world/bnetserver : No") endif() if(SCRIPTS AND (NOT SCRIPTS STREQUAL "none")) diff --git a/contrib/conf_merge/README b/contrib/conf_merge/README index 974c1063064..9e6b1e1546c 100644 --- a/contrib/conf_merge/README +++ b/contrib/conf_merge/README @@ -1,6 +1,6 @@ ==== PHP merger (index.php + merge.php) ==== -This is a PHP script for merging a new .dist file with your existing .conf file (worldserver.conf.dist and authserver.conf.dist) +This is a PHP script for merging a new .dist file with your existing .conf file (worldserver.conf.dist and bnetserver.conf.dist) It should also work with mangos dist/conf files as well. It uses sessions so it is multi user safe, it adds any options that are removed to the bottom of the file, diff --git a/doc/UnixInstall.txt b/doc/UnixInstall.txt index 77a97cab0af..c4843a10caf 100644 --- a/doc/UnixInstall.txt +++ b/doc/UnixInstall.txt @@ -49,7 +49,7 @@ than where to install using flags built into our cmake files. Just open up CMakeLists.txt in the main folder and take a look at some of the flags like - SERVERS Build worldserver and authserver + SERVERS Build worldserver and bnetserver SCRIPTS Build core with scripts included TOOLS Build map/vmap extraction/assembler tools USE_SCRIPTPCH Use precompiled headers when compiling scripts diff --git a/src/server/CMakeLists.txt b/src/server/CMakeLists.txt index 62ddaaa89b8..a4a6ec7f70b 100644 --- a/src/server/CMakeLists.txt +++ b/src/server/CMakeLists.txt @@ -30,7 +30,6 @@ endif(WIN32) add_subdirectory(database) add_subdirectory(shared) add_subdirectory(ipc) -add_subdirectory(authserver) add_subdirectory(bnetserver) add_subdirectory(game) add_subdirectory(scripts) diff --git a/src/server/authserver/Authentication/AuthCodes.cpp b/src/server/authserver/Authentication/AuthCodes.cpp deleted file mode 100644 index 98d61ce2c4c..00000000000 --- a/src/server/authserver/Authentication/AuthCodes.cpp +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Copyright (C) 2008-2018 TrinityCore - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -#include "AuthCodes.h" -#include - -namespace AuthHelper -{ - static RealmBuildInfo const PostBcAcceptedClientBuilds[] = - { - {15595, 4, 3, 4, ' '}, - {14545, 4, 2, 2, ' '}, - {13623, 4, 0, 6, 'a'}, - {13930, 3, 3, 5, 'a'}, // 3.3.5a China Mainland build - {12340, 3, 3, 5, 'a'}, - {11723, 3, 3, 3, 'a'}, - {11403, 3, 3, 2, ' '}, - {11159, 3, 3, 0, 'a'}, - {10505, 3, 2, 2, 'a'}, - {9947, 3, 1, 3, ' '}, - {8606, 2, 4, 3, ' '}, - {0, 0, 0, 0, ' '} // terminator - }; - - static RealmBuildInfo const PreBcAcceptedClientBuilds[] = - { - {6141, 1, 12, 3, ' '}, - {6005, 1, 12, 2, ' '}, - {5875, 1, 12, 1, ' '}, - {0, 0, 0, 0, ' '} // terminator - }; - - bool IsPreBCAcceptedClientBuild(int build) - { - for (int i = 0; PreBcAcceptedClientBuilds[i].Build; ++i) - if (PreBcAcceptedClientBuilds[i].Build == build) - return true; - - return false; - } - - bool IsPostBCAcceptedClientBuild(int build) - { - for (int i = 0; PostBcAcceptedClientBuilds[i].Build; ++i) - if (PostBcAcceptedClientBuilds[i].Build == build) - return true; - - return false; - } - - bool IsAcceptedClientBuild(int build) - { - return (IsPostBCAcceptedClientBuild(build) || IsPreBCAcceptedClientBuild(build)); - } - - RealmBuildInfo const* GetBuildInfo(int build) - { - for (int i = 0; PostBcAcceptedClientBuilds[i].Build; ++i) - if (PostBcAcceptedClientBuilds[i].Build == build) - return &PostBcAcceptedClientBuilds[i]; - - for (int i = 0; PreBcAcceptedClientBuilds[i].Build; ++i) - if (PreBcAcceptedClientBuilds[i].Build == build) - return &PreBcAcceptedClientBuilds[i]; - - return nullptr; - } - - bool IsBuildSupportingBattlenet(int build) - { - return build >= 15595; - } -} diff --git a/src/server/authserver/Authentication/AuthCodes.h b/src/server/authserver/Authentication/AuthCodes.h deleted file mode 100644 index 80efec90c4c..00000000000 --- a/src/server/authserver/Authentication/AuthCodes.h +++ /dev/null @@ -1,132 +0,0 @@ -/* - * Copyright (C) 2008-2018 TrinityCore - * Copyright (C) 2005-2009 MaNGOS - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -#ifndef _AUTHCODES_H -#define _AUTHCODES_H - -enum AuthResult -{ - WOW_SUCCESS = 0x00, - WOW_FAIL_BANNED = 0x03, - WOW_FAIL_UNKNOWN_ACCOUNT = 0x04, - WOW_FAIL_INCORRECT_PASSWORD = 0x05, - WOW_FAIL_ALREADY_ONLINE = 0x06, - WOW_FAIL_NO_TIME = 0x07, - WOW_FAIL_DB_BUSY = 0x08, - WOW_FAIL_VERSION_INVALID = 0x09, - WOW_FAIL_VERSION_UPDATE = 0x0A, - WOW_FAIL_INVALID_SERVER = 0x0B, - WOW_FAIL_SUSPENDED = 0x0C, - WOW_FAIL_FAIL_NOACCESS = 0x0D, - WOW_SUCCESS_SURVEY = 0x0E, - WOW_FAIL_PARENTCONTROL = 0x0F, - WOW_FAIL_LOCKED_ENFORCED = 0x10, - WOW_FAIL_TRIAL_ENDED = 0x11, - WOW_FAIL_USE_BATTLENET = 0x12, - WOW_FAIL_ANTI_INDULGENCE = 0x13, - WOW_FAIL_EXPIRED = 0x14, - WOW_FAIL_NO_GAME_ACCOUNT = 0x15, - WOW_FAIL_CHARGEBACK = 0x16, - WOW_FAIL_INTERNET_GAME_ROOM_WITHOUT_BNET = 0x17, - WOW_FAIL_GAME_ACCOUNT_LOCKED = 0x18, - WOW_FAIL_UNLOCKABLE_LOCK = 0x19, - WOW_FAIL_CONVERSION_REQUIRED = 0x20, - WOW_FAIL_DISCONNECTED = 0xFF -}; - -enum LoginResult -{ - LOGIN_OK = 0x00, - LOGIN_FAILED = 0x01, - LOGIN_FAILED2 = 0x02, - LOGIN_BANNED = 0x03, - LOGIN_UNKNOWN_ACCOUNT = 0x04, - LOGIN_UNKNOWN_ACCOUNT3 = 0x05, - LOGIN_ALREADYONLINE = 0x06, - LOGIN_NOTIME = 0x07, - LOGIN_DBBUSY = 0x08, - LOGIN_BADVERSION = 0x09, - LOGIN_DOWNLOAD_FILE = 0x0A, - LOGIN_FAILED3 = 0x0B, - LOGIN_SUSPENDED = 0x0C, - LOGIN_FAILED4 = 0x0D, - LOGIN_CONNECTED = 0x0E, - LOGIN_PARENTALCONTROL = 0x0F, - LOGIN_LOCKED_ENFORCED = 0x10 -}; - -enum GameAccountFlags -{ - GAMEACCOUNT_FLAG_GM = 0x00000001, - GAMEACCOUNT_FLAG_NOKICK = 0x00000002, - GAMEACCOUNT_FLAG_COLLECTOR = 0x00000004, - GAMEACCOUNT_FLAG_WOW_TRIAL = 0x00000008, - GAMEACCOUNT_FLAG_CANCELLED = 0x00000010, - GAMEACCOUNT_FLAG_IGR = 0x00000020, - GAMEACCOUNT_FLAG_WHOLESALER = 0x00000040, - GAMEACCOUNT_FLAG_PRIVILEGED = 0x00000080, - GAMEACCOUNT_FLAG_EU_FORBID_ELV = 0x00000100, - GAMEACCOUNT_FLAG_EU_FORBID_BILLING = 0x00000200, - GAMEACCOUNT_FLAG_WOW_RESTRICTED = 0x00000400, - GAMEACCOUNT_FLAG_REFERRAL = 0x00000800, - GAMEACCOUNT_FLAG_BLIZZARD = 0x00001000, - GAMEACCOUNT_FLAG_RECURRING_BILLING = 0x00002000, - GAMEACCOUNT_FLAG_NOELECTUP = 0x00004000, - GAMEACCOUNT_FLAG_KR_CERTIFICATE = 0x00008000, - GAMEACCOUNT_FLAG_EXPANSION_COLLECTOR = 0x00010000, - GAMEACCOUNT_FLAG_DISABLE_VOICE = 0x00020000, - GAMEACCOUNT_FLAG_DISABLE_VOICE_SPEAK = 0x00040000, - GAMEACCOUNT_FLAG_REFERRAL_RESURRECT = 0x00080000, - GAMEACCOUNT_FLAG_EU_FORBID_CC = 0x00100000, - GAMEACCOUNT_FLAG_OPENBETA_DELL = 0x00200000, - GAMEACCOUNT_FLAG_PROPASS = 0x00400000, - GAMEACCOUNT_FLAG_PROPASS_LOCK = 0x00800000, - GAMEACCOUNT_FLAG_PENDING_UPGRADE = 0x01000000, - GAMEACCOUNT_FLAG_RETAIL_FROM_TRIAL = 0x02000000, - GAMEACCOUNT_FLAG_EXPANSION2_COLLECTOR = 0x04000000, - GAMEACCOUNT_FLAG_OVERMIND_LINKED = 0x08000000, - GAMEACCOUNT_FLAG_DEMOS = 0x10000000, - GAMEACCOUNT_FLAG_DEATH_KNIGHT_OK = 0x20000000, -}; - -enum ExpansionFlags -{ - POST_BC_EXP_FLAG = 0x2, - PRE_BC_EXP_FLAG = 0x1, - NO_VALID_EXP_FLAG = 0x0 -}; - -struct RealmBuildInfo -{ - int Build; - int MajorVersion; - int MinorVersion; - int BugfixVersion; - int HotfixVersion; -}; - -namespace AuthHelper -{ - RealmBuildInfo const* GetBuildInfo(int build); - bool IsAcceptedClientBuild(int build); - bool IsPostBCAcceptedClientBuild(int build); - bool IsPreBCAcceptedClientBuild(int build); - bool IsBuildSupportingBattlenet(int build); -} - -#endif diff --git a/src/server/authserver/Authentication/TOTP.cpp b/src/server/authserver/Authentication/TOTP.cpp deleted file mode 100644 index 76df2f653ec..00000000000 --- a/src/server/authserver/Authentication/TOTP.cpp +++ /dev/null @@ -1,95 +0,0 @@ -/* - * Copyright (C) 2008-2018 TrinityCore - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -#include "TOTP.h" -#include - -int base32_decode(char const* encoded, char* result, int bufSize) -{ - // Base32 implementation - // Copyright 2010 Google Inc. - // Author: Markus Gutschke - // Licensed under the Apache License, Version 2.0 - int buffer = 0; - int bitsLeft = 0; - int count = 0; - for (const char *ptr = encoded; count < bufSize && *ptr; ++ptr) - { - char ch = *ptr; - if (ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n' || ch == '-') - continue; - buffer <<= 5; - - // Deal with commonly mistyped characters - if (ch == '0') - ch = 'O'; - else if (ch == '1') - ch = 'L'; - else if (ch == '8') - ch = 'B'; - - // Look up one base32 digit - if ((ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z')) - ch = (ch & 0x1F) - 1; - else if (ch >= '2' && ch <= '7') - ch -= '2' - 26; - else - return -1; - - buffer |= ch; - bitsLeft += 5; - if (bitsLeft >= 8) - { - result[count++] = buffer >> (bitsLeft - 8); - bitsLeft -= 8; - } - } - - if (count < bufSize) - result[count] = '\000'; - return count; -} - -#define HMAC_RES_SIZE 20 - -namespace TOTP -{ - unsigned int GenerateToken(char const* b32key) - { - size_t keySize = strlen(b32key); - int bufsize = (keySize + 7)/8*5; - char* encoded = new char[bufsize]; - memset(encoded, 0, bufsize); - unsigned int hmacResSize = HMAC_RES_SIZE; - unsigned char hmacRes[HMAC_RES_SIZE]; - unsigned long timestamp = time(nullptr)/30; - unsigned char challenge[8]; - - for (int i = 8; i--;timestamp >>= 8) - challenge[i] = timestamp; - - base32_decode(b32key, encoded, bufsize); - HMAC(EVP_sha1(), encoded, bufsize, challenge, 8, hmacRes, &hmacResSize); - unsigned int offset = hmacRes[19] & 0xF; - unsigned int truncHash = (hmacRes[offset] << 24) | (hmacRes[offset+1] << 16 )| (hmacRes[offset+2] << 8) | (hmacRes[offset+3]); - truncHash &= 0x7FFFFFFF; - - delete[] encoded; - - return truncHash % 1000000; - } -} diff --git a/src/server/authserver/Authentication/TOTP.h b/src/server/authserver/Authentication/TOTP.h deleted file mode 100644 index 2c274a222b1..00000000000 --- a/src/server/authserver/Authentication/TOTP.h +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright (C) 2008-2018 TrinityCore - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -#ifndef _TOTP_H -#define _TOTP_H - -#include "openssl/hmac.h" -#include "openssl/evp.h" - -namespace TOTP -{ - unsigned int GenerateToken(char const* b32key); -} - -#endif diff --git a/src/server/authserver/CMakeLists.txt b/src/server/authserver/CMakeLists.txt deleted file mode 100644 index b56866ec0ee..00000000000 --- a/src/server/authserver/CMakeLists.txt +++ /dev/null @@ -1,90 +0,0 @@ -# Copyright (C) 2008-2018 TrinityCore -# -# This file is free software; as a special exception the author gives -# unlimited permission to copy and/or distribute it, with or without -# modifications, as long as this notice is preserved. -# -# This program is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY, to the extent permitted by law; without even the -# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - -########### authserver ############### - -CollectSourceFiles( - ${CMAKE_CURRENT_SOURCE_DIR} - PRIVATE_SOURCES - # Exclude - ${CMAKE_CURRENT_SOURCE_DIR}/PrecompiledHeaders) - -if( WIN32 ) - list(APPEND PRIVATE_SOURCES ${sources_windows}) - if ( MSVC ) - list(APPEND PRIVATE_SOURCES authserver.rc) - endif() -endif() - -if (USE_COREPCH) - set(PRIVATE_PCH_HEADER PrecompiledHeaders/authPCH.h) -endif() - -GroupSources(${CMAKE_CURRENT_SOURCE_DIR}) - -add_executable(authserver - ${PRIVATE_SOURCES} -) - -if( NOT WIN32 ) - set_target_properties(authserver PROPERTIES - COMPILE_DEFINITIONS _TRINITY_REALM_CONFIG="${CONF_DIR}/authserver.conf" - ) -endif() - -target_link_libraries(authserver - PRIVATE - trinity-core-interface - PUBLIC - shared) - -CollectIncludeDirectories( - ${CMAKE_CURRENT_SOURCE_DIR} - PUBLIC_INCLUDES - # Exclude - ${CMAKE_CURRENT_SOURCE_DIR}/PrecompiledHeaders) - -target_include_directories(authserver - PUBLIC - ${PUBLIC_INCLUDES} - PRIVATE - ${CMAKE_CURRENT_BINARY_DIR}) - -set_target_properties(authserver - PROPERTIES - FOLDER - "server") - -if( WIN32 ) - if ( "${CMAKE_MAKE_PROGRAM}" MATCHES "MSBuild" ) - add_custom_command(TARGET authserver - POST_BUILD - COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/authserver.conf.dist ${CMAKE_BINARY_DIR}/bin/$(ConfigurationName)/ - ) - elseif ( MINGW ) - add_custom_command(TARGET authserver - POST_BUILD - COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/authserver.conf.dist ${CMAKE_BINARY_DIR}/bin/ - ) - endif() -endif() - -if( UNIX ) - install(TARGETS authserver DESTINATION bin) - install(FILES authserver.conf.dist DESTINATION ${CONF_DIR}) -elseif( WIN32 ) - install(TARGETS authserver DESTINATION "${CMAKE_INSTALL_PREFIX}") - install(FILES authserver.conf.dist DESTINATION "${CMAKE_INSTALL_PREFIX}") -endif() - -# Generate precompiled header -if (USE_COREPCH) - add_cxx_pch(authserver ${PRIVATE_PCH_HEADER}) -endif() diff --git a/src/server/authserver/Main.cpp b/src/server/authserver/Main.cpp deleted file mode 100644 index 7e084d59de9..00000000000 --- a/src/server/authserver/Main.cpp +++ /dev/null @@ -1,344 +0,0 @@ -/* - * Copyright (C) 2008-2018 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 . - */ - -/** -* @file main.cpp -* @brief Authentication Server main program -* -* This file contains the main program for the -* authentication server -*/ - -#include "AppenderDB.h" -#include "AuthSocketMgr.h" -#include "Banner.h" -#include "Config.h" -#include "DatabaseEnv.h" -#include "DatabaseLoader.h" -#include "DeadlineTimer.h" -#include "GitRevision.h" -#include "GruntRealmList.h" -#include "IoContext.h" -#include "IPLocation.h" -#include "MySQLThreading.h" -#include "ProcessPriority.h" -#include "Util.h" -#include -#include -#include -#include -#include -#include -#include - -using boost::asio::ip::tcp; -using namespace boost::program_options; -namespace fs = boost::filesystem; - -#ifndef _TRINITY_REALM_CONFIG -# define _TRINITY_REALM_CONFIG "authserver.conf" -#endif - -#if TRINITY_PLATFORM == TRINITY_PLATFORM_WINDOWS -#include "ServiceWin32.h" -char serviceName[] = "authserver"; -char serviceLongName[] = "TrinityCore auth service"; -char serviceDescription[] = "TrinityCore World of Warcraft emulator auth service"; -/* -* -1 - not in service mode -* 0 - stopped -* 1 - running -* 2 - paused -*/ -int m_ServiceStatus = -1; - -void ServiceStatusWatcher(std::weak_ptr serviceStatusWatchTimerRef, std::weak_ptr ioContextRef, boost::system::error_code const& error); -#endif - -bool StartDB(); -void StopDB(); -void SignalHandler(std::weak_ptr ioContextRef, boost::system::error_code const& error, int signalNumber); -void KeepDatabaseAliveHandler(std::weak_ptr dbPingTimerRef, int32 dbPingInterval, boost::system::error_code const& error); -void BanExpiryHandler(std::weak_ptr banExpiryCheckTimerRef, int32 banExpiryCheckInterval, boost::system::error_code const& error); -variables_map GetConsoleArguments(int argc, char** argv, fs::path& configFile, std::string& configService); - -int main(int argc, char** argv) -{ - signal(SIGABRT, &Trinity::AbortHandler); - - auto configFile = fs::absolute(_TRINITY_REALM_CONFIG); - std::string configService; - auto vm = GetConsoleArguments(argc, argv, configFile, configService); - // exit if help or version is enabled - if (vm.count("help") || vm.count("version")) - return 0; - -#if TRINITY_PLATFORM == TRINITY_PLATFORM_WINDOWS - if (configService.compare("install") == 0) - return WinServiceInstall() == true ? 0 : 1; - else if (configService.compare("uninstall") == 0) - return WinServiceUninstall() == true ? 0 : 1; - else if (configService.compare("run") == 0) - return WinServiceRun() ? 0 : 1; -#endif - - std::string configError; - if (!sConfigMgr->LoadInitial(configFile.generic_string(), - std::vector(argv, argv + argc), - configError)) - { - printf("Error in config file: %s\n", configError.c_str()); - return 1; - } - - sLog->RegisterAppender(); - sLog->Initialize(nullptr); - - Trinity::Banner::Show("authserver", - [](char const* text) - { - TC_LOG_INFO("server.authserver", "%s", text); - }, - []() - { - TC_LOG_INFO("server.authserver", "Using configuration file %s.", sConfigMgr->GetFilename().c_str()); - TC_LOG_INFO("server.authserver", "Using SSL version: %s (library: %s)", OPENSSL_VERSION_TEXT, SSLeay_version(SSLEAY_VERSION)); - TC_LOG_INFO("server.authserver", "Using Boost version: %i.%i.%i", BOOST_VERSION / 100000, BOOST_VERSION / 100 % 1000, BOOST_VERSION % 100); - } - ); - - // authserver PID file creation - std::string pidFile = sConfigMgr->GetStringDefault("PidFile", ""); - if (!pidFile.empty()) - { - if (uint32 pid = CreatePIDFile(pidFile)) - TC_LOG_INFO("server.authserver", "Daemon PID: %u\n", pid); - else - { - TC_LOG_ERROR("server.authserver", "Cannot create PID file %s.\n", pidFile.c_str()); - return 1; - } - } - - // Initialize the database connection - if (!StartDB()) - return 1; - - // Load IP Location Database - sIPLocation->Load(); - - std::shared_ptr dbHandle(nullptr, [](void*) { StopDB(); }); - - std::shared_ptr ioContext = std::make_shared(); - - // Get the list of realms for the server - sGruntRealmList->Initialize(*ioContext, sConfigMgr->GetIntDefault("RealmsStateUpdateDelay", 20)); - - std::shared_ptr sRealmListHandle(nullptr, [](void*) { sGruntRealmList->Close(); }); - - if (sGruntRealmList->GetRealms().empty()) - { - TC_LOG_ERROR("server.authserver", "No valid realms specified."); - return 1; - } - - // Start the listening port (acceptor) for auth connections - int32 port = sConfigMgr->GetIntDefault("RealmServerPort", 3724); - if (port < 0 || port > 0xFFFF) - { - TC_LOG_ERROR("server.authserver", "Specified port out of allowed range (1-65535)"); - return 1; - } - - std::string bindIp = sConfigMgr->GetStringDefault("BindIP", "0.0.0.0"); - - if (!sAuthSocketMgr.StartNetwork(*ioContext, bindIp, port)) - { - TC_LOG_ERROR("server.authserver", "Failed to initialize network"); - return 1; - } - - std::shared_ptr sAuthSocketMgrHandle(nullptr, [](void*) { sAuthSocketMgr.StopNetwork(); }); - - // Set signal handlers - boost::asio::signal_set signals(*ioContext, SIGINT, SIGTERM); -#if TRINITY_PLATFORM == TRINITY_PLATFORM_WINDOWS - signals.add(SIGBREAK); -#endif - signals.async_wait(std::bind(&SignalHandler, std::weak_ptr(ioContext), std::placeholders::_1, std::placeholders::_2)); - - // Set process priority according to configuration settings - SetProcessPriority("server.authserver", sConfigMgr->GetIntDefault(CONFIG_PROCESSOR_AFFINITY, 0), sConfigMgr->GetBoolDefault(CONFIG_HIGH_PRIORITY, false)); - - // Enabled a timed callback for handling the database keep alive ping - int32 dbPingInterval = sConfigMgr->GetIntDefault("MaxPingTime", 30); - std::shared_ptr dbPingTimer = std::make_shared(*ioContext); - dbPingTimer->expires_from_now(boost::posix_time::minutes(dbPingInterval)); - dbPingTimer->async_wait(std::bind(&KeepDatabaseAliveHandler, std::weak_ptr(dbPingTimer), dbPingInterval, std::placeholders::_1)); - - int32 banExpiryCheckInterval = sConfigMgr->GetIntDefault("BanExpiryCheckInterval", 60); - std::shared_ptr banExpiryCheckTimer = std::make_shared(*ioContext); - banExpiryCheckTimer->expires_from_now(boost::posix_time::seconds(banExpiryCheckInterval)); - banExpiryCheckTimer->async_wait(std::bind(&BanExpiryHandler, std::weak_ptr(banExpiryCheckTimer), banExpiryCheckInterval, std::placeholders::_1)); - -#if TRINITY_PLATFORM == TRINITY_PLATFORM_WINDOWS - std::shared_ptr serviceStatusWatchTimer; - if (m_ServiceStatus != -1) - { - serviceStatusWatchTimer = std::make_shared(*ioContext); - serviceStatusWatchTimer->expires_from_now(boost::posix_time::seconds(1)); - serviceStatusWatchTimer->async_wait(std::bind(&ServiceStatusWatcher, - std::weak_ptr(serviceStatusWatchTimer), - std::weak_ptr(ioContext), - std::placeholders::_1)); - } -#endif - - // Start the io service worker loop - ioContext->run(); - - banExpiryCheckTimer->cancel(); - dbPingTimer->cancel(); - - TC_LOG_INFO("server.authserver", "Halting process..."); - - signals.cancel(); - - return 0; -} - -/// Initialize connection to the database -bool StartDB() -{ - MySQL::Library_Init(); - - // Load databases - // NOTE: While authserver is singlethreaded you should keep synch_threads == 1. - // Increasing it is just silly since only 1 will be used ever. - DatabaseLoader loader("server.authserver", DatabaseLoader::DATABASE_NONE); - loader - .AddDatabase(LoginDatabase, "Login"); - - if (!loader.Load()) - return false; - - TC_LOG_INFO("server.authserver", "Started auth database connection pool."); - sLog->SetRealmId(0); // Enables DB appenders when realm is set. - return true; -} - -/// Close the connection to the database -void StopDB() -{ - LoginDatabase.Close(); - MySQL::Library_End(); -} - -void SignalHandler(std::weak_ptr ioContextRef, boost::system::error_code const& error, int /*signalNumber*/) -{ - if (!error) - if (std::shared_ptr ioContext = ioContextRef.lock()) - ioContext->stop(); -} - -void KeepDatabaseAliveHandler(std::weak_ptr dbPingTimerRef, int32 dbPingInterval, boost::system::error_code const& error) -{ - if (!error) - { - if (std::shared_ptr dbPingTimer = dbPingTimerRef.lock()) - { - TC_LOG_INFO("server.authserver", "Ping MySQL to keep connection alive"); - LoginDatabase.KeepAlive(); - - dbPingTimer->expires_from_now(boost::posix_time::minutes(dbPingInterval)); - dbPingTimer->async_wait(std::bind(&KeepDatabaseAliveHandler, dbPingTimerRef, dbPingInterval, std::placeholders::_1)); - } - } -} - -void BanExpiryHandler(std::weak_ptr banExpiryCheckTimerRef, int32 banExpiryCheckInterval, boost::system::error_code const& error) -{ - if (!error) - { - if (std::shared_ptr banExpiryCheckTimer = banExpiryCheckTimerRef.lock()) - { - LoginDatabase.Execute(LoginDatabase.GetPreparedStatement(LOGIN_DEL_EXPIRED_IP_BANS)); - LoginDatabase.Execute(LoginDatabase.GetPreparedStatement(LOGIN_UPD_EXPIRED_ACCOUNT_BANS)); - - banExpiryCheckTimer->expires_from_now(boost::posix_time::seconds(banExpiryCheckInterval)); - banExpiryCheckTimer->async_wait(std::bind(&BanExpiryHandler, banExpiryCheckTimerRef, banExpiryCheckInterval, std::placeholders::_1)); - } - } -} - -#if TRINITY_PLATFORM == TRINITY_PLATFORM_WINDOWS -void ServiceStatusWatcher(std::weak_ptr serviceStatusWatchTimerRef, std::weak_ptr ioContextRef, boost::system::error_code const& error) -{ - if (!error) - { - if (std::shared_ptr ioContext = ioContextRef.lock()) - { - if (m_ServiceStatus == 0) - ioContext->stop(); - else if (std::shared_ptr serviceStatusWatchTimer = serviceStatusWatchTimerRef.lock()) - { - serviceStatusWatchTimer->expires_from_now(boost::posix_time::seconds(1)); - serviceStatusWatchTimer->async_wait(std::bind(&ServiceStatusWatcher, serviceStatusWatchTimerRef, ioContextRef, std::placeholders::_1)); - } - } - } -} -#endif - -variables_map GetConsoleArguments(int argc, char** argv, fs::path& configFile, std::string& configService) -{ - options_description all("Allowed options"); - all.add_options() - ("help,h", "print usage message") - ("version,v", "print version build info") - ("config,c", value(&configFile)->default_value(fs::absolute(_TRINITY_REALM_CONFIG)), - "use as configuration file") - ; -#if TRINITY_PLATFORM == TRINITY_PLATFORM_WINDOWS - options_description win("Windows platform specific options"); - win.add_options() - ("service,s", value(&configService)->default_value(""), "Windows service options: [install | uninstall]") - ; - - all.add(win); -#else - (void)configService; -#endif - variables_map variablesMap; - try - { - store(command_line_parser(argc, argv).options(all).allow_unregistered().run(), variablesMap); - notify(variablesMap); - } - catch (std::exception& e) - { - std::cerr << e.what() << "\n"; - } - - if (variablesMap.count("help")) - std::cout << all << "\n"; - else if (variablesMap.count("version")) - std::cout << GitRevision::GetFullVersion() << "\n"; - - return variablesMap; -} diff --git a/src/server/authserver/PrecompiledHeaders/authPCH.h b/src/server/authserver/PrecompiledHeaders/authPCH.h deleted file mode 100644 index b2be78a8a37..00000000000 --- a/src/server/authserver/PrecompiledHeaders/authPCH.h +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright (C) 2008-2018 TrinityCore - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -#include "Common.h" -#include "Configuration/Config.h" -#include "Database/DatabaseEnv.h" -#include "Log.h" -#include "GruntRealmList.h" -#include "AuthSession.h" diff --git a/src/server/authserver/Realms/GruntRealmList.cpp b/src/server/authserver/Realms/GruntRealmList.cpp deleted file mode 100644 index 29877dd33a8..00000000000 --- a/src/server/authserver/Realms/GruntRealmList.cpp +++ /dev/null @@ -1,190 +0,0 @@ -/* - * Copyright (C) 2008-2018 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 "GruntRealmList.h" -#include "DatabaseEnv.h" -#include "DeadlineTimer.h" -#include "DeadlineTimer.h" -#include "IoContext.h" -#include "Log.h" -#include "Resolver.h" -#include "Util.h" -#include - -GruntRealmList::GruntRealmList() : _updateInterval(0) -{ -} - -GruntRealmList::~GruntRealmList() -{ -} - -GruntRealmList* GruntRealmList::Instance() -{ - static GruntRealmList instance; - return &instance; -} - -// Load the realm list from the database -void GruntRealmList::Initialize(Trinity::Asio::IoContext& ioContext, uint32 updateInterval) -{ - _updateInterval = updateInterval; - _updateTimer = Trinity::make_unique(ioContext); - _resolver = Trinity::make_unique(ioContext); - - // Get the content of the realmlist table in the database - UpdateRealms(boost::system::error_code()); -} - -void GruntRealmList::Close() -{ - _updateTimer->cancel(); -} - -void GruntRealmList::UpdateRealm(Battlenet::RealmHandle const& id, uint32 build, std::string const& name, - boost::asio::ip::address&& address, boost::asio::ip::address&& localAddr, boost::asio::ip::address&& localSubmask, - uint16 port, uint8 icon, RealmFlags flag, uint8 timezone, AccountTypes allowedSecurityLevel, float population) -{ - // Create new if not exist or update existed - Realm& realm = _realms[id]; - - // grunt server doesn't use these values, but keep them initialized - realm.Updated = false; - realm.Keep = true; - - realm.Id = id; - realm.Build = build; - realm.Name = name; - realm.Type = icon; - realm.Flags = flag; - realm.Timezone = timezone; - realm.AllowedSecurityLevel = allowedSecurityLevel; - realm.PopulationLevel = population; - if (!realm.ExternalAddress || *realm.ExternalAddress != address) - realm.ExternalAddress = Trinity::make_unique(std::move(address)); - if (!realm.LocalAddress || *realm.LocalAddress != localAddr) - realm.LocalAddress = Trinity::make_unique(std::move(localAddr)); - if (!realm.LocalSubnetMask || *realm.LocalSubnetMask != localSubmask) - realm.LocalSubnetMask = Trinity::make_unique(std::move(localSubmask)); - realm.Port = port; -} - -void GruntRealmList::UpdateRealms(boost::system::error_code const& error) -{ - if (error) - return; - - TC_LOG_DEBUG("server.authserver", "Updating Realm List..."); - - PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_REALMLIST); - PreparedQueryResult result = LoginDatabase.Query(stmt); - - std::map existingRealms; - for (auto const& p : _realms) - existingRealms[p.first] = p.second.Name; - - _realms.clear(); - - // Circle through results and add them to the realm map - if (result) - { - do - { - try - { - Field* fields = result->Fetch(); - uint32 realmId = fields[0].GetUInt32(); - std::string name = fields[1].GetString(); - std::string externalAddressString = fields[2].GetString(); - std::string localAddressString = fields[3].GetString(); - std::string localSubmaskString = fields[4].GetString(); - - Optional externalAddress = Trinity::Net::Resolve(*_resolver, boost::asio::ip::tcp::v4(), externalAddressString, ""); - if (!externalAddress) - { - TC_LOG_ERROR("realmlist", "Could not resolve address %s", externalAddressString.c_str()); - continue; - } - - Optional localAddress = Trinity::Net::Resolve(*_resolver, boost::asio::ip::tcp::v4(), localAddressString, ""); - if (!localAddress) - { - TC_LOG_ERROR("realmlist", "Could not resolve address %s", localAddressString.c_str()); - continue; - } - - Optional localSubmask = Trinity::Net::Resolve(*_resolver, boost::asio::ip::tcp::v4(), localSubmaskString, ""); - if (!localSubmask) - { - TC_LOG_ERROR("realmlist", "Could not resolve address %s", localSubmaskString.c_str()); - continue; - } - - uint16 port = fields[5].GetUInt16(); - uint8 icon = fields[6].GetUInt8(); - if (icon == REALM_TYPE_FFA_PVP) - icon = REALM_TYPE_PVP; - if (icon >= MAX_CLIENT_REALM_TYPE) - icon = REALM_TYPE_NORMAL; - 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(); - uint8 region = fields[12].GetUInt8(); - uint8 battlegroup = fields[13].GetUInt8(); - - Battlenet::RealmHandle id{ region, battlegroup, realmId }; - - UpdateRealm(id, build, name, externalAddress->address(), localAddress->address(), localSubmask->address(), port, icon, flag, - timezone, (allowedSecurityLevel <= SEC_ADMINISTRATOR ? AccountTypes(allowedSecurityLevel) : SEC_ADMINISTRATOR), pop); - - if (!existingRealms.count(id)) - TC_LOG_INFO("server.authserver", "Added realm \"%s\" at %s:%u.", name.c_str(), externalAddressString.c_str(), port); - else - TC_LOG_DEBUG("server.authserver", "Updating realm \"%s\" at %s:%u.", name.c_str(), externalAddressString.c_str(), port); - - existingRealms.erase(id); - } - catch (std::exception& ex) - { - TC_LOG_ERROR("server.authserver", "GruntRealmList::UpdateRealms has thrown an exception: %s", ex.what()); - ABORT(); - } - } - while (result->NextRow()); - } - - for (auto itr = existingRealms.begin(); itr != existingRealms.end(); ++itr) - TC_LOG_INFO("server.authserver", "Removed realm \"%s\".", itr->second.c_str()); - - if (_updateInterval) - { - _updateTimer->expires_from_now(boost::posix_time::seconds(_updateInterval)); - _updateTimer->async_wait(std::bind(&GruntRealmList::UpdateRealms, this, std::placeholders::_1)); - } -} - -Realm const* GruntRealmList::GetRealm(Battlenet::RealmHandle const& id) const -{ - auto itr = _realms.find(id); - if (itr != _realms.end()) - return &itr->second; - - return nullptr; -} diff --git a/src/server/authserver/Realms/GruntRealmList.h b/src/server/authserver/Realms/GruntRealmList.h deleted file mode 100644 index 1f314e9d371..00000000000 --- a/src/server/authserver/Realms/GruntRealmList.h +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright (C) 2008-2018 TrinityCore - * Copyright (C) 2005-2009 MaNGOS - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -#ifndef GruntRealmList_h__ -#define GruntRealmList_h__ - -#include "Define.h" -#include "Realm.h" -#include -#include -#include - -namespace boost -{ - namespace system - { - class error_code; - } -} - -namespace Trinity -{ - namespace Asio - { - class IoContext; - class DeadlineTimer; - } -} - -/// Storage object for the list of realms on the server -class GruntRealmList -{ - public: - typedef std::map RealmMap; - - static GruntRealmList* Instance(); - - ~GruntRealmList(); - - void Initialize(Trinity::Asio::IoContext& ioContext, uint32 updateInterval); - void Close(); - - RealmMap const& GetRealms() const { return _realms; } - Realm const* GetRealm(Battlenet::RealmHandle const& id) const; - - private: - GruntRealmList(); - - void UpdateRealms(boost::system::error_code const& error); - void UpdateRealm(Battlenet::RealmHandle const& id, uint32 build, std::string const& name, - boost::asio::ip::address&& address, boost::asio::ip::address&& localAddr, boost::asio::ip::address&& localSubmask, - uint16 port, uint8 icon, RealmFlags flag, uint8 timezone, AccountTypes allowedSecurityLevel, float population); - - RealmMap _realms; - uint32 _updateInterval; - std::unique_ptr _updateTimer; - std::unique_ptr _resolver; -}; - -#define sGruntRealmList GruntRealmList::Instance() - -#endif // GruntRealmList_h__ diff --git a/src/server/authserver/Server/AuthSession.cpp b/src/server/authserver/Server/AuthSession.cpp deleted file mode 100644 index c78f14be399..00000000000 --- a/src/server/authserver/Server/AuthSession.cpp +++ /dev/null @@ -1,924 +0,0 @@ -/* -* Copyright (C) 2008-2018 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 "AuthSession.h" -#include "AuthCodes.h" -#include "ByteBuffer.h" -#include "Config.h" -#include "DatabaseEnv.h" -#include "Errors.h" -#include "IPLocation.h" -#include "GruntRealmList.h" -#include "Log.h" -#include "Realm.h" -#include "SHA1.h" -#include "TOTP.h" -#include "Util.h" -#include -#include - -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 -}; - -#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 AccountFlags; - uint32 SurveyId; - 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) - -enum class BufferSizes : uint32 -{ - SRP_6_V = 0x20, - SRP_6_S = 0x20, -}; - -#define MAX_ACCEPTED_CHALLENGE_SIZE (sizeof(AUTH_LOGON_CHALLENGE_C) + 16) - -#define AUTH_LOGON_CHALLENGE_INITIAL_SIZE 4 -#define REALM_LIST_PACKET_SIZE 5 - -std::unordered_map AuthSession::InitHandlers() -{ - std::unordered_map handlers; - - handlers[AUTH_LOGON_CHALLENGE] = { STATUS_CHALLENGE, AUTH_LOGON_CHALLENGE_INITIAL_SIZE, &AuthSession::HandleLogonChallenge }; - handlers[AUTH_LOGON_PROOF] = { STATUS_LOGON_PROOF, sizeof(AUTH_LOGON_PROOF_C), &AuthSession::HandleLogonProof }; - handlers[AUTH_RECONNECT_CHALLENGE] = { STATUS_CHALLENGE, AUTH_LOGON_CHALLENGE_INITIAL_SIZE, &AuthSession::HandleReconnectChallenge }; - handlers[AUTH_RECONNECT_PROOF] = { STATUS_RECONNECT_PROOF, sizeof(AUTH_RECONNECT_PROOF_C), &AuthSession::HandleReconnectProof }; - handlers[REALM_LIST] = { STATUS_AUTHED, REALM_LIST_PACKET_SIZE, &AuthSession::HandleRealmList }; - - return handlers; -} - -std::unordered_map const Handlers = AuthSession::InitHandlers(); - -void AccountInfo::LoadResult(Field* fields) -{ - // 0 1 2 3 4 5 6 - //SELECT a.id, a.username, a.locked, a.lock_country, a.last_ip, a.failed_logins, ab.unbandate > UNIX_TIMESTAMP() OR ab.unbandate = ab.bandate, - // 7 8 9 10 11 12 - // ab.unbandate = ab.bandate, aa.gmlevel, a.token_key, a.sha_pass_hash, a.v, a.s - //FROM account a LEFT JOIN account_access aa ON a.id = aa.id LEFT JOIN account_banned ab ON ab.id = a.id AND ab.active = 1 WHERE a.username = ? - - Id = fields[0].GetUInt32(); - Login = fields[1].GetString(); - IsLockedToIP = fields[2].GetBool(); - LockCountry = fields[3].GetString(); - LastIP = fields[4].GetString(); - FailedLogins = fields[5].GetUInt32(); - IsBanned = fields[6].GetUInt64() != 0; - IsPermanenetlyBanned = fields[7].GetUInt64() != 0; - SecurityLevel = AccountTypes(fields[8].GetUInt8()); - - // Use our own uppercasing of the account name instead of using UPPER() in mysql query - // This is how the account was created in the first place and changing it now would result in breaking - // login for all accounts having accented characters in their name - Utf8ToUpperOnlyLatin(Login); -} - -AuthSession::AuthSession(tcp::socket&& socket) : Socket(std::move(socket)), -_status(STATUS_CHALLENGE), _build(0), _expversion(0) -{ - N.SetHexStr("894B645E89E1535BBDAD5B8B290650530801B18EBFBF5E8FAB3C82872A3E9BB7"); - g.SetDword(7); -} - -void AuthSession::Start() -{ - std::string ip_address = GetRemoteIpAddress().to_string(); - TC_LOG_TRACE("session", "Accepted connection from %s", ip_address.c_str()); - - PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_IP_INFO); - stmt->setString(0, ip_address); - - _queryProcessor.AddQuery(LoginDatabase.AsyncQuery(stmt).WithPreparedCallback(std::bind(&AuthSession::CheckIpCallback, this, std::placeholders::_1))); -} - -bool AuthSession::Update() -{ - if (!AuthSocket::Update()) - return false; - - _queryProcessor.ProcessReadyQueries(); - - return true; -} - -void AuthSession::CheckIpCallback(PreparedQueryResult result) -{ - if (result) - { - bool banned = false; - do - { - Field* fields = result->Fetch(); - if (fields[0].GetUInt64() != 0) - banned = true; - - } while (result->NextRow()); - - if (banned) - { - ByteBuffer pkt; - pkt << uint8(AUTH_LOGON_CHALLENGE); - pkt << uint8(0x00); - pkt << uint8(WOW_FAIL_BANNED); - SendPacket(pkt); - TC_LOG_DEBUG("session", "[AuthSession::CheckIpCallback] Banned ip '%s:%d' tries to login!", GetRemoteIpAddress().to_string().c_str(), GetRemotePort()); - return; - } - } - - AsyncRead(); -} - -void AuthSession::ReadHandler() -{ - MessageBuffer& packet = GetReadBuffer(); - while (packet.GetActiveSize()) - { - uint8 cmd = packet.GetReadPointer()[0]; - auto itr = Handlers.find(cmd); - if (itr == Handlers.end()) - { - // well we dont handle this, lets just ignore it - packet.Reset(); - break; - } - - if (_status != itr->second.status) - { - CloseSocket(); - return; - } - - uint16 size = uint16(itr->second.packetSize); - if (packet.GetActiveSize() < size) - break; - - if (cmd == AUTH_LOGON_CHALLENGE || cmd == AUTH_RECONNECT_CHALLENGE) - { - sAuthLogonChallenge_C* challenge = reinterpret_cast(packet.GetReadPointer()); - size += challenge->size; - if (size > MAX_ACCEPTED_CHALLENGE_SIZE) - { - CloseSocket(); - return; - } - } - - if (packet.GetActiveSize() < size) - break; - - if (!(*this.*itr->second.handler)()) - { - CloseSocket(); - return; - } - - packet.ReadCompleted(size); - } - - AsyncRead(); -} - -void AuthSession::SendPacket(ByteBuffer& packet) -{ - if (!IsOpen()) - return; - - if (!packet.empty()) - { - MessageBuffer buffer; - buffer.Write(packet.contents(), packet.size()); - QueuePacket(std::move(buffer)); - } -} - -bool AuthSession::HandleLogonChallenge() -{ - _status = STATUS_CLOSED; - - sAuthLogonChallenge_C* challenge = reinterpret_cast(GetReadBuffer().GetReadPointer()); - if (challenge->size - (sizeof(sAuthLogonChallenge_C) - AUTH_LOGON_CHALLENGE_INITIAL_SIZE - 1) != challenge->I_len) - return false; - - std::string login((char const*)challenge->I, challenge->I_len); - TC_LOG_DEBUG("server.authserver", "[AuthChallenge] '%s'", login.c_str()); - - _build = challenge->build; - _expversion = uint8(AuthHelper::IsPostBCAcceptedClientBuild(_build) ? POST_BC_EXP_FLAG : (AuthHelper::IsPreBCAcceptedClientBuild(_build) ? PRE_BC_EXP_FLAG : NO_VALID_EXP_FLAG)); - std::array os; - os.fill('\0'); - memcpy(os.data(), challenge->os, sizeof(challenge->os)); - _os = os.data(); - - // Restore string order as its byte order is reversed - std::reverse(_os.begin(), _os.end()); - - _localizationName.resize(4); - for (int i = 0; i < 4; ++i) - _localizationName[i] = challenge->country[4 - i - 1]; - - // Get the account details from the account table - PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_LOGONCHALLENGE); - stmt->setString(0, login); - - _queryProcessor.AddQuery(LoginDatabase.AsyncQuery(stmt).WithPreparedCallback(std::bind(&AuthSession::LogonChallengeCallback, this, std::placeholders::_1))); - return true; -} - -void AuthSession::LogonChallengeCallback(PreparedQueryResult result) -{ - ByteBuffer pkt; - pkt << uint8(AUTH_LOGON_CHALLENGE); - pkt << uint8(0x00); - - if (!result) - { - pkt << uint8(WOW_FAIL_UNKNOWN_ACCOUNT); - SendPacket(pkt); - return; - } - - Field* fields = result->Fetch(); - - _accountInfo.LoadResult(fields); - - std::string ipAddress = GetRemoteIpAddress().to_string(); - uint16 port = GetRemotePort(); - - // If the IP is 'locked', check that the player comes indeed from the correct IP address - if (_accountInfo.IsLockedToIP) - { - TC_LOG_DEBUG("server.authserver", "[AuthChallenge] Account '%s' is locked to IP - '%s' is logging in from '%s'", _accountInfo.Login.c_str(), _accountInfo.LastIP.c_str(), ipAddress.c_str()); - if (_accountInfo.LastIP != ipAddress) - { - pkt << uint8(WOW_FAIL_LOCKED_ENFORCED); - SendPacket(pkt); - return; - } - } - else - { - if (IpLocationRecord const* location = sIPLocation->GetLocationRecord(ipAddress)) - _ipCountry = location->CountryCode; - - TC_LOG_DEBUG("server.authserver", "[AuthChallenge] Account '%s' is not locked to ip", _accountInfo.Login.c_str()); - if (_accountInfo.LockCountry.empty() || _accountInfo.LockCountry == "00") - TC_LOG_DEBUG("server.authserver", "[AuthChallenge] Account '%s' is not locked to country", _accountInfo.Login.c_str()); - else if (!_accountInfo.LockCountry.empty() && !_ipCountry.empty()) - { - TC_LOG_DEBUG("server.authserver", "[AuthChallenge] Account '%s' is locked to country: '%s' Player country is '%s'", _accountInfo.Login.c_str(), _accountInfo.LockCountry.c_str(), _ipCountry.c_str()); - if (_ipCountry != _accountInfo.LockCountry) - { - pkt << uint8(WOW_FAIL_UNLOCKABLE_LOCK); - SendPacket(pkt); - return; - } - } - } - - // If the account is banned, reject the logon attempt - if (_accountInfo.IsBanned) - { - if (_accountInfo.IsPermanenetlyBanned) - { - pkt << uint8(WOW_FAIL_BANNED); - SendPacket(pkt); - TC_LOG_INFO("server.authserver.banned", "'%s:%d' [AuthChallenge] Banned account %s tried to login!", ipAddress.c_str(), port, _accountInfo.Login.c_str()); - return; - } - else - { - pkt << uint8(WOW_FAIL_SUSPENDED); - SendPacket(pkt); - TC_LOG_INFO("server.authserver.banned", "'%s:%d' [AuthChallenge] Temporarily banned account %s tried to login!", ipAddress.c_str(), port, _accountInfo.Login.c_str()); - return; - } - } - - // Get the password from the account table, upper it, and make the SRP6 calculation - std::string rI = fields[10].GetString(); - - // Don't calculate (v, s) if there are already some in the database - std::string databaseV = fields[11].GetString(); - std::string databaseS = fields[12].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() != size_t(BufferSizes::SRP_6_V) * 2 || databaseS.size() != size_t(BufferSizes::SRP_6_S) * 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 (fields[13].GetUInt32() && AuthHelper::IsBuildSupportingBattlenet(_build)) - pkt << uint8(WOW_FAIL_USE_BATTLENET); - else if (AuthHelper::IsAcceptedClientBuild(_build)) - { - pkt << uint8(WOW_SUCCESS); - _status = STATUS_LOGON_PROOF; - } - 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(1).get(), 1); - pkt << uint8(32); - pkt.append(N.AsByteArray(32).get(), 32); - pkt.append(s.AsByteArray(int32(BufferSizes::SRP_6_S)).get(), size_t(BufferSizes::SRP_6_S)); // 32 bytes - pkt.append(unk3.AsByteArray(16).get(), 16); - uint8 securityFlags = 0; - - // Check if token is used - _tokenKey = fields[9].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); - - TC_LOG_DEBUG("server.authserver", "'%s:%d' [AuthChallenge] account %s is using '%s' locale (%u)", - ipAddress.c_str(), port, _accountInfo.Login.c_str(), _localizationName.c_str(), GetLocaleByName(_localizationName)); - - SendPacket(pkt); -} - -// Logon Proof command handler -bool AuthSession::HandleLogonProof() -{ - TC_LOG_DEBUG("server.authserver", "Entering _HandleLogonProof"); - _status = STATUS_CLOSED; - - // Read the packet - sAuthLogonProof_C *logonProof = reinterpret_cast(GetReadBuffer().GetReadPointer()); - - // 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 % N).IsZero()) - return false; - - SHA1Hash sha; - sha.UpdateBigNumbers(&A, &B, nullptr); - 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, nullptr); - sha.Finalize(); - memcpy(hash, sha.GetDigest(), 20); - sha.Initialize(); - sha.UpdateBigNumbers(&g, nullptr); - sha.Finalize(); - - for (int i = 0; i < 20; ++i) - hash[i] ^= sha.GetDigest()[i]; - - BigNumber t3; - t3.SetBinary(hash, 20); - - sha.Initialize(); - sha.UpdateData(_accountInfo.Login); - sha.Finalize(); - uint8 t4[SHA_DIGEST_LENGTH]; - memcpy(t4, sha.GetDigest(), SHA_DIGEST_LENGTH); - - sha.Initialize(); - sha.UpdateBigNumbers(&t3, nullptr); - sha.UpdateData(t4, SHA_DIGEST_LENGTH); - sha.UpdateBigNumbers(&s, &A, &B, &K, nullptr); - sha.Finalize(); - BigNumber M; - M.SetBinary(sha.GetDigest(), sha.GetLength()); - - // Check if SRP6 results match (password is correct), else send an error - if (!memcmp(M.AsByteArray(sha.GetLength()).get(), logonProof->M1, 20)) - { - // Check auth token - if ((logonProof->securityFlags & 0x04) || !_tokenKey.empty()) - { - uint8 size = *(GetReadBuffer().GetReadPointer() + sizeof(sAuthLogonProof_C)); - std::string token(reinterpret_cast(GetReadBuffer().GetReadPointer() + sizeof(sAuthLogonProof_C) + sizeof(size)), size); - GetReadBuffer().ReadCompleted(sizeof(size) + size); - uint32 validToken = TOTP::GenerateToken(_tokenKey.c_str()); - _tokenKey.clear(); - uint32 incomingToken = atoi(token.c_str()); - if (validToken != incomingToken) - { - ByteBuffer packet; - packet << uint8(AUTH_LOGON_PROOF); - packet << uint8(WOW_FAIL_UNKNOWN_ACCOUNT); - packet << uint8(3); - packet << uint8(0); - SendPacket(packet); - return true; - } - } - - TC_LOG_DEBUG("server.authserver", "'%s:%d' User '%s' successfully authenticated", GetRemoteIpAddress().to_string().c_str(), GetRemotePort(), _accountInfo.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 - - PreparedStatement *stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_LOGONPROOF); - stmt->setString(0, K.AsHexStr()); - stmt->setString(1, GetRemoteIpAddress().to_string()); - stmt->setUInt32(2, GetLocaleByName(_localizationName)); - stmt->setString(3, _os); - stmt->setString(4, _accountInfo.Login); - LoginDatabase.DirectExecute(stmt); - - // Finish SRP6 and send the final result to the client - sha.Initialize(); - sha.UpdateBigNumbers(&A, &M, &K, nullptr); - sha.Finalize(); - - ByteBuffer packet; - 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.AccountFlags = GAMEACCOUNT_FLAG_PROPASS_LOCK; - proof.SurveyId = 0; - proof.unk3 = 0; - - packet.resize(sizeof(proof)); - std::memcpy(packet.contents(), &proof, sizeof(proof)); - } - else - { - sAuthLogonProof_S_Old proof; - memcpy(proof.M2, sha.GetDigest(), 20); - proof.cmd = AUTH_LOGON_PROOF; - proof.error = 0; - proof.unk2 = 0x00; - - packet.resize(sizeof(proof)); - std::memcpy(packet.contents(), &proof, sizeof(proof)); - } - - SendPacket(packet); - _status = STATUS_AUTHED; - } - else - { - ByteBuffer packet; - packet << uint8(AUTH_LOGON_PROOF); - packet << uint8(WOW_FAIL_UNKNOWN_ACCOUNT); - packet << uint8(3); - packet << uint8(0); - SendPacket(packet); - - TC_LOG_INFO("server.authserver.hack", "'%s:%d' [AuthChallenge] account %s tried to login with invalid password!", - GetRemoteIpAddress().to_string().c_str(), GetRemotePort(), _accountInfo.Login.c_str()); - - 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("WrongPass.Logging", false)) - { - PreparedStatement* logstmt = LoginDatabase.GetPreparedStatement(LOGIN_INS_FALP_IP_LOGGING); - logstmt->setUInt32(0, _accountInfo.Id); - logstmt->setString(1, GetRemoteIpAddress().to_string()); - logstmt->setString(2, "Logged on failed AccountLogin due wrong password"); - - LoginDatabase.Execute(logstmt); - } - - 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, _accountInfo.Login); - LoginDatabase.Execute(stmt); - - if (++_accountInfo.FailedLogins >= MaxWrongPassCount) - { - uint32 WrongPassBanTime = sConfigMgr->GetIntDefault("WrongPass.BanTime", 600); - bool WrongPassBanType = sConfigMgr->GetBoolDefault("WrongPass.BanType", false); - - if (WrongPassBanType) - { - stmt = LoginDatabase.GetPreparedStatement(LOGIN_INS_ACCOUNT_AUTO_BANNED); - stmt->setUInt32(0, _accountInfo.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().to_string().c_str(), GetRemotePort(), _accountInfo.Login.c_str(), WrongPassBanTime, _accountInfo.FailedLogins); - } - else - { - stmt = LoginDatabase.GetPreparedStatement(LOGIN_INS_IP_AUTO_BANNED); - stmt->setString(0, GetRemoteIpAddress().to_string()); - 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().to_string().c_str(), GetRemotePort(), WrongPassBanTime, _accountInfo.Login.c_str(), _accountInfo.FailedLogins); - } - } - } - } - - return true; -} - -bool AuthSession::HandleReconnectChallenge() -{ - _status = STATUS_CLOSED; - - sAuthLogonChallenge_C* challenge = reinterpret_cast(GetReadBuffer().GetReadPointer()); - if (challenge->size - (sizeof(sAuthLogonChallenge_C) - AUTH_LOGON_CHALLENGE_INITIAL_SIZE - 1) != challenge->I_len) - return false; - - std::string login((char const*)challenge->I, challenge->I_len); - TC_LOG_DEBUG("server.authserver", "[ReconnectChallenge] '%s'", login.c_str()); - - _build = challenge->build; - _expversion = uint8(AuthHelper::IsPostBCAcceptedClientBuild(_build) ? POST_BC_EXP_FLAG : (AuthHelper::IsPreBCAcceptedClientBuild(_build) ? PRE_BC_EXP_FLAG : NO_VALID_EXP_FLAG)); - std::array os; - os.fill('\0'); - memcpy(os.data(), challenge->os, sizeof(challenge->os)); - _os = os.data(); - - // Restore string order as its byte order is reversed - std::reverse(_os.begin(), _os.end()); - - _localizationName.resize(4); - for (int i = 0; i < 4; ++i) - _localizationName[i] = challenge->country[4 - i - 1]; - - // Get the account details from the account table - PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_RECONNECTCHALLENGE); - stmt->setString(0, login); - - _queryProcessor.AddQuery(LoginDatabase.AsyncQuery(stmt).WithPreparedCallback(std::bind(&AuthSession::ReconnectChallengeCallback, this, std::placeholders::_1))); - return true; -} - -void AuthSession::ReconnectChallengeCallback(PreparedQueryResult result) -{ - ByteBuffer pkt; - pkt << uint8(AUTH_RECONNECT_CHALLENGE); - - if (!result) - { - pkt << uint8(WOW_FAIL_UNKNOWN_ACCOUNT); - SendPacket(pkt); - return; - } - - Field* fields = result->Fetch(); - - _accountInfo.LoadResult(fields); - K.SetHexStr(fields[9].GetCString()); - _reconnectProof.SetRand(16 * 8); - _status = STATUS_RECONNECT_PROOF; - - pkt << uint8(WOW_SUCCESS); - pkt.append(_reconnectProof.AsByteArray(16).get(), 16); // 16 bytes random - pkt << uint64(0x00) << uint64(0x00); // 16 bytes zeros - - SendPacket(pkt); -} - -bool AuthSession::HandleReconnectProof() -{ - TC_LOG_DEBUG("server.authserver", "Entering _HandleReconnectProof"); - _status = STATUS_CLOSED; - - sAuthReconnectProof_C *reconnectProof = reinterpret_cast(GetReadBuffer().GetReadPointer()); - - if (_accountInfo.Login.empty() || !_reconnectProof.GetNumBytes() || !K.GetNumBytes()) - return false; - - BigNumber t1; - t1.SetBinary(reconnectProof->R1, 16); - - SHA1Hash sha; - sha.Initialize(); - sha.UpdateData(_accountInfo.Login); - sha.UpdateBigNumbers(&t1, &_reconnectProof, &K, nullptr); - 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 - SendPacket(pkt); - _status = STATUS_AUTHED; - return true; - } - else - { - TC_LOG_ERROR("server.authserver.hack", "'%s:%d' [ERROR] user %s tried to login, but session is invalid.", GetRemoteIpAddress().to_string().c_str(), - GetRemotePort(), _accountInfo.Login.c_str()); - return false; - } -} - -bool AuthSession::HandleRealmList() -{ - TC_LOG_DEBUG("server.authserver", "Entering _HandleRealmList"); - - PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_REALM_CHARACTER_COUNTS); - stmt->setUInt32(0, _accountInfo.Id); - - _queryProcessor.AddQuery(LoginDatabase.AsyncQuery(stmt).WithPreparedCallback(std::bind(&AuthSession::RealmListCallback, this, std::placeholders::_1))); - _status = STATUS_WAITING_FOR_REALM_LIST; - return true; -} - -void AuthSession::RealmListCallback(PreparedQueryResult result) -{ - std::map characterCounts; - if (result) - { - do - { - Field* fields = result->Fetch(); - characterCounts[fields[0].GetUInt32()] = fields[1].GetUInt8(); - } while (result->NextRow()); - } - - // 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 (auto const& i : sGruntRealmList->GetRealms()) - { - Realm const& realm = i.second; - // don't work with realms which not compatible with the client - bool okBuild = ((_expversion & POST_BC_EXP_FLAG) && realm.Build == _build) || ((_expversion & PRE_BC_EXP_FLAG) && !AuthHelper::IsPreBCAcceptedClientBuild(realm.Build)); - - // No SQL injection. id of realm is controlled by the database. - uint32 flag = realm.Flags; - RealmBuildInfo const* buildInfo = AuthHelper::GetBuildInfo(realm.Build); - 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 = realm.Name; - if (_expversion & PRE_BC_EXP_FLAG && flag & REALM_FLAG_SPECIFYBUILD) - { - std::ostringstream ss; - ss << name << " (" << buildInfo->MajorVersion << '.' << buildInfo->MinorVersion << '.' << buildInfo->BugfixVersion << ')'; - name = ss.str(); - } - - uint8 lock = (realm.AllowedSecurityLevel > _accountInfo.SecurityLevel) ? 1 : 0; - - pkt << uint8(realm.Type); // realm type - if (_expversion & POST_BC_EXP_FLAG) // only 2.x and 3.x clients - pkt << uint8(lock); // if 1, then realm locked - pkt << uint8(flag); // RealmFlags - pkt << name; - pkt << boost::lexical_cast(realm.GetAddressForClient(GetRemoteIpAddress())); - pkt << float(realm.PopulationLevel); - pkt << uint8(characterCounts[realm.Id.Realm]); - pkt << uint8(realm.Timezone); // realm category - if (_expversion & POST_BC_EXP_FLAG) // 2.x and 3.x clients - pkt << uint8(realm.Id.Realm); - 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 - SendPacket(hdr); - - _status = STATUS_AUTHED; -} - -// Make the SRP6 calculation from hash in dB -void AuthSession::SetVSFields(const std::string& rI) -{ - s.SetRand(int32(BufferSizes::SRP_6_S) * 8); - - BigNumber I; - I.SetHexStr(rI.c_str()); - - // In case of leading zeros in the rI hash, restore them - uint8 mDigest[SHA_DIGEST_LENGTH]; - memcpy(mDigest, I.AsByteArray(SHA_DIGEST_LENGTH).get(), SHA_DIGEST_LENGTH); - - std::reverse(mDigest, mDigest + SHA_DIGEST_LENGTH); - - SHA1Hash sha; - sha.UpdateData(s.AsByteArray(uint32(BufferSizes::SRP_6_S)).get(), (uint32(BufferSizes::SRP_6_S))); - 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) - PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_VS); - stmt->setString(0, v.AsHexStr()); - stmt->setString(1, s.AsHexStr()); - stmt->setString(2, _accountInfo.Login); - LoginDatabase.Execute(stmt); -} diff --git a/src/server/authserver/Server/AuthSession.h b/src/server/authserver/Server/AuthSession.h deleted file mode 100644 index 12ce0ea9fcb..00000000000 --- a/src/server/authserver/Server/AuthSession.h +++ /dev/null @@ -1,121 +0,0 @@ -/* -* Copyright (C) 2008-2018 TrinityCore -* Copyright (C) 2005-2009 MaNGOS -* -* This program is free software; you can redistribute it and/or modify it -* under the terms of the GNU General Public License as published by the -* Free Software Foundation; either version 2 of the License, or (at your -* option) any later version. -* -* This program is distributed in the hope that it will be useful, but WITHOUT -* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -* more details. -* -* You should have received a copy of the GNU General Public License along -* with this program. If not, see . -*/ - -#ifndef __AUTHSESSION_H__ -#define __AUTHSESSION_H__ - -#include "Common.h" -#include "BigNumber.h" -#include "DatabaseEnvFwd.h" -#include "QueryCallbackProcessor.h" -#include "Socket.h" -#include -#include - -using boost::asio::ip::tcp; - -class ByteBuffer; -class Field; -struct AuthHandler; - -enum AuthStatus -{ - STATUS_CHALLENGE = 0, - STATUS_LOGON_PROOF, - STATUS_RECONNECT_PROOF, - STATUS_AUTHED, - STATUS_WAITING_FOR_REALM_LIST, - STATUS_CLOSED -}; - -struct AccountInfo -{ - void LoadResult(Field* fields); - - uint32 Id = 0; - std::string Login; - bool IsLockedToIP = false; - std::string LockCountry; - std::string LastIP; - uint32 FailedLogins = 0; - bool IsBanned = false; - bool IsPermanenetlyBanned = false; - AccountTypes SecurityLevel = SEC_PLAYER; - std::string TokenKey; -}; - -class AuthSession : public Socket -{ - typedef Socket AuthSocket; - -public: - static std::unordered_map InitHandlers(); - - AuthSession(tcp::socket&& socket); - - void Start() override; - bool Update() override; - - void SendPacket(ByteBuffer& packet); - -protected: - void ReadHandler() override; - -private: - bool HandleLogonChallenge(); - bool HandleLogonProof(); - bool HandleReconnectChallenge(); - bool HandleReconnectProof(); - bool HandleRealmList(); - - void CheckIpCallback(PreparedQueryResult result); - void LogonChallengeCallback(PreparedQueryResult result); - void ReconnectChallengeCallback(PreparedQueryResult result); - void RealmListCallback(PreparedQueryResult result); - - void SetVSFields(const std::string& rI); - - BigNumber N, s, g, v; - BigNumber b, B; - BigNumber K; - BigNumber _reconnectProof; - - AuthStatus _status; - AccountInfo _accountInfo; - std::string _tokenKey; - std::string _localizationName; - std::string _os; - std::string _ipCountry; - uint16 _build; - uint8 _expversion; - - QueryCallbackProcessor _queryProcessor; -}; - -#pragma pack(push, 1) - -struct AuthHandler -{ - AuthStatus status; - size_t packetSize; - bool (AuthSession::*handler)(); -}; - -#pragma pack(pop) - -#endif diff --git a/src/server/authserver/Server/AuthSocketMgr.h b/src/server/authserver/Server/AuthSocketMgr.h deleted file mode 100644 index 04d65d396b0..00000000000 --- a/src/server/authserver/Server/AuthSocketMgr.h +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright (C) 2008-2018 TrinityCore - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -#ifndef AuthSocketMgr_h__ -#define AuthSocketMgr_h__ - -#include "SocketMgr.h" -#include "AuthSession.h" - -class AuthSocketMgr : public SocketMgr -{ - typedef SocketMgr BaseSocketMgr; - -public: - static AuthSocketMgr& Instance() - { - static AuthSocketMgr instance; - return instance; - } - - bool StartNetwork(Trinity::Asio::IoContext& ioContext, std::string const& bindIp, uint16 port, int threadCount = 1) override - { - if (!BaseSocketMgr::StartNetwork(ioContext, bindIp, port, threadCount)) - return false; - - _acceptor->AsyncAcceptWithCallback<&AuthSocketMgr::OnSocketAccept>(); - return true; - } - -protected: - NetworkThread* CreateThreads() const override - { - return new NetworkThread[1]; - } - - static void OnSocketAccept(tcp::socket&& sock, uint32 threadIndex) - { - Instance().OnSocketOpen(std::forward(sock), threadIndex); - } -}; - -#define sAuthSocketMgr AuthSocketMgr::Instance() - -#endif // AuthSocketMgr_h__ diff --git a/src/server/authserver/authserver.conf.dist b/src/server/authserver/authserver.conf.dist deleted file mode 100644 index efde048726c..00000000000 --- a/src/server/authserver/authserver.conf.dist +++ /dev/null @@ -1,359 +0,0 @@ -############################################### -# Trinity Core Auth Server configuration file # -############################################### -[authserver] - -################################################################################################### -# SECTION INDEX -# -# EXAMPLE CONFIG -# AUTH SERVER SETTINGS -# MYSQL SETTINGS -# UPDATE SETTINGS -# LOGGING SYSTEM SETTINGS -# -################################################################################################### - -################################################################################################### -# EXAMPLE CONFIG -# -# Variable -# Description: Brief description what the variable is doing. -# Important: Annotation for important things about this variable. -# Example: "Example, i.e. if the value is a string" -# Default: 10 - (Enabled|Comment|Variable name in case of grouped config options) -# 0 - (Disabled|Comment|Variable name in case of grouped config options) -# -# Note to developers: -# - Copy this example to keep the formatting. -# - Line breaks should be at column 100. -################################################################################################### - -################################################################################################### -# AUTH SERVER SETTINGS -# -# LogsDir -# Description: Logs directory setting. -# Important: LogsDir needs to be quoted, as the string might contain space characters. -# Logs directory must exists, or log file creation will be disabled. -# Default: "" - (Log files will be stored in the current path) - -LogsDir = "" - -# -# MaxPingTime -# Description: Time (in minutes) between database pings. -# Default: 30 - -MaxPingTime = 30 - -# -# RealmServerPort -# Description: TCP port to reach the auth server. -# Default: 3724 - -RealmServerPort = 3724 - -# -# -# BindIP -# Description: Bind auth server to IP/hostname -# Default: "0.0.0.0" - (Bind to all IPs on the system) - -BindIP = "0.0.0.0" - -# -# PidFile -# Description: Auth server PID file. -# Example: "./authserver.pid" - (Enabled) -# Default: "" - (Disabled) - -PidFile = "" - -# -# UseProcessors -# Description: Processors mask for Windows and Linux based multi-processor systems. -# Example: A computer with 2 CPUs: -# 1 - 1st CPU only, 2 - 2nd CPU only, 3 - 1st and 2nd CPU, because 1 | 2 is 3 -# Default: 0 - (Selected by OS) -# 1+ - (Bit mask value of selected processors) - -UseProcessors = 0 - -# -# ProcessPriority -# Description: Process priority setting for Windows and Linux based systems. -# Details: On Linux, a nice value of -15 is used. (requires superuser). On Windows, process is set to HIGH class. -# Default: 0 - (Normal) -# 1 - (High) - -ProcessPriority = 0 - -# -# RealmsStateUpdateDelay -# Description: Time (in seconds) between realm list updates. -# Default: 20 - (Enabled) -# 0 - (Disabled) - -RealmsStateUpdateDelay = 20 - -# -# WrongPass.MaxCount -# Description: Number of login attemps with wrong password before the account or IP will be -# banned. -# Default: 0 - (Disabled) -# 1+ - (Enabled) - -WrongPass.MaxCount = 0 - -# -# WrongPass.BanTime -# Description: Time (in seconds) for banning account or IP for invalid login attempts. -# Default: 600 - (10 minutes) -# 0 - (Permanent ban) - -WrongPass.BanTime = 600 - -# -# WrongPass.BanType -# Description: Ban type for invalid login attempts. -# Default: 0 - (Ban IP) -# 1 - (Ban Account) - -WrongPass.BanType = 0 - -# -# WrongPass.Logging -# Description: Additionally log attempted wrong password logging -# Default: 0 - (Disabled) -# 1 - (Enabled) - -WrongPass.Logging = 0 - -# -# BanExpiryCheckInterval -# Description: Time (in seconds) between checks for expired bans -# Default: 60 - -BanExpiryCheckInterval = 60 - -# -# SourceDirectory -# Description: The path to your TrinityCore source directory. -# If the path is left empty, the built-in CMAKE_SOURCE_DIR is used. -# Example: "../TrinityCore" -# Default: "" - -SourceDirectory = "" - -# -# MySQLExecutable -# Description: The path to your mysql cli binary. -# If the path is left empty, built-in path from cmake is used. -# Example: "C:/Program Files/MySQL/MySQL Server 5.6/bin/mysql.exe" -# "mysql.exe" -# "/usr/bin/mysql" -# Default: "" - -MySQLExecutable = "" - -# -# IPLocationFile -# Description: The path to your IP2Location database CSV file. -# Example: "C:/Trinity/IP2LOCATION-LITE-DB1.CSV" -# "/home/trinity/IP2LOCATION-LITE-DB1.CSV" -# Default: "" - (Disabled) - -IPLocationFile = "" - -# -################################################################################################### - -################################################################################################### -# MYSQL SETTINGS -# -# LoginDatabaseInfo -# Description: Database connection settings for the realm server. -# Example: "hostname;port;username;password;database" -# ".;somenumber;username;password;database" - (Use named pipes on Windows -# "enable-named-pipe" to [mysqld] -# section my.ini) -# ".;/path/to/unix_socket;username;password;database" - (use Unix sockets on -# Unix/Linux) -# Default: "127.0.0.1;3306;trinity;trinity;auth" - -LoginDatabaseInfo = "127.0.0.1;3306;trinity;trinity;auth" - -# -# LoginDatabase.WorkerThreads -# Description: The amount of worker threads spawned to handle asynchronous (delayed) MySQL -# statements. Each worker thread is mirrored with its own connection to the -# MySQL server and their own thread on the MySQL server. -# Default: 1 - -LoginDatabase.WorkerThreads = 1 - -# -# LoginDatabase.SynchThreads -# Description: The amount of MySQL connections spawned to handle. -# Default: 1 - (LoginDatabase.WorkerThreads) - -LoginDatabase.SynchThreads = 1 - -# -################################################################################################### - -################################################################################################### -# UPDATE SETTINGS -# -# Updates.EnableDatabases -# Description: A mask that describes which databases shall be updated. -# -# Following flags are available -# DATABASE_LOGIN = 1, // Auth database -# -# Default: 0 - (All Disabled) -# 1 - (All Enabled) - -Updates.EnableDatabases = 0 - -# -# Updates.AutoSetup -# Description: Auto populate empty databases. -# Default: 1 - (Enabled) -# 0 - (Disabled) - -Updates.AutoSetup = 1 - -# -# Updates.Redundancy -# Description: Perform data redundancy checks through hashing -# to detect changes on sql updates and reapply it. -# Default: 1 - (Enabled) -# 0 - (Disabled) - -Updates.Redundancy = 1 - -# -# Updates.ArchivedRedundancy -# Description: Check hashes of archived updates (slows down startup). -# Default: 0 - (Disabled) -# 1 - (Enabled) - -Updates.ArchivedRedundancy = 0 - -# -# Updates.AllowRehash -# Description: Inserts the current file hash in the database if it is left empty. -# Useful if you want to mark a file as applied but you don't know its hash. -# Default: 1 - (Enabled) -# 0 - (Disabled) - -Updates.AllowRehash = 1 - -# -# Updates.CleanDeadRefMaxCount -# Description: Cleans dead/ orphaned references that occur if an update was removed or renamed and edited in one step. -# It only starts the clean up if the count of the missing updates is below or equal the Updates.CleanDeadRefMaxCount value. -# This way prevents erasing of the update history due to wrong source directory state (maybe wrong branch or bad revision). -# Disable this if you want to know if the database is in a possible "dirty state". -# Default: 3 - (Enabled) -# 0 - (Disabled) -# -1 - (Enabled - unlimited) - -Updates.CleanDeadRefMaxCount = 3 - -# -################################################################################################### - -################################################################################################### -# -# LOGGING SYSTEM SETTINGS -# -# Appender config values: Given a appender "name" -# Appender.name -# Description: Defines 'where to log' -# Format: Type,LogLevel,Flags,optional1,optional2,optional3 -# -# Type -# 0 - (None) -# 1 - (Console) -# 2 - (File) -# 3 - (DB) -# -# LogLevel -# 0 - (Disabled) -# 1 - (Trace) -# 2 - (Debug) -# 3 - (Info) -# 4 - (Warn) -# 5 - (Error) -# 6 - (Fatal) -# -# Flags: -# 0 - None -# 1 - Prefix Timestamp to the text -# 2 - Prefix Log Level to the text -# 4 - Prefix Log Filter type to the text -# 8 - Append timestamp to the log file name. Format: YYYY-MM-DD_HH-MM-SS (Only used with Type = 2) -# 16 - Make a backup of existing file before overwrite (Only used with Mode = w) -# -# Colors (read as optional1 if Type = Console) -# Format: "fatal error warn info debug trace" -# 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 -# Example: "13 11 9 5 3 1" -# -# File: Name of the file (read as optional1 if Type = File) -# Allows to use one "%s" to create dynamic files -# -# Mode: Mode to open the file (read as optional2 if Type = File) -# a - (Append) -# w - (Overwrite) -# -# MaxFileSize: Maximum file size of the log file before creating a new log file -# (read as optional3 if Type = File) -# Size is measured in bytes expressed in a 64-bit unsigned integer. -# Maximum value is 4294967295 (4 gb). Leave blank for no limit. -# NOTE: Does not work with dynamic filenames. -# Example: 536870912 (512 mb) -# - -Appender.Console=1,2,0 -Appender.Auth=2,2,0,Auth.log,w - -# Logger config values: Given a logger "name" -# Logger.name -# Description: Defines 'What to log' -# Format: LogLevel,AppenderList -# -# LogLevel -# 0 - (Disabled) -# 1 - (Trace) -# 2 - (Debug) -# 3 - (Info) -# 4 - (Warn) -# 5 - (Error) -# 6 - (Fatal) -# -# AppenderList: List of appenders linked to logger -# (Using spaces as separator). -# - -Logger.root=3,Console Auth - -# -################################################################################################### diff --git a/src/server/authserver/authserver.ico b/src/server/authserver/authserver.ico deleted file mode 100644 index da318f48a8c2f4dc94507596ec88d0cc4409b32f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 136606 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 T(nN6@5vdF diff --git a/src/server/authserver/authserver.rc b/src/server/authserver/authserver.rc deleted file mode 100644 index a8270e06eab..00000000000 --- a/src/server/authserver/authserver.rc +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Copyright (C) 2008-2018 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 "resource.h" -#include "revision_data.h" - -#define APSTUDIO_READONLY_SYMBOLS -///////////////////////////////////////////////////////////////////////////// -// -// Generated from the TEXTINCLUDE 2 resource. -// -#include "windows.h" //"afxres.h" - -///////////////////////////////////////////////////////////////////////////// -#undef APSTUDIO_READONLY_SYMBOLS - -///////////////////////////////////////////////////////////////////////////// -// -// Icon -// - -// Icon with lowest ID value placed first to ensure application icon -// remains consistent on all systems. -IDI_APPICON ICON "authserver.ico" - -///////////////////////////////////////////////////////////////////////////// -// Neutre (Par défaut système) resources - -#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_NEUSD) -#ifdef _WIN32 -LANGUAGE LANG_NEUTRAL, SUBLANG_SYS_DEFAULT -#pragma code_page(1252) -#endif //_WIN32 - -///////////////////////////////////////////////////////////////////////////// -// -// Version -// - -VS_VERSION_INFO VERSIONINFO -FILEVERSION VER_FILEVERSION -PRODUCTVERSION VER_PRODUCTVERSION - -FILEFLAGSMASK VS_FFI_FILEFLAGSMASK - -#ifndef _DEBUG - FILEFLAGS 0 -#else - #define VER_PRERELEASE VS_FF_PRERELEASE - #define VER_PRIVATEBUILD VS_FF_PRIVATEBUILD - #define VER_DEBUG 0 - FILEFLAGS (VER_PRIVATEBUILD|VER_PRERELEASE|VER_DEBUG) -#endif - -FILEOS VOS_NT_WINDOWS32 -FILETYPE VFT_APP - -BEGIN - BLOCK "StringFileInfo" - BEGIN - BLOCK "080004b0" - BEGIN - VALUE "CompanyName", VER_COMPANYNAME_STR - VALUE "FileDescription", "TrinityCore Authentication Server Daemon" - VALUE "FileVersion", VER_FILEVERSION_STR - VALUE "InternalName", "authserver" - VALUE "LegalCopyright", VER_LEGALCOPYRIGHT_STR - VALUE "OriginalFilename", "authserver.exe" - VALUE "ProductName", "TrinityCore Authentication Server" - VALUE "ProductVersion", VER_PRODUCTVERSION_STR - END - END - - BLOCK "VarFileInfo" - BEGIN - VALUE "Translation", 0x800, 1200 - END -END -#endif diff --git a/src/server/authserver/resource.h b/src/server/authserver/resource.h deleted file mode 100644 index 7dc5cb9ef7b..00000000000 --- a/src/server/authserver/resource.h +++ /dev/null @@ -1,15 +0,0 @@ -//{{NO_DEPENDENCIES}} -// Microsoft Visual C++ generated include file. -// Used by TrinityCore.rc -// - -// Next default values for new objects -// -#ifdef APSTUDIO_INVOKED -#ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 101 -#define _APS_NEXT_COMMAND_VALUE 40001 -#define _APS_NEXT_CONTROL_VALUE 1000 -#define _APS_NEXT_SYMED_VALUE 101 -#endif -#endif diff --git a/src/server/bnetserver/bnetserver.conf.dist b/src/server/bnetserver/bnetserver.conf.dist index 102ddb9906a..462bb0cd075 100644 --- a/src/server/bnetserver/bnetserver.conf.dist +++ b/src/server/bnetserver/bnetserver.conf.dist @@ -1,7 +1,7 @@ ############################################### # Trinity Core Auth Server configuration file # ############################################### -[authserver] +[bnetserver] ################################################################################################### # SECTION INDEX @@ -71,7 +71,7 @@ BindIP = "0.0.0.0" # # PidFile # Description: Auth server PID file. -# Example: "./authserver.pid" - (Enabled) +# Example: "./bnetserver.pid" - (Enabled) # Default: "" - (Disabled) PidFile = "" diff --git a/src/server/scripts/Commands/cs_battlenet_account.cpp b/src/server/scripts/Commands/cs_battlenet_account.cpp index fb325bbe33a..a71e30a410b 100644 --- a/src/server/scripts/Commands/cs_battlenet_account.cpp +++ b/src/server/scripts/Commands/cs_battlenet_account.cpp @@ -140,7 +140,7 @@ public: else { handler->PSendSysMessage("IP2Location] No information"); - TC_LOG_DEBUG("server.authserver", "IP2Location] No information"); + TC_LOG_DEBUG("server.bnetserver", "IP2Location] No information"); } } else if (param == "off") diff --git a/src/server/worldserver/worldserver.conf.dist b/src/server/worldserver/worldserver.conf.dist index aec3af155ac..3c940b2b661 100644 --- a/src/server/worldserver/worldserver.conf.dist +++ b/src/server/worldserver/worldserver.conf.dist @@ -3910,7 +3910,7 @@ Logger.sql.updates=3,Console Server #Logger.rbac=3,Console Server #Logger.scripts=3,Console Server #Logger.scripts.ai=3,Console Server -#Logger.server.authserver=3,Console Server +#Logger.server.bnetserver=3,Console Server #Logger.spells=3,Console Server #Logger.spells.periodic=3,Console Server #Logger.sql.dev=3,Console Server