diff --git a/code/client/cl_main.c b/code/client/cl_main.c index 59be427e..82d0edfb 100644 --- a/code/client/cl_main.c +++ b/code/client/cl_main.c @@ -1245,7 +1245,7 @@ void CL_ClearMemory(qboolean shutdownRef) CL_ShutdownAll(shutdownRef); // if not running a server clear the whole hunk - if ( !com_sv_running->integer ) { + if ( !com_sv_running || !com_sv_running->integer ) { // clear the whole hunk Hunk_Clear(); // clear collision map data @@ -1361,7 +1361,7 @@ static void CL_OldGame(void) { // change back to previous fs_game cl_oldGameSet = qfalse; - Cvar_Set2("fs_game", cl_oldGame, qtrue); + Cvar_Set("fs_game", cl_oldGame); FS_ConditionalRestart(clc.checksumFeed, qfalse); } } diff --git a/code/client/cl_parse.c b/code/client/cl_parse.c index 318c8d88..80bbec2d 100644 --- a/code/client/cl_parse.c +++ b/code/client/cl_parse.c @@ -399,7 +399,7 @@ void CL_SystemInfoChanged( void ) { // ehw! if (!Q_stricmp(key, "fs_game")) { - if(FS_CheckDirTraversal(value)) + if(FS_InvalidGameDir(value)) { Com_Printf(S_COLOR_YELLOW "WARNING: Server sent invalid fs_game value %s\n", value); continue; diff --git a/code/qcommon/common.c b/code/qcommon/common.c index 3dbee88f..6580073b 100644 --- a/code/qcommon/common.c +++ b/code/qcommon/common.c @@ -2404,6 +2404,9 @@ void Com_GameRestart(int checksumFeed, qboolean disconnect) CL_Shutdown("Game directory changed", disconnect, qfalse); } + // change com_basegame to latched value + com_basegame = Cvar_Get("com_basegame", BASEGAME, CVAR_LATCH|CVAR_NORESTART); + FS_Restart(checksumFeed); // Clean out any user and VM created cvars @@ -2439,16 +2442,7 @@ Expose possibility to change current running mod to the user void Com_GameRestart_f(void) { - if(!FS_FilenameCompare(Cmd_Argv(1), com_basegame->string)) - { - // This is the standard base game. Servers and clients should - // use "" and not the standard basegame name because this messes - // up pak file negotiation and lots of other stuff - - Cvar_Set("fs_game", ""); - } - else - Cvar_Set("fs_game", Cmd_Argv(1)); + Cvar_Set("fs_game", Cmd_Argv(1)); Com_GameRestart(0, qtrue); } @@ -2705,11 +2699,8 @@ void Com_Init( char *commandLine ) { CL_InitKeyCommands(); com_standalone = Cvar_Get("com_standalone", "0", CVAR_ROM); - com_basegame = Cvar_Get("com_basegame", BASEGAME, CVAR_INIT); - com_homepath = Cvar_Get("com_homepath", "", CVAR_INIT); - - if(!com_basegame->string[0]) - Cvar_ForceReset("com_basegame"); + com_basegame = Cvar_Get("com_basegame", BASEGAME, CVAR_LATCH|CVAR_NORESTART); + com_homepath = Cvar_Get("com_homepath", "", CVAR_INIT|CVAR_PROTECTED); FS_InitFilesystem (); diff --git a/code/qcommon/files.c b/code/qcommon/files.c index 3545cd1d..eb61af9c 100644 --- a/code/qcommon/files.c +++ b/code/qcommon/files.c @@ -3067,6 +3067,24 @@ qboolean FS_CheckDirTraversal(const char *checkdir) return qfalse; } +/* +================ +FS_InvalidGameDir + +return true if path is a reference to current directory or directory traversal +================ +*/ +qboolean FS_InvalidGameDir( const char *gamedir ) { + if ( !strcmp( gamedir, "." ) || !strcmp( gamedir, ".." ) + || !strcmp( gamedir, "/" ) || !strcmp( gamedir, "\\" ) + || strstr( gamedir, "/.." ) || strstr( gamedir, "\\.." ) + || FS_CheckDirTraversal( gamedir ) ) { + return qtrue; + } + + return qfalse; +} + /* ================ FS_ComparePaks @@ -3301,13 +3319,34 @@ static void FS_Startup( const char *gameName ) fs_debug = Cvar_Get( "fs_debug", "0", 0 ); fs_basepath = Cvar_Get ("fs_basepath", Sys_DefaultInstallPath(), CVAR_INIT|CVAR_PROTECTED ); - fs_basegame = Cvar_Get ("fs_basegame", "", CVAR_INIT ); + fs_basegame = Cvar_Get ("fs_basegame", "", CVAR_LATCH|CVAR_NORESTART ); homePath = Sys_DefaultHomePath(); if (!homePath || !homePath[0]) { homePath = fs_basepath->string; } fs_homepath = Cvar_Get ("fs_homepath", homePath, CVAR_INIT|CVAR_PROTECTED ); - fs_gamedirvar = Cvar_Get ("fs_game", "", CVAR_INIT|CVAR_SYSTEMINFO ); + fs_gamedirvar = Cvar_Get ("fs_game", "", CVAR_LATCH|CVAR_NORESTART|CVAR_SYSTEMINFO ); + + if (!gameName[0]) { + Cvar_ForceReset( "com_basegame" ); + } + + if (!FS_FilenameCompare(fs_gamedirvar->string, gameName)) { + // This is the standard base game. Servers and clients should + // use "" and not the standard basegame name because this messes + // up pak file negotiation and lots of other stuff + Cvar_ForceReset( "fs_game" ); + } + + if (FS_InvalidGameDir(gameName)) { + Com_Error( ERR_DROP, "Invalid com_basegame '%s'", gameName ); + } + if (FS_InvalidGameDir(fs_basegame->string)) { + Com_Error( ERR_DROP, "Invalid fs_basegame '%s'", fs_basegame->string ); + } + if (FS_InvalidGameDir(fs_gamedirvar->string)) { + Com_Error( ERR_DROP, "Invalid fs_game '%s'", fs_gamedirvar->string ); + } // add search path elements in reverse priority order fs_gogpath = Cvar_Get ("fs_gogpath", Sys_GogPath(), CVAR_INIT|CVAR_PROTECTED ); @@ -3391,8 +3430,6 @@ static void FS_Startup( const char *gameName ) // print the current search paths FS_Path_f(); - fs_gamedirvar->modified = qfalse; // We just loaded, it's not modified - Com_Printf( "----------------------\n" ); #ifdef FS_MISSING @@ -4040,17 +4077,10 @@ Return qtrue if restarting due to game directory changed, qfalse otherwise */ qboolean FS_ConditionalRestart(int checksumFeed, qboolean disconnect) { - if(fs_gamedirvar->modified) + if (com_basegame->latchedString || fs_basegame->latchedString || fs_gamedirvar->latchedString) { - if(FS_FilenameCompare(lastValidGame, fs_gamedirvar->string) && - (*lastValidGame || FS_FilenameCompare(fs_gamedirvar->string, com_basegame->string)) && - (*fs_gamedirvar->string || FS_FilenameCompare(lastValidGame, com_basegame->string))) - { - Com_GameRestart(checksumFeed, disconnect); - return qtrue; - } - else - fs_gamedirvar->modified = qfalse; + Com_GameRestart(checksumFeed, disconnect); + return qtrue; } if(checksumFeed != fs_checksumFeed) diff --git a/code/qcommon/qcommon.h b/code/qcommon/qcommon.h index 2880f70d..4471198c 100644 --- a/code/qcommon/qcommon.h +++ b/code/qcommon/qcommon.h @@ -726,6 +726,7 @@ void FS_PureServerSetLoadedPaks( const char *pakSums, const char *pakNames ); // sole exception of .cfg files. qboolean FS_CheckDirTraversal(const char *checkdir); +qboolean FS_InvalidGameDir(const char *gamedir); qboolean FS_idPak(char *pak, char *base, int numPaks); qboolean FS_ComparePaks( char *neededpaks, int len, qboolean dlstring );