aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/server/authserver/Authentication/AuthCodes.cpp8
-rw-r--r--src/server/authserver/Server/AuthSession.cpp18
-rw-r--r--src/server/game/Server/WorldSocket.cpp3
-rw-r--r--src/server/shared/Realm/ClientBuildInfo.cpp139
-rw-r--r--src/server/shared/Realm/ClientBuildInfo.h79
-rw-r--r--src/server/shared/Realm/RealmList.cpp43
-rw-r--r--src/server/shared/Realm/RealmList.h19
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;