From 6131cfd99d74b9db68f32dfc990f06875744c99b Mon Sep 17 00:00:00 2001 From: NepDisk Date: Sat, 23 Aug 2025 20:25:24 -0400 Subject: [PATCH 1/6] Add support for multiple admin passwords https://git.do.srb2.org/STJr/SRB2/-/merge_requests/2201/ --- src/d_clisrv.c | 27 ++++++++++++++++----------- src/d_clisrv.h | 4 ++-- src/d_netcmd.c | 36 ++++++++++++++++++++++++++++++++---- src/d_netcmd.h | 1 + 4 files changed, 51 insertions(+), 17 deletions(-) diff --git a/src/d_clisrv.c b/src/d_clisrv.c index f8a60004c..1ac529422 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -143,8 +143,8 @@ UINT8 hu_redownloadinggamestate = 0; // kart, true when a player is connecting or disconnecting so that the gameplay has stopped in its tracks boolean hu_stopped = false; -UINT8 adminpassmd5[16]; -boolean adminpasswordset = false; +UINT8 (*adminpassmd5)[16]; +UINT32 adminpasscount = 0; // Client specific static ticcmd_t localcmds[MAXSPLITSCREENPLAYERS][MAXGENTLEMENDELAY]; @@ -4629,6 +4629,7 @@ static void HandlePacketFromPlayer(SINT8 node) INT32 netconsole; tic_t realend, realstart; UINT8 *pak, *txtpak, numtxtpak; + UINT32 i; #ifndef NOMD5 UINT8 finalmd5[16];/* Well, it's the cool thing to do? */ #endif @@ -4874,22 +4875,26 @@ static void HandlePacketFromPlayer(SINT8 node) if (doomcom->datalength < 16)/* ignore partial sends */ break; - if (!adminpasswordset) + if (adminpasscount == 0) { CONS_Printf(M_GetText("Password from %s failed (no password set).\n"), player_names[netconsole]); break; } - // Do the final pass to compare with the sent md5 - D_MD5PasswordPass(adminpassmd5, 16, va("PNUM%02d", netconsole), &finalmd5); - - if (!memcmp(netbuffer->u.md5sum, finalmd5, 16)) + for (i = 0; i < adminpasscount; i++) { - CONS_Printf(M_GetText("%s passed authentication.\n"), player_names[netconsole]); - COM_BufInsertText(va("promote %d\n", netconsole)); // do this immediately + // Do the final pass to compare with the sent md5 + D_MD5PasswordPass(adminpassmd5[i], 16, va("PNUM%02d", netconsole), &finalmd5); + + if (!memcmp(netbuffer->u.md5sum, finalmd5, 16)) + { + CONS_Printf(M_GetText("%s passed authentication.\n"), player_names[netconsole]); + COM_BufInsertText(va("promote %d\n", netconsole)); // do this immediately + continue; + } } - else - CONS_Printf(M_GetText("Password from %s failed.\n"), player_names[netconsole]); + + CONS_Printf(M_GetText("Password from %s failed.\n"), player_names[netconsole]); #endif break; case PT_NODETIMEOUT: diff --git a/src/d_clisrv.h b/src/d_clisrv.h index 36e273074..26b233d53 100644 --- a/src/d_clisrv.h +++ b/src/d_clisrv.h @@ -588,8 +588,8 @@ void D_MD5PasswordPass(const UINT8 *buffer, size_t len, const char *salt, void * extern UINT8 hu_redownloadinggamestate; -extern UINT8 adminpassmd5[16]; -extern boolean adminpasswordset; +extern UINT8 (*adminpassmd5)[16]; +extern UINT32 adminpasscount; extern boolean hu_stopped; diff --git a/src/d_netcmd.c b/src/d_netcmd.c index 3dc402cb1..a2ec45c42 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -216,6 +216,7 @@ static void Command_Clearscores_f(void); // Remote Administration static void Command_Changepassword_f(void); +static void Command_Clearpassword_f(void); static void Command_Login_f(void); static void Got_Verification(UINT8 **cp, INT32 playernum); static void Got_Removal(UINT8 **cp, INT32 playernum); @@ -806,6 +807,7 @@ void D_RegisterServerCommands(void) // Remote Administration COM_AddCommand("password", Command_Changepassword_f); + COM_AddCommand("clearpassword", Command_Clearpassword_f); COM_AddCommand("login", Command_Login_f); // useful in dedicated to kick off remote admin COM_AddCommand("promote", Command_Verify_f); RegisterNetXCmd(XD_VERIFIED, Got_Verification); @@ -4065,8 +4067,15 @@ static void Got_Teamchange(UINT8 **cp, INT32 playernum) void D_SetPassword(const char *pw) { - D_MD5PasswordPass((const UINT8 *)pw, strlen(pw), BASESALT, &adminpassmd5); - adminpasswordset = true; + adminpassmd5 = Z_Realloc(adminpassmd5, sizeof(*adminpassmd5) * ++adminpasscount, PU_STATIC, NULL); + D_MD5PasswordPass((const UINT8 *)pw, strlen(pw), BASESALT, &adminpassmd5[adminpasscount-1]); +} + +void D_ClearPassword(void) +{ + Z_Free(adminpassmd5); + adminpassmd5 = NULL; + adminpasscount = 0; } // Remote Administration @@ -4084,12 +4093,31 @@ static void Command_Changepassword_f(void) if (COM_Argc() != 2) { - CONS_Printf(M_GetText("password : change remote admin password\n")); + CONS_Printf(M_GetText("password : add remote admin password\n")); return; } D_SetPassword(COM_Argv(1)); - CONS_Printf(M_GetText("Password set.\n")); + CONS_Printf(M_GetText("Password added.\n")); +#endif +} + + +// Remote Administration +static void Command_Clearpassword_f(void) +{ +#ifdef NOMD5 + // If we have no MD5 support then completely disable XD_LOGIN responses for security. + CONS_Alert(CONS_NOTICE, "Remote administration commands are not supported in this build.\n"); +#else + if (client) // cannot change remotely + { + CONS_Printf(M_GetText("Only the server can use this.\n")); + return; + } + + D_ClearPassword(); + CONS_Printf(M_GetText("Passwords cleared.\n")); #endif } diff --git a/src/d_netcmd.h b/src/d_netcmd.h index f68586a1a..f960b0c8e 100644 --- a/src/d_netcmd.h +++ b/src/d_netcmd.h @@ -348,6 +348,7 @@ void ClearAdminPlayers(void); void RemoveAdminPlayer(INT32 playernum); void ItemFinder_OnChange(void); void D_SetPassword(const char *pw); +void D_ClearPassword(void); void P_SetPlayerSpectator(INT32 playernum); From bc82e2564c031aa5d87dc2d0383bb941a35abc0d Mon Sep 17 00:00:00 2001 From: NepDisk Date: Sat, 23 Aug 2025 20:42:10 -0400 Subject: [PATCH 2/6] Multipassword and salts SRB2Classic ports by Hanicef --- src/d_clisrv.c | 136 ++++++++++++++++++++++++++++++++----------- src/d_clisrv.h | 6 +- src/d_netcmd.c | 23 ++++---- src/i_system.h | 4 ++ src/sdl/i_system.cpp | 32 ++++++++++ 5 files changed, 156 insertions(+), 45 deletions(-) diff --git a/src/d_clisrv.c b/src/d_clisrv.c index 1ac529422..1bbf83cc5 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -143,8 +143,11 @@ UINT8 hu_redownloadinggamestate = 0; // kart, true when a player is connecting or disconnecting so that the gameplay has stopped in its tracks boolean hu_stopped = false; -UINT8 (*adminpassmd5)[16]; +char *reqpass; +char **adminpass; UINT32 adminpasscount = 0; +char adminsalt[MAXPLAYERS][9]; +//I_StaticAssert(sizeof(netbuffer->u.salt) == sizeof(adminsalt[0])); // Client specific static ticcmd_t localcmds[MAXSPLITSCREENPLAYERS][MAXGENTLEMENDELAY]; @@ -4276,6 +4279,97 @@ static void HandleShutdown(SINT8 node) M_StartMessage(M_GetText("Server has shutdown\n\nPress Esc\n"), NULL, MM_NOTHING); } +static void PT_Login(SINT8 node) +{ + doomdata_t *netbuffer = DOOMCOM_DATA(doomcom); + + if (client) + return; + +#ifndef NOMD5 + // I_GetRandomBytes should get it's data from a CSPRNG, so it's safe to use it here. + I_GetRandomBytes(adminsalt[node], sizeof(adminsalt[node])); + adminsalt[node][8] = '\0'; // convenience + netbuffer->packettype = PT_LOGINCHALLENGE; + memcpy(netbuffer->u.salt, adminsalt[node], sizeof(adminsalt[node])); + HSendPacket(node, true, 0, sizeof(adminsalt[node])); +#else + (void)node; +#endif +} + +static void PT_LoginChallenge(SINT8 node) +{ + doomdata_t *netbuffer = DOOMCOM_DATA(doomcom); + +#ifndef NOMD5 + if (node != servernode) + return; + + if ((size_t)doomcom->datalength < sizeof(netbuffer->u.salt))/* ignore partial sends */ + return; + + if (reqpass == NULL) + return; // got PT_LOGINCHALLENGE but we didn't request a login + + D_MD5PasswordPass((const UINT8 *)reqpass, strlen(reqpass), netbuffer->u.salt, &netbuffer->u.md5sum); + Z_Free(reqpass); + reqpass = NULL; + + netbuffer->packettype = PT_LOGINAUTH; + HSendPacket(servernode, true, 0, 16); +#else + (void)node; +#endif +} + +static void PT_LoginAuth(SINT8 node, INT32 netconsole) +{ + doomdata_t *netbuffer = DOOMCOM_DATA(doomcom); +#ifndef NOMD5 + UINT8 finalmd5[16];/* Well, it's the cool thing to do? */ + UINT32 i; + if (client) + return; + + if (doomcom->datalength < 16)/* ignore partial sends */ + return; + + if (adminsalt[node][0] == 0) + { + CONS_Printf(M_GetText("Password from %s failed (no login request).\n"), player_names[netconsole]); + return; + } + if (adminpasscount == 0) + { + adminsalt[node][0] = 0; + CONS_Printf(M_GetText("Password from %s failed (no password set).\n"), player_names[netconsole]); + return; + } + + for (i = 0; i < adminpasscount; i++) + { + // Do the final pass to compare with the sent md5 + D_MD5PasswordPass((const UINT8 *)adminpass[i], strlen(adminpass[i]), adminsalt[node], finalmd5); + + if (!memcmp(netbuffer->u.md5sum, finalmd5, 16)) + { + adminsalt[node][0] = 0; + CONS_Printf(M_GetText("%s passed authentication.\n"), player_names[netconsole]); + COM_BufInsertText(va("promote %d\n", netconsole)); // do this immediately + return; + } + } + + adminsalt[node][0] = 0; + CONS_Printf(M_GetText("Password from %s failed.\n"), player_names[netconsole]); +#else + (void)node; + (void)netconsole; +#endif +} + + /** Called when a PT_NODETIMEOUT packet is received * * \param node The packet sender (should be the server) @@ -4629,10 +4723,6 @@ static void HandlePacketFromPlayer(SINT8 node) INT32 netconsole; tic_t realend, realstart; UINT8 *pak, *txtpak, numtxtpak; - UINT32 i; -#ifndef NOMD5 - UINT8 finalmd5[16];/* Well, it's the cool thing to do? */ -#endif txtpak = NULL; @@ -4868,34 +4958,10 @@ static void HandlePacketFromPlayer(SINT8 node) } break; case PT_LOGIN: - if (client) - break; - -#ifndef NOMD5 - if (doomcom->datalength < 16)/* ignore partial sends */ - break; - - if (adminpasscount == 0) - { - CONS_Printf(M_GetText("Password from %s failed (no password set).\n"), player_names[netconsole]); - break; - } - - for (i = 0; i < adminpasscount; i++) - { - // Do the final pass to compare with the sent md5 - D_MD5PasswordPass(adminpassmd5[i], 16, va("PNUM%02d", netconsole), &finalmd5); - - if (!memcmp(netbuffer->u.md5sum, finalmd5, 16)) - { - CONS_Printf(M_GetText("%s passed authentication.\n"), player_names[netconsole]); - COM_BufInsertText(va("promote %d\n", netconsole)); // do this immediately - continue; - } - } - - CONS_Printf(M_GetText("Password from %s failed.\n"), player_names[netconsole]); -#endif + PT_Login(node); + break; + case PT_LOGINAUTH: + PT_LoginAuth(node, netconsole); break; case PT_NODETIMEOUT: case PT_CLIENTQUIT: @@ -5071,6 +5137,9 @@ static void HandlePacketFromPlayer(SINT8 node) if (server) PT_FileReceived(); break; + case PT_LOGINCHALLENGE: + PT_LoginChallenge(node); + break; case PT_WILLRESENDGAMESTATE: PT_WillResendGamestate(); break; @@ -6236,6 +6305,7 @@ rewind_t *CL_RewindToTime(tic_t time) void D_MD5PasswordPass(const UINT8 *buffer, size_t len, const char *salt, void *dest) { + // FIXME: replace with SHA-256, since MD5 is busted. #ifdef NOMD5 (void)buffer; (void)len; diff --git a/src/d_clisrv.h b/src/d_clisrv.h index 26b233d53..6335dbfdb 100644 --- a/src/d_clisrv.h +++ b/src/d_clisrv.h @@ -117,6 +117,8 @@ typedef enum PT_MOREFILESNEEDED, // Server, to client: "you need these (+ more on top of those)" PT_LOGIN, // Login attempt from the client. + PT_LOGINCHALLENGE,// Challenge request sent to the client. + PT_LOGINAUTH, // Challenge response from the client. PT_PING, // Packet sent to tell clients the other client's latency to server. NUMPACKETTYPE @@ -374,6 +376,7 @@ struct doomdata_t char fileack[sizeof (fileack_pak)]; UINT8 filereceived; clientconfig_pak clientcfg; // 136 bytes + char salt[9]; UINT8 md5sum[16]; serverinfo_pak serverinfo; // 1024 bytes serverrefuse_pak serverrefuse; // 65025 bytes (somehow I feel like those values are garbage...) @@ -588,7 +591,8 @@ void D_MD5PasswordPass(const UINT8 *buffer, size_t len, const char *salt, void * extern UINT8 hu_redownloadinggamestate; -extern UINT8 (*adminpassmd5)[16]; +extern char *reqpass; +extern char **adminpass; extern UINT32 adminpasscount; extern boolean hu_stopped; diff --git a/src/d_netcmd.c b/src/d_netcmd.c index a2ec45c42..4330bedff 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -4067,14 +4067,17 @@ static void Got_Teamchange(UINT8 **cp, INT32 playernum) void D_SetPassword(const char *pw) { - adminpassmd5 = Z_Realloc(adminpassmd5, sizeof(*adminpassmd5) * ++adminpasscount, PU_STATIC, NULL); - D_MD5PasswordPass((const UINT8 *)pw, strlen(pw), BASESALT, &adminpassmd5[adminpasscount-1]); + adminpass = Z_Realloc(adminpass, sizeof(*adminpass) * ++adminpasscount, PU_STATIC, NULL); + adminpass[adminpasscount-1] = Z_StrDup(pw); } void D_ClearPassword(void) { - Z_Free(adminpassmd5); - adminpassmd5 = NULL; + UINT32 i; + for (i = 0; i < adminpasscount; i++) + Z_Free(adminpass[i]); + Z_Free(adminpass); + adminpass = NULL; adminpasscount = 0; } @@ -4144,18 +4147,16 @@ static void Command_Login_f(void) return; } + if (reqpass) + Z_Free(reqpass); + pw = COM_Argv(1); - - // Do the base pass to get what the server has (or should?) - D_MD5PasswordPass((const UINT8 *)pw, strlen(pw), BASESALT, &netbuffer->u.md5sum); - - // Do the final pass to get the comparison the server will come up with - D_MD5PasswordPass(netbuffer->u.md5sum, 16, va("PNUM%02d", consoleplayer), &netbuffer->u.md5sum); + reqpass = Z_StrDup(pw); CONS_Printf(M_GetText("Sending login... (Notice only given if password is correct.)\n")); netbuffer->packettype = PT_LOGIN; - HSendPacket(servernode, true, 0, 16); + HSendPacket(servernode, true, 0, 0); #endif } diff --git a/src/i_system.h b/src/i_system.h index aaf37fb9a..48fef0f74 100644 --- a/src/i_system.h +++ b/src/i_system.h @@ -52,6 +52,10 @@ UINT32 I_GetFreeMem(UINT32 *total); */ precise_t I_GetPreciseTime(void); +/** \brief Fills a buffer with random data, returns amount of data obtained. + */ +size_t I_GetRandomBytes(char *destination, size_t count); + /** \brief Get the precision of precise_t in units per second. Invocations of this function for the program's duration MUST return the same value. */ diff --git a/src/sdl/i_system.cpp b/src/sdl/i_system.cpp index eef9d3f5d..14b3148c0 100644 --- a/src/sdl/i_system.cpp +++ b/src/sdl/i_system.cpp @@ -2317,6 +2317,38 @@ char *I_GetEnv(const char *name) #endif } +size_t I_GetRandomBytes(char *destination, size_t count) +{ +#if defined (__unix__) || defined (UNIXCOMMON) || defined(__APPLE__) + FILE *rndsource; + size_t actual_bytes = 0; + + if (!(rndsource = fopen("/dev/urandom", "r"))) + if (!(rndsource = fopen("/dev/random", "r"))) + actual_bytes = 0; + + if (rndsource) + { + actual_bytes = fread(destination, 1, count, rndsource); + fclose(rndsource); + } + + if (actual_bytes == 0) + I_OutputMsg("I_GetRandomBytes(): couldn't get any random bytes"); + + return actual_bytes; +#elif defined (_WIN32) + if (RtlGenRandom(destination, count)) + return count; + + I_OutputMsg("I_GetRandomBytes(): couldn't get any random bytes"); + return 0; +#else + #warning SDL I_GetRandomBytes is not implemented on this platform. + return 0; +#endif +} + INT32 I_PutEnv(char *variable) { #ifdef NEED_SDL_GETENV From 2ba06e7d83a3f5629038a47dd7e0be773ab4298d Mon Sep 17 00:00:00 2001 From: NepDisk Date: Sat, 23 Aug 2025 20:56:07 -0400 Subject: [PATCH 3/6] Switch to SHA256 for authentication SRB2Classic Port by Hanicef --- src/CMakeLists.txt | 2 +- src/Makefile | 1 - src/Makefile.d/features.mk | 6 +- src/Sourcefile | 1 + src/d_clisrv.c | 55 ++--- src/d_clisrv.h | 6 +- src/d_netcmd.c | 16 +- src/doomdef.h | 1 - src/lonesha256.c | 2 + src/lonesha256.h | 143 +++++++++++++ src/md5.c | 403 ------------------------------------- src/md5.h | 139 ------------- 12 files changed, 171 insertions(+), 604 deletions(-) create mode 100644 src/lonesha256.c create mode 100644 src/lonesha256.h delete mode 100644 src/md5.c delete mode 100644 src/md5.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index b7b6aa774..d94b56560 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -24,7 +24,7 @@ set_property(TARGET SRB2SDL2 PROPERTY CXX_STANDARD 17) # Core sources target_sourcefile(c) -target_sources(SRB2SDL2 PRIVATE comptime.c md5.c config.h.in) +target_sources(SRB2SDL2 PRIVATE comptime.c config.h.in) ### Configuration set(SRB2_CONFIG_DEV_BUILD OFF CACHE BOOL diff --git a/src/Makefile b/src/Makefile index dd309ba41..1dd50f2ca 100644 --- a/src/Makefile +++ b/src/Makefile @@ -62,7 +62,6 @@ # # Netplay incompatible # -------------------- -# NOMD5=1 - Disable MD5 checksum (validation tool). # NOPOSTPROCESSING=1 - ? # MOBJCONSISTANCY=1 - ?? # PACKETDROP=1 - ?? diff --git a/src/Makefile.d/features.mk b/src/Makefile.d/features.mk index 6b26ebe53..3326a39ff 100644 --- a/src/Makefile.d/features.mk +++ b/src/Makefile.d/features.mk @@ -3,7 +3,7 @@ # passthru_opts+=\ - NO_IPV6 NOHW NOMD5 NOPOSTPROCESSING\ + NO_IPV6 NOHW NOPOSTPROCESSING\ MOBJCONSISTANCY PACKETDROP ZDEBUG\ HAVE_MINIUPNPC\ HAVE_DISCORDRPC DEVELOP @@ -20,10 +20,6 @@ opts+=-DHWRENDER sources+=$(call List,hardware/Sourcefile) endif -ifndef NOMD5 -sources+=md5.c -endif - ifndef NOZLIB ifndef NOPNG ifdef PNG_PKGCONFIG diff --git a/src/Sourcefile b/src/Sourcefile index 581140c50..e13a8a47f 100644 --- a/src/Sourcefile +++ b/src/Sourcefile @@ -137,3 +137,4 @@ k_mapuser.c k_stats.c h_timers.cpp stun.c +lonesha256.c diff --git a/src/d_clisrv.c b/src/d_clisrv.c index 1bbf83cc5..e42838e1b 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -45,7 +45,7 @@ #include "lzf.h" #include "lua_script.h" #include "lua_hook.h" -#include "md5.h" +#include "lonesha256.h" #include "m_perfstats.h" // SRB2Kart @@ -146,7 +146,7 @@ boolean hu_stopped = false; char *reqpass; char **adminpass; UINT32 adminpasscount = 0; -char adminsalt[MAXPLAYERS][9]; +static char adminsalt[MAXNETNODES][9]; //I_StaticAssert(sizeof(netbuffer->u.salt) == sizeof(adminsalt[0])); // Client specific @@ -4286,23 +4286,22 @@ static void PT_Login(SINT8 node) if (client) return; -#ifndef NOMD5 + I_Assert((UINT8)node < sizeof(adminsalt) / sizeof(adminsalt[0])); + // I_GetRandomBytes should get it's data from a CSPRNG, so it's safe to use it here. I_GetRandomBytes(adminsalt[node], sizeof(adminsalt[node])); adminsalt[node][8] = '\0'; // convenience netbuffer->packettype = PT_LOGINCHALLENGE; memcpy(netbuffer->u.salt, adminsalt[node], sizeof(adminsalt[node])); HSendPacket(node, true, 0, sizeof(adminsalt[node])); -#else - (void)node; -#endif } static void PT_LoginChallenge(SINT8 node) { + char salt[9]; + //I_StaticAssert(sizeof(salt) == sizeof(netbuffer->u.salt)); doomdata_t *netbuffer = DOOMCOM_DATA(doomcom); -#ifndef NOMD5 if (node != servernode) return; @@ -4312,27 +4311,24 @@ static void PT_LoginChallenge(SINT8 node) if (reqpass == NULL) return; // got PT_LOGINCHALLENGE but we didn't request a login - D_MD5PasswordPass((const UINT8 *)reqpass, strlen(reqpass), netbuffer->u.salt, &netbuffer->u.md5sum); + memcpy(salt, netbuffer->u.salt, sizeof(netbuffer->u.salt)); + D_SHA256PasswordPass((const UINT8 *)reqpass, strlen(reqpass), salt, netbuffer->u.sha256sum); Z_Free(reqpass); reqpass = NULL; netbuffer->packettype = PT_LOGINAUTH; - HSendPacket(servernode, true, 0, 16); -#else - (void)node; -#endif + HSendPacket(servernode, true, 0, sizeof(netbuffer->u.sha256sum)); } static void PT_LoginAuth(SINT8 node, INT32 netconsole) { doomdata_t *netbuffer = DOOMCOM_DATA(doomcom); -#ifndef NOMD5 - UINT8 finalmd5[16];/* Well, it's the cool thing to do? */ + UINT8 finalsha256[32];/* Well, it's the cool thing to do? */ UINT32 i; if (client) return; - if (doomcom->datalength < 16)/* ignore partial sends */ + if (doomcom->datalength < sizeof(netbuffer->u.sha256sum))/* ignore partial sends */ return; if (adminsalt[node][0] == 0) @@ -4350,9 +4346,9 @@ static void PT_LoginAuth(SINT8 node, INT32 netconsole) for (i = 0; i < adminpasscount; i++) { // Do the final pass to compare with the sent md5 - D_MD5PasswordPass((const UINT8 *)adminpass[i], strlen(adminpass[i]), adminsalt[node], finalmd5); + D_SHA256PasswordPass((const UINT8 *)adminpass[i], strlen(adminpass[i]), adminsalt[node], finalsha256); - if (!memcmp(netbuffer->u.md5sum, finalmd5, 16)) + if (!memcmp(netbuffer->u.sha256sum, finalsha256, 32)) { adminsalt[node][0] = 0; CONS_Printf(M_GetText("%s passed authentication.\n"), player_names[netconsole]); @@ -4363,10 +4359,6 @@ static void PT_LoginAuth(SINT8 node, INT32 netconsole) adminsalt[node][0] = 0; CONS_Printf(M_GetText("Password from %s failed.\n"), player_names[netconsole]); -#else - (void)node; - (void)netconsole; -#endif } @@ -6303,29 +6295,18 @@ rewind_t *CL_RewindToTime(tic_t time) return rewindhead; } -void D_MD5PasswordPass(const UINT8 *buffer, size_t len, const char *salt, void *dest) +void D_SHA256PasswordPass(const UINT8 *buffer, size_t len, const char *salt, UINT8 dest[static 32]) { - // FIXME: replace with SHA-256, since MD5 is busted. -#ifdef NOMD5 - (void)buffer; - (void)len; - (void)salt; - memset(dest, 0, 16); -#else - char tmpbuf[256]; + UINT8 *tmpbuf; const size_t sl = strlen(salt); if (len > 256-sl) len = 256-sl; + tmpbuf = Z_Malloc(sizeof(char) * (sl + len), PU_STATIC, NULL); memcpy(tmpbuf, buffer, len); memmove(&tmpbuf[len], salt, sl); - //strcpy(&tmpbuf[len], salt); - len += strlen(salt); - if (len < 256) - memset(&tmpbuf[len],0,256-len); - // Yes, we intentionally md5 the ENTIRE buffer regardless of size... - md5_buffer(tmpbuf, 256, dest); -#endif + lonesha256(dest, tmpbuf, len+sl); + Z_Free(tmpbuf); } diff --git a/src/d_clisrv.h b/src/d_clisrv.h index 6335dbfdb..ae0e71a91 100644 --- a/src/d_clisrv.h +++ b/src/d_clisrv.h @@ -377,7 +377,7 @@ struct doomdata_t UINT8 filereceived; clientconfig_pak clientcfg; // 136 bytes char salt[9]; - UINT8 md5sum[16]; + UINT8 sha256sum[32]; serverinfo_pak serverinfo; // 1024 bytes serverrefuse_pak serverrefuse; // 65025 bytes (somehow I feel like those values are garbage...) askinfo_pak askinfo; // 61 bytes @@ -587,7 +587,9 @@ ticcmd_t *D_LocalTiccmd(UINT8 ss); tic_t GetLag(INT32 node); UINT8 GetFreeXCmdSize(UINT8 playerid); -void D_MD5PasswordPass(const UINT8 *buffer, size_t len, const char *salt, void *dest); +#ifndef __cplusplus +void D_SHA256PasswordPass(const UINT8 *buffer, size_t len, const char *salt, UINT8 dest[static 32]); +#endif extern UINT8 hu_redownloadinggamestate; diff --git a/src/d_netcmd.c b/src/d_netcmd.c index 4330bedff..c3f939e38 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -4084,10 +4084,6 @@ void D_ClearPassword(void) // Remote Administration static void Command_Changepassword_f(void) { -#ifdef NOMD5 - // If we have no MD5 support then completely disable XD_LOGIN responses for security. - CONS_Alert(CONS_NOTICE, "Remote administration commands are not supported in this build.\n"); -#else if (client) // cannot change remotely { CONS_Printf(M_GetText("Only the server can use this.\n")); @@ -4102,17 +4098,12 @@ static void Command_Changepassword_f(void) D_SetPassword(COM_Argv(1)); CONS_Printf(M_GetText("Password added.\n")); -#endif } // Remote Administration static void Command_Clearpassword_f(void) { -#ifdef NOMD5 - // If we have no MD5 support then completely disable XD_LOGIN responses for security. - CONS_Alert(CONS_NOTICE, "Remote administration commands are not supported in this build.\n"); -#else if (client) // cannot change remotely { CONS_Printf(M_GetText("Only the server can use this.\n")); @@ -4121,16 +4112,12 @@ static void Command_Clearpassword_f(void) D_ClearPassword(); CONS_Printf(M_GetText("Passwords cleared.\n")); -#endif } static void Command_Login_f(void) { doomdata_t *netbuffer = DOOMCOM_DATA(doomcom); -#ifdef NOMD5 - // If we have no MD5 support then completely disable XD_LOGIN responses for security. - CONS_Alert(CONS_NOTICE, "Remote administration commands are not supported in this build.\n"); -#else + const char *pw; if (!netgame) @@ -4157,7 +4144,6 @@ static void Command_Login_f(void) netbuffer->packettype = PT_LOGIN; HSendPacket(servernode, true, 0, 0); -#endif } boolean IsPlayerAdmin(INT32 playernum) diff --git a/src/doomdef.h b/src/doomdef.h index 001d61bd3..765f69fcc 100644 --- a/src/doomdef.h +++ b/src/doomdef.h @@ -102,7 +102,6 @@ extern "C" { #endif // Special Hashing. -//#define NOMD5 //#define NOFILEHASH //#define NOVERIFYIWADS diff --git a/src/lonesha256.c b/src/lonesha256.c new file mode 100644 index 000000000..aac023e26 --- /dev/null +++ b/src/lonesha256.c @@ -0,0 +1,2 @@ +#define LONESHA256_IMPLEMENTATION +#include "lonesha256.h" diff --git a/src/lonesha256.h b/src/lonesha256.h new file mode 100644 index 000000000..2eea32672 --- /dev/null +++ b/src/lonesha256.h @@ -0,0 +1,143 @@ +/* +lonesha256.h - Portable, endian-proof, single-file, single-function sha256 implementation, originally based on LibTomCrypt + +To the extent possible under law, the author(s) have dedicated all copyright and related and neighboring +rights to this software to the public domain worldwide. This software is distributed without any warranty. +You should have received a copy of the CC0 Public Domain Dedication along with this software. +If not, see . +*/ + +/* +lonesha256 supports the following three configurations: +#define LONESHA256_EXTERN + Default, should be used when using lonesha256 in multiple compilation units within the same project. +#define LONESHA256_IMPLEMENTATION + Must be defined in exactly one source file within a project for lonesha256 to be found by the linker. +#define LONESHA256_STATIC + Defines the lonesha256() function as static, useful if lonesha256 is only used in a single compilation unit. + +lonesha256 function: +(static|extern) int lonesha256 (unsigned char out[32], const unsigned char* in, size_t len) + writes the sha256 hash of the first "len" bytes in buffer "in" to buffer "out" + returns 0 on success, may return non-zero in future versions to indicate error +*/ + +//header section +#ifndef LONESHA256_H +#define LONESHA256_H + +//process configuration +#ifdef LONESHA256_STATIC + #define LONESHA256_IMPLEMENTATION + #define LSHA256DEF static +#else //LONESHA256_EXTERN + #define LSHA256DEF extern +#endif + +//includes +#include //size_t + +//lonesha256 declaration +LSHA256DEF int lonesha256(unsigned char[32], const unsigned char*, size_t); + +#endif //LONESHA256_H + +//implementation section +#ifdef LONESHA256_IMPLEMENTATION +#undef LONESHA256_IMPLEMENTATION + +//macros +#define S(x, n) (((((uint32_t)(x)&0xFFFFFFFFUL)>>(uint32_t)((n)&31))|((uint32_t)(x)<<(uint32_t)((32-((n)&31))&31)))&0xFFFFFFFFUL) +#define R(x, n) (((x)&0xFFFFFFFFUL)>>(n)) +#define Gamma0(x) (S(x, 7) ^ S(x, 18) ^ R(x, 3)) +#define Gamma1(x) (S(x, 17) ^ S(x, 19) ^ R(x, 10)) +#define RND(a,b,c,d,e,f,g,h,i) \ + t0 = h + (S(e, 6) ^ S(e, 11) ^ S(e, 25)) + (g ^ (e & (f ^ g))) + K[i] + W[i]; \ + t1 = (S(a, 2) ^ S(a, 13) ^ S(a, 22)) + (((a | b) & c) | (a & b)); \ + d += t0; \ + h = t0 + t1; +#define STORE32H(x, y) \ + (y)[0] = (unsigned char)(((x)>>24)&255); (y)[1] = (unsigned char)(((x)>>16)&255); \ + (y)[2] = (unsigned char)(((x)>>8)&255); (y)[3] = (unsigned char)((x)&255); +#define LOAD32H(x, y) \ + x = ((uint32_t)((y)[0]&255)<<24)|((uint32_t)((y)[1]&255)<<16)|((uint32_t)((y)[2]&255)<<8)|((uint32_t)((y)[3]&255)); +#define STORE64H(x, y) \ + (y)[0] = (unsigned char)(((x)>>56)&255); (y)[1] = (unsigned char)(((x)>>48)&255); \ + (y)[2] = (unsigned char)(((x)>>40)&255); (y)[3] = (unsigned char)(((x)>>32)&255); \ + (y)[4] = (unsigned char)(((x)>>24)&255); (y)[5] = (unsigned char)(((x)>>16)&255); \ + (y)[6] = (unsigned char)(((x)>>8)&255); (y)[7] = (unsigned char)((x)&255); +#define SHA256_COMPRESS(buff) \ + for (int i = 0; i < 8; i++) S[i] = sha256_state[i]; \ + for (int i = 0; i < 16; i++) LOAD32H(W[i], buff + (4*i)); \ + for (int i = 16; i < 64; i++) W[i] = Gamma1(W[i-2]) + W[i-7] + Gamma0(W[i-15]) + W[i-16]; \ + for (int i = 0; i < 64; i++) { \ + RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],i); \ + t = S[7]; S[7] = S[6]; S[6] = S[5]; S[5] = S[4]; \ + S[4] = S[3]; S[3] = S[2]; S[2] = S[1]; S[1] = S[0]; S[0] = t; \ + } \ + for (int i = 0; i < 8; i++) sha256_state[i] = sha256_state[i] + S[i]; + +//includes +#include //uint32_t, uint64_t +#include //memcpy + +//lonesha256 function +LSHA256DEF int lonesha256 (unsigned char out[32], const unsigned char* in, size_t len) { + //writes the sha256 hash of the first "len" bytes in buffer "in" to buffer "out" + //returns 0 on success, may return non-zero in future versions to indicate error + const uint32_t K[64] = { + 0x428a2f98UL, 0x71374491UL, 0xb5c0fbcfUL, 0xe9b5dba5UL, + 0x3956c25bUL, 0x59f111f1UL, 0x923f82a4UL, 0xab1c5ed5UL, + 0xd807aa98UL, 0x12835b01UL, 0x243185beUL, 0x550c7dc3UL, + 0x72be5d74UL, 0x80deb1feUL, 0x9bdc06a7UL, 0xc19bf174UL, + 0xe49b69c1UL, 0xefbe4786UL, 0x0fc19dc6UL, 0x240ca1ccUL, + 0x2de92c6fUL, 0x4a7484aaUL, 0x5cb0a9dcUL, 0x76f988daUL, + 0x983e5152UL, 0xa831c66dUL, 0xb00327c8UL, 0xbf597fc7UL, + 0xc6e00bf3UL, 0xd5a79147UL, 0x06ca6351UL, 0x14292967UL, + 0x27b70a85UL, 0x2e1b2138UL, 0x4d2c6dfcUL, 0x53380d13UL, + 0x650a7354UL, 0x766a0abbUL, 0x81c2c92eUL, 0x92722c85UL, + 0xa2bfe8a1UL, 0xa81a664bUL, 0xc24b8b70UL, 0xc76c51a3UL, + 0xd192e819UL, 0xd6990624UL, 0xf40e3585UL, 0x106aa070UL, + 0x19a4c116UL, 0x1e376c08UL, 0x2748774cUL, 0x34b0bcb5UL, + 0x391c0cb3UL, 0x4ed8aa4aUL, 0x5b9cca4fUL, 0x682e6ff3UL, + 0x748f82eeUL, 0x78a5636fUL, 0x84c87814UL, 0x8cc70208UL, + 0x90befffaUL, 0xa4506cebUL, 0xbef9a3f7UL, 0xc67178f2UL + }; + uint64_t sha256_length = 0; + uint32_t sha256_state[8] = { + 0x6A09E667UL, 0xBB67AE85UL, 0x3C6EF372UL, 0xA54FF53AUL, + 0x510E527FUL, 0x9B05688CUL, 0x1F83D9ABUL, 0x5BE0CD19UL + }, S[8], W[64], t0, t1, t; + unsigned char sha256_buf[64]; + //process input in 64 byte chunks + while (len >= 64) { + SHA256_COMPRESS(in); + sha256_length += 64 * 8; + in += 64; + len -= 64; + } + //copy remaining bytes into sha256_buf + memcpy(sha256_buf, in, len); + //finish up (len now number of bytes in sha256_buf) + sha256_length += len * 8; + sha256_buf[len++] = 0x80; + //pad then compress if length is above 56 bytes + if (len > 56) { + while (len < 64) sha256_buf[len++] = 0; + SHA256_COMPRESS(sha256_buf); + len = 0; + } + //pad up to 56 bytes + while (len < 56) sha256_buf[len++] = 0; + //store length and compress + STORE64H(sha256_length, sha256_buf + 56); + SHA256_COMPRESS(sha256_buf); + //copy output + for (int i = 0; i < 8; i++) { + STORE32H(sha256_state[i], out + 4*i); + } + //return + return 0; +} + +#endif //LONESHA256_IMPLEMENTATION diff --git a/src/md5.c b/src/md5.c deleted file mode 100644 index d1c3a16b3..000000000 --- a/src/md5.c +++ /dev/null @@ -1,403 +0,0 @@ -// BLANKART -//----------------------------------------------------------------------------- -// Copyright (C) 1995-1996 by the Free Software Foundation, Inc. -// -// This program is free software distributed under the -// terms of the GNU General Public License, version 2. -// See the 'LICENSE' file for more details. -//----------------------------------------------------------------------------- -/// \file md5.c -/// \brief Functions to compute MD5 message digest of files or memory blocks -/// according to the definition of MD5 in RFC 1321 from April 1992. - -/* NOTE: The canonical source of this file is maintained with the GNU C - Library. Bugs can be reported to bug-glibc@prep.ai.mit.edu. */ -/* Written by Ulrich Drepper , 1995. */ - -#ifdef HAVE_CONFIG_H - #include -#endif - -#include -#include -#ifdef _MSC_VER -#pragma warning(disable : 4127) -#endif - -#if defined (STDC_HEADERS) || defined (_LIBC) - #include -#else - #ifndef HAVE_MEMCPY - #if !(defined (_WIN32) && !defined (__CYGWIN__)) && !defined (__APPLE__) - #define memcpy(d, s, n) bcopy ((s), (d), (n)) - #endif - #endif -#endif - -#include "md5.h" - -#include "endian.h" - -#if defined (SRB2_BIG_ENDIAN) - #define SWAP(n) \ - (((n) << 24) | (((n) & 0xff00) << 8) | (((n) >> 8) & 0xff00) | ((n) >> 24)) -#else - #define SWAP(n) (n) -#endif - -/* This array contains the bytes used to pad the buffer to the next - 64-byte boundary. (RFC 1321, 3.1: Step 1) */ -static const unsigned char fillbuf[64] = { 0x80, 0 /*, 0, 0, ... */ }; - -/* Structure to save state of computation between the single steps. */ -struct md5_ctx -{ - md5_uint32 A; - md5_uint32 B; - md5_uint32 C; - md5_uint32 D; - - md5_uint32 total[2]; - md5_uint32 buflen; - char buffer[128]; -}; - -/* Initialize structure containing state of computation. - (RFC 1321, 3.3: Step 3) */ -static void md5_init_ctx (struct md5_ctx *ctx) -{ - ctx->A = 0x67452301; - ctx->B = 0xefcdab89; - ctx->C = 0x98badcfe; - ctx->D = 0x10325476; - - ctx->total[0] = ctx->total[1] = 0; - ctx->buflen = 0; -} - -/* Put result from CTX in first 16 bytes following RESBUF. The result - must be in little endian byte order. - - IMPORTANT: On some systems it is required that RESBUF is correctly - aligned for a 32 bits value. */ -static void *md5_read_ctx (const struct md5_ctx *ctx, void *resbuf) -{ - ((md5_uint32 *) resbuf)[0] = SWAP (ctx->A); - ((md5_uint32 *) resbuf)[1] = SWAP (ctx->B); - ((md5_uint32 *) resbuf)[2] = SWAP (ctx->C); - ((md5_uint32 *) resbuf)[3] = SWAP (ctx->D); - - return resbuf; -} - -/* These are the four functions used in the four steps of the MD5 algorithm - and defined in the RFC 1321. The first function is a little bit optimized - (as found in Colin Plumbs public domain implementation). */ -/* #define FF(b, c, d) ((b & c) | (~b & d)) */ -#define FF(b, c, d) (d ^ (b & (c ^ d))) -#define FG(b, c, d) FF (d, b, c) -#define FH(b, c, d) (b ^ c ^ d) -#define FI(b, c, d) (c ^ (b | ~d)) - -/* Process LEN bytes of BUFFER, accumulating context into CTX. - It is assumed that LEN % 64 == 0. */ - -static void md5_process_block (const void *buffer, size_t len, struct md5_ctx *ctx) -{ - md5_uint32 correct_words[16]; - const md5_uint32 *words = buffer; - size_t nwords = len / sizeof (md5_uint32); - const md5_uint32 *endp = words + nwords; - md5_uint32 A = ctx->A; - md5_uint32 B = ctx->B; - md5_uint32 C = ctx->C; - md5_uint32 D = ctx->D; - - /* First increment the byte count. RFC 1321 specifies the possible - length of the file up to 2^64 bits. Here we only compute the - number of bytes. Do a double word increment. */ - ctx->total[0] = (md5_uint32)(len+ctx->total[0]); - if (ctx->total[0] < len) - ++ctx->total[1]; - - /* Process all bytes in the buffer with 64 bytes in each round of - the loop. */ - while (words < endp) - { - md5_uint32 *cwp = correct_words; - md5_uint32 A_save = A; - md5_uint32 B_save = B; - md5_uint32 C_save = C; - md5_uint32 D_save = D; - - /* First round: using the given function, the context and a constant - the next context is computed. Because the algorithms processing - unit is a 32-bit word and it is determined to work on words in - little endian byte order we perhaps have to change the byte order - before the computation. To reduce the work for the next steps - we store the swapped words in the array CORRECT_WORDS. */ - -#define OP(a, b, c, d, s, T) \ - do \ - { \ - a += FF (b, c, d) + (*cwp++ = SWAP (*words)) + T; \ - ++words; \ - CYCLIC (a, s); \ - a += b; \ - } \ - while (0) - - /* It is unfortunate that C does not provide an operator for - cyclic rotation. Hope the C compiler is smart enough. */ -#define CYCLIC(w, s) (w = (w << s) | (w >> (32 - s))) - - /* Before we start, one word to the strange constants. - They are defined in RFC 1321 as - - T[i] = (int) (4294967296.0 * fabs (sin (i))), i = 1..64 - */ - - /* Round 1. */ - OP (A, B, C, D, 7, 0xd76aa478); - OP (D, A, B, C, 12, 0xe8c7b756); - OP (C, D, A, B, 17, 0x242070db); - OP (B, C, D, A, 22, 0xc1bdceee); - OP (A, B, C, D, 7, 0xf57c0faf); - OP (D, A, B, C, 12, 0x4787c62a); - OP (C, D, A, B, 17, 0xa8304613); - OP (B, C, D, A, 22, 0xfd469501); - OP (A, B, C, D, 7, 0x698098d8); - OP (D, A, B, C, 12, 0x8b44f7af); - OP (C, D, A, B, 17, 0xffff5bb1); - OP (B, C, D, A, 22, 0x895cd7be); - OP (A, B, C, D, 7, 0x6b901122); - OP (D, A, B, C, 12, 0xfd987193); - OP (C, D, A, B, 17, 0xa679438e); - OP (B, C, D, A, 22, 0x49b40821); - - /* For the second to fourth round we have the possibly swapped words - in CORRECT_WORDS. Redefine the macro to take an additional first - argument specifying the function to use. */ -#undef OP -#define OP(f, a, b, c, d, k, s, T) \ - do \ - { \ - a += f (b, c, d) + correct_words[k] + T; \ - CYCLIC (a, s); \ - a += b; \ - } \ - while (0) - - /* Round 2. */ - OP (FG, A, B, C, D, 1, 5, 0xf61e2562); - OP (FG, D, A, B, C, 6, 9, 0xc040b340); - OP (FG, C, D, A, B, 11, 14, 0x265e5a51); - OP (FG, B, C, D, A, 0, 20, 0xe9b6c7aa); - OP (FG, A, B, C, D, 5, 5, 0xd62f105d); - OP (FG, D, A, B, C, 10, 9, 0x02441453); - OP (FG, C, D, A, B, 15, 14, 0xd8a1e681); - OP (FG, B, C, D, A, 4, 20, 0xe7d3fbc8); - OP (FG, A, B, C, D, 9, 5, 0x21e1cde6); - OP (FG, D, A, B, C, 14, 9, 0xc33707d6); - OP (FG, C, D, A, B, 3, 14, 0xf4d50d87); - OP (FG, B, C, D, A, 8, 20, 0x455a14ed); - OP (FG, A, B, C, D, 13, 5, 0xa9e3e905); - OP (FG, D, A, B, C, 2, 9, 0xfcefa3f8); - OP (FG, C, D, A, B, 7, 14, 0x676f02d9); - OP (FG, B, C, D, A, 12, 20, 0x8d2a4c8a); - - /* Round 3. */ - OP (FH, A, B, C, D, 5, 4, 0xfffa3942); - OP (FH, D, A, B, C, 8, 11, 0x8771f681); - OP (FH, C, D, A, B, 11, 16, 0x6d9d6122); - OP (FH, B, C, D, A, 14, 23, 0xfde5380c); - OP (FH, A, B, C, D, 1, 4, 0xa4beea44); - OP (FH, D, A, B, C, 4, 11, 0x4bdecfa9); - OP (FH, C, D, A, B, 7, 16, 0xf6bb4b60); - OP (FH, B, C, D, A, 10, 23, 0xbebfbc70); - OP (FH, A, B, C, D, 13, 4, 0x289b7ec6); - OP (FH, D, A, B, C, 0, 11, 0xeaa127fa); - OP (FH, C, D, A, B, 3, 16, 0xd4ef3085); - OP (FH, B, C, D, A, 6, 23, 0x04881d05); - OP (FH, A, B, C, D, 9, 4, 0xd9d4d039); - OP (FH, D, A, B, C, 12, 11, 0xe6db99e5); - OP (FH, C, D, A, B, 15, 16, 0x1fa27cf8); - OP (FH, B, C, D, A, 2, 23, 0xc4ac5665); - - /* Round 4. */ - OP (FI, A, B, C, D, 0, 6, 0xf4292244); - OP (FI, D, A, B, C, 7, 10, 0x432aff97); - OP (FI, C, D, A, B, 14, 15, 0xab9423a7); - OP (FI, B, C, D, A, 5, 21, 0xfc93a039); - OP (FI, A, B, C, D, 12, 6, 0x655b59c3); - OP (FI, D, A, B, C, 3, 10, 0x8f0ccc92); - OP (FI, C, D, A, B, 10, 15, 0xffeff47d); - OP (FI, B, C, D, A, 1, 21, 0x85845dd1); - OP (FI, A, B, C, D, 8, 6, 0x6fa87e4f); - OP (FI, D, A, B, C, 15, 10, 0xfe2ce6e0); - OP (FI, C, D, A, B, 6, 15, 0xa3014314); - OP (FI, B, C, D, A, 13, 21, 0x4e0811a1); - OP (FI, A, B, C, D, 4, 6, 0xf7537e82); - OP (FI, D, A, B, C, 11, 10, 0xbd3af235); - OP (FI, C, D, A, B, 2, 15, 0x2ad7d2bb); - OP (FI, B, C, D, A, 9, 21, 0xeb86d391); - - /* Add the starting values of the context. */ - A += A_save; - B += B_save; - C += C_save; - D += D_save; - } - - /* Put checksum in context given as argument. */ - ctx->A = A; - ctx->B = B; - ctx->C = C; - ctx->D = D; -} - - -static void md5_process_bytes (const void *buffer, size_t len, struct md5_ctx *ctx) -{ - /* When we already have some bits in our internal buffer concatenate - both inputs first. */ - if (ctx->buflen != 0) - { - size_t left_over = ctx->buflen; - size_t add = 128 - left_over > len ? len : 128 - left_over; - - memcpy (&ctx->buffer[left_over], buffer, add); - ctx->buflen = (md5_uint32)(add+ctx->buflen); - - if (left_over + add > 64) - { - md5_process_block (ctx->buffer, (left_over + add) & ~63, ctx); - /* The regions in the following copy operation cannot overlap. */ - memcpy (ctx->buffer, &ctx->buffer[(left_over + add) & ~63], - (left_over + add) & 63); - ctx->buflen = (md5_uint32)((left_over + add) & 63); - } - - buffer = (const char *) buffer + add; - len -= add; - } - - /* Process available complete blocks. */ - if (len > 64) - { - md5_process_block (buffer, len & ~63, ctx); - buffer = (const char *) buffer + (len & ~63); - len &= 63; - } - - /* Move remaining bytes in internal buffer. */ - if (len > 0) - { - memcpy (ctx->buffer, buffer, len); - ctx->buflen = (md5_uint32)len; - } -} - - -/* Process the remaining bytes in the internal buffer and the usual - prolog according to the standard and write the result to RESBUF. - - IMPORTANT: On some systems it is required that RESBUF is correctly - aligned for a 32 bits value. */ -static void *md5_finish_ctx (struct md5_ctx *ctx, void *resbuf) -{ - /* Take yet unprocessed bytes into account. */ - md5_uint32 bytes = ctx->buflen; - size_t pad; - md5_uint32 *buffer = NULL; - - /* Now count remaining bytes. */ - ctx->total[0] += bytes; - if (ctx->total[0] < bytes) - ++ctx->total[1]; - - pad = bytes >= 56 ? 64 + 56 - bytes : 56 - bytes; - memcpy (&ctx->buffer[bytes], fillbuf, pad); - - /* Put the 64-bit file length in *bits* at the end of the buffer. */ - buffer = (void *)&ctx->buffer[bytes + pad]; - *buffer = SWAP (ctx->total[0] << 3); - buffer = (void *)&ctx->buffer[bytes + pad + 4]; - *buffer = SWAP ((ctx->total[1] << 3) | (ctx->total[0] >> 29)); - - /* Process last bytes. */ - md5_process_block (ctx->buffer, bytes + pad + 8, ctx); - - return md5_read_ctx (ctx, resbuf); -} - -/* Compute MD5 message digest for bytes read from STREAM. The - resulting message digest number will be written into the 16 bytes - beginning at RESBLOCK. */ -int md5_stream (FILE *stream, void *resblock) -{ - /* Important: BLOCKSIZE must be a multiple of 64. */ -#define BLOCKSIZE 4096 - struct md5_ctx ctx; - char buffer[BLOCKSIZE + 72]; - size_t sum = 0; - - /* Initialize the computation context. */ - md5_init_ctx (&ctx); - - /* Iterate over full file contents. */ - while (1) - { - /* We read the file in blocks of BLOCKSIZE bytes. One call of the - computation function processes the whole buffer so that with the - next round of the loop another block can be read. */ - size_t n; - sum = 0; - - /* Read block. Take care for partial reads. */ - do - { - n = fread (buffer + sum, 1, BLOCKSIZE - sum, stream); - - sum += n; - } - while (sum < BLOCKSIZE && n != 0); - if (n == 0 && ferror (stream)) - return 1; - - /* If end of file is reached, end the loop. */ - if (n == 0) - break; - - /* Process buffer with BLOCKSIZE bytes. Note that - BLOCKSIZE % 64 == 0 - */ - md5_process_block (buffer, BLOCKSIZE, &ctx); - } - - /* Add the last bytes if necessary. */ - if (sum > 0) - md5_process_bytes (buffer, sum, &ctx); - - /* Construct result in desired memory. */ - md5_finish_ctx (&ctx, resblock); - return 0; -} - -/* Compute MD5 message digest for LEN bytes beginning at BUFFER. The - result is always in little endian byte order, so that a byte-wise - output yields to the wanted ASCII representation of the message - digest. */ -void *md5_buffer (const char *buffer, size_t len, void *resblock) -{ - struct md5_ctx ctx; - - /* Initialize the computation context. */ - md5_init_ctx (&ctx); - - /* Process whole buffer but last len % 64 bytes. */ - md5_process_bytes (buffer, len, &ctx); - - /* Put result in desired memory area. */ - return md5_finish_ctx (&ctx, resblock); -} diff --git a/src/md5.h b/src/md5.h deleted file mode 100644 index 141422c22..000000000 --- a/src/md5.h +++ /dev/null @@ -1,139 +0,0 @@ -// BLANKART -//----------------------------------------------------------------------------- -// Copyright (C) 1995-1996 by the Free Software Foundation, Inc. -// -// This program is free software distributed under the -// terms of the GNU General Public License, version 2. -// See the 'LICENSE' file for more details. -//----------------------------------------------------------------------------- -/// \file md5.h -/// \brief Functions to compute MD5 message digest of files or memory blocks -/// according to the definition of MD5 in RFC 1321 from April 1992 - -/* NOTE: The canonical source of this file is maintained with the GNU C - Library. Bugs can be reported to bug-glibc@prep.ai.mit.edu. */ - -#ifndef _MD5_H -#define _MD5_H 1 - -#include - -#if defined (HAVE_LIMITS_H) || (defined (_LIBC) && _LIBC) || defined (_WIN32) -# include -#endif - -#define MD5_LEN 16 - -/* The following contortions are an attempt to use the C preprocessor - to determine an unsigned integral type that is 32 bits wide. An - alternative approach is to use autoconf's AC_CHECK_SIZEOF macro, but - doing that would require that the configure script compile and *run* - the resulting executable. Locally running cross-compiled executables - is usually not possible. */ - -#ifdef _LIBC -# include -typedef u_int32_t md5_uint32; -#else -# if defined __STDC__ && __STDC__ -# define UINT_MAX_32_BITS 4294967295U -# else -# define UINT_MAX_32_BITS 0xFFFFFFFF -# endif - -/* If UINT_MAX isn't defined, assume it's a 32-bit type. - This should be valid for all systems GNU cares about because - that doesn't include 16-bit systems, and only modern systems - (that certainly have ) have 64+-bit integral types. */ - -# ifndef UINT_MAX -# define UINT_MAX UINT_MAX_32_BITS -# endif - -# if UINT_MAX == UINT_MAX_32_BITS - typedef unsigned int md5_uint32; -# else -# if USHRT_MAX == UINT_MAX_32_BITS - typedef unsigned short md5_uint32; -# else -# if ULONG_MAX == UINT_MAX_32_BITS - typedef unsigned long md5_uint32; -# else - /* The following line is intended to evoke an error. - Using #error is not portable enough. */ - "Cannot determine unsigned 32-bit data type." -# endif -# endif -# endif -#endif - -#undef __P -#if defined (__STDC__) && __STDC__ -#define __P(x) x -#else -#define __P(x) () -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -/* - * The following three functions are build up the low level used in - * the functions `md5_stream' and `md5_buffer'. - */ -#if 0 -/* Initialize structure containing state of computation. - (RFC 1321, 3.3: Step 3) */ -extern void md5_init_ctx __P ((struct md5_ctx *ctx)); - -/* Starting with the result of former calls of this function (or the - initialization function update the context for the next LEN bytes - starting at BUFFER. - It is necessary that LEN is a multiple of 64!!! */ -extern void md5_process_block __P ((const void *buffer, size_t len, - struct md5_ctx *ctx)); - -/* Starting with the result of former calls of this function (or the - initialization function update the context for the next LEN bytes - starting at BUFFER. - It is NOT required that LEN is a multiple of 64. */ -extern void md5_process_bytes __P ((const void *buffer, size_t len, - struct md5_ctx *ctx)); - -/* Process the remaining bytes in the buffer and put result from CTX - in first 16 bytes following RESBUF. The result is always in little - endian byte order, so that a byte-wise output yields to the wanted - ASCII representation of the message digest. - - IMPORTANT: On some systems it is required that RESBUF is correctly - aligned for a 32 bits value. */ -extern void *md5_finish_ctx __P ((struct md5_ctx *ctx, void *resbuf)); - - -/* Put result from CTX in first 16 bytes following RESBUF. The result is - always in little endian byte order, so that a byte-wise output yields - to the wanted ASCII representation of the message digest. - - IMPORTANT: On some systems it is required that RESBUF is correctly - aligned for a 32 bits value. */ -extern void *md5_read_ctx __P ((const struct md5_ctx *ctx, void *resbuf)); - -#endif - -/* Compute MD5 message digest for bytes read from STREAM. The - resulting message digest number will be written into the 16 bytes - beginning at RESBLOCK. */ -int md5_stream __P ((FILE *stream, void *resblock)); - -/* Compute MD5 message digest for LEN bytes beginning at BUFFER. The - result is always in little endian byte order, so that a byte-wise - output yields to the wanted ASCII representation of the message - digest. */ -extern void *md5_buffer __P ((const char *buffer, size_t len, void *resblock)); - -#ifdef __cplusplus -} // extern "C" -#endif - -#endif From fff5efc78f1062cc43e4ad0f366936e9cadd59c2 Mon Sep 17 00:00:00 2001 From: NepDisk Date: Sat, 23 Aug 2025 20:59:38 -0400 Subject: [PATCH 4/6] Fix compiler warning SRB2Classic Port by Hanicef --- src/d_clisrv.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/d_clisrv.c b/src/d_clisrv.c index e42838e1b..b6c5626ce 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -4328,7 +4328,7 @@ static void PT_LoginAuth(SINT8 node, INT32 netconsole) if (client) return; - if (doomcom->datalength < sizeof(netbuffer->u.sha256sum))/* ignore partial sends */ + if ((size_t)doomcom->datalength < sizeof(netbuffer->u.sha256sum))/* ignore partial sends */ return; if (adminsalt[node][0] == 0) From f9a332dbcc1450b968802a2400a8cbc8f51b804b Mon Sep 17 00:00:00 2001 From: NepDisk Date: Sat, 23 Aug 2025 21:12:10 -0400 Subject: [PATCH 5/6] Remove static asserts --- src/d_clisrv.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/d_clisrv.c b/src/d_clisrv.c index b6c5626ce..b949eed08 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -147,7 +147,6 @@ char *reqpass; char **adminpass; UINT32 adminpasscount = 0; static char adminsalt[MAXNETNODES][9]; -//I_StaticAssert(sizeof(netbuffer->u.salt) == sizeof(adminsalt[0])); // Client specific static ticcmd_t localcmds[MAXSPLITSCREENPLAYERS][MAXGENTLEMENDELAY]; @@ -4299,7 +4298,6 @@ static void PT_Login(SINT8 node) static void PT_LoginChallenge(SINT8 node) { char salt[9]; - //I_StaticAssert(sizeof(salt) == sizeof(netbuffer->u.salt)); doomdata_t *netbuffer = DOOMCOM_DATA(doomcom); if (node != servernode) From eb6c79d97db468c1dbbe75090cba8ad5e7968eab Mon Sep 17 00:00:00 2001 From: NepDisk Date: Sat, 23 Aug 2025 21:20:55 -0400 Subject: [PATCH 6/6] Add CC0-1.0 license --- LICENSE-3RD-PARTY | 124 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 124 insertions(+) diff --git a/LICENSE-3RD-PARTY b/LICENSE-3RD-PARTY index fde27f45e..369d9e967 100644 --- a/LICENSE-3RD-PARTY +++ b/LICENSE-3RD-PARTY @@ -1725,6 +1725,130 @@ DEALINGS IN THE SOFTWARE. ------------------------------------------------------------------------------- + +-------------------------------------------------------------------------------- + CC0 1.0 Universal + applies to: + - lonesha256 + https://github.com/BareRose/lonesha256 +-------------------------------------------------------------------------------- + +Statement of Purpose + +The laws of most jurisdictions throughout the world automatically confer +exclusive Copyright and Related Rights (defined below) upon the creator and +subsequent owner(s) (each and all, an "owner") of an original work of +authorship and/or a database (each, a "Work"). + +Certain owners wish to permanently relinquish those rights to a Work for the +purpose of contributing to a commons of creative, cultural and scientific +works ("Commons") that the public can reliably and without fear of later +claims of infringement build upon, modify, incorporate in other works, reuse +and redistribute as freely as possible in any form whatsoever and for any +purposes, including without limitation commercial purposes. These owners may +contribute to the Commons to promote the ideal of a free culture and the +further production of creative, cultural and scientific works, or to gain +reputation or greater distribution for their Work in part through the use and +efforts of others. + +For these and/or other purposes and motivations, and without any expectation +of additional consideration or compensation, the person associating CC0 with a +Work (the "Affirmer"), to the extent that he or she is an owner of Copyright +and Related Rights in the Work, voluntarily elects to apply CC0 to the Work +and publicly distribute the Work under its terms, with knowledge of his or her +Copyright and Related Rights in the Work and the meaning and intended legal +effect of CC0 on those rights. + +1. Copyright and Related Rights. A Work made available under CC0 may be +protected by copyright and related or neighboring rights ("Copyright and +Related Rights"). Copyright and Related Rights include, but are not limited +to, the following: + + i. the right to reproduce, adapt, distribute, perform, display, communicate, + and translate a Work; + + ii. moral rights retained by the original author(s) and/or performer(s); + + iii. publicity and privacy rights pertaining to a person's image or likeness + depicted in a Work; + + iv. rights protecting against unfair competition in regards to a Work, + subject to the limitations in paragraph 4(a), below; + + v. rights protecting the extraction, dissemination, use and reuse of data in + a Work; + + vi. database rights (such as those arising under Directive 96/9/EC of the + European Parliament and of the Council of 11 March 1996 on the legal + protection of databases, and under any national implementation thereof, + including any amended or successor version of such directive); and + + vii. other similar, equivalent or corresponding rights throughout the world + based on applicable law or treaty, and any national implementations thereof. + +2. Waiver. To the greatest extent permitted by, but not in contravention of, +applicable law, Affirmer hereby overtly, fully, permanently, irrevocably and +unconditionally waives, abandons, and surrenders all of Affirmer's Copyright +and Related Rights and associated claims and causes of action, whether now +known or unknown (including existing as well as future claims and causes of +action), in the Work (i) in all territories worldwide, (ii) for the maximum +duration provided by applicable law or treaty (including future time +extensions), (iii) in any current or future medium and for any number of +copies, and (iv) for any purpose whatsoever, including without limitation +commercial, advertising or promotional purposes (the "Waiver"). Affirmer makes +the Waiver for the benefit of each member of the public at large and to the +detriment of Affirmer's heirs and successors, fully intending that such Waiver +shall not be subject to revocation, rescission, cancellation, termination, or +any other legal or equitable action to disrupt the quiet enjoyment of the Work +by the public as contemplated by Affirmer's express Statement of Purpose. + +3. Public License Fallback. Should any part of the Waiver for any reason be +judged legally invalid or ineffective under applicable law, then the Waiver +shall be preserved to the maximum extent permitted taking into account +Affirmer's express Statement of Purpose. In addition, to the extent the Waiver +is so judged Affirmer hereby grants to each affected person a royalty-free, +non transferable, non sublicensable, non exclusive, irrevocable and +unconditional license to exercise Affirmer's Copyright and Related Rights in +the Work (i) in all territories worldwide, (ii) for the maximum duration +provided by applicable law or treaty (including future time extensions), (iii) +in any current or future medium and for any number of copies, and (iv) for any +purpose whatsoever, including without limitation commercial, advertising or +promotional purposes (the "License"). The License shall be deemed effective as +of the date CC0 was applied by Affirmer to the Work. Should any part of the +License for any reason be judged legally invalid or ineffective under +applicable law, such partial invalidity or ineffectiveness shall not +invalidate the remainder of the License, and in such case Affirmer hereby +affirms that he or she will not (i) exercise any of his or her remaining +Copyright and Related Rights in the Work or (ii) assert any associated claims +and causes of action with respect to the Work, in either case contrary to +Affirmer's express Statement of Purpose. + +4. Limitations and Disclaimers. + + a. No trademark or patent rights held by Affirmer are waived, abandoned, + surrendered, licensed or otherwise affected by this document. + + b. Affirmer offers the Work as-is and makes no representations or warranties + of any kind concerning the Work, express, implied, statutory or otherwise, + including without limitation warranties of title, merchantability, fitness + for a particular purpose, non infringement, or the absence of latent or + other defects, accuracy, or the present or absence of errors, whether or not + discoverable, all to the greatest extent permissible under applicable law. + + c. Affirmer disclaims responsibility for clearing rights of other persons + that may apply to the Work or any use thereof, including without limitation + any person's Copyright and Related Rights in the Work. Further, Affirmer + disclaims responsibility for obtaining any necessary consents, permissions + or other rights required for any use of the Work. + + d. Affirmer understands and acknowledges that Creative Commons is not a + party to this document and has no duty or obligation with respect to this + CC0 or use of the Work. + +For more information, please see + +------------------------------------------------------------------------------- + In addition to the above, we make use of the following public-domain software: * glad - https://github.com/Dav1dde/glad