r5sdk/r5dev/engine/client/client.cpp

477 lines
16 KiB
C++
Raw Normal View History

//===============================================================================//
//
// Purpose:
//
// $NoKeywords: $
//
//===============================================================================//
// client.cpp: implementation of the CClient class.
2022-06-16 18:04:43 +02:00
//
///////////////////////////////////////////////////////////////////////////////////
Code base refactor + major performance and readability improvement. Read description for details. * Codebase restructured to SourceSDK codebase style and .cpp/.h assertion paths in the game executable. * Document most functions with valve style 'Purpose' blocks. * Rename variables to match the rest of the codebase and Valve's naming convention. * Dedicated DLL and the SDKLauncher now share the same codebase as the DevSDK. * Obtain globals or pointers directly instead of waiting for runtime initialized data. * Dynamically search for all functions and globals (this doesn't count for dedicated yet!). * Initialize most in-SDK variables. * Move certain prints and other utilities under ConVars to reduce verbosity and increase performance. * Print all pattern scan results through a virtual function to make it easier to add and debug new patterns in the future. * Type global var pointers appropriately if class or type is known and implemented. * Forward declare 'CClient' class to avoid having 2 'g_pClient' copies. * Add IDA's pseudo definitions for easier prototyping with decompiled assembly code. * RPAK decompress Command callback implementation. * Load decompressed RPaks from 'paks\Win32\' overriding the ones in 'paks\Win64\' (the decompress callback will automatically fix the header and write it to 'paks\Win32\'). * VPK decompress Command callback implementation. * Move CRC32 ands Adler32 to implementation files. * Server will print out more details about the connecting client. * Upgrade ImGui lib to v1.86. * Don't compile id3dx.h for dedicated. * Don't compile id3dx.cpp for dedicated * Implement DevMsg print function allowing to print information to the in-game VGUI/RUI console overlay, ImGui console overlay and the external windows console * Fixed bug where the Error function would not properly terminate the process when an error is called. This caused access violations for critical/non-recoverable errors. * Fixed bug where the game would crash if the console or server browser was enabled while the game was still starting up. * Several bug fixes for the dedicated server (warning: dedicated is still considered work-in-progress!).
2021-12-25 22:36:38 +01:00
#include "core/stdafx.h"
#include "tier1/cvar.h"
#include "tier1/strtools.h"
#include "mathlib/sha256.h"
#include "engine/server/server.h"
#include "engine/client/client.h"
#ifndef CLIENT_DLL
#include "jwt/include/decode.h"
#endif
Code base refactor + major performance and readability improvement. Read description for details. * Codebase restructured to SourceSDK codebase style and .cpp/.h assertion paths in the game executable. * Document most functions with valve style 'Purpose' blocks. * Rename variables to match the rest of the codebase and Valve's naming convention. * Dedicated DLL and the SDKLauncher now share the same codebase as the DevSDK. * Obtain globals or pointers directly instead of waiting for runtime initialized data. * Dynamically search for all functions and globals (this doesn't count for dedicated yet!). * Initialize most in-SDK variables. * Move certain prints and other utilities under ConVars to reduce verbosity and increase performance. * Print all pattern scan results through a virtual function to make it easier to add and debug new patterns in the future. * Type global var pointers appropriately if class or type is known and implemented. * Forward declare 'CClient' class to avoid having 2 'g_pClient' copies. * Add IDA's pseudo definitions for easier prototyping with decompiled assembly code. * RPAK decompress Command callback implementation. * Load decompressed RPaks from 'paks\Win32\' overriding the ones in 'paks\Win64\' (the decompress callback will automatically fix the header and write it to 'paks\Win32\'). * VPK decompress Command callback implementation. * Move CRC32 ands Adler32 to implementation files. * Server will print out more details about the connecting client. * Upgrade ImGui lib to v1.86. * Don't compile id3dx.h for dedicated. * Don't compile id3dx.cpp for dedicated * Implement DevMsg print function allowing to print information to the in-game VGUI/RUI console overlay, ImGui console overlay and the external windows console * Fixed bug where the Error function would not properly terminate the process when an error is called. This caused access violations for critical/non-recoverable errors. * Fixed bug where the game would crash if the console or server browser was enabled while the game was still starting up. * Several bug fixes for the dedicated server (warning: dedicated is still considered work-in-progress!).
2021-12-25 22:36:38 +01:00
// Absolute max string cmd length, any character past this will be NULLED.
#define STRINGCMD_MAX_LEN 512
2022-05-21 18:56:56 +02:00
//---------------------------------------------------------------------------------
// Purpose: throw away any residual garbage in the channel
//---------------------------------------------------------------------------------
void CClient::Clear(void)
{
2022-09-22 00:08:49 +02:00
#ifndef CLIENT_DLL
g_ServerPlayer[GetUserID()].Reset(); // Reset ServerPlayer slot.
2022-09-22 00:08:49 +02:00
#endif // !CLIENT_DLL
2022-05-21 18:56:56 +02:00
v_CClient_Clear(this);
}
Code base refactor + major performance and readability improvement. Read description for details. * Codebase restructured to SourceSDK codebase style and .cpp/.h assertion paths in the game executable. * Document most functions with valve style 'Purpose' blocks. * Rename variables to match the rest of the codebase and Valve's naming convention. * Dedicated DLL and the SDKLauncher now share the same codebase as the DevSDK. * Obtain globals or pointers directly instead of waiting for runtime initialized data. * Dynamically search for all functions and globals (this doesn't count for dedicated yet!). * Initialize most in-SDK variables. * Move certain prints and other utilities under ConVars to reduce verbosity and increase performance. * Print all pattern scan results through a virtual function to make it easier to add and debug new patterns in the future. * Type global var pointers appropriately if class or type is known and implemented. * Forward declare 'CClient' class to avoid having 2 'g_pClient' copies. * Add IDA's pseudo definitions for easier prototyping with decompiled assembly code. * RPAK decompress Command callback implementation. * Load decompressed RPaks from 'paks\Win32\' overriding the ones in 'paks\Win64\' (the decompress callback will automatically fix the header and write it to 'paks\Win32\'). * VPK decompress Command callback implementation. * Move CRC32 ands Adler32 to implementation files. * Server will print out more details about the connecting client. * Upgrade ImGui lib to v1.86. * Don't compile id3dx.h for dedicated. * Don't compile id3dx.cpp for dedicated * Implement DevMsg print function allowing to print information to the in-game VGUI/RUI console overlay, ImGui console overlay and the external windows console * Fixed bug where the Error function would not properly terminate the process when an error is called. This caused access violations for critical/non-recoverable errors. * Fixed bug where the game would crash if the console or server browser was enabled while the game was still starting up. * Several bug fixes for the dedicated server (warning: dedicated is still considered work-in-progress!).
2021-12-25 22:36:38 +01:00
//---------------------------------------------------------------------------------
// Purpose: throw away any residual garbage in the channel
// Input : *pClient -
//---------------------------------------------------------------------------------
void CClient::VClear(CClient* pClient)
2022-05-21 18:56:56 +02:00
{
2023-07-17 17:38:21 +02:00
pClient->Clear();
2022-05-21 18:56:56 +02:00
}
static const char JWT_PUBLIC_KEY[] =
"-----BEGIN PUBLIC KEY-----\n"
"MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2/335exIZ6LE8pYi6e50\n"
"7tH19tXaeeEJVF5XXpTCXpndXIIWVimvg6xQ381eajySDw93wvG1DzW3U/6LHzyt\n"
"Q++N8w7N+FwnXyoDUD5Y8hheTZv6jjLoYT8ZtsMl20k9UosrbFBTMUhgmIT2dVth\n"
"LH+rT9ohpUNwQXHJvTOs9eY74GyfFw93+32LANBPZ8b+S8S3oZnKFVeCxRkYKsV0\n"
"b34POHVBbXNw6Kt163gR5zaiCfJJtRto9AA7MV2t9pfy8CChs3uJ+Xn7QVHD5cqt\n"
"Msg9MBac2Pvs2j+8wJ/igAVL5L81z3FXVt04id59TfPMUbYhRfY8pk7FB0MCigOH\n"
"dwIDAQAB\n"
"-----END PUBLIC KEY-----\n";
bool CClient::Authenticate(const char* const playerName, char* const reasonBuf, const size_t reasonBufLen)
{
#ifndef CLIENT_DLL
// don't bother checking origin auth on bots or local clients
if (IsFakeClient() || GetNetChan()->GetRemoteAddress().IsLoopback())
return true;
#define FORMAT_ERROR_REASON(fmt, ...) V_snprintf(reasonBuf, reasonBufLen, fmt, ##__VA_ARGS__);
KeyValues* cl_onlineAuthTokenKv = this->m_ConVars->FindKey("cl_onlineAuthToken");
KeyValues* cl_onlineAuthTokenSignature1Kv = this->m_ConVars->FindKey("cl_onlineAuthTokenSignature1");
KeyValues* cl_onlineAuthTokenSignature2Kv = this->m_ConVars->FindKey("cl_onlineAuthTokenSignature2");
if (!cl_onlineAuthTokenKv || !cl_onlineAuthTokenSignature1Kv)
{
FORMAT_ERROR_REASON("Missing token");
return false;
}
const char* onlineAuthToken = cl_onlineAuthTokenKv->GetString();
const char* onlineAuthTokenSignature1 = cl_onlineAuthTokenSignature1Kv->GetString();
const char* onlineAuthTokenSignature2 = cl_onlineAuthTokenSignature2Kv->GetString();
const std::string fullToken = Format("%s.%s%s", onlineAuthToken, onlineAuthTokenSignature1, onlineAuthTokenSignature2);
struct l8w8jwt_decoding_params params;
l8w8jwt_decoding_params_init(&params);
params.alg = L8W8JWT_ALG_RS256;
params.jwt = (char*)fullToken.c_str();
params.jwt_length = fullToken.length();
params.verification_key = (unsigned char*)JWT_PUBLIC_KEY;
params.verification_key_length = strlen(JWT_PUBLIC_KEY);
params.validate_exp = 1;
params.exp_tolerance_seconds = 1;
params.validate_iat = 1;
params.iat_tolerance_seconds = 30;
l8w8jwt_claim* claims = nullptr;
size_t numClaims = 0;
enum l8w8jwt_validation_result validation_result;
const int r = l8w8jwt_decode(&params, &validation_result, &claims, &numClaims);
if (r != L8W8JWT_SUCCESS)
{
FORMAT_ERROR_REASON("Code %i", r);
return false;
}
if (validation_result != L8W8JWT_VALID)
{
char reasonBuffer[256];
l8w8jwt_get_validation_result_desc(validation_result, reasonBuffer, sizeof(reasonBuffer));
FORMAT_ERROR_REASON("%s", reasonBuffer);
return false;
}
bool foundSessionId = false;
for (size_t i = 0; i < numClaims; ++i)
{
// session id
if (!strcmp(claims[i].key, "sessionId"))
{
const char* const sessionId = claims[i].value;
const std::string newId = Format(
"%lld-%s-%s",
this->m_DataBlock.userData,
playerName,
g_pMasterServer->GetHostIP().c_str()
);
DevMsg(eDLL_T::SERVER, "%s: newId=%s\n", __FUNCTION__, newId.c_str());
const std::string hashedNewId = sha256(newId);
if (hashedNewId.compare(sessionId) != 0)
{
FORMAT_ERROR_REASON("Token is not authorized for the connecting client");
return false;
}
foundSessionId = true;
}
}
if (!foundSessionId)
{
FORMAT_ERROR_REASON("No session ID");
return false;
}
#undef REJECT_CONNECTION
#endif // !CLIENT_DLL
return true;
}
2022-05-21 18:56:56 +02:00
//---------------------------------------------------------------------------------
// Purpose: connect new client
// Input : *szName -
// *pNetChannel -
// bFakePlayer -
// *conVars -
2022-05-21 18:56:56 +02:00
// *szMessage -
// nMessageSize -
// Output : true if connection was successful, false otherwise
2022-05-21 18:56:56 +02:00
//---------------------------------------------------------------------------------
bool CClient::Connect(const char* szName, void* pNetChannel, bool bFakePlayer,
CUtlVector<NET_SetConVar::cvar_t>* conVars, char* szMessage, int nMessageSize)
{
#ifndef CLIENT_DLL
g_ServerPlayer[GetUserID()].Reset(); // Reset ServerPlayer slot.
#endif
if (!v_CClient_Connect(this, szName, pNetChannel, bFakePlayer, conVars, szMessage, nMessageSize))
return false;
#ifndef CLIENT_DLL
#define REJECT_CONNECTION(fmt, ...) V_snprintf(szMessage, nMessageSize, fmt, ##__VA_ARGS__);
char authFailReason[512];
if (!Authenticate(szName, authFailReason, sizeof(authFailReason)))
{
REJECT_CONNECTION("Failed to verify authentication token [%s]", authFailReason);
return false;
}
#undef REJECT_CONNECTION
#endif // !CLIENT_DLL
return true;
}
//---------------------------------------------------------------------------------
// Purpose: connect new client
// Input : *pClient -
// *szName -
// *pNetChannel -
// bFakePlayer -
// *a5 -
// *szMessage -
// nMessageSize -
// Output : true if connection was successful, false otherwise
Code base refactor + major performance and readability improvement. Read description for details. * Codebase restructured to SourceSDK codebase style and .cpp/.h assertion paths in the game executable. * Document most functions with valve style 'Purpose' blocks. * Rename variables to match the rest of the codebase and Valve's naming convention. * Dedicated DLL and the SDKLauncher now share the same codebase as the DevSDK. * Obtain globals or pointers directly instead of waiting for runtime initialized data. * Dynamically search for all functions and globals (this doesn't count for dedicated yet!). * Initialize most in-SDK variables. * Move certain prints and other utilities under ConVars to reduce verbosity and increase performance. * Print all pattern scan results through a virtual function to make it easier to add and debug new patterns in the future. * Type global var pointers appropriately if class or type is known and implemented. * Forward declare 'CClient' class to avoid having 2 'g_pClient' copies. * Add IDA's pseudo definitions for easier prototyping with decompiled assembly code. * RPAK decompress Command callback implementation. * Load decompressed RPaks from 'paks\Win32\' overriding the ones in 'paks\Win64\' (the decompress callback will automatically fix the header and write it to 'paks\Win32\'). * VPK decompress Command callback implementation. * Move CRC32 ands Adler32 to implementation files. * Server will print out more details about the connecting client. * Upgrade ImGui lib to v1.86. * Don't compile id3dx.h for dedicated. * Don't compile id3dx.cpp for dedicated * Implement DevMsg print function allowing to print information to the in-game VGUI/RUI console overlay, ImGui console overlay and the external windows console * Fixed bug where the Error function would not properly terminate the process when an error is called. This caused access violations for critical/non-recoverable errors. * Fixed bug where the game would crash if the console or server browser was enabled while the game was still starting up. * Several bug fixes for the dedicated server (warning: dedicated is still considered work-in-progress!).
2021-12-25 22:36:38 +01:00
//---------------------------------------------------------------------------------
bool CClient::VConnect(CClient* pClient, const char* szName, void* pNetChannel, bool bFakePlayer,
CUtlVector<NET_SetConVar::cvar_t>* conVars, char* szMessage, int nMessageSize)
Code base refactor + major performance and readability improvement. Read description for details. * Codebase restructured to SourceSDK codebase style and .cpp/.h assertion paths in the game executable. * Document most functions with valve style 'Purpose' blocks. * Rename variables to match the rest of the codebase and Valve's naming convention. * Dedicated DLL and the SDKLauncher now share the same codebase as the DevSDK. * Obtain globals or pointers directly instead of waiting for runtime initialized data. * Dynamically search for all functions and globals (this doesn't count for dedicated yet!). * Initialize most in-SDK variables. * Move certain prints and other utilities under ConVars to reduce verbosity and increase performance. * Print all pattern scan results through a virtual function to make it easier to add and debug new patterns in the future. * Type global var pointers appropriately if class or type is known and implemented. * Forward declare 'CClient' class to avoid having 2 'g_pClient' copies. * Add IDA's pseudo definitions for easier prototyping with decompiled assembly code. * RPAK decompress Command callback implementation. * Load decompressed RPaks from 'paks\Win32\' overriding the ones in 'paks\Win64\' (the decompress callback will automatically fix the header and write it to 'paks\Win32\'). * VPK decompress Command callback implementation. * Move CRC32 ands Adler32 to implementation files. * Server will print out more details about the connecting client. * Upgrade ImGui lib to v1.86. * Don't compile id3dx.h for dedicated. * Don't compile id3dx.cpp for dedicated * Implement DevMsg print function allowing to print information to the in-game VGUI/RUI console overlay, ImGui console overlay and the external windows console * Fixed bug where the Error function would not properly terminate the process when an error is called. This caused access violations for critical/non-recoverable errors. * Fixed bug where the game would crash if the console or server browser was enabled while the game was still starting up. * Several bug fixes for the dedicated server (warning: dedicated is still considered work-in-progress!).
2021-12-25 22:36:38 +01:00
{
return pClient->Connect(szName, pNetChannel, bFakePlayer, conVars, szMessage, nMessageSize);;
Code base refactor + major performance and readability improvement. Read description for details. * Codebase restructured to SourceSDK codebase style and .cpp/.h assertion paths in the game executable. * Document most functions with valve style 'Purpose' blocks. * Rename variables to match the rest of the codebase and Valve's naming convention. * Dedicated DLL and the SDKLauncher now share the same codebase as the DevSDK. * Obtain globals or pointers directly instead of waiting for runtime initialized data. * Dynamically search for all functions and globals (this doesn't count for dedicated yet!). * Initialize most in-SDK variables. * Move certain prints and other utilities under ConVars to reduce verbosity and increase performance. * Print all pattern scan results through a virtual function to make it easier to add and debug new patterns in the future. * Type global var pointers appropriately if class or type is known and implemented. * Forward declare 'CClient' class to avoid having 2 'g_pClient' copies. * Add IDA's pseudo definitions for easier prototyping with decompiled assembly code. * RPAK decompress Command callback implementation. * Load decompressed RPaks from 'paks\Win32\' overriding the ones in 'paks\Win64\' (the decompress callback will automatically fix the header and write it to 'paks\Win32\'). * VPK decompress Command callback implementation. * Move CRC32 ands Adler32 to implementation files. * Server will print out more details about the connecting client. * Upgrade ImGui lib to v1.86. * Don't compile id3dx.h for dedicated. * Don't compile id3dx.cpp for dedicated * Implement DevMsg print function allowing to print information to the in-game VGUI/RUI console overlay, ImGui console overlay and the external windows console * Fixed bug where the Error function would not properly terminate the process when an error is called. This caused access violations for critical/non-recoverable errors. * Fixed bug where the game would crash if the console or server browser was enabled while the game was still starting up. * Several bug fixes for the dedicated server (warning: dedicated is still considered work-in-progress!).
2021-12-25 22:36:38 +01:00
}
//---------------------------------------------------------------------------------
// Purpose: disconnect client
// Input : nRepLvl -
// *szReason -
// ... -
//---------------------------------------------------------------------------------
void CClient::Disconnect(const Reputation_t nRepLvl, const char* szReason, ...)
{
if (m_nSignonState != SIGNONSTATE::SIGNONSTATE_NONE)
{
char szBuf[1024];
{/////////////////////////////
va_list vArgs;
va_start(vArgs, szReason);
vsnprintf(szBuf, sizeof(szBuf), szReason, vArgs);
szBuf[sizeof(szBuf) - 1] = '\0';
va_end(vArgs);
}/////////////////////////////
v_CClient_Disconnect(this, nRepLvl, szBuf);
}
}
//---------------------------------------------------------------------------------
// Purpose: activate player
// Input : *pClient -
//---------------------------------------------------------------------------------
void CClient::VActivatePlayer(CClient* pClient)
{
// Set the client instance to 'ready' before calling ActivatePlayer.
pClient->SetPersistenceState(PERSISTENCE::PERSISTENCE_READY);
v_CClient_ActivatePlayer(pClient);
#ifndef CLIENT_DLL
const CNetChan* pNetChan = pClient->GetNetChan();
if (pNetChan && sv_showconnecting->GetBool())
{
Msg(eDLL_T::SERVER, "Activated player #%d; channel %s(%s) ('%llu')\n",
pClient->GetUserID(), pNetChan->GetName(), pNetChan->GetAddress(), pClient->GetNucleusID());
}
#endif // !CLIENT_DLL
}
//---------------------------------------------------------------------------------
// Purpose: send a net message with replay.
// set 'CNetMessage::m_nGroup' to 'NoReplay' to disable replay.
// Input : *pMsg -
// bLocal -
// bForceReliable -
// bVoice -
//---------------------------------------------------------------------------------
bool CClient::SendNetMsgEx(CNetMessage* pMsg, char bLocal, bool bForceReliable, bool bVoice)
{
if (!ShouldReplayMessage(pMsg))
{
// Don't copy the message into the replay buffer.
pMsg->m_nGroup = NetMessageGroup::NoReplay;
}
return v_CClient_SendNetMsgEx(this, pMsg, bLocal, bForceReliable, bVoice);
}
//---------------------------------------------------------------------------------
// Purpose: send a snapshot
// Input : *pClient -
// *pFrame -
// nTick -
// nTickAck -
//---------------------------------------------------------------------------------
void* CClient::VSendSnapshot(CClient* pClient, CClientFrame* pFrame, int nTick, int nTickAck)
{
return v_CClient_SendSnapshot(pClient, pFrame, nTick, nTickAck);
}
//---------------------------------------------------------------------------------
// Purpose: internal hook to 'CClient::SendNetMsgEx'
// Input : *pClient -
// *pMsg -
// bLocal -
// bForceReliable -
// bVoice -
//---------------------------------------------------------------------------------
bool CClient::VSendNetMsgEx(CClient* pClient, CNetMessage* pMsg, char bLocal, bool bForceReliable, bool bVoice)
{
return pClient->SendNetMsgEx(pMsg, bLocal, bForceReliable, bVoice);
}
//---------------------------------------------------------------------------------
// Purpose: some versions of the binary have an optimization that shifts the 'this'
// pointer of the CClient structure by 8 bytes to avoid having to cache the vftable
// pointer if it never get used. Here we shift it back so it aligns again.
//---------------------------------------------------------------------------------
CClient* AdjustShiftedThisPointer(CClient* shiftedPointer)
{
#if defined (GAMEDLL_S0) || defined (GAMEDLL_S1)
return shiftedPointer;
#elif defined (GAMEDLL_S2) || defined (GAMEDLL_S3)
/* Original function called method "CClient::ExecuteStringCommand" with an optimization
* that shifted the 'this' pointer with 8 bytes.
* Since this has been inlined with "CClient::ProcessStringCmd" as of S2, the shifting
* happens directly to anything calling this function. */
char* pShifted = reinterpret_cast<char*>(shiftedPointer) - 8;
return reinterpret_cast<CClient*>(pShifted);
#endif // !GAMEDLL_S0 || !GAMEDLL_S1
}
//---------------------------------------------------------------------------------
// Purpose: process string commands (kicking anyone attempting to DOS)
// Input : *pClient - (ADJ)
// *pMsg -
// Output : false if cmd should be passed to CServerGameClients
//---------------------------------------------------------------------------------
bool CClient::VProcessStringCmd(CClient* pClient, NET_StringCmd* pMsg)
{
#ifndef CLIENT_DLL
CClient* const pClient_Adj = AdjustShiftedThisPointer(pClient);
// Jettison the cmd if the client isn't active.
if (!pClient_Adj->IsActive())
return true;
const int nUserID = pClient_Adj->GetUserID();
ServerPlayer_t* const pSlot = &g_ServerPlayer[nUserID];
const double flStartTime = Plat_FloatTime();
const int nCmdQuotaLimit = sv_quota_stringCmdsPerSecond->GetInt();
2022-09-22 21:20:37 +02:00
if (!nCmdQuotaLimit)
return true;
const char* pCmd = pMsg->cmd;
// Just skip if the cmd pointer is null, we still check if the
// client sent too many commands and take appropriate actions.
// The internal function discards the command if it's null.
if (pCmd)
{
// There is an issue in CUtlBuffer::ParseToken() that causes it to read
// past its buffer; mostly seems to happen on 32bit, but a carefully
// crafted string should work on 64bit too). The fix is to just null
// everything past the maximum allowed length. The second 'theoretical'
// fix would be to properly fix CUtlBuffer::ParseToken() by computing
// the UTF8 character size each iteration and check if it still doesn't
// exceed bounds.
memset(&pMsg->buffer[STRINGCMD_MAX_LEN],
'\0', sizeof(pMsg->buffer) - (STRINGCMD_MAX_LEN));
if (!V_IsValidUTF8(pCmd))
{
Warning(eDLL_T::SERVER, "Removing client '%s' from slot #%i ('%llu' sent invalid string command!)\n",
pClient_Adj->GetNetChan()->GetAddress(), pClient_Adj->GetUserID(), pClient_Adj->GetNucleusID());
pClient_Adj->Disconnect(Reputation_t::REP_MARK_BAD, "#DISCONNECT_INVALID_STRINGCMD");
return true;
}
}
if (flStartTime - pSlot->m_flStringCommandQuotaTimeStart >= 1.0)
{
pSlot->m_flStringCommandQuotaTimeStart = flStartTime;
pSlot->m_nStringCommandQuotaCount = 0;
}
++pSlot->m_nStringCommandQuotaCount;
2022-09-22 21:20:37 +02:00
if (pSlot->m_nStringCommandQuotaCount > nCmdQuotaLimit)
{
Warning(eDLL_T::SERVER, "Removing client '%s' from slot #%i ('%llu' exceeded string command quota!)\n",
pClient_Adj->GetNetChan()->GetAddress(), pClient_Adj->GetUserID(), pClient_Adj->GetNucleusID());
pClient_Adj->Disconnect(Reputation_t::REP_MARK_BAD, "#DISCONNECT_STRINGCMD_OVERFLOW");
return true;
}
#endif // !CLIENT_DLL
return v_CClient_ProcessStringCmd(pClient, pMsg);
}
//---------------------------------------------------------------------------------
// Purpose: process set convar
// Input : *pClient - (ADJ)
// *pMsg -
// Output :
//---------------------------------------------------------------------------------
bool CClient::VProcessSetConVar(CClient* pClient, NET_SetConVar* pMsg)
{
#ifndef CLIENT_DLL
CClient* const pAdj = AdjustShiftedThisPointer(pClient);
ServerPlayer_t* const pSlot = &g_ServerPlayer[pAdj->GetUserID()];
// This loop never exceeds 255 iterations, NET_SetConVar::ReadFromBuffer(...)
// reads and inserts up to 255 entries in the vector (reads a byte for size).
FOR_EACH_VEC(pMsg->m_ConVars, i)
{
const NET_SetConVar::cvar_t& entry = pMsg->m_ConVars[i];
const char* const name = entry.name;
const char* const value = entry.value;
// Discard any ConVar change request if it contains funky characters.
bool bFunky = false;
for (const char* s = name; *s != '\0'; ++s)
{
if (!isalnum(*s) && *s != '_')
{
bFunky = true;
break;
}
}
if (bFunky)
{
DevWarning(eDLL_T::SERVER, "Ignoring ConVar change request for variable '%s' from client '%s'; invalid characters in the variable name\n",
name, pAdj->GetClientName());
continue;
}
// The initial set of ConVars must contain all client ConVars that are
// flagged UserInfo. This is a simple fix to exploits that send bogus
// data later, and catches bugs, such as new UserInfo ConVars appearing
// later, which shouldn't happen.
if (pSlot->m_bInitialConVarsSet && !pAdj->m_ConVars->FindKey(name))
{
DevWarning(eDLL_T::SERVER, "UserInfo update from \"%s\" ignored: %s = %s\n",
pAdj->GetClientName(), name, value);
continue;
}
// Add ConVar to list and set string.
pAdj->m_ConVars->SetString(name, value);
DevMsg(eDLL_T::SERVER, "UserInfo update from \"%s\": %s = %s\n", pAdj->GetClientName(), name, value);
}
pSlot->m_bInitialConVarsSet = true;
pAdj->m_bConVarsChanged = true;
#endif // !CLIENT_DLL
return true;
}
void VClient::Attach(void) const
{
#ifndef CLIENT_DLL
DetourAttach((LPVOID*)&v_CClient_Clear, &CClient::VClear);
DetourAttach((LPVOID*)&v_CClient_Connect, &CClient::VConnect);
DetourAttach((LPVOID*)&v_CClient_ActivatePlayer, &CClient::VActivatePlayer);
DetourAttach((LPVOID*)&v_CClient_SendNetMsgEx, &CClient::VSendNetMsgEx);
//DetourAttach((LPVOID*)&p_CClient_SendSnapshot, &CClient::VSendSnapshot);
DetourAttach((LPVOID*)&v_CClient_ProcessStringCmd, &CClient::VProcessStringCmd);
DetourAttach((LPVOID*)&v_CClient_ProcessSetConVar, &CClient::VProcessSetConVar);
#endif // !CLIENT_DLL
}
void VClient::Detach(void) const
{
#ifndef CLIENT_DLL
DetourDetach((LPVOID*)&v_CClient_Clear, &CClient::VClear);
DetourDetach((LPVOID*)&v_CClient_Connect, &CClient::VConnect);
DetourDetach((LPVOID*)&v_CClient_ActivatePlayer, &CClient::VActivatePlayer);
DetourDetach((LPVOID*)&v_CClient_SendNetMsgEx, &CClient::VSendNetMsgEx);
//DetourDetach((LPVOID*)&p_CClient_SendSnapshot, &CClient::VSendSnapshot);
DetourDetach((LPVOID*)&v_CClient_ProcessStringCmd, &CClient::VProcessStringCmd);
DetourDetach((LPVOID*)&v_CClient_ProcessSetConVar, &CClient::VProcessSetConVar);
#endif // !CLIENT_DLL
}