diff options
| author | Shauren <shauren.trinity@gmail.com> | 2014-08-21 23:59:00 +0200 |
|---|---|---|
| committer | Shauren <shauren.trinity@gmail.com> | 2014-08-21 23:59:00 +0200 |
| commit | 42cac6796abbc683f8d383b43750860f05bb2dc6 (patch) | |
| tree | 5984c512c709feca55efce941aa20a0ff6da7711 /src/server/game/Server | |
| parent | d2361ae056da8caf2c9b42e03a9f17f3fcb10790 (diff) | |
| parent | 0c1587cc916de846eedf3ccf48f80caf053f427b (diff) | |
Merge branch 'master' of https://github.com/TrinityCore/TrinityCore into 4.3.4
Conflicts:
src/server/authserver/Server/AuthSession.cpp
src/server/game/Entities/Player/Player.cpp
src/server/game/Server/WorldSocket.cpp
Diffstat (limited to 'src/server/game/Server')
| -rw-r--r-- | src/server/game/Server/WorldSocket.cpp | 149 | ||||
| -rw-r--r-- | src/server/game/Server/WorldSocket.h | 2 |
2 files changed, 98 insertions, 53 deletions
diff --git a/src/server/game/Server/WorldSocket.cpp b/src/server/game/Server/WorldSocket.cpp index 09fb0acda97..4e7ad6590a8 100644 --- a/src/server/game/Server/WorldSocket.cpp +++ b/src/server/game/Server/WorldSocket.cpp @@ -16,14 +16,15 @@ * with this program. If not, see <http://www.gnu.org/licenses/>. */ -#include <memory> #include "WorldSocket.h" #include "BigNumber.h" #include "Opcodes.h" +#include "Player.h" #include "ScriptMgr.h" #include "SHA1.h" #include "PacketLog.h" #include "BattlenetAccountMgr.h" +#include <memory> using boost::asio::ip::tcp; @@ -68,6 +69,22 @@ void WorldSocket::ReadHeaderHandler() EndianConvertReverse(header->size); EndianConvert(header->cmd); + if (!header->IsValid()) + { + if (_worldSession) + { + Player* player = _worldSession->GetPlayer(); + TC_LOG_ERROR("network", "WorldSocket::ReadHeaderHandler(): client (account: %u, char [GUID: %u, name: %s]) sent malformed packet (size: %hu, cmd: %u)", + _worldSession->GetAccountId(), player ? player->GetGUIDLow() : 0, player ? player->GetName().c_str() : "<none>", header->size, header->cmd); + } + else + TC_LOG_ERROR("network", "WorldSocket::ReadHeaderHandler(): client %s sent malformed packet (size: %hu, cmd: %u)", + GetRemoteIpAddress().to_string().c_str(), header->size, header->cmd); + + CloseSocket(); + return; + } + AsyncReadData(header->size - sizeof(header->cmd)); } @@ -75,8 +92,6 @@ void WorldSocket::ReadDataHandler() { ClientPktHeader* header = reinterpret_cast<ClientPktHeader*>(GetHeaderBuffer()); - header->size -= sizeof(header->cmd); - Opcodes opcode = PacketFilter::DropHighBytes(Opcodes(header->cmd)); std::string opcodeName = GetOpcodeNameForLogging(opcode); @@ -141,7 +156,8 @@ void WorldSocket::ReadDataHandler() if (!_worldSession) { TC_LOG_ERROR("network.opcode", "ProcessIncoming: Client not authed opcode = %u", uint32(opcode)); - break; + CloseSocket(); + return; } // Our Idle timer will reset on any non PING opcodes. @@ -197,10 +213,12 @@ void WorldSocket::HandleAuthSession(WorldPacket& recvPacket) BigNumber k; bool wardenActive = sWorld->getBoolConfig(CONFIG_WARDEN_ENABLED); WorldPacket addonsData; + uint8 loginServerType; + uint32 realmIndex; - recvPacket.read_skip<uint32>(); - recvPacket.read_skip<uint32>(); - recvPacket.read_skip<uint8>(); + recvPacket.read_skip<uint32>(); // ServerId - Used for GRUNT only + recvPacket.read_skip<uint32>(); // Battlegroup + recvPacket >> loginServerType; recvPacket >> digest[10]; recvPacket >> digest[18]; recvPacket >> digest[12]; @@ -215,7 +233,7 @@ void WorldSocket::HandleAuthSession(WorldPacket& recvPacket) recvPacket >> digest[3]; recvPacket >> clientBuild; recvPacket >> digest[8]; - recvPacket.read_skip<uint32>(); + recvPacket >> realmIndex; recvPacket.read_skip<uint8>(); recvPacket >> digest[17]; recvPacket >> digest[6]; @@ -224,7 +242,7 @@ void WorldSocket::HandleAuthSession(WorldPacket& recvPacket) recvPacket >> digest[11]; recvPacket >> clientSeed; recvPacket >> digest[2]; - recvPacket.read_skip<uint32>(); + recvPacket.read_skip<uint32>(); // Region recvPacket >> digest[14]; recvPacket >> digest[13]; @@ -236,15 +254,9 @@ void WorldSocket::HandleAuthSession(WorldPacket& recvPacket) recvPacket.read((uint8*)addonsData.contents(), addonSize); } - recvPacket.ReadBit(); + recvPacket.ReadBit(); // UseIPv6 uint32 accountNameLength = recvPacket.ReadBits(12); account = recvPacket.ReadString(accountNameLength); - if (sWorld->IsClosed()) - { - SendAuthResponseError(AUTH_REJECT); - TC_LOG_ERROR("network", "WorldSocket::HandleAuthSession: World closed, denying client (%s).", GetRemoteIpAddress().to_string().c_str()); - return; - } // Get the account information from the auth database // 0 1 2 3 4 5 6 7 8 @@ -252,8 +264,17 @@ void WorldSocket::HandleAuthSession(WorldPacket& recvPacket) PreparedStatement* stmt; uint32 battlenetAccountId = 0; uint8 battlenetAccountIndex = 0; - if (Battlenet::AccountMgr::GetAccountIdAndIndex(account, &battlenetAccountId, &battlenetAccountIndex)) + if (loginServerType == 1) { + if (!Battlenet::AccountMgr::GetAccountIdAndIndex(account, &battlenetAccountId, &battlenetAccountIndex)) + { + // We can not log here, as we do not know the account. Thus, no accountId. + SendAuthResponseError(AUTH_UNKNOWN_ACCOUNT); + TC_LOG_ERROR("network", "WorldSocket::HandleAuthSession: Sent Auth Response (unknown account)."); + DelayedCloseSocket(); + return; + } + stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_ACCOUNT_INFO_BY_BNET); stmt->setUInt32(0, battlenetAccountId); stmt->setUInt8(1, battlenetAccountIndex); @@ -272,6 +293,7 @@ void WorldSocket::HandleAuthSession(WorldPacket& recvPacket) // We can not log here, as we do not know the account. Thus, no accountId. SendAuthResponseError(AUTH_UNKNOWN_ACCOUNT); TC_LOG_ERROR("network", "WorldSocket::HandleAuthSession: Sent Auth Response (unknown account)."); + DelayedCloseSocket(); return; } @@ -297,6 +319,57 @@ void WorldSocket::HandleAuthSession(WorldPacket& recvPacket) // id has to be fetched at this point, so that first actual account response that fails can be logged id = fields[0].GetUInt32(); + k.SetHexStr(fields[1].GetCString()); + + // even if auth credentials are bad, try using the session key we have - client cannot read auth response error without it + _authCrypt.Init(&k); + + // First reject the connection if packet contains invalid data or realm state doesn't allow logging in + if (sWorld->IsClosed()) + { + SendAuthResponseError(AUTH_REJECT); + TC_LOG_ERROR("network", "WorldSocket::HandleAuthSession: World closed, denying client (%s).", GetRemoteIpAddress().to_string().c_str()); + DelayedCloseSocket(); + return; + } + + if (realmIndex != realmID) + { + SendAuthResponseError(REALM_LIST_REALM_NOT_FOUND); + TC_LOG_ERROR("network", "WorldSocket::HandleAuthSession: Sent Auth Response (bad realm)."); + DelayedCloseSocket(); + return; + } + + std::string os = fields[8].GetString(); + + // Must be done before WorldSession is created + if (wardenActive && os != "Win" && os != "OSX") + { + SendAuthResponseError(AUTH_REJECT); + TC_LOG_ERROR("network", "WorldSocket::HandleAuthSession: Client %s attempted to log in using invalid client OS (%s).", address.c_str(), os.c_str()); + DelayedCloseSocket(); + return; + } + + // Check that Key and account name are the same on client and server + uint32 t = 0; + + sha.UpdateData(account); + sha.UpdateData((uint8*)&t, 4); + sha.UpdateData((uint8*)&clientSeed, 4); + sha.UpdateData((uint8*)&_authSeed, 4); + sha.UpdateBigNumbers(&k, NULL); + sha.Finalize(); + + if (memcmp(sha.GetDigest(), digest, 20)) + { + SendAuthResponseError(AUTH_FAILED); + TC_LOG_ERROR("network", "WorldSocket::HandleAuthSession: Authentication failed for account: %u ('%s') address: %s", id, account.c_str(), address.c_str()); + DelayedCloseSocket(); + return; + } + ///- Re-check ip locking (same check as in auth). if (fields[3].GetUInt8() == 1) // if ip is locked { @@ -306,12 +379,11 @@ void WorldSocket::HandleAuthSession(WorldPacket& recvPacket) TC_LOG_DEBUG("network", "WorldSocket::HandleAuthSession: Sent Auth Response (Account IP differs. Original IP: %s, new IP: %s).", fields[2].GetCString(), address.c_str()); // We could log on hook only instead of an additional db log, however action logger is config based. Better keep DB logging as well sScriptMgr->OnFailedAccountLogin(id); + DelayedCloseSocket(); return; } } - k.SetHexStr(fields[1].GetCString()); - int64 mutetime = fields[5].GetInt64(); //! Negative mutetime indicates amount of seconds to be muted effective on next login - which is now. if (mutetime < 0) @@ -331,16 +403,6 @@ void WorldSocket::HandleAuthSession(WorldPacket& recvPacket) locale = LOCALE_enUS; uint32 recruiter = fields[7].GetUInt32(); - std::string os = fields[8].GetString(); - - // Must be done before WorldSession is created - if (wardenActive && os != "Win" && os != "OSX") - { - SendAuthResponseError(AUTH_REJECT); - TC_LOG_ERROR("network", "WorldSocket::HandleAuthSession: Client %s attempted to log in using invalid client OS (%s).", address.c_str(), os.c_str()); - return; - } - // Checks gmlevel per Realm stmt = LoginDatabase.GetPreparedStatement(LOGIN_GET_GMLEVEL_BY_REALMID); @@ -370,6 +432,7 @@ void WorldSocket::HandleAuthSession(WorldPacket& recvPacket) SendAuthResponseError(AUTH_BANNED); TC_LOG_ERROR("network", "WorldSocket::HandleAuthSession: Sent Auth Response (Account banned)."); sScriptMgr->OnFailedAccountLogin(id); + DelayedCloseSocket(); return; } @@ -381,23 +444,7 @@ void WorldSocket::HandleAuthSession(WorldPacket& recvPacket) SendAuthResponseError(AUTH_UNAVAILABLE); TC_LOG_INFO("network", "WorldSocket::HandleAuthSession: User tries to login but his security level is not enough"); sScriptMgr->OnFailedAccountLogin(id); - return; - } - - // Check that Key and account name are the same on client and server - uint32 t = 0; - - sha.UpdateData(account); - sha.UpdateData((uint8*)&t, 4); - sha.UpdateData((uint8*)&clientSeed, 4); - sha.UpdateData((uint8*)&_authSeed, 4); - sha.UpdateBigNumbers(&k, NULL); - sha.Finalize(); - - if (memcmp(sha.GetDigest(), digest, 20)) - { - SendAuthResponseError(AUTH_FAILED); - TC_LOG_ERROR("network", "WorldSocket::HandleAuthSession: Authentication failed for account: %u ('%s') address: %s", id, account.c_str(), address.c_str()); + DelayedCloseSocket(); return; } @@ -424,19 +471,15 @@ void WorldSocket::HandleAuthSession(WorldPacket& recvPacket) LoginDatabase.Execute(stmt); - // NOTE ATM the socket is single-threaded, have this in mind ... - _worldSession = new WorldSession(id, battlenetAccountId, shared_from_this(), AccountTypes(security), expansion, mutetime, locale, recruiter, isRecruiter); - - _authCrypt.Init(&k); + // At this point, we can safely hook a successful login + sScriptMgr->OnAccountLogin(id); + _worldSession = new WorldSession(id, battlenetAccountId, shared_from_this(), AccountTypes(security), expansion, mutetime, locale, recruiter, isRecruiter); _worldSession->LoadGlobalAccountData(); _worldSession->LoadTutorialsData(); _worldSession->ReadAddonsInfo(addonsData); _worldSession->LoadPermissions(); - // At this point, we can safely hook a successful login - sScriptMgr->OnAccountLogin(id); - // Initialize Warden system only if it is enabled by config if (wardenActive) _worldSession->InitWarden(&k, os); diff --git a/src/server/game/Server/WorldSocket.h b/src/server/game/Server/WorldSocket.h index 404999499ef..d53896274d7 100644 --- a/src/server/game/Server/WorldSocket.h +++ b/src/server/game/Server/WorldSocket.h @@ -48,6 +48,8 @@ struct ClientPktHeader { uint16 size; uint32 cmd; + + bool IsValid() const { return size >= 4 && size < 10240 && (cmd < NUM_OPCODE_HANDLERS || (header.cmd >> 16) == 0x4C52); } }; #pragma pack(pop) |
