From d9f1d6466dbb16fdbc792fe42a92c18ec29dfb48 Mon Sep 17 00:00:00 2001 From: Shauren Date: Tue, 6 May 2014 23:43:29 +0200 Subject: Core/Battle.net: Implemented authserver --- src/server/shared/Database/Implementation/LoginDatabase.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/server/shared/Database/Implementation') diff --git a/src/server/shared/Database/Implementation/LoginDatabase.cpp b/src/server/shared/Database/Implementation/LoginDatabase.cpp index de1e5b992e6..07158dfcbdb 100644 --- a/src/server/shared/Database/Implementation/LoginDatabase.cpp +++ b/src/server/shared/Database/Implementation/LoginDatabase.cpp @@ -22,7 +22,7 @@ void LoginDatabaseConnection::DoPrepareStatements() if (!m_reconnecting) m_stmts.resize(MAX_LOGINDATABASE_STATEMENTS); - PrepareStatement(LOGIN_SEL_REALMLIST, "SELECT id, name, address, localAddress, localSubnetMask, port, icon, flag, timezone, allowedSecurityLevel, population, gamebuild FROM realmlist WHERE flag <> 3 ORDER BY name", CONNECTION_SYNCH); + PrepareStatement(LOGIN_SEL_REALMLIST, "SELECT id, name, address, localAddress, localSubnetMask, port, icon, flag, timezone, allowedSecurityLevel, population, gamebuild, Region, Battlegroup FROM realmlist WHERE flag <> 3 ORDER BY name", CONNECTION_SYNCH); PrepareStatement(LOGIN_DEL_EXPIRED_IP_BANS, "DELETE FROM ip_banned WHERE unbandate<>bandate AND unbandate<=UNIX_TIMESTAMP()", CONNECTION_ASYNC); PrepareStatement(LOGIN_UPD_EXPIRED_ACCOUNT_BANS, "UPDATE account_banned SET active = 0 WHERE active = 1 AND unbandate<>bandate AND unbandate<=UNIX_TIMESTAMP()", CONNECTION_SYNCH); PrepareStatement(LOGIN_SEL_IP_BANNED, "SELECT * FROM ip_banned WHERE ip = ?", CONNECTION_SYNCH); -- cgit v1.2.3 From a842f2ef11339df7814cacf470fe99fadafbaa45 Mon Sep 17 00:00:00 2001 From: Shauren Date: Mon, 12 May 2014 17:57:35 +0200 Subject: Core/Battle.net: Changed HandleAuthSession to work with battle.net formatted account names --- src/server/game/Server/WorldSocket.cpp | 2 +- src/server/shared/Database/Implementation/LoginDatabase.cpp | 1 + src/server/shared/Database/Implementation/LoginDatabase.h | 1 + 3 files changed, 3 insertions(+), 1 deletion(-) (limited to 'src/server/shared/Database/Implementation') diff --git a/src/server/game/Server/WorldSocket.cpp b/src/server/game/Server/WorldSocket.cpp index 737a2f8cbf1..cc839b5281c 100644 --- a/src/server/game/Server/WorldSocket.cpp +++ b/src/server/game/Server/WorldSocket.cpp @@ -856,7 +856,7 @@ int WorldSocket::HandleAuthSession(WorldPacket& recvPacket) // Get the account information from the realmd database // 0 1 2 3 4 5 6 7 8 // SELECT id, sessionkey, last_ip, locked, expansion, mutetime, locale, recruiter, os FROM account WHERE username = ? - PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_ACCOUNT_INFO_BY_NAME); + PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(account.find('#') == std::string::npos ? LOGIN_SEL_ACCOUNT_INFO_BY_NAME : LOGIN_SEL_ACCOUNT_INFO_BY_BNET); stmt->setString(0, account); diff --git a/src/server/shared/Database/Implementation/LoginDatabase.cpp b/src/server/shared/Database/Implementation/LoginDatabase.cpp index 07158dfcbdb..e8bb1e75d2f 100644 --- a/src/server/shared/Database/Implementation/LoginDatabase.cpp +++ b/src/server/shared/Database/Implementation/LoginDatabase.cpp @@ -44,6 +44,7 @@ void LoginDatabaseConnection::DoPrepareStatements() PrepareStatement(LOGIN_SEL_ACCOUNT_ID_BY_NAME, "SELECT id FROM account WHERE username = ?", CONNECTION_SYNCH); PrepareStatement(LOGIN_SEL_ACCOUNT_LIST_BY_NAME, "SELECT id, username FROM account WHERE username = ?", CONNECTION_SYNCH); PrepareStatement(LOGIN_SEL_ACCOUNT_INFO_BY_NAME, "SELECT id, sessionkey, last_ip, locked, expansion, mutetime, locale, recruiter, os FROM account WHERE username = ?", CONNECTION_SYNCH); + PrepareStatement(LOGIN_SEL_ACCOUNT_INFO_BY_BNET, "SELECT id, sessionkey, last_ip, locked, expansion, mutetime, locale, recruiter, os FROM account WHERE id = SUBSTRING_INDEX(?, '#', 1)", CONNECTION_SYNCH); PrepareStatement(LOGIN_SEL_ACCOUNT_LIST_BY_EMAIL, "SELECT id, username FROM account WHERE email = ?", CONNECTION_SYNCH); PrepareStatement(LOGIN_SEL_NUM_CHARS_ON_REALM, "SELECT numchars FROM realmcharacters WHERE realmid = ? AND acctid= ?", CONNECTION_SYNCH); PrepareStatement(LOGIN_SEL_ACCOUNT_BY_IP, "SELECT id, username FROM account WHERE last_ip = ?", CONNECTION_SYNCH); diff --git a/src/server/shared/Database/Implementation/LoginDatabase.h b/src/server/shared/Database/Implementation/LoginDatabase.h index 01f9fd973b6..d8e6687f755 100644 --- a/src/server/shared/Database/Implementation/LoginDatabase.h +++ b/src/server/shared/Database/Implementation/LoginDatabase.h @@ -62,6 +62,7 @@ enum LoginDatabaseStatements LOGIN_SEL_ACCOUNT_ID_BY_NAME, LOGIN_SEL_ACCOUNT_LIST_BY_NAME, LOGIN_SEL_ACCOUNT_INFO_BY_NAME, + LOGIN_SEL_ACCOUNT_INFO_BY_BNET, LOGIN_SEL_ACCOUNT_LIST_BY_EMAIL, LOGIN_SEL_NUM_CHARS_ON_REALM, LOGIN_SEL_ACCOUNT_BY_IP, -- cgit v1.2.3 From 8ec0be28027f3eda55995ef13e6e522631e36dc1 Mon Sep 17 00:00:00 2001 From: Shauren Date: Tue, 13 May 2014 22:02:51 +0200 Subject: Core/Battle.net: Use prepared statements in Battlenet::Socket --- src/server/authserver/Server/BattlenetSocket.cpp | 50 +++++++++++++++------- .../Database/Implementation/LoginDatabase.cpp | 8 ++++ .../shared/Database/Implementation/LoginDatabase.h | 9 ++++ 3 files changed, 51 insertions(+), 16 deletions(-) (limited to 'src/server/shared/Database/Implementation') diff --git a/src/server/authserver/Server/BattlenetSocket.cpp b/src/server/authserver/Server/BattlenetSocket.cpp index a0597dce2a0..6723024d868 100644 --- a/src/server/authserver/Server/BattlenetSocket.cpp +++ b/src/server/authserver/Server/BattlenetSocket.cpp @@ -195,9 +195,10 @@ bool Battlenet::Socket::HandleAuthChallenge(PacketHeader& header, BitStream& pac _os = info.Platform; Utf8ToUpperOnlyLatin(_accountName); - LoginDatabase.EscapeString(_accountName); - // 0 1 2 3 4 5 6 - QueryResult result = LoginDatabase.PQuery("SELECT sha_pass_hash, id, locked, lock_country, last_ip, v, s FROM battlenet_accounts WHERE email = '%s'", _accountName.c_str()); + stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_BNET_ACCOUNT_INFO); + stmt->setString(0, _accountName); + + PreparedQueryResult result = LoginDatabase.Query(stmt); if (!result) { AuthComplete complete; @@ -252,10 +253,12 @@ bool Battlenet::Socket::HandleAuthChallenge(PacketHeader& header, BitStream& pac } //set expired bans to inactive - LoginDatabase.DirectExecute("UPDATE battlenet_account_bans SET active = 0 WHERE active = 1 AND unbandate <> bandate AND unbandate <= UNIX_TIMESTAMP()"); + LoginDatabase.DirectExecute(LoginDatabase.GetPreparedStatement(LOGIN_DEL_BNET_EXPIRED_BANS)); // If the account is banned, reject the logon attempt - QueryResult banresult = LoginDatabase.PQuery("SELECT bandate, unbandate FROM battlenet_account_bans WHERE id = %u AND active = 1", _accountId); + stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_BNET_ACTIVE_ACCOUNT_BAN); + stmt->setUInt32(0, _accountId); + PreparedQueryResult banresult = LoginDatabase.Query(stmt); if (banresult) { Field* fields = banresult->Fetch(); @@ -380,17 +383,23 @@ bool Battlenet::Socket::HandleRealmUpdateSubscribe(PacketHeader& /*header*/, Bit ACE_INET_Addr clientAddr; _socket.peer().get_remote_addr(clientAddr); + PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_BNET_CHARACTER_COUNTS); + stmt->setUInt32(0, _gameAccountId); + + if (PreparedQueryResult countResult = LoginDatabase.Query(stmt)) + { + do + { + Field* fields = countResult->Fetch(); + uint32 build = fields[4].GetUInt32(); + counts.CharacterCounts.push_back({ { fields[2].GetUInt8(), fields[3].GetUInt8(), fields[1].GetUInt32(), (_build != build ? build : 0) }, fields[0].GetUInt8() }); + } while (countResult->NextRow()); + } + for (RealmList::RealmMap::const_iterator i = sRealmList->begin(); i != sRealmList->end(); ++i) { Realm const& realm = i->second; - PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_NUM_CHARS_ON_REALM); - stmt->setUInt32(0, realm.m_ID); - stmt->setUInt32(1, _gameAccountId); - - if (PreparedQueryResult result = LoginDatabase.Query(stmt)) - counts.CharacterCounts.push_back({ { realm.Region, realm.Battlegroup, realm.m_ID, 0 }, (*result)[0].GetUInt8() }); - uint32 flag = realm.flag; RealmBuildInfo const* buildInfo = AuthHelper::GetBuildInfo(realm.gamebuild); if (realm.gamebuild != _build) @@ -656,7 +665,9 @@ bool Battlenet::Socket::HandlePasswordModule(BitStream* dataStream, ServerPacket } uint64 numAccounts = 0; - QueryResult result = LoginDatabase.PQuery("SELECT a.username, a.id, ab.bandate, ab.unbandate, ab.active FROM account a LEFT JOIN account_banned ab ON a.id = ab.id WHERE battlenet_account = '%u'", _accountId); + PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_BNET_GAME_ACCOUNTS); + stmt->setUInt32(0, _accountId); + PreparedQueryResult result = LoginDatabase.Query(stmt); if (result) numAccounts = result->GetRowCount(); @@ -759,8 +770,10 @@ bool Battlenet::Socket::HandleSelectGameAccountModule(BitStream* dataStream, Ser dataStream->Read(8); std::string account = dataStream->ReadString(8); - LoginDatabase.EscapeString(account); - QueryResult result = LoginDatabase.PQuery("SELECT a.id, ab.bandate, ab.unbandate, ab.active FROM account a LEFT JOIN account_banned ab ON a.id = ab.id WHERE username = '%s' AND battlenet_account = '%u'", account.c_str(), _accountId); + PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_BNET_GAME_ACCOUNT); + stmt->setString(0, account); + stmt->setUInt32(1, _accountId); + PreparedQueryResult result = LoginDatabase.Query(stmt); if (!result) { AuthComplete* complete = new AuthComplete(); @@ -810,7 +823,12 @@ bool Battlenet::Socket::HandleRiskFingerprintModule(BitStream* dataStream, Serve complete->GameAccountName = str.str(); complete->AccountFlags = 0x800000; // 0x1 IsGMAccount, 0x8 IsTrialAccount, 0x800000 IsProPassAccount - LoginDatabase.PExecute("UPDATE battlenet_accounts SET last_ip = '%s', last_login = NOW(), locale = %u, failed_logins = 0, os = '%s' WHERE id = %u", _socket.getRemoteAddress().c_str(), GetLocaleByName(_locale), _os.c_str(), _accountId); + PreparedStatement *stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_BNET_LAST_LOGIN_INFO); + stmt->setString(0, _socket.getRemoteAddress()); + stmt->setUInt8(1, GetLocaleByName(_locale)); + stmt->setString(2, _os); + stmt->setUInt32(3, _accountId); + LoginDatabase.Execute(stmt); } else complete->SetAuthResult(AUTH_BAD_VERSION_HASH); diff --git a/src/server/shared/Database/Implementation/LoginDatabase.cpp b/src/server/shared/Database/Implementation/LoginDatabase.cpp index e8bb1e75d2f..3ff0f923af8 100644 --- a/src/server/shared/Database/Implementation/LoginDatabase.cpp +++ b/src/server/shared/Database/Implementation/LoginDatabase.cpp @@ -102,4 +102,12 @@ void LoginDatabaseConnection::DoPrepareStatements() PrepareStatement(LOGIN_SEL_RBAC_ACCOUNT_PERMISSIONS, "SELECT permissionId, granted FROM rbac_account_permissions WHERE accountId = ? AND (realmId = ? OR realmId = -1) ORDER BY permissionId, realmId", CONNECTION_SYNCH); PrepareStatement(LOGIN_INS_RBAC_ACCOUNT_PERMISSION, "INSERT INTO rbac_account_permissions (accountId, permissionId, granted, realmId) VALUES (?, ?, ?, ?) ON DUPLICATE KEY UPDATE granted = VALUES(granted)", CONNECTION_ASYNC); PrepareStatement(LOGIN_DEL_RBAC_ACCOUNT_PERMISSION, "DELETE FROM rbac_account_permissions WHERE accountId = ? AND permissionId = ? AND (realmId = ? OR realmId = -1)", CONNECTION_ASYNC); + + PrepareStatement(LOGIN_SEL_BNET_ACCOUNT_INFO, "SELECT sha_pass_hash, id, locked, lock_country, last_ip, v, s FROM battlenet_accounts WHERE email = ?", CONNECTION_SYNCH); + PrepareStatement(LOGIN_DEL_BNET_EXPIRED_BANS, "UPDATE battlenet_account_bans SET active = 0 WHERE active = 1 AND unbandate <> bandate AND unbandate <= UNIX_TIMESTAMP()", CONNECTION_SYNCH); + PrepareStatement(LOGIN_SEL_BNET_ACTIVE_ACCOUNT_BAN, "SELECT bandate, unbandate FROM battlenet_account_bans WHERE id = ? AND active = 1", CONNECTION_SYNCH); + PrepareStatement(LOGIN_SEL_BNET_GAME_ACCOUNTS, "SELECT a.username, a.id, ab.bandate, ab.unbandate, ab.active FROM account a LEFT JOIN account_banned ab ON a.id = ab.id WHERE battlenet_account = ?", CONNECTION_SYNCH); + PrepareStatement(LOGIN_SEL_BNET_GAME_ACCOUNT, "SELECT a.id, ab.bandate, ab.unbandate, ab.active FROM account a LEFT JOIN account_banned ab ON a.id = ab.id WHERE username = ? AND battlenet_account = ?", CONNECTION_SYNCH); + PrepareStatement(LOGIN_UPD_BNET_LAST_LOGIN_INFO, "UPDATE battlenet_accounts SET last_ip = ?, last_login = NOW(), locale = ?, failed_logins = 0, os = ? WHERE id = ?", CONNECTION_ASYNC); + PrepareStatement(LOGIN_SEL_BNET_CHARACTER_COUNTS, "SELECT rc.numchars, r.id, r.Region, r.Battlegroup, r.gamebuild FROM realmcharacters rc INNER JOIN realmlist r ON rc.realmid = r.id WHERE rc.acctid = ?", CONNECTION_SYNCH); } diff --git a/src/server/shared/Database/Implementation/LoginDatabase.h b/src/server/shared/Database/Implementation/LoginDatabase.h index d8e6687f755..2f1edab270b 100644 --- a/src/server/shared/Database/Implementation/LoginDatabase.h +++ b/src/server/shared/Database/Implementation/LoginDatabase.h @@ -121,6 +121,15 @@ enum LoginDatabaseStatements LOGIN_SEL_RBAC_ACCOUNT_PERMISSIONS, LOGIN_INS_RBAC_ACCOUNT_PERMISSION, LOGIN_DEL_RBAC_ACCOUNT_PERMISSION, + + LOGIN_SEL_BNET_ACCOUNT_INFO, + LOGIN_DEL_BNET_EXPIRED_BANS, + LOGIN_SEL_BNET_ACTIVE_ACCOUNT_BAN, + LOGIN_SEL_BNET_GAME_ACCOUNTS, + LOGIN_SEL_BNET_GAME_ACCOUNT, + LOGIN_UPD_BNET_LAST_LOGIN_INFO, + LOGIN_SEL_BNET_CHARACTER_COUNTS, + MAX_LOGINDATABASE_STATEMENTS }; -- cgit v1.2.3 From 81b8deef529517a1f13397ff2aa13154bccf86c9 Mon Sep 17 00:00:00 2001 From: Shauren Date: Tue, 13 May 2014 23:33:02 +0200 Subject: Core/Battle.net: Use prepared statements in Battlenet::AccountMgr --- src/server/game/Accounts/BattlenetAccountMgr.cpp | 57 +++++++++++++--------- .../Database/Implementation/LoginDatabase.cpp | 5 ++ .../shared/Database/Implementation/LoginDatabase.h | 5 ++ 3 files changed, 44 insertions(+), 23 deletions(-) (limited to 'src/server/shared/Database/Implementation') diff --git a/src/server/game/Accounts/BattlenetAccountMgr.cpp b/src/server/game/Accounts/BattlenetAccountMgr.cpp index d03e356a900..8b73ba19a97 100644 --- a/src/server/game/Accounts/BattlenetAccountMgr.cpp +++ b/src/server/game/Accounts/BattlenetAccountMgr.cpp @@ -32,8 +32,10 @@ AccountOpResult Battlenet::AccountMgr::CreateBattlenetAccount(std::string email, if (GetId(email)) return AccountOpResult::AOR_NAME_ALREADY_EXIST; - LoginDatabase.EscapeString(email); - LoginDatabase.DirectPExecute("INSERT INTO battlenet_accounts (`email`,`sha_pass_hash`) VALUES ('%s', '%s')", email.c_str(), CalculateShaPassHash(email, password).c_str()); + PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_INS_BNET_ACCOUNT); + stmt->setString(0, email); + stmt->setString(1, CalculateShaPassHash(email, password)); + LoginDatabase.Execute(stmt); return AccountOpResult::AOR_OK; } @@ -41,24 +43,26 @@ AccountOpResult Battlenet::AccountMgr::CreateBattlenetAccount(std::string email, AccountOpResult Battlenet::AccountMgr::ChangeUsername(uint32 accountId, std::string newUsername, std::string newPassword) { // Check if accounts exists - QueryResult result = LoginDatabase.PQuery("SELECT 1 FROM battlenet_accounts WHERE id = %u", accountId); + PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_BNET_ACCOUNT_EMAIL_BY_ID); + stmt->setUInt32(0, accountId); + PreparedQueryResult result = LoginDatabase.Query(stmt); if (!result) return AccountOpResult::AOR_NAME_NOT_EXIST; + Utf8ToUpperOnlyLatin(newUsername); if (utf8length(newUsername) > MAX_ACCOUNT_STR) return AccountOpResult::AOR_NAME_TOO_LONG; + Utf8ToUpperOnlyLatin(newPassword); if (utf8length(newPassword) > MAX_PASS_STR) return AccountOpResult::AOR_PASS_TOO_LONG; - Utf8ToUpperOnlyLatin(newUsername); - Utf8ToUpperOnlyLatin(newPassword); - - LoginDatabase.EscapeString(newUsername); - LoginDatabase.EscapeString(newPassword); - LoginDatabase.PExecute("UPDATE account SET v = '', s = '', username = '%s', sha_pass_hash = '%s' WHERE id = '%u'", - newUsername.c_str(), CalculateShaPassHash(newUsername, newPassword).c_str(), newPassword.c_str(), accountId); + stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_BNET_PASSWORD); + stmt->setString(0, newUsername); + stmt->setString(1, CalculateShaPassHash(newUsername, newPassword)); + stmt->setUInt32(2, accountId); + LoginDatabase.Execute(stmt); return AccountOpResult::AOR_OK; } @@ -69,31 +73,35 @@ AccountOpResult Battlenet::AccountMgr::ChangePassword(uint32 accountId, std::str if (!GetName(accountId, username)) return AccountOpResult::AOR_NAME_NOT_EXIST; // account doesn't exist - if (utf8length(newPassword) > MAX_PASS_STR) - return AccountOpResult::AOR_PASS_TOO_LONG; - Utf8ToUpperOnlyLatin(username); Utf8ToUpperOnlyLatin(newPassword); + if (utf8length(newPassword) > MAX_PASS_STR) + return AccountOpResult::AOR_PASS_TOO_LONG; - LoginDatabase.EscapeString(newPassword); - LoginDatabase.PExecute("UPDATE account SET v = '', s = '', sha_pass_hash = '%s' WHERE id = '%u'", - CalculateShaPassHash(username, newPassword).c_str(), newPassword.c_str(), accountId); + PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_BNET_PASSWORD); + stmt->setString(0, username); + stmt->setString(1, CalculateShaPassHash(username, newPassword)); + stmt->setUInt32(2, accountId); + LoginDatabase.Execute(stmt); return AccountOpResult::AOR_OK; } uint32 Battlenet::AccountMgr::GetId(std::string const& username) { - QueryResult result = LoginDatabase.PQuery("SELECT id FROM battlenet_accounts WHERE email = '%s'", username.c_str()); + PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_BNET_ACCOUNT_ID_BY_EMAIL); + stmt->setString(0, username); + if (PreparedQueryResult result = LoginDatabase.Query(stmt)) + return (*result)[0].GetUInt32(); - return result ? (*result)[0].GetUInt32() : 0; + return 0; } bool Battlenet::AccountMgr::GetName(uint32 accountId, std::string& name) { - QueryResult result = LoginDatabase.PQuery("SELECT email FROM battlenet_accounts WHERE id = '%u'", accountId); - - if (result) + PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_BNET_ACCOUNT_EMAIL_BY_ID); + stmt->setUInt32(0, accountId); + if (PreparedQueryResult result = LoginDatabase.Query(stmt)) { name = (*result)[0].GetString(); return true; @@ -112,9 +120,12 @@ bool Battlenet::AccountMgr::CheckPassword(uint32 accountId, std::string password Utf8ToUpperOnlyLatin(username); Utf8ToUpperOnlyLatin(password); - QueryResult result = LoginDatabase.PQuery("SELECT 1 FROM battlenet_accounts WHERE id = %u AND sha_pass_hash = '%s'", accountId, CalculateShaPassHash(username, password)); + PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_BNET_CHECK_PASSWORD); + stmt->setUInt32(0, accountId); + stmt->setString(1, CalculateShaPassHash(username, password)); + PreparedQueryResult result = LoginDatabase.Query(stmt); - return (result) ? true : false; + return !result.null(); } std::string Battlenet::AccountMgr::CalculateShaPassHash(std::string const& name, std::string const& password) diff --git a/src/server/shared/Database/Implementation/LoginDatabase.cpp b/src/server/shared/Database/Implementation/LoginDatabase.cpp index 3ff0f923af8..208873448c6 100644 --- a/src/server/shared/Database/Implementation/LoginDatabase.cpp +++ b/src/server/shared/Database/Implementation/LoginDatabase.cpp @@ -110,4 +110,9 @@ void LoginDatabaseConnection::DoPrepareStatements() PrepareStatement(LOGIN_SEL_BNET_GAME_ACCOUNT, "SELECT a.id, ab.bandate, ab.unbandate, ab.active FROM account a LEFT JOIN account_banned ab ON a.id = ab.id WHERE username = ? AND battlenet_account = ?", CONNECTION_SYNCH); PrepareStatement(LOGIN_UPD_BNET_LAST_LOGIN_INFO, "UPDATE battlenet_accounts SET last_ip = ?, last_login = NOW(), locale = ?, failed_logins = 0, os = ? WHERE id = ?", CONNECTION_ASYNC); PrepareStatement(LOGIN_SEL_BNET_CHARACTER_COUNTS, "SELECT rc.numchars, r.id, r.Region, r.Battlegroup, r.gamebuild FROM realmcharacters rc INNER JOIN realmlist r ON rc.realmid = r.id WHERE rc.acctid = ?", CONNECTION_SYNCH); + PrepareStatement(LOGIN_INS_BNET_ACCOUNT, "INSERT INTO battlenet_accounts (`email`,`sha_pass_hash`) VALUES (?, ?)", CONNECTION_ASYNC); + PrepareStatement(LOGIN_SEL_BNET_ACCOUNT_EMAIL_BY_ID, "SELECT email FROM battlenet_accounts WHERE id = ?", CONNECTION_SYNCH); + PrepareStatement(LOGIN_SEL_BNET_ACCOUNT_ID_BY_EMAIL, "SELECT id FROM battlenet_accounts WHERE email = ?", CONNECTION_SYNCH); + PrepareStatement(LOGIN_UPD_BNET_PASSWORD, "UPDATE account SET v = '', s = '', username = ?, sha_pass_hash = ? WHERE id = ?", CONNECTION_ASYNC); + PrepareStatement(LOGIN_SEL_BNET_CHECK_PASSWORD, "SELECT 1 FROM battlenet_accounts WHERE id = %u AND sha_pass_hash = ?", CONNECTION_ASYNC); } diff --git a/src/server/shared/Database/Implementation/LoginDatabase.h b/src/server/shared/Database/Implementation/LoginDatabase.h index 2f1edab270b..18f9110409d 100644 --- a/src/server/shared/Database/Implementation/LoginDatabase.h +++ b/src/server/shared/Database/Implementation/LoginDatabase.h @@ -129,6 +129,11 @@ enum LoginDatabaseStatements LOGIN_SEL_BNET_GAME_ACCOUNT, LOGIN_UPD_BNET_LAST_LOGIN_INFO, LOGIN_SEL_BNET_CHARACTER_COUNTS, + LOGIN_INS_BNET_ACCOUNT, + LOGIN_SEL_BNET_ACCOUNT_EMAIL_BY_ID, + LOGIN_SEL_BNET_ACCOUNT_ID_BY_EMAIL, + LOGIN_UPD_BNET_PASSWORD, + LOGIN_SEL_BNET_CHECK_PASSWORD, MAX_LOGINDATABASE_STATEMENTS }; -- cgit v1.2.3 From dc5c5ef6361f3f4dbb5fc9b5a755951c83f954fa Mon Sep 17 00:00:00 2001 From: Shauren Date: Sun, 1 Jun 2014 13:03:30 +0200 Subject: Core/Authserver: Refactoring - moved GetAddressForClient to Realm structure, changed BigNumber string methods to return std::string, added missing prepared statement --- src/server/authserver/Realms/RealmList.cpp | 21 ++++++++++- src/server/authserver/Realms/RealmList.h | 2 + src/server/authserver/Server/AuthSocket.cpp | 43 ++-------------------- src/server/authserver/Server/AuthSocket.h | 2 - src/server/authserver/Server/BattlenetSocket.cpp | 39 ++++---------------- src/server/authserver/Server/BattlenetSocket.h | 3 +- src/server/shared/Cryptography/BigNumber.cpp | 14 +++++-- src/server/shared/Cryptography/BigNumber.h | 5 ++- .../Database/Implementation/LoginDatabase.cpp | 3 +- .../shared/Database/Implementation/LoginDatabase.h | 1 + 10 files changed, 51 insertions(+), 82 deletions(-) (limited to 'src/server/shared/Database/Implementation') diff --git a/src/server/authserver/Realms/RealmList.cpp b/src/server/authserver/Realms/RealmList.cpp index bd856623faf..48b7a178c2d 100644 --- a/src/server/authserver/Realms/RealmList.cpp +++ b/src/server/authserver/Realms/RealmList.cpp @@ -20,8 +20,27 @@ #include "RealmList.h" #include "BattlenetManager.h" #include "Database/DatabaseEnv.h" +#include "Util.h" -RealmList::RealmList() : m_UpdateInterval(0), m_NextUpdateTime(time(NULL)) { } +ACE_INET_Addr const& Realm::GetAddressForClient(ACE_INET_Addr const& clientAddr) const +{ + // Attempt to send best address for client + if (clientAddr.is_loopback()) + // Assume that user connecting from the machine that authserver is located on + // has all realms available in his local network + return LocalAddress; + + // Check if connecting client is in the same network + if (IsIPAddrInNetwork(LocalAddress, clientAddr, LocalSubnetMask)) + return LocalAddress; + + // Return external IP + return ExternalAddress; +} + +RealmList::RealmList() : m_UpdateInterval(0), m_NextUpdateTime(time(NULL)) +{ +} // Load the realm list from the database void RealmList::Initialize(uint32 updateInterval) diff --git a/src/server/authserver/Realms/RealmList.h b/src/server/authserver/Realms/RealmList.h index ab453720827..c4a6b4eaa0b 100644 --- a/src/server/authserver/Realms/RealmList.h +++ b/src/server/authserver/Realms/RealmList.h @@ -53,6 +53,8 @@ struct Realm uint32 gamebuild; uint8 Region; uint8 Battlegroup; + + ACE_INET_Addr const& GetAddressForClient(ACE_INET_Addr const& clientAddr) const; }; namespace Battlenet diff --git a/src/server/authserver/Server/AuthSocket.cpp b/src/server/authserver/Server/AuthSocket.cpp index 3afce0d77d9..8180967a92e 100644 --- a/src/server/authserver/Server/AuthSocket.cpp +++ b/src/server/authserver/Server/AuthSocket.cpp @@ -293,19 +293,11 @@ void AuthSocket::_SetVSFields(const std::string& rI) x.SetBinary(sha.GetDigest(), sha.GetLength()); v = g.ModExp(x, N); - // No SQL injection (username escaped) - char *v_hex, *s_hex; - v_hex = v.AsHexStr(); - s_hex = s.AsHexStr(); - PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_VS); - stmt->setString(0, v_hex); - stmt->setString(1, s_hex); + stmt->setString(0, v.AsHexStr()); + stmt->setString(1, s.AsHexStr()); stmt->setString(2, _login); LoginDatabase.Execute(stmt); - - OPENSSL_free(v_hex); - OPENSSL_free(s_hex); } // Logon Challenge command handler @@ -650,19 +642,14 @@ bool AuthSocket::_HandleLogonProof() TC_LOG_DEBUG("server.authserver", "'%s:%d' User '%s' successfully authenticated", socket().getRemoteAddress().c_str(), socket().getRemotePort(), _login.c_str()); // Update the sessionkey, last_ip, last login time and reset number of failed logins in the account table for this account - // No SQL injection (escaped user name) and IP address as received by socket - const char *K_hex = K.AsHexStr(); - PreparedStatement *stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_LOGONPROOF); - stmt->setString(0, K_hex); + stmt->setString(0, K.AsHexStr()); stmt->setString(1, socket().getRemoteAddress().c_str()); stmt->setUInt32(2, GetLocaleByName(_localizationName)); stmt->setString(3, _os); stmt->setString(4, _login); LoginDatabase.DirectExecute(stmt); - OPENSSL_free((void*)K_hex); - // Finish SRP6 and send the final result to the client sha.Initialize(); sha.UpdateBigNumbers(&A, &M, &K, NULL); @@ -879,28 +866,6 @@ bool AuthSocket::_HandleReconnectProof() } } -ACE_INET_Addr const& AuthSocket::GetAddressForClient(Realm const& realm, ACE_INET_Addr const& clientAddr) -{ - // Attempt to send best address for client - if (clientAddr.is_loopback()) - { - // Try guessing if realm is also connected locally - if (realm.LocalAddress.is_loopback() || realm.ExternalAddress.is_loopback()) - return clientAddr; - - // Assume that user connecting from the machine that authserver is located on - // has all realms available in his local network - return realm.LocalAddress; - } - - // Check if connecting client is in the same network - if (IsIPAddrInNetwork(realm.LocalAddress, clientAddr, realm.LocalSubnetMask)) - return realm.LocalAddress; - - // Return external IP - return realm.ExternalAddress; -} - // Realm List command handler bool AuthSocket::_HandleRealmList() { @@ -981,7 +946,7 @@ bool AuthSocket::_HandleRealmList() pkt << lock; // if 1, then realm locked pkt << uint8(flag); // RealmFlags pkt << name; - pkt << GetAddressString(GetAddressForClient(realm, clientAddr)); + pkt << GetAddressString(realm.GetAddressForClient(clientAddr)); pkt << realm.populationLevel; pkt << AmountOfCharacters; pkt << realm.timezone; // realm category diff --git a/src/server/authserver/Server/AuthSocket.h b/src/server/authserver/Server/AuthSocket.h index 5e04d459ba1..e81944389ef 100644 --- a/src/server/authserver/Server/AuthSocket.h +++ b/src/server/authserver/Server/AuthSocket.h @@ -39,8 +39,6 @@ public: virtual void OnAccept(void); virtual void OnClose(void); - static ACE_INET_Addr const& GetAddressForClient(Realm const& realm, ACE_INET_Addr const& clientAddr); - bool _HandleLogonChallenge(); bool _HandleLogonProof(); bool _HandleReconnectChallenge(); diff --git a/src/server/authserver/Server/BattlenetSocket.cpp b/src/server/authserver/Server/BattlenetSocket.cpp index 12b02b5963e..258ae371075 100644 --- a/src/server/authserver/Server/BattlenetSocket.cpp +++ b/src/server/authserver/Server/BattlenetSocket.cpp @@ -94,35 +94,12 @@ void Battlenet::Socket::_SetVSFields(std::string const& pstr) x.SetBinary(sha.GetDigest(), sha.GetLength()); v = g.ModExp(x, N); - char* v_hex = v.AsHexStr(); - char* s_hex = s.AsHexStr(); + PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_BNET_VS_FIELDS); + stmt->setString(0, v.AsHexStr()); + stmt->setString(1, s.AsHexStr()); + stmt->setString(2, _accountName); - LoginDatabase.PExecute("UPDATE battlenet_accounts SET s = '%s', v = '%s' WHERE email ='%s'", s_hex, v_hex, _accountName.c_str()); - - OPENSSL_free(v_hex); - OPENSSL_free(s_hex); -} - -ACE_INET_Addr const& Battlenet::Socket::GetAddressForClient(Realm const& realm, ACE_INET_Addr const& clientAddr) -{ - // Attempt to send best address for client - if (clientAddr.is_loopback()) - { - // Try guessing if realm is also connected locally - if (realm.LocalAddress.is_loopback() || realm.ExternalAddress.is_loopback()) - return clientAddr; - - // Assume that user connecting from the machine that authserver is located on - // has all realms available in his local network - return realm.LocalAddress; - } - - // Check if connecting client is in the same network - if (IsIPAddrInNetwork(realm.LocalAddress, clientAddr, realm.LocalSubnetMask)) - return realm.LocalAddress; - - // Return external IP - return realm.ExternalAddress; + LoginDatabase.Execute(stmt); } bool Battlenet::Socket::HandleAuthChallenge(PacketHeader& header, BitStream& packet) @@ -425,7 +402,7 @@ bool Battlenet::Socket::HandleRealmUpdateSubscribe(PacketHeader& /*header*/, Bit version << buildInfo->MajorVersion << '.' << buildInfo->MinorVersion << '.' << buildInfo->BugfixVersion << '.' << buildInfo->HotfixVersion; update->Version = version.str(); - update->Address = GetAddressForClient(realm, clientAddr); + update->Address = realm.GetAddressForClient(clientAddr); update->Build = realm.gamebuild; } @@ -821,7 +798,7 @@ bool Battlenet::Socket::HandleRiskFingerprintModule(BitStream* dataStream, Serve complete->GameAccountName = str.str(); complete->AccountFlags = 0x800000; // 0x1 IsGMAccount, 0x8 IsTrialAccount, 0x800000 IsProPassAccount - PreparedStatement *stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_BNET_LAST_LOGIN_INFO); + PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_BNET_LAST_LOGIN_INFO); stmt->setString(0, _socket.getRemoteAddress()); stmt->setUInt8(1, GetLocaleByName(_locale)); stmt->setString(2, _os); @@ -832,7 +809,7 @@ bool Battlenet::Socket::HandleRiskFingerprintModule(BitStream* dataStream, Serve complete->SetAuthResult(AUTH_BAD_VERSION_HASH); ReplaceResponse(response, complete); - return false; + return true; } bool Battlenet::Socket::UnhandledModule(BitStream* /*dataStream*/, ServerPacket** response) diff --git a/src/server/authserver/Server/BattlenetSocket.h b/src/server/authserver/Server/BattlenetSocket.h index ef6157b022a..ff441b19cdd 100644 --- a/src/server/authserver/Server/BattlenetSocket.h +++ b/src/server/authserver/Server/BattlenetSocket.h @@ -47,7 +47,7 @@ namespace Battlenet static uint32 const SRP6_V_Size; static uint32 const SRP6_S_Size; - Socket(RealmSocket& socket); + explicit Socket(RealmSocket& socket); typedef bool(Socket::*PacketHandler)(PacketHeader& socket, BitStream& packet); @@ -71,7 +71,6 @@ namespace Battlenet private: void _SetVSFields(std::string const& rI); - static ACE_INET_Addr const& GetAddressForClient(Realm const& realm, ACE_INET_Addr const& clientAddr); typedef bool(Socket::*ModuleHandler)(BitStream* dataStream, ServerPacket** response); static ModuleHandler const ModuleHandlers[MODULE_COUNT]; diff --git a/src/server/shared/Cryptography/BigNumber.cpp b/src/server/shared/Cryptography/BigNumber.cpp index 1f3fc96e28d..1c82314bdba 100644 --- a/src/server/shared/Cryptography/BigNumber.cpp +++ b/src/server/shared/Cryptography/BigNumber.cpp @@ -190,13 +190,19 @@ ACE_Auto_Array_Ptr BigNumber::AsByteArray(int32 minSize, bool littleEndia return ret; } -char * BigNumber::AsHexStr() const +std::string BigNumber::AsHexStr() const { - return BN_bn2hex(_bn); + char* ch = BN_bn2hex(_bn); + std::string ret = ch; + OPENSSL_free(ch); + return ret; } -char * BigNumber::AsDecStr() const +std::string BigNumber::AsDecStr() const { - return BN_bn2dec(_bn); + char* ch = BN_bn2dec(_bn); + std::string ret = ch; + OPENSSL_free(ch); + return ret; } diff --git a/src/server/shared/Cryptography/BigNumber.h b/src/server/shared/Cryptography/BigNumber.h index dc553babec9..7de53b442ae 100644 --- a/src/server/shared/Cryptography/BigNumber.h +++ b/src/server/shared/Cryptography/BigNumber.h @@ -21,6 +21,7 @@ #include "Define.h" #include +#include struct bignum_st; @@ -89,8 +90,8 @@ class BigNumber ACE_Auto_Array_Ptr AsByteArray(int32 minSize = 0, bool littleEndian = true); - char * AsHexStr() const; - char * AsDecStr() const; + std::string AsHexStr() const; + std::string AsDecStr() const; private: struct bignum_st *_bn; diff --git a/src/server/shared/Database/Implementation/LoginDatabase.cpp b/src/server/shared/Database/Implementation/LoginDatabase.cpp index 208873448c6..a54557310e1 100644 --- a/src/server/shared/Database/Implementation/LoginDatabase.cpp +++ b/src/server/shared/Database/Implementation/LoginDatabase.cpp @@ -106,6 +106,7 @@ void LoginDatabaseConnection::DoPrepareStatements() PrepareStatement(LOGIN_SEL_BNET_ACCOUNT_INFO, "SELECT sha_pass_hash, id, locked, lock_country, last_ip, v, s FROM battlenet_accounts WHERE email = ?", CONNECTION_SYNCH); PrepareStatement(LOGIN_DEL_BNET_EXPIRED_BANS, "UPDATE battlenet_account_bans SET active = 0 WHERE active = 1 AND unbandate <> bandate AND unbandate <= UNIX_TIMESTAMP()", CONNECTION_SYNCH); PrepareStatement(LOGIN_SEL_BNET_ACTIVE_ACCOUNT_BAN, "SELECT bandate, unbandate FROM battlenet_account_bans WHERE id = ? AND active = 1", CONNECTION_SYNCH); + PrepareStatement(LOGIN_UPD_BNET_VS_FIELDS, "UPDATE battlenet_accounts SET v = ?, s = ? WHERE email = ?", CONNECTION_ASYNC); PrepareStatement(LOGIN_SEL_BNET_GAME_ACCOUNTS, "SELECT a.username, a.id, ab.bandate, ab.unbandate, ab.active FROM account a LEFT JOIN account_banned ab ON a.id = ab.id WHERE battlenet_account = ?", CONNECTION_SYNCH); PrepareStatement(LOGIN_SEL_BNET_GAME_ACCOUNT, "SELECT a.id, ab.bandate, ab.unbandate, ab.active FROM account a LEFT JOIN account_banned ab ON a.id = ab.id WHERE username = ? AND battlenet_account = ?", CONNECTION_SYNCH); PrepareStatement(LOGIN_UPD_BNET_LAST_LOGIN_INFO, "UPDATE battlenet_accounts SET last_ip = ?, last_login = NOW(), locale = ?, failed_logins = 0, os = ? WHERE id = ?", CONNECTION_ASYNC); @@ -114,5 +115,5 @@ void LoginDatabaseConnection::DoPrepareStatements() PrepareStatement(LOGIN_SEL_BNET_ACCOUNT_EMAIL_BY_ID, "SELECT email FROM battlenet_accounts WHERE id = ?", CONNECTION_SYNCH); PrepareStatement(LOGIN_SEL_BNET_ACCOUNT_ID_BY_EMAIL, "SELECT id FROM battlenet_accounts WHERE email = ?", CONNECTION_SYNCH); PrepareStatement(LOGIN_UPD_BNET_PASSWORD, "UPDATE account SET v = '', s = '', username = ?, sha_pass_hash = ? WHERE id = ?", CONNECTION_ASYNC); - PrepareStatement(LOGIN_SEL_BNET_CHECK_PASSWORD, "SELECT 1 FROM battlenet_accounts WHERE id = %u AND sha_pass_hash = ?", CONNECTION_ASYNC); + PrepareStatement(LOGIN_SEL_BNET_CHECK_PASSWORD, "SELECT 1 FROM battlenet_accounts WHERE id = ? AND sha_pass_hash = ?", CONNECTION_ASYNC); } diff --git a/src/server/shared/Database/Implementation/LoginDatabase.h b/src/server/shared/Database/Implementation/LoginDatabase.h index 18f9110409d..fff7a36766c 100644 --- a/src/server/shared/Database/Implementation/LoginDatabase.h +++ b/src/server/shared/Database/Implementation/LoginDatabase.h @@ -125,6 +125,7 @@ enum LoginDatabaseStatements LOGIN_SEL_BNET_ACCOUNT_INFO, LOGIN_DEL_BNET_EXPIRED_BANS, LOGIN_SEL_BNET_ACTIVE_ACCOUNT_BAN, + LOGIN_UPD_BNET_VS_FIELDS, LOGIN_SEL_BNET_GAME_ACCOUNTS, LOGIN_SEL_BNET_GAME_ACCOUNT, LOGIN_UPD_BNET_LAST_LOGIN_INFO, -- cgit v1.2.3 From bdd6e9aa8aeeda439a2a3a8f23bc21bb04699133 Mon Sep 17 00:00:00 2001 From: Shauren Date: Sun, 1 Jun 2014 13:56:36 +0200 Subject: Core/Battle.net: Implemented reconnects --- sql/base/auth_database.sql | 7 +- sql/updates/auth/2014_xx_xx_01_auth_battlenet.sql | 8 + src/server/authserver/Server/BattlenetPackets.cpp | 149 +++++++++++++++--- src/server/authserver/Server/BattlenetPackets.h | 54 ++++++- src/server/authserver/Server/BattlenetSocket.cpp | 173 ++++++++++++++++++++- src/server/authserver/Server/BattlenetSocket.h | 7 + .../Database/Implementation/LoginDatabase.cpp | 2 + .../shared/Database/Implementation/LoginDatabase.h | 2 + 8 files changed, 375 insertions(+), 27 deletions(-) create mode 100644 sql/updates/auth/2014_xx_xx_01_auth_battlenet.sql (limited to 'src/server/shared/Database/Implementation') diff --git a/sql/base/auth_database.sql b/sql/base/auth_database.sql index f610bac2b6a..2d217dabe91 100644 --- a/sql/base/auth_database.sql +++ b/sql/base/auth_database.sql @@ -176,6 +176,7 @@ CREATE TABLE `battlenet_accounts` ( `sha_pass_hash` varchar(64) NOT NULL DEFAULT '', `v` varchar(256) NOT NULL DEFAULT '', `s` varchar(64) NOT NULL DEFAULT '', + `sessionKey` varchar(128) NOT NULL DEFAULT '', `joindate` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, `last_ip` varchar(15) NOT NULL DEFAULT '127.0.0.1', `failed_logins` int(10) unsigned NOT NULL DEFAULT '0', @@ -272,7 +273,11 @@ INSERT INTO `battlenet_modules` VALUES ('b37136b39add83cfdbafa81857de3dd8f15b34e0135ec6cd9c3131d3a578d8c2','Thumbprint','auth','Mc64','E716F4F0A01EB9C032A6C1393356A4F766F067949D71023C0CFC0613718966EF814E65CC6EE70C432A7F8AFD8A062B52603A2697E851D231D72C0277614181D713369B1E8E4BEEAB72045A9AAD45F319DB918ECDDB83C8EF8B7510600D391D45E7FEC0BEEAE904A5F9FA620F1CCDAD699D84A4739CE669B5A551831E396214E13B4C88F573F5CDC784CD01530C086B674C03BEB66403A0F87ED17ABBB403DE54CF31BE828A20C566C22E4D4263AA77220B0644D99245345BCAC276EA06925EB984D664725C3CB757140AFE12E27CB996F17159B1057E9B58B78BBB5A139C9FF6215A0D250B75FC9DD435655DDEADCD6CFD84800792C146B3633188ECEB53D2038C185E0BD51A9E6C70FD38ADF530F8DF50FB62053C5E894897AB7DD65C7AC80665F18E7989BE6E30F15E939751123D6D8A44F033175301D15AAAD2AEA06FAC60BA4065846AE938F32B1CB15F16DC0E76792A7332346896048065D17C059899E1D2300E402BD0EA74265DA6A42B1C854E2470D7B21AE4A2DAE90E602A759B2CA0EE610B50D5389DB89335D5451FE76DD85B09FD5297D6F9EFB6C34CE885007F7DF20D6A524E0C3E772FA04B3DD2E014D3A337A790943DAD523CBB5453F4FDF8E74DFE361BD5F25AB31952B478148B570DF5762643F32B994FEC99A747E4A265A66EE84A53509EC285C84679606049314FC526C61B537AC8061C788F8B86F52208'), ('c0f38d05aa1b83065e839c9bd96c831e9f7e42477085138752657a6a9bb9c520','RiskFingerprint','auth','Mac',NULL), ('c3a1ac0694979e709c3b5486927e558af1e2be02ca96e5615c5a65aacc829226','Thumbprint','auth','Wn64','E716F4F0A01EB9C032A6C1393356A4F766F067949D71023C0CFC0613718966EF814E65CC6EE70C432A7F8AFD8A062B52603A2697E851D231D72C0277614181D713369B1E8E4BEEAB72045A9AAD45F319DB918ECDDB83C8EF8B7510600D391D45E7FEC0BEEAE904A5F9FA620F1CCDAD699D84A4739CE669B5A551831E396214E13B4C88F573F5CDC784CD01530C086B674C03BEB66403A0F87ED17ABBB403DE54CF31BE828A20C566C22E4D4263AA77220B0644D99245345BCAC276EA06925EB984D664725C3CB757140AFE12E27CB996F17159B1057E9B58B78BBB5A139C9FF6215A0D250B75FC9DD435655DDEADCD6CFD84800792C146B3633188ECEB53D2038C185E0BD51A9E6C70FD38ADF530F8DF50FB62053C5E894897AB7DD65C7AC80665F18E7989BE6E30F15E939751123D6D8A44F033175301D15AAAD2AEA06FAC60BA4065846AE938F32B1CB15F16DC0E76792A7332346896048065D17C059899E1D2300E402BD0EA74265DA6A42B1C854E2470D7B21AE4A2DAE90E602A759B2CA0EE610B50D5389DB89335D5451FE76DD85B09FD5297D6F9EFB6C34CE885007F7DF20D6A524E0C3E772FA04B3DD2E014D3A337A790943DAD523CBB5453F4FDF8E74DFE361BD5F25AB31952B478148B570DF5762643F32B994FEC99A747E4A265A66EE84A53509EC285C84679606049314FC526C61B537AC8061C788F8B86F52208'), -('fbe675a99fb5f4b7fb3eb5e5a22add91a4cabf83e3c5930c6659ad13c457ba18','Token','auth','Win',NULL); +('fbe675a99fb5f4b7fb3eb5e5a22add91a4cabf83e3c5930c6659ad13c457ba18','Token','auth','Win',NULL), +('bfe4ceb47700aa872e815e007e27df955d4cd4bc1fe731039ee6498ce209f368','Resume','auth','Win',NULL), +('00ffd88a437afbb88d7d4b74be2e3b43601605ee229151aa9f4bebb29ef66280','Resume','auth','Mac',NULL), +('898166926805f897804bdbbf40662c9d768590a51a0b26c40dbcdf332ba11974','Resume','auth','Wn64',NULL), +('304627d437c38500c0b5ca0c6220eeade91390e52a2b005ff3f7754afa1f93cd','Resume','auth','Mc64',NULL); /*!40000 ALTER TABLE `battlenet_modules` ENABLE KEYS */; UNLOCK TABLES; diff --git a/sql/updates/auth/2014_xx_xx_01_auth_battlenet.sql b/sql/updates/auth/2014_xx_xx_01_auth_battlenet.sql new file mode 100644 index 00000000000..ee88c91b323 --- /dev/null +++ b/sql/updates/auth/2014_xx_xx_01_auth_battlenet.sql @@ -0,0 +1,8 @@ +ALTER TABLE `battlenet_accounts` ADD `sessionKey` VARCHAR(128) NOT NULL DEFAULT '' AFTER `s`; + +DELETE FROM `battlenet_modules` WHERE `Name`='Resume'; +INSERT INTO `battlenet_modules` VALUES +('bfe4ceb47700aa872e815e007e27df955d4cd4bc1fe731039ee6498ce209f368','Resume','auth','Win',NULL), +('00ffd88a437afbb88d7d4b74be2e3b43601605ee229151aa9f4bebb29ef66280','Resume','auth','Mac',NULL), +('898166926805f897804bdbbf40662c9d768590a51a0b26c40dbcdf332ba11974','Resume','auth','Wn64',NULL), +('304627d437c38500c0b5ca0c6220eeade91390e52a2b005ff3f7754afa1f93cd','Resume','auth','Mc64',NULL); diff --git a/src/server/authserver/Server/BattlenetPackets.cpp b/src/server/authserver/Server/BattlenetPackets.cpp index 99e3fa10b14..471a6128c4c 100644 --- a/src/server/authserver/Server/BattlenetPackets.cpp +++ b/src/server/authserver/Server/BattlenetPackets.cpp @@ -57,9 +57,6 @@ void Battlenet::AuthChallenge::Read() if (_stream.Read(1)) Login = _stream.ReadString(9, 3); - - if (GetHeader().Opcode == CMSG_AUTH_CHALLENGE_NEW) - _stream.FinishReading(); } std::string Battlenet::AuthChallenge::ToString() const @@ -75,6 +72,40 @@ std::string Battlenet::AuthChallenge::ToString() const return stream.str(); } +void Battlenet::AuthResumeInfo::Read() +{ + Program = _stream.ReadFourCC(); + Platform = _stream.ReadFourCC(); + Locale = _stream.ReadFourCC(); + + Components.resize(_stream.Read(6)); + for (size_t i = 0; i < Components.size(); ++i) + { + Component& component = Components[i]; + component.Program = _stream.ReadFourCC(); + component.Platform = _stream.ReadFourCC(); + component.Build = _stream.Read(32); + } + + Login = _stream.ReadString(9, 3); + Region = _stream.Read(8); + GameAccountName = _stream.ReadString(5, 1); +} + +std::string Battlenet::AuthResumeInfo::ToString() const +{ + std::ostringstream stream; + stream << "Battlenet::AuthReconnect Program: " << Program << ", Platform: " << Platform << ", Locale: " << Locale; + for (Component const& component : Components) + stream << std::endl << "Battlenet::Component Program: " << component.Program << ", Platform: " << component.Platform << ", Build: " << component.Build; + + stream << std::endl << "Battlenet::AuthReconnect Login: " << Login; + stream << std::endl << "Battlenet::AuthReconnect Region: " << uint32(Region); + stream << std::endl << "Battlenet::AuthReconnect GameAccountName: " << GameAccountName; + + return stream.str(); +} + Battlenet::ProofRequest::~ProofRequest() { for (size_t i = 0; i < Modules.size(); ++i) @@ -134,6 +165,12 @@ std::string Battlenet::ProofResponse::ToString() const return stream.str(); } +Battlenet::AuthComplete::~AuthComplete() +{ + for (ModuleInfo* m : Modules) + delete m; +} + void Battlenet::AuthComplete::Write() { _stream.Write(Result != 0, 1); @@ -142,12 +179,12 @@ void Battlenet::AuthComplete::Write() _stream.Write(Modules.size(), 3); for (size_t i = 0; i < Modules.size(); ++i) { - ModuleInfo& info = Modules[i]; - _stream.WriteBytes(info.Type.c_str(), 4); - _stream.WriteFourCC(info.Region); - _stream.WriteBytes(info.ModuleId, 32); - _stream.Write(info.DataSize, 10); - _stream.WriteBytes(info.Data, info.DataSize); + ModuleInfo* info = Modules[i]; + _stream.WriteBytes(info->Type.c_str(), 4); + _stream.WriteFourCC(info->Region); + _stream.WriteBytes(info->ModuleId, 32); + _stream.Write(info->DataSize, 10); + _stream.WriteBytes(info->Data, info->DataSize); } _stream.Write(PingTimeout + std::numeric_limits::min(), 32); @@ -168,10 +205,10 @@ void Battlenet::AuthComplete::Write() _stream.Write(GameAccountId, 32); _stream.Write(2, 8); _stream.Write(0, 64); - _stream.Write(2, 8); + _stream.Write(2, 8); _stream.WriteString(GameAccountName, 5, -1); - _stream.Write(AccountFlags, 64); + _stream.Write(GameAccountFlags, 64); _stream.Write(0, 32); } @@ -180,12 +217,10 @@ void Battlenet::AuthComplete::Write() _stream.Write(!Modules.empty(), 1); if (!Modules.empty()) { - ModuleInfo& info = Modules[0]; - _stream.WriteBytes(info.Type.c_str(), 4); - _stream.WriteFourCC(info.Region); - _stream.WriteBytes(info.ModuleId, 32); - _stream.Write(info.DataSize, 10); - _stream.WriteBytes(info.Data, info.DataSize); + ModuleInfo* info = Modules[0]; + _stream.WriteBytes(info->Type.c_str(), 4); + _stream.WriteFourCC(info->Region); + _stream.WriteBytes(info->ModuleId, 32); } _stream.Write(ErrorType, 2); @@ -199,7 +234,15 @@ void Battlenet::AuthComplete::Write() std::string Battlenet::AuthComplete::ToString() const { - return "Battlenet::AuthComplete"; + std::ostringstream stream; + stream << "Battlenet::AuthComplete AuthResult " << Result << " PingTimeout " << PingTimeout << " Threshold " << Threshold << " Rate " << Rate + << " FirstName " << FirstName << " LastName " << LastName << " GameAccountId " << GameAccountId << " GameAccountName " << GameAccountName + << " GameAccountFlags " << GameAccountFlags << " Modules " << Modules.size(); + + for (ModuleInfo const* module : Modules) + stream << std::endl << "Battlenet::ModuleInfo Locale " << module->Region.c_str() << ", ModuleId " << ByteArrayToHexStr(module->ModuleId, 32) << ", DataSize " << module->DataSize << ", Data " << ByteArrayToHexStr(module->Data, module->DataSize); + + return stream.str(); } void Battlenet::AuthComplete::SetAuthResult(AuthResult result) @@ -208,6 +251,76 @@ void Battlenet::AuthComplete::SetAuthResult(AuthResult result) Result = result; } +Battlenet::AuthResume::~AuthResume() +{ + for (ModuleInfo* m : Modules) + delete m; +} + +void Battlenet::AuthResume::Write() +{ + _stream.Write(Result != 0, 1); + if (Result == 0) + { + _stream.Write(Modules.size(), 3); + for (size_t i = 0; i < Modules.size(); ++i) + { + ModuleInfo* info = Modules[i]; + _stream.WriteBytes(info->Type.c_str(), 4); + _stream.WriteFourCC(info->Region); + _stream.WriteBytes(info->ModuleId, 32); + _stream.Write(info->DataSize, 10); + _stream.WriteBytes(info->Data, info->DataSize); + } + + _stream.Write(PingTimeout + std::numeric_limits::min(), 32); + _stream.Write(1, 1); + // if written == 1 + { + _stream.Write(1, 1); + // if written == 1 + { + _stream.Write(Threshold, 32); + _stream.Write(Rate, 32); + } + } + } + else + { + _stream.Write(!Modules.empty(), 1); + if (!Modules.empty()) + { + ModuleInfo* info = Modules[0]; + _stream.WriteBytes(info->Type.c_str(), 4); + _stream.WriteFourCC(info->Region); + _stream.WriteBytes(info->ModuleId, 32); + } + + _stream.Write(ErrorType, 2); + if (ErrorType == 1) + { + _stream.Write(Result, 16); + _stream.Write(0x80000000, 32); + } + } +} + +std::string Battlenet::AuthResume::ToString() const +{ + std::ostringstream stream; + stream << "Battlenet::AuthResume AuthResult " << Result << " PingTimeout " << PingTimeout << " Threshold " << Threshold << " Rate " << Rate << " Modules " << Modules.size(); + for (ModuleInfo const* module : Modules) + stream << std::endl << "Battlenet::ModuleInfo Locale " << module->Region.c_str() << ", ModuleId " << ByteArrayToHexStr(module->ModuleId, 32) << ", DataSize " << module->DataSize << ", Data " << ByteArrayToHexStr(module->Data, module->DataSize); + + return stream.str(); +} + +void Battlenet::AuthResume::SetAuthResult(AuthResult result) +{ + ErrorType = result != AUTH_OK ? 1 : 0; + Result = result; +} + Battlenet::RealmCharacterCounts::~RealmCharacterCounts() { for (ServerPacket* realmData : RealmData) diff --git a/src/server/authserver/Server/BattlenetPackets.h b/src/server/authserver/Server/BattlenetPackets.h index 9acc707bd10..d790760ea24 100644 --- a/src/server/authserver/Server/BattlenetPackets.h +++ b/src/server/authserver/Server/BattlenetPackets.h @@ -41,9 +41,9 @@ namespace Battlenet CMSG_AUTH_CHALLENGE = 0x0, CMSG_AUTH_RECONNECT = 0x1, CMSG_AUTH_PROOF_RESPONSE = 0x2, - CMSG_AUTH_CHALLENGE_NEW = 0x9, // MoP SMSG_AUTH_COMPLETE = 0x0, + SMSG_AUTH_RESUME = 0x1, SMSG_AUTH_PROOF_REQUEST = 0x2 }; @@ -51,6 +51,7 @@ namespace Battlenet { CMSG_PING = 0x0, CMSG_ENABLE_ENCRYPTION = 0x5, + CMSG_DISCONNECT = 0x6, CMSG_INVALID_PACKET = 0x9, SMSG_PONG = 0x0 @@ -141,7 +142,7 @@ namespace Battlenet public: AuthChallenge(PacketHeader const& header, BitStream& stream) : ClientPacket(header, stream) { - ASSERT(header.Channel == AUTHENTICATION && (header.Opcode == CMSG_AUTH_CHALLENGE || header.Opcode == CMSG_AUTH_CHALLENGE_NEW) && "Invalid packet header for AuthChallenge"); + ASSERT(header == PacketHeader(CMSG_AUTH_CHALLENGE, AUTHENTICATION) && "Invalid packet header for AuthChallenge"); } void Read() override; @@ -154,6 +155,26 @@ namespace Battlenet std::string Login; }; + class AuthResumeInfo final : public ClientPacket + { + public: + AuthResumeInfo(PacketHeader const& header, BitStream& stream) : ClientPacket(header, stream) + { + ASSERT(header == PacketHeader(CMSG_AUTH_RECONNECT, AUTHENTICATION) && "Invalid packet header for AuthResumeInfo"); + } + + void Read() override; + std::string ToString() const override; + + std::string Program; + std::string Platform; + std::string Locale; + std::vector Components; + std::string Login; + uint8 Region; + std::string GameAccountName; + }; + class ProofRequest final : public ServerPacket { public: @@ -191,10 +212,12 @@ namespace Battlenet { } + ~AuthComplete(); + void Write() override; std::string ToString() const override; - std::vector Modules; + std::vector Modules; void SetAuthResult(AuthResult result); AuthResult Result; uint32 ErrorType; @@ -206,7 +229,30 @@ namespace Battlenet std::string LastName; uint32 GameAccountId; std::string GameAccountName; - uint64 AccountFlags; + uint64 GameAccountFlags; + }; + + class AuthResume final : public ServerPacket + { + public: + AuthResume() : ServerPacket(PacketHeader(SMSG_AUTH_RESUME, AUTHENTICATION)), + Result(AUTH_OK), ErrorType(0), PingTimeout(120000), Threshold(25000000), Rate(1000) + { + } + + ~AuthResume(); + + void Write() override; + std::string ToString() const override; + + std::vector Modules; + void SetAuthResult(AuthResult result); + AuthResult Result; + uint32 ErrorType; + + int32 PingTimeout; + uint32 Threshold; + uint32 Rate; }; class Pong final : public ServerPacket diff --git a/src/server/authserver/Server/BattlenetSocket.cpp b/src/server/authserver/Server/BattlenetSocket.cpp index 258ae371075..119fccd9abb 100644 --- a/src/server/authserver/Server/BattlenetSocket.cpp +++ b/src/server/authserver/Server/BattlenetSocket.cpp @@ -33,11 +33,12 @@ std::map InitHandlers std::map handlers; handlers[Battlenet::PacketHeader(Battlenet::CMSG_AUTH_CHALLENGE, Battlenet::AUTHENTICATION)] = &Battlenet::Socket::HandleAuthChallenge; - handlers[Battlenet::PacketHeader(Battlenet::CMSG_AUTH_CHALLENGE_NEW, Battlenet::AUTHENTICATION)] = &Battlenet::Socket::HandleAuthChallenge; + handlers[Battlenet::PacketHeader(Battlenet::CMSG_AUTH_RECONNECT, Battlenet::AUTHENTICATION)] = &Battlenet::Socket::HandleAuthReconnect; handlers[Battlenet::PacketHeader(Battlenet::CMSG_AUTH_PROOF_RESPONSE, Battlenet::AUTHENTICATION)] = &Battlenet::Socket::HandleAuthProofResponse; handlers[Battlenet::PacketHeader(Battlenet::CMSG_PING, Battlenet::CREEP)] = &Battlenet::Socket::HandlePing; handlers[Battlenet::PacketHeader(Battlenet::CMSG_ENABLE_ENCRYPTION, Battlenet::CREEP)] = &Battlenet::Socket::HandleEnableEncryption; + handlers[Battlenet::PacketHeader(Battlenet::CMSG_DISCONNECT, Battlenet::CREEP)] = &Battlenet::Socket::HandleDisconnect; handlers[Battlenet::PacketHeader(Battlenet::CMSG_REALM_UPDATE_SUBSCRIBE, Battlenet::WOW)] = &Battlenet::Socket::HandleRealmUpdateSubscribe; handlers[Battlenet::PacketHeader(Battlenet::CMSG_JOIN_REQUEST, Battlenet::WOW)] = &Battlenet::Socket::HandleRealmJoinRequest; @@ -54,10 +55,12 @@ Battlenet::Socket::ModuleHandler const Battlenet::Socket::ModuleHandlers[MODULE_ &Battlenet::Socket::UnhandledModule, &Battlenet::Socket::HandleSelectGameAccountModule, &Battlenet::Socket::HandleRiskFingerprintModule, + &Battlenet::Socket::HandleResumeModule, }; Battlenet::Socket::Socket(RealmSocket& socket) : _socket(socket), _accountId(0), _accountName(), _locale(), - _os(), _build(0), _gameAccountId(0), _accountSecurityLevel(SEC_PLAYER) + _os(), _build(0), _gameAccountId(0), _accountSecurityLevel(SEC_PLAYER), I(), s(), v(), b(), B(), K(), + _reconnectProof(), _crypt(), _authed(false) { static uint8 const N_Bytes[] = { @@ -304,6 +307,61 @@ bool Battlenet::Socket::HandleAuthChallenge(PacketHeader& header, BitStream& pac return true; } +bool Battlenet::Socket::HandleAuthReconnect(PacketHeader& header, BitStream& packet) +{ + AuthResumeInfo reconnect(header, packet); + reconnect.Read(); + + TC_LOG_DEBUG("server.battlenet", "%s", reconnect.ToString().c_str()); + + _accountName = reconnect.Login; + _locale = reconnect.Locale; + _os = reconnect.Platform; + auto baseComponent = std::find_if(reconnect.Components.begin(), reconnect.Components.end(), [](Component const& c) { return c.Program == "base"; }); + if (baseComponent != reconnect.Components.end()) + _build = baseComponent->Build; + + Utf8ToUpperOnlyLatin(_accountName); + PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_BNET_RECONNECT_INFO); + stmt->setString(0, _accountName); + stmt->setString(1, reconnect.GameAccountName.c_str()); + PreparedQueryResult result = LoginDatabase.Query(stmt); + if (!result) + { + AuthResume resume; + resume.SetAuthResult(AUTH_UNKNOWN_ACCOUNT); + Send(resume); + return false; + } + + Field* fields = result->Fetch(); + + _accountId = fields[0].GetUInt32(); + K.SetHexStr(fields[1].GetString().c_str()); + _gameAccountId = fields[2].GetUInt32(); + + ModuleInfo* thumbprint = sBattlenetMgr->CreateModule(_os, "Thumbprint"); + ModuleInfo* resume = sBattlenetMgr->CreateModule(_os, "Resume"); + BitStream resumeData; + uint8 state = 0; + _reconnectProof.SetRand(16 * 8); + + resumeData.WriteBytes(&state, 1); + resumeData.WriteBytes(_reconnectProof.AsByteArray().get(), 16); + + resume->DataSize = resumeData.GetSize(); + resume->Data = new uint8[resume->DataSize]; + memcpy(resume->Data, resumeData.GetBuffer(), resume->DataSize); + + _modulesWaitingForData.push(MODULE_RESUME); + + ProofRequest request; + request.Modules.push_back(thumbprint); + request.Modules.push_back(resume); + Send(request); + return true; +} + bool Battlenet::Socket::HandleAuthProofResponse(PacketHeader& header, BitStream& packet) { ProofResponse proof(header, packet); @@ -350,6 +408,15 @@ bool Battlenet::Socket::HandleEnableEncryption(PacketHeader& /*header*/, BitStre return true; } +bool Battlenet::Socket::HandleDisconnect(PacketHeader& /*header*/, BitStream& /*packet*/) +{ + PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_BNET_SESSION_KEY); + stmt->setString(0, ""); + stmt->setUInt32(1, _accountId); + LoginDatabase.Execute(stmt); + return true; +} + bool Battlenet::Socket::HandleRealmUpdateSubscribe(PacketHeader& /*header*/, BitStream& /*packet*/) { sRealmList->UpdateIfNeed(); @@ -484,6 +551,13 @@ void Battlenet::Socket::OnRead() if (packet.Read(1)) header.Channel = packet.Read(4); + if (header.Channel != AUTHENTICATION && !_authed) + { + TC_LOG_DEBUG("server.battlenet", "Battlenet::Socket::OnRead Received not allowed packet %s", header.ToString().c_str()); + _socket.shutdown(); + return; + } + TC_LOG_TRACE("server.battlenet", "Battlenet::Socket::OnRead %s", header.ToString().c_str()); std::map::const_iterator itr = Handlers.find(header); if (itr != Handlers.end()) @@ -796,14 +870,25 @@ bool Battlenet::Socket::HandleRiskFingerprintModule(BitStream* dataStream, Serve complete->GameAccountId = _gameAccountId; complete->GameAccountName = str.str(); - complete->AccountFlags = 0x800000; // 0x1 IsGMAccount, 0x8 IsTrialAccount, 0x800000 IsProPassAccount + complete->GameAccountFlags = 1; + + SQLTransaction trans = LoginDatabase.BeginTransaction(); PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_BNET_LAST_LOGIN_INFO); stmt->setString(0, _socket.getRemoteAddress()); stmt->setUInt8(1, GetLocaleByName(_locale)); stmt->setString(2, _os); stmt->setUInt32(3, _accountId); - LoginDatabase.Execute(stmt); + trans->Append(stmt); + + stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_BNET_SESSION_KEY); + stmt->setString(0, K.AsHexStr()); + stmt->setUInt32(1, _accountId); + trans->Append(stmt); + + LoginDatabase.CommitTransaction(trans); + + _authed = true; } else complete->SetAuthResult(AUTH_BAD_VERSION_HASH); @@ -812,6 +897,86 @@ bool Battlenet::Socket::HandleRiskFingerprintModule(BitStream* dataStream, Serve return true; } +bool Battlenet::Socket::HandleResumeModule(BitStream* dataStream, ServerPacket** response) +{ + if (dataStream->Read(8) != 1) + { + AuthResume* complete = new AuthResume(); + complete->SetAuthResult(AUTH_CORRUPTED_MODULE); + ReplaceResponse(response, complete); + return false; + } + + static uint8 const ResumeClient = 0; + static uint8 const ResumeServer = 1; + + ACE_Auto_Array_Ptr&& clientChallenge = dataStream->ReadBytes(16); + ACE_Auto_Array_Ptr&& clientProof = dataStream->ReadBytes(32); + ACE_Auto_Array_Ptr&& serverChallenge = _reconnectProof.AsByteArray(); + ACE_Auto_Array_Ptr&& sessionKey = K.AsByteArray(); + + HmacHash clientPart(64, sessionKey.get(), EVP_sha256(), SHA256_DIGEST_LENGTH); + clientPart.UpdateData(&ResumeClient, 1); + clientPart.UpdateData(clientChallenge.get(), 16); + clientPart.UpdateData(serverChallenge.get(), 16); + clientPart.Finalize(); + + HmacHash serverPart(64, sessionKey.get(), EVP_sha256(), SHA256_DIGEST_LENGTH); + serverPart.UpdateData(&ResumeServer, 1); + serverPart.UpdateData(serverChallenge.get(), 16); + serverPart.UpdateData(clientChallenge.get(), 16); + serverPart.Finalize(); + + uint8 newSessionKey[64]; + memcpy(&newSessionKey[0], clientPart.GetDigest(), clientPart.GetLength()); + memcpy(&newSessionKey[32], serverPart.GetDigest(), serverPart.GetLength()); + + K.SetBinary(newSessionKey, 64); + + HmacHash proof(64, newSessionKey, EVP_sha256(), SHA256_DIGEST_LENGTH); + proof.UpdateData(&ResumeClient, 1); + proof.UpdateData(clientChallenge.get(), 16); + proof.UpdateData(serverChallenge.get(), 16); + proof.Finalize(); + + if (memcmp(proof.GetDigest(), clientProof.get(), serverPart.GetLength())) + { + TC_LOG_DEBUG("server.battlenet", "[Battlenet::Resume] Invalid proof!"); + AuthResume* result = new AuthResume(); + result->SetAuthResult(AUTH_UNKNOWN_ACCOUNT); + ReplaceResponse(response, result); + return false; + } + + PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_BNET_SESSION_KEY); + stmt->setString(0, K.AsHexStr()); + stmt->setUInt32(1, _accountId); + LoginDatabase.Execute(stmt); + + HmacHash serverProof(64, newSessionKey, EVP_sha256(), SHA256_DIGEST_LENGTH); + serverProof.UpdateData(&ResumeServer, 1); + serverProof.UpdateData(serverChallenge.get(), 16); + serverProof.UpdateData(clientChallenge.get(), 16); + serverProof.Finalize(); + + ModuleInfo* resume = sBattlenetMgr->CreateModule(_os, "Resume"); + + BitStream resumeData; + uint8 state = 2; + resumeData.WriteBytes(&state, 1); + resumeData.WriteBytes(serverProof.GetDigest(), serverProof.GetLength()); + + resume->DataSize = resumeData.GetSize(); + resume->Data = new uint8[resume->DataSize]; + memcpy(resume->Data, resumeData.GetBuffer(), resume->DataSize); + + AuthResume* result = new AuthResume(); + result->Modules.push_back(resume); + ReplaceResponse(response, result); + _authed = true; + return true; +} + bool Battlenet::Socket::UnhandledModule(BitStream* /*dataStream*/, ServerPacket** response) { AuthComplete* complete = new AuthComplete(); diff --git a/src/server/authserver/Server/BattlenetSocket.h b/src/server/authserver/Server/BattlenetSocket.h index ff441b19cdd..c634a81b517 100644 --- a/src/server/authserver/Server/BattlenetSocket.h +++ b/src/server/authserver/Server/BattlenetSocket.h @@ -37,6 +37,7 @@ namespace Battlenet MODULE_THUMBPRINT, MODULE_SELECT_GAME_ACCOUNT, MODULE_RISK_FINGERPRINT, + MODULE_RESUME, MODULE_COUNT }; @@ -53,11 +54,13 @@ namespace Battlenet // Auth bool HandleAuthChallenge(PacketHeader& header, BitStream& packet); + bool HandleAuthReconnect(PacketHeader& header, BitStream& packet); bool HandleAuthProofResponse(PacketHeader& header, BitStream& packet); // Creep bool HandlePing(PacketHeader& header, BitStream& packet); bool HandleEnableEncryption(PacketHeader& header, BitStream& packet); + bool HandleDisconnect(PacketHeader& header, BitStream& packet); // WoW bool HandleRealmUpdateSubscribe(PacketHeader& header, BitStream& packet); @@ -78,6 +81,7 @@ namespace Battlenet bool HandlePasswordModule(BitStream* dataStream, ServerPacket** response); bool HandleSelectGameAccountModule(BitStream* dataStream, ServerPacket** response); bool HandleRiskFingerprintModule(BitStream* dataStream, ServerPacket** response); + bool HandleResumeModule(BitStream* dataStream, ServerPacket** response); bool UnhandledModule(BitStream* dataStream, ServerPacket** response); RealmSocket& _socket; @@ -102,9 +106,12 @@ namespace Battlenet BigNumber B; BigNumber K; // session key + BigNumber _reconnectProof; + std::queue _modulesWaitingForData; PacketCrypt _crypt; + bool _authed; }; } diff --git a/src/server/shared/Database/Implementation/LoginDatabase.cpp b/src/server/shared/Database/Implementation/LoginDatabase.cpp index a54557310e1..abe733e55e2 100644 --- a/src/server/shared/Database/Implementation/LoginDatabase.cpp +++ b/src/server/shared/Database/Implementation/LoginDatabase.cpp @@ -107,6 +107,8 @@ void LoginDatabaseConnection::DoPrepareStatements() PrepareStatement(LOGIN_DEL_BNET_EXPIRED_BANS, "UPDATE battlenet_account_bans SET active = 0 WHERE active = 1 AND unbandate <> bandate AND unbandate <= UNIX_TIMESTAMP()", CONNECTION_SYNCH); PrepareStatement(LOGIN_SEL_BNET_ACTIVE_ACCOUNT_BAN, "SELECT bandate, unbandate FROM battlenet_account_bans WHERE id = ? AND active = 1", CONNECTION_SYNCH); PrepareStatement(LOGIN_UPD_BNET_VS_FIELDS, "UPDATE battlenet_accounts SET v = ?, s = ? WHERE email = ?", CONNECTION_ASYNC); + PrepareStatement(LOGIN_UPD_BNET_SESSION_KEY, "UPDATE battlenet_accounts SET sessionKey = ? WHERE id = ?", CONNECTION_ASYNC); + PrepareStatement(LOGIN_SEL_BNET_RECONNECT_INFO, "SELECT ba.id, ba.sessionKey, a.id FROM battlenet_accounts ba LEFT JOIN account a ON ba.id = a.battlenet_account WHERE ba.email = ? AND a.id = SUBSTRING_INDEX(?, '#', 1)", CONNECTION_SYNCH); PrepareStatement(LOGIN_SEL_BNET_GAME_ACCOUNTS, "SELECT a.username, a.id, ab.bandate, ab.unbandate, ab.active FROM account a LEFT JOIN account_banned ab ON a.id = ab.id WHERE battlenet_account = ?", CONNECTION_SYNCH); PrepareStatement(LOGIN_SEL_BNET_GAME_ACCOUNT, "SELECT a.id, ab.bandate, ab.unbandate, ab.active FROM account a LEFT JOIN account_banned ab ON a.id = ab.id WHERE username = ? AND battlenet_account = ?", CONNECTION_SYNCH); PrepareStatement(LOGIN_UPD_BNET_LAST_LOGIN_INFO, "UPDATE battlenet_accounts SET last_ip = ?, last_login = NOW(), locale = ?, failed_logins = 0, os = ? WHERE id = ?", CONNECTION_ASYNC); diff --git a/src/server/shared/Database/Implementation/LoginDatabase.h b/src/server/shared/Database/Implementation/LoginDatabase.h index fff7a36766c..64264984e29 100644 --- a/src/server/shared/Database/Implementation/LoginDatabase.h +++ b/src/server/shared/Database/Implementation/LoginDatabase.h @@ -126,6 +126,8 @@ enum LoginDatabaseStatements LOGIN_DEL_BNET_EXPIRED_BANS, LOGIN_SEL_BNET_ACTIVE_ACCOUNT_BAN, LOGIN_UPD_BNET_VS_FIELDS, + LOGIN_UPD_BNET_SESSION_KEY, + LOGIN_SEL_BNET_RECONNECT_INFO, LOGIN_SEL_BNET_GAME_ACCOUNTS, LOGIN_SEL_BNET_GAME_ACCOUNT, LOGIN_UPD_BNET_LAST_LOGIN_INFO, -- cgit v1.2.3 From 05c0524bf3d97ba29496fa13e93acd3b8d7d37a4 Mon Sep 17 00:00:00 2001 From: Shauren Date: Sun, 8 Jun 2014 14:54:37 +0200 Subject: Core/Battle.net: Refactored handling multiple game accounts --- sql/base/auth_database.sql | 2 ++ .../auth/2014_06_08_00_auth_account_434.sql | 3 +++ src/server/authserver/Server/BattlenetPackets.cpp | 6 ++--- src/server/authserver/Server/BattlenetPackets.h | 4 +-- src/server/authserver/Server/BattlenetSocket.cpp | 30 +++++++++++++++++----- src/server/authserver/Server/BattlenetSocket.h | 1 + src/server/game/Server/WorldSocket.cpp | 17 +++++++++--- .../Database/Implementation/LoginDatabase.cpp | 8 +++--- 8 files changed, 52 insertions(+), 19 deletions(-) create mode 100644 sql/updates/auth/2014_06_08_00_auth_account_434.sql (limited to 'src/server/shared/Database/Implementation') diff --git a/sql/base/auth_database.sql b/sql/base/auth_database.sql index 7ab0c855f45..6dca9aa1e14 100644 --- a/sql/base/auth_database.sql +++ b/sql/base/auth_database.sql @@ -47,8 +47,10 @@ CREATE TABLE `account` ( `os` varchar(3) NOT NULL DEFAULT '', `recruiter` int(10) unsigned NOT NULL DEFAULT '0', `battlenet_account` int(10) unsigned DEFAULT NULL, + `battlenet_index` tinyint(3) unsigned DEFAULT NULL, PRIMARY KEY (`id`), UNIQUE KEY `idx_username` (`username`), + UNIQUE KEY `uk_bnet_acc` (`battlenet_account`, `battlenet_index`), CONSTRAINT `fk_bnet_acc` FOREIGN KEY (`battlenet_account`) REFERENCES `battlenet_accounts` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Account System'; /*!40101 SET character_set_client = @saved_cs_client */; diff --git a/sql/updates/auth/2014_06_08_00_auth_account_434.sql b/sql/updates/auth/2014_06_08_00_auth_account_434.sql new file mode 100644 index 00000000000..bc57136dc07 --- /dev/null +++ b/sql/updates/auth/2014_06_08_00_auth_account_434.sql @@ -0,0 +1,3 @@ +ALTER TABLE `account` + ADD `battlenet_index` tinyint(3) unsigned DEFAULT NULL AFTER `battlenet_account`, + ADD UNIQUE KEY `uk_bnet_acc` (`battlenet_account`, `battlenet_index`); diff --git a/src/server/authserver/Server/BattlenetPackets.cpp b/src/server/authserver/Server/BattlenetPackets.cpp index 9997ea8d259..6a8e09090ef 100644 --- a/src/server/authserver/Server/BattlenetPackets.cpp +++ b/src/server/authserver/Server/BattlenetPackets.cpp @@ -202,7 +202,7 @@ void Battlenet::AuthComplete::Write() _stream.WriteString(FirstName, 8); // First name _stream.WriteString(LastName, 8); // Last name - not set for WoW - _stream.Write(GameAccountId, 32); + _stream.Write(AccountId, 32); _stream.Write(Region, 8); _stream.Write(0, 64); @@ -236,7 +236,7 @@ std::string Battlenet::AuthComplete::ToString() const { std::ostringstream stream; stream << "Battlenet::AuthComplete AuthResult " << Result << " PingTimeout " << PingTimeout << " Threshold " << Threshold << " Rate " << Rate - << " FirstName " << FirstName << " LastName " << LastName << " GameAccountId " << GameAccountId << " GameAccountName " << GameAccountName + << " FirstName " << FirstName << " LastName " << LastName << " AccountId " << AccountId << " Region " << uint32(Region) << " GameAccountName " << GameAccountName << " GameAccountFlags " << GameAccountFlags << " Modules " << Modules.size(); for (ModuleInfo const* module : Modules) @@ -441,7 +441,7 @@ void Battlenet::RealmJoinResult::Write() std::string Battlenet::RealmJoinResult::ToString() const { std::ostringstream stream; - stream << "Battlenet::RealmJoinResult ServerSeed " << ServerSeed << " Addresses (IPv4)" << IPv4.size(); + stream << "Battlenet::RealmJoinResult ServerSeed " << ServerSeed << " IPv4 Addresses " << IPv4.size(); for (ACE_INET_Addr const& addr : IPv4) stream << std::endl << "Battlenet::RealmJoinResult::Address " << GetAddressString(addr); diff --git a/src/server/authserver/Server/BattlenetPackets.h b/src/server/authserver/Server/BattlenetPackets.h index 3fa628c2ba3..54fb50184a0 100644 --- a/src/server/authserver/Server/BattlenetPackets.h +++ b/src/server/authserver/Server/BattlenetPackets.h @@ -208,7 +208,7 @@ namespace Battlenet public: AuthComplete() : ServerPacket(PacketHeader(SMSG_AUTH_COMPLETE, AUTHENTICATION)), Result(AUTH_OK), ErrorType(0), PingTimeout(120000), Threshold(25000000), Rate(1000), - FirstName(""), LastName(""), Region(2), GameAccountId(0), GameAccountRegion(2), GameAccountName("") + FirstName(""), LastName(""), AccountId(0), Region(2), GameAccountRegion(2), GameAccountName("") { } @@ -227,8 +227,8 @@ namespace Battlenet uint32 Rate; std::string FirstName; std::string LastName; + uint32 AccountId; uint8 Region; - uint32 GameAccountId; uint8 GameAccountRegion; std::string GameAccountName; uint64 GameAccountFlags; diff --git a/src/server/authserver/Server/BattlenetSocket.cpp b/src/server/authserver/Server/BattlenetSocket.cpp index 56744784167..eb8dc1158f0 100644 --- a/src/server/authserver/Server/BattlenetSocket.cpp +++ b/src/server/authserver/Server/BattlenetSocket.cpp @@ -59,7 +59,7 @@ Battlenet::Socket::ModuleHandler const Battlenet::Socket::ModuleHandlers[MODULE_ }; Battlenet::Socket::Socket(RealmSocket& socket) : _socket(socket), _accountId(0), _accountName(), _locale(), - _os(), _build(0), _gameAccountId(0), _accountSecurityLevel(SEC_PLAYER), I(), s(), v(), b(), B(), K(), + _os(), _build(0), _gameAccountId(0), _gameAccountIndex(0), _accountSecurityLevel(SEC_PLAYER), I(), s(), v(), b(), B(), K(), _reconnectProof(), _crypt(), _authed(false) { static uint8 const N_Bytes[] = @@ -323,10 +323,12 @@ bool Battlenet::Socket::HandleAuthReconnect(PacketHeader& header, BitStream& pac if (baseComponent != reconnect.Components.end()) _build = baseComponent->Build; + uint8 accountIndex = atol(reconnect.GameAccountName.substr(reconnect.GameAccountName.find_last_of('#') + 1).c_str()); + Utf8ToUpperOnlyLatin(_accountName); PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_BNET_RECONNECT_INFO); stmt->setString(0, _accountName); - stmt->setString(1, reconnect.GameAccountName.c_str()); + stmt->setUInt8(1, accountIndex); PreparedQueryResult result = LoginDatabase.Query(stmt); if (!result) { @@ -341,6 +343,7 @@ bool Battlenet::Socket::HandleAuthReconnect(PacketHeader& header, BitStream& pac _accountId = fields[0].GetUInt32(); K.SetHexStr(fields[1].GetString().c_str()); _gameAccountId = fields[2].GetUInt32(); + _gameAccountIndex = accountIndex; ModuleInfo* thumbprint = sBattlenetMgr->CreateModule(_os, "Thumbprint"); ModuleInfo* resume = sBattlenetMgr->CreateModule(_os, "Resume"); @@ -768,8 +771,10 @@ bool Battlenet::Socket::HandlePasswordModule(BitStream* dataStream, ServerPacket do { fields = result->Fetch(); + std::ostringstream name; + name << "WoW" << uint32(fields[0].GetUInt8()); accounts.Write(2, 8); - accounts.WriteString(fields[0].GetString(), 8); + accounts.WriteString(name.str(), 8); } while (result->NextRow()); ModuleInfo* selectGameAccount = sBattlenetMgr->CreateModule(_os, "SelectGameAccount"); @@ -801,7 +806,8 @@ bool Battlenet::Socket::HandlePasswordModule(BitStream* dataStream, ServerPacket return false; } - _gameAccountId = (*result)[1].GetUInt32(); + _gameAccountId = fields[1].GetUInt32(); + _gameAccountIndex = fields[0].GetUInt8(); request->Modules.push_back(sBattlenetMgr->CreateModule(_os, "RiskFingerprint")); _modulesWaitingForData.push(MODULE_RISK_FINGERPRINT); @@ -823,9 +829,18 @@ bool Battlenet::Socket::HandleSelectGameAccountModule(BitStream* dataStream, Ser dataStream->Read(8); std::string account = dataStream->ReadString(8); + if (account.length() < 4) + { + AuthComplete* complete = new AuthComplete(); + complete->SetAuthResult(LOGIN_NO_GAME_ACCOUNT); + ReplaceResponse(response, complete); + return false; + } + + uint8 accountIndex = atol(account.substr(3).c_str()); PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_BNET_GAME_ACCOUNT); - stmt->setString(0, account); + stmt->setUInt8(0, accountIndex); stmt->setUInt32(1, _accountId); PreparedQueryResult result = LoginDatabase.Query(stmt); if (!result) @@ -856,6 +871,7 @@ bool Battlenet::Socket::HandleSelectGameAccountModule(BitStream* dataStream, Ser } _gameAccountId = fields[0].GetUInt32(); + _gameAccountIndex = accountIndex; ProofRequest* request = new ProofRequest(); request->Modules.push_back(sBattlenetMgr->CreateModule(_os, "RiskFingerprint")); @@ -871,9 +887,9 @@ bool Battlenet::Socket::HandleRiskFingerprintModule(BitStream* dataStream, Serve if (dataStream->Read(8) == 1) { std::ostringstream str; - str << _gameAccountId << "#1"; + str << _accountId << "#" << uint32(_gameAccountIndex); - complete->GameAccountId = _gameAccountId; + complete->AccountId = _accountId; complete->GameAccountName = str.str(); complete->GameAccountFlags = GAMEACCOUNT_FLAG_PROPASS_LOCK; diff --git a/src/server/authserver/Server/BattlenetSocket.h b/src/server/authserver/Server/BattlenetSocket.h index c634a81b517..ee399e26b09 100644 --- a/src/server/authserver/Server/BattlenetSocket.h +++ b/src/server/authserver/Server/BattlenetSocket.h @@ -92,6 +92,7 @@ namespace Battlenet std::string _os; uint32 _build; uint32 _gameAccountId; + uint8 _gameAccountIndex; AccountTypes _accountSecurityLevel; BigNumber N; diff --git a/src/server/game/Server/WorldSocket.cpp b/src/server/game/Server/WorldSocket.cpp index cc839b5281c..1a93e7ae1d5 100644 --- a/src/server/game/Server/WorldSocket.cpp +++ b/src/server/game/Server/WorldSocket.cpp @@ -856,9 +856,20 @@ int WorldSocket::HandleAuthSession(WorldPacket& recvPacket) // Get the account information from the realmd database // 0 1 2 3 4 5 6 7 8 // SELECT id, sessionkey, last_ip, locked, expansion, mutetime, locale, recruiter, os FROM account WHERE username = ? - PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(account.find('#') == std::string::npos ? LOGIN_SEL_ACCOUNT_INFO_BY_NAME : LOGIN_SEL_ACCOUNT_INFO_BY_BNET); - - stmt->setString(0, account); + size_t hashPos = account.find_last_of('#'); + PreparedStatement* stmt; + if (hashPos != std::string::npos) + { + Tokenizer tokens(account, '#', 2); + stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_ACCOUNT_INFO_BY_BNET); + stmt->setUInt32(0, atol(tokens[0])); + stmt->setUInt8(1, atol(tokens[1])); + } + else + { + stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_ACCOUNT_INFO_BY_NAME); + stmt->setString(0, account); + } PreparedQueryResult result = LoginDatabase.Query(stmt); diff --git a/src/server/shared/Database/Implementation/LoginDatabase.cpp b/src/server/shared/Database/Implementation/LoginDatabase.cpp index abe733e55e2..1da8088ed36 100644 --- a/src/server/shared/Database/Implementation/LoginDatabase.cpp +++ b/src/server/shared/Database/Implementation/LoginDatabase.cpp @@ -44,7 +44,7 @@ void LoginDatabaseConnection::DoPrepareStatements() PrepareStatement(LOGIN_SEL_ACCOUNT_ID_BY_NAME, "SELECT id FROM account WHERE username = ?", CONNECTION_SYNCH); PrepareStatement(LOGIN_SEL_ACCOUNT_LIST_BY_NAME, "SELECT id, username FROM account WHERE username = ?", CONNECTION_SYNCH); PrepareStatement(LOGIN_SEL_ACCOUNT_INFO_BY_NAME, "SELECT id, sessionkey, last_ip, locked, expansion, mutetime, locale, recruiter, os FROM account WHERE username = ?", CONNECTION_SYNCH); - PrepareStatement(LOGIN_SEL_ACCOUNT_INFO_BY_BNET, "SELECT id, sessionkey, last_ip, locked, expansion, mutetime, locale, recruiter, os FROM account WHERE id = SUBSTRING_INDEX(?, '#', 1)", CONNECTION_SYNCH); + PrepareStatement(LOGIN_SEL_ACCOUNT_INFO_BY_BNET, "SELECT id, sessionkey, last_ip, locked, expansion, mutetime, locale, recruiter, os FROM account WHERE battlenet_account = ? AND battlenet_index = ?", CONNECTION_SYNCH); PrepareStatement(LOGIN_SEL_ACCOUNT_LIST_BY_EMAIL, "SELECT id, username FROM account WHERE email = ?", CONNECTION_SYNCH); PrepareStatement(LOGIN_SEL_NUM_CHARS_ON_REALM, "SELECT numchars FROM realmcharacters WHERE realmid = ? AND acctid= ?", CONNECTION_SYNCH); PrepareStatement(LOGIN_SEL_ACCOUNT_BY_IP, "SELECT id, username FROM account WHERE last_ip = ?", CONNECTION_SYNCH); @@ -108,9 +108,9 @@ void LoginDatabaseConnection::DoPrepareStatements() PrepareStatement(LOGIN_SEL_BNET_ACTIVE_ACCOUNT_BAN, "SELECT bandate, unbandate FROM battlenet_account_bans WHERE id = ? AND active = 1", CONNECTION_SYNCH); PrepareStatement(LOGIN_UPD_BNET_VS_FIELDS, "UPDATE battlenet_accounts SET v = ?, s = ? WHERE email = ?", CONNECTION_ASYNC); PrepareStatement(LOGIN_UPD_BNET_SESSION_KEY, "UPDATE battlenet_accounts SET sessionKey = ? WHERE id = ?", CONNECTION_ASYNC); - PrepareStatement(LOGIN_SEL_BNET_RECONNECT_INFO, "SELECT ba.id, ba.sessionKey, a.id FROM battlenet_accounts ba LEFT JOIN account a ON ba.id = a.battlenet_account WHERE ba.email = ? AND a.id = SUBSTRING_INDEX(?, '#', 1)", CONNECTION_SYNCH); - PrepareStatement(LOGIN_SEL_BNET_GAME_ACCOUNTS, "SELECT a.username, a.id, ab.bandate, ab.unbandate, ab.active FROM account a LEFT JOIN account_banned ab ON a.id = ab.id WHERE battlenet_account = ?", CONNECTION_SYNCH); - PrepareStatement(LOGIN_SEL_BNET_GAME_ACCOUNT, "SELECT a.id, ab.bandate, ab.unbandate, ab.active FROM account a LEFT JOIN account_banned ab ON a.id = ab.id WHERE username = ? AND battlenet_account = ?", CONNECTION_SYNCH); + PrepareStatement(LOGIN_SEL_BNET_RECONNECT_INFO, "SELECT ba.id, ba.sessionKey, a.id FROM battlenet_accounts ba LEFT JOIN account a ON ba.id = a.battlenet_account WHERE ba.email = ? AND a.battlenet_index = ?", CONNECTION_SYNCH); + PrepareStatement(LOGIN_SEL_BNET_GAME_ACCOUNTS, "SELECT a.battlenet_index, a.id, ab.bandate, ab.unbandate, ab.active FROM account a LEFT JOIN account_banned ab ON a.id = ab.id WHERE battlenet_account = ?", CONNECTION_SYNCH); + PrepareStatement(LOGIN_SEL_BNET_GAME_ACCOUNT, "SELECT a.id, ab.bandate, ab.unbandate, ab.active FROM account a LEFT JOIN account_banned ab ON a.id = ab.id WHERE battlenet_index = ? AND battlenet_account = ?", CONNECTION_SYNCH); PrepareStatement(LOGIN_UPD_BNET_LAST_LOGIN_INFO, "UPDATE battlenet_accounts SET last_ip = ?, last_login = NOW(), locale = ?, failed_logins = 0, os = ? WHERE id = ?", CONNECTION_ASYNC); PrepareStatement(LOGIN_SEL_BNET_CHARACTER_COUNTS, "SELECT rc.numchars, r.id, r.Region, r.Battlegroup, r.gamebuild FROM realmcharacters rc INNER JOIN realmlist r ON rc.realmid = r.id WHERE rc.acctid = ?", CONNECTION_SYNCH); PrepareStatement(LOGIN_INS_BNET_ACCOUNT, "INSERT INTO battlenet_accounts (`email`,`sha_pass_hash`) VALUES (?, ?)", CONNECTION_ASYNC); -- cgit v1.2.3 From 9f69eda67f7fad50553f8d569851a5005437e677 Mon Sep 17 00:00:00 2001 From: Shauren Date: Sun, 8 Jun 2014 15:34:24 +0200 Subject: Core/Battle.net: Additional checks * Force grunt login for versions < 15595 * Force bn login if supported and game account is linked to bn account --- sql/base/auth_database.sql | 6 ------ sql/updates/auth/2014_06_08_01_auth_account_434.sql | 3 +++ src/server/authserver/Authentication/AuthCodes.cpp | 5 +++++ src/server/authserver/Authentication/AuthCodes.h | 1 + src/server/authserver/Server/AuthSocket.cpp | 4 +++- src/server/authserver/Server/BattlenetSocket.cpp | 8 ++++++-- src/server/shared/Database/Implementation/LoginDatabase.cpp | 2 +- 7 files changed, 19 insertions(+), 10 deletions(-) create mode 100644 sql/updates/auth/2014_06_08_01_auth_account_434.sql (limited to 'src/server/shared/Database/Implementation') diff --git a/sql/base/auth_database.sql b/sql/base/auth_database.sql index 6dca9aa1e14..3ccbadbbda0 100644 --- a/sql/base/auth_database.sql +++ b/sql/base/auth_database.sql @@ -216,18 +216,12 @@ LOCK TABLES `battlenet_components` WRITE; /*!40000 ALTER TABLE `battlenet_components` DISABLE KEYS */; INSERT INTO `battlenet_components` VALUES ('Bnet','Cmp1',3), -('Bnet','Win',21719), ('Bnet','Win',26487), ('Bnet','Wn64',26487), -('Tool','Win',1569), ('Tool','Win',2736), -('WoW','base',12340), ('WoW','base',15595), -('WoW','enGB',12340), ('WoW','enGB',15595), -('WoW','enUS',12340), ('WoW','enUS',15595), -('WoW','Win',12340), ('WoW','Win',15595), ('WoW','Wn64',15595); /*!40000 ALTER TABLE `battlenet_components` ENABLE KEYS */; diff --git a/sql/updates/auth/2014_06_08_01_auth_account_434.sql b/sql/updates/auth/2014_06_08_01_auth_account_434.sql new file mode 100644 index 00000000000..dc05a98d17b --- /dev/null +++ b/sql/updates/auth/2014_06_08_01_auth_account_434.sql @@ -0,0 +1,3 @@ +DELETE FROM `battlenet_components` WHERE `Program`='WoW' AND `Build`=12340; +DELETE FROM `battlenet_components` WHERE `Program`='Tool' AND `Build`=1569; +DELETE FROM `battlenet_components` WHERE `Program`='Bnet' AND `Build`=21719; diff --git a/src/server/authserver/Authentication/AuthCodes.cpp b/src/server/authserver/Authentication/AuthCodes.cpp index bb278dd6653..7a4998f7028 100644 --- a/src/server/authserver/Authentication/AuthCodes.cpp +++ b/src/server/authserver/Authentication/AuthCodes.cpp @@ -79,4 +79,9 @@ namespace AuthHelper return NULL; } + + bool IsBuildSupportingBattlenet(int build) + { + return build >= 15595; + } }; diff --git a/src/server/authserver/Authentication/AuthCodes.h b/src/server/authserver/Authentication/AuthCodes.h index 57db55c98a8..a6113b0d26d 100644 --- a/src/server/authserver/Authentication/AuthCodes.h +++ b/src/server/authserver/Authentication/AuthCodes.h @@ -182,6 +182,7 @@ namespace AuthHelper bool IsAcceptedClientBuild(int build); bool IsPostBCAcceptedClientBuild(int build); bool IsPreBCAcceptedClientBuild(int build); + bool IsBuildSupportingBattlenet(int build); }; #endif diff --git a/src/server/authserver/Server/AuthSocket.cpp b/src/server/authserver/Server/AuthSocket.cpp index 32140f76ba4..7ca49b03b56 100644 --- a/src/server/authserver/Server/AuthSocket.cpp +++ b/src/server/authserver/Server/AuthSocket.cpp @@ -480,7 +480,9 @@ bool AuthSocket::_HandleLogonChallenge() unk3.SetRand(16 * 8); // Fill the response packet with the result - if (AuthHelper::IsAcceptedClientBuild(_build)) + if (fields[9].GetUInt32() && AuthHelper::IsBuildSupportingBattlenet(_build)) + pkt << uint8(WOW_FAIL_USE_BATTLENET); + else if (AuthHelper::IsAcceptedClientBuild(_build)) pkt << uint8(WOW_SUCCESS); else pkt << uint8(WOW_FAIL_VERSION_INVALID); diff --git a/src/server/authserver/Server/BattlenetSocket.cpp b/src/server/authserver/Server/BattlenetSocket.cpp index eb8dc1158f0..4ee3c8e9b3d 100644 --- a/src/server/authserver/Server/BattlenetSocket.cpp +++ b/src/server/authserver/Server/BattlenetSocket.cpp @@ -107,7 +107,6 @@ void Battlenet::Socket::_SetVSFields(std::string const& pstr) bool Battlenet::Socket::HandleAuthChallenge(PacketHeader& header, BitStream& packet) { - // Verify that this IP is not in the ip_banned table LoginDatabase.Execute(LoginDatabase.GetPreparedStatement(LOGIN_DEL_EXPIRED_IP_BANS)); @@ -160,7 +159,12 @@ bool Battlenet::Socket::HandleAuthChallenge(PacketHeader& header, BitStream& pac else if (!sBattlenetMgr->HasPlatform(component.Platform)) complete.SetAuthResult(AUTH_INVALID_OS); else - complete.SetAuthResult(AUTH_REGION_BAD_VERSION); + { + if (component.Program != "WoW" || AuthHelper::IsBuildSupportingBattlenet(component.Build)) + complete.SetAuthResult(AUTH_REGION_BAD_VERSION); + else + complete.SetAuthResult(AUTH_USE_GRUNT_LOGON); + } Send(complete); return true; diff --git a/src/server/shared/Database/Implementation/LoginDatabase.cpp b/src/server/shared/Database/Implementation/LoginDatabase.cpp index 1da8088ed36..bccbe41a6ec 100644 --- a/src/server/shared/Database/Implementation/LoginDatabase.cpp +++ b/src/server/shared/Database/Implementation/LoginDatabase.cpp @@ -37,7 +37,7 @@ void LoginDatabaseConnection::DoPrepareStatements() PrepareStatement(LOGIN_SEL_SESSIONKEY, "SELECT a.sessionkey, a.id, aa.gmlevel FROM account a LEFT JOIN account_access aa ON (a.id = aa.id) WHERE username = ?", CONNECTION_SYNCH); PrepareStatement(LOGIN_UPD_VS, "UPDATE account SET v = ?, s = ? WHERE username = ?", CONNECTION_ASYNC); PrepareStatement(LOGIN_UPD_LOGONPROOF, "UPDATE account SET sessionkey = ?, last_ip = ?, last_login = NOW(), locale = ?, failed_logins = 0, os = ? WHERE username = ?", CONNECTION_SYNCH); - PrepareStatement(LOGIN_SEL_LOGONCHALLENGE, "SELECT a.sha_pass_hash, a.id, a.locked, a.lock_country, a.last_ip, aa.gmlevel, a.v, a.s, a.token_key FROM account a LEFT JOIN account_access aa ON (a.id = aa.id) WHERE a.username = ?", CONNECTION_SYNCH); + PrepareStatement(LOGIN_SEL_LOGONCHALLENGE, "SELECT a.sha_pass_hash, a.id, a.locked, a.lock_country, a.last_ip, aa.gmlevel, a.v, a.s, a.token_key, a.battlenet_account FROM account a LEFT JOIN account_access aa ON (a.id = aa.id) WHERE a.username = ?", CONNECTION_SYNCH); PrepareStatement(LOGIN_SEL_LOGON_COUNTRY, "SELECT country FROM ip2nation WHERE ip < ? ORDER BY ip DESC LIMIT 0,1", CONNECTION_SYNCH); PrepareStatement(LOGIN_UPD_FAILEDLOGINS, "UPDATE account SET failed_logins = failed_logins + 1 WHERE username = ?", CONNECTION_ASYNC); PrepareStatement(LOGIN_SEL_FAILEDLOGINS, "SELECT id, failed_logins FROM account WHERE username = ?", CONNECTION_SYNCH); -- cgit v1.2.3