summaryrefslogtreecommitdiff
path: root/source/sv_mvd.c
diff options
context:
space:
mode:
authorAndrey Nazarov <skuller@skuller.net>2008-10-15 18:07:06 +0000
committerAndrey Nazarov <skuller@skuller.net>2008-10-15 18:07:06 +0000
commit58c8e2e0377eddcae7f44d30b78578fbedf0eaa7 (patch)
tree3643ef5da6e9e397cf4c27ff93b4722843b5c83c /source/sv_mvd.c
parent2ff447b2019b5696375fbc09d87416345418cd9a (diff)
Added `sv_mvd_allow_stufftext' and `sv_mvd_password' cvars.
MVD admins now can execute arbitrary commands on behaf of the dummy MVD observer on game server side via `fwd' command, if allowed. MVD channel is now listed in the menu when it is not suspended, not just when there are active players. Made `mvdconnect' command accept --user and --pass options. When masking off high-bit characters before displaying them on system console or writing into logfile, ignore any control characters. Updated documentation.
Diffstat (limited to 'source/sv_mvd.c')
-rw-r--r--source/sv_mvd.c115
1 files changed, 84 insertions, 31 deletions
diff --git a/source/sv_mvd.c b/source/sv_mvd.c
index 0bf663e..6a106d0 100644
--- a/source/sv_mvd.c
+++ b/source/sv_mvd.c
@@ -90,7 +90,7 @@ static LIST_DECL( gtv_host_list );
static cvar_t *sv_mvd_enable;
static cvar_t *sv_mvd_maxclients;
static cvar_t *sv_mvd_bufsize;
-static cvar_t *sv_mvd_auth;
+static cvar_t *sv_mvd_password;
static cvar_t *sv_mvd_noblend;
static cvar_t *sv_mvd_nogun;
static cvar_t *sv_mvd_nomsgs;
@@ -103,6 +103,7 @@ static cvar_t *sv_mvd_autorecord;
static cvar_t *sv_mvd_capture_flags;
static cvar_t *sv_mvd_disconnect_time;
static cvar_t *sv_mvd_suspend_time;
+static cvar_t *sv_mvd_allow_stufftext;
static qboolean mvd_enable( void );
static void mvd_disable( void );
@@ -144,10 +145,7 @@ static void dummy_wait_f( void ) {
dummy_buffer.waitCount = count;
}
-static void dummy_forward_f( void ) {
- Cmd_Shift();
- Com_DPrintf( "dummy cmd: %s %s\n", Cmd_Argv( 0 ), Cmd_Args() );
-
+static void dummy_command( void ) {
sv_client = mvd.dummy;
sv_player = sv_client->edict;
ge->ClientCommand( sv_player );
@@ -155,6 +153,12 @@ static void dummy_forward_f( void ) {
sv_player = NULL;
}
+static void dummy_forward_f( void ) {
+ Cmd_Shift();
+ Com_DPrintf( "dummy cmd: %s %s\n", Cmd_Argv( 0 ), Cmd_Args() );
+ dummy_command();
+}
+
static void dummy_record_f( void ) {
char buffer[MAX_OSPATH];
fileHandle_t demofile;
@@ -214,7 +218,9 @@ static const ucmd_t dummy_cmds[] = {
{ "set", Cvar_Set_f },
{ "alias", Cmd_Alias_f },
{ "play", NULL },
+ { "stopsound", NULL },
{ "exec", NULL },
+ { "screenshot", NULL },
{ "wait", dummy_wait_f },
{ "record", dummy_record_f },
{ "stop", dummy_stop_f },
@@ -236,19 +242,17 @@ static void dummy_exec_string( const char *line ) {
if( !cmd[0] ) {
return;
}
- for( u = dummy_cmds; u->name; u++ ) {
- if( !strcmp( cmd, u->name ) ) {
- if( u->func ) {
- u->func();
- }
- return;
+ if( ( u = Com_Find( dummy_cmds, cmd ) ) != NULL ) {
+ if( u->func ) {
+ u->func();
}
+ return;
}
alias = Cmd_AliasCommand( cmd );
if( alias ) {
if( ++dummy_buffer.aliasCount == ALIAS_LOOP_COUNT ) {
- Com_WPrintf( "dummy_exec_string: runaway alias loop\n" );
+ Com_WPrintf( "%s: runaway alias loop\n", __func__ );
return;
}
Cbuf_InsertTextEx( &dummy_buffer, alias );
@@ -261,26 +265,27 @@ static void dummy_exec_string( const char *line ) {
return;
}
- Com_DPrintf( "dummy stufftext: %s\n", line );
- sv_client = mvd.dummy;
- sv_player = mvd.dummy->edict;
- ge->ClientCommand( sv_player );
- sv_client = NULL;
- sv_player = NULL;
+ Com_DPrintf( "dummy forward: %s\n", line );
+ dummy_command();
}
static void dummy_add_message( client_t *client, byte *data,
size_t length, qboolean reliable )
{
- if( !length || !reliable ) {
- return;
+ char *text;
+
+ if( !length || !reliable || data[0] != svc_stufftext ) {
+ return; // not interesting
}
- if( data[0] == svc_stufftext ) {
- data[length] = 0;
- Cbuf_AddTextEx( &dummy_buffer, ( char * )( data + 1 ) );
- return;
+ if( sv_mvd_allow_stufftext->integer <= 0 ) {
+ return; // not allowed
}
+
+ data[length] = 0;
+ text = ( char * )( data + 1 );
+ Com_DPrintf( "dummy stufftext: %s\n", text );
+ Cbuf_AddTextEx( &dummy_buffer, text );
}
static void dummy_spawn( void ) {
@@ -1285,7 +1290,21 @@ static void write_message( gtv_client_t *client, gtv_serverop_t op ) {
write_stream( client, msg_write.data, msg_write.cursize );
}
+static qboolean auth_client( gtv_client_t *client, const char *password ) {
+ if( SV_MatchAddress( &gtv_host_list, &client->stream.address ) ) {
+ return qtrue; // dedicated GTV hosts don't need password
+ }
+ if( !sv_mvd_password->string[0] ) {
+ return qfalse; // no password set on the server
+ }
+ if( strcmp( sv_mvd_password->string, password ) ) {
+ return qfalse; // password doesn't match
+ }
+ return qtrue;
+}
+
static void parse_hello( gtv_client_t *client ) {
+ char password[MAX_QPATH];
int protocol, flags;
size_t size;
byte *data;
@@ -1311,15 +1330,20 @@ static void parse_hello( gtv_client_t *client ) {
flags = MSG_ReadLong();
MSG_ReadLong();
MSG_ReadString( client->name, sizeof( client->name ) );
- MSG_ReadString( NULL, 0 );
+ MSG_ReadString( password, sizeof( password ) );
MSG_ReadString( client->version, sizeof( client->version ) );
- if( !SV_MatchAddress( &gtv_host_list, &client->stream.address ) ) {
+ // authorize access
+ if( !auth_client( client, password ) ) {
write_message( client, GTS_NOACCESS );
drop_client( client, "not authorized" );
return;
}
+ if( sv_mvd_allow_stufftext->integer >= 0 ) {
+ flags &= ~GTF_STRINGCMDS;
+ }
+
#if !USE_ZLIB
flags &= ~GTF_DEFLATE;
#endif
@@ -1427,6 +1451,29 @@ static void parse_stream_stop( gtv_client_t *client ) {
#endif
}
+static void parse_stringcmd( gtv_client_t *client ) {
+ char string[MAX_GTC_MSGLEN];
+
+ if( client->state < cs_primed ) {
+ drop_client( client, "unexpected stringcmd message" );
+ return;
+ }
+
+ if( !mvd.dummy || !( client->flags & GTF_STRINGCMDS ) ) {
+ Com_DPrintf( "ignored stringcmd from %s[%s]\n", client->name,
+ NET_AdrToString( &client->stream.address ) );
+ return;
+ }
+
+ MSG_ReadString( string, sizeof( string ) );
+
+ Cmd_TokenizeString( string, qfalse );
+
+ Com_DPrintf( "dummy stringcmd from %s[%s]: %s\n", client->name,
+ NET_AdrToString( &client->stream.address ), string );
+ dummy_command();
+}
+
static qboolean parse_message( gtv_client_t *client ) {
uint32_t magic;
uint16_t msglen;
@@ -1490,6 +1537,9 @@ static qboolean parse_message( gtv_client_t *client ) {
case GTC_STREAM_STOP:
parse_stream_stop( client );
break;
+ case GTC_STRINGCMD:
+ parse_stringcmd( client );
+ break;
default:
drop_client( client, "unknown command byte" );
return qfalse;
@@ -1875,6 +1925,10 @@ void SV_MvdInit( void ) {
Cvar_Set( "sv_mvd_enable", "1" );
}
}
+
+ dummy_buffer.text = dummy_buffer_text;
+ dummy_buffer.maxsize = sizeof( dummy_buffer_text );
+ dummy_buffer.exec = dummy_exec_string;
}
/*
@@ -1896,6 +1950,8 @@ void SV_MvdShutdown( killtype_t type ) {
NET_Listen( qfalse );
memset( &mvd, 0, sizeof( mvd ) );
+
+ memset( &dummy_buffer, 0, sizeof( dummy_buffer ) );
}
@@ -2121,7 +2177,7 @@ void SV_MvdRegister( void ) {
sv_mvd_enable = Cvar_Get( "sv_mvd_enable", "0", CVAR_LATCH );
sv_mvd_maxclients = Cvar_Get( "sv_mvd_maxclients", "8", CVAR_LATCH );
sv_mvd_bufsize = Cvar_Get( "sv_mvd_bufsize", "2", CVAR_LATCH );
- sv_mvd_auth = Cvar_Get( "sv_mvd_auth", "", CVAR_PRIVATE );
+ sv_mvd_password = Cvar_Get( "sv_mvd_password", "", CVAR_PRIVATE );
sv_mvd_maxsize = Cvar_Get( "sv_mvd_maxsize", "0", 0 );
sv_mvd_maxtime = Cvar_Get( "sv_mvd_maxtime", "0", 0 );
sv_mvd_maxmaps = Cvar_Get( "sv_mvd_maxmaps", "1", 0 );
@@ -2136,10 +2192,7 @@ void SV_MvdRegister( void ) {
sv_mvd_capture_flags = Cvar_Get( "sv_mvd_capture_flags", "5", 0 );
sv_mvd_disconnect_time = Cvar_Get( "sv_mvd_disconnect_time", "15", 0 );
sv_mvd_suspend_time = Cvar_Get( "sv_mvd_suspend_time", "5", 0 );
-
- dummy_buffer.text = dummy_buffer_text;
- dummy_buffer.maxsize = sizeof( dummy_buffer_text );
- dummy_buffer.exec = dummy_exec_string;
+ sv_mvd_allow_stufftext = Cvar_Get( "sv_mvd_allow_stufftext", "0", CVAR_LATCH );
Cmd_Register( c_svmvd );
}