Skip to content

Commit

Permalink
Merge pull request #979 from osm/add-remote-capabilities-validation
Browse files Browse the repository at this point in the history
Add remote capabilities validation
  • Loading branch information
tcsabina authored Jan 2, 2025
2 parents ac82675 + c04f608 commit 1678bb1
Show file tree
Hide file tree
Showing 4 changed files with 152 additions and 9 deletions.
27 changes: 27 additions & 0 deletions help_variables.json
Original file line number Diff line number Diff line change
Expand Up @@ -1037,6 +1037,27 @@
}
]
},
"cl_allow_downloads": {
"default": "bsp,lmp,loc,mdl,mvd,pcx,spr,wad,wav",
"desc": "This variable controls which file extensions a client/server can download/upload from/to the server/client.",
"group-id": "9",
"type": "string"
},
"cl_allow_uploads": {
"default": "0",
"group-id": "9",
"type": "boolean",
"values": [
{
"description": "Don't allow uploads.",
"name": "0"
},
{
"description": "Allow uploads.",
"name": "1"
}
]
},
"cl_anglespeedkey": {
"default": "1.5",
"desc": "This variable sets multiplier by which your \"cl_yawspeed\" (how fast you turn) is multiplied when running (+speed).",
Expand Down Expand Up @@ -2500,6 +2521,12 @@
}
]
},
"cl_remote_capabilities": {
"default": "alias,bf,changing,cmd,color,download,exec,fullserverinfo,impulse,infoset,ktx_infoset,ktx_sinfoset,nextul,on_enter,on_enter_ctf,on_enter_ffa,on_spec_enter,on_spec_enter_ctf,on_spec_enter_ffa,packet,play,reconnect,say,sinfoset,skin,skins,team,tempalias,track,wait",
"desc": "This variable controls which commands and variables a server is allowed to execute or set on the client. Input a comma-separated list of commands and variables to toggle access. The default values are adapted for KTX use.",
"group-id": "9",
"type": "string"
},
"cl_restrictions": {
"default": "0",
"desc": "Triggers and re/msg trigger restrictions for spectator and demoplay modes.",
Expand Down
22 changes: 19 additions & 3 deletions src/cl_cmd.c
Original file line number Diff line number Diff line change
Expand Up @@ -626,14 +626,30 @@ void CL_Rcon_f (void) {

qbool CL_Download_Accept(const char *filename)
{
char *str, *tmp, *ext;
qbool is_valid = false;
extern cvar_t cl_allow_downloads;

if (strstr(filename, "..") || !strcmp(filename, "") || filename[0] == '/' || strchr(filename, '\\') || strchr(filename, ':') || strstr(filename, "//")) {
Com_Printf("Warning: Invalid characters in filename \"%s\"\n", filename);
return false;
}

const char *tmp = strrchr(filename, '.');
if (tmp != NULL && (!strcasecmp(tmp, ".dll") || !strcasecmp(tmp, ".so"))) {
Com_Printf("Warning: Non-allowed file \"%s\" skipped\n", filename);
ext = COM_FileExtension(filename);
str = Q_strdup(cl_allow_downloads.string);
tmp = strtok(str, ",");
while (tmp != NULL) {
if (strcmp(ext, tmp) == 0) {
is_valid = true;
break;
}

tmp = strtok(NULL, ",");
}
Q_free(str);

if (!is_valid) {
Com_Printf("Warning: Non-allowed file \"%s\" skipped. Add \"%s\" to cl_allow_download_file_extensions to allow the file to be downloaded\n", filename, ext);
return false;
}

Expand Down
6 changes: 6 additions & 0 deletions src/cl_parse.c
Original file line number Diff line number Diff line change
Expand Up @@ -1287,7 +1287,13 @@ void CL_StartFileUpload (void)
{
char *name;
int i;
extern cvar_t cl_allow_uploads;

if (!cl_allow_uploads.integer)
{
Com_Printf ("This command has been disabled for security reasons. Set cl_allow_uploads to 1 if you want to enable uploads.\n");
return;
}

if (cls.state < ca_onserver)
{
Expand Down
106 changes: 100 additions & 6 deletions src/cmd.c
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "parser.h"
#include "utils.h"
#include "keys.h"
#include "hash.h"
#include <pcre2.h>

typedef struct {
Expand All @@ -57,13 +58,85 @@ cvar_t cl_warncmd = {"cl_warncmd", "1"};
cvar_t cl_warnexec = {"cl_warnexec", "1"};
cvar_t cl_curlybraces = {"cl_curlybraces", "0"};

#define REMOTE_CAPABILITIES "alias,bf,changing,cmd,color,download,exec,fullserverinfo,impulse," \
"infoset,ktx_infoset,ktx_sinfoset,nextul,on_enter," \
"on_enter_ctf,on_enter_ffa,on_spec_enter,on_spec_enter_ctf," \
"on_spec_enter_ffa,packet,play,reconnect,say,sinfoset,skin," \
"skins,team,tempalias,track,wait"
static void OnChange_remote_capabilities(cvar_t *var, char *string, qbool *cancel);
cvar_t cl_remote_capabilities = {"cl_remote_capabilities", REMOTE_CAPABILITIES, 0,
OnChange_remote_capabilities};
hashtable_t *rc_hash;

cvar_t cl_allow_downloads = {"cl_allow_downloads", "bsp,lmp,loc,mdl,mvd,pcx,spr,wad,wav"};
cvar_t cl_allow_uploads = {"cl_allow_uploads", "0"};

cbuf_t cbuf_main;
cbuf_t cbuf_svc;
cbuf_t cbuf_safe, cbuf_formatted_comms;
cbuf_t cbuf_server;

cbuf_t *cbuf_current = NULL;

static void OnChange_remote_capabilities(cvar_t *var, char *string, qbool *cancel)
{
char *cmd, *ent, *tmp;

if (cls.state != ca_disconnected)
{
Com_Printf("You cannot change remote capabilities unless you are disconnected\n");
return;
}

if (!rc_hash || strlen(var->string) == 0)
{
goto add;
}

tmp = Q_strdup(var->string);
cmd = strtok(tmp, ",");
while (cmd != NULL)
{
Com_DPrintf("Removing %s from remote capabilities\n", cmd);

if ((ent = Hash_Get(rc_hash, cmd)))
{
Q_free(ent);
Hash_Remove(rc_hash, cmd);
}

cmd = strtok(NULL, ",");
}
Q_free(tmp);

add:
if (!rc_hash)
{
rc_hash = Hash_InitTable(512);
}
else
{
Hash_Flush(rc_hash);
}

tmp = Q_strdup(string);
cmd = strtok(tmp, ",");
while (cmd != NULL)
{
Com_DPrintf("Adding %s to capabilities\n", cmd);

if (!Hash_Get(rc_hash, cmd))
{
ent = Q_malloc(sizeof(char));
*ent = 1;
Hash_Add(rc_hash, cmd, (void *)ent);
}

cmd = strtok(NULL, ",");
}
Q_free(tmp);
}

//=============================================================================

//Causes execution of the remainder of the command buffer to be delayed until next frame.
Expand Down Expand Up @@ -1742,6 +1815,7 @@ static void Cmd_ExecuteStringEx (cbuf_t *context, char *text)
cbuf_t *inserttarget, *oldcontext;
char *p, *n, *s;
char text_exp[1024];
qbool is_server_alias = false;

oldcontext = cbuf_current;
cbuf_current = context;
Expand Down Expand Up @@ -1778,10 +1852,17 @@ static void Cmd_ExecuteStringEx (cbuf_t *context, char *text)
}
}

if (cmd->function)
if (cmd->function) {
if (cbuf_current == &cbuf_svc && !Hash_Get(rc_hash, cmd->name)) {
Com_Printf("Blocked %s: not in cl_remote_capabilities\n", cmd->name);
goto done;
}

cmd->function();
else
}
else {
Cmd_ForwardToServer ();
}
goto done;
}

Expand All @@ -1791,6 +1872,11 @@ static void Cmd_ExecuteStringEx (cbuf_t *context, char *text)

// check cvars
if ((v = Cvar_Find(Cmd_Argv(0)))) {
if (cbuf_current == &cbuf_svc && !Hash_Get(rc_hash, v->name)) {
Com_Printf("Blocked %s: not in cl_remote_capabilities\n", v->name);
goto done;
}

if (cbuf_current == &cbuf_formatted_comms) {
Com_Printf ("\"%s\" cannot be used in combination with teamplay $macros\n", Cmd_Argv(0));
goto done;
Expand All @@ -1802,6 +1888,7 @@ static void Cmd_ExecuteStringEx (cbuf_t *context, char *text)
// check aliases
checkaliases:
if ((a = Cmd_FindAlias(Cmd_Argv(0)))) {
is_server_alias = a->flags & ALIAS_SERVER;

// QW262 -->
if (a->value[0] == '\0') {
Expand Down Expand Up @@ -1851,11 +1938,15 @@ static void Cmd_ExecuteStringEx (cbuf_t *context, char *text)

if (cbuf_current == &cbuf_svc)
{
Cbuf_AddText (p);
Cbuf_AddText ("\n");
Cbuf_AddTextEx (&cbuf_svc, p);
Cbuf_AddTextEx (&cbuf_svc, "\n");
} else
{
inserttarget = cbuf_current ? cbuf_current : &cbuf_main;
if (is_server_alias)
inserttarget = &cbuf_svc;
else
inserttarget = cbuf_current ? cbuf_current : &cbuf_main;

Cbuf_InsertTextEx (inserttarget, "\n");

// if the alias value is a command or cvar and
Expand Down Expand Up @@ -2403,7 +2494,10 @@ void Cmd_Init (void)
// <-- QW262

Cvar_Register(&cl_curlybraces);
Cvar_Register(&cl_warnexec);
Cvar_Register(&cl_warnexec);
Cvar_Register(&cl_remote_capabilities);
Cvar_Register(&cl_allow_downloads);
Cvar_Register(&cl_allow_uploads);

Cmd_AddCommand ("macrolist", Cmd_MacroList_f);
qsort(msgtrigger_commands,
Expand Down

0 comments on commit 1678bb1

Please sign in to comment.