diff options
Diffstat (limited to 'src/server/authserver')
| -rw-r--r-- | src/server/authserver/Authentication/AuthCodes.cpp | 5 | ||||
| -rw-r--r-- | src/server/authserver/Authentication/AuthCodes.h | 4 | ||||
| -rw-r--r-- | src/server/authserver/Authentication/TOTP.cpp | 2 | ||||
| -rw-r--r-- | src/server/authserver/Authentication/TOTP.h | 4 | ||||
| -rw-r--r-- | src/server/authserver/CMakeLists.txt | 6 | ||||
| -rw-r--r-- | src/server/authserver/Main.cpp | 277 | ||||
| -rw-r--r-- | src/server/authserver/PrecompiledHeaders/authPCH.h | 4 | ||||
| -rw-r--r-- | src/server/authserver/Realms/RealmList.cpp | 101 | ||||
| -rw-r--r-- | src/server/authserver/Realms/RealmList.h | 56 | ||||
| -rw-r--r-- | src/server/authserver/Server/AuthSession.cpp (renamed from src/server/authserver/Server/AuthSocket.cpp) | 808 | ||||
| -rw-r--r-- | src/server/authserver/Server/AuthSession.h | 100 | ||||
| -rw-r--r-- | src/server/authserver/Server/AuthSocket.h | 83 | ||||
| -rw-r--r-- | src/server/authserver/Server/RealmAcceptor.h | 70 | ||||
| -rw-r--r-- | src/server/authserver/Server/RealmSocket.cpp | 291 | ||||
| -rw-r--r-- | src/server/authserver/Server/RealmSocket.h | 80 | ||||
| -rw-r--r-- | src/server/authserver/authserver.conf.dist | 7 | ||||
| -rw-r--r-- | src/server/authserver/authserver.rc | 2 |
17 files changed, 592 insertions, 1308 deletions
diff --git a/src/server/authserver/Authentication/AuthCodes.cpp b/src/server/authserver/Authentication/AuthCodes.cpp index b47ef21b24b..55517884b8e 100644 --- a/src/server/authserver/Authentication/AuthCodes.cpp +++ b/src/server/authserver/Authentication/AuthCodes.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008-2013 TrinityCore <http://www.trinitycore.org/> + * Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/> * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the @@ -25,6 +25,7 @@ namespace AuthHelper {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, ' '}, @@ -78,4 +79,4 @@ namespace AuthHelper return NULL; } -}; +} diff --git a/src/server/authserver/Authentication/AuthCodes.h b/src/server/authserver/Authentication/AuthCodes.h index df7de3ed684..97b4779da0e 100644 --- a/src/server/authserver/Authentication/AuthCodes.h +++ b/src/server/authserver/Authentication/AuthCodes.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008-2013 TrinityCore <http://www.trinitycore.org/> + * Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/> * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/> * * This program is free software; you can redistribute it and/or modify it @@ -92,6 +92,6 @@ namespace AuthHelper bool IsAcceptedClientBuild(int build); bool IsPostBCAcceptedClientBuild(int build); bool IsPreBCAcceptedClientBuild(int build); -}; +} #endif diff --git a/src/server/authserver/Authentication/TOTP.cpp b/src/server/authserver/Authentication/TOTP.cpp index 51a21822bc0..01842cfe234 100644 --- a/src/server/authserver/Authentication/TOTP.cpp +++ b/src/server/authserver/Authentication/TOTP.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008-2013 TrinityCore <http://www.trinitycore.org/> + * Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/> * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the diff --git a/src/server/authserver/Authentication/TOTP.h b/src/server/authserver/Authentication/TOTP.h index 3080e7c7787..7ced260758c 100644 --- a/src/server/authserver/Authentication/TOTP.h +++ b/src/server/authserver/Authentication/TOTP.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008-2013 TrinityCore <http://www.trinitycore.org/> + * Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/> * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the @@ -16,7 +16,7 @@ */ #ifndef _TOTP_H -#define _TOPT_H +#define _TOTP_H #include "openssl/hmac.h" #include "openssl/evp.h" diff --git a/src/server/authserver/CMakeLists.txt b/src/server/authserver/CMakeLists.txt index ff3a4cdd67c..d6f0515a8e1 100644 --- a/src/server/authserver/CMakeLists.txt +++ b/src/server/authserver/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright (C) 2008-2013 TrinityCore <http://www.trinitycore.org/> +# Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/> # # This file is free software; as a special exception the author gives # unlimited permission to copy and/or distribute it, with or without @@ -50,13 +50,13 @@ include_directories( ${CMAKE_SOURCE_DIR}/src/server/shared/Cryptography ${CMAKE_SOURCE_DIR}/src/server/shared/Cryptography/Authentication ${CMAKE_SOURCE_DIR}/src/server/shared/Logging + ${CMAKE_SOURCE_DIR}/src/server/shared/Networking ${CMAKE_SOURCE_DIR}/src/server/shared/Threading ${CMAKE_SOURCE_DIR}/src/server/shared/Utilities ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/Authentication ${CMAKE_CURRENT_SOURCE_DIR}/Realms ${CMAKE_CURRENT_SOURCE_DIR}/Server - ${ACE_INCLUDE_DIR} ${MYSQL_INCLUDE_DIR} ${OPENSSL_INCLUDE_DIR} ) @@ -79,7 +79,7 @@ target_link_libraries(authserver ${MYSQL_LIBRARY} ${OPENSSL_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT} - ${ACE_LIBRARY} + ${Boost_LIBRARIES} ) if( WIN32 ) diff --git a/src/server/authserver/Main.cpp b/src/server/authserver/Main.cpp index 80a810e4ce1..f26c0342654 100644 --- a/src/server/authserver/Main.cpp +++ b/src/server/authserver/Main.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008-2013 TrinityCore <http://www.trinitycore.org/> + * Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/> * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/> * * This program is free software; you can redistribute it and/or modify it @@ -24,28 +24,26 @@ * authentication server */ -#include <ace/Dev_Poll_Reactor.h> -#include <ace/TP_Reactor.h> -#include <ace/ACE.h> -#include <ace/Sig_Handler.h> +#include <cstdlib> +#include <boost/date_time/posix_time/posix_time.hpp> +#include <boost/program_options.hpp> +#include <iostream> #include <openssl/opensslv.h> #include <openssl/crypto.h> +#include "AsyncAcceptor.h" +#include "AuthSession.h" #include "Common.h" -#include "Database/DatabaseEnv.h" #include "Configuration/Config.h" +#include "Database/DatabaseEnv.h" #include "Log.h" +#include "ProcessPriority.h" +#include "RealmList.h" #include "SystemConfig.h" #include "Util.h" -#include "SignalHandler.h" -#include "RealmList.h" -#include "RealmAcceptor.h" -#ifdef __linux__ -#include <sched.h> -#include <sys/resource.h> -#define PROCESS_HIGH_PRIORITY -15 // [-20, 19], default is 0 -#endif +using boost::asio::ip::tcp; +using namespace boost::program_options; #ifndef _TRINITY_REALM_CONFIG # define _TRINITY_REALM_CONFIG "authserver.conf" @@ -53,77 +51,35 @@ bool StartDB(); void StopDB(); +void SignalHandler(const boost::system::error_code& error, int signalNumber); +void KeepDatabaseAliveHandler(const boost::system::error_code& error); +variables_map GetConsoleArguments(int argc, char** argv, std::string& configFile); -bool stopEvent = false; // Setting it to true stops the server - -LoginDatabaseWorkerPool LoginDatabase; // Accessor to the authserver database - -/// Handle authserver's termination signals -class AuthServerSignalHandler : public Trinity::SignalHandler -{ -public: - virtual void HandleSignal(int sigNum) - { - switch (sigNum) - { - case SIGINT: - case SIGTERM: - stopEvent = true; - break; - } - } -}; - -/// Print out the usage string for this program on the console. -void usage(const char* prog) -{ - TC_LOG_INFO("server.authserver", "Usage: \n %s [<options>]\n" - " -c config_file use config_file as configuration file\n\r", - prog); -} +boost::asio::io_service _ioService; +boost::asio::deadline_timer _dbPingTimer(_ioService); +uint32 _dbPingInterval; +LoginDatabaseWorkerPool LoginDatabase; -/// Launch the auth server -extern int main(int argc, char** argv) +int main(int argc, char** argv) { - // Command line parsing to get the configuration file name - char const* configFile = _TRINITY_REALM_CONFIG; - int count = 1; - while (count < argc) - { - if (strcmp(argv[count], "-c") == 0) - { - if (++count >= argc) - { - printf("Runtime-Error: -c option requires an input argument\n"); - usage(argv[0]); - return 1; - } - else - configFile = argv[count]; - } - ++count; - } - - if (!sConfigMgr->LoadInitial(configFile)) + std::string configFile = _TRINITY_REALM_CONFIG; + auto vm = GetConsoleArguments(argc, argv, configFile); + // exit if help is enabled + if (vm.count("help")) + return 0; + + std::string configError; + if (!sConfigMgr->LoadInitial(configFile, configError)) { - printf("Invalid or missing configuration file : %s\n", configFile); - printf("Verify that the file exists and has \'[authserver]\' written in the top of the file!\n"); + printf("Error in config file: %s\n", configError.c_str()); return 1; } TC_LOG_INFO("server.authserver", "%s (authserver)", _FULLVERSION); TC_LOG_INFO("server.authserver", "<Ctrl-C> to stop.\n"); - TC_LOG_INFO("server.authserver", "Using configuration file %s.", configFile); - - TC_LOG_WARN("server.authserver", "%s (Library: %s)", OPENSSL_VERSION_TEXT, SSLeay_version(SSLEAY_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 - - TC_LOG_DEBUG("server.authserver", "Max allowed open files is %d", ACE::max_handles()); + TC_LOG_INFO("server.authserver", "Using configuration file %s.", configFile.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", ""); @@ -143,126 +99,44 @@ extern int main(int argc, char** argv) return 1; // Get the list of realms for the server - sRealmList->Initialize(sConfigMgr->GetIntDefault("RealmsStateUpdateDelay", 20)); + sRealmList->Initialize(_ioService, sConfigMgr->GetIntDefault("RealmsStateUpdateDelay", 20)); + if (sRealmList->size() == 0) { TC_LOG_ERROR("server.authserver", "No valid realms specified."); + StopDB(); return 1; } - // Launch the listening network socket - RealmAcceptor acceptor; - - int32 rmport = sConfigMgr->GetIntDefault("RealmServerPort", 3724); - if (rmport < 0 || rmport > 0xFFFF) + // 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)"); + StopDB(); return 1; } - std::string bind_ip = sConfigMgr->GetStringDefault("BindIP", "0.0.0.0"); - - ACE_INET_Addr bind_addr(uint16(rmport), bind_ip.c_str()); - - if (acceptor.open(bind_addr, ACE_Reactor::instance(), ACE_NONBLOCK) == -1) - { - TC_LOG_ERROR("server.authserver", "Auth server can not bind to %s:%d", bind_ip.c_str(), rmport); - return 1; - } - - // Initialize the signal handlers - AuthServerSignalHandler SignalINT, SignalTERM; - - // Register authservers's signal handlers - ACE_Sig_Handler Handler; - Handler.register_handler(SIGINT, &SignalINT); - Handler.register_handler(SIGTERM, &SignalTERM); - - ///- Handle affinity for multiple processors and process priority - uint32 affinity = sConfigMgr->GetIntDefault("UseProcessors", 0); - bool highPriority = sConfigMgr->GetBoolDefault("ProcessPriority", false); - -#ifdef _WIN32 // Windows - { - HANDLE hProcess = GetCurrentProcess(); - - if (affinity > 0) - { - ULONG_PTR appAff; - ULONG_PTR sysAff; - - if (GetProcessAffinityMask(hProcess, &appAff, &sysAff)) - { - ULONG_PTR currentAffinity = affinity & appAff; // remove non accessible processors - - if (!currentAffinity) - TC_LOG_ERROR("server.authserver", "Processors marked in UseProcessors bitmask (hex) %x are not accessible for the authserver. Accessible processors bitmask (hex): %x", affinity, appAff); - else if (SetProcessAffinityMask(hProcess, currentAffinity)) - TC_LOG_INFO("server.authserver", "Using processors (bitmask, hex): %x", currentAffinity); - else - TC_LOG_ERROR("server.authserver", "Can't set used processors (hex): %x", currentAffinity); - } - } - - if (highPriority) - { - if (SetPriorityClass(hProcess, HIGH_PRIORITY_CLASS)) - TC_LOG_INFO("server.authserver", "authserver process priority class set to HIGH"); - else - TC_LOG_ERROR("server.authserver", "Can't set authserver process priority class."); - } - } -#elif __linux__ // Linux - - if (affinity > 0) - { - cpu_set_t mask; - CPU_ZERO(&mask); - - for (unsigned int i = 0; i < sizeof(affinity) * 8; ++i) - if (affinity & (1 << i)) - CPU_SET(i, &mask); - - if (sched_setaffinity(0, sizeof(mask), &mask)) - TC_LOG_ERROR("server.authserver", "Can't set used processors (hex): %x, error: %s", affinity, strerror(errno)); - else - { - CPU_ZERO(&mask); - sched_getaffinity(0, sizeof(mask), &mask); - TC_LOG_INFO("server.authserver", "Using processors (bitmask, hex): %x", *(uint32*)(&mask)); - } - } - - if (highPriority) - { - if (setpriority(PRIO_PROCESS, 0, PROCESS_HIGH_PRIORITY)) - TC_LOG_ERROR("server.authserver", "Can't set authserver process priority class, error: %s", strerror(errno)); - else - TC_LOG_INFO("server.authserver", "authserver process priority class set to %i", getpriority(PRIO_PROCESS, 0)); - } + std::string bindIp = sConfigMgr->GetStringDefault("BindIP", "0.0.0.0"); + AsyncAcceptor<AuthSession> authServer(_ioService, bindIp, port); + // Set signal handlers + boost::asio::signal_set signals(_ioService, SIGINT, SIGTERM); +#if PLATFORM == PLATFORM_WINDOWS + signals.add(SIGBREAK); #endif + signals.async_wait(SignalHandler); - // maximum counter for next ping - uint32 numLoops = (sConfigMgr->GetIntDefault("MaxPingTime", 30) * (MINUTE * 1000000 / 100000)); - uint32 loopCounter = 0; + // Set process priority according to configuration settings + SetProcessPriority("server.authserver"); - // 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; + // Enabled a timed callback for handling the database keep alive ping + _dbPingInterval = sConfigMgr->GetIntDefault("MaxPingTime", 30); + _dbPingTimer.expires_from_now(boost::posix_time::minutes(_dbPingInterval)); + _dbPingTimer.async_wait(KeepDatabaseAliveHandler); - if ((++loopCounter) == numLoops) - { - loopCounter = 0; - TC_LOG_INFO("server.authserver", "Ping MySQL to keep connection alive"); - LoginDatabase.KeepAlive(); - } - } + // Start the io service worker loop + _ioService.run(); // Close the Database Pool and library StopDB(); @@ -271,6 +145,7 @@ extern int main(int argc, char** argv) return 0; } + /// Initialize connection to the database bool StartDB() { @@ -315,3 +190,45 @@ void StopDB() LoginDatabase.Close(); MySQL::Library_End(); } + +void SignalHandler(const boost::system::error_code& error, int /*signalNumber*/) +{ + if (!error) + _ioService.stop(); +} + +void KeepDatabaseAliveHandler(const boost::system::error_code& error) +{ + if (!error) + { + TC_LOG_INFO("server.authserver", "Ping MySQL to keep connection alive"); + LoginDatabase.KeepAlive(); + + _dbPingTimer.expires_from_now(boost::posix_time::minutes(_dbPingInterval)); + _dbPingTimer.async_wait(KeepDatabaseAliveHandler); + } +} + +variables_map GetConsoleArguments(int argc, char** argv, std::string& configFile) +{ + options_description all("Allowed options"); + all.add_options() + ("help,h", "print usage message") + ("config,c", value<std::string>(&configFile)->default_value(_TRINITY_REALM_CONFIG), "use <arg> as configuration file") + ; + 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"; + } + + return variablesMap; +} diff --git a/src/server/authserver/PrecompiledHeaders/authPCH.h b/src/server/authserver/PrecompiledHeaders/authPCH.h index 5fc3b0a3416..ef757a656d5 100644 --- a/src/server/authserver/PrecompiledHeaders/authPCH.h +++ b/src/server/authserver/PrecompiledHeaders/authPCH.h @@ -1,6 +1,6 @@ +#include "Common.h" #include "Configuration/Config.h" #include "Database/DatabaseEnv.h" #include "Log.h" #include "RealmList.h" -#include "RealmSocket.h" -#include "Common.h" +#include "AuthSession.h" diff --git a/src/server/authserver/Realms/RealmList.cpp b/src/server/authserver/Realms/RealmList.cpp index 34120f75e88..8f11d3882ce 100644 --- a/src/server/authserver/Realms/RealmList.cpp +++ b/src/server/authserver/Realms/RealmList.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008-2013 TrinityCore <http://www.trinitycore.org/> + * Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/> * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/> * * This program is free software; you can redistribute it and/or modify it @@ -16,22 +16,31 @@ * with this program. If not, see <http://www.gnu.org/licenses/>. */ +#include <boost/asio/ip/tcp.hpp> #include "Common.h" #include "RealmList.h" #include "Database/DatabaseEnv.h" -RealmList::RealmList() : m_UpdateInterval(0), m_NextUpdateTime(time(NULL)) { } +namespace boost { namespace asio { namespace ip { class address; } } } + +RealmList::RealmList() : m_UpdateInterval(0), m_NextUpdateTime(time(NULL)), _resolver(nullptr) { } +RealmList::~RealmList() +{ + delete _resolver; +} // Load the realm list from the database -void RealmList::Initialize(uint32 updateInterval) +void RealmList::Initialize(boost::asio::io_service& ioService, uint32 updateInterval) { + _resolver = new boost::asio::ip::tcp::resolver(ioService); m_UpdateInterval = updateInterval; // Get the content of the realmlist table in the database UpdateRealms(true); } -void RealmList::UpdateRealm(uint32 id, const std::string& name, ACE_INET_Addr const& address, ACE_INET_Addr const& localAddr, ACE_INET_Addr const& localSubmask, uint8 icon, RealmFlags flag, uint8 timezone, AccountTypes allowedSecurityLevel, float popu, uint32 build) +void RealmList::UpdateRealm(uint32 id, const std::string& name, ip::address const& address, ip::address const& localAddr, + ip::address const& localSubmask, uint16 port, uint8 icon, RealmFlags flag, uint8 timezone, AccountTypes allowedSecurityLevel, float population, uint32 build) { // Create new if not exist or update existed Realm& realm = m_realms[name]; @@ -42,12 +51,14 @@ void RealmList::UpdateRealm(uint32 id, const std::string& name, ACE_INET_Addr co realm.flag = flag; realm.timezone = timezone; realm.allowedSecurityLevel = allowedSecurityLevel; - realm.populationLevel = popu; + realm.populationLevel = population; // Append port to IP address. + realm.ExternalAddress = address; realm.LocalAddress = localAddr; realm.LocalSubnetMask = localSubmask; + realm.port = port; realm.gamebuild = build; } @@ -78,28 +89,64 @@ void RealmList::UpdateRealms(bool init) { do { - Field* fields = result->Fetch(); - uint32 realmId = fields[0].GetUInt32(); - std::string name = fields[1].GetString(); - std::string externalAddress = fields[2].GetString(); - std::string localAddress = fields[3].GetString(); - std::string localSubmask = fields[4].GetString(); - uint16 port = fields[5].GetUInt16(); - uint8 icon = fields[6].GetUInt8(); - RealmFlags flag = RealmFlags(fields[7].GetUInt8()); - uint8 timezone = fields[8].GetUInt8(); - uint8 allowedSecurityLevel = fields[9].GetUInt8(); - float pop = fields[10].GetFloat(); - uint32 build = fields[11].GetUInt32(); - - ACE_INET_Addr externalAddr(port, externalAddress.c_str(), AF_INET); - ACE_INET_Addr localAddr(port, localAddress.c_str(), AF_INET); - ACE_INET_Addr submask(0, localSubmask.c_str(), AF_INET); - - UpdateRealm(realmId, name, externalAddr, localAddr, submask, icon, flag, timezone, (allowedSecurityLevel <= SEC_ADMINISTRATOR ? AccountTypes(allowedSecurityLevel) : SEC_ADMINISTRATOR), pop, build); - - if (init) - TC_LOG_INFO("server.authserver", "Added realm \"%s\" at %s:%u.", name.c_str(), m_realms[name].ExternalAddress.get_host_addr(), port); + try + { + boost::asio::ip::tcp::resolver::iterator end; + + Field* fields = result->Fetch(); + uint32 realmId = fields[0].GetUInt32(); + std::string name = fields[1].GetString(); + boost::asio::ip::tcp::resolver::query externalAddressQuery(ip::tcp::v4(), fields[2].GetString(), ""); + + boost::system::error_code ec; + boost::asio::ip::tcp::resolver::iterator endPoint = _resolver->resolve(externalAddressQuery, ec); + if (endPoint == end || ec) + { + TC_LOG_ERROR("server.authserver", "Could not resolve address %s", fields[2].GetString().c_str()); + return; + } + + ip::address externalAddress = (*endPoint).endpoint().address(); + + boost::asio::ip::tcp::resolver::query localAddressQuery(ip::tcp::v4(), fields[3].GetString(), ""); + endPoint = _resolver->resolve(localAddressQuery, ec); + if (endPoint == end || ec) + { + TC_LOG_ERROR("server.authserver", "Could not resolve address %s", fields[3].GetString().c_str()); + return; + } + + ip::address localAddress = (*endPoint).endpoint().address(); + + boost::asio::ip::tcp::resolver::query localSubmaskQuery(ip::tcp::v4(), fields[4].GetString(), ""); + endPoint = _resolver->resolve(localSubmaskQuery, ec); + if (endPoint == end || ec) + { + TC_LOG_ERROR("server.authserver", "Could not resolve address %s", fields[4].GetString().c_str()); + return; + } + + ip::address localSubmask = (*endPoint).endpoint().address(); + + uint16 port = fields[5].GetUInt16(); + uint8 icon = fields[6].GetUInt8(); + RealmFlags flag = RealmFlags(fields[7].GetUInt8()); + uint8 timezone = fields[8].GetUInt8(); + uint8 allowedSecurityLevel = fields[9].GetUInt8(); + float pop = fields[10].GetFloat(); + uint32 build = fields[11].GetUInt32(); + + UpdateRealm(realmId, name, externalAddress, localAddress, localSubmask, port, icon, flag, timezone, + (allowedSecurityLevel <= SEC_ADMINISTRATOR ? AccountTypes(allowedSecurityLevel) : SEC_ADMINISTRATOR), pop, build); + + if (init) + TC_LOG_INFO("server.authserver", "Added realm \"%s\" at %s:%u.", name.c_str(), m_realms[name].ExternalAddress.to_string().c_str(), port); + } + catch (std::exception& ex) + { + TC_LOG_ERROR("server.authserver", "Realmlist::UpdateRealms has thrown an exception: %s", ex.what()); + ASSERT(false); + } } while (result->NextRow()); } diff --git a/src/server/authserver/Realms/RealmList.h b/src/server/authserver/Realms/RealmList.h index bf9493ad372..b8630f23a0e 100644 --- a/src/server/authserver/Realms/RealmList.h +++ b/src/server/authserver/Realms/RealmList.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008-2013 TrinityCore <http://www.trinitycore.org/> + * Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/> * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/> * * This program is free software; you can redistribute it and/or modify it @@ -19,30 +19,33 @@ #ifndef _REALMLIST_H #define _REALMLIST_H -#include <ace/Singleton.h> -#include <ace/Null_Mutex.h> -#include <ace/INET_Addr.h> +#include <boost/asio/ip/address.hpp> +#include <boost/asio/ip/tcp.hpp> +#include <boost/asio/io_service.hpp> #include "Common.h" +using namespace boost::asio; + enum RealmFlags { - REALM_FLAG_NONE = 0x00, - REALM_FLAG_INVALID = 0x01, - REALM_FLAG_OFFLINE = 0x02, - REALM_FLAG_SPECIFYBUILD = 0x04, - REALM_FLAG_UNK1 = 0x08, - REALM_FLAG_UNK2 = 0x10, - REALM_FLAG_RECOMMENDED = 0x20, - REALM_FLAG_NEW = 0x40, - REALM_FLAG_FULL = 0x80 + REALM_FLAG_NONE = 0x00, + REALM_FLAG_INVALID = 0x01, + REALM_FLAG_OFFLINE = 0x02, + REALM_FLAG_SPECIFYBUILD = 0x04, + REALM_FLAG_UNK1 = 0x08, + REALM_FLAG_UNK2 = 0x10, + REALM_FLAG_RECOMMENDED = 0x20, + REALM_FLAG_NEW = 0x40, + REALM_FLAG_FULL = 0x80 }; // Storage object for a realm struct Realm { - ACE_INET_Addr ExternalAddress; - ACE_INET_Addr LocalAddress; - ACE_INET_Addr LocalSubnetMask; + ip::address ExternalAddress; + ip::address LocalAddress; + ip::address LocalSubnetMask; + uint16 port; std::string name; uint8 icon; RealmFlags flag; @@ -59,10 +62,15 @@ class RealmList public: typedef std::map<std::string, Realm> RealmMap; - RealmList(); - ~RealmList() { } + static RealmList* instance() + { + static RealmList instance; + return &instance; + } + + ~RealmList(); - void Initialize(uint32 updateInterval); + void Initialize(boost::asio::io_service& ioService, uint32 updateInterval); void UpdateIfNeed(); @@ -73,13 +81,17 @@ public: uint32 size() const { return m_realms.size(); } private: - void UpdateRealms(bool init=false); - void UpdateRealm(uint32 id, const std::string& name, ACE_INET_Addr const& address, ACE_INET_Addr const& localAddr, ACE_INET_Addr const& localSubmask, uint8 icon, RealmFlags flag, uint8 timezone, AccountTypes allowedSecurityLevel, float popu, uint32 build); + RealmList(); + + void UpdateRealms(bool init = false); + void UpdateRealm(uint32 id, const std::string& name, ip::address const& address, ip::address const& localAddr, + ip::address const& localSubmask, uint16 port, uint8 icon, RealmFlags flag, uint8 timezone, AccountTypes allowedSecurityLevel, float population, uint32 build); RealmMap m_realms; uint32 m_UpdateInterval; time_t m_NextUpdateTime; + boost::asio::ip::tcp::resolver* _resolver; }; -#define sRealmList ACE_Singleton<RealmList, ACE_Null_Mutex>::instance() +#define sRealmList RealmList::instance() #endif diff --git a/src/server/authserver/Server/AuthSocket.cpp b/src/server/authserver/Server/AuthSession.cpp index 6595b6238b2..8276183fb10 100644 --- a/src/server/authserver/Server/AuthSocket.cpp +++ b/src/server/authserver/Server/AuthSession.cpp @@ -1,68 +1,58 @@ /* - * Copyright (C) 2008-2013 TrinityCore <http://www.trinitycore.org/> - * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see <http://www.gnu.org/licenses/>. - */ - -#include <algorithm> -#include <openssl/md5.h> - -#include "Common.h" -#include "Database/DatabaseEnv.h" -#include "ByteBuffer.h" -#include "Configuration/Config.h" +* Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/> +* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/> +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at your +* option) any later version. +* +* This program is distributed in the hope that it will be useful, but WITHOUT +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +* more details. +* +* You should have received a copy of the GNU General Public License along +* with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "AuthSession.h" #include "Log.h" -#include "RealmList.h" -#include "AuthSocket.h" #include "AuthCodes.h" -#include "TOTP.h" +#include "Database/DatabaseEnv.h" #include "SHA1.h" +#include "TOTP.h" #include "openssl/crypto.h" +#include "Configuration/Config.h" +#include "RealmList.h" +#include <boost/lexical_cast.hpp> -#define ChunkSize 2048 +using boost::asio::ip::tcp; enum eAuthCmd { - AUTH_LOGON_CHALLENGE = 0x00, - AUTH_LOGON_PROOF = 0x01, - AUTH_RECONNECT_CHALLENGE = 0x02, - AUTH_RECONNECT_PROOF = 0x03, - REALM_LIST = 0x10, - XFER_INITIATE = 0x30, - XFER_DATA = 0x31, - XFER_ACCEPT = 0x32, - XFER_RESUME = 0x33, - XFER_CANCEL = 0x34 + AUTH_LOGON_CHALLENGE = 0x00, + AUTH_LOGON_PROOF = 0x01, + AUTH_RECONNECT_CHALLENGE = 0x02, + AUTH_RECONNECT_PROOF = 0x03, + REALM_LIST = 0x10, + XFER_INITIATE = 0x30, + XFER_DATA = 0x31, + XFER_ACCEPT = 0x32, + XFER_RESUME = 0x33, + XFER_CANCEL = 0x34 }; enum eStatus { - STATUS_CONNECTED = 0, + STATUS_CONNECTED = 0, STATUS_AUTHED }; -// 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]; @@ -81,12 +71,11 @@ typedef struct AUTH_LOGON_CHALLENGE_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; // 0x00-0x04 + uint8 securityFlags; } sAuthLogonProof_C; typedef struct AUTH_LOGON_PROOF_S @@ -94,8 +83,8 @@ typedef struct AUTH_LOGON_PROOF_S uint8 cmd; uint8 error; uint8 M2[20]; - uint32 unk1; - uint32 unk2; + uint32 AccountFlags; + uint32 SurveyId; uint16 unk3; } sAuthLogonProof_S; @@ -109,256 +98,103 @@ typedef struct AUTH_LOGON_PROOF_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; -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 XFER_DATA -{ - uint8 opcode; - uint16 data_size; - uint8 data[ChunkSize]; -} XFER_DATA_STRUCT; - -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 -// Launch a thread to transfer a patch to the client -class PatcherRunnable: public ACE_Based::Runnable +enum class BufferSizes : uint32 { -public: - PatcherRunnable(class AuthSocket*); - void run(); - -private: - AuthSocket* mySocket; + SRP_6_V = 0x20, + SRP_6_S = 0x20, }; -typedef struct PATCH_INFO -{ - uint8 md5[MD5_DIGEST_LENGTH]; -} PATCH_INFO; - -// Caches MD5 hash of client patches present on the server -class Patcher -{ -public: - typedef std::map<std::string, PATCH_INFO*> Patches; - ~Patcher(); - Patcher(); - Patches::const_iterator begin() const { return _patches.begin(); } - Patches::const_iterator end() const { return _patches.end(); } - void LoadPatchMD5(char*); - bool GetHash(char * pat, uint8 mymd5[16]); - -private: - void LoadPatchesInfo(); - Patches _patches; -}; - -const AuthHandler table[] = -{ - { AUTH_LOGON_CHALLENGE, STATUS_CONNECTED, &AuthSocket::_HandleLogonChallenge }, - { AUTH_LOGON_PROOF, STATUS_CONNECTED, &AuthSocket::_HandleLogonProof }, - { AUTH_RECONNECT_CHALLENGE, STATUS_CONNECTED, &AuthSocket::_HandleReconnectChallenge}, - { AUTH_RECONNECT_PROOF, STATUS_CONNECTED, &AuthSocket::_HandleReconnectProof }, - { REALM_LIST, STATUS_AUTHED, &AuthSocket::_HandleRealmList }, - { XFER_ACCEPT, STATUS_CONNECTED, &AuthSocket::_HandleXferAccept }, - { XFER_RESUME, STATUS_CONNECTED, &AuthSocket::_HandleXferResume }, - { XFER_CANCEL, STATUS_CONNECTED, &AuthSocket::_HandleXferCancel } -}; - -#define AUTH_TOTAL_COMMANDS 8 - -// Holds the MD5 hash of client patches present on the server -Patcher PatchesCache; +#define REALM_LIST_PACKET_SIZE 4 +#define XFER_ACCEPT_SIZE 0 +#define XFER_RESUME_SIZE 8 +#define XFER_CANCEL_SIZE 0 -// Constructor - set the N and g values for SRP6 -AuthSocket::AuthSocket(RealmSocket& socket) : - pPatch(NULL), socket_(socket), _authed(false), _build(0), - _expversion(0), _accountSecurityLevel(SEC_PLAYER) +std::unordered_map<uint8, AuthHandler> AuthSession::InitHandlers() { - N.SetHexStr("894B645E89E1535BBDAD5B8B290650530801B18EBFBF5E8FAB3C82872A3E9BB7"); - g.SetDword(7); -} + std::unordered_map<uint8, AuthHandler> handlers; -// Close patch file descriptor before leaving -AuthSocket::~AuthSocket(void) { } + handlers[AUTH_LOGON_CHALLENGE] = { STATUS_CONNECTED, sizeof(AUTH_LOGON_CHALLENGE_C), &AuthSession::HandleLogonChallenge }; + handlers[AUTH_LOGON_PROOF] = { STATUS_CONNECTED, sizeof(AUTH_LOGON_PROOF_C), &AuthSession::HandleLogonProof }; + handlers[AUTH_RECONNECT_CHALLENGE] = { STATUS_CONNECTED, sizeof(AUTH_LOGON_CHALLENGE_C), &AuthSession::HandleReconnectChallenge }; + handlers[AUTH_RECONNECT_PROOF] = { STATUS_CONNECTED, sizeof(AUTH_RECONNECT_PROOF_C), &AuthSession::HandleReconnectProof }; + handlers[REALM_LIST] = { STATUS_AUTHED, REALM_LIST_PACKET_SIZE, &AuthSession::HandleRealmList }; + handlers[XFER_ACCEPT] = { STATUS_AUTHED, XFER_ACCEPT_SIZE, &AuthSession::HandleXferAccept }; + handlers[XFER_RESUME] = { STATUS_AUTHED, XFER_RESUME_SIZE, &AuthSession::HandleXferResume }; + handlers[XFER_CANCEL] = { STATUS_AUTHED, XFER_CANCEL_SIZE, &AuthSession::HandleXferCancel }; -// Accept the connection -void AuthSocket::OnAccept(void) -{ - TC_LOG_DEBUG("server.authserver", "'%s:%d' Accepting connection", socket().getRemoteAddress().c_str(), socket().getRemotePort()); + return handlers; } -void AuthSocket::OnClose(void) -{ - TC_LOG_DEBUG("server.authserver", "AuthSocket::OnClose"); -} +std::unordered_map<uint8, AuthHandler> const Handlers = AuthSession::InitHandlers(); -// Read the packet from the client -void AuthSocket::OnRead() +void AuthSession::ReadHeaderHandler() { - #define MAX_AUTH_LOGON_CHALLENGES_IN_A_ROW 3 - uint32 challengesInARow = 0; - uint8 _cmd; - while (1) + uint8 cmd = GetHeaderBuffer()[0]; + auto itr = Handlers.find(cmd); + if (itr != Handlers.end()) { - if (!socket().recv_soft((char *)&_cmd, 1)) - return; - - if (_cmd == AUTH_LOGON_CHALLENGE) + // Handle dynamic size packet + if (cmd == AUTH_LOGON_CHALLENGE || cmd == AUTH_RECONNECT_CHALLENGE) { - ++challengesInARow; - if (challengesInARow == MAX_AUTH_LOGON_CHALLENGES_IN_A_ROW) - { - TC_LOG_WARN("server.authserver", "Got %u AUTH_LOGON_CHALLENGE in a row from '%s', possible ongoing DoS", challengesInARow, socket().getRemoteAddress().c_str()); - socket().shutdown(); - 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))) - { - TC_LOG_DEBUG("server.authserver", "Got data for cmd %u recv length %u", (uint32)_cmd, (uint32)socket().recv_len()); - - if (!(*this.*table[i].handler)()) - { - TC_LOG_DEBUG("server.authserver", "Command handler failed for cmd %u recv length %u", (uint32)_cmd, (uint32)socket().recv_len()); - return; - } - break; - } - } + ReadData(sizeof(uint8) + sizeof(uint16)); //error + size + sAuthLogonChallenge_C* challenge = reinterpret_cast<sAuthLogonChallenge_C*>(GetDataBuffer()); - // Report unknown packets in the error log - if (i == AUTH_TOTAL_COMMANDS) - { - TC_LOG_ERROR("server.authserver", "Got unknown packet from '%s'", socket().getRemoteAddress().c_str()); - socket().shutdown(); - return; + AsyncReadData(challenge->size); } + else + AsyncReadData(itr->second.packetSize); } + else + CloseSocket(); } -// Make the SRP6 calculation from hash in dB -void AuthSocket::_SetVSFields(const std::string& rI) +void AuthSession::ReadDataHandler() { - 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().get(), I.GetNumBytes()); - - std::reverse(mDigest, mDigest + SHA_DIGEST_LENGTH); - - SHA1Hash sha; - sha.UpdateData(s.AsByteArray().get(), s.GetNumBytes()); - sha.UpdateData(mDigest, SHA_DIGEST_LENGTH); - sha.Finalize(); - BigNumber x; - x.SetBinary(sha.GetDigest(), sha.GetLength()); - v = g.ModExp(x, N); - - // No SQL injection (username escaped) - char *v_hex, *s_hex; - v_hex = v.AsHexStr(); - s_hex = s.AsHexStr(); - - PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_VS); - stmt->setString(0, v_hex); - stmt->setString(1, s_hex); - stmt->setString(2, _login); - LoginDatabase.Execute(stmt); + if (!(*this.*Handlers.at(GetHeaderBuffer()[0]).handler)()) + { + CloseSocket(); + return; + } - OPENSSL_free(v_hex); - OPENSSL_free(s_hex); + AsyncReadHeader(); } -// Logon Challenge command handler -bool AuthSocket::_HandleLogonChallenge() +void AuthSession::AsyncWrite(ByteBuffer& packet) { - TC_LOG_DEBUG("server.authserver", "Entering _HandleLogonChallenge"); - if (socket().recv_len() < sizeof(sAuthLogonChallenge_C)) - return false; + if (!IsOpen()) + return; - // Read the first 4 bytes (header) to get the length of the remaining of the packet - std::vector<uint8> buf; - buf.resize(4); + std::lock_guard<std::mutex> guard(_writeLock); - socket().recv((char *)&buf[0], 4); + bool needsWriteStart = _writeQueue.empty(); -#if TRINITY_ENDIAN == TRINITY_BIGENDIAN - EndianConvert(*((uint16*)(buf[0]))); -#endif + _writeQueue.push(std::move(packet)); - uint16 remaining = ((sAuthLogonChallenge_C *)&buf[0])->size; - TC_LOG_DEBUG("server.authserver", "[AuthChallenge] got header, body is %#04x bytes", remaining); + if (needsWriteStart) + Base::AsyncWrite(_writeQueue.front()); +} - if ((remaining < sizeof(sAuthLogonChallenge_C) - buf.size()) || (socket().recv_len() < remaining)) - return false; +bool AuthSession::HandleLogonChallenge() +{ + sAuthLogonChallenge_C* challenge = reinterpret_cast<sAuthLogonChallenge_C*>(GetDataBuffer()); - //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 - socket().recv((char *)&buf[4], remaining); - TC_LOG_DEBUG("server.authserver", "[AuthChallenge] got full packet, %#04x bytes", ch->size); - TC_LOG_DEBUG("server.authserver", "[AuthChallenge] name(%d): '%s'", ch->I_len, ch->I); - - // BigEndian code, nop in little endian case - // size already converted -#if TRINITY_ENDIAN == TRINITY_BIGENDIAN - 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); -#endif + //TC_LOG_DEBUG("server.authserver", "[AuthChallenge] got full packet, %#04x bytes", challenge->size); + TC_LOG_DEBUG("server.authserver", "[AuthChallenge] name(%d): '%s'", challenge->I_len, challenge->I); ByteBuffer pkt; - _login = (const char*)ch->I; - _build = ch->build; + _login.assign((const char*)challenge->I, challenge->I_len); + _build = challenge->build; _expversion = uint8(AuthHelper::IsPostBCAcceptedClientBuild(_build) ? POST_BC_EXP_FLAG : (AuthHelper::IsPreBCAcceptedClientBuild(_build) ? PRE_BC_EXP_FLAG : NO_VALID_EXP_FLAG)); - _os = (const char*)ch->os; + _os = (const char*)challenge->os; if (_os.size() > 4) return false; @@ -372,14 +208,16 @@ bool AuthSocket::_HandleLogonChallenge() // Verify that this IP is not in the ip_banned table LoginDatabase.Execute(LoginDatabase.GetPreparedStatement(LOGIN_DEL_EXPIRED_IP_BANS)); - std::string const& ip_address = socket().getRemoteAddress(); + std::string ipAddress = GetRemoteIpAddress().to_string(); + uint16 port = GetRemotePort(); + PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_IP_BANNED); - stmt->setString(0, ip_address); + stmt->setString(0, ipAddress); PreparedQueryResult result = LoginDatabase.Query(stmt); if (result) { pkt << uint8(WOW_FAIL_BANNED); - TC_LOG_DEBUG("server.authserver", "'%s:%d' [AuthChallenge] Banned ip tries to login!", socket().getRemoteAddress().c_str(), socket().getRemotePort()); + TC_LOG_DEBUG("server.authserver", "'%s:%d' [AuthChallenge] Banned ip tries to login!", ipAddress.c_str(), port); } else { @@ -397,10 +235,10 @@ bool AuthSocket::_HandleLogonChallenge() bool locked = false; if (fields[2].GetUInt8() == 1) // if ip is locked { - TC_LOG_DEBUG("server.authserver", "[AuthChallenge] Account '%s' is locked to IP - '%s'", _login.c_str(), fields[3].GetCString()); - TC_LOG_DEBUG("server.authserver", "[AuthChallenge] Player address is '%s'", ip_address.c_str()); + TC_LOG_DEBUG("server.authserver", "[AuthChallenge] Account '%s' is locked to IP - '%s'", _login.c_str(), fields[4].GetCString()); + TC_LOG_DEBUG("server.authserver", "[AuthChallenge] Player address is '%s'", ipAddress.c_str()); - if (strcmp(fields[4].GetCString(), ip_address.c_str()) != 0) + if (strcmp(fields[4].GetCString(), ipAddress.c_str()) != 0) { TC_LOG_DEBUG("server.authserver", "[AuthChallenge] Account IP differs"); pkt << uint8(WOW_FAIL_LOCKED_ENFORCED); @@ -417,7 +255,7 @@ bool AuthSocket::_HandleLogonChallenge() TC_LOG_DEBUG("server.authserver", "[AuthChallenge] Account '%s' is not locked to country", _login.c_str()); else if (!accountCountry.empty()) { - uint32 ip = inet_addr(ip_address.c_str()); + uint32 ip = inet_addr(ipAddress.c_str()); EndianConvertReverse(ip); stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_LOGON_COUNTRY); @@ -425,7 +263,9 @@ bool AuthSocket::_HandleLogonChallenge() if (PreparedQueryResult sessionCountryQuery = LoginDatabase.Query(stmt)) { std::string loginCountry = (*sessionCountryQuery)[0].GetString(); - TC_LOG_DEBUG("server.authserver", "[AuthChallenge] Account '%s' is locked to country: '%s' Player country is '%s'", _login.c_str(), accountCountry.c_str(), loginCountry.c_str()); + TC_LOG_DEBUG("server.authserver", "[AuthChallenge] Account '%s' is locked to country: '%s' Player country is '%s'", _login.c_str(), + accountCountry.c_str(), loginCountry.c_str()); + if (loginCountry != accountCountry) { TC_LOG_DEBUG("server.authserver", "[AuthChallenge] Account country differs."); @@ -443,7 +283,7 @@ bool AuthSocket::_HandleLogonChallenge() if (!locked) { //set expired bans to inactive - LoginDatabase.Execute(LoginDatabase.GetPreparedStatement(LOGIN_UPD_EXPIRED_ACCOUNT_BANS)); + LoginDatabase.DirectExecute(LoginDatabase.GetPreparedStatement(LOGIN_UPD_EXPIRED_ACCOUNT_BANS)); // If the account is banned, reject the logon attempt stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_ACCOUNT_BANNED); @@ -454,12 +294,14 @@ bool AuthSocket::_HandleLogonChallenge() if ((*banresult)[0].GetUInt32() == (*banresult)[1].GetUInt32()) { pkt << uint8(WOW_FAIL_BANNED); - TC_LOG_DEBUG("server.authserver", "'%s:%d' [AuthChallenge] Banned account %s tried to login!", socket().getRemoteAddress().c_str(), socket().getRemotePort(), _login.c_str ()); + TC_LOG_DEBUG("server.authserver", "'%s:%d' [AuthChallenge] Banned account %s tried to login!", ipAddress.c_str(), + port, _login.c_str()); } else { pkt << uint8(WOW_FAIL_SUSPENDED); - TC_LOG_DEBUG("server.authserver", "'%s:%d' [AuthChallenge] Temporarily banned account %s tried to login!", socket().getRemoteAddress().c_str(), socket().getRemotePort(), _login.c_str ()); + TC_LOG_DEBUG("server.authserver", "'%s:%d' [AuthChallenge] Temporarily banned account %s tried to login!", + ipAddress.c_str(), port, _login.c_str()); } } else @@ -474,8 +316,8 @@ bool AuthSocket::_HandleLogonChallenge() 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() != s_BYTE_SIZE * 2 || databaseS.size() != s_BYTE_SIZE * 2) - _SetVSFields(rI); + 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()); @@ -500,10 +342,10 @@ bool AuthSocket::_HandleLogonChallenge() // B may be calculated < 32B so we force minimal length to 32B pkt.append(B.AsByteArray(32).get(), 32); // 32 bytes pkt << uint8(1); - pkt.append(g.AsByteArray().get(), 1); + pkt.append(g.AsByteArray(1).get(), 1); pkt << uint8(32); pkt.append(N.AsByteArray(32).get(), 32); - pkt.append(s.AsByteArray().get(), s.GetNumBytes()); // 32 bytes + 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; @@ -537,10 +379,12 @@ bool AuthSocket::_HandleLogonChallenge() _localizationName.resize(4); for (int i = 0; i < 4; ++i) - _localizationName[i] = ch->country[4-i-1]; + _localizationName[i] = challenge->country[4 - i - 1]; - TC_LOG_DEBUG("server.authserver", "'%s:%d' [AuthChallenge] account %s is using '%c%c%c%c' locale (%u)", socket().getRemoteAddress().c_str(), socket().getRemotePort(), - _login.c_str (), ch->country[3], ch->country[2], ch->country[1], ch->country[0], GetLocaleByName(_localizationName) + TC_LOG_DEBUG("server.authserver", "'%s:%d' [AuthChallenge] account %s is using '%c%c%c%c' locale (%u)", + ipAddress.c_str(), port, _login.c_str(), + challenge->country[3], challenge->country[2], challenge->country[1], challenge->country[0], + GetLocaleByName(_localizationName) ); } } @@ -549,39 +393,35 @@ bool AuthSocket::_HandleLogonChallenge() pkt << uint8(WOW_FAIL_UNKNOWN_ACCOUNT); } - socket().send((char const*)pkt.contents(), pkt.size()); + AsyncWrite(pkt); return true; } // Logon Proof command handler -bool AuthSocket::_HandleLogonProof() +bool AuthSession::HandleLogonProof() { + TC_LOG_DEBUG("server.authserver", "Entering _HandleLogonProof"); // Read the packet - sAuthLogonProof_C lp; - - if (!socket().recv((char *)&lp, sizeof(sAuthLogonProof_C))) - return false; + sAuthLogonProof_C *logonProof = reinterpret_cast<sAuthLogonProof_C*>(GetDataBuffer()); // 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"); - socket().shutdown(); - return true; + return false; } // Continue the SRP6 calculation based on data received from the client BigNumber A; - A.SetBinary(lp.A, 32); + A.SetBinary(logonProof->A, 32); // SRP safeguard: abort if A == 0 if (A.isZero()) { - socket().shutdown(); - return true; + return false; } SHA1Hash sha; @@ -646,12 +486,12 @@ bool AuthSocket::_HandleLogonProof() sha.UpdateBigNumbers(&s, &A, &B, &K, NULL); sha.Finalize(); BigNumber M; - M.SetBinary(sha.GetDigest(), 20); + M.SetBinary(sha.GetDigest(), sha.GetLength()); // Check if SRP6 results match (password is correct), else send an error - if (!memcmp(M.AsByteArray().get(), lp.M1, 20)) + if (!memcmp(M.AsByteArray(sha.GetLength()).get(), logonProof->M1, 20)) { - TC_LOG_DEBUG("server.authserver", "'%s:%d' User '%s' successfully authenticated", socket().getRemoteAddress().c_str(), socket().getRemotePort(), _login.c_str()); + TC_LOG_DEBUG("server.authserver", "'%s:%d' User '%s' successfully authenticated", GetRemoteIpAddress().to_string().c_str(), GetRemotePort(), _login.c_str()); // Update the sessionkey, last_ip, last login time and reset number of failed logins in the account table for this account // No SQL injection (escaped user name) and IP address as received by socket @@ -659,7 +499,7 @@ bool AuthSocket::_HandleLogonProof() PreparedStatement *stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_LOGONPROOF); stmt->setString(0, K_hex); - stmt->setString(1, socket().getRemoteAddress().c_str()); + stmt->setString(1, GetRemoteIpAddress().to_string().c_str()); stmt->setUInt32(2, GetLocaleByName(_localizationName)); stmt->setString(3, _os); stmt->setString(4, _login); @@ -673,34 +513,39 @@ bool AuthSocket::_HandleLogonProof() sha.Finalize(); // Check auth token - if ((lp.securityFlags & 0x04) || !_tokenKey.empty()) + if ((logonProof->securityFlags & 0x04) || !_tokenKey.empty()) { - uint8 size; - socket().recv((char*)&size, 1); - char* token = new char[size + 1]; - token[size] = '\0'; - socket().recv(token, size); - unsigned int validToken = TOTP::GenerateToken(_tokenKey.c_str()); - unsigned int incomingToken = atoi(token); - delete[] token; + ReadData(1); + uint8 size = *(GetDataBuffer() + sizeof(sAuthLogonProof_C)); + ReadData(size); + std::string token(reinterpret_cast<char*>(GetDataBuffer() + sizeof(sAuthLogonProof_C) + sizeof(size)), size); + uint32 validToken = TOTP::GenerateToken(_tokenKey.c_str()); + uint32 incomingToken = atoi(token.c_str()); if (validToken != incomingToken) { - char data[] = { AUTH_LOGON_PROOF, WOW_FAIL_UNKNOWN_ACCOUNT, 3, 0 }; - socket().send(data, sizeof(data)); + ByteBuffer packet; + packet << uint8(AUTH_LOGON_PROOF); + packet << uint8(WOW_FAIL_UNKNOWN_ACCOUNT); + packet << uint8(3); + packet << uint8(0); + AsyncWrite(packet); return false; } } + 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.unk1 = 0x00800000; // Accountflags. 0x01 = GM, 0x08 = Trial, 0x00800000 = Pro pass (arena tournament) - proof.unk2 = 0x00; // SurveyId - proof.unk3 = 0x00; - socket().send((char *)&proof, sizeof(proof)); + proof.AccountFlags = 0x00800000; // 0x01 = GM, 0x08 = Trial, 0x00800000 = Pro pass (arena tournament) + proof.SurveyId = 0; + proof.unk3 = 0; + + packet.resize(sizeof(proof)); + std::memcpy(packet.contents(), &proof, sizeof(proof)); } else { @@ -709,23 +554,43 @@ bool AuthSocket::_HandleLogonProof() proof.cmd = AUTH_LOGON_PROOF; proof.error = 0; proof.unk2 = 0x00; - socket().send((char *)&proof, sizeof(proof)); + + packet.resize(sizeof(proof)); + std::memcpy(packet.contents(), &proof, sizeof(proof)); } - _authed = true; + AsyncWrite(packet); + _isAuthenticated = true; } else { - char data[4] = { AUTH_LOGON_PROOF, WOW_FAIL_UNKNOWN_ACCOUNT, 3, 0 }; - socket().send(data, sizeof(data)); + ByteBuffer packet; + packet << uint8(AUTH_LOGON_PROOF); + packet << uint8(WOW_FAIL_UNKNOWN_ACCOUNT); + packet << uint8(3); + packet << uint8(0); + AsyncWrite(packet); - TC_LOG_DEBUG("server.authserver", "'%s:%d' [AuthChallenge] account %s tried to login with invalid password!", socket().getRemoteAddress().c_str(), socket().getRemotePort(), _login.c_str ()); + TC_LOG_DEBUG("server.authserver", "'%s:%d' [AuthChallenge] account %s tried to login with invalid password!", + GetRemoteIpAddress().to_string().c_str(), GetRemotePort(), _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("Wrong.Password.Login.Logging", false)) + { + PreparedStatement* logstmt = LoginDatabase.GetPreparedStatement(LOGIN_INS_FALP_IP_LOGGING); + logstmt->setString(0, _login); + 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); + PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_FAILEDLOGINS); stmt->setString(0, _login); LoginDatabase.Execute(stmt); @@ -750,17 +615,17 @@ bool AuthSocket::_HandleLogonProof() 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", - socket().getRemoteAddress().c_str(), socket().getRemotePort(), _login.c_str(), WrongPassBanTime, failed_logins); + GetRemoteIpAddress().to_string().c_str(), GetRemotePort(), _login.c_str(), WrongPassBanTime, failed_logins); } else { stmt = LoginDatabase.GetPreparedStatement(LOGIN_INS_IP_AUTO_BANNED); - stmt->setString(0, socket().getRemoteAddress()); + stmt->setString(0, GetRemoteIpAddress().to_string()); stmt->setUInt32(1, WrongPassBanTime); LoginDatabase.Execute(stmt); - TC_LOG_DEBUG("server.authserver", "'%s:%d' [AuthChallenge] IP %s got banned for '%u' seconds because account %s failed to authenticate '%u' times", - socket().getRemoteAddress().c_str(), socket().getRemotePort(), socket().getRemoteAddress().c_str(), WrongPassBanTime, _login.c_str(), failed_logins); + 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, _login.c_str(), failed_logins); } } } @@ -770,40 +635,15 @@ bool AuthSocket::_HandleLogonProof() return true; } -// Reconnect Challenge command handler -bool AuthSocket::_HandleReconnectChallenge() +bool AuthSession::HandleReconnectChallenge() { TC_LOG_DEBUG("server.authserver", "Entering _HandleReconnectChallenge"); - if (socket().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<uint8> buf; - buf.resize(4); - - socket().recv((char *)&buf[0], 4); - -#if TRINITY_ENDIAN == TRINITY_BIGENDIAN - EndianConvert(*((uint16*)(buf[0]))); -#endif - - uint16 remaining = ((sAuthLogonChallenge_C *)&buf[0])->size; - TC_LOG_DEBUG("server.authserver", "[ReconnectChallenge] got header, body is %#04x bytes", remaining); + sAuthLogonChallenge_C* challenge = reinterpret_cast<sAuthLogonChallenge_C*>(GetDataBuffer()); - if ((remaining < sizeof(sAuthLogonChallenge_C) - buf.size()) || (socket().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]; + //TC_LOG_DEBUG("server.authserver", "[AuthChallenge] got full packet, %#04x bytes", challenge->size); + TC_LOG_DEBUG("server.authserver", "[AuthChallenge] name(%d): '%s'", challenge->I_len, challenge->I); - // Read the remaining of the packet - socket().recv((char *)&buf[4], remaining); - TC_LOG_DEBUG("server.authserver", "[ReconnectChallenge] got full packet, %#04x bytes", ch->size); - TC_LOG_DEBUG("server.authserver", "[ReconnectChallenge] name(%d): '%s'", ch->I_len, ch->I); - - _login = (const char*)ch->I; + _login.assign((const char*)challenge->I, challenge->I_len); PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_SESSIONKEY); stmt->setString(0, _login); @@ -812,15 +652,15 @@ bool AuthSocket::_HandleReconnectChallenge() // Stop if the account is not found if (!result) { - TC_LOG_ERROR("server.authserver", "'%s:%d' [ERROR] user %s tried to login and we cannot find his session key in the database.", socket().getRemoteAddress().c_str(), socket().getRemotePort(), _login.c_str()); - socket().shutdown(); + TC_LOG_ERROR("server.authserver", "'%s:%d' [ERROR] user %s tried to login and we cannot find his session key in the database.", + GetRemoteIpAddress().to_string().c_str(), GetRemotePort(), _login.c_str()); return false; } // Reinitialize build, expansion and the account securitylevel - _build = ch->build; + _build = challenge->build; _expversion = uint8(AuthHelper::IsPostBCAcceptedClientBuild(_build) ? POST_BC_EXP_FLAG : (AuthHelper::IsPreBCAcceptedClientBuild(_build) ? PRE_BC_EXP_FLAG : NO_VALID_EXP_FLAG)); - _os = (const char*)ch->os; + _os = (const char*)challenge->os; if (_os.size() > 4) return false; @@ -832,7 +672,7 @@ bool AuthSocket::_HandleReconnectChallenge() uint8 secLevel = fields[2].GetUInt8(); _accountSecurityLevel = secLevel <= SEC_ADMINISTRATOR ? AccountTypes(secLevel) : SEC_ADMINISTRATOR; - K.SetHexStr ((*result)[0].GetCString()); + K.SetHexStr((*result)[0].GetCString()); // Sending response ByteBuffer pkt; @@ -841,24 +681,21 @@ bool AuthSocket::_HandleReconnectChallenge() _reconnectProof.SetRand(16 * 8); pkt.append(_reconnectProof.AsByteArray(16).get(), 16); // 16 bytes random pkt << uint64(0x00) << uint64(0x00); // 16 bytes zeros - socket().send((char const*)pkt.contents(), pkt.size()); + + AsyncWrite(pkt); + return true; } - -// Reconnect Proof command handler -bool AuthSocket::_HandleReconnectProof() +bool AuthSession::HandleReconnectProof() { TC_LOG_DEBUG("server.authserver", "Entering _HandleReconnectProof"); - // Read the packet - sAuthReconnectProof_C lp; - if (!socket().recv((char *)&lp, sizeof(sAuthReconnectProof_C))) - return false; + sAuthReconnectProof_C *reconnectProof = reinterpret_cast<sAuthReconnectProof_C*>(GetDataBuffer()); if (_login.empty() || !_reconnectProof.GetNumBytes() || !K.GetNumBytes()) return false; BigNumber t1; - t1.SetBinary(lp.R1, 16); + t1.SetBinary(reconnectProof->R1, 16); SHA1Hash sha; sha.Initialize(); @@ -866,55 +703,63 @@ bool AuthSocket::_HandleReconnectProof() sha.UpdateBigNumbers(&t1, &_reconnectProof, &K, NULL); sha.Finalize(); - if (!memcmp(sha.GetDigest(), lp.R2, SHA_DIGEST_LENGTH)) + 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 - socket().send((char const*)pkt.contents(), pkt.size()); - _authed = true; + AsyncWrite(pkt); + _isAuthenticated = true; return true; } else { - TC_LOG_ERROR("server.authserver", "'%s:%d' [ERROR] user %s tried to login, but session is invalid.", socket().getRemoteAddress().c_str(), socket().getRemotePort(), _login.c_str()); - socket().shutdown(); + TC_LOG_ERROR("server.authserver", "'%s:%d' [ERROR] user %s tried to login, but session is invalid.", GetRemoteIpAddress().to_string().c_str(), + GetRemotePort(), _login.c_str()); return false; } } -ACE_INET_Addr const& AuthSocket::GetAddressForClient(Realm const& realm, ACE_INET_Addr const& clientAddr) +tcp::endpoint const GetAddressForClient(Realm const& realm, ip::address const& clientAddr) { + ip::address realmIp; + // Attempt to send best address for client if (clientAddr.is_loopback()) { // Try guessing if realm is also connected locally if (realm.LocalAddress.is_loopback() || realm.ExternalAddress.is_loopback()) - return clientAddr; - - // Assume that user connecting from the machine that authserver is located on - // has all realms available in his local network - return realm.LocalAddress; + realmIp = clientAddr; + else + { + // Assume that user connecting from the machine that authserver is located on + // has all realms available in his local network + realmIp = realm.LocalAddress; + } + } + else + { + if (clientAddr.is_v4() && + (clientAddr.to_v4().to_ulong() & realm.LocalSubnetMask.to_v4().to_ulong()) == + (realm.LocalAddress.to_v4().to_ulong() & realm.LocalSubnetMask.to_v4().to_ulong())) + { + realmIp = realm.LocalAddress; + } + else + realmIp = realm.ExternalAddress; } - // Check if connecting client is in the same network - if (IsIPAddrInNetwork(realm.LocalAddress, clientAddr, realm.LocalSubnetMask)) - return realm.LocalAddress; + tcp::endpoint endpoint(realmIp, realm.port); // Return external IP - return realm.ExternalAddress; + return endpoint; } -// Realm List command handler -bool AuthSocket::_HandleRealmList() +bool AuthSession::HandleRealmList() { TC_LOG_DEBUG("server.authserver", "Entering _HandleRealmList"); - if (socket().recv_len() < 5) - return false; - - socket().recv_skip(5); // Get the user id (else close the connection) // No SQL injection (prepared statement) @@ -923,8 +768,8 @@ bool AuthSocket::_HandleRealmList() PreparedQueryResult result = LoginDatabase.Query(stmt); if (!result) { - TC_LOG_ERROR("server.authserver", "'%s:%d' [ERROR] user %s tried to login but we cannot find him in the database.", socket().getRemoteAddress().c_str(), socket().getRemotePort(), _login.c_str()); - socket().shutdown(); + TC_LOG_ERROR("server.authserver", "'%s:%d' [ERROR] user %s tried to login but we cannot find him in the database.", GetRemoteIpAddress().to_string().c_str(), + GetRemotePort(), _login.c_str()); return false; } @@ -934,9 +779,6 @@ bool AuthSocket::_HandleRealmList() // Update realm list if need sRealmList->UpdateIfNeed(); - ACE_INET_Addr clientAddr; - socket().peer().get_remote_addr(clientAddr); - // Circle through realms in the RealmList and construct the return packet (including # of user characters in each realm) ByteBuffer pkt; @@ -969,9 +811,6 @@ bool AuthSocket::_HandleRealmList() name = ss.str(); } - // We don't need the port number from which client connects with but the realm's port - clientAddr.set_port_number(realm.ExternalAddress.get_port_number()); - uint8 lock = (realm.allowedSecurityLevel > _accountSecurityLevel) ? 1 : 0; uint8 AmountOfCharacters = 0; @@ -987,12 +826,12 @@ bool AuthSocket::_HandleRealmList() pkt << lock; // if 1, then realm locked pkt << uint8(flag); // RealmFlags pkt << name; - pkt << GetAddressString(GetAddressForClient(realm, clientAddr)); + pkt << boost::lexical_cast<std::string>(GetAddressForClient(realm, GetRemoteIpAddress())); pkt << realm.populationLevel; pkt << AmountOfCharacters; pkt << realm.timezone; // realm category if (_expversion & POST_BC_EXP_FLAG) // 2.x and 3.x clients - pkt << uint8(0x2C); // unk, may be realm number/id? + pkt << uint8(realm.m_ID); else pkt << uint8(0x0); // 1.12.1 and 1.12.2 clients @@ -1031,183 +870,68 @@ bool AuthSocket::_HandleRealmList() hdr << uint16(pkt.size() + RealmListSizeBuffer.size()); hdr.append(RealmListSizeBuffer); // append RealmList's size buffer hdr.append(pkt); // append realms in the realmlist - - socket().send((char const*)hdr.contents(), hdr.size()); - + AsyncWrite(hdr); return true; } // Resume patch transfer -bool AuthSocket::_HandleXferResume() +bool AuthSession::HandleXferResume() { TC_LOG_DEBUG("server.authserver", "Entering _HandleXferResume"); - // Check packet length and patch existence - if (socket().recv_len() < 9 || !pPatch) // FIXME: pPatch is never used - { - TC_LOG_ERROR("server.authserver", "Error while resuming patch transfer (wrong packet)"); - return false; - } - - // Launch a PatcherRunnable thread starting at given patch file offset - uint64 start; - socket().recv_skip(1); - socket().recv((char*)&start, sizeof(start)); - fseek(pPatch, long(start), 0); - - ACE_Based::Thread u(new PatcherRunnable(this)); + //uint8 + //uint64 return true; } // Cancel patch transfer -bool AuthSocket::_HandleXferCancel() +bool AuthSession::HandleXferCancel() { TC_LOG_DEBUG("server.authserver", "Entering _HandleXferCancel"); - - // Close and delete the socket - socket().recv_skip(1); //clear input buffer - socket().shutdown(); - - return true; + //uint8 + return false; } // Accept patch transfer -bool AuthSocket::_HandleXferAccept() +bool AuthSession::HandleXferAccept() { TC_LOG_DEBUG("server.authserver", "Entering _HandleXferAccept"); - - // Check packet length and patch existence - if (!pPatch) - { - TC_LOG_ERROR("server.authserver", "Error while accepting patch transfer (wrong packet)"); - return false; - } - - // Launch a PatcherRunnable thread, starting at the beginning of the patch file - socket().recv_skip(1); // clear input buffer - fseek(pPatch, 0, 0); - - ACE_Based::Thread u(new PatcherRunnable(this)); + //uint8 return true; } -PatcherRunnable::PatcherRunnable(class AuthSocket* as) -{ - mySocket = as; -} - -// Send content of patch file to the client -void PatcherRunnable::run() { } - -// Preload MD5 hashes of existing patch files on server -#ifndef _WIN32 -#include <dirent.h> -#include <errno.h> -void Patcher::LoadPatchesInfo() -{ - DIR *dirp; - struct dirent *dp; - dirp = opendir("./patches/"); - - if (!dirp) - return; - - while (dirp) - { - errno = 0; - if ((dp = 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); - } - else - { - if (errno != 0) - { - closedir(dirp); - return; - } - break; - } - } - - if (dirp) - closedir(dirp); -} -#else -void Patcher::LoadPatchesInfo() -{ - WIN32_FIND_DATA fil; - HANDLE hFil = FindFirstFile("./patches/*.mpq", &fil); - if (hFil == INVALID_HANDLE_VALUE) - return; // no patches were found - - do - LoadPatchMD5(fil.cFileName); - while (FindNextFile(hFil, &fil)); -} -#endif - -// Calculate and store MD5 hash for a given patch file -void Patcher::LoadPatchMD5(char *szFileName) +// Make the SRP6 calculation from hash in dB +void AuthSession::SetVSFields(const std::string& rI) { - // Try to open the patch file - std::string path = "./patches/"; - path += szFileName; - FILE* pPatch = fopen(path.c_str(), "rb"); - TC_LOG_DEBUG("network", "Loading patch info from %s\n", path.c_str()); + s.SetRand(int32(BufferSizes::SRP_6_S) * 8); - if (!pPatch) - { - TC_LOG_ERROR("server.authserver", "Error loading patch %s\n", path.c_str()); - return; - } - - // Calculate the MD5 hash - MD5_CTX ctx; - MD5_Init(&ctx); - uint8* buf = new uint8[512 * 1024]; - - while (!feof(pPatch)) - { - size_t read = fread(buf, 1, 512 * 1024, pPatch); - MD5_Update(&ctx, buf, read); - } + BigNumber I; + I.SetHexStr(rI.c_str()); - delete [] buf; - fclose(pPatch); + // 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); - // Store the result in the internal patch hash map - _patches[path] = new PATCH_INFO; - MD5_Final((uint8 *)&_patches[path]->md5, &ctx); -} + std::reverse(mDigest, mDigest + SHA_DIGEST_LENGTH); -// Get cached MD5 hash for a given patch file -bool Patcher::GetHash(char * pat, uint8 mymd5[16]) -{ - for (Patches::iterator i = _patches.begin(); i != _patches.end(); ++i) - if (!stricmp(pat, i->first.c_str())) - { - memcpy(mymd5, i->second->md5, 16); - return true; - } + 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); - return false; -} + // No SQL injection (username escaped) + char *v_hex, *s_hex; + v_hex = v.AsHexStr(); + s_hex = s.AsHexStr(); -// Launch the patch hashing mechanism on object creation -Patcher::Patcher() -{ - LoadPatchesInfo(); -} + PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_VS); + stmt->setString(0, v_hex); + stmt->setString(1, s_hex); + stmt->setString(2, _login); + LoginDatabase.Execute(stmt); -// Empty and delete the patch map on termination -Patcher::~Patcher() -{ - for (Patches::iterator i = _patches.begin(); i != _patches.end(); ++i) - delete i->second; + OPENSSL_free(v_hex); + OPENSSL_free(s_hex); } diff --git a/src/server/authserver/Server/AuthSession.h b/src/server/authserver/Server/AuthSession.h new file mode 100644 index 00000000000..3497e3a030c --- /dev/null +++ b/src/server/authserver/Server/AuthSession.h @@ -0,0 +1,100 @@ +/* +* Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/> +* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/> +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at your +* option) any later version. +* +* This program is distributed in the hope that it will be useful, but WITHOUT +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +* more details. +* +* You should have received a copy of the GNU General Public License along +* with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#ifndef __AUTHSESSION_H__ +#define __AUTHSESSION_H__ + +#include "Common.h" +#include "ByteBuffer.h" +#include "Socket.h" +#include "BigNumber.h" +#include <memory> +#include <boost/asio/ip/tcp.hpp> + +using boost::asio::ip::tcp; + +struct AuthHandler; + +class AuthSession : public Socket<AuthSession, ByteBuffer> +{ + typedef Socket<AuthSession, ByteBuffer> Base; + +public: + static std::unordered_map<uint8, AuthHandler> InitHandlers(); + + AuthSession(tcp::socket&& socket) : Socket(std::move(socket), 1), + _isAuthenticated(false), _build(0), _expversion(0), _accountSecurityLevel(SEC_PLAYER) + { + N.SetHexStr("894B645E89E1535BBDAD5B8B290650530801B18EBFBF5E8FAB3C82872A3E9BB7"); + g.SetDword(7); + } + + void Start() override + { + AsyncReadHeader(); + } + + using Base::AsyncWrite; + void AsyncWrite(ByteBuffer& packet); + +protected: + void ReadHeaderHandler() override; + void ReadDataHandler() override; + +private: + 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); + + BigNumber N, s, g, v; + BigNumber b, B; + BigNumber K; + BigNumber _reconnectProof; + + bool _isAuthenticated; + std::string _tokenKey; + std::string _login; + std::string _localizationName; + std::string _os; + uint16 _build; + uint8 _expversion; + + AccountTypes _accountSecurityLevel; +}; + +#pragma pack(push, 1) + +struct AuthHandler +{ + uint32 status; + size_t packetSize; + bool (AuthSession::*handler)(); +}; + +#pragma pack(pop) + +#endif diff --git a/src/server/authserver/Server/AuthSocket.h b/src/server/authserver/Server/AuthSocket.h deleted file mode 100644 index c6513eaa5bf..00000000000 --- a/src/server/authserver/Server/AuthSocket.h +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Copyright (C) 2008-2013 TrinityCore <http://www.trinitycore.org/> - * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see <http://www.gnu.org/licenses/>. - */ - -#ifndef _AUTHSOCKET_H -#define _AUTHSOCKET_H - -#include "Common.h" -#include "BigNumber.h" -#include "RealmSocket.h" - -class ACE_INET_Addr; -struct Realm; - -// Handle login commands -class AuthSocket: public RealmSocket::Session -{ -public: - const static int s_BYTE_SIZE = 32; - - AuthSocket(RealmSocket& socket); - virtual ~AuthSocket(void); - - virtual void OnRead(void); - virtual void OnAccept(void); - virtual void OnClose(void); - - static ACE_INET_Addr const& GetAddressForClient(Realm const& realm, ACE_INET_Addr const& clientAddr); - - bool _HandleLogonChallenge(); - bool _HandleLogonProof(); - bool _HandleReconnectChallenge(); - bool _HandleReconnectProof(); - bool _HandleRealmList(); - - //data transfer handle for patch - bool _HandleXferResume(); - bool _HandleXferCancel(); - bool _HandleXferAccept(); - - void _SetVSFields(const std::string& rI); - - FILE* pPatch; - ACE_Thread_Mutex patcherLock; - -private: - RealmSocket& socket_; - RealmSocket& socket(void) { return socket_; } - - BigNumber N, s, g, v; - BigNumber b, B; - BigNumber K; - BigNumber _reconnectProof; - - bool _authed; - - std::string _login; - std::string _tokenKey; - - // 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; - std::string _os; - uint16 _build; - uint8 _expversion; - AccountTypes _accountSecurityLevel; -}; - -#endif diff --git a/src/server/authserver/Server/RealmAcceptor.h b/src/server/authserver/Server/RealmAcceptor.h deleted file mode 100644 index 39877f71538..00000000000 --- a/src/server/authserver/Server/RealmAcceptor.h +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright (C) 2008-2013 TrinityCore <http://www.trinitycore.org/> - * Copyright (C) 2005-2010 MaNGOS <http://getmangos.com/> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see <http://www.gnu.org/licenses/>. - */ - -#ifndef __REALMACCEPTOR_H__ -#define __REALMACCEPTOR_H__ - -#include <ace/Acceptor.h> -#include <ace/SOCK_Acceptor.h> - -#include "RealmSocket.h" -#include "AuthSocket.h" - -class RealmAcceptor : public ACE_Acceptor<RealmSocket, ACE_SOCK_Acceptor> -{ -public: - RealmAcceptor(void) { } - virtual ~RealmAcceptor(void) - { - if (reactor()) - reactor()->cancel_timer(this, 1); - } - -protected: - virtual int make_svc_handler(RealmSocket* &sh) - { - if (sh == 0) - ACE_NEW_RETURN(sh, RealmSocket, -1); - - sh->reactor(reactor()); - sh->set_session(new AuthSocket(*sh)); - return 0; - } - - virtual int handle_timeout(const ACE_Time_Value& /*current_time*/, const void* /*act = 0*/) - { - TC_LOG_DEBUG("server.authserver", "Resuming acceptor"); - reactor()->cancel_timer(this, 1); - return reactor()->register_handler(this, ACE_Event_Handler::ACCEPT_MASK); - } - - virtual int handle_accept_error(void) - { -#if defined(ENFILE) && defined(EMFILE) - if (errno == ENFILE || errno == EMFILE) - { - TC_LOG_ERROR("server.authserver", "Out of file descriptors, suspending incoming connections for 10 seconds"); - reactor()->remove_handler(this, ACE_Event_Handler::ACCEPT_MASK | ACE_Event_Handler::DONT_CALL); - reactor()->schedule_timer(this, NULL, ACE_Time_Value(10)); - } -#endif - return 0; - } -}; - -#endif diff --git a/src/server/authserver/Server/RealmSocket.cpp b/src/server/authserver/Server/RealmSocket.cpp deleted file mode 100644 index 13bc71f99a4..00000000000 --- a/src/server/authserver/Server/RealmSocket.cpp +++ /dev/null @@ -1,291 +0,0 @@ -/* - * Copyright (C) 2008-2013 TrinityCore <http://www.trinitycore.org/> - * Copyright (C) 2005-2010 MaNGOS <http://getmangos.com/> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see <http://www.gnu.org/licenses/>. - */ - -#include <ace/OS_NS_string.h> -#include <ace/INET_Addr.h> -#include <ace/SString.h> - -#include "RealmSocket.h" -#include "Log.h" - -RealmSocket::Session::Session(void) { } - -RealmSocket::Session::~Session(void) { } - -RealmSocket::RealmSocket(void) : - input_buffer_(4096), session_(NULL), - _remoteAddress(), _remotePort(0) -{ - reference_counting_policy().value(ACE_Event_Handler::Reference_Counting_Policy::ENABLED); - - msg_queue()->high_water_mark(8 * 1024 * 1024); - msg_queue()->low_water_mark(8 * 1024 * 1024); -} - -RealmSocket::~RealmSocket(void) -{ - if (msg_queue()) - msg_queue()->close(); - - // delete RealmSocketObject must never be called from our code. - closing_ = true; - - delete session_; - - peer().close(); -} - -int RealmSocket::open(void * arg) -{ - ACE_INET_Addr addr; - - if (peer().get_remote_addr(addr) == -1) - { - TC_LOG_ERROR("server.authserver", "Error %s while opening realm socket!", ACE_OS::strerror(errno)); - return -1; - } - - _remoteAddress = addr.get_host_addr(); - _remotePort = addr.get_port_number(); - - // Register with ACE Reactor - if (Base::open(arg) == -1) - return -1; - - if (session_) - session_->OnAccept(); - - // reactor takes care of the socket from now on - remove_reference(); - - return 0; -} - -int RealmSocket::close(u_long) -{ - shutdown(); - - closing_ = true; - - remove_reference(); - - return 0; -} - -const std::string& RealmSocket::getRemoteAddress(void) const -{ - return _remoteAddress; -} - -uint16 RealmSocket::getRemotePort(void) const -{ - return _remotePort; -} - -size_t RealmSocket::recv_len(void) const -{ - return input_buffer_.length(); -} - -bool RealmSocket::recv_soft(char *buf, size_t len) -{ - if (input_buffer_.length() < len) - return false; - - ACE_OS::memcpy(buf, input_buffer_.rd_ptr(), len); - - return true; -} - -bool RealmSocket::recv(char *buf, size_t len) -{ - bool ret = recv_soft(buf, len); - - if (ret) - recv_skip(len); - - return ret; -} - -void RealmSocket::recv_skip(size_t len) -{ - input_buffer_.rd_ptr(len); -} - -ssize_t RealmSocket::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. -#ifdef MSG_NOSIGNAL - ssize_t n = peer().send(message_block.rd_ptr(), len, MSG_NOSIGNAL); -#else - ssize_t n = peer().send(message_block.rd_ptr(), len); -#endif // MSG_NOSIGNAL - - if (n < 0) - { - if (errno == EWOULDBLOCK) // Blocking signal - return 0; - else // Error happened - return -1; - } - else if (n == 0) - { - // Can this happen ? - return -1; - } - - // return bytes transmitted - return n; -} - -bool RealmSocket::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 (msg_queue()->is_empty()) - { - // Try to send it directly. - ssize_t n = noblk_send(message_block); - - if (n < 0) - return false; - - size_t un = size_t(n); - if (un == len) - return true; - - // fall down - message_block.rd_ptr(un); - } - - ACE_Message_Block* mb = message_block.clone(); - - if (msg_queue()->enqueue_tail(mb, (ACE_Time_Value *)(&ACE_Time_Value::zero)) == -1) - { - mb->release(); - return false; - } - - if (reactor()->schedule_wakeup(this, ACE_Event_Handler::WRITE_MASK) == -1) - return false; - - return true; -} - -int RealmSocket::handle_output(ACE_HANDLE) -{ - if (closing_) - return -1; - - ACE_Message_Block* mb = 0; - - if (msg_queue()->is_empty()) - { - reactor()->cancel_wakeup(this, ACE_Event_Handler::WRITE_MASK); - return 0; - } - - if (msg_queue()->dequeue_head(mb, (ACE_Time_Value *)(&ACE_Time_Value::zero)) == -1) - return -1; - - ssize_t n = noblk_send(*mb); - - if (n < 0) - { - mb->release(); - return -1; - } - else if (size_t(n) == mb->length()) - { - mb->release(); - return 1; - } - else - { - mb->rd_ptr(n); - - if (msg_queue()->enqueue_head(mb, (ACE_Time_Value *) &ACE_Time_Value::zero) == -1) - { - mb->release(); - return -1; - } - - return 0; - } - - ACE_NOTREACHED(return -1); -} - -int RealmSocket::handle_close(ACE_HANDLE h, ACE_Reactor_Mask) -{ - // As opposed to WorldSocket::handle_close, we don't need locks here. - closing_ = true; - - if (h == ACE_INVALID_HANDLE) - peer().close_writer(); - - if (session_) - session_->OnClose(); - - reactor()->remove_handler(this, ACE_Event_Handler::DONT_CALL | ACE_Event_Handler::ALL_EVENTS_MASK); - return 0; -} - -int RealmSocket::handle_input(ACE_HANDLE) -{ - if (closing_) - return -1; - - const ssize_t space = input_buffer_.space(); - - ssize_t n = peer().recv(input_buffer_.wr_ptr(), space); - - if (n < 0) - return errno == EWOULDBLOCK ? 0 : -1; - else if (n == 0) // EOF - return -1; - - input_buffer_.wr_ptr((size_t)n); - - if (session_ != NULL) - { - session_->OnRead(); - input_buffer_.crunch(); - } - - // return 1 in case there is more data to read from OS - return n == space ? 1 : 0; -} - -void RealmSocket::set_session(Session* session) -{ - delete session_; - - session_ = session; -} diff --git a/src/server/authserver/Server/RealmSocket.h b/src/server/authserver/Server/RealmSocket.h deleted file mode 100644 index 24f2a5dc109..00000000000 --- a/src/server/authserver/Server/RealmSocket.h +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright (C) 2008-2013 TrinityCore <http://www.trinitycore.org/> - * Copyright (C) 2005-2010 MaNGOS <http://getmangos.com/> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see <http://www.gnu.org/licenses/>. - */ - -#ifndef __REALMSOCKET_H__ -#define __REALMSOCKET_H__ - -#include <ace/Synch_Traits.h> -#include <ace/Svc_Handler.h> -#include <ace/SOCK_Stream.h> -#include <ace/Message_Block.h> -#include <ace/Basic_Types.h> -#include "Common.h" - -class RealmSocket : public ACE_Svc_Handler<ACE_SOCK_STREAM, ACE_NULL_SYNCH> -{ -private: - typedef ACE_Svc_Handler<ACE_SOCK_STREAM, ACE_NULL_SYNCH> Base; - -public: - class Session - { - public: - Session(void); - virtual ~Session(void); - - virtual void OnRead(void) = 0; - virtual void OnAccept(void) = 0; - virtual void OnClose(void) = 0; - }; - - RealmSocket(void); - virtual ~RealmSocket(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& getRemoteAddress(void) const; - - uint16 getRemotePort(void) const; - - virtual int open(void *); - - virtual int close(u_long); - - virtual int handle_input(ACE_HANDLE = ACE_INVALID_HANDLE); - virtual int handle_output(ACE_HANDLE = ACE_INVALID_HANDLE); - - virtual int handle_close(ACE_HANDLE = ACE_INVALID_HANDLE, ACE_Reactor_Mask = ACE_Event_Handler::ALL_EVENTS_MASK); - - void set_session(Session* session); - -private: - ssize_t noblk_send(ACE_Message_Block &message_block); - - ACE_Message_Block input_buffer_; - Session* session_; - std::string _remoteAddress; - uint16 _remotePort; -}; - -#endif /* __REALMSOCKET_H__ */ diff --git a/src/server/authserver/authserver.conf.dist b/src/server/authserver/authserver.conf.dist index 83edf9669ac..b7dee9ac08b 100644 --- a/src/server/authserver/authserver.conf.dist +++ b/src/server/authserver/authserver.conf.dist @@ -148,6 +148,13 @@ LoginDatabaseInfo = "127.0.0.1;3306;trinity;trinity;auth" LoginDatabase.WorkerThreads = 1 # +# Wrong.Password.Login.Logging +# Description: Additionally log attempted wrong password logging +# Default: 0 - (Disabled) +# 1 - (Enabled) + +Wrong.Password.Login.Logging = 0 +# ################################################################################################### ################################################################################################### diff --git a/src/server/authserver/authserver.rc b/src/server/authserver/authserver.rc index acfed6323ae..6ceaa135b42 100644 --- a/src/server/authserver/authserver.rc +++ b/src/server/authserver/authserver.rc @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008-2013 TrinityCore <http://www.trinitycore.org/> + * Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/> * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/> * * This program is free software; you can redistribute it and/or modify it |
