mirror of
https://github.com/EQEmu/Server.git
synced 2025-12-11 16:51:29 +00:00
[Feature] Client Checksum Verification (Resubmit old 1678) (#1922)
* [Feature] Client Checksum Verification (Resubmit old 1678) * Updated db version * Add new updatechecksum to CmakeLists.txt * Removed magic number and used constant * Fix new command to have access to worldserver * spacing, more venbose desc and remove unneeded check * Cleanup, refactoring Co-authored-by: Akkadius <akkadius1@gmail.com>
This commit is contained in:
parent
eca2ed0321
commit
2a5ddde78a
@ -997,6 +997,18 @@ bool Database::SetVariable(const std::string varname, const std::string &varvalu
|
||||
return true;
|
||||
}
|
||||
|
||||
void Database::SetAccountCRCField(uint32 account_id, std::string field_name, uint64 checksum)
|
||||
{
|
||||
QueryDatabase(
|
||||
fmt::format(
|
||||
"UPDATE `account` SET `{}` = '{}' WHERE `id` = {}",
|
||||
field_name,
|
||||
checksum,
|
||||
account_id
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
// Get zone starting points from DB
|
||||
bool Database::GetSafePoints(const char* zone_short_name, uint32 instance_version, float* safe_x, float* safe_y, float* safe_z, float* safe_heading, int16* min_status, uint8* min_level, char *flag_needed) {
|
||||
|
||||
@ -2285,7 +2297,7 @@ void Database::SetIPExemption(std::string account_ip, int exemption_amount) {
|
||||
auto row = results.begin();
|
||||
exemption_id = atoi(row[0]);
|
||||
}
|
||||
|
||||
|
||||
query = fmt::format(
|
||||
"INSERT INTO `ip_exemptions` (`exemption_ip`, `exemption_amount`) VALUES ('{}', {})",
|
||||
account_ip,
|
||||
|
||||
@ -190,6 +190,8 @@ public:
|
||||
|
||||
int16 CheckStatus(uint32 account_id);
|
||||
|
||||
void SetAccountCRCField(uint32 account_id, std::string field_name, uint64 checksum);
|
||||
|
||||
uint32 CheckLogin(const char* name, const char* password, const char *loginserver, int16* oStatus = 0);
|
||||
uint32 CreateAccount(const char* name, const char* password, int16 status, const char* loginserver, uint32 lsaccount_id);
|
||||
uint32 GetAccountIDFromLSID(const std::string& in_loginserver_id, uint32 in_loginserver_account_id, char* in_account_name = 0, int16* in_status = 0);
|
||||
|
||||
@ -558,6 +558,7 @@ N(OP_WhoAllRequest),
|
||||
N(OP_WhoAllResponse),
|
||||
N(OP_World_Client_CRC1),
|
||||
N(OP_World_Client_CRC2),
|
||||
N(OP_World_Client_CRC3),
|
||||
N(OP_WorldClientReady),
|
||||
N(OP_WorldComplete),
|
||||
N(OP_WorldLogout),
|
||||
|
||||
@ -5582,6 +5582,11 @@ struct SayLinkBodyFrame_Struct {
|
||||
/*056*/
|
||||
};
|
||||
|
||||
struct Checksum_Struct {
|
||||
uint64 checksum;
|
||||
uint8 data[2048];
|
||||
};
|
||||
|
||||
struct UpdateMovementEntry {
|
||||
/* 00 */ float Y;
|
||||
/* 04 */ float X;
|
||||
|
||||
@ -116,22 +116,24 @@ EQEmuLogSys *EQEmuLogSys::LoadLogSettingsDefaults()
|
||||
/**
|
||||
* Set Defaults
|
||||
*/
|
||||
log_settings[Logs::WorldServer].log_to_console = static_cast<uint8>(Logs::General);
|
||||
log_settings[Logs::ZoneServer].log_to_console = static_cast<uint8>(Logs::General);
|
||||
log_settings[Logs::QSServer].log_to_console = static_cast<uint8>(Logs::General);
|
||||
log_settings[Logs::UCSServer].log_to_console = static_cast<uint8>(Logs::General);
|
||||
log_settings[Logs::Crash].log_to_console = static_cast<uint8>(Logs::General);
|
||||
log_settings[Logs::MySQLError].log_to_console = static_cast<uint8>(Logs::General);
|
||||
log_settings[Logs::Loginserver].log_to_console = static_cast<uint8>(Logs::General);
|
||||
log_settings[Logs::HeadlessClient].log_to_console = static_cast<uint8>(Logs::General);
|
||||
log_settings[Logs::NPCScaling].log_to_gmsay = static_cast<uint8>(Logs::General);
|
||||
log_settings[Logs::HotReload].log_to_gmsay = static_cast<uint8>(Logs::General);
|
||||
log_settings[Logs::HotReload].log_to_console = static_cast<uint8>(Logs::General);
|
||||
log_settings[Logs::Loot].log_to_gmsay = static_cast<uint8>(Logs::General);
|
||||
log_settings[Logs::Scheduler].log_to_console = static_cast<uint8>(Logs::General);
|
||||
log_settings[Logs::Cheat].log_to_console = static_cast<uint8>(Logs::General);
|
||||
log_settings[Logs::HTTP].log_to_console = static_cast<uint8>(Logs::General);
|
||||
log_settings[Logs::HTTP].log_to_gmsay = static_cast<uint8>(Logs::General);
|
||||
log_settings[Logs::WorldServer].log_to_console = static_cast<uint8>(Logs::General);
|
||||
log_settings[Logs::ZoneServer].log_to_console = static_cast<uint8>(Logs::General);
|
||||
log_settings[Logs::QSServer].log_to_console = static_cast<uint8>(Logs::General);
|
||||
log_settings[Logs::UCSServer].log_to_console = static_cast<uint8>(Logs::General);
|
||||
log_settings[Logs::Crash].log_to_console = static_cast<uint8>(Logs::General);
|
||||
log_settings[Logs::MySQLError].log_to_console = static_cast<uint8>(Logs::General);
|
||||
log_settings[Logs::Loginserver].log_to_console = static_cast<uint8>(Logs::General);
|
||||
log_settings[Logs::HeadlessClient].log_to_console = static_cast<uint8>(Logs::General);
|
||||
log_settings[Logs::NPCScaling].log_to_gmsay = static_cast<uint8>(Logs::General);
|
||||
log_settings[Logs::HotReload].log_to_gmsay = static_cast<uint8>(Logs::General);
|
||||
log_settings[Logs::HotReload].log_to_console = static_cast<uint8>(Logs::General);
|
||||
log_settings[Logs::Loot].log_to_gmsay = static_cast<uint8>(Logs::General);
|
||||
log_settings[Logs::Scheduler].log_to_console = static_cast<uint8>(Logs::General);
|
||||
log_settings[Logs::Cheat].log_to_console = static_cast<uint8>(Logs::General);
|
||||
log_settings[Logs::HTTP].log_to_console = static_cast<uint8>(Logs::General);
|
||||
log_settings[Logs::HTTP].log_to_gmsay = static_cast<uint8>(Logs::General);
|
||||
log_settings[Logs::ChecksumVerification].log_to_console = static_cast<uint8>(Logs::General);
|
||||
log_settings[Logs::ChecksumVerification].log_to_gmsay = static_cast<uint8>(Logs::General);
|
||||
|
||||
/**
|
||||
* RFC 5424
|
||||
@ -241,7 +243,7 @@ void EQEmuLogSys::ProcessGMSay(
|
||||
*/
|
||||
if (EQEmuLogSys::log_platform == EQEmuExePlatform::ExePlatformZone ||
|
||||
EQEmuLogSys::log_platform == EQEmuExePlatform::ExePlatformWorld
|
||||
) {
|
||||
) {
|
||||
on_log_gmsay_hook(log_category, message);
|
||||
}
|
||||
}
|
||||
|
||||
@ -127,6 +127,7 @@ namespace Logs {
|
||||
DiaWind,
|
||||
HTTP,
|
||||
Saylink,
|
||||
ChecksumVerification,
|
||||
MaxCategoryID /* Don't Remove this */
|
||||
};
|
||||
|
||||
@ -212,6 +213,7 @@ namespace Logs {
|
||||
"DialogueWindow",
|
||||
"HTTP",
|
||||
"Saylink",
|
||||
"ChecksumVerification",
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@ -696,6 +696,16 @@
|
||||
OutF(LogSys, Logs::Detail, Logs::Saylink, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
|
||||
} while (0)
|
||||
|
||||
#define LogChecksumVerification(message, ...) do {\
|
||||
if (LogSys.log_settings[Logs::ChecksumVerification].is_category_enabled == 1)\
|
||||
OutF(LogSys, Logs::General, Logs::ChecksumVerification, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
|
||||
} while (0)
|
||||
|
||||
#define LogChecksumVerificationDetail(message, ...) do {\
|
||||
if (LogSys.log_settings[Logs::ChecksumVerification].is_category_enabled == 1)\
|
||||
OutF(LogSys, Logs::Detail, Logs::ChecksumVerification, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
|
||||
} while (0)
|
||||
|
||||
#define Log(debug_level, log_category, message, ...) do {\
|
||||
if (LogSys.log_settings[log_category].is_category_enabled == 1)\
|
||||
LogSys.Out(debug_level, log_category, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
|
||||
@ -1092,6 +1102,18 @@
|
||||
#define LogHTTPDetail(message, ...) do {\
|
||||
} while (0)
|
||||
|
||||
#define LogSaylink(message, ...) do {\
|
||||
} while (0)
|
||||
|
||||
#define LogSaylinkDetail(message, ...) do {\
|
||||
} while (0)
|
||||
|
||||
#define LogChecksumVerification(message, ...) do {\
|
||||
} while (0)
|
||||
|
||||
#define LogChecksumVerificationDetail(message, ...) do {\
|
||||
} while (0)
|
||||
|
||||
#define Log(debug_level, log_category, message, ...) do {\
|
||||
} while (0)
|
||||
|
||||
|
||||
@ -5218,6 +5218,11 @@ struct SayLinkBodyFrame_Struct {
|
||||
/*056*/
|
||||
};
|
||||
|
||||
struct Checksum_Struct {
|
||||
uint64_t checksum;
|
||||
uint8_t data[2048];
|
||||
};
|
||||
|
||||
}; /*structs*/
|
||||
|
||||
}; /*RoF2*/
|
||||
|
||||
@ -14,6 +14,7 @@
|
||||
|
||||
#include "../../database.h"
|
||||
#include "../../string_util.h"
|
||||
#include <ctime>
|
||||
|
||||
class BaseAccountRepository {
|
||||
public:
|
||||
@ -32,11 +33,14 @@ public:
|
||||
std::string minilogin_ip;
|
||||
int hideme;
|
||||
int rulesflag;
|
||||
std::string suspendeduntil;
|
||||
time_t suspendeduntil;
|
||||
int time_creation;
|
||||
int expansion;
|
||||
std::string ban_reason;
|
||||
std::string suspend_reason;
|
||||
std::string crc_eqgame;
|
||||
std::string crc_skillcaps;
|
||||
std::string crc_basedata;
|
||||
};
|
||||
|
||||
static std::string PrimaryKey()
|
||||
@ -66,6 +70,37 @@ public:
|
||||
"expansion",
|
||||
"ban_reason",
|
||||
"suspend_reason",
|
||||
"crc_eqgame",
|
||||
"crc_skillcaps",
|
||||
"crc_basedata",
|
||||
};
|
||||
}
|
||||
|
||||
static std::vector<std::string> SelectColumns()
|
||||
{
|
||||
return {
|
||||
"id",
|
||||
"name",
|
||||
"charname",
|
||||
"sharedplat",
|
||||
"password",
|
||||
"status",
|
||||
"ls_id",
|
||||
"lsaccount_id",
|
||||
"gmspeed",
|
||||
"revoked",
|
||||
"karma",
|
||||
"minilogin_ip",
|
||||
"hideme",
|
||||
"rulesflag",
|
||||
"UNIX_TIMESTAMP(suspendeduntil)",
|
||||
"time_creation",
|
||||
"expansion",
|
||||
"ban_reason",
|
||||
"suspend_reason",
|
||||
"crc_eqgame",
|
||||
"crc_skillcaps",
|
||||
"crc_basedata",
|
||||
};
|
||||
}
|
||||
|
||||
@ -74,6 +109,11 @@ public:
|
||||
return std::string(implode(", ", Columns()));
|
||||
}
|
||||
|
||||
static std::string SelectColumnsRaw()
|
||||
{
|
||||
return std::string(implode(", ", SelectColumns()));
|
||||
}
|
||||
|
||||
static std::string TableName()
|
||||
{
|
||||
return std::string("account");
|
||||
@ -83,7 +123,7 @@ public:
|
||||
{
|
||||
return fmt::format(
|
||||
"SELECT {} FROM {}",
|
||||
ColumnsRaw(),
|
||||
SelectColumnsRaw(),
|
||||
TableName()
|
||||
);
|
||||
}
|
||||
@ -115,11 +155,14 @@ public:
|
||||
entry.minilogin_ip = "";
|
||||
entry.hideme = 0;
|
||||
entry.rulesflag = 0;
|
||||
entry.suspendeduntil = "0000-00-00 00:00:00";
|
||||
entry.suspendeduntil = 0;
|
||||
entry.time_creation = 0;
|
||||
entry.expansion = 0;
|
||||
entry.ban_reason = "";
|
||||
entry.suspend_reason = "";
|
||||
entry.crc_eqgame = "";
|
||||
entry.crc_skillcaps = "";
|
||||
entry.crc_basedata = "";
|
||||
|
||||
return entry;
|
||||
}
|
||||
@ -169,11 +212,14 @@ public:
|
||||
entry.minilogin_ip = row[11] ? row[11] : "";
|
||||
entry.hideme = atoi(row[12]);
|
||||
entry.rulesflag = atoi(row[13]);
|
||||
entry.suspendeduntil = row[14] ? row[14] : "";
|
||||
entry.suspendeduntil = strtoll(row[14] ? row[14] : "-1", nullptr, 10);
|
||||
entry.time_creation = atoi(row[15]);
|
||||
entry.expansion = atoi(row[16]);
|
||||
entry.ban_reason = row[17] ? row[17] : "";
|
||||
entry.suspend_reason = row[18] ? row[18] : "";
|
||||
entry.crc_eqgame = row[19] ? row[19] : "";
|
||||
entry.crc_skillcaps = row[20] ? row[20] : "";
|
||||
entry.crc_basedata = row[21] ? row[21] : "";
|
||||
|
||||
return entry;
|
||||
}
|
||||
@ -220,11 +266,14 @@ public:
|
||||
update_values.push_back(columns[11] + " = '" + EscapeString(account_entry.minilogin_ip) + "'");
|
||||
update_values.push_back(columns[12] + " = " + std::to_string(account_entry.hideme));
|
||||
update_values.push_back(columns[13] + " = " + std::to_string(account_entry.rulesflag));
|
||||
update_values.push_back(columns[14] + " = '" + EscapeString(account_entry.suspendeduntil) + "'");
|
||||
update_values.push_back(columns[14] + " = FROM_UNIXTIME(" + (account_entry.suspendeduntil > 0 ? std::to_string(account_entry.suspendeduntil) : "null") + ")");
|
||||
update_values.push_back(columns[15] + " = " + std::to_string(account_entry.time_creation));
|
||||
update_values.push_back(columns[16] + " = " + std::to_string(account_entry.expansion));
|
||||
update_values.push_back(columns[17] + " = '" + EscapeString(account_entry.ban_reason) + "'");
|
||||
update_values.push_back(columns[18] + " = '" + EscapeString(account_entry.suspend_reason) + "'");
|
||||
update_values.push_back(columns[19] + " = '" + EscapeString(account_entry.crc_eqgame) + "'");
|
||||
update_values.push_back(columns[20] + " = '" + EscapeString(account_entry.crc_skillcaps) + "'");
|
||||
update_values.push_back(columns[21] + " = '" + EscapeString(account_entry.crc_basedata) + "'");
|
||||
|
||||
auto results = db.QueryDatabase(
|
||||
fmt::format(
|
||||
@ -260,11 +309,14 @@ public:
|
||||
insert_values.push_back("'" + EscapeString(account_entry.minilogin_ip) + "'");
|
||||
insert_values.push_back(std::to_string(account_entry.hideme));
|
||||
insert_values.push_back(std::to_string(account_entry.rulesflag));
|
||||
insert_values.push_back("'" + EscapeString(account_entry.suspendeduntil) + "'");
|
||||
insert_values.push_back("FROM_UNIXTIME(" + (account_entry.suspendeduntil > 0 ? std::to_string(account_entry.suspendeduntil) : "null") + ")");
|
||||
insert_values.push_back(std::to_string(account_entry.time_creation));
|
||||
insert_values.push_back(std::to_string(account_entry.expansion));
|
||||
insert_values.push_back("'" + EscapeString(account_entry.ban_reason) + "'");
|
||||
insert_values.push_back("'" + EscapeString(account_entry.suspend_reason) + "'");
|
||||
insert_values.push_back("'" + EscapeString(account_entry.crc_eqgame) + "'");
|
||||
insert_values.push_back("'" + EscapeString(account_entry.crc_skillcaps) + "'");
|
||||
insert_values.push_back("'" + EscapeString(account_entry.crc_basedata) + "'");
|
||||
|
||||
auto results = db.QueryDatabase(
|
||||
fmt::format(
|
||||
@ -308,11 +360,14 @@ public:
|
||||
insert_values.push_back("'" + EscapeString(account_entry.minilogin_ip) + "'");
|
||||
insert_values.push_back(std::to_string(account_entry.hideme));
|
||||
insert_values.push_back(std::to_string(account_entry.rulesflag));
|
||||
insert_values.push_back("'" + EscapeString(account_entry.suspendeduntil) + "'");
|
||||
insert_values.push_back("FROM_UNIXTIME(" + (account_entry.suspendeduntil > 0 ? std::to_string(account_entry.suspendeduntil) : "null") + ")");
|
||||
insert_values.push_back(std::to_string(account_entry.time_creation));
|
||||
insert_values.push_back(std::to_string(account_entry.expansion));
|
||||
insert_values.push_back("'" + EscapeString(account_entry.ban_reason) + "'");
|
||||
insert_values.push_back("'" + EscapeString(account_entry.suspend_reason) + "'");
|
||||
insert_values.push_back("'" + EscapeString(account_entry.crc_eqgame) + "'");
|
||||
insert_values.push_back("'" + EscapeString(account_entry.crc_skillcaps) + "'");
|
||||
insert_values.push_back("'" + EscapeString(account_entry.crc_basedata) + "'");
|
||||
|
||||
insert_chunks.push_back("(" + implode(",", insert_values) + ")");
|
||||
}
|
||||
@ -360,11 +415,14 @@ public:
|
||||
entry.minilogin_ip = row[11] ? row[11] : "";
|
||||
entry.hideme = atoi(row[12]);
|
||||
entry.rulesflag = atoi(row[13]);
|
||||
entry.suspendeduntil = row[14] ? row[14] : "";
|
||||
entry.suspendeduntil = strtoll(row[14] ? row[14] : "-1", nullptr, 10);
|
||||
entry.time_creation = atoi(row[15]);
|
||||
entry.expansion = atoi(row[16]);
|
||||
entry.ban_reason = row[17] ? row[17] : "";
|
||||
entry.suspend_reason = row[18] ? row[18] : "";
|
||||
entry.crc_eqgame = row[19] ? row[19] : "";
|
||||
entry.crc_skillcaps = row[20] ? row[20] : "";
|
||||
entry.crc_basedata = row[21] ? row[21] : "";
|
||||
|
||||
all_entries.push_back(entry);
|
||||
}
|
||||
@ -403,11 +461,14 @@ public:
|
||||
entry.minilogin_ip = row[11] ? row[11] : "";
|
||||
entry.hideme = atoi(row[12]);
|
||||
entry.rulesflag = atoi(row[13]);
|
||||
entry.suspendeduntil = row[14] ? row[14] : "";
|
||||
entry.suspendeduntil = strtoll(row[14] ? row[14] : "-1", nullptr, 10);
|
||||
entry.time_creation = atoi(row[15]);
|
||||
entry.expansion = atoi(row[16]);
|
||||
entry.ban_reason = row[17] ? row[17] : "";
|
||||
entry.suspend_reason = row[18] ? row[18] : "";
|
||||
entry.crc_eqgame = row[19] ? row[19] : "";
|
||||
entry.crc_skillcaps = row[20] ? row[20] : "";
|
||||
entry.crc_basedata = row[21] ? row[21] : "";
|
||||
|
||||
all_entries.push_back(entry);
|
||||
}
|
||||
|
||||
@ -242,6 +242,7 @@ RULE_INT(GM, MinStatusToSummonItem, 250, "Minimum required status to summon item
|
||||
RULE_INT(GM, MinStatusToZoneAnywhere, 250, "Minimum required status to zone anywhere")
|
||||
RULE_INT(GM, MinStatusToLevelTarget, 100, "Minimum required status to set the level of a player")
|
||||
RULE_INT(GM, MinStatusToBypassLockedServer, 100, "Players >= this status can log in to the server even when it is locked")
|
||||
RULE_INT(GM, MinStatusToBypassCheckSumVerification, 100, "Players >= this status can bypass the eqgame.exe and spells_us.txt checksum verification")
|
||||
RULE_CATEGORY_END()
|
||||
|
||||
RULE_CATEGORY(World)
|
||||
@ -275,6 +276,7 @@ RULE_INT (World, TellQueueSize, 20, "Maximum tell queue size")
|
||||
RULE_BOOL(World, StartZoneSameAsBindOnCreation, true, "Should the start zone always be the same location as your bind?")
|
||||
RULE_BOOL(World, EnforceCharacterLimitAtLogin, false, "Enforce the limit for characters that are online at login")
|
||||
RULE_BOOL(World, EnableDevTools, true, "Enable or Disable the Developer Tools globally (Most of the time you want this enabled)")
|
||||
RULE_BOOL(World, EnableChecksumVerification, false, "Enable or Disable the Checksum Verification for eqgame.exe and spells_us.txt")
|
||||
RULE_CATEGORY_END()
|
||||
|
||||
RULE_CATEGORY(Zone)
|
||||
|
||||
@ -227,6 +227,7 @@
|
||||
#define ServerOP_HotReloadQuests 0x4011
|
||||
#define ServerOP_UpdateSchedulerEvents 0x4012
|
||||
#define ServerOP_ReloadContentFlags 0x4013
|
||||
#define ServerOP_ReloadVariablesWorld 0x4014
|
||||
|
||||
#define ServerOP_CZDialogueWindow 0x4500
|
||||
#define ServerOP_CZLDoNUpdate 0x4501
|
||||
|
||||
@ -34,7 +34,7 @@
|
||||
* Manifest: https://github.com/EQEmu/Server/blob/master/utils/sql/db_update_manifest.txt
|
||||
*/
|
||||
|
||||
#define CURRENT_BINARY_DATABASE_VERSION 9175
|
||||
#define CURRENT_BINARY_DATABASE_VERSION 9176
|
||||
|
||||
#ifdef BOTS
|
||||
#define CURRENT_BINARY_BOTS_DATABASE_VERSION 9028
|
||||
|
||||
@ -22,8 +22,9 @@ OP_ExpansionInfo=0x590d
|
||||
OP_GuildsList=0x507a
|
||||
OP_EnterWorld=0x578f
|
||||
OP_PostEnterWorld=0x6259
|
||||
OP_World_Client_CRC1=0x12cc
|
||||
OP_World_Client_CRC2=0x0f13
|
||||
OP_World_Client_CRC1=0x0f13
|
||||
OP_World_Client_CRC2=0x4b8d
|
||||
OP_World_Client_CRC3=0x298d
|
||||
OP_SendSpellChecksum=0x0000
|
||||
OP_SendSkillCapsChecksum=0x0000
|
||||
|
||||
|
||||
@ -249,6 +249,11 @@ foreach my $table_to_generate (@tables) {
|
||||
$default_value = '""';
|
||||
}
|
||||
|
||||
# for datetime values that set default value all zeroed out
|
||||
if ($default_value =~ /0000-00-00 00:00:00/i) {
|
||||
$default_value = 0;
|
||||
}
|
||||
|
||||
my $struct_data_type = translate_mysql_data_type_to_c($data_type);
|
||||
|
||||
# struct
|
||||
|
||||
@ -429,6 +429,7 @@
|
||||
9173|2021_09_14_zone_lava_damage.sql|SHOW COLUMNS FROM `zone` LIKE 'lava_damage'|empty|
|
||||
9174|2021_10_09_not_null_door_columns.sql|SELECT * FROM db_version WHERE version >= 9174|empty|
|
||||
9175|2022_01_02_expansion_default_value_all.sql|SHOW COLUMNS FROM `forage` LIKE 'min_expansion'|contains|unsigned
|
||||
9176|2022_01_10_checksum_verification.sql|SHOW COLUMNS FROM `account` LIKE 'checksum_crc1_eqgame'|empty|
|
||||
|
||||
# Upgrade conditions:
|
||||
# This won't be needed after this system is implemented, but it is used database that are not
|
||||
|
||||
10
utils/sql/git/required/2022_01_10_checksum_verification.sql
Normal file
10
utils/sql/git/required/2022_01_10_checksum_verification.sql
Normal file
@ -0,0 +1,10 @@
|
||||
INSERT INTO `variables` (`varname`, `value`, `information`, `ts`) VALUES ('crc_eqgame', '0', 'Client CRC64 Checksum on: eqgame.exe', '2021-09-23 14:16:27');
|
||||
INSERT INTO `variables` (`varname`, `value`, `information`, `ts`) VALUES ('crc_skillcaps', '0', 'Client CRC64 Checksum on: SkillCaps.txt', '2021-09-23 14:16:21');
|
||||
INSERT INTO `variables` (`varname`, `value`, `information`, `ts`) VALUES ('crc_basedata', '0', 'Client CRC64 Checksum on: BaseData.txt','2021-09-23 14:16:21');
|
||||
|
||||
ALTER TABLE `account`
|
||||
ADD COLUMN `crc_eqgame` TEXT NULL AFTER `suspend_reason`,
|
||||
ADD COLUMN `crc_skillcaps` TEXT NULL AFTER `crc_eqgame`,
|
||||
ADD COLUMN `crc_basedata` TEXT NULL AFTER `crc_skillcaps`;
|
||||
|
||||
ALTER TABLE account` CHANGE `suspendeduntil` `suspendeduntil` datetime NULL COMMENT '';
|
||||
150
world/client.cpp
150
world/client.cpp
@ -47,6 +47,7 @@
|
||||
#include "wguild_mgr.h"
|
||||
#include "sof_char_create_data.h"
|
||||
#include "world_store.h"
|
||||
#include "../common/repositories/account_repository.h"
|
||||
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
@ -1013,15 +1014,18 @@ bool Client::HandlePacket(const EQApplicationPacket *app) {
|
||||
|
||||
switch(opcode)
|
||||
{
|
||||
case OP_World_Client_CRC1:
|
||||
case OP_World_Client_CRC2:
|
||||
case OP_World_Client_CRC1: // eqgame.exe
|
||||
case OP_World_Client_CRC2: // SkillCaps.txt
|
||||
case OP_World_Client_CRC3: // BaseData.txt
|
||||
{
|
||||
// There is no obvious entry in the CC struct to indicate that the 'Start Tutorial button
|
||||
// is selected when a character is created. I have observed that in this case, OP_EnterWorld is sent
|
||||
// before OP_World_Client_CRC1. Therefore, if we receive OP_World_Client_CRC1 before OP_EnterWorld,
|
||||
// then 'Start Tutorial' was not chosen.
|
||||
StartInTutorial = false;
|
||||
return true;
|
||||
|
||||
return HandleChecksumPacket(app);
|
||||
|
||||
}
|
||||
case OP_SendLoginInfo:
|
||||
{
|
||||
@ -1142,6 +1146,146 @@ bool Client::Process() {
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool Client::HandleChecksumPacket(const EQApplicationPacket *app)
|
||||
{
|
||||
// Is checksum verification turned on
|
||||
if (!RuleB(World, EnableChecksumVerification)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Get packet structure
|
||||
auto *cs = (Checksum_Struct *)app->pBuffer;
|
||||
|
||||
// Determine which checksum to process
|
||||
switch (app->GetOpcode()) {
|
||||
case OP_World_Client_CRC1: // eqgame.exe
|
||||
{
|
||||
bool passes_checksum_validation = (
|
||||
ChecksumVerificationCRCEQGame(cs->checksum) ||
|
||||
(GetAdmin() >= RuleI(GM, MinStatusToBypassCheckSumVerification))
|
||||
);
|
||||
|
||||
LogChecksumVerification(
|
||||
"eqgame.exe validation [{}] client [{}] ({}) has [{}] status [{}]",
|
||||
passes_checksum_validation ? "Passed" : "Failed",
|
||||
GetAccountName(),
|
||||
GetAccountID(),
|
||||
cs->checksum,
|
||||
GetAdmin()
|
||||
);
|
||||
|
||||
return passes_checksum_validation;
|
||||
}
|
||||
case OP_World_Client_CRC2: // SkillCaps.txt
|
||||
{
|
||||
bool passes_checksum_validation = (
|
||||
ChecksumVerificationCRCSkillCaps(cs->checksum) ||
|
||||
(GetAdmin() >= RuleI(GM, MinStatusToBypassCheckSumVerification))
|
||||
);
|
||||
|
||||
LogChecksumVerification(
|
||||
"SkillCaps.txt validation [{}] client [{}] ({}) has [{}] status [{}]",
|
||||
passes_checksum_validation ? "Passed" : "Failed",
|
||||
GetAccountName(),
|
||||
GetAccountID(),
|
||||
cs->checksum,
|
||||
GetAdmin()
|
||||
);
|
||||
|
||||
return passes_checksum_validation;
|
||||
}
|
||||
case OP_World_Client_CRC3: // BaseData.txt
|
||||
{
|
||||
bool passes_checksum_validation = (
|
||||
ChecksumVerificationCRCBaseData(cs->checksum) ||
|
||||
(GetAdmin() >= RuleI(GM, MinStatusToBypassCheckSumVerification))
|
||||
);
|
||||
|
||||
LogChecksumVerification(
|
||||
"BaseData.txt validation [{}] client [{}] ({}) has [{}] status [{}]",
|
||||
passes_checksum_validation ? "Passed" : "Failed",
|
||||
GetAccountName(),
|
||||
GetAccountID(),
|
||||
cs->checksum,
|
||||
GetAdmin()
|
||||
);
|
||||
|
||||
return passes_checksum_validation;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Client::ChecksumVerificationCRCEQGame(uint64 checksum)
|
||||
{
|
||||
database.SetAccountCRCField(GetAccountID(), "crc_eqgame", checksum);
|
||||
|
||||
// Get checksum variable for eqgame.exe
|
||||
std::string checksumvar;
|
||||
uint64_t checksumint;
|
||||
if (database.GetVariable("crc_eqgame", checksumvar)) {
|
||||
checksumint = atoll(checksumvar.c_str());
|
||||
}
|
||||
else {
|
||||
LogChecksumVerification("[checksum_crc1_eqgame] variable not set in variables table.");
|
||||
return true;
|
||||
}
|
||||
|
||||
// Verify checksums match
|
||||
if (checksumint == checksum) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Client::ChecksumVerificationCRCSkillCaps(uint64 checksum)
|
||||
{
|
||||
database.SetAccountCRCField(GetAccountID(), "crc_skillcaps", checksum);
|
||||
|
||||
// Get checksum variable for eqgame.exe
|
||||
std::string checksumvar;
|
||||
uint64_t checksumint;
|
||||
if (database.GetVariable("crc_skillcaps", checksumvar)) {
|
||||
checksumint = atoll(checksumvar.c_str());
|
||||
}
|
||||
else {
|
||||
LogChecksumVerification("[checksum_crc2_skillcaps] variable not set in variables table.");
|
||||
return true;
|
||||
}
|
||||
|
||||
// Verify checksums match
|
||||
if (checksumint == checksum) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Client::ChecksumVerificationCRCBaseData(uint64 checksum)
|
||||
{
|
||||
database.SetAccountCRCField(GetAccountID(), "crc_basedata", checksum);
|
||||
|
||||
// Get checksum variable for skill_caps.txt
|
||||
std::string checksumvar;
|
||||
uint64_t checksumint;
|
||||
if (database.GetVariable("crc_basedata", checksumvar)) {
|
||||
checksumint = atoll(checksumvar.c_str());
|
||||
}
|
||||
else {
|
||||
LogChecksumVerification("[checksum_crc3_basedata] variable not set in variables table.");
|
||||
return true;
|
||||
}
|
||||
|
||||
// Verify checksums match
|
||||
if (checksumint == checksum) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void Client::EnterWorld(bool TryBootup) {
|
||||
if (zone_id == 0)
|
||||
return;
|
||||
|
||||
@ -116,6 +116,10 @@ private:
|
||||
bool HandleEnterWorldPacket(const EQApplicationPacket *app);
|
||||
bool HandleDeleteCharacterPacket(const EQApplicationPacket *app);
|
||||
bool HandleZoneChangePacket(const EQApplicationPacket *app);
|
||||
bool HandleChecksumPacket(const EQApplicationPacket *app);
|
||||
bool ChecksumVerificationCRCEQGame(uint64 checksum);
|
||||
bool ChecksumVerificationCRCSkillCaps(uint64 checksum);
|
||||
bool ChecksumVerificationCRCBaseData(uint64 checksum);
|
||||
|
||||
EQStreamInterface* eqs;
|
||||
};
|
||||
|
||||
@ -879,6 +879,11 @@ void ZoneServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p) {
|
||||
RuleManager::Instance()->LoadRules(&database, "default", true);
|
||||
break;
|
||||
}
|
||||
case ServerOP_ReloadVariablesWorld:
|
||||
{
|
||||
database.LoadVariables();
|
||||
break;
|
||||
}
|
||||
case ServerOP_ReloadPerlExportSettings:
|
||||
{
|
||||
zoneserver_list.SendPacket(pack);
|
||||
|
||||
@ -548,6 +548,7 @@ SET(gm_commands
|
||||
gm_commands/unmemspells.cpp
|
||||
gm_commands/unscribespell.cpp
|
||||
gm_commands/unscribespells.cpp
|
||||
gm_commands/updatechecksum.cpp
|
||||
gm_commands/untraindisc.cpp
|
||||
gm_commands/untraindiscs.cpp
|
||||
gm_commands/uptime.cpp
|
||||
|
||||
@ -388,6 +388,7 @@ int command_init(void)
|
||||
command_add("unscribespells", "- Clear out your or your player target's spell book.", AccountStatus::GMCoder, command_unscribespells) ||
|
||||
command_add("untraindisc", "[Spell ID] - Untrain your or your target's discipline by Spell ID", AccountStatus::GMCoder, command_untraindisc) ||
|
||||
command_add("untraindiscs", "- Untrains all disciplines from your target.", AccountStatus::GMCoder, command_untraindiscs) ||
|
||||
command_add("updatechecksum", "update client checksum", AccountStatus::GMImpossible, command_updatechecksum) ||
|
||||
command_add("uptime", "[zone server id] - Get uptime of worldserver, or zone server if argument provided", AccountStatus::Steward, command_uptime) ||
|
||||
command_add("version", "- Display current version of EQEmu server", AccountStatus::Player, command_version) ||
|
||||
command_add("viewcurrencies", "- View your or your target's currencies", AccountStatus::GMAdmin, command_viewcurrencies) ||
|
||||
|
||||
@ -310,6 +310,7 @@ void command_unscribespell(Client *c, const Seperator *sep);
|
||||
void command_unscribespells(Client *c, const Seperator *sep);
|
||||
void command_untraindisc(Client *c, const Seperator *sep);
|
||||
void command_untraindiscs(Client *c, const Seperator *sep);
|
||||
void command_updatechecksum(Client* c, const Seperator* sep);
|
||||
void command_uptime(Client *c, const Seperator *sep);
|
||||
void command_version(Client *c, const Seperator *sep);
|
||||
void command_viewcurrencies(Client *c, const Seperator *sep);
|
||||
|
||||
35
zone/gm_commands/updatechecksum.cpp
Executable file
35
zone/gm_commands/updatechecksum.cpp
Executable file
@ -0,0 +1,35 @@
|
||||
#include "../client.h"
|
||||
#include "../worldserver.h"
|
||||
#include "../../common/repositories/account_repository.h"
|
||||
|
||||
extern WorldServer worldserver;
|
||||
|
||||
void command_updatechecksum(Client *c, const Seperator *sep)
|
||||
{
|
||||
if (c) {
|
||||
// if account found
|
||||
auto account = AccountRepository::FindOne(database, c->AccountID());
|
||||
if (account.id > 0) {
|
||||
database.SetVariable("crc_eqgame", account.crc_eqgame);
|
||||
database.SetVariable("crc_skillcaps", account.crc_skillcaps);
|
||||
database.SetVariable("crc_basedata", account.crc_basedata);
|
||||
|
||||
// reload rules (world)
|
||||
auto pack = new ServerPacket(ServerOP_ReloadRulesWorld, 0);
|
||||
worldserver.SendPacket(pack);
|
||||
c->Message(Chat::Red, "Successfully sent the packet to world to reload rules. (only world)");
|
||||
safe_delete(pack);
|
||||
|
||||
// reload variables (world)
|
||||
pack = new ServerPacket(ServerOP_ReloadVariablesWorld, 0);
|
||||
worldserver.SendPacket(pack);
|
||||
c->Message(Chat::Red, "Successfully sent the packet to world to reload variables. (only world)");
|
||||
safe_delete(pack);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// we should never see this
|
||||
c->Message(Chat::Red, "Error: Your account was not found!");
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user