36#include <boost/endian/arithmetic.hpp>
37#include <boost/lexical_cast.hpp>
39using boost::asio::ip::tcp;
40using boost::endian::little_uint16_t;
41using boost::endian::little_uint32_t;
77static_assert(
sizeof(
sAuthLogonChallenge_C) == (1 + 1 + 2 + 4 + 1 + 1 + 1 + 2 + 4 + 4 + 4 + 4 + 4 + 1 + 1));
121std::array<uint8, 16>
VersionChallenge = { { 0xBA, 0xA3, 0x1E, 0x99, 0xA0, 0x0B, 0x21, 0x57, 0xFC, 0x37, 0x3F, 0xB3, 0x69, 0xCD, 0xD2, 0xF1 } };
123#define MAX_ACCEPTED_CHALLENGE_SIZE (sizeof(AUTH_LOGON_CHALLENGE_C) + 16)
125#define AUTH_LOGON_CHALLENGE_INITIAL_SIZE 4
126#define REALM_LIST_PACKET_SIZE 5
158 if (handler.
cmd != cmd)
168 return (c & 0x7) + ((c & 0x10) >> 2) - ((c & 0x20) >> 5);
204 _timeout(underlying_stream().get_executor()),
212 std::array<std::shared_ptr<Trinity::Net::SocketConnectionInitializer>, 2> initializers =
214 std::make_shared<Trinity::Net::IpBanCheckConnectionInitializer<AuthSession>>(
this),
224 if (!AuthSocket::Update())
252 size += challenge->
size;
302 std::string_view login(challenge->
I, challenge->
I_len);
303 TC_LOG_DEBUG(
"server.authserver",
"[AuthChallenge] '{}'", login);
317 .WithPreparedCallback([
this](
PreparedQueryResult result) { LogonChallengeCallback(std::move(result)); }));
334 Field* fields = result->Fetch();
379 TC_LOG_INFO(
"server.authserver.banned",
"'{}:{}' [AuthChallenge] Banned account {} tried to login!", ipAddress, port,
_accountInfo.
Login);
386 TC_LOG_INFO(
"server.authserver.banned",
"'{}:{}' [AuthChallenge] Temporarily banned account {} tried to login!", ipAddress, port,
_accountInfo.
Login);
391 uint8 securityFlags = 0;
393 if (!fields[9].IsNull())
399 bool success = Trinity::Crypto::AEDecrypt<Trinity::Crypto::AES>(*
_totpSecret, *secret);
428 pkt <<
uint8(securityFlags);
430 if (securityFlags & 0x01)
436 if (securityFlags & 0x02)
445 if (securityFlags & 0x04)
448 TC_LOG_DEBUG(
"server.authserver",
"'{}:{}' [AuthChallenge] account {} is using '{}' locale ({})",
462 TC_LOG_DEBUG(
"server.authserver",
"Entering _HandleLogonProof");
472 TC_LOG_DEBUG(
"network",
"Client with invalid version, patching is not implemented");
477 if (std::optional<SessionKey> K =
_srp6->VerifyChallengeResponse(logonProof->
A, logonProof->
clientM))
481 bool tokenSuccess =
false;
489 uint32 incomingToken = atoi(token.c_str());
520 std::string address =
sConfigMgr->GetBoolDefault(
"AllowLoggingIPAddressesInDatabase",
true,
true) ?
GetRemoteIpAddress().to_string() :
"127.0.0.1";
533 if (_expversion & POST_BC_EXP_FLAG)
535 sAuthLogonProof_S proof;
537 proof.cmd = AUTH_LOGON_PROOF;
539 proof.AccountFlags = GAMEACCOUNT_FLAG_PROPASS_LOCK;
541 proof.LoginFlags = 0;
543 packet.resize(sizeof(proof));
544 std::memcpy(packet.contents(), &proof, sizeof(proof));
548 sAuthLogonProof_S_Old proof;
550 proof.cmd = AUTH_LOGON_PROOF;
554 packet.resize(sizeof(proof));
555 std::memcpy(packet.contents(), &proof, sizeof(proof));
570 TC_LOG_INFO(
"server.authserver.hack",
"'{}:{}' [AuthChallenge] account {} tried to login with invalid password!",
571 GetRemoteIpAddress().to_string(), GetRemotePort(), _accountInfo.Login);
573 uint32 MaxWrongPassCount =
sConfigMgr->GetIntDefault(
"WrongPass.MaxCount", 0);
576 if (
sConfigMgr->GetBoolDefault(
"WrongPass.Logging",
false))
580 logstmt->
setString(1, GetRemoteIpAddress().to_string());
581 logstmt->
setString(2,
"Login to WoW Failed - Incorrect Password");
586 if (MaxWrongPassCount > 0)
593 if (++_accountInfo.FailedLogins >= MaxWrongPassCount)
595 uint32 WrongPassBanTime =
sConfigMgr->GetIntDefault(
"WrongPass.BanTime", 600);
596 bool WrongPassBanType =
sConfigMgr->GetBoolDefault(
"WrongPass.BanType",
false);
598 if (WrongPassBanType)
605 TC_LOG_DEBUG(
"server.authserver",
"'{}:{}' [AuthChallenge] account {} got banned for '{}' seconds because it failed to authenticate '{}' times",
606 GetRemoteIpAddress().to_string(), GetRemotePort(), _accountInfo.Login, WrongPassBanTime, _accountInfo.FailedLogins);
611 stmt->
setString(0, GetRemoteIpAddress().to_string());
615 TC_LOG_DEBUG(
"server.authserver",
"'{}:{}' [AuthChallenge] IP got banned for '{}' seconds because account {} failed to authenticate '{}' times",
616 GetRemoteIpAddress().to_string(), GetRemotePort(), WrongPassBanTime, _accountInfo.Login, _accountInfo.FailedLogins);
633 std::string_view login(challenge->
I, challenge->
I_len);
634 TC_LOG_DEBUG(
"server.authserver",
"[ReconnectChallenge] '{}'", login);
648 .WithPreparedCallback([
this](
PreparedQueryResult result) { ReconnectChallengeCallback(std::move(result)); }));
664 Field* fields = result->Fetch();
680 TC_LOG_DEBUG(
"server.authserver",
"Entering _HandleReconnectProof");
725 TC_LOG_DEBUG(
"server.authserver",
"Entering _HandleRealmList");
737 std::map<uint32, uint8> characterCounts;
742 Field* fields = result->Fetch();
744 }
while (result->NextRow());
750 size_t RealmListSize = 0;
751 for (RealmList::RealmMap::value_type
const& i :
sRealmList->GetRealms())
769 flag &= ~REALM_FLAG_SPECIFYBUILD;
815 RealmListSizeBuffer <<
uint32(0);
817 RealmListSizeBuffer <<
uint16(RealmListSize);
819 RealmListSizeBuffer <<
uint32(RealmListSize);
824 hdr.
append(RealmListSizeBuffer);
833 TC_LOG_DEBUG(
"server.authserver",
"Entering _HandleXferAccept");
841 TC_LOG_DEBUG(
"server.authserver",
"Entering _HandleXferResume");
849 TC_LOG_DEBUG(
"server.authserver",
"Entering _HandleXferCancel");
857 if (!
sConfigMgr->GetBoolDefault(
"StrictVersionCheck",
false))
872 versionHash = &platformItr->Hash;
875 versionHash = &zeros;
882 return versionProof == version.
GetDigest();
902 _timeout.async_wait([selfRef = weak_from_this()](boost::system::error_code
const& error)
904 std::shared_ptr<AuthSession> self = static_pointer_cast<AuthSession>(selfRef.lock());
908 if (error == boost::asio::error::operation_aborted)
911 TC_LOG_DEBUG(
"server.authserver",
"{}:{} session timed out.", self->GetRemoteIpAddress().to_string(), self->GetRemotePort());
@ WOW_FAIL_LOCKED_ENFORCED
@ WOW_FAIL_UNKNOWN_ACCOUNT
@ WOW_FAIL_UNLOCKABLE_LOCK
@ WOW_FAIL_VERSION_INVALID
constexpr size_t SESSION_KEY_LENGTH
struct AUTH_LOGON_PROOF_S sAuthLogonProof_S
std::array< uint8, 16 > VersionChallenge
#define MAX_ACCEPTED_CHALLENGE_SIZE
@ AUTH_RECONNECT_CHALLENGE
#define AUTH_LOGON_CHALLENGE_INITIAL_SIZE
class AuthHandlerTable Handlers
struct AUTH_LOGON_PROOF_C sAuthLogonProof_C
struct AUTH_LOGON_PROOF_S_OLD sAuthLogonProof_S_Old
struct AUTH_RECONNECT_PROOF_C sAuthReconnectProof_C
struct AUTH_LOGON_CHALLENGE_C sAuthLogonChallenge_C
#define REALM_LIST_PACKET_SIZE
@ STATUS_WAITING_FOR_REALM_LIST
char const * localeNames[TOTAL_LOCALES]
LocaleConstant GetLocaleByName(const std::string &name)
std::shared_ptr< PreparedResultSet > PreparedQueryResult
DatabaseWorkerPool< LoginDatabaseConnection > LoginDatabase
Accessor to the realm/login database.
std::chrono::minutes Minutes
Minutes shorthand typedef.
#define TC_LOG_DEBUG(filterType__,...)
#define TC_LOG_ERROR(filterType__,...)
#define TC_LOG_INFO(filterType__,...)
@ LOGIN_INS_ACCOUNT_AUTO_BANNED
@ LOGIN_INS_FALP_IP_LOGGING
@ LOGIN_SEL_RECONNECTCHALLENGE
@ LOGIN_INS_IP_AUTO_BANNED
@ LOGIN_SEL_LOGONCHALLENGE
@ LOGIN_SEL_REALM_CHARACTER_COUNTS
@ REALM_FLAG_SPECIFYBUILD
bool Utf8ToUpperOnlyLatin(std::string &utf8String)
T & AddCallback(T &&query)
void ProcessReadyCallbacks()
consteval AuthHandlerTable()
static constexpr std::size_t GetOpcodeArrayIndex(eAuthCmd c)
constexpr void InitializeHandler(eAuthCmd cmd, AuthStatus status, std::size_t packetSize, bool(*handler)(AuthSession *))
std::array< AuthHandler, 8 > _handlers
constexpr AuthHandler const * operator[](eAuthCmd cmd) const
void QueueQuery(QueryCallback &&queryCallback)
Trinity::Asio::DeadlineTimer _timeout
Optional< Trinity::Crypto::SRP6 > _srp6
bool HandleLogonChallenge()
bool VerifyVersion(std::span< uint8 const > a, Trinity::Crypto::SHA1::Digest const &versionProof, bool isReconnect)
void RealmListCallback(PreparedQueryResult result)
AuthSession(Trinity::Net::IoContextTcpSocket &&socket)
std::string_view _ipCountry
void ReconnectChallengeCallback(PreparedQueryResult result)
bool HandleReconnectChallenge()
Trinity::Net::SocketReadCallbackResult ReadHandler() override
QueryCallbackProcessor _queryProcessor
void SendPacket(ByteBuffer &packet)
void LogonChallengeCallback(PreparedQueryResult result)
Optional< std::vector< uint8 > > _totpSecret
bool HandleReconnectProof()
std::array< uint8, 16 > _reconnectProof
Class used to access individual fields of database query result.
std::vector< uint8 > GetBinary() const
std::string_view GetStringView() const
void ReadCompleted(size_type bytes)
size_type GetActiveSize() const
void Write(void const *data, std::size_t size)
void setInt16(uint8 index, int16 value)
void setUInt32(uint8 index, uint32 value)
void setStringView(uint8 index, std::string_view value)
void setBinary(uint8 index, std::vector< uint8 > const &value)
void setString(uint8 index, std::string const &value)
static constexpr size_t SALT_LENGTH
static constexpr size_t VERIFIER_LENGTH
std::array< uint8, EPHEMERAL_KEY_LENGTH > EphemeralKey
static SHA1::Digest GetSessionVerifier(EphemeralKey const &A, SHA1::Digest const &clientM, SessionKey const &K)
std::array< uint8, DIGEST_LENGTH > Digest
void UpdateData(uint8 const *data, size_t len)
Digest const & GetDigest() const
uint16 GetRemotePort() const
boost::asio::ip::address const & GetRemoteIpAddress() const
void QueuePacket(MessageBuffer &&buffer)
MessageBuffer & GetReadBuffer()
bool IsAcceptedClientBuild(uint32 build)
bool IsPreBCAcceptedClientBuild(uint32 build)
bool IsPostBCAcceptedClientBuild(uint32 build)
Info const * GetBuildInfo(uint32 build)
std::array< char, 5 > ToCharArray(uint32 value)
std::array< uint8, S > GetRandomBytes()
boost::asio::basic_stream_socket< boost::asio::ip::tcp, boost::asio::io_context::executor_type > IoContextTcpSocket
OutputIt StringFormatTo(OutputIt out, FormatString< Args... > fmt, Args &&... args)
little_uint32_t timezone_bias
Trinity::Crypto::SHA1::Digest crc_hash
Trinity::Crypto::SRP6::EphemeralKey A
Trinity::Crypto::SHA1::Digest clientM
Trinity::Crypto::SHA1::Digest M2
little_uint32_t AccountFlags
Trinity::Crypto::SHA1::Digest M2
little_uint16_t LoginFlags
Trinity::Crypto::SHA1::Digest R3
Trinity::Crypto::SHA1::Digest R2
void LoadResult(Field *fields)
AccountTypes SecurityLevel
bool IsPermanenetlyBanned
bool(* handler)(AuthSession *)
std::vector< ExecutableHash > ExecutableHashes
AccountTypes AllowedSecurityLevel
boost::asio::ip::tcp_endpoint GetAddressForClient(boost::asio::ip::address const &clientAddr) const
static bool ValidateToken(Secret const &key, uint32 token)
static std::shared_ptr< SocketConnectionInitializer > & SetupChain(std::span< std::shared_ptr< SocketConnectionInitializer > > initializers)