19#include "openssl/crypto.h"
131#define AUTH_TOTAL_COMMANDS 8
135 bool ReadAuthChallengeFrame(
RealmSocket& socket, std::vector<uint8>& packet,
uint16& remaining)
137 const size_t headerSize = 4;
141 std::vector<uint8> header(headerSize);
142 if (!socket.
PeekBytes(&header[0], header.size()))
157 packet.resize(headerSize + remaining + 1);
158 packet[packet.size() - 1] = 0;
160 if (!socket.
ReadBytes(&packet[0], packet.size() - 1))
181 SF_LOG_DEBUG(
"server.authserver",
"'%s:%d' Accepting connection",
182 socket().getRemoteAddress().c_str(),
socket().getRemotePort());
187 SF_LOG_DEBUG(
"server.authserver",
"AuthSocket::OnClose");
193#define MAX_AUTH_LOGON_CHALLENGES_IN_A_ROW 3
194 uint32 challengesInARow = 0;
198 if (!
socket().PeekBytes(&_cmd, 1))
206 SF_LOG_WARN(
"server.authserver",
"Got %u AUTH_LOGON_CHALLENGE in a row from '%s', possible ongoing DoS",
207 challengesInARow,
socket().getRemoteAddress().c_str());
221 SF_LOG_DEBUG(
"server.authserver",
"Got data for cmd %u recv length %u",
224 if (!(*this.*table[i].handler)())
226 SF_LOG_DEBUG(
"server.authserver",
"Command handler failed for cmd %u recv length %u",
237 SF_LOG_ERROR(
"server.authserver",
"Got unknown packet from '%s'",
socket().getRemoteAddress().c_str());
247 SF_LOG_DEBUG(
"server.authserver",
"Entering _HandleLogonChallenge");
248 std::vector<uint8> buf;
250 if (!ReadAuthChallengeFrame(
socket(), buf, remaining))
253 SF_LOG_DEBUG(
"server.authserver",
"[AuthChallenge] got header, body is %#04x bytes", remaining);
256 SF_LOG_DEBUG(
"server.authserver",
"[AuthChallenge] got full packet, %#04x bytes", ch->
size);
257 SF_LOG_DEBUG(
"server.authserver",
"[AuthChallenge] name(%d): '%s'", ch->
I_len, ch->
I);
276 _os = (
const char*)ch->
os;
282 std::reverse(
_os.begin(),
_os.end());
297 SF_LOG_DEBUG(
"server.authserver",
"'%s:%d' [AuthChallenge] Banned ip tries to login!",
298 socket().getRemoteAddress().c_str(),
socket().getRemotePort());
310 Field* fields = res2->Fetch();
314 if (fields[1].GetUInt8() == 1)
316 SF_LOG_DEBUG(
"server.authserver",
"[AuthChallenge] Account '%s' is locked to IP - '%s'",
318 SF_LOG_DEBUG(
"server.authserver",
"[AuthChallenge] Player address is '%s'", ip_address.c_str());
320 if (strcmp(fields[3].GetCString(), ip_address.c_str()) != 0)
322 SF_LOG_DEBUG(
"server.authserver",
"[AuthChallenge] Account IP differs");
327 SF_LOG_DEBUG(
"server.authserver",
"[AuthChallenge] Account IP matches");
331 SF_LOG_DEBUG(
"server.authserver",
"[AuthChallenge] Account '%s' is not locked to ip",
_login.c_str());
332 std::string accountCountry = fields[2].
GetString();
333 if (accountCountry.empty() || accountCountry ==
"00")
335 SF_LOG_DEBUG(
"server.authserver",
"[AuthChallenge] Account '%s' is not locked to country",
339 if (!accountCountry.empty())
348 std::string loginCountry = (*sessionCountryQuery)[0].GetString();
350 "[AuthChallenge] Account '%s' is locked to country: '%s' Player country is '%s'",
351 _login.c_str(), accountCountry.c_str(), loginCountry.c_str());
352 if (loginCountry != accountCountry)
354 SF_LOG_DEBUG(
"server.authserver",
"[AuthChallenge] Account country differs.");
359 SF_LOG_DEBUG(
"server.authserver",
"[AuthChallenge] Account country matches");
362 SF_LOG_DEBUG(
"server.authserver",
"[AuthChallenge] IP2NATION Table empty");
373 stmt->
setUInt32(0, fields[1].GetUInt32());
377 if ((*banresult)[0].GetUInt32() == (*banresult)[1].GetUInt32())
380 SF_LOG_DEBUG(
"server.authserver",
"'%s:%d' [AuthChallenge] Banned account %s tried to login!",
387 "'%s:%d' [AuthChallenge] Temporarily banned account %s tried to login!",
393 _srp6.emplace(
_login, fields[5].GetBinary<SkyFire::Crypto::SRP6::SALT_LENGTH>(),
394 fields[6].GetBinary<SkyFire::Crypto::SRP6::VERIFIER_LENGTH>());
413 uint8 securityFlags = 0;
420 pkt <<
uint8(securityFlags);
422 if (securityFlags & 0x01)
428 if (securityFlags & 0x02)
437 if (securityFlags & 0x04)
445 for (
int i = 0; i < 4; ++i)
449 "'%s:%d' [AuthChallenge] account %s is using '%c%c%c%c' locale (%u)",
467 SF_LOG_DEBUG(
"server.authserver",
"Entering _HandleLogonProof");
479 if (!
socket().PeekBytes(&tokenSize,
sizeof(tokenSize), requiredBytes))
482 requiredBytes +=
sizeof(tokenSize) + tokenSize;
483 if (
socket().GetAvailableBytes() < requiredBytes)
494 SF_LOG_DEBUG(
"network",
"Client with invalid version, patching is not implemented");
499 if (std::optional<SessionKey> K =
_srp6->VerifyChallengeResponse(lp.
A, lp.
clientM))
503 SF_LOG_DEBUG(
"server.authserver",
"'%s:%d' User '%s' successfully authenticated",
525 if (!
socket().ReadBytes(&size,
sizeof(size)))
528 std::vector<char> token(size + 1);
530 if (!
socket().ReadBytes(&token[0], size))
534 unsigned int incomingToken = atoi(&token[0]);
535 if (validToken != incomingToken)
549 proof.
unk1 = 0x00800000;
572 "'%s:%d' [AuthChallenge] account %s tried to login with invalid password!",
575 uint32 MaxWrongPassCount =
sConfigMgr->GetIntDefault(
"WrongPass.MaxCount", 0);
576 if (MaxWrongPassCount > 0)
588 uint32 failed_logins = (*loginfail)[1].GetUInt32();
590 if (failed_logins >= MaxWrongPassCount)
592 uint32 WrongPassBanTime =
sConfigMgr->GetIntDefault(
"WrongPass.BanTime", 600);
593 bool WrongPassBanType =
sConfigMgr->GetBoolDefault(
"WrongPass.BanType",
false);
595 if (WrongPassBanType)
597 uint32 acc_id = (*loginfail)[0].GetUInt32();
604 "'%s:%d' [AuthChallenge] account %s got banned for '%u' seconds "
605 "because it failed to authenticate '%u' times",
607 WrongPassBanTime, failed_logins);
617 "'%s:%d' [AuthChallenge] IP %s got banned for '%u' seconds "
618 "because account %s failed to authenticate '%u' times",
619 socket().getRemoteAddress().c_str(),
socket().getRemotePort(),
620 socket().getRemoteAddress().c_str(), WrongPassBanTime,
_login.c_str(), failed_logins);
633 SF_LOG_DEBUG(
"server.authserver",
"Entering _HandleReconnectChallenge");
634 std::vector<uint8> buf;
636 if (!ReadAuthChallengeFrame(
socket(), buf, remaining))
639 SF_LOG_DEBUG(
"server.authserver",
"[ReconnectChallenge] got header, body is %#04x bytes", remaining);
642 SF_LOG_DEBUG(
"server.authserver",
"[ReconnectChallenge] got full packet, %#04x bytes", ch->
size);
643 SF_LOG_DEBUG(
"server.authserver",
"[ReconnectChallenge] name(%d): '%s'", ch->
I_len, ch->
I);
656 "'%s:%d' [ERROR] user %s tried to login and we cannot find his session key in the database.",
666 _os = (
const char*)ch->
os;
672 std::reverse(
_os.begin(),
_os.end());
674 Field* fields = result->Fetch();
695 SF_LOG_DEBUG(
"server.authserver",
"Entering _HandleReconnectProof");
727 SF_LOG_ERROR(
"server.authserver",
"'%s:%d' [ERROR] user %s tried to login, but session is invalid.",
759 SF_LOG_DEBUG(
"server.authserver",
"Entering _HandleRealmList");
760 if (
socket().GetAvailableBytes() < 5)
773 "'%s:%d' [ERROR] user %s tried to login but we cannot find him in the database.",
779 Field* fields = result->Fetch();
791 size_t RealmListSize = 0;
794 const Realm& realm = i->second;
813 std::string name = i->first;
816 std::ostringstream ss;
827 uint8 AmountOfCharacters = 0;
833 AmountOfCharacters = (*result)[0].GetUInt8();
842 pkt << AmountOfCharacters;
873 RealmListSizeBuffer <<
uint32(0);
875 RealmListSizeBuffer <<
uint16(RealmListSize);
877 RealmListSizeBuffer <<
uint32(RealmListSize);
882 hdr.
append(RealmListSizeBuffer);
893 SF_LOG_DEBUG(
"server.authserver",
"Entering _HandleXferResume");
898 SF_LOG_ERROR(
"server.authserver",
"Error while resuming patch transfer (wrong packet)");
901 SF_LOG_ERROR(
"server.authserver",
"Client requested unsupported patch transfer resume");
914 SF_LOG_DEBUG(
"server.authserver",
"Entering _HandleXferCancel");
930 SF_LOG_DEBUG(
"server.authserver",
"Entering _HandleXferAccept");
935 SF_LOG_ERROR(
"server.authserver",
"Client requested unsupported patch transfer accept");
@ WOW_FAIL_UNKNOWN_ACCOUNT
@ WOW_FAIL_VERSION_INVALID
@ WOW_FAIL_UNLOCKABLE_LOCK
@ WOW_FAIL_LOCKED_ENFORCED
constexpr size_t SESSION_KEY_LENGTH
struct AUTH_LOGON_PROOF_S sAuthLogonProof_S
const AuthHandler table[]
@ AUTH_RECONNECT_CHALLENGE
#define AUTH_TOTAL_COMMANDS
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 MAX_AUTH_LOGON_CHALLENGES_IN_A_ROW
void EndianConvertReverse(T &val)
void EndianConvertPtr(void *)
LocaleConstant GetLocaleByName(const std::string &name)
#define SF_LOG_DEBUG(filterType__,...)
#define SF_LOG_WARN(filterType__,...)
#define SF_LOG_ERROR(filterType__,...)
@ LOGIN_INS_ACCOUNT_AUTO_BANNED
@ LOGIN_DEL_EXPIRED_IP_BANS
@ LOGIN_SEL_LOGON_COUNTRY
@ LOGIN_SEL_NUM_CHARS_ON_REALM
@ LOGIN_UPD_EXPIRED_ACCOUNT_BANS
@ LOGIN_SEL_ACCOUNT_ID_BY_NAME
@ LOGIN_INS_IP_AUTO_BANNED
@ LOGIN_SEL_ACCOUNT_BANNED
@ LOGIN_SEL_LOGONCHALLENGE
Skyfire::AutoPtr< PreparedResultSet, Skyfire::Mutex > PreparedQueryResult
@ REALM_FLAG_SPECIFYBUILD
bool IsIPAddrInNetwork(Skyfire::Net::Address const &net, Skyfire::Net::Address const &addr, Skyfire::Net::Address const &subnetMask)
Checks if address belongs to the a network with specified submask.
std::string GetAddressString(Skyfire::Net::Address const &addr)
Transforms network address into string format "dotted_ip:port".
virtual void OnClose(void)
AuthSocket(RealmSocket &socket)
virtual void OnAccept(void)
std::optional< SkyFire::Crypto::SRP6 > _srp6
bool _HandleReconnectChallenge()
AccountTypes _accountSecurityLevel
static Skyfire::Net::Address const & GetAddressForClient(Realm const &realm, Skyfire::Net::Address const &clientAddr)
bool _HandleLogonChallenge()
virtual void OnRead(void)
virtual ~AuthSocket(void)
RealmSocket & socket(void)
std::array< uint8, 16 > _reconnectProof
bool _HandleReconnectProof()
std::string _localizationName
std::array< uint8, Size > ToByteArray(bool littleEndian=true) const
void SetRand(int32 numbits)
void SetBinary(uint8 const *bytes, int32 len, bool littleEndian=true)
std::string GetString() const
std::vector< uint8 > GetBinary() const
char const * GetCString() const
void setString(const uint8 index, const std::string &value)
void setBinary(const uint8 index, const std::vector< uint8 > &value)
void setUInt32(const uint8 index, const uint32 value)
bool PeekBytes(void *buf, size_t len, size_t offset=0) const
size_t GetAvailableBytes(void) const
bool ReadBytes(void *buf, size_t len)
const std::string & getRemoteAddress(void) const
void DiscardBytes(size_t len)
bool QueueSend(void const *buf, size_t len)
void SetPacketLogAccountName(std::string accountName)
std::array< uint8, EPHEMERAL_KEY_LENGTH > EphemeralKey
static SHA1::Digest GetSessionVerifier(EphemeralKey const &A, SHA1::Digest const &clientM, SessionKey const &K)
Digest const & GetDigest() const
void UpdateData(uint8 const *data, size_t len)
std::array< uint8, DIGEST_LENGTH > Digest
void SetPort(uint16 port)
bool IsAcceptedClientBuild(int build)
RealmBuildInfo const * GetBuildInfo(int build)
bool IsPreBCAcceptedClientBuild(int build)
bool IsPostBCAcceptedClientBuild(int build)
SkyFire::Impl::GenericHash< EVP_sha1, Constants::SHA1_DIGEST_LENGTH_BYTES > SHA1
std::array< uint8, S > GetRandomBytes()
PatchTransferDecision EvaluatePatchTransferRequest(PatchTransferAction action, size_t availableBytes)
uint32 ToIPv4NetworkOrder(std::string const &host)
unsigned int GenerateToken(std::string &b32key)
LoginDatabaseWorkerPool LoginDatabase
SkyFire::Crypto::SRP6::EphemeralKey A
SkyFire::Crypto::SHA1::Digest clientM
SkyFire::Crypto::SHA1::Digest crc_hash
SkyFire::Crypto::SHA1::Digest M2
SkyFire::Crypto::SHA1::Digest M2
SkyFire::Crypto::SHA1::Digest R3
SkyFire::Crypto::SHA1::Digest R2
bool(AuthSocket::* handler)(void)
Skyfire::Net::Address LocalAddress
AccountTypes allowedSecurityLevel
Skyfire::Net::Address ExternalAddress
Skyfire::Net::Address LocalSubnetMask