From dd6a7cbc6f600396878e62f9bb8f32d41395f16c Mon Sep 17 00:00:00 2001 From: Anonymous Maarten Date: Sat, 1 Apr 2023 02:42:28 +0000 Subject: [PATCH] Fix for running with -robots + implement DOS gore password check (#249) * Fix SIGSEGV when running with -robots We cannot write to read-only memory. * Add --dos-mode argument to require entering password --- src/DETHRACE/common/init.c | 8 ++++- src/DETHRACE/common/skidmark.c | 12 ++++++-- src/DETHRACE/pc-dos/dossys.c | 44 ++++++++++++++++++++++++++-- src/harness/harness.c | 5 ++++ src/harness/include/harness/config.h | 1 + src/harness/include/harness/os.h | 2 ++ src/harness/os/linux.c | 43 +++++++++++++++++++++++++++ src/harness/os/macos.c | 7 +++++ src/harness/os/windows.c | 7 +++++ 9 files changed, 124 insertions(+), 5 deletions(-) diff --git a/src/DETHRACE/common/init.c b/src/DETHRACE/common/init.c index 56209602..8188786a 100644 --- a/src/DETHRACE/common/init.c +++ b/src/DETHRACE/common/init.c @@ -335,7 +335,13 @@ void Init2DStuff() { // IDA: void __usercall InitialiseApplication(int pArgc@, char **pArgv@) void InitialiseApplication(int pArgc, char** pArgv) { - gProgram_state.sausage_eater_mode = gSausage_override; + if (harness_game_config.dos_mode) { + gProgram_state.sausage_eater_mode = gSausage_override ? 1 : (PDGetGorePassword() ? 0 : 1); + PDDisplayGoreworthiness(!gProgram_state.sausage_eater_mode); + } else { + gProgram_state.sausage_eater_mode = gSausage_override; + } + MAMSInitMem(); PrintMemoryDump(gSausage_override, *pArgv); if (gAustere_override || PDDoWeLeadAnAustereExistance() != 0) { diff --git a/src/DETHRACE/common/skidmark.c b/src/DETHRACE/common/skidmark.c index e0ab3dda..ba42b023 100644 --- a/src/DETHRACE/common/skidmark.c +++ b/src/DETHRACE/common/skidmark.c @@ -110,22 +110,30 @@ void InitSkids() { int sl; br_model* square; char* str; +#if defined(DETHRACE_FIX_BUGS) + char mat_name[32]; +#endif LOG_TRACE("()"); - for (mat = 0; mat < 2; mat++) { + for (mat = 0; mat < COUNT_OF(gMaterial_names); mat++) { if (gProgram_state.sausage_eater_mode) { str = gBoring_material_names[mat]; } else { str = gMaterial_names[mat]; } gMaterial[mat] = BrMaterialFind(str); - if (!gMaterial[mat]) { + if (gMaterial[mat] == NULL) { if (gProgram_state.sausage_eater_mode) { str = gBoring_material_names[mat]; } else { str = gMaterial_names[mat]; } +#if defined(DETHRACE_FIX_BUGS) + // Avoid modification of read-only data by strtok. + strcpy(mat_name, str); + str = mat_name; +#endif sl = strlen(strtok(str, ".")); strcpy(str + sl, ".PIX"); BrMapAdd(LoadPixelmap(str)); diff --git a/src/DETHRACE/pc-dos/dossys.c b/src/DETHRACE/pc-dos/dossys.c index e0ab62c7..9ad402df 100644 --- a/src/DETHRACE/pc-dos/dossys.c +++ b/src/DETHRACE/pc-dos/dossys.c @@ -687,6 +687,34 @@ int OurGetChar() { NOT_IMPLEMENTED(); } +int CheckGorePasswordFile(char* pPassword) { + tPath_name path; + FILE* f; + char line[10]; + + PathCat(path, "DATA", "PASS.TXT"); + f = fopen(path, "rb"); + if (f == NULL) { + return 0; + } + if (fgets(line, sizeof(line), f) == NULL) { + fclose(f); + return 0; + } + fclose(f); +#if defined(DETHRACE_FIX_BUGS) + // Allow a final newline in DATA/PASS.TXT + while (strlen(line) > 0 && (line[strlen(line) - 1] == '\n' || line[strlen(line) - 1] == '\r')) { + line[strlen(line) - 1] = '\0'; + } +#endif +#ifdef _WIN32 + return stricmp(line, pPassword) == 0; +#else + return strcasecmp(line, pPassword) == 0; +#endif +} + // IDA: int __cdecl PDGetGorePassword() int PDGetGorePassword() { int ch; @@ -694,14 +722,26 @@ int PDGetGorePassword() { int chances; char password[17]; LOG_TRACE("()"); - NOT_IMPLEMENTED(); + + for (chances = 0; chances < 3; chances++) { + printf(chances == 0 ? "\n\n\n\n\nEnter password for uncut version...\n" : "\nIncorrect password, please try again...\n"); + OS_ConsoleReadPassword(password, sizeof(password)); + dr_dprintf("Password entered is '%s'", password); + if (CheckGorePasswordFile(password)) { + return 1; + } + } + return 0; } // IDA: void __usercall PDDisplayGoreworthiness(int pGory@) void PDDisplayGoreworthiness(int pGory) { tU32 delay_start; LOG_TRACE("(%d)", pGory); - NOT_IMPLEMENTED(); + + printf(pGory ? "\nPlaying full version...\n" : "\nPlaying zombie version...\n"); + delay_start = 2; + OS_Sleep(delay_start * 1000); } // IDA: void __usercall PDEnterDebugger(char *pStr@) diff --git a/src/harness/harness.c b/src/harness/harness.c index 4ce35a5d..889e563c 100644 --- a/src/harness/harness.c +++ b/src/harness/harness.c @@ -195,6 +195,8 @@ void Harness_Init(int* argc, char* argv[]) { harness_game_config.start_full_screen = 0; // disable replay by default harness_game_config.enable_replay = 0; + // Emulate DOS behavior + harness_game_config.dos_mode = 0; // install signal handler by default harness_game_config.install_signalhandler = 1; @@ -286,6 +288,9 @@ int Harness_ProcessCommandLine(int* argc, char* argv[]) { } else if (strcasecmp(argv[i], "--enable-replay") == 0) { harness_game_config.enable_replay = 1; handled = 1; + } else if (strcasecmp(argv[i], "--dos-mode") == 0) { + harness_game_config.dos_mode = 1; + handled = 1; } if (handled) { diff --git a/src/harness/include/harness/config.h b/src/harness/include/harness/config.h index 41174225..17c74475 100644 --- a/src/harness/include/harness/config.h +++ b/src/harness/include/harness/config.h @@ -40,6 +40,7 @@ typedef struct tHarness_game_config { float volume_multiplier; int start_full_screen; int enable_replay; + int dos_mode; int install_signalhandler; } tHarness_game_config; diff --git a/src/harness/include/harness/os.h b/src/harness/include/harness/os.h index 8514abaa..c66cfbbb 100644 --- a/src/harness/include/harness/os.h +++ b/src/harness/include/harness/os.h @@ -49,4 +49,6 @@ FILE* OS_fopen(const char* pathname, const char* mode); // Required: return a buffer for action replay. Preferably 20MB. If that is not available, then allocate a buffer of 12MB, 6MB, 4MB, 500kB or 64kiB void OS_AllocateActionReplayBuffer(char** pBuffer, unsigned* pBuffer_size); +size_t OS_ConsoleReadPassword(char* pBuffer, size_t pBufferLen); + #endif diff --git a/src/harness/os/linux.c b/src/harness/os/linux.c index 0b61b80e..eb8b9151 100644 --- a/src/harness/os/linux.c +++ b/src/harness/os/linux.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include @@ -367,3 +368,45 @@ void OS_AllocateActionReplayBuffer(char** pBuffer, unsigned* pBuffer_size) { *pBuffer = buffer; *pBuffer_size = buffer_size; } + +size_t OS_ConsoleReadPassword(char* pBuffer, size_t pBufferLen) { + struct termios old, new; + char c; + size_t len; + + tcgetattr(STDIN_FILENO, &old); + new = old; + new.c_lflag &= ~(ICANON | ECHO); + tcsetattr(STDIN_FILENO, TCSAFLUSH, &new); + + len = 0; + pBuffer[len] = '\0'; + while (1) { + if (read(STDIN_FILENO, &c, 1) == 1) { + if (c == 0x7f) { + if (len > 0) { + len--; + pBuffer[len] = '\0'; + printf("\033[1D \033[1D"); + fflush(stdout); + continue; + } + } else if (c == '\r' || c == '\n') { + printf("\n"); + fflush(stdout); + break; + } else if (len < pBufferLen - 1) { + if ((c >= '0' && c <= '9') || (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z')) { + pBuffer[len] = c; + printf("*"); + fflush(stdout); + len++; + pBuffer[len] = '\0'; + } + } + } + } + + tcsetattr(STDIN_FILENO, TCSANOW, &old); + return len; +} diff --git a/src/harness/os/macos.c b/src/harness/os/macos.c index 31e8fbd3..fec72d51 100644 --- a/src/harness/os/macos.c +++ b/src/harness/os/macos.c @@ -324,3 +324,10 @@ void OS_AllocateActionReplayBuffer(char** pBuffer, unsigned* pBuffer_size) { *pBuffer = buffer; *pBuffer_size = buffer_size; } + +size_t OS_ConsoleReadPassword(char* pBuffer, size_t pBufferLen) { + // FIXME: unsafe implementation (echos the password) + pBuffer[0] = '\0'; + fgets(pBuffer, pBufferLen, stdin); + return strlen(pBuffer); +} diff --git a/src/harness/os/windows.c b/src/harness/os/windows.c index 357e5786..6fe1ed7d 100644 --- a/src/harness/os/windows.c +++ b/src/harness/os/windows.c @@ -308,3 +308,10 @@ void OS_AllocateActionReplayBuffer(char** pBuffer, unsigned* pBuffer_size) { *pBuffer = buffer; *pBuffer_size = buffer_size; } + +size_t OS_ConsoleReadPassword(char* pBuffer, size_t pBufferLen) { + // FIXME: unsafe implementation (echos the password) + pBuffer[0] = '\0'; + fgets(pBuffer, pBufferLen, stdin); + return strlen(pBuffer); +}