From 37d48ec37151bb0ee498e82e42549b4da6611ecc Mon Sep 17 00:00:00 2001 From: Hondacrx Date: Wed, 9 Oct 2024 14:28:10 -0400 Subject: [PATCH] Core/Auth: Refactor client auth key storage to support more future client variants and preserve more information about client version Port From (https://github.com/TrinityCore/TrinityCore/commit/8e1595265925e0840d07e943b8c9ff1e906d4719) --- .../Networking/Services/Authentication.cs | 3 +- .../Networking/Services/GameUtilities.cs | 4 +- Source/BNetServer/Networking/Session.cs | 1 + Source/Framework/Database/QueryCallback.cs | 5 ++ Source/Framework/Realm/ClientBuildHelper.cs | 79 +++++++++++++++++++ Source/Framework/Realm/RealmId.cs | 2 +- Source/Framework/Realm/RealmManager.cs | 67 +++++++++------- Source/Framework/Util/Extensions.cs | 15 ++++ .../Rest/Realmlist/RealmCharacterCountList.cs | 2 +- .../Web/Rest/Realmlist/RealmJoinTicket.cs | 22 ++++++ .../Web/Rest/Realmlist/RealmListRAFInfo.cs | 3 +- .../Realmlist/RealmListServerIPAddresses.cs | 2 +- Source/Game/DataStorage/Structs/T_Records.cs | 2 +- Source/Game/Networking/WorldSocket.cs | 60 ++++++++------ Source/Game/Server/WorldSession.cs | 5 +- Source/Game/Services/GameUtilitiesService.cs | 4 +- 16 files changed, 213 insertions(+), 63 deletions(-) create mode 100644 Source/Framework/Realm/ClientBuildHelper.cs create mode 100644 Source/Framework/Web/Rest/Realmlist/RealmJoinTicket.cs diff --git a/Source/BNetServer/Networking/Services/Authentication.cs b/Source/BNetServer/Networking/Services/Authentication.cs index 9cb8f49f7..a42bb0b3d 100644 --- a/Source/BNetServer/Networking/Services/Authentication.cs +++ b/Source/BNetServer/Networking/Services/Authentication.cs @@ -5,6 +5,7 @@ using Bgs.Protocol; using Bgs.Protocol.Authentication.V1; using Bgs.Protocol.Challenge.V1; using Framework; +using Framework.ClientBuild; using Framework.Constants; using Framework.Database; using Framework.Realm; @@ -25,7 +26,7 @@ namespace BNetServer.Networking return BattlenetRpcErrorCode.BadProgram; } - if (logonRequest.Platform != "Win" && logonRequest.Platform != "Wn64" && logonRequest.Platform != "Mc64" && logonRequest.Platform != "MacA") + if (!ClientBuildHelper.IsValid(logonRequest.Platform)) { Log.outDebug(LogFilter.Session, $"Battlenet.LogonRequest: {GetClientInfo()} attempted to log in from an unsupported platform (using {logonRequest.Platform})!"); return BattlenetRpcErrorCode.BadPlatform; diff --git a/Source/BNetServer/Networking/Services/GameUtilities.cs b/Source/BNetServer/Networking/Services/GameUtilities.cs index 7244de0a0..893f36a44 100644 --- a/Source/BNetServer/Networking/Services/GameUtilities.cs +++ b/Source/BNetServer/Networking/Services/GameUtilities.cs @@ -115,6 +115,8 @@ namespace BNetServer.Networking int i = 0; foreach (byte b in realmListTicketClientInformation.Info.Secret) clientSecret[i++] = b; + + _clientInfo = new() { Platform = realmListTicketClientInformation.Info.PlatformType, Arch = realmListTicketClientInformation.Info.ClientArch, Type = realmListTicketClientInformation.Info.Type }; } } @@ -227,7 +229,7 @@ namespace BNetServer.Networking { Variant realmAddress = Params.LookupByKey("Param_RealmAddress"); if (realmAddress != null) - return Global.RealmMgr.JoinRealm((uint)realmAddress.UintValue, build, GetRemoteIpAddress(), clientSecret, (Locale)Enum.Parse(typeof(Locale), locale), os, _timezoneOffset, gameAccountInfo.Name, gameAccountInfo.SecurityLevel, response); + return Global.RealmMgr.JoinRealm((uint)realmAddress.UintValue, build, _clientInfo, GetRemoteIpAddress(), clientSecret, (Locale)Enum.Parse(typeof(Locale), locale), os, _timezoneOffset, gameAccountInfo.Name, gameAccountInfo.SecurityLevel, response); return BattlenetRpcErrorCode.WowServicesInvalidJoinTicket; } diff --git a/Source/BNetServer/Networking/Session.cs b/Source/BNetServer/Networking/Session.cs index 35dc4a76a..2e350f4bf 100644 --- a/Source/BNetServer/Networking/Session.cs +++ b/Source/BNetServer/Networking/Session.cs @@ -24,6 +24,7 @@ namespace BNetServer.Networking string locale; string os; uint build; + Framework.ClientBuild.ClientBuildVariantId _clientInfo; TimeSpan _timezoneOffset; string ipCountry; diff --git a/Source/Framework/Database/QueryCallback.cs b/Source/Framework/Database/QueryCallback.cs index ce796b17d..2c66430c8 100644 --- a/Source/Framework/Database/QueryCallback.cs +++ b/Source/Framework/Database/QueryCallback.cs @@ -24,6 +24,11 @@ namespace Framework.Database return WithChainingCallback((queryCallback, result) => callback(obj, result)); } + public QueryCallback WithCallback(Action callback, T obj, U obj2) + { + return WithChainingCallback((queryCallback, result) => callback(obj, obj2, result)); + } + public QueryCallback WithChainingCallback(Action callback) { _callbacks.Enqueue(new QueryCallbackData(callback)); diff --git a/Source/Framework/Realm/ClientBuildHelper.cs b/Source/Framework/Realm/ClientBuildHelper.cs new file mode 100644 index 000000000..ded5b0a9b --- /dev/null +++ b/Source/Framework/Realm/ClientBuildHelper.cs @@ -0,0 +1,79 @@ +// Copyright (c) CypherCore All rights reserved. +// Licensed under the GNU GENERAL PUBLIC LICENSE. See LICENSE file in the project root for full license information. + +using System; +using System.Collections.Generic; + +namespace Framework.ClientBuild +{ + struct ClientBuildPlatformType + { + public static int Windows = "Win".fourcc(); + public static int macOS = "Mac".fourcc(); + } + + struct ClientBuildArch + { + public static int x86 = "x86".fourcc(); + public static int x64 = "x64".fourcc(); + public static int Arm32 = "A32".fourcc(); + public static int Arm64 = "A64".fourcc(); + public static int WA32 = "WA32".fourcc(); + } + + struct ClientBuildType + { + public static int Retail = "WoW".fourcc(); + public static int RetailChina = "WoWC".fourcc(); + public static int Beta = "WoWB".fourcc(); + public static int BetaRelease = "WoWE".fourcc(); + public static int Ptr = "WoWT".fourcc(); + public static int PtrRelease = "WoWR".fourcc(); + } + + public class ClientBuildHelper + { + public static bool IsValid(string platform) + { + switch (platform) + { + case "Win": + case "Wn64": + case "WinA": + case "Mac": + case "Mc64": + case "MacA": + return true; + default: + break; + } + + return false; + } + } + + public class ClientBuildVariantId + { + public int Platform; + public int Arch; + public int Type; + } + + public class ClientBuildAuthKey + { + public static int Size = 16; + + public ClientBuildVariantId Variant; + public byte[] Key = new byte[Size]; + } + + public class ClientBuildInfo + { + public uint Build; + public uint MajorVersion; + public uint MinorVersion; + public uint BugfixVersion; + public char[] HotfixVersion = new char[4]; + public List AuthKeys = new(); + } +} diff --git a/Source/Framework/Realm/RealmId.cs b/Source/Framework/Realm/RealmId.cs index 1ef0678ad..6b947834a 100644 --- a/Source/Framework/Realm/RealmId.cs +++ b/Source/Framework/Realm/RealmId.cs @@ -6,7 +6,7 @@ using System; namespace Framework.Realm { public struct RealmId : IEquatable - { + { public uint Index { get; set; } public byte Region { get; set; } public byte Site { get; set; } diff --git a/Source/Framework/Realm/RealmManager.cs b/Source/Framework/Realm/RealmManager.cs index b63ddba60..fa8693a3f 100644 --- a/Source/Framework/Realm/RealmManager.cs +++ b/Source/Framework/Realm/RealmManager.cs @@ -1,6 +1,7 @@ // Copyright (c) CypherCore All rights reserved. // Licensed under the GNU GENERAL PUBLIC LICENSE. See LICENSE file in the project root for full license information. +using Framework.ClientBuild; using Framework.Constants; using Framework.Database; using Framework.IO; @@ -36,13 +37,15 @@ public class RealmManager : Singleton void LoadBuildInfo() { + _builds.Clear(); + // 0 1 2 3 4 5 6 7 SQLResult result = DB.Login.Query("SELECT majorVersion, minorVersion, bugfixVersion, hotfixVersion, build, win64AuthSeed, mac64AuthSeed, macArmAuthSeed FROM build_info ORDER BY build ASC"); if (!result.IsEmpty()) { do { - RealmBuildInfo build = new(); + ClientBuildInfo build = new(); build.MajorVersion = result.Read(0); build.MinorVersion = result.Read(1); build.BugfixVersion = result.Read(2); @@ -51,17 +54,33 @@ public class RealmManager : Singleton build.HotfixVersion = hotfixVersion.ToCharArray(); build.Build = result.Read(4); + string win64AuthSeedHexStr = result.Read(5); - if (!win64AuthSeedHexStr.IsEmpty() && win64AuthSeedHexStr.Length == build.Win64AuthSeed.Length * 2) - build.Win64AuthSeed = win64AuthSeedHexStr.ToByteArray(); + if (win64AuthSeedHexStr.Length == ClientBuildAuthKey.Size * 2) + { + ClientBuildAuthKey buildKey = new(); + buildKey.Variant = new() { Platform = ClientBuildPlatformType.Windows, Arch = ClientBuildArch.x64, Type = ClientBuildType.Retail }; + buildKey.Key = win64AuthSeedHexStr.ToByteArray(); + build.AuthKeys.Add(buildKey); + } string mac64AuthSeedHexStr = result.Read(6); - if (!mac64AuthSeedHexStr.IsEmpty() && mac64AuthSeedHexStr.Length == build.Mac64AuthSeed.Length * 2) - build.Mac64AuthSeed = mac64AuthSeedHexStr.ToByteArray(); + if (mac64AuthSeedHexStr.Length == ClientBuildAuthKey.Size * 2) + { + ClientBuildAuthKey buildKey = new(); + buildKey.Variant = new() { Platform = ClientBuildPlatformType.macOS, Arch = ClientBuildArch.x64, Type = ClientBuildType.Retail }; + buildKey.Key = mac64AuthSeedHexStr.ToByteArray(); + build.AuthKeys.Add(buildKey); + } string macArmAuthSeedHexStr = result.Read(7); - if (macArmAuthSeedHexStr.IsEmpty() && mac64AuthSeedHexStr.Length == build.MacArmAuthSeed.Length * 2) - build.MacArmAuthSeed = macArmAuthSeedHexStr.ToByteArray(); + if (macArmAuthSeedHexStr.Length == ClientBuildAuthKey.Size * 2) + { + ClientBuildAuthKey buildKey = new(); + buildKey.Variant = new() { Platform = ClientBuildPlatformType.macOS, Arch = ClientBuildArch.Arm64, Type = ClientBuildType.Retail }; + buildKey.Key = macArmAuthSeedHexStr.ToByteArray(); + build.AuthKeys.Add(buildKey); + } _builds.Add(build); @@ -199,7 +218,7 @@ public class RealmManager : Singleton } } - public RealmBuildInfo GetBuildInfo(uint build) + public ClientBuildInfo GetBuildInfo(uint build) { foreach (var clientBuild in _builds) if (clientBuild.Build == build) @@ -210,7 +229,7 @@ public class RealmManager : Singleton public uint GetMinorMajorBugfixVersionForBuild(uint build) { - RealmBuildInfo buildInfo = _builds.FirstOrDefault(p => p.Build < build); + ClientBuildInfo buildInfo = _builds.FirstOrDefault(p => p.Build < build); return buildInfo != null ? (buildInfo.MajorVersion * 10000 + buildInfo.MinorVersion * 100 + buildInfo.BugfixVersion) : 0; } @@ -226,7 +245,7 @@ public class RealmManager : Singleton realmEntry.CfgCategoriesID = realm.Timezone; ClientVersion version = new(); - RealmBuildInfo buildInfo = GetBuildInfo(realm.Build); + ClientBuildInfo buildInfo = GetBuildInfo(realm.Build); if (buildInfo != null) { version.Major = (int)buildInfo.MajorVersion; @@ -302,7 +321,7 @@ public class RealmManager : Singleton return BitConverter.GetBytes(jsonData.Length).Combine(ZLib.Compress(jsonData)); } - public BattlenetRpcErrorCode JoinRealm(uint realmAddress, uint build, IPAddress clientAddress, byte[] clientSecret, Locale locale, string os, TimeSpan timezoneOffset, string accountName, AccountTypes accountSecurityLevel, Bgs.Protocol.GameUtilities.V1.ClientResponse response) + public BattlenetRpcErrorCode JoinRealm(uint realmAddress, uint build, ClientBuildVariantId buildVariant, IPAddress clientAddress, byte[] clientSecret, Locale locale, string os, TimeSpan timezoneOffset, string accountName, AccountTypes accountSecurityLevel, Bgs.Protocol.GameUtilities.V1.ClientResponse response) { Realm realm = GetRealm(new RealmId(realmAddress)); if (realm != null) @@ -336,10 +355,16 @@ public class RealmManager : Singleton stmt.AddValue(6, accountName); DB.Login.DirectExecute(stmt); + RealmJoinTicket joinTicket = new(); + joinTicket.GameAccount = accountName; + joinTicket.Platform = buildVariant.Platform; + joinTicket.ClientArch = buildVariant.Arch; + joinTicket.Type = buildVariant.Type; + Bgs.Protocol.Attribute attribute = new(); attribute.Name = "Param_RealmJoinTicket"; attribute.Value = new Bgs.Protocol.Variant(); - attribute.Value.BlobValue = Google.Protobuf.ByteString.CopyFrom(accountName, Encoding.UTF8); + attribute.Value.BlobValue = Google.Protobuf.ByteString.CopyFromUtf8(JsonSerializer.Serialize(joinTicket)); response.Attribute.Add(attribute); attribute = new Bgs.Protocol.Attribute(); @@ -369,7 +394,7 @@ public class RealmManager : Singleton RealmPopulationState ConvertLegacyPopulationState(LegacyRealmFlags legacyRealmFlags, float population) { - if (legacyRealmFlags .HasAnyFlag(LegacyRealmFlags.Offline)) + if (legacyRealmFlags.HasAnyFlag(LegacyRealmFlags.Offline)) return RealmPopulationState.Offline; if (legacyRealmFlags.HasAnyFlag(LegacyRealmFlags.Recommended)) return RealmPopulationState.Recommended; @@ -387,22 +412,10 @@ public class RealmManager : Singleton public ICollection GetRealms() { return _realms.Values; } List GetSubRegions() { return _subRegions; } - List _builds = new(); + List _builds = new(); ConcurrentDictionary _realms = new(); Dictionary _removedRealms = new(); List _subRegions = new(); Timer _updateTimer; RealmId? _currentRealmId; -} - -public class RealmBuildInfo -{ - public uint Build; - public uint MajorVersion; - public uint MinorVersion; - public uint BugfixVersion; - public char[] HotfixVersion = new char[4]; - public byte[] Win64AuthSeed = new byte[16]; - public byte[] Mac64AuthSeed = new byte[16]; - public byte[] MacArmAuthSeed = new byte[16]; -} +} \ No newline at end of file diff --git a/Source/Framework/Util/Extensions.cs b/Source/Framework/Util/Extensions.cs index 5441a22ba..9a922dd1a 100644 --- a/Source/Framework/Util/Extensions.cs +++ b/Source/Framework/Util/Extensions.cs @@ -438,6 +438,21 @@ namespace System } return hash; } + + public static int fourcc(this string str) + { + //if (length > sizeof(uint)) + // throw "Text can only be max 4 characters long"; + + int intValue = 0; + foreach (char c in str.ToCharArray()) + { + intValue <<= 8; + intValue |= c; + } + + return intValue; + } #endregion #region BinaryReader diff --git a/Source/Framework/Web/Rest/Realmlist/RealmCharacterCountList.cs b/Source/Framework/Web/Rest/Realmlist/RealmCharacterCountList.cs index 16bdf2e14..a23bc1c86 100644 --- a/Source/Framework/Web/Rest/Realmlist/RealmCharacterCountList.cs +++ b/Source/Framework/Web/Rest/Realmlist/RealmCharacterCountList.cs @@ -1,9 +1,9 @@ // Copyright (c) CypherCore All rights reserved. // Licensed under the GNU GENERAL PUBLIC LICENSE. See LICENSE file in the project root for full license information. +using Framework.Web.Rest.Realmlist; using System.Collections.Generic; using System.Text.Json.Serialization; -using Framework.Web.Rest.Realmlist; namespace Framework.Web { diff --git a/Source/Framework/Web/Rest/Realmlist/RealmJoinTicket.cs b/Source/Framework/Web/Rest/Realmlist/RealmJoinTicket.cs new file mode 100644 index 000000000..e27c8d96d --- /dev/null +++ b/Source/Framework/Web/Rest/Realmlist/RealmJoinTicket.cs @@ -0,0 +1,22 @@ +// Copyright (c) CypherCore All rights reserved. +// Licensed under the GNU GENERAL PUBLIC LICENSE. See LICENSE file in the project root for full license information. + +using System.Text.Json.Serialization; + +namespace Framework.Web +{ + public class RealmJoinTicket + { + [JsonPropertyName("gameAccount")] + public string GameAccount { get; set; } + + [JsonPropertyName("platform")] + public int Platform { get; set; } + + [JsonPropertyName("type")] + public int Type { get; set; } + + [JsonPropertyName("clientArch")] + public int ClientArch { get; set; } + } +} diff --git a/Source/Framework/Web/Rest/Realmlist/RealmListRAFInfo.cs b/Source/Framework/Web/Rest/Realmlist/RealmListRAFInfo.cs index 3c254f5ec..845f64f41 100644 --- a/Source/Framework/Web/Rest/Realmlist/RealmListRAFInfo.cs +++ b/Source/Framework/Web/Rest/Realmlist/RealmListRAFInfo.cs @@ -2,9 +2,8 @@ // Licensed under the GNU GENERAL PUBLIC LICENSE. See LICENSE file in the project root for full license information. using System.Text.Json.Serialization; -using Framework.Web.Rest.Realmlist; -namespace Framework.Web.Rest.Realmlist +namespace Framework.Web { internal class RealmListRAFInfo { diff --git a/Source/Framework/Web/Rest/Realmlist/RealmListServerIPAddresses.cs b/Source/Framework/Web/Rest/Realmlist/RealmListServerIPAddresses.cs index d13d01dca..41b0c6c1d 100644 --- a/Source/Framework/Web/Rest/Realmlist/RealmListServerIPAddresses.cs +++ b/Source/Framework/Web/Rest/Realmlist/RealmListServerIPAddresses.cs @@ -1,9 +1,9 @@ // Copyright (c) CypherCore All rights reserved. // Licensed under the GNU GENERAL PUBLIC LICENSE. See LICENSE file in the project root for full license information. +using Framework.Web.Rest.Realmlist; using System.Collections.Generic; using System.Text.Json.Serialization; -using Framework.Web.Rest.Realmlist; namespace Framework.Web { diff --git a/Source/Game/DataStorage/Structs/T_Records.cs b/Source/Game/DataStorage/Structs/T_Records.cs index 789746b0a..4af9d2158 100644 --- a/Source/Game/DataStorage/Structs/T_Records.cs +++ b/Source/Game/DataStorage/Structs/T_Records.cs @@ -2,8 +2,8 @@ // Licensed under the GNU GENERAL PUBLIC LICENSE. See LICENSE file in the project root for full license information. using Framework.Constants; -using System.Numerics; using System; +using System.Numerics; namespace Game.DataStorage { diff --git a/Source/Game/Networking/WorldSocket.cs b/Source/Game/Networking/WorldSocket.cs index ada02766b..a31d353cb 100644 --- a/Source/Game/Networking/WorldSocket.cs +++ b/Source/Game/Networking/WorldSocket.cs @@ -1,14 +1,17 @@ // Copyright (c) CypherCore All rights reserved. // Licensed under the GNU GENERAL PUBLIC LICENSE. See LICENSE file in the project root for full license information. +using Framework.ClientBuild; using Framework.Constants; using Framework.Cryptography; using Framework.Database; using Framework.IO; using Framework.Networking; +using Framework.Web; using Game.Networking.Packets; using System; using System.Net.Sockets; +using System.Text.Json; using System.Threading.Tasks; namespace Game.Networking @@ -451,15 +454,23 @@ namespace Game.Networking void HandleAuthSession(AuthSession authSession) { + RealmJoinTicket joinTicket = JsonSerializer.Deserialize(authSession.RealmJoinTicket); + if (joinTicket == null) + { + SendAuthResponseError(BattlenetRpcErrorCode.WowServicesInvalidJoinTicket); + CloseSocket(); + return; + } + // Get the account information from the realmd database PreparedStatement stmt = LoginDatabase.GetPreparedStatement(LoginStatements.SEL_ACCOUNT_INFO_BY_NAME); stmt.AddValue(0, Global.RealmMgr.GetCurrentRealmId().Index); - stmt.AddValue(1, authSession.RealmJoinTicket); + stmt.AddValue(1, joinTicket.GameAccount); - _queryProcessor.AddCallback(DB.Login.AsyncQuery(stmt).WithCallback(HandleAuthSessionCallback, authSession)); + _queryProcessor.AddCallback(DB.Login.AsyncQuery(stmt).WithCallback(HandleAuthSessionCallback, authSession, joinTicket)); } - async void HandleAuthSessionCallback(AuthSession authSession, SQLResult result) + async void HandleAuthSessionCallback(AuthSession authSession, RealmJoinTicket joinTicket, SQLResult result) { // Stop if the account is not found if (result.IsEmpty()) @@ -471,11 +482,21 @@ namespace Game.Networking AccountInfo account = new(result.GetFields()); - RealmBuildInfo buildInfo = Global.RealmMgr.GetBuildInfo(account.game.Build); + ClientBuildInfo buildInfo = Global.RealmMgr.GetBuildInfo(account.game.Build); if (buildInfo == null) { SendAuthResponseError(BattlenetRpcErrorCode.BadVersion); - Log.outError(LogFilter.Network, $"WorldSocket.HandleAuthSessionCallback: Missing auth seed for realm build {account.game.Build} ({GetRemoteIpAddress()})."); + Log.outError(LogFilter.Network, $"WorldSocket.HandleAuthSessionCallback: Missing client build info for realm build {account.game.Build} ({GetRemoteIpAddress()})."); + CloseSocket(); + return; + } + + ClientBuildVariantId buildVariant = new() { Platform = joinTicket.Platform, Arch = joinTicket.ClientArch, Type = joinTicket.Type }; + var clientBuildAuthKey = buildInfo.AuthKeys.Find(p => p.Variant == buildVariant); + if (clientBuildAuthKey == null) + { + SendAuthResponseError(BattlenetRpcErrorCode.BadVersion); + Log.outError(LogFilter.Network, $"WorldSocket::HandleAuthSession: Missing client build auth key for build {account.game.Build} variant {buildVariant.Platform}-{buildVariant.Arch}-{buildVariant.Type} ({GetRemoteIpAddress()})."); CloseSocket(); return; } @@ -485,18 +506,7 @@ namespace Game.Networking Sha256 digestKeyHash = new(); digestKeyHash.Process(account.game.KeyData, account.game.KeyData.Length); - if (account.game.OS == "Wn64") - digestKeyHash.Finish(buildInfo.Win64AuthSeed); - else if (account.game.OS == "Mc64") - digestKeyHash.Finish(buildInfo.Mac64AuthSeed); - else if (account.game.OS == "MacA") - digestKeyHash.Finish(buildInfo.MacArmAuthSeed); - else - { - Log.outError(LogFilter.Network, "WorldSocket.HandleAuthSession: Authentication failed for account: {0} ('{1}') address: {2}", account.game.Id, authSession.RealmJoinTicket, address); - CloseSocket(); - return; - } + digestKeyHash.Finish(clientBuildAuthKey.Key); HmacSha256 hmac = new(digestKeyHash.Digest); hmac.Process(authSession.LocalChallenge, authSession.LocalChallenge.Count); @@ -507,7 +517,7 @@ namespace Game.Networking if (!hmac.Digest.Compare(authSession.Digest)) { SendAuthResponseError(BattlenetRpcErrorCode.Denied); - Log.outError(LogFilter.Network, "WorldSocket.HandleAuthSession: Authentication failed for account: {0} ('{1}') address: {2}", account.game.Id, authSession.RealmJoinTicket, address); + Log.outError(LogFilter.Network, $"WorldSocket.HandleAuthSession: Authentication failed for account: {account.game.Id} ('{joinTicket.GameAccount}') address: {address}"); CloseSocket(); return; } @@ -539,7 +549,7 @@ namespace Game.Networking // As we don't know if attempted login process by ip works, we update last_attempt_ip right away stmt = LoginDatabase.GetPreparedStatement(LoginStatements.UPD_LAST_ATTEMPT_IP); stmt.AddValue(0, address.ToString()); - stmt.AddValue(1, authSession.RealmJoinTicket); + stmt.AddValue(1, joinTicket.GameAccount); DB.Login.Execute(stmt); // This also allows to check for possible "hack" attempts on account } @@ -569,10 +579,10 @@ namespace Game.Networking // Must be done before WorldSession is created bool wardenActive = WorldConfig.GetBoolValue(WorldCfg.WardenEnabled); - if (wardenActive && account.game.OS != "Win" && account.game.OS != "Wn64" && account.game.OS != "Mc64" && account.game.OS != "MacA") + if (wardenActive && !ClientBuildHelper.IsValid(account.game.OS)) { SendAuthResponseError(BattlenetRpcErrorCode.Denied); - Log.outError(LogFilter.Network, "WorldSocket.HandleAuthSession: Client {0} attempted to log in using invalid client OS ({1}).", address, account.game.OS); + Log.outError(LogFilter.Network, $"WorldSocket.HandleAuthSession: Client {address} attempted to log in using invalid client OS ({account.game.OS})."); CloseSocket(); return; } @@ -635,22 +645,22 @@ namespace Game.Networking return; } - Log.outDebug(LogFilter.Network, "WorldSocket:HandleAuthSession: Client '{0}' authenticated successfully from {1}.", authSession.RealmJoinTicket, address); + Log.outDebug(LogFilter.Network, $"WorldSocket:HandleAuthSession: Client '{joinTicket.GameAccount}' authenticated successfully from {address}."); if (WorldConfig.GetBoolValue(WorldCfg.AllowLogginIpAddressesInDatabase)) { // Update the last_ip in the database stmt = LoginDatabase.GetPreparedStatement(LoginStatements.UPD_LAST_IP); stmt.AddValue(0, address.ToString()); - stmt.AddValue(1, authSession.RealmJoinTicket); + stmt.AddValue(1, joinTicket.GameAccount); DB.Login.Execute(stmt); } // At this point, we can safely hook a successful login Global.ScriptMgr.OnAccountLogin(account.game.Id); - _worldSession = new WorldSession(account.game.Id, authSession.RealmJoinTicket, account.battleNet.Id, this, account.game.Security, (Expansion)account.game.Expansion, - mutetime, account.game.OS, account.game.TimezoneOffset, account.game.Build, account.game.Locale, account.game.Recruiter, account.game.IsRectuiter); + _worldSession = new WorldSession(account.game.Id, joinTicket.GameAccount, account.battleNet.Id, this, account.game.Security, (Expansion)account.game.Expansion, + mutetime, account.game.OS, account.game.TimezoneOffset, account.game.Build, buildVariant, account.game.Locale, account.game.Recruiter, account.game.IsRectuiter); // Initialize Warden system only if it is enabled by config //if (wardenActive) diff --git a/Source/Game/Server/WorldSession.cs b/Source/Game/Server/WorldSession.cs index 0f5243ea5..8659fdc52 100644 --- a/Source/Game/Server/WorldSession.cs +++ b/Source/Game/Server/WorldSession.cs @@ -25,7 +25,7 @@ namespace Game { public partial class WorldSession : IDisposable { - public WorldSession(uint id, string name, uint battlenetAccountId, WorldSocket sock, AccountTypes sec, Expansion expansion, long mute_time, string os, TimeSpan timezoneOffset, uint build, Locale locale, uint recruiter, bool isARecruiter) + public WorldSession(uint id, string name, uint battlenetAccountId, WorldSocket sock, AccountTypes sec, Expansion expansion, long mute_time, string os, TimeSpan timezoneOffset, uint build, Framework.ClientBuild.ClientBuildVariantId clientBuildVariant, Locale locale, uint recruiter, bool isARecruiter) { m_muteTime = mute_time; AntiDOS = new DosProtection(this); @@ -38,6 +38,7 @@ namespace Game m_expansion = (Expansion)Math.Min((byte)expansion, WorldConfig.GetIntValue(WorldCfg.Expansion)); _os = os; _clientBuild = build; + _clientBuildVariant = clientBuildVariant; m_sessionDbcLocale = Global.WorldMgr.GetAvailableDbcLocale(locale); m_sessionDbLocaleIndex = locale; _timezoneOffset = timezoneOffset; @@ -686,6 +687,7 @@ namespace Game public Expansion GetExpansion() { return m_expansion; } public string GetOS() { return _os; } public uint GetClientBuild() { return _clientBuild; } + public Framework.ClientBuild.ClientBuildVariantId GetClientBuildVariant() { return _clientBuildVariant; } public void SetInQueue(bool state) { m_inQueue = state; } public bool IsLogingOut() { return _logoutTime != 0 || m_playerLogout; } @@ -953,6 +955,7 @@ namespace Game Expansion m_expansion; string _os; uint _clientBuild; + Framework.ClientBuild.ClientBuildVariantId _clientBuildVariant; uint expireTime; bool forceExit; diff --git a/Source/Game/Services/GameUtilitiesService.cs b/Source/Game/Services/GameUtilitiesService.cs index 49b023f45..9dc0b63da 100644 --- a/Source/Game/Services/GameUtilitiesService.cs +++ b/Source/Game/Services/GameUtilitiesService.cs @@ -112,8 +112,8 @@ namespace Game { var realmAddress = Params.LookupByKey("Param_RealmAddress"); if (realmAddress != null) - return Global.RealmMgr.JoinRealm((uint)realmAddress.UintValue, GetClientBuild(), System.Net.IPAddress.Parse(GetRemoteAddress()), GetRealmListSecret(), - GetSessionDbcLocale(), GetOS(), GetTimezoneOffset(), GetAccountName(), GetSecurity(), response); + return Global.RealmMgr.JoinRealm((uint)realmAddress.UintValue, GetClientBuild(), GetClientBuildVariant(), + System.Net.IPAddress.Parse(GetRemoteAddress()), GetRealmListSecret(), GetSessionDbcLocale(), GetOS(), GetTimezoneOffset(), GetAccountName(), GetSecurity(), response); return BattlenetRpcErrorCode.Ok; }