diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/server/authserver/Authentication/AuthCodes.cpp | 8 | ||||
-rw-r--r-- | src/server/authserver/Server/AuthSession.cpp | 18 | ||||
-rw-r--r-- | src/server/game/Server/WorldSocket.cpp | 3 | ||||
-rw-r--r-- | src/server/shared/Realm/ClientBuildInfo.cpp | 139 | ||||
-rw-r--r-- | src/server/shared/Realm/ClientBuildInfo.h | 79 | ||||
-rw-r--r-- | src/server/shared/Realm/RealmList.cpp | 43 | ||||
-rw-r--r-- | src/server/shared/Realm/RealmList.h | 19 |
7 files changed, 233 insertions, 76 deletions
diff --git a/src/server/authserver/Authentication/AuthCodes.cpp b/src/server/authserver/Authentication/AuthCodes.cpp index 5af0f15482d..9f10e18f82c 100644 --- a/src/server/authserver/Authentication/AuthCodes.cpp +++ b/src/server/authserver/Authentication/AuthCodes.cpp @@ -16,7 +16,7 @@ */ #include "AuthCodes.h" -#include "RealmList.h" +#include "ClientBuildInfo.h" namespace AuthHelper { @@ -24,16 +24,16 @@ namespace AuthHelper bool IsPreBCAcceptedClientBuild(uint32 build) { - return build <= MAX_PRE_BC_CLIENT_BUILD && sRealmList->GetBuildInfo(build); + return build <= MAX_PRE_BC_CLIENT_BUILD && ClientBuild::GetBuildInfo(build); } bool IsPostBCAcceptedClientBuild(uint32 build) { - return build > MAX_PRE_BC_CLIENT_BUILD && sRealmList->GetBuildInfo(build); + return build > MAX_PRE_BC_CLIENT_BUILD && ClientBuild::GetBuildInfo(build); } bool IsAcceptedClientBuild(uint32 build) { - return sRealmList->GetBuildInfo(build) != nullptr; + return ClientBuild::GetBuildInfo(build) != nullptr; } } diff --git a/src/server/authserver/Server/AuthSession.cpp b/src/server/authserver/Server/AuthSession.cpp index ba2ef766ac7..81e8b6c48f6 100644 --- a/src/server/authserver/Server/AuthSession.cpp +++ b/src/server/authserver/Server/AuthSession.cpp @@ -19,6 +19,7 @@ #include "AES.h" #include "AuthCodes.h" #include "ByteBuffer.h" +#include "ClientBuildInfo.h" #include "Config.h" #include "CryptoGenerics.h" #include "CryptoHash.h" @@ -756,7 +757,7 @@ void AuthSession::RealmListCallback(PreparedQueryResult result) // No SQL injection. id of realm is controlled by the database. uint32 flag = realm.Flags; - RealmBuildInfo const* buildInfo = sRealmList->GetBuildInfo(realm.Build); + ClientBuild::Info const* buildInfo = ClientBuild::GetBuildInfo(realm.Build); if (!okBuild) { if (!buildInfo) @@ -841,20 +842,15 @@ bool AuthSession::VerifyVersion(uint8 const* a, int32 aLength, Trinity::Crypto:: Trinity::Crypto::SHA1::Digest const* versionHash = nullptr; if (!isReconnect) { - RealmBuildInfo const* buildInfo = sRealmList->GetBuildInfo(_build); + ClientBuild::Info const* buildInfo = ClientBuild::GetBuildInfo(_build); if (!buildInfo) return false; - if (_os == "Win") - versionHash = &buildInfo->WindowsHash; - else if (_os == "OSX") - versionHash = &buildInfo->MacHash; - - if (!versionHash) - return false; - - if (zeros == *versionHash) + auto platformItr = std::ranges::find(buildInfo->ExecutableHashes, ClientBuild::ToFourCC(_os), &ClientBuild::ExecutableHash::Platform); + if (platformItr == buildInfo->ExecutableHashes.end()) return true; // not filled serverside + + versionHash = &platformItr->Hash; } else versionHash = &zeros; diff --git a/src/server/game/Server/WorldSocket.cpp b/src/server/game/Server/WorldSocket.cpp index 02fa39e2a07..64307b823f3 100644 --- a/src/server/game/Server/WorldSocket.cpp +++ b/src/server/game/Server/WorldSocket.cpp @@ -17,6 +17,7 @@ #include "WorldSocket.h" #include "BigNumber.h" +#include "ClientBuildInfo.h" #include "DatabaseEnv.h" #include "GameTime.h" #include "CryptoHash.h" @@ -506,7 +507,7 @@ void WorldSocket::HandleAuthSessionCallback(std::shared_ptr<AuthSession> authSes // Must be done before WorldSession is created bool wardenActive = sWorld->getBoolConfig(CONFIG_WARDEN_ENABLED); - if (wardenActive && account.OS != "Win" && account.OS != "OSX") + if (wardenActive && !ClientBuild::Platform::IsValid(account.OS)) { SendAuthResponseError(AUTH_REJECT); TC_LOG_ERROR("network", "WorldSocket::HandleAuthSession: Client {} attempted to log in using invalid client OS ({}).", address, account.OS); diff --git a/src/server/shared/Realm/ClientBuildInfo.cpp b/src/server/shared/Realm/ClientBuildInfo.cpp new file mode 100644 index 00000000000..b2ccf07b99a --- /dev/null +++ b/src/server/shared/Realm/ClientBuildInfo.cpp @@ -0,0 +1,139 @@ +/* + * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information + * + * 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 "ClientBuildInfo.h" +#include "DatabaseEnv.h" +#include "Log.h" +#include "Util.h" +#include <algorithm> +#include <cctype> + +namespace +{ +std::vector<ClientBuild::Info> Builds; +} + +namespace ClientBuild +{ +std::array<char, 5> ToCharArray(uint32 value) +{ + auto normalize = [](uint8 c) -> char + { + if (!c || std::isprint(c)) + return char(c); + return ' '; + }; + + std::array<char, 5> chars = { char((value >> 24) & 0xFF), char((value >> 16) & 0xFF), char((value >> 8) & 0xFF), char(value & 0xFF), '\0' }; + + auto firstNonZero = std::ranges::find_if(chars, [](char c) { return c != '\0'; }); + if (firstNonZero != chars.end()) + { + // move leading zeros to end + std::rotate(chars.begin(), firstNonZero, chars.end()); + + // ensure we only have printable characters remaining + std::ranges::transform(chars, chars.begin(), normalize); + } + + return chars; +} + +bool Platform::IsValid(std::string_view platform) +{ + if (platform.length() > sizeof(uint32)) + return false; + + switch (ToFourCC(platform)) + { + case Win_x86: + case Mac_x86: + return true; + default: + break; + } + + return false; +} + +void LoadBuildInfo() +{ + Builds.clear(); + + // 0 1 2 3 4 + if (QueryResult result = LoginDatabase.Query("SELECT majorVersion, minorVersion, bugfixVersion, hotfixVersion, build FROM build_info ORDER BY build ASC")) + { + do + { + Field* fields = result->Fetch(); + Info& build = Builds.emplace_back(); + build.MajorVersion = fields[0].GetUInt32(); + build.MinorVersion = fields[1].GetUInt32(); + build.BugfixVersion = fields[2].GetUInt32(); + std::string hotfixVersion = fields[3].GetString(); + if (hotfixVersion.length() < build.HotfixVersion.size()) + std::ranges::copy(hotfixVersion, build.HotfixVersion.begin()); + else + build.HotfixVersion = { }; + + build.Build = fields[4].GetUInt32(); + + } while (result->NextRow()); + } + + // 0 1 2 + if (QueryResult result = LoginDatabase.Query("SELECT `build`, `platform`, `executableHash` FROM `build_executable_hash`")) + { + do + { + Field* fields = result->Fetch(); + + uint32 build = fields[0].GetInt32(); + auto buildInfo = std::ranges::find(Builds, build, &Info::Build); + if (buildInfo == Builds.end()) + { + TC_LOG_ERROR("sql.sql", "ClientBuild::LoadBuildInfo: Unknown `build` {} in `build_executable_hash` - missing from `build_info`, skipped.", build); + continue; + } + + std::string_view platform = fields[1].GetStringView(); + if (!Platform::IsValid(platform)) + { + TC_LOG_ERROR("sql.sql", "ClientBuild::LoadBuildInfo: Invalid platform {} for `build` {} in `build_executable_hash`, skipped.", platform, build); + continue; + } + + ExecutableHash& buildKey = buildInfo->ExecutableHashes.emplace_back(); + buildKey.Platform = ToFourCC(platform); + buildKey.Hash = fields[2].GetBinary<ExecutableHash::Size>(); + + } while (result->NextRow()); + } +} + +Info const* GetBuildInfo(uint32 build) +{ + auto buildInfo = std::ranges::find(Builds, build, &Info::Build); + return buildInfo != Builds.end() ? &*buildInfo : nullptr; +} + +uint32 GetMinorMajorBugfixVersionForBuild(uint32 build) +{ + auto buildInfo = std::ranges::lower_bound(Builds, build, {}, &Info::Build); + return buildInfo != Builds.end() ? (buildInfo->MajorVersion * 10000 + buildInfo->MinorVersion * 100 + buildInfo->BugfixVersion) : 0; +} +} diff --git a/src/server/shared/Realm/ClientBuildInfo.h b/src/server/shared/Realm/ClientBuildInfo.h new file mode 100644 index 00000000000..2889470b9c2 --- /dev/null +++ b/src/server/shared/Realm/ClientBuildInfo.h @@ -0,0 +1,79 @@ +/* + * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information + * + * 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 TRINITYCORE_CLIENT_BUILD_INFO_H +#define TRINITYCORE_CLIENT_BUILD_INFO_H + +#include "Define.h" +#include <array> +#include <string_view> +#include <vector> + +namespace ClientBuild +{ +inline constexpr uint32 ToFourCC(std::string_view text) +{ + uint32 uintValue = 0; + for (uint8 c : text) + { + uintValue <<= 8; + uintValue |= c; + } + return uintValue; +} + +consteval uint32 operator""_fourcc(char const* chars, std::size_t length) +{ + if (length > sizeof(uint32)) + throw "Text can only be max 4 characters long"; + + return ToFourCC({ chars, length }); +} + +TC_SHARED_API std::array<char, 5> ToCharArray(uint32 value); + +namespace Platform +{ + inline constexpr uint32 Win_x86 = "Win"_fourcc; + inline constexpr uint32 Mac_x86 = "OSX"_fourcc; + + TC_SHARED_API bool IsValid(std::string_view platform); +} + +struct ExecutableHash +{ + static constexpr std::size_t Size = 20; + + uint32 Platform; + std::array<uint8, Size> Hash; +}; + +struct Info +{ + uint32 Build; + uint32 MajorVersion; + uint32 MinorVersion; + uint32 BugfixVersion; + std::array<char, 4> HotfixVersion; + std::vector<ExecutableHash> ExecutableHashes; +}; + +TC_SHARED_API void LoadBuildInfo(); +TC_SHARED_API Info const* GetBuildInfo(uint32 build); +} + +#endif // TRINITYCORE_CLIENT_BUILD_INFO_H diff --git a/src/server/shared/Realm/RealmList.cpp b/src/server/shared/Realm/RealmList.cpp index 4e353fa7711..f68623c5a5d 100644 --- a/src/server/shared/Realm/RealmList.cpp +++ b/src/server/shared/Realm/RealmList.cpp @@ -16,6 +16,7 @@ */ #include "RealmList.h" +#include "ClientBuildInfo.h" #include "DatabaseEnv.h" #include "DeadlineTimer.h" #include "IoContext.h" @@ -43,7 +44,7 @@ void RealmList::Initialize(Trinity::Asio::IoContext& ioContext, uint32 updateInt _updateTimer = std::make_unique<Trinity::Asio::DeadlineTimer>(ioContext); _resolver = std::make_unique<Trinity::Asio::Resolver>(ioContext); - LoadBuildInfo(); + ClientBuild::LoadBuildInfo(); // Get the content of the realmlist table in the database UpdateRealms(boost::system::error_code()); } @@ -53,37 +54,6 @@ void RealmList::Close() _updateTimer->cancel(); } -void RealmList::LoadBuildInfo() -{ - // 0 1 2 3 4 5 6 - if (QueryResult result = LoginDatabase.Query("SELECT majorVersion, minorVersion, bugfixVersion, hotfixVersion, build, winChecksumSeed, macChecksumSeed FROM build_info ORDER BY build ASC")) - { - do - { - Field* fields = result->Fetch(); - RealmBuildInfo& build = _builds.emplace_back(); - build.MajorVersion = fields[0].GetUInt32(); - build.MinorVersion = fields[1].GetUInt32(); - build.BugfixVersion = fields[2].GetUInt32(); - std::string hotfixVersion = fields[3].GetString(); - if (hotfixVersion.length() < build.HotfixVersion.size()) - std::copy(hotfixVersion.begin(), hotfixVersion.end(), build.HotfixVersion.begin()); - else - std::fill(hotfixVersion.begin(), hotfixVersion.end(), '\0'); - - build.Build = fields[4].GetUInt32(); - std::string windowsHash = fields[5].GetString(); - if (windowsHash.length() == build.WindowsHash.size() * 2) - HexStrToByteArray(windowsHash, build.WindowsHash); - - std::string macHash = fields[6].GetString(); - if (macHash.length() == build.MacHash.size() * 2) - HexStrToByteArray(macHash, build.MacHash); - - } while (result->NextRow()); - } -} - void RealmList::UpdateRealm(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) @@ -210,12 +180,3 @@ Realm const* RealmList::GetRealm(RealmHandle const& id) const return nullptr; } - -RealmBuildInfo const* RealmList::GetBuildInfo(uint32 build) const -{ - for (RealmBuildInfo const& clientBuild : _builds) - if (clientBuild.Build == build) - return &clientBuild; - - return nullptr; -} diff --git a/src/server/shared/Realm/RealmList.h b/src/server/shared/Realm/RealmList.h index 056472533e2..45f0a9b6ffe 100644 --- a/src/server/shared/Realm/RealmList.h +++ b/src/server/shared/Realm/RealmList.h @@ -19,23 +19,8 @@ #define _REALMLIST_H #include "Define.h" -#include "Duration.h" #include "Realm.h" -#include <array> #include <map> -#include <vector> -#include <unordered_set> - -struct RealmBuildInfo -{ - uint32 Build; - uint32 MajorVersion; - uint32 MinorVersion; - uint32 BugfixVersion; - std::array<char, 4> HotfixVersion; - std::array<uint8, 20> WindowsHash; - std::array<uint8, 20> MacHash; -}; namespace boost { @@ -61,18 +46,14 @@ public: RealmMap const& GetRealms() const { return _realms; } Realm const* GetRealm(RealmHandle const& id) const; - RealmBuildInfo const* GetBuildInfo(uint32 build) const; - private: RealmList(); - void LoadBuildInfo(); void UpdateRealms(boost::system::error_code const& error); void UpdateRealm(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); - std::vector<RealmBuildInfo> _builds; RealmMap _realms; uint32 _updateInterval; std::unique_ptr<Trinity::Asio::DeadlineTimer> _updateTimer; |