[IO]: Add functions to read file streams safely (#862)
This commit is contained in:
parent
ed9fc9aa7b
commit
b89dd52118
@ -6,15 +6,86 @@ namespace Components::GSC
|
||||
{
|
||||
const char* IO::ForbiddenStrings[] = { R"(..)", R"(../)", R"(..\)" };
|
||||
|
||||
FILE* IO::openScriptIOFileHandle;
|
||||
|
||||
std::filesystem::path IO::Path;
|
||||
|
||||
void IO::GScr_OpenFile()
|
||||
{
|
||||
const auto* filepath = Game::Scr_GetString(0);
|
||||
const auto* mode = Game::Scr_GetString(1);
|
||||
|
||||
if (mode != "read"s)
|
||||
{
|
||||
Logger::PrintError(Game::CON_CHANNEL_PARSERSCRIPT, "Valid openfile modes are 'read'\n");
|
||||
Game::Scr_AddInt(-1);
|
||||
return;
|
||||
}
|
||||
|
||||
if (openScriptIOFileHandle)
|
||||
{
|
||||
Logger::PrintError(Game::CON_CHANNEL_PARSERSCRIPT, "OpenFile failed. {} files already open\n", 1);
|
||||
Game::Scr_AddInt(-1);
|
||||
return;
|
||||
}
|
||||
|
||||
const auto scriptData = Path / "scriptdata"s / filepath;
|
||||
|
||||
_set_errno(0);
|
||||
const auto result = fopen_s(&openScriptIOFileHandle, scriptData.string().data(), "r");
|
||||
if (result || !openScriptIOFileHandle)
|
||||
{
|
||||
Logger::PrintError(Game::CON_CHANNEL_PARSERSCRIPT, "OpenFile failed. '{}'", result);
|
||||
Game::Scr_AddInt(-1);
|
||||
return;
|
||||
}
|
||||
|
||||
Game::Scr_AddInt(1);
|
||||
}
|
||||
|
||||
void IO::GScr_ReadStream()
|
||||
{
|
||||
if (!openScriptIOFileHandle)
|
||||
{
|
||||
Logger::PrintError(Game::CON_CHANNEL_PARSERSCRIPT, "ReadStream failed. File stream was not opened\n");
|
||||
return;
|
||||
}
|
||||
|
||||
char line[1024]{};
|
||||
if (std::fgets(line, sizeof(line), openScriptIOFileHandle) != nullptr)
|
||||
{
|
||||
Game::Scr_AddString(line);
|
||||
return;
|
||||
}
|
||||
|
||||
Logger::PrintError(Game::CON_CHANNEL_PARSERSCRIPT, "ReadStream failed.\n");
|
||||
|
||||
if (std::feof(openScriptIOFileHandle))
|
||||
{
|
||||
Logger::Print(Game::CON_CHANNEL_PARSERSCRIPT, "ReadStream: EOF reached\n");
|
||||
}
|
||||
}
|
||||
|
||||
void IO::GScr_CloseFile()
|
||||
{
|
||||
if (!openScriptIOFileHandle)
|
||||
{
|
||||
Logger::PrintError(Game::CON_CHANNEL_PARSERSCRIPT, "CloseFile failed. File stream was not opened\n");
|
||||
Game::Scr_AddInt(-1);
|
||||
return;
|
||||
}
|
||||
|
||||
Game::Scr_AddInt(std::fclose(openScriptIOFileHandle));
|
||||
openScriptIOFileHandle = nullptr;
|
||||
}
|
||||
|
||||
void IO::AddScriptFunctions()
|
||||
{
|
||||
Script::AddFunction("FileWrite", [] // gsc: FileWrite(<filepath>, <string>, <mode>)
|
||||
{
|
||||
const auto* filepath = Game::Scr_GetString(0);
|
||||
auto* text = Game::Scr_GetString(1);
|
||||
auto* mode = Game::Scr_GetString(2);
|
||||
const auto* text = Game::Scr_GetString(1);
|
||||
const auto* mode = Game::Scr_GetString(2);
|
||||
|
||||
if (!filepath)
|
||||
{
|
||||
@ -32,14 +103,14 @@ namespace Components::GSC
|
||||
{
|
||||
if (std::strstr(filepath, ForbiddenStrings[i]) != nullptr)
|
||||
{
|
||||
Logger::PrintError(Game::CON_CHANNEL_ERROR, "FileWrite: directory traversal is not allowed!\n");
|
||||
Logger::PrintError(Game::CON_CHANNEL_PARSERSCRIPT, "FileWrite: directory traversal is not allowed!\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (mode != "append"s && mode != "write"s)
|
||||
{
|
||||
Logger::Warning(Game::CON_CHANNEL_SCRIPT, "FileWrite: mode not defined or was wrong, defaulting to 'write'\n");
|
||||
Logger::Warning(Game::CON_CHANNEL_PARSERSCRIPT, "FileWrite: mode not defined or was wrong, defaulting to 'write'\n");
|
||||
mode = "write";
|
||||
}
|
||||
|
||||
@ -61,7 +132,7 @@ namespace Components::GSC
|
||||
{
|
||||
if (std::strstr(filepath, ForbiddenStrings[i]) != nullptr)
|
||||
{
|
||||
Logger::PrintError(Game::CON_CHANNEL_ERROR, "FileRead: directory traversal is not allowed!\n");
|
||||
Logger::PrintError(Game::CON_CHANNEL_PARSERSCRIPT, "FileRead: directory traversal is not allowed!\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -71,7 +142,7 @@ namespace Components::GSC
|
||||
std::string file;
|
||||
if (!Utils::IO::ReadFile(scriptData.string(), &file))
|
||||
{
|
||||
Logger::PrintError(Game::CON_CHANNEL_ERROR, "FileRead: file '{}' not found!\n", scriptData.string());
|
||||
Logger::PrintError(Game::CON_CHANNEL_PARSERSCRIPT, "FileRead: file '{}' not found!\n", scriptData.string());
|
||||
return;
|
||||
}
|
||||
|
||||
@ -92,7 +163,7 @@ namespace Components::GSC
|
||||
{
|
||||
if (std::strstr(filepath, ForbiddenStrings[i]) != nullptr)
|
||||
{
|
||||
Logger::PrintError(Game::CON_CHANNEL_ERROR, "FileExists: directory traversal is not allowed!\n");
|
||||
Logger::PrintError(Game::CON_CHANNEL_PARSERSCRIPT, "FileExists: directory traversal is not allowed!\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -114,7 +185,7 @@ namespace Components::GSC
|
||||
{
|
||||
if (std::strstr(filepath, ForbiddenStrings[i]) != nullptr)
|
||||
{
|
||||
Logger::Print("FileRemove: directory traversal is not allowed!\n");
|
||||
Logger::PrintError(Game::CON_CHANNEL_PARSERSCRIPT, "FileRemove: directory traversal is not allowed!\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -122,12 +193,21 @@ namespace Components::GSC
|
||||
const auto scriptData = Path / "scriptdata"s / filepath;
|
||||
Game::Scr_AddInt(Utils::IO::RemoveFile(scriptData.string()));
|
||||
});
|
||||
|
||||
Script::AddFunction("ReadStream", GScr_ReadStream);
|
||||
}
|
||||
|
||||
IO::IO()
|
||||
{
|
||||
openScriptIOFileHandle = nullptr;
|
||||
Path = "userraw"s;
|
||||
|
||||
AddScriptFunctions();
|
||||
|
||||
Utils::Hook::Set<Game::BuiltinFunction>(0x79A858, GScr_OpenFile);
|
||||
Utils::Hook::Set<int>(0x79A85C, 0);
|
||||
|
||||
Utils::Hook::Set<Game::BuiltinFunction>(0x79A864, GScr_CloseFile);
|
||||
Utils::Hook::Set<int>(0x79A868, 0);
|
||||
}
|
||||
}
|
||||
|
@ -10,8 +10,14 @@ namespace Components::GSC
|
||||
private:
|
||||
static const char* ForbiddenStrings[];
|
||||
|
||||
static FILE* openScriptIOFileHandle;
|
||||
|
||||
static std::filesystem::path Path;
|
||||
|
||||
static void GScr_OpenFile();
|
||||
static void GScr_ReadStream();
|
||||
static void GScr_CloseFile();
|
||||
|
||||
static void AddScriptFunctions();
|
||||
};
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user