Professional Documents
Culture Documents
* This file is part of the AzerothCore Project. See AUTHORS file for Copyright
information
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by the
* Free Software Foundation; either version 3 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "Warden.h"
#include "AccountMgr.h"
#include "BanMgr.h"
#include "ByteBuffer.h"
#include "Common.h"
#include "Log.h"
#include "Opcodes.h"
#include "Player.h"
#include "SharedDefines.h"
#include "Util.h"
#include "World.h"
#include "WorldPacket.h"
#include "WorldSession.h"
#include <openssl/sha.h>
Warden::~Warden()
{
delete[] _module->CompressedData;
delete _module;
_module = nullptr;
_initialized = false;
}
void Warden::SendModuleToClient()
{
LOG_DEBUG("warden", "Send module to client");
void Warden::RequestModule()
{
LOG_DEBUG("warden", "Request module");
EndianConvert(request.Size);
if (_dataSent)
{
uint32 maxClientResponseDelay = sWorld-
>getIntConfig(CONFIG_WARDEN_CLIENT_RESPONSE_DELAY);
if (maxClientResponseDelay > 0)
{
if (_clientResponseTimer > maxClientResponseDelay * IN_MILLISECONDS)
{
_session->KickPlayer("Warden: clientResponseTimer >
maxClientResponseDelay (Warden::Update)");
}
else
{
_clientResponseTimer += diff;
}
}
}
else
{
if (diff >= _checkTimer)
{
RequestChecks();
}
else
{
_checkTimer -= diff;
}
}
}
if (checksum != newChecksum)
{
LOG_DEBUG("warden", "CHECKSUM IS NOT VALID");
return false;
}
else
{
LOG_DEBUG("warden", "CHECKSUM IS VALID");
return true;
}
}
struct keyData
{
union
{
struct
{
uint8 bytes[20];
} bytes;
struct
{
uint32 ints[5];
} ints;
};
};
uint32 Warden::BuildChecksum(const uint8* data, uint32 length)
{
keyData hash;
SHA1(data, length, hash.bytes.bytes);
uint32 checkSum = 0;
for (uint8 i = 0; i < 5; ++i)
{
checkSum = checkSum ^ hash.ints.ints[i];
}
return checkSum;
}
if (checkData->Comment.empty())
{
causeMsg = "Warden id " + std::to_string(checkId) + " violation";
}
else
{
causeMsg = "Warden: " + checkData->Comment;
}
}
else
{
// if its not warden check id based, reason must be always provided
ASSERT(!reason.empty());
causeMsg = reason;
}
switch (action)
{
case WARDEN_ACTION_LOG:
break;
case WARDEN_ACTION_KICK:
{
_session->KickPlayer(causeMsg.find("Warden") != std::string::npos ?
causeMsg : "Warden: " + causeMsg);
break;
}
case WARDEN_ACTION_BAN:
{
std::stringstream duration;
duration << sWorld->getIntConfig(CONFIG_WARDEN_CLIENT_BAN_DURATION) <<
"s";
std::string accountName;
AccountMgr::GetName(_session->GetAccountId(), accountName);
sBan->BanAccount(accountName, duration.str(), causeMsg, "Server");
break;
}
}
std::string reportMsg;
if (checkId)
{
if (Player const* plr = _session->GetPlayer())
{
std::string const reportFormat = "Player %s (guid %u, account id: %u)
failed warden %u check (%s). Action: %s";
reportMsg = Acore::StringFormat(reportFormat, plr->GetName().c_str(),
plr->GetGUID().GetCounter(), _session->GetAccountId(),
checkId, ((checkData && !checkData-
>Comment.empty()) ? checkData->Comment.c_str() : "<warden comment is not set>"),
GetWardenActionStr(action).c_str());
}
else
{
std::string const reportFormat = "Account id: %u failed warden %u
check. Action: %s";
reportMsg = Acore::StringFormat(reportFormat, _session->GetAccountId(),
checkId, GetWardenActionStr(action).c_str());
}
}
else
{
if (Player const* plr = _session->GetPlayer())
{
std::string const reportFormat = "Player %s (guid %u, account id: %u)
triggered warden penalty by reason: %s. Action: %s";
reportMsg = Acore::StringFormat(reportFormat, plr->GetName().c_str(),
plr->GetGUID().GetCounter(), _session->GetAccountId(), causeMsg.c_str(),
GetWardenActionStr(action).c_str());
}
else
{
std::string const reportFormat = "Account id: %u failed warden %u
check. Action: %s";
reportMsg = Acore::StringFormat(reportFormat, _session->GetAccountId(),
causeMsg.c_str(), GetWardenActionStr(action).c_str());
}
}
reportMsg = "Warden: " + reportMsg;
LOG_INFO("warden", "> Warden: {}", reportMsg);
}
uint16 id = 0;
{
std::stringstream msg2(msg);
std::string temp;
while (msg2 >> temp)
{
// Found check id - stop loop
if (std::stringstream(temp) >> id)
break;
}
}
_warden->DecryptData(recvData.contents(), recvData.size());
uint8 opcode;
recvData >> opcode;
LOG_DEBUG("warden", "Got packet, opcode {:02X}, size {}", opcode,
uint32(recvData.size()));
recvData.hexlike();
switch (opcode)
{
case WARDEN_CMSG_MODULE_MISSING:
_warden->SendModuleToClient();
break;
case WARDEN_CMSG_MODULE_OK:
_warden->RequestHash();
break;
case WARDEN_CMSG_CHEAT_CHECKS_RESULT:
_warden->HandleData(recvData);
break;
case WARDEN_CMSG_MEM_CHECKS_RESULT:
LOG_DEBUG("warden", "NYI WARDEN_CMSG_MEM_CHECKS_RESULT received!");
break;
case WARDEN_CMSG_HASH_RESULT:
_warden->HandleHashResult(recvData);
_warden->InitializeModule();
break;
case WARDEN_CMSG_MODULE_FAILED:
LOG_DEBUG("warden", "NYI WARDEN_CMSG_MODULE_FAILED received!");
break;
default:
LOG_DEBUG("warden", "Got unknown warden opcode {:02X} of size {}.",
opcode, uint32(recvData.size() - 1));
break;
}
}