/* =============== SVC_RemoteCommand An rcon packet arrived from the network. Shift down the remaining args Redirect all printfs =============== */ void SVC_RemoteCommand( netadr_t from, msg_t *msg ) { qboolean valid; unsigned int time; char remaining[1024]; // TTimo - scaled down to accumulate, but not overflow anything network wise, print wise etc. // (OOB messages are the bottleneck here) #define SV_OUTPUTBUF_LENGTH (1024 - 16) char sv_outputbuf[SV_OUTPUTBUF_LENGTH]; static unsigned int lasttime = 0; char *cmd_aux; // TTimo - https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=534 time = Com_Milliseconds(); if ( (unsigned)( time - lasttime ) < 500u ) { return; } lasttime = time; if ( !strlen( sv_rconPassword->string ) || strcmp (Cmd_Argv(1), sv_rconPassword->string) ) { valid = qfalse; Com_Printf ("Bad rcon from %s:\n%s\n", NET_AdrToString (from), Cmd_Argv(2) ); } else { valid = qtrue; Com_Printf ("Rcon from %s:\n%s\n", NET_AdrToString (from), Cmd_Argv(2) ); } // start redirecting all print outputs to the packet svs.redirectAddress = from; Com_BeginRedirect (sv_outputbuf, SV_OUTPUTBUF_LENGTH, SV_FlushRedirect); if ( !strlen( sv_rconPassword->string ) ) { Com_Printf ("No rconpassword set on the server.\n"); } else if ( !valid ) { Com_Printf ("Bad rconpassword.\n"); } else { remaining[0] = 0; // https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=543 // get the command directly, "rcon <pass> <command>" to avoid quoting issues // extract the command by walking // since the cmd formatting can fuckup (amount of spaces), using a dumb step by step parsing cmd_aux = Cmd_Cmd(); cmd_aux+=4; while(cmd_aux[0]==' ') cmd_aux++; while(cmd_aux[0] && cmd_aux[0]!=' ') // password cmd_aux++; while(cmd_aux[0]==' ') cmd_aux++; Q_strcat( remaining, sizeof(remaining), cmd_aux); Cmd_ExecuteString (remaining); } Com_EndRedirect (); }
/* =============== SVC_RemoteCommand An rcon packet arrived from the network. Shift down the remaining args Redirect all printfs =============== */ void SVC_RemoteCommand( netadr_t from, msg_t *msg ) { #if defined RTCW_SP qboolean valid; int i; char remaining[1024]; #define SV_OUTPUTBUF_LENGTH ( MAX_MSGLEN - 16 ) char sv_outputbuf[SV_OUTPUTBUF_LENGTH]; if ( !strlen( sv_rconPassword->string ) || strcmp( Cmd_Argv( 1 ), sv_rconPassword->string ) ) { valid = qfalse; Com_DPrintf( "Bad rcon from %s:\n%s\n", NET_AdrToString( from ), Cmd_Argv( 2 ) ); } else { valid = qtrue; Com_DPrintf( "Rcon from %s:\n%s\n", NET_AdrToString( from ), Cmd_Argv( 2 ) ); } // start redirecting all print outputs to the packet svs.redirectAddress = from; Com_BeginRedirect( sv_outputbuf, SV_OUTPUTBUF_LENGTH, SV_FlushRedirect ); if ( !strlen( sv_rconPassword->string ) ) { Com_Printf( "No rconpassword set.\n" ); } else if ( !valid ) { Com_Printf( "Bad rconpassword.\n" ); } else { remaining[0] = 0; for ( i = 2 ; i < Cmd_Argc() ; i++ ) { strcat( remaining, Cmd_Argv( i ) ); strcat( remaining, " " ); } Cmd_ExecuteString( remaining ); } Com_EndRedirect(); #else qboolean valid; unsigned int time; char remaining[1024]; // show_bug.cgi?id=376 // if we send an OOB print message this size, 1.31 clients die in a Com_Printf buffer overflow // the buffer overflow will be fixed in > 1.31 clients // but we want a server side fix // we must NEVER send an OOB message that will be > 1.31 MAXPRINTMSG (4096) #define SV_OUTPUTBUF_LENGTH ( 256 - 16 ) char sv_outputbuf[SV_OUTPUTBUF_LENGTH]; static unsigned int lasttime = 0; char *cmd_aux; // TTimo - show_bug.cgi?id=534 time = Com_Milliseconds(); if ( time < ( lasttime + 500 ) ) { return; } lasttime = time; if ( !strlen( sv_rconPassword->string ) || strcmp( Cmd_Argv( 1 ), sv_rconPassword->string ) ) { valid = qfalse; Com_Printf( "Bad rcon from %s:\n%s\n", NET_AdrToString( from ), Cmd_Argv( 2 ) ); } else { valid = qtrue; Com_Printf( "Rcon from %s:\n%s\n", NET_AdrToString( from ), Cmd_Argv( 2 ) ); } // start redirecting all print outputs to the packet svs.redirectAddress = from; // FIXME TTimo our rcon redirection could be improved // big rcon commands such as status lead to sending // out of band packets on every single call to Com_Printf // which leads to client overflows // see show_bug.cgi?id=51 // (also a Q3 issue) Com_BeginRedirect( sv_outputbuf, SV_OUTPUTBUF_LENGTH, SV_FlushRedirect ); if ( !strlen( sv_rconPassword->string ) ) { Com_Printf( "No rconpassword set on the server.\n" ); } else if ( !valid ) { Com_Printf( "Bad rconpassword.\n" ); } else { remaining[0] = 0; // ATVI Wolfenstein Misc #284 // get the command directly, "rcon <pass> <command>" to avoid quoting issues // extract the command by walking // since the cmd formatting can fuckup (amount of spaces), using a dumb step by step parsing cmd_aux = Cmd_Cmd(); cmd_aux += 4; while ( cmd_aux[0] == ' ' ) cmd_aux++; while ( cmd_aux[0] && cmd_aux[0] != ' ' ) // password cmd_aux++; while ( cmd_aux[0] == ' ' ) cmd_aux++; Q_strcat( remaining, sizeof( remaining ), cmd_aux ); Cmd_ExecuteString( remaining ); } Com_EndRedirect(); #endif // RTCW_XX }
/* =============== SVC_RemoteCommand An rcon packet arrived from the network. Shift down the remaining args Redirect all printfs =============== */ void SVC_RemoteCommand(netadr_t from, msg_t * msg) { bool valid; unsigned int time; char remaining[1024]; // show_bug.cgi?id=376 // if we send an OOB print message this size, 1.31 clients die in a Com_Printf buffer overflow // the buffer overflow will be fixed in > 1.31 clients // but we want a server side fix // we must NEVER send an OOB message that will be > 1.31 MAXPRINTMSG (4096) #define SV_OUTPUTBUF_LENGTH ( 256 - 16 ) char sv_outputbuf[SV_OUTPUTBUF_LENGTH], *cmd_aux; static unsigned int lasttime = 0; // TTimo - show_bug.cgi?id=534 time = Com_Milliseconds(); // Do we have a whitelist for rcon? if(sv_WhiteListRcon->string && *sv_WhiteListRcon->string) { // Prevent use of rcon from addresses that have not been whitelisted if(!SV_IsRconWhitelisted(&from)) { Com_Printf( "SVC_RemoteCommand: attempt from %s who is not whitelisted\n", NET_AdrToString( from ) ); NET_OutOfBandPrint(NS_SERVER, from, "print\nClient not found whitelist data.\n"); SV_DropClientsByAddress(&from, "Client tried to access to RCON password."); return; } } if ( !strlen( sv_rconPassword->string ) || strcmp (Cmd_Argv(1), sv_rconPassword->string) ) { // MaJ - If the rconpassword is bad and one just happned recently, don't spam the log file, just die. if ( (unsigned)( time - lasttime ) < 500u ) { return; } valid = false; Com_Printf ("Bad rcon from %s:\n%s\n", NET_AdrToString (from), Cmd_Argv(2) ); } else { // MaJ - If the rconpassword is good, allow it much sooner than a bad one. if ( (unsigned)( time - lasttime ) < 200u ) { return; } valid = true; Com_Printf ("Rcon from %s:\n%s\n", NET_AdrToString (from), Cmd_Argv(2) ); } lasttime = time; // start redirecting all print outputs to the packet svs.redirectAddress = from; // FIXME TTimo our rcon redirection could be improved // big rcon commands such as status lead to sending // out of band packets on every single call to Com_Printf // which leads to client overflows // see show_bug.cgi?id=51 // (also a Q3 issue) Com_BeginRedirect(sv_outputbuf, SV_OUTPUTBUF_LENGTH, SV_FlushRedirect); if(!strlen(sv_rconPassword->string)) { Com_Printf("No rconpassword set on the server.\n"); } else if(!valid) { Com_Printf("Bad rconpassword.\n"); } else { remaining[0] = 0; // ATVI Wolfenstein Misc #284 // get the command directly, "rcon <pass> <command>" to avoid quoting issues // extract the command by walking // since the cmd formatting can fuckup (amount of spaces), using a dumb step by step parsing cmd_aux = Cmd_Cmd(); cmd_aux += 4; while(cmd_aux[0] == ' ') { cmd_aux++; } while(cmd_aux[0] && cmd_aux[0] != ' ') { // password cmd_aux++; } while(cmd_aux[0] == ' ') { cmd_aux++; } Q_strcat(remaining, sizeof(remaining), cmd_aux); Cmd_ExecuteString(remaining); } Com_EndRedirect(); }
/* =============== SVC_RemoteCommand An rcon packet arrived from the network. Shift down the remaining args Redirect all printfs =============== */ void SVC_RemoteCommand( netadr_t from, msg_t *msg ) { qboolean valid; unsigned int time; char remaining[1024]; // TTimo - scaled down to accumulate, but not overflow anything network wise, print wise etc. // (OOB messages are the bottleneck here) #define SV_OUTPUTBUF_LENGTH (1024 - 16) char sv_outputbuf[SV_OUTPUTBUF_LENGTH]; static unsigned int lasttime = 0; char *cmd_aux; fileHandle_t rconLog = 0; // TTimo - https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=534 time = Com_Milliseconds(); if ( (unsigned)( time - lasttime ) < 500u ) { return; } lasttime = time; if(strlen(sv_rconLog->string)) { rconLog = FS_FOpenFileAppend(sv_rconLog->string); if (!rconLog) { Com_Printf("Warning: Unable to open sv_rconLog: \"%s\"", sv_rconLog->string); Cvar_Set ("sv_rconLog", ""); } } const char *message = ""; if ( !strlen( sv_rconPassword->string ) || strcmp (Cmd_Argv(1), sv_rconPassword->string) ) { valid = qfalse; message = va("Bad rcon from %s: %s\n", NET_AdrToString (from), Cmd_ArgsFrom(2)); } else { valid = qtrue; message = va("Rcon from %s: %s\n", NET_AdrToString (from), Cmd_ArgsFrom(2)); } Com_Printf (message); if (rconLog) { qtime_t qt; Com_RealTime(&qt); char *timestamp = va( "%02i/%02i/%02i %02i:%02i:%02i ", qt.tm_mday, qt.tm_mon, qt.tm_year-100, qt.tm_hour, qt.tm_min, qt.tm_sec ); FS_Write(timestamp, strlen(timestamp), rconLog); FS_Write(message, strlen(message), rconLog); FS_FCloseFile(rconLog); } // start redirecting all print outputs to the packet svs.redirectAddress = from; Com_BeginRedirect (sv_outputbuf, SV_OUTPUTBUF_LENGTH, SV_FlushRedirect); if ( !strlen( sv_rconPassword->string ) ) { Com_Printf ("No rconpassword set on the server.\n"); } else if ( !valid ) { Com_Printf ("Bad rconpassword.\n"); } else { remaining[0] = 0; // https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=543 // get the command directly, "rcon <pass> <command>" to avoid quoting issues // extract the command by walking // since the cmd formatting can fuckup (amount of spaces), using a dumb step by step parsing cmd_aux = Cmd_Cmd(); cmd_aux+=4; while(cmd_aux[0]==' ') cmd_aux++; while(cmd_aux[0] && cmd_aux[0]!=' ') // password cmd_aux++; while(cmd_aux[0]==' ') cmd_aux++; Q_strcat( remaining, sizeof(remaining), cmd_aux); Cmd_ExecuteString (remaining); } Com_EndRedirect (); }