forked from Mirrors/openclonk
MsgBoard commands: Handle and assemble on clients
MsgBoard commands used to be evaluated on the issuing client. Malicious clients would be able to insert arbitrary C4Script code to be executed instead of the scenario-defined command; other clients would not be able to tell the difference. Instead, we now only send the command identifier, issuing player and command parameter. This is still not perfect because clients can insert any player they want, but it's better than before. Part of #936.stable-5.4
parent
f920e853e0
commit
f2dba4a6b3
|
@ -49,6 +49,7 @@
|
|||
#include <C4PlayerList.h>
|
||||
#include <C4GameObjects.h>
|
||||
#include <C4GameControl.h>
|
||||
#include "gui/C4MessageInput.h"
|
||||
|
||||
#ifndef NOAULDEBUG
|
||||
#include <C4AulDebug.h>
|
||||
|
@ -317,6 +318,45 @@ void C4ControlMsgBoardReply::CompileFunc(StdCompiler *pComp)
|
|||
C4ControlPacket::CompileFunc(pComp);
|
||||
}
|
||||
|
||||
// *** C4ControlMsgBoardCmd
|
||||
void C4ControlMsgBoardCmd::Execute() const
|
||||
{
|
||||
C4Player *source_player = ::Players.Get(player);
|
||||
|
||||
// don't handle this if the game isn't actually running
|
||||
if (!::Game.IsRunning) return;
|
||||
|
||||
// fetch command script
|
||||
C4MessageBoardCommand *cmd = ::MessageInput.GetCommand(command.getData());
|
||||
if (!cmd) return;
|
||||
StdCopyStrBuf script(cmd->Script);
|
||||
|
||||
// interpolate parameters as required
|
||||
script.Replace("%player%", FormatString("%d", player).getData());
|
||||
if (parameter)
|
||||
{
|
||||
script.Replace("%d", FormatString("%d", std::atoi(parameter.getData())).getData());
|
||||
StdCopyStrBuf escaped_param(parameter);
|
||||
escaped_param.EscapeString();
|
||||
script.Replace("%s", escaped_param.getData());
|
||||
}
|
||||
|
||||
// Run script
|
||||
C4Value rv(::ScriptEngine.DirectExec(nullptr, script.getData(), "message board command"));
|
||||
#ifndef NOAULDEBUG
|
||||
C4AulDebug* pDebug = C4AulDebug::GetDebugger();
|
||||
if (pDebug)
|
||||
pDebug->ControlScriptEvaluated(script.getData(), rv.GetDataString().getData());
|
||||
#endif
|
||||
}
|
||||
|
||||
void C4ControlMsgBoardCmd::CompileFunc(StdCompiler *pComp)
|
||||
{
|
||||
pComp->Value(mkNamingAdapt(player, "Player", NO_OWNER));
|
||||
pComp->Value(mkNamingAdapt(command, "Command"));
|
||||
pComp->Value(mkNamingAdapt(parameter, "Parameter"));
|
||||
C4ControlPacket::CompileFunc(pComp);
|
||||
}
|
||||
// *** C4ControlPlayerSelect
|
||||
|
||||
C4ControlPlayerSelect::C4ControlPlayerSelect(int32_t iPlr, const C4ObjectList &Objs, bool fIsAlt)
|
||||
|
|
|
@ -171,6 +171,25 @@ public:
|
|||
DECLARE_C4CONTROL_VIRTUALS
|
||||
};
|
||||
|
||||
class C4ControlMsgBoardCmd : public C4ControlPacket // sync
|
||||
{
|
||||
public:
|
||||
C4ControlMsgBoardCmd()
|
||||
: player(NO_OWNER)
|
||||
{}
|
||||
C4ControlMsgBoardCmd(const char *command, const char *parameter, int32_t player)
|
||||
: command(command), parameter(parameter), player(player)
|
||||
{}
|
||||
|
||||
private:
|
||||
StdCopyStrBuf command;
|
||||
StdCopyStrBuf parameter;
|
||||
int32_t player;
|
||||
|
||||
public:
|
||||
DECLARE_C4CONTROL_VIRTUALS
|
||||
};
|
||||
|
||||
class C4ControlPlayerSelect : public C4ControlPacket // sync
|
||||
{
|
||||
public:
|
||||
|
|
|
@ -779,40 +779,15 @@ bool C4MessageInput::ProcessCommand(const char *szCommand)
|
|||
if (Game.IsRunning)
|
||||
if ((pCmd = GetCommand(szCmdName)))
|
||||
{
|
||||
StdStrBuf Script, CmdScript;
|
||||
// replace %player% by calling player number
|
||||
if (SSearch(pCmd->Script, "%player%"))
|
||||
{
|
||||
int32_t iLocalPlr = NO_OWNER;
|
||||
C4Player *pLocalPlr = ::Players.GetLocalByIndex(0);
|
||||
if (pLocalPlr) iLocalPlr = pLocalPlr->Number;
|
||||
StdStrBuf sLocalPlr; sLocalPlr.Format("%d", iLocalPlr);
|
||||
CmdScript.Copy(pCmd->Script);
|
||||
CmdScript.Replace("%player%", sLocalPlr.getData());
|
||||
}
|
||||
else
|
||||
{
|
||||
CmdScript.Ref(pCmd->Script);
|
||||
}
|
||||
// insert parameters
|
||||
if (SSearch(CmdScript.getData(), "%d"))
|
||||
{
|
||||
// make sure it's a number by converting
|
||||
Script.Format(CmdScript.getData(), (int) atoi(pCmdPar));
|
||||
}
|
||||
else if (SSearch(CmdScript.getData(), "%s"))
|
||||
{
|
||||
// escape strings
|
||||
StdStrBuf Par;
|
||||
Par.Copy(pCmdPar);
|
||||
Par.EscapeString();
|
||||
// compose script
|
||||
Script.Format(CmdScript.getData(), Par.getData());
|
||||
}
|
||||
else
|
||||
Script = CmdScript.getData();
|
||||
// add script
|
||||
::Control.DoInput(CID_Script, new C4ControlScript(Script.getData()), CDT_Decide);
|
||||
// get player number of first local player; if multiple players
|
||||
// share one computer, we can't distinguish between them anyway
|
||||
int32_t player_num = NO_OWNER;
|
||||
C4Player *player = ::Players.GetLocalByIndex(0);
|
||||
if (player) player_num = player->Number;
|
||||
|
||||
// send command to network
|
||||
::Control.DoInput(CID_MsgBoardCmd, new C4ControlMsgBoardCmd(szCmdName, pCmdPar, player_num), CDT_Decide);
|
||||
|
||||
// ok
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -117,6 +117,7 @@ const C4PktHandlingData PktHandlingData[] =
|
|||
{ CID_Set, PC_Control, "Set", false, true, 0, PKT_UNPACK(C4ControlSet) },
|
||||
{ CID_Script, PC_Control, "Script", false, true, 0, PKT_UNPACK(C4ControlScript) },
|
||||
{ CID_MsgBoardReply,PC_Control, "Message Board Reply", false, true, 0, PKT_UNPACK(C4ControlMsgBoardReply)},
|
||||
{ CID_MsgBoardCmd ,PC_Control, "Message Board Command", false, true, 0, PKT_UNPACK(C4ControlMsgBoardCmd)},
|
||||
{ CID_PlrInfo, PC_Control, "Player Info", false, true, 0, PKT_UNPACK(C4ControlPlayerInfo) },
|
||||
{ CID_JoinPlr, PC_Control, "Join Player", false, true, 0, PKT_UNPACK(C4ControlJoinPlayer) },
|
||||
{ CID_RemovePlr, PC_Control, "Remove Player", false, true, 0, PKT_UNPACK(C4ControlRemovePlr) },
|
||||
|
|
|
@ -154,6 +154,7 @@ enum C4PacketType
|
|||
CID_Set = CID_First | 0x07,
|
||||
CID_Script = CID_First | 0x08,
|
||||
CID_MsgBoardReply = CID_First | 0x09,
|
||||
CID_MsgBoardCmd = CID_First | 0x0A,
|
||||
|
||||
CID_PlrInfo = CID_First | 0x10,
|
||||
CID_JoinPlr = CID_First | 0x11,
|
||||
|
|
Loading…
Reference in New Issue