From 264454ca708a7320512aba166a1ed90a5721f41e Mon Sep 17 00:00:00 2001 From: fickleheart Date: Tue, 5 Mar 2019 22:27:25 -0600 Subject: [PATCH 01/33] hblurgle spburgle this code sucks --- src/d_clisrv.c | 106 +++++++++++++++++++++++++++++++++++++++++++++++-- src/d_clisrv.h | 13 +++++- src/d_netcmd.c | 104 ++++++++++++++++++++++++++++++++++++++++++++++++ src/d_netcmd.h | 6 +++ 4 files changed, 225 insertions(+), 4 deletions(-) diff --git a/src/d_clisrv.c b/src/d_clisrv.c index 8e2a42de..e1c4f8bc 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -1126,13 +1126,55 @@ typedef enum CL_DOWNLOADSAVEGAME, #endif CL_CONNECTED, - CL_ABORTED + CL_ABORTED, + CL_CHALLENGE } cl_mode_t; static void GetPackets(void); static cl_mode_t cl_mode = CL_SEARCHING; +static UINT8 cl_challengenum = 0; +static UINT8 cl_challengequestion[17]; +static char cl_challengepassword[65]; +static UINT8 cl_challengeanswer[17]; + +static void D_JoinChallengeInput(INT32 ch) +{ + size_t len; + + while (ch) + { + if ((ch >= HU_FONTSTART && ch <= HU_FONTEND && hu_font[ch-HU_FONTSTART]) + || ch == ' ') // Allow spaces, of course + { + len = strlen(cl_challengepassword); + if (len < 64) + { + cl_challengepassword[len+1] = 0; + cl_challengepassword[len] = ch; + } + } + else if (ch == KEY_BACKSPACE) + { + len = strlen(cl_challengepassword); + + if (len > 0) + cl_challengepassword[len-1] = 0; + } + else if (ch == KEY_ENTER) + { + // Done? + D_ComputeChallengeAnswer(cl_challengequestion, cl_challengepassword, cl_challengeanswer); + cl_mode = CL_ASKJOIN; + return; + } + + ch = I_GetKey(); + } + +} + // Player name send/load static void CV_SavePlayerNames(UINT8 **p) @@ -1191,11 +1233,25 @@ static inline void CL_DrawConnectionStatus(void) // 15 pal entries total. const char *cltext; - for (i = 0; i < 16; ++i) - V_DrawFill((BASEVIDWIDTH/2-128) + (i * 16), BASEVIDHEIGHT-24, 16, 8, palstart + ((animtime - i) & 15)); + if (cl_mode != CL_CHALLENGE) + for (i = 0; i < 16; ++i) + V_DrawFill((BASEVIDWIDTH/2-128) + (i * 16), BASEVIDHEIGHT-24, 16, 8, palstart + ((animtime - i) & 15)); switch (cl_mode) { + case CL_CHALLENGE: + { + char asterisks[65]; + size_t sl = strlen(cl_challengepassword); + + memset(asterisks, '*', sl); + memset(asterisks+sl, 0, 65-sl); + + V_DrawString(BASEVIDWIDTH/2-128, BASEVIDHEIGHT-24, V_MONOSPACE|V_ALLOWLOWERCASE, asterisks); + + cltext = M_GetText("Please enter the server password."); + } + break; #ifdef JOININGAME case CL_DOWNLOADSAVEGAME: if (lastfilenum != -1) @@ -1292,6 +1348,8 @@ static boolean CL_SendJoin(void) netbuffer->u.clientcfg.localplayers = localplayers; netbuffer->u.clientcfg.version = VERSION; netbuffer->u.clientcfg.subversion = SUBVERSION; + netbuffer->u.clientcfg.challengenum = cl_challengenum; + memcpy(netbuffer->u.clientcfg.challengeanswer, cl_challengeanswer, 16); return HSendPacket(servernode, true, 0, sizeof (clientconfig_pak)); } @@ -2059,6 +2117,7 @@ static boolean CL_ServerConnectionTicker(boolean viams, const char *tmpsave, tic break; #endif + case CL_CHALLENGE: case CL_WAITJOINRESPONSE: case CL_CONNECTED: default: @@ -2091,6 +2150,8 @@ static boolean CL_ServerConnectionTicker(boolean viams, const char *tmpsave, tic D_StartTitle(); return false; } + else if (cl_mode == CL_CHALLENGE) + D_JoinChallengeInput(key); // why are these here? this is for servers, we're a client //if (key == 's' && server) @@ -3142,6 +3203,9 @@ void D_ClientServerInit(void) gametic = 0; localgametic = 0; + memset(cl_challengequestion, 0x00, 17); + memset(cl_challengeanswer, 0x00, 17); + // do not send anything before the real begin SV_StopServer(); SV_ResetServer(); @@ -3631,6 +3695,26 @@ static void HandleConnect(SINT8 node) boolean newnode = false; #endif + if (D_IsJoinPasswordOn()) + { + // Ensure node sent the correct password challenge + boolean passed = false; + + if (netbuffer->u.clientcfg.challengenum && D_VerifyJoinPasswordChallenge(netbuffer->u.clientcfg.challengenum, netbuffer->u.clientcfg.challengeanswer)) + passed = true; + + if (!passed) + { + D_MakeJoinPasswordChallenge(&netbuffer->u.joinchallenge.challengenum, netbuffer->u.joinchallenge.question); + + netbuffer->packettype = PT_JOINCHALLENGE; + HSendPacket(node, true, 0, sizeof(joinchallenge_pak)); + //Net_CloseConnection(node); + + return; + } + } + // client authorised to join nodewaiting[node] = (UINT8)(netbuffer->u.clientcfg.localplayers - playerpernode[node]); if (!nodeingame[node]) @@ -3794,6 +3878,22 @@ static void HandlePacketFromAwayNode(SINT8 node) Net_CloseConnection(node); break; + case PT_JOINCHALLENGE: + if (server && serverrunning) + { // But wait I thought I'm the server? + Net_CloseConnection(node); + break; + } + SERVERONLY + if (cl_mode == CL_WAITJOINRESPONSE) + { + cl_challengenum = netbuffer->u.joinchallenge.challengenum; + memcpy(cl_challengequestion, netbuffer->u.joinchallenge.question, 16); + + cl_mode = CL_CHALLENGE; + } + break; + case PT_SERVERREFUSE: // Negative response of client join request if (server && serverrunning) { // But wait I thought I'm the server? diff --git a/src/d_clisrv.h b/src/d_clisrv.h index 6615d67d..e4ff7cc7 100644 --- a/src/d_clisrv.h +++ b/src/d_clisrv.h @@ -73,6 +73,8 @@ typedef enum PT_CLIENT4MIS, PT_BASICKEEPALIVE,// Keep the network alive during wipes, as tics aren't advanced and NetUpdate isn't called + PT_JOINCHALLENGE, // You must give a password to joinnnnn + PT_CANFAIL, // This is kind of a priority. Anything bigger than CANFAIL // allows HSendPacket(*, true, *, *) to return false. // In addition, this packet can't occupy all the available slots. @@ -354,8 +356,16 @@ typedef struct UINT8 subversion; // Contains build version UINT8 localplayers; UINT8 mode; + UINT8 challengenum; // Non-zero if trying to join with a password attempt + UINT8 challengeanswer[16]; // Join challenge } ATTRPACK clientconfig_pak; +typedef struct +{ + UINT8 challengenum; // Number to send back in join attempt + UINT8 question[16]; // Challenge data to be manipulated and answered with +} ATTRPACK joinchallenge_pak; + #define MAXSERVERNAME 32 #define MAXFILENEEDED 915 // This packet is too large @@ -447,7 +457,8 @@ typedef struct UINT8 resynchgot; // UINT8 textcmd[MAXTEXTCMD+1]; // 66049 bytes (wut??? 64k??? More like 257 bytes...) filetx_pak filetxpak; // 139 bytes - clientconfig_pak clientcfg; // 136 bytes + clientconfig_pak clientcfg; // 153 bytes + joinchallenge_pak joinchallenge; // 17 bytes serverinfo_pak serverinfo; // 1024 bytes serverrefuse_pak serverrefuse; // 65025 bytes (somehow I feel like those values are garbage...) askinfo_pak askinfo; // 61 bytes diff --git a/src/d_netcmd.c b/src/d_netcmd.c index a8efd306..a8014ec4 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -169,6 +169,7 @@ static void Got_Verification(UINT8 **cp, INT32 playernum); static void Got_Removal(UINT8 **cp, INT32 playernum); static void Command_Verify_f(void); static void Command_RemoveAdmin_f(void); +static void Command_ChangeJoinPassword_f(void); static void Command_MotD_f(void); static void Got_MotD_f(UINT8 **cp, INT32 playernum); @@ -534,6 +535,7 @@ void D_RegisterServerCommands(void) RegisterNetXCmd(XD_PICKVOTE, Got_PickVotecmd); // Remote Administration + COM_AddCommand("joinpassword", Command_ChangeJoinPassword_f); COM_AddCommand("password", Command_Changepassword_f); RegisterNetXCmd(XD_LOGIN, Got_Login); COM_AddCommand("login", Command_Login_f); // useful in dedicated to kick off remote admin @@ -3427,6 +3429,7 @@ static void D_MD5PasswordPass(const UINT8 *buffer, size_t len, const char *salt, if (len > 256-sl) len = 256-sl; + memcpy(tmpbuf, buffer, len); memmove(&tmpbuf[len], salt, sl); //strcpy(&tmpbuf[len], salt); @@ -3702,6 +3705,107 @@ static void Got_Removal(UINT8 **cp, INT32 playernum) CONS_Printf(M_GetText("You are no longer a server administrator.\n")); } +// Join password stuff +#define NUMJOINCHALLENGES 32 +static UINT8 joinpassmd5[17]; +static boolean joinpasswordset = false; +static UINT8 joinpasschallenges[NUMJOINCHALLENGES][17]; +static boolean joinpasschallengeson[NUMJOINCHALLENGES]; + +boolean D_IsJoinPasswordOn(void) +{ + return joinpasswordset; +} + +static inline void GetChallengeAnswer(UINT8 *question, UINT8 *passwordmd5, UINT8 *answer) +{ + D_MD5PasswordPass(question, 16, (char *) passwordmd5, answer); +} + +void D_ComputeChallengeAnswer(UINT8 *question, const char *pw, UINT8 *answer) +{ + static UINT8 passwordmd5[17]; + + memset(passwordmd5, 0x00, 17); + D_MD5PasswordPass((const UINT8 *)pw, strlen(pw), BASESALT, &passwordmd5); + GetChallengeAnswer(question, passwordmd5, answer); +} + +void D_SetJoinPassword(const char *pw) +{ + memset(joinpassmd5, 0x00, 17); + D_MD5PasswordPass((const UINT8 *)pw, strlen(pw), BASESALT, &joinpassmd5); + joinpasswordset = true; +} + +boolean D_VerifyJoinPasswordChallenge(UINT8 num, UINT8 *answer) +{ + boolean passed = false; + + num %= NUMJOINCHALLENGES; + + //@TODO use a constant-time memcmp.... + if (joinpasschallengeson[num] && memcmp(answer, joinpasschallenges[num], 16) == 0) + passed = true; + + // Wipe and reset the challenge so that it can't be tried against again, as a small measure against brute-force attacks. + memset(joinpasschallenges[num], 0x00, 17); + joinpasschallengeson[num] = false; + + return passed; +} + +void D_MakeJoinPasswordChallenge(UINT8 *num, UINT8 *question) +{ + size_t i; + + for (i = 0; i < NUMJOINCHALLENGES; i++) + { + (*num) = M_RandomKey(NUMJOINCHALLENGES); + + if (!joinpasschallengeson[(*num)]) + break; + } + + // If the above loop never breaks, then uh.... we're obliterating one random stored challenge. Sorry (: + joinpasschallengeson[(*num)] = true; + + memset(question, 0x00, 17); + for (i = 0; i < 16; i++) + question[i] = M_RandomByte(); + + // Store the answer in memory. What was the question again? + GetChallengeAnswer(question, joinpassmd5, joinpasschallenges[(*num)]); + + // This ensures that num is always non-zero and will be valid when used for the answer + if ((*num) == 0) + (*num) = NUMJOINCHALLENGES; +} + +// Remote Administration +static void Command_ChangeJoinPassword_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; + } + + if (COM_Argc() != 2) + { + CONS_Printf(M_GetText("joinpassword : set a password to join the server\n")); + return; + } + + D_SetJoinPassword(COM_Argv(1)); + CONS_Printf(M_GetText("Join password set.\n")); +#endif +} + static void Command_MotD_f(void) { size_t i, j; diff --git a/src/d_netcmd.h b/src/d_netcmd.h index e0827013..438ba3ff 100644 --- a/src/d_netcmd.h +++ b/src/d_netcmd.h @@ -248,6 +248,12 @@ void RemoveAdminPlayer(INT32 playernum); void ItemFinder_OnChange(void); void D_SetPassword(const char *pw); +boolean D_IsJoinPasswordOn(void); +void D_ComputeChallengeAnswer(UINT8 *question, const char *pw, UINT8 *answer); +void D_SetJoinPassword(const char *pw); +boolean D_VerifyJoinPasswordChallenge(UINT8 num, UINT8 *answer); +void D_MakeJoinPasswordChallenge(UINT8 *num, UINT8 *question); + // used for the player setup menu UINT8 CanChangeSkin(INT32 playernum); From b5c4866706dbc09645112ea91e2227b1b5c56dc0 Mon Sep 17 00:00:00 2001 From: fickleheart Date: Wed, 6 Mar 2019 21:30:39 -0600 Subject: [PATCH 02/33] Add -remove option to joinpassword --- src/d_netcmd.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/d_netcmd.c b/src/d_netcmd.c index a8014ec4..70e6098d 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -3797,12 +3797,20 @@ static void Command_ChangeJoinPassword_f(void) if (COM_Argc() != 2) { - CONS_Printf(M_GetText("joinpassword : set a password to join the server\n")); + CONS_Printf(M_GetText("joinpassword : set a password to join the server\nUse -remove to disable the password.\n")); return; } - D_SetJoinPassword(COM_Argv(1)); - CONS_Printf(M_GetText("Join password set.\n")); + if (strcmp(COM_Argv(1), "-remove") == 0) + { + joinpasswordset = false; + CONS_Printf(M_GetText("Join password removed.\n")); + } + else + { + D_SetJoinPassword(COM_Argv(1)); + CONS_Printf(M_GetText("Join password set.\n")); + } #endif } From 52b743a18ffe249a7cfc2a562c451bcee3586d13 Mon Sep 17 00:00:00 2001 From: fickleheart Date: Wed, 6 Mar 2019 22:07:28 -0600 Subject: [PATCH 03/33] Fix join password not recognizing shifted characters --- src/d_clisrv.c | 129 ++++++++++++++++++++++++++++++------------------- src/d_clisrv.h | 1 + src/d_main.c | 3 ++ 3 files changed, 83 insertions(+), 50 deletions(-) diff --git a/src/d_clisrv.c b/src/d_clisrv.c index e1c4f8bc..ca32aaaf 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -22,6 +22,7 @@ #include "i_video.h" #include "d_net.h" #include "d_main.h" +#include "d_event.h" #include "g_game.h" #include "hu_stuff.h" #include "keys.h" @@ -1139,42 +1140,6 @@ static UINT8 cl_challengequestion[17]; static char cl_challengepassword[65]; static UINT8 cl_challengeanswer[17]; -static void D_JoinChallengeInput(INT32 ch) -{ - size_t len; - - while (ch) - { - if ((ch >= HU_FONTSTART && ch <= HU_FONTEND && hu_font[ch-HU_FONTSTART]) - || ch == ' ') // Allow spaces, of course - { - len = strlen(cl_challengepassword); - if (len < 64) - { - cl_challengepassword[len+1] = 0; - cl_challengepassword[len] = ch; - } - } - else if (ch == KEY_BACKSPACE) - { - len = strlen(cl_challengepassword); - - if (len > 0) - cl_challengepassword[len-1] = 0; - } - else if (ch == KEY_ENTER) - { - // Done? - D_ComputeChallengeAnswer(cl_challengequestion, cl_challengepassword, cl_challengeanswer); - cl_mode = CL_ASKJOIN; - return; - } - - ch = I_GetKey(); - } - -} - // Player name send/load static void CV_SavePlayerNames(UINT8 **p) @@ -2136,22 +2101,10 @@ static boolean CL_ServerConnectionTicker(boolean viams, const char *tmpsave, tic // Call it only once by tic if (*oldtic != I_GetTime()) { - INT32 key; - I_OsPolling(); - key = I_GetKey(); - // Only ESC and non-keyboard keys abort connection - if (key == KEY_ESCAPE || key >= KEY_MOUSE1) - { - CONS_Printf(M_GetText("Network game synchronization aborted.\n")); -// M_StartMessage(M_GetText("Network game synchronization aborted.\n\nPress ESC\n"), NULL, MM_NOTHING); - D_QuitNetGame(); - CL_Reset(); - D_StartTitle(); + D_ProcessEvents(); + if (gamestate != GS_WAITINGPLAYERS) return false; - } - else if (cl_mode == CL_CHALLENGE) - D_JoinChallengeInput(key); // why are these here? this is for servers, we're a client //if (key == 's' && server) @@ -2180,6 +2133,82 @@ static boolean CL_ServerConnectionTicker(boolean viams, const char *tmpsave, tic return true; } +boolean CL_Responder(event_t *ev) +{ + size_t len; + INT32 ch; + + if (!(client && cl_mode != CL_CONNECTED && cl_mode != CL_ABORTED)) + return false; // Don't do anything outside of the connection screen + + if (ev->type != ev_keydown) + return false; + + ch = (INT32)ev->data1; + + if (ch == KEY_CAPSLOCK) // it's a toggle. + { + capslock = !capslock; + return true; + } + + // Only ESC and non-keyboard keys abort connection + if (ch == KEY_ESCAPE || ch >= KEY_MOUSE1) + { + CONS_Printf(M_GetText("Network game synchronization aborted.\n")); + //M_StartMessage(M_GetText("Network game synchronization aborted.\n\nPress ESC\n"), NULL, MM_NOTHING); + D_QuitNetGame(); + CL_Reset(); + D_StartTitle(); + return true; + } + + if (cl_mode != CL_CHALLENGE) + return false; + + if ((ch >= HU_FONTSTART && ch <= HU_FONTEND && hu_font[ch-HU_FONTSTART]) + || ch == ' ') // Allow spaces, of course + { + len = strlen(cl_challengepassword); + if (len < 64) + { + + // shifting code stolen from lat by fickle, thx :) + + // I know this looks very messy but this works. If it ain't broke, don't fix it! + // shift LETTERS to uppercase if we have capslock or are holding shift + if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z')) + { + if (shiftdown ^ capslock) + ch = shiftxform[ch]; + } + else // if we're holding shift we should still shift non letter symbols + { + if (shiftdown) + ch = shiftxform[ch]; + } + + cl_challengepassword[len+1] = 0; + cl_challengepassword[len] = ch; + } + } + else if (ch == KEY_BACKSPACE) + { + len = strlen(cl_challengepassword); + + if (len > 0) + cl_challengepassword[len-1] = 0; + } + else if (ch == KEY_ENTER) + { + // Done? + D_ComputeChallengeAnswer(cl_challengequestion, cl_challengepassword, cl_challengeanswer); + cl_mode = CL_ASKJOIN; + } + + return true; +} + /** Use adaptive send using net_bandwidth and stat.sendbytes * * \param viams ??? diff --git a/src/d_clisrv.h b/src/d_clisrv.h index e4ff7cc7..4d410130 100644 --- a/src/d_clisrv.h +++ b/src/d_clisrv.h @@ -566,6 +566,7 @@ void CL_RemoveSplitscreenPlayer(UINT8 p); void CL_Reset(void); void CL_ClearPlayer(INT32 playernum); void CL_UpdateServerList(boolean internetsearch, INT32 room); +boolean CL_Responder(event_t *ev); // Is there a game running boolean Playing(void); diff --git a/src/d_main.c b/src/d_main.c index 28f89f4f..92c1e6ae 100644 --- a/src/d_main.c +++ b/src/d_main.c @@ -236,6 +236,9 @@ void D_ProcessEvents(void) if (M_ScreenshotResponder(ev)) continue; // ate the event + if (CL_Responder(ev)) + continue; + if (gameaction == ga_nothing && gamestate == GS_TITLESCREEN) { if (cht_Responder(ev)) From bc46c3540f580c043921ba224fd4e04cb76963e4 Mon Sep 17 00:00:00 2001 From: fickleheart Date: Wed, 6 Mar 2019 22:11:35 -0600 Subject: [PATCH 04/33] Show message on incorrect password --- src/d_clisrv.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/d_clisrv.c b/src/d_clisrv.c index ca32aaaf..9652561e 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -1139,6 +1139,7 @@ static UINT8 cl_challengenum = 0; static UINT8 cl_challengequestion[17]; static char cl_challengepassword[65]; static UINT8 cl_challengeanswer[17]; +static boolean cl_challengeattempted; // Player name send/load @@ -1214,7 +1215,7 @@ static inline void CL_DrawConnectionStatus(void) V_DrawString(BASEVIDWIDTH/2-128, BASEVIDHEIGHT-24, V_MONOSPACE|V_ALLOWLOWERCASE, asterisks); - cltext = M_GetText("Please enter the server password."); + cltext = M_GetText(cl_challengeattempted ? "Incorrect password. Please try again." : "Please enter the server password."); } break; #ifdef JOININGAME @@ -2191,6 +2192,8 @@ boolean CL_Responder(event_t *ev) cl_challengepassword[len+1] = 0; cl_challengepassword[len] = ch; } + + cl_challengeattempted = false; } else if (ch == KEY_BACKSPACE) { @@ -2198,12 +2201,15 @@ boolean CL_Responder(event_t *ev) if (len > 0) cl_challengepassword[len-1] = 0; + + cl_challengeattempted = false; } else if (ch == KEY_ENTER) { // Done? D_ComputeChallengeAnswer(cl_challengequestion, cl_challengepassword, cl_challengeanswer); cl_mode = CL_ASKJOIN; + cl_challengeattempted = true; } return true; @@ -2286,6 +2292,8 @@ static void CL_ConnectToServer(boolean viams) SL_ClearServerList(servernode); #endif + cl_challengeattempted = false; + do { // If the connection was aborted for some reason, leave From 219b240bcf01966256e2086dde217c6ca53da838 Mon Sep 17 00:00:00 2001 From: fickleheart Date: Wed, 6 Mar 2019 22:36:13 -0600 Subject: [PATCH 05/33] Recycle oldest challenges first if all are taken --- src/d_clisrv.c | 1 + src/d_netcmd.c | 26 ++++++++++++++++++++------ 2 files changed, 21 insertions(+), 6 deletions(-) diff --git a/src/d_clisrv.c b/src/d_clisrv.c index 9652561e..8e97ca1c 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -2235,6 +2235,7 @@ static void CL_ConnectToServer(boolean viams) #endif cl_mode = CL_SEARCHING; + cl_challengenum = 0; #ifdef CLIENT_LOADINGSCREEN lastfilenum = -1; diff --git a/src/d_netcmd.c b/src/d_netcmd.c index 70e6098d..789c505e 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -3710,7 +3710,7 @@ static void Got_Removal(UINT8 **cp, INT32 playernum) static UINT8 joinpassmd5[17]; static boolean joinpasswordset = false; static UINT8 joinpasschallenges[NUMJOINCHALLENGES][17]; -static boolean joinpasschallengeson[NUMJOINCHALLENGES]; +static tic_t joinpasschallengeson[NUMJOINCHALLENGES]; boolean D_IsJoinPasswordOn(void) { @@ -3745,12 +3745,12 @@ boolean D_VerifyJoinPasswordChallenge(UINT8 num, UINT8 *answer) num %= NUMJOINCHALLENGES; //@TODO use a constant-time memcmp.... - if (joinpasschallengeson[num] && memcmp(answer, joinpasschallenges[num], 16) == 0) + if (joinpasschallengeson[num] > 0 && memcmp(answer, joinpasschallenges[num], 16) == 0) passed = true; // Wipe and reset the challenge so that it can't be tried against again, as a small measure against brute-force attacks. memset(joinpasschallenges[num], 0x00, 17); - joinpasschallengeson[num] = false; + joinpasschallengeson[num] = 0; return passed; } @@ -3763,12 +3763,26 @@ void D_MakeJoinPasswordChallenge(UINT8 *num, UINT8 *question) { (*num) = M_RandomKey(NUMJOINCHALLENGES); - if (!joinpasschallengeson[(*num)]) + if (joinpasschallengeson[(*num)] == 0) break; } - // If the above loop never breaks, then uh.... we're obliterating one random stored challenge. Sorry (: - joinpasschallengeson[(*num)] = true; + if (joinpasschallengeson[(*num)] > 0) + { + // Ugh, all challenges are (probably) taken. Let's find the oldest one and overwrite it. + tic_t oldesttic = INT32_MAX; + + for (i = 0; i < NUMJOINCHALLENGES; i++) + { + if (joinpasschallengeson[i] < oldesttic) + { + (*num) = i; + oldesttic = joinpasschallengeson[i]; + } + } + } + + joinpasschallengeson[(*num)] = I_GetTime(); memset(question, 0x00, 17); for (i = 0; i < 16; i++) From 0ed74b306614e399753caf1ec709d49ba1115ee5 Mon Sep 17 00:00:00 2001 From: fickleheart Date: Wed, 6 Mar 2019 22:45:02 -0600 Subject: [PATCH 06/33] Missed an include --- src/d_clisrv.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/d_clisrv.h b/src/d_clisrv.h index 4d410130..55ff0749 100644 --- a/src/d_clisrv.h +++ b/src/d_clisrv.h @@ -13,6 +13,7 @@ #ifndef __D_CLISRV__ #define __D_CLISRV__ +#include "d_event.h" #include "d_ticcmd.h" #include "d_netcmd.h" #include "tables.h" From ddf2db8a36ec0b95f3a547bd6715d6bcc74c0e25 Mon Sep 17 00:00:00 2001 From: fickleheart Date: Wed, 6 Mar 2019 23:32:47 -0600 Subject: [PATCH 07/33] Fix freeze when trying to host with a join password already set --- 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 8e97ca1c..ed6939e2 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -3733,7 +3733,7 @@ static void HandleConnect(SINT8 node) boolean newnode = false; #endif - if (D_IsJoinPasswordOn()) + if (node != servernode && D_IsJoinPasswordOn()) { // Ensure node sent the correct password challenge boolean passed = false; From 18dba65f17e658d7a647fad451a2a3cf8f2f2ef9 Mon Sep 17 00:00:00 2001 From: fickleheart Date: Wed, 6 Mar 2019 23:34:30 -0600 Subject: [PATCH 08/33] Don't shoot asterisks off-screen on the join password screen --- src/d_clisrv.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/d_clisrv.c b/src/d_clisrv.c index ed6939e2..b1070426 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -1207,11 +1207,11 @@ static inline void CL_DrawConnectionStatus(void) { case CL_CHALLENGE: { - char asterisks[65]; - size_t sl = strlen(cl_challengepassword); + char asterisks[33]; + size_t sl = min(32, strlen(cl_challengepassword)); memset(asterisks, '*', sl); - memset(asterisks+sl, 0, 65-sl); + memset(asterisks+sl, 0, 33-sl); V_DrawString(BASEVIDWIDTH/2-128, BASEVIDHEIGHT-24, V_MONOSPACE|V_ALLOWLOWERCASE, asterisks); From 6bba2f16c0c0c8dd657629e829760ecf75ce37a4 Mon Sep 17 00:00:00 2001 From: fickleheart Date: Sat, 9 Mar 2019 12:01:47 -0600 Subject: [PATCH 09/33] Move HandleConnect to the same place as other packets --- src/d_clisrv.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/d_clisrv.c b/src/d_clisrv.c index b1070426..1afbe89e 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -3916,6 +3916,10 @@ static void HandlePacketFromAwayNode(SINT8 node) Net_CloseConnection(node); break; + case PT_CLIENTJOIN: + if (server) + HandleConnect(node); + break; case PT_JOINCHALLENGE: if (server && serverrunning) { // But wait I thought I'm the server? @@ -4592,12 +4596,6 @@ FILESTAMP while (HGetPacket()) { node = (SINT8)doomcom->remotenode; - - if (netbuffer->packettype == PT_CLIENTJOIN && server) - { - HandleConnect(node); - continue; - } if (node == servernode && client && cl_mode != CL_SEARCHING) { if (netbuffer->packettype == PT_SERVERSHUTDOWN) From 2954b68e12b62a7897069d0e3838ae385c2cb85c Mon Sep 17 00:00:00 2001 From: fickleheart Date: Sat, 9 Mar 2019 13:30:22 -0600 Subject: [PATCH 10/33] Check password and etc before downloading files --- src/d_clisrv.c | 85 ++++++++++++++++++++++++++++++++++++++++++++------ src/d_clisrv.h | 3 +- src/d_net.c | 2 +- 3 files changed, 79 insertions(+), 11 deletions(-) diff --git a/src/d_clisrv.c b/src/d_clisrv.c index 1afbe89e..37282519 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -1128,18 +1128,21 @@ typedef enum #endif CL_CONNECTED, CL_ABORTED, + CL_ASKDOWNLOADFILES, + CL_WAITDOWNLOADFILESRESPONSE, CL_CHALLENGE } cl_mode_t; static void GetPackets(void); static cl_mode_t cl_mode = CL_SEARCHING; +static boolean cl_needsdownload = false; static UINT8 cl_challengenum = 0; static UINT8 cl_challengequestion[17]; static char cl_challengepassword[65]; static UINT8 cl_challengeanswer[17]; -static boolean cl_challengeattempted; +static UINT8 cl_challengeattempted = 0; // Player name send/load @@ -1237,6 +1240,9 @@ static inline void CL_DrawConnectionStatus(void) case CL_WAITJOINRESPONSE: cltext = M_GetText("Requesting to join..."); break; + case CL_ASKDOWNLOADFILES: + case CL_WAITDOWNLOADFILESRESPONSE: + cltext = M_GetText("Waiting to download files..."); default: cltext = M_GetText("Connecting to server..."); break; @@ -1314,6 +1320,7 @@ static boolean CL_SendJoin(void) netbuffer->u.clientcfg.localplayers = localplayers; netbuffer->u.clientcfg.version = VERSION; netbuffer->u.clientcfg.subversion = SUBVERSION; + netbuffer->u.clientcfg.needsdownload = cl_needsdownload; netbuffer->u.clientcfg.challengenum = cl_challengenum; memcpy(netbuffer->u.clientcfg.challengeanswer, cl_challengeanswer, 16); @@ -1989,9 +1996,12 @@ static boolean CL_ServerConnectionSearchTicker(boolean viams, tic_t *asksent) ), NULL, MM_NOTHING); return false; } + + cl_mode = CL_ASKDOWNLOADFILES; + // no problem if can't send packet, we will retry later - if (CL_SendRequestFile()) - cl_mode = CL_DOWNLOADFILES; + //if (CL_SendRequestFile()) + // cl_mode = CL_DOWNLOADFILES; } } else @@ -2059,6 +2069,7 @@ static boolean CL_ServerConnectionTicker(boolean viams, const char *tmpsave, tic /* FALLTHRU */ case CL_ASKJOIN: + cl_needsdownload = false; CL_LoadServerFiles(); #ifdef JOININGAME // prepare structures to save the file @@ -2070,6 +2081,14 @@ static boolean CL_ServerConnectionTicker(boolean viams, const char *tmpsave, tic cl_mode = CL_WAITJOINRESPONSE; break; + case CL_ASKDOWNLOADFILES: + cl_needsdownload = true; + + if (CL_SendJoin()) + cl_mode = CL_WAITDOWNLOADFILESRESPONSE; + break; + + #ifdef JOININGAME case CL_DOWNLOADSAVEGAME: // At this state, the first (and only) needed file is the gamestate @@ -2085,6 +2104,7 @@ static boolean CL_ServerConnectionTicker(boolean viams, const char *tmpsave, tic case CL_CHALLENGE: case CL_WAITJOINRESPONSE: + case CL_WAITDOWNLOADFILESRESPONSE: case CL_CONNECTED: default: break; @@ -2193,7 +2213,7 @@ boolean CL_Responder(event_t *ev) cl_challengepassword[len] = ch; } - cl_challengeattempted = false; + cl_challengeattempted = 0; } else if (ch == KEY_BACKSPACE) { @@ -2202,14 +2222,14 @@ boolean CL_Responder(event_t *ev) if (len > 0) cl_challengepassword[len-1] = 0; - cl_challengeattempted = false; + cl_challengeattempted = 0; } else if (ch == KEY_ENTER) { // Done? D_ComputeChallengeAnswer(cl_challengequestion, cl_challengepassword, cl_challengeanswer); - cl_mode = CL_ASKJOIN; - cl_challengeattempted = true; + cl_mode = cl_needsdownload ? CL_ASKDOWNLOADFILES : CL_ASKJOIN; + cl_challengeattempted = 1; } return true; @@ -2293,7 +2313,7 @@ static void CL_ConnectToServer(boolean viams) SL_ClearServerList(servernode); #endif - cl_challengeattempted = false; + cl_challengeattempted = 0; do { @@ -3753,6 +3773,13 @@ static void HandleConnect(SINT8 node) } } + if (netbuffer->u.clientcfg.needsdownload) + { + netbuffer->packettype = PT_DOWNLOADFILESOKAY; + HSendPacket(node, true, 0, 0); + return; + } + // client authorised to join nodewaiting[node] = (UINT8)(netbuffer->u.clientcfg.localplayers - playerpernode[node]); if (!nodeingame[node]) @@ -3761,6 +3788,7 @@ static void HandleConnect(SINT8 node) #ifndef NONET newnode = true; #endif + SV_AddNode(node); /// \note Wait what??? @@ -3927,12 +3955,19 @@ static void HandlePacketFromAwayNode(SINT8 node) break; } SERVERONLY - if (cl_mode == CL_WAITJOINRESPONSE) + if (cl_mode == CL_WAITJOINRESPONSE || cl_mode == CL_WAITDOWNLOADFILESRESPONSE) { cl_challengenum = netbuffer->u.joinchallenge.challengenum; memcpy(cl_challengequestion, netbuffer->u.joinchallenge.question, 16); cl_mode = CL_CHALLENGE; + + if (cl_challengeattempted == 2) + { + // We already sent a correct password, so throw it back up again. + D_ComputeChallengeAnswer(cl_challengequestion, cl_challengepassword, cl_challengeanswer); + cl_mode = CL_ASKJOIN; + } } break; @@ -3964,6 +3999,38 @@ static void HandlePacketFromAwayNode(SINT8 node) } break; + case PT_DOWNLOADFILESOKAY: + if (server && serverrunning) + { // But wait I thought I'm the server? + Net_CloseConnection(node); + break; + } + + SERVERONLY + + // This should've already been checked, but just to be safe... + if (!CL_CheckDownloadable()) + { + D_QuitNetGame(); + CL_Reset(); + D_StartTitle(); + M_StartMessage(M_GetText( + "You cannot connect to this server\n" + "because you cannot download the files\n" + "that you are missing from the server.\n\n" + "See the console or log file for\n" + "more details.\n\n" + "Press ESC\n" + ), NULL, MM_NOTHING); + break; + } + + cl_challengeattempted = 2; + CONS_Printf("trying to download\n"); + if (CL_SendRequestFile()) + cl_mode = CL_DOWNLOADFILES; + break; + case PT_SERVERCFG: // Positive response of client join request { INT32 j; diff --git a/src/d_clisrv.h b/src/d_clisrv.h index 55ff0749..59a0b5c6 100644 --- a/src/d_clisrv.h +++ b/src/d_clisrv.h @@ -75,6 +75,7 @@ typedef enum PT_BASICKEEPALIVE,// Keep the network alive during wipes, as tics aren't advanced and NetUpdate isn't called PT_JOINCHALLENGE, // You must give a password to joinnnnn + PT_DOWNLOADFILESOKAY, // You can download files from the server.... PT_CANFAIL, // This is kind of a priority. Anything bigger than CANFAIL // allows HSendPacket(*, true, *, *) to return false. @@ -356,7 +357,7 @@ typedef struct UINT8 version; // Different versions don't work UINT8 subversion; // Contains build version UINT8 localplayers; - UINT8 mode; + UINT8 needsdownload; UINT8 challengenum; // Non-zero if trying to join with a password attempt UINT8 challengeanswer[16]; // Join challenge } ATTRPACK clientconfig_pak; diff --git a/src/d_net.c b/src/d_net.c index 6702a60a..530ee6df 100644 --- a/src/d_net.c +++ b/src/d_net.c @@ -868,7 +868,7 @@ static void DebugPrintpacket(const char *header) break; case PT_CLIENTJOIN: fprintf(debugfile, " number %d mode %d\n", netbuffer->u.clientcfg.localplayers, - netbuffer->u.clientcfg.mode); + netbuffer->u.clientcfg.needsdownload); break; case PT_SERVERTICS: { From d5691b92897a3b4ca3c4839d99a042131c8ca4e2 Mon Sep 17 00:00:00 2001 From: fickleheart Date: Sat, 9 Mar 2019 14:30:04 -0600 Subject: [PATCH 11/33] Show kartspeed and password status on server browser --- src/d_clisrv.c | 8 +++++++- src/d_clisrv.h | 6 +++++- src/m_menu.c | 13 ++++++++++++- 3 files changed, 24 insertions(+), 3 deletions(-) diff --git a/src/d_clisrv.c b/src/d_clisrv.c index 37282519..6ff024cd 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -1343,7 +1343,13 @@ static void SV_SendServerInfo(INT32 node, tic_t servertime) netbuffer->u.serverinfo.gametype = (UINT8)(G_BattleGametype() ? VANILLA_GT_MATCH : VANILLA_GT_RACE); // SRB2Kart: Vanilla's gametype constants for MS support netbuffer->u.serverinfo.modifiedgame = (UINT8)modifiedgame; netbuffer->u.serverinfo.cheatsenabled = CV_CheatsEnabled(); - netbuffer->u.serverinfo.isdedicated = (UINT8)dedicated; + + netbuffer->u.serverinfo.kartvars = (UINT8) ( + cv_kartspeed.value | + (dedicated ? SV_DEDICATED : 0) | + (D_IsJoinPasswordOn() ? SV_PASSWORD : 0) + ); + strncpy(netbuffer->u.serverinfo.servername, cv_servername.string, MAXSERVERNAME); strncpy(netbuffer->u.serverinfo.mapname, G_BuildMapName(gamemap), 7); diff --git a/src/d_clisrv.h b/src/d_clisrv.h index 59a0b5c6..2937e882 100644 --- a/src/d_clisrv.h +++ b/src/d_clisrv.h @@ -368,6 +368,10 @@ typedef struct UINT8 question[16]; // Challenge data to be manipulated and answered with } ATTRPACK joinchallenge_pak; +#define SV_SPEEDMASK 0x03 +#define SV_DEDICATED 0x40 +#define SV_PASSWORD 0x80 + #define MAXSERVERNAME 32 #define MAXFILENEEDED 915 // This packet is too large @@ -380,7 +384,7 @@ typedef struct UINT8 gametype; UINT8 modifiedgame; UINT8 cheatsenabled; - UINT8 isdedicated; + UINT8 kartvars; // Previously isdedicated, now appropriated for our own nefarious purposes UINT8 fileneedednum; SINT8 adminplayer; tic_t time; diff --git a/src/m_menu.c b/src/m_menu.c index 57a73c14..23e6ede4 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -7241,6 +7241,7 @@ static void M_DrawConnectMenu(void) { UINT16 i, j; const char *gt = "Unknown"; + const char *spd = ""; INT32 numPages = (serverlistcount+(SERVERS_PER_PAGE-1))/SERVERS_PER_PAGE; for (i = FIRSTSERVERLINE; i < min(localservercount, SERVERS_PER_PAGE)+FIRSTSERVERLINE; i++) @@ -7294,7 +7295,17 @@ static void M_DrawConnectMenu(void) V_DrawSmallString(currentMenu->x+46,S_LINEY(i)+8, globalflags, va("Players: %02d/%02d", serverlist[slindex].info.numberofplayer, serverlist[slindex].info.maxplayer)); - V_DrawSmallString(currentMenu->x+112, S_LINEY(i)+8, globalflags, va("Gametype: %s", gt)); + V_DrawSmallString(currentMenu->x+112, S_LINEY(i)+8, globalflags, gt); + + if (serverlist[slindex].info.gametype == GT_RACE) + { + spd = kartspeed_cons_t[serverlist[slindex].info.kartvars & SV_SPEEDMASK].strvalue; + + V_DrawSmallString(currentMenu->x+132, S_LINEY(i)+8, globalflags, va("(%s Speed)", spd)); + } + + if (serverlist[slindex].info.kartvars & SV_PASSWORD) + V_DrawFixedPatch((currentMenu->x - 10) << FRACBITS, (S_LINEY(i)) << FRACBITS, FRACUNIT, globalflags & (~V_ALLOWLOWERCASE), W_CachePatchName("SERVLOCK", PU_CACHE), NULL); MP_ConnectMenu[i+FIRSTSERVERLINE].status = IT_STRING | IT_CALL; } From 1b6035e322d59c60cbd0930f217b25e2fb3618d3 Mon Sep 17 00:00:00 2001 From: fickleheart Date: Sat, 9 Mar 2019 15:00:48 -0600 Subject: [PATCH 12/33] Add join password to server host menu --- src/d_netcmd.c | 5 ++++- src/d_netcmd.h | 2 ++ src/m_menu.c | 34 +++++++++++++++++++++++++++------- src/m_menu.h | 1 + 4 files changed, 34 insertions(+), 8 deletions(-) diff --git a/src/d_netcmd.c b/src/d_netcmd.c index 789c505e..451e9762 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -535,6 +535,7 @@ void D_RegisterServerCommands(void) RegisterNetXCmd(XD_PICKVOTE, Got_PickVotecmd); // Remote Administration + CV_RegisterVar(&cv_dummyjoinpassword); COM_AddCommand("joinpassword", Command_ChangeJoinPassword_f); COM_AddCommand("password", Command_Changepassword_f); RegisterNetXCmd(XD_LOGIN, Got_Login); @@ -3706,9 +3707,11 @@ static void Got_Removal(UINT8 **cp, INT32 playernum) } // Join password stuff +consvar_t cv_dummyjoinpassword = {"dummyjoinpassword", "", CV_HIDEN|CV_NOSHOWHELP, NULL, NULL, 0, NULL, NULL, 0, 0, NULL}; + #define NUMJOINCHALLENGES 32 static UINT8 joinpassmd5[17]; -static boolean joinpasswordset = false; +boolean joinpasswordset = false; static UINT8 joinpasschallenges[NUMJOINCHALLENGES][17]; static tic_t joinpasschallengeson[NUMJOINCHALLENGES]; diff --git a/src/d_netcmd.h b/src/d_netcmd.h index 438ba3ff..166c5e00 100644 --- a/src/d_netcmd.h +++ b/src/d_netcmd.h @@ -248,6 +248,8 @@ void RemoveAdminPlayer(INT32 playernum); void ItemFinder_OnChange(void); void D_SetPassword(const char *pw); +extern consvar_t cv_dummyjoinpassword; +extern boolean joinpasswordset; boolean D_IsJoinPasswordOn(void); void D_ComputeChallengeAnswer(UINT8 *question, const char *pw, UINT8 *answer); void D_SetJoinPassword(const char *pw); diff --git a/src/m_menu.c b/src/m_menu.c index 23e6ede4..83bec981 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -948,14 +948,15 @@ static menuitem_t MP_MainMenu[] = static menuitem_t MP_ServerMenu[] = { - {IT_STRING|IT_CVAR, NULL, "Max. Player Count", &cv_maxplayers, 10}, - {IT_STRING|IT_CALL, NULL, "Room...", M_RoomMenu, 20}, - {IT_STRING|IT_CVAR|IT_CV_STRING, NULL, "Server Name", &cv_servername, 30}, + {IT_STRING|IT_CVAR, NULL, "Max. Player Count", &cv_maxplayers, 0}, + {IT_STRING|IT_CALL, NULL, "Room...", M_RoomMenu, 10}, + {IT_STRING|IT_CVAR|IT_CV_STRING, NULL, "Server Name", &cv_servername, 20}, + {IT_STRING|IT_CVAR|IT_CV_PASSWORD, NULL, "Password", &cv_dummyjoinpassword, 44}, - {IT_STRING|IT_CVAR, NULL, "Game Type", &cv_newgametype, 68}, - {IT_STRING|IT_CVAR, NULL, "Level", &cv_nextmap, 78}, + {IT_STRING|IT_CVAR, NULL, "Game Type", &cv_newgametype, 68}, + {IT_STRING|IT_CVAR, NULL, "Level", &cv_nextmap, 78}, - {IT_WHITESTRING|IT_CALL, NULL, "Start", M_StartServer, 130}, + {IT_WHITESTRING|IT_CALL, NULL, "Start", M_StartServer, 130}, }; #endif @@ -2682,7 +2683,7 @@ boolean M_Responder(event_t *ev) // BP: one of the more big hack i have never made if (routine && (currentMenu->menuitems[itemOn].status & IT_TYPE) == IT_CVAR) { - if ((currentMenu->menuitems[itemOn].status & IT_CVARTYPE) == IT_CV_STRING) + if ((currentMenu->menuitems[itemOn].status & IT_CVARTYPE) == IT_CV_STRING || (currentMenu->menuitems[itemOn].status & IT_CVARTYPE) == IT_CV_PASSWORD) { if (shiftdown && ch >= 32 && ch <= 127) ch = shiftxform[ch]; @@ -3557,6 +3558,8 @@ static void M_DrawGenericMenu(void) case IT_CVAR: { consvar_t *cv = (consvar_t *)currentMenu->menuitems[i].itemaction; + char asterisks[MAXSTRINGLENGTH+1]; + size_t sl; switch (currentMenu->menuitems[i].status & IT_CVARTYPE) { case IT_CV_SLIDER: @@ -3572,6 +3575,18 @@ static void M_DrawGenericMenu(void) '_' | 0x80, false); y += 16; break; + case IT_CV_PASSWORD: + sl = strlen(cv->string); + memset(asterisks, '*', sl); + memset(asterisks + sl, 0, MAXSTRINGLENGTH+1-sl); + + M_DrawTextBox(x, y + 4, MAXSTRINGLENGTH, 1); + V_DrawString(x + 8, y + 12, V_ALLOWLOWERCASE, asterisks); + if (skullAnimCounter < 4 && i == itemOn) + V_DrawCharacter(x + 8 + V_StringWidth(asterisks, 0), y + 12, + '_' | 0x80, false); + y += 16; + break; default: w = V_StringWidth(cv->string, 0); V_DrawString(BASEVIDWIDTH - x - w, y, @@ -7540,6 +7555,11 @@ static void M_StartServer(INT32 choice) // Still need to reset devmode cv_debug = 0; + if (strlen(cv_dummyjoinpassword.string) > 0) + D_SetJoinPassword(cv_dummyjoinpassword.string); + else + joinpasswordset = false; + if (demoplayback) G_StopDemo(); if (metalrecording) diff --git a/src/m_menu.h b/src/m_menu.h index 864f4cac..06ae7114 100644 --- a/src/m_menu.h +++ b/src/m_menu.h @@ -104,6 +104,7 @@ boolean M_CanShowLevelInList(INT32 mapnum, INT32 gt); #define IT_CV_NOPRINT 1536 #define IT_CV_NOMOD 2048 #define IT_CV_INVISSLIDER 2560 +#define IT_CV_PASSWORD 3072 //call/submenu specific // There used to be a lot more here but ... From 870a800d89c1c585f71d6281618fc140e4a37158 Mon Sep 17 00:00:00 2001 From: fickleheart Date: Sat, 9 Mar 2019 15:14:08 -0600 Subject: [PATCH 13/33] Toggle showing password with tab --- src/m_menu.c | 42 ++++++++++++++++++++++++++++++------------ 1 file changed, 30 insertions(+), 12 deletions(-) diff --git a/src/m_menu.c b/src/m_menu.c index 83bec981..dd035388 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -2384,6 +2384,9 @@ static void M_NextOpt(void) { INT16 oldItemOn = itemOn; // prevent infinite loop + if ((currentMenu->menuitems[itemOn].status & IT_CVARTYPE) == IT_CV_PASSWORD) + ((consvar_t *)currentMenu->menuitems[itemOn].itemaction)->value = 0; + do { if (itemOn + 1 > currentMenu->numitems - 1) @@ -2397,6 +2400,9 @@ static void M_PrevOpt(void) { INT16 oldItemOn = itemOn; // prevent infinite loop + if ((currentMenu->menuitems[itemOn].status & IT_CVARTYPE) == IT_CV_PASSWORD) + ((consvar_t *)currentMenu->menuitems[itemOn].itemaction)->value = 0; + do { if (!itemOn) @@ -2685,6 +2691,9 @@ boolean M_Responder(event_t *ev) { if ((currentMenu->menuitems[itemOn].status & IT_CVARTYPE) == IT_CV_STRING || (currentMenu->menuitems[itemOn].status & IT_CVARTYPE) == IT_CV_PASSWORD) { + if (ch == KEY_TAB) + ((consvar_t *)currentMenu->menuitems[itemOn].itemaction)->value ^= 1; + if (shiftdown && ch >= 32 && ch <= 127) ch = shiftxform[ch]; if (M_ChangeStringCvar(ch)) @@ -3567,6 +3576,27 @@ static void M_DrawGenericMenu(void) case IT_CV_NOPRINT: // color use this case IT_CV_INVISSLIDER: // monitor toggles use this break; + case IT_CV_PASSWORD: + if (i == itemOn) + { + V_DrawRightAlignedThinString(x + MAXSTRINGLENGTH*8 + 10, y, V_ALLOWLOWERCASE, va(M_GetText("Tab: %s password"), cv->value ? "hide" : "show")); + } + + if (!cv->value || i != itemOn) + { + sl = strlen(cv->string); + memset(asterisks, '*', sl); + memset(asterisks + sl, 0, MAXSTRINGLENGTH+1-sl); + + M_DrawTextBox(x, y + 4, MAXSTRINGLENGTH, 1); + V_DrawString(x + 8, y + 12, V_ALLOWLOWERCASE, asterisks); + if (skullAnimCounter < 4 && i == itemOn) + V_DrawCharacter(x + 8 + V_StringWidth(asterisks, 0), y + 12, + '_' | 0x80, false); + y += 16; + break; + } + /* fallthru */ case IT_CV_STRING: M_DrawTextBox(x, y + 4, MAXSTRINGLENGTH, 1); V_DrawString(x + 8, y + 12, V_ALLOWLOWERCASE, cv->string); @@ -3575,18 +3605,6 @@ static void M_DrawGenericMenu(void) '_' | 0x80, false); y += 16; break; - case IT_CV_PASSWORD: - sl = strlen(cv->string); - memset(asterisks, '*', sl); - memset(asterisks + sl, 0, MAXSTRINGLENGTH+1-sl); - - M_DrawTextBox(x, y + 4, MAXSTRINGLENGTH, 1); - V_DrawString(x + 8, y + 12, V_ALLOWLOWERCASE, asterisks); - if (skullAnimCounter < 4 && i == itemOn) - V_DrawCharacter(x + 8 + V_StringWidth(asterisks, 0), y + 12, - '_' | 0x80, false); - y += 16; - break; default: w = V_StringWidth(cv->string, 0); V_DrawString(BASEVIDWIDTH - x - w, y, From e4d99605ebcb0fc8dc849f686861f74dec7b60cb Mon Sep 17 00:00:00 2001 From: fickleheart Date: Sat, 9 Mar 2019 15:27:23 -0600 Subject: [PATCH 14/33] Nudge lock over a tad --- src/m_menu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/m_menu.c b/src/m_menu.c index dd035388..881b6682 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -7338,7 +7338,7 @@ static void M_DrawConnectMenu(void) } if (serverlist[slindex].info.kartvars & SV_PASSWORD) - V_DrawFixedPatch((currentMenu->x - 10) << FRACBITS, (S_LINEY(i)) << FRACBITS, FRACUNIT, globalflags & (~V_ALLOWLOWERCASE), W_CachePatchName("SERVLOCK", PU_CACHE), NULL); + V_DrawFixedPatch((currentMenu->x - 9) << FRACBITS, (S_LINEY(i)) << FRACBITS, FRACUNIT, globalflags & (~V_ALLOWLOWERCASE), W_CachePatchName("SERVLOCK", PU_CACHE), NULL); MP_ConnectMenu[i+FIRSTSERVERLINE].status = IT_STRING | IT_CALL; } From 5f0c4271d7fdf29aa8ee28bb257985a8ece553c0 Mon Sep 17 00:00:00 2001 From: fickleheart Date: Sat, 9 Mar 2019 16:46:55 -0600 Subject: [PATCH 15/33] Use consts in place of some 16s --- src/d_clisrv.h | 4 ++-- src/d_netcmd.c | 36 ++++++++++++++++++------------------ src/md5.h | 2 ++ src/w_wad.c | 1 - 4 files changed, 22 insertions(+), 21 deletions(-) diff --git a/src/d_clisrv.h b/src/d_clisrv.h index 2937e882..d979fb28 100644 --- a/src/d_clisrv.h +++ b/src/d_clisrv.h @@ -359,13 +359,13 @@ typedef struct UINT8 localplayers; UINT8 needsdownload; UINT8 challengenum; // Non-zero if trying to join with a password attempt - UINT8 challengeanswer[16]; // Join challenge + UINT8 challengeanswer[MD5_LEN]; // Join challenge } ATTRPACK clientconfig_pak; typedef struct { UINT8 challengenum; // Number to send back in join attempt - UINT8 question[16]; // Challenge data to be manipulated and answered with + UINT8 question[MD5_LEN]; // Challenge data to be manipulated and answered with } ATTRPACK joinchallenge_pak; #define SV_SPEEDMASK 0x03 diff --git a/src/d_netcmd.c b/src/d_netcmd.c index 451e9762..abc31949 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -3444,7 +3444,7 @@ static void D_MD5PasswordPass(const UINT8 *buffer, size_t len, const char *salt, } #define BASESALT "basepasswordstorage" -static UINT8 adminpassmd5[16]; +static UINT8 adminpassmd5[MD5_LEN]; static boolean adminpasswordset = false; void D_SetPassword(const char *pw) @@ -3483,7 +3483,7 @@ static void Command_Login_f(void) // 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 - XBOXSTATIC UINT8 finalmd5[16]; + XBOXSTATIC UINT8 finalmd5[MD5_LEN]; const char *pw; if (!netgame) @@ -3506,11 +3506,11 @@ static void Command_Login_f(void) D_MD5PasswordPass((const UINT8 *)pw, strlen(pw), BASESALT, &finalmd5); // Do the final pass to get the comparison the server will come up with - D_MD5PasswordPass(finalmd5, 16, va("PNUM%02d", consoleplayer), &finalmd5); + D_MD5PasswordPass(finalmd5, MD5_LEN, va("PNUM%02d", consoleplayer), &finalmd5); CONS_Printf(M_GetText("Sending login... (Notice only given if password is correct.)\n")); - SendNetXCmd(XD_LOGIN, finalmd5, 16); + SendNetXCmd(XD_LOGIN, finalmd5, MD5_LEN); #endif } @@ -3521,9 +3521,9 @@ static void Got_Login(UINT8 **cp, INT32 playernum) (void)cp; (void)playernum; #else - UINT8 sentmd5[16], finalmd5[16]; + UINT8 sentmd5[MD5_LEN], finalmd5[MD5_LEN]; - READMEM(*cp, sentmd5, 16); + READMEM(*cp, sentmd5, MD5_LEN); if (client) return; @@ -3535,9 +3535,9 @@ static void Got_Login(UINT8 **cp, INT32 playernum) } // Do the final pass to compare with the sent md5 - D_MD5PasswordPass(adminpassmd5, 16, va("PNUM%02d", playernum), &finalmd5); + D_MD5PasswordPass(adminpassmd5, MD5_LEN, va("PNUM%02d", playernum), &finalmd5); - if (!memcmp(sentmd5, finalmd5, 16)) + if (!memcmp(sentmd5, finalmd5, MD5_LEN)) { CONS_Printf(M_GetText("%s passed authentication.\n"), player_names[playernum]); COM_BufInsertText(va("promote %d\n", playernum)); // do this immediately @@ -3710,9 +3710,9 @@ static void Got_Removal(UINT8 **cp, INT32 playernum) consvar_t cv_dummyjoinpassword = {"dummyjoinpassword", "", CV_HIDEN|CV_NOSHOWHELP, NULL, NULL, 0, NULL, NULL, 0, 0, NULL}; #define NUMJOINCHALLENGES 32 -static UINT8 joinpassmd5[17]; +static UINT8 joinpassmd5[MD5_LEN+1]; boolean joinpasswordset = false; -static UINT8 joinpasschallenges[NUMJOINCHALLENGES][17]; +static UINT8 joinpasschallenges[NUMJOINCHALLENGES][MD5_LEN+1]; static tic_t joinpasschallengeson[NUMJOINCHALLENGES]; boolean D_IsJoinPasswordOn(void) @@ -3722,21 +3722,21 @@ boolean D_IsJoinPasswordOn(void) static inline void GetChallengeAnswer(UINT8 *question, UINT8 *passwordmd5, UINT8 *answer) { - D_MD5PasswordPass(question, 16, (char *) passwordmd5, answer); + D_MD5PasswordPass(question, MD5_LEN, (char *) passwordmd5, answer); } void D_ComputeChallengeAnswer(UINT8 *question, const char *pw, UINT8 *answer) { - static UINT8 passwordmd5[17]; + static UINT8 passwordmd5[MD5_LEN+1]; - memset(passwordmd5, 0x00, 17); + memset(passwordmd5, 0x00, MD5_LEN+1); D_MD5PasswordPass((const UINT8 *)pw, strlen(pw), BASESALT, &passwordmd5); GetChallengeAnswer(question, passwordmd5, answer); } void D_SetJoinPassword(const char *pw) { - memset(joinpassmd5, 0x00, 17); + memset(joinpassmd5, 0x00, MD5_LEN+1); D_MD5PasswordPass((const UINT8 *)pw, strlen(pw), BASESALT, &joinpassmd5); joinpasswordset = true; } @@ -3748,11 +3748,11 @@ boolean D_VerifyJoinPasswordChallenge(UINT8 num, UINT8 *answer) num %= NUMJOINCHALLENGES; //@TODO use a constant-time memcmp.... - if (joinpasschallengeson[num] > 0 && memcmp(answer, joinpasschallenges[num], 16) == 0) + if (joinpasschallengeson[num] > 0 && memcmp(answer, joinpasschallenges[num], MD5_LEN) == 0) passed = true; // Wipe and reset the challenge so that it can't be tried against again, as a small measure against brute-force attacks. - memset(joinpasschallenges[num], 0x00, 17); + memset(joinpasschallenges[num], 0x00, MD5_LEN+1); joinpasschallengeson[num] = 0; return passed; @@ -3787,8 +3787,8 @@ void D_MakeJoinPasswordChallenge(UINT8 *num, UINT8 *question) joinpasschallengeson[(*num)] = I_GetTime(); - memset(question, 0x00, 17); - for (i = 0; i < 16; i++) + memset(question, 0x00, MD5_LEN+1); + for (i = 0; i < MD5_LEN; i++) question[i] = M_RandomByte(); // Store the answer in memory. What was the question again? diff --git a/src/md5.h b/src/md5.h index 0fe017f5..eaa85dc1 100644 --- a/src/md5.h +++ b/src/md5.h @@ -22,6 +22,8 @@ # 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 diff --git a/src/w_wad.c b/src/w_wad.c index d1c6d488..b4ae1e0a 100644 --- a/src/w_wad.c +++ b/src/w_wad.c @@ -1556,7 +1556,6 @@ void *W_CachePatchName(const char *name, INT32 tag) return W_CachePatchNum(num, tag); } #ifndef NOMD5 -#define MD5_LEN 16 /** * Prints an MD5 string into a human-readable textual format. From 7c7034a22934e26181236307555bc785fa14cb8e Mon Sep 17 00:00:00 2001 From: fickleheart Date: Sat, 9 Mar 2019 16:49:23 -0600 Subject: [PATCH 16/33] More... --- src/d_clisrv.c | 10 +++++----- src/d_clisrv.h | 2 ++ 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/d_clisrv.c b/src/d_clisrv.c index 6ff024cd..6d139114 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -1139,9 +1139,9 @@ static cl_mode_t cl_mode = CL_SEARCHING; static boolean cl_needsdownload = false; static UINT8 cl_challengenum = 0; -static UINT8 cl_challengequestion[17]; +static UINT8 cl_challengequestion[MD5_LEN+1]; static char cl_challengepassword[65]; -static UINT8 cl_challengeanswer[17]; +static UINT8 cl_challengeanswer[MD5_LEN+1]; static UINT8 cl_challengeattempted = 0; // Player name send/load @@ -1322,7 +1322,7 @@ static boolean CL_SendJoin(void) netbuffer->u.clientcfg.subversion = SUBVERSION; netbuffer->u.clientcfg.needsdownload = cl_needsdownload; netbuffer->u.clientcfg.challengenum = cl_challengenum; - memcpy(netbuffer->u.clientcfg.challengeanswer, cl_challengeanswer, 16); + memcpy(netbuffer->u.clientcfg.challengeanswer, cl_challengeanswer, MD5_LEN); return HSendPacket(servernode, true, 0, sizeof (clientconfig_pak)); } @@ -3267,8 +3267,8 @@ void D_ClientServerInit(void) gametic = 0; localgametic = 0; - memset(cl_challengequestion, 0x00, 17); - memset(cl_challengeanswer, 0x00, 17); + memset(cl_challengequestion, 0x00, MD5_LEN+1); + memset(cl_challengeanswer, 0x00, MD5_LEN+1); // do not send anything before the real begin SV_StopServer(); diff --git a/src/d_clisrv.h b/src/d_clisrv.h index d979fb28..f3a9011e 100644 --- a/src/d_clisrv.h +++ b/src/d_clisrv.h @@ -19,6 +19,8 @@ #include "tables.h" #include "d_player.h" +#include "md5.h" + // Network play related stuff. // There is a data struct that stores network // communication related stuff, and another From ad3a32f500572d0eef09fd0f041a7b0645456638 Mon Sep 17 00:00:00 2001 From: fickleheart Date: Sat, 9 Mar 2019 16:55:18 -0600 Subject: [PATCH 17/33] Handle capslock in just one place...? --- src/console.c | 10 ---------- src/d_main.c | 2 ++ src/hu_stuff.c | 10 ---------- 3 files changed, 2 insertions(+), 20 deletions(-) diff --git a/src/console.c b/src/console.c index a10d73e7..2b3ee0e2 100644 --- a/src/console.c +++ b/src/console.c @@ -1084,16 +1084,6 @@ boolean CON_Responder(event_t *ev) else if (key == KEY_KPADSLASH) key = '/'; - // capslock - if (key == KEY_CAPSLOCK) // it's a toggle. - { - if (capslock) - capslock = false; - else - capslock = true; - return true; - } - // same capslock code as hu_stuff.c's HU_responder. Check there for details. if ((key >= 'a' && key <= 'z') || (key >= 'A' && key <= 'Z')) { diff --git a/src/d_main.c b/src/d_main.c index 92c1e6ae..07cfdfb2 100644 --- a/src/d_main.c +++ b/src/d_main.c @@ -203,6 +203,8 @@ static inline void D_ModifierKeyResponder(event_t *ev) case KEY_RCTRL: ctrldown |= 0x2; return; case KEY_LALT: altdown |= 0x1; return; case KEY_RALT: altdown |= 0x2; return; + case KEY_CAPSLOCK: capslock = !capslock; return; + default: return; } else if (ev->type == ev_keyup) switch (ev->data1) diff --git a/src/hu_stuff.c b/src/hu_stuff.c index 94cca970..bd8f7fd9 100644 --- a/src/hu_stuff.c +++ b/src/hu_stuff.c @@ -1159,16 +1159,6 @@ boolean HU_Responder(event_t *ev) c = (INT32)ev->data1; - // capslock (now handled outside of chat on so that it works everytime......) - if (c && c == KEY_CAPSLOCK) // it's a toggle. - { - if (capslock) - capslock = false; - else - capslock = true; - return true; - } - #ifndef NONET if (!chat_on) { From 3bb014ea42a25de222619812f2af5ffbcd46a36a Mon Sep 17 00:00:00 2001 From: fickleheart Date: Sat, 9 Mar 2019 17:03:52 -0600 Subject: [PATCH 18/33] Make password toggle only affect password fields --- src/m_menu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/m_menu.c b/src/m_menu.c index 881b6682..f92b0e05 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -2691,7 +2691,7 @@ boolean M_Responder(event_t *ev) { if ((currentMenu->menuitems[itemOn].status & IT_CVARTYPE) == IT_CV_STRING || (currentMenu->menuitems[itemOn].status & IT_CVARTYPE) == IT_CV_PASSWORD) { - if (ch == KEY_TAB) + if (ch == KEY_TAB && (currentMenu->menuitems[itemOn].status & IT_CVARTYPE) == IT_CV_PASSWORD) ((consvar_t *)currentMenu->menuitems[itemOn].itemaction)->value ^= 1; if (shiftdown && ch >= 32 && ch <= 127) From d804dc3a34c1321a33cf1008b9c92e2449eedd79 Mon Sep 17 00:00:00 2001 From: fickleheart Date: Sat, 9 Mar 2019 17:06:44 -0600 Subject: [PATCH 19/33] Fix password auto-hiding if you type into it --- src/command.c | 3 ++- src/command.h | 3 ++- src/d_clisrv.c | 6 ------ src/d_netcmd.c | 2 +- 4 files changed, 5 insertions(+), 9 deletions(-) diff --git a/src/command.c b/src/command.c index bb2ea86e..a5d45bc1 100644 --- a/src/command.c +++ b/src/command.c @@ -1254,7 +1254,8 @@ found: var->string = var->zstring = Z_StrDup(valstr); - if (override) + if (var->flags & CV_PASSWORD); // Don't change value for password field + else if (override) var->value = overrideval; else if (var->flags & CV_FLOAT) { diff --git a/src/command.h b/src/command.h index 82dfaf8a..f9d177e2 100644 --- a/src/command.h +++ b/src/command.h @@ -95,7 +95,8 @@ typedef enum CV_HIDEN = 1024, // variable is not part of the cvar list so cannot be accessed by the console // can only be set when we have the pointer to it // used on menus - CV_CHEAT = 2048 // Don't let this be used in multiplayer unless cheats are on. + CV_CHEAT = 2048, // Don't let this be used in multiplayer unless cheats are on. + CV_PASSWORD = 4096 // Password field } cvflags_t; typedef struct CV_PossibleValue_s diff --git a/src/d_clisrv.c b/src/d_clisrv.c index 6d139114..08788613 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -2173,12 +2173,6 @@ boolean CL_Responder(event_t *ev) ch = (INT32)ev->data1; - if (ch == KEY_CAPSLOCK) // it's a toggle. - { - capslock = !capslock; - return true; - } - // Only ESC and non-keyboard keys abort connection if (ch == KEY_ESCAPE || ch >= KEY_MOUSE1) { diff --git a/src/d_netcmd.c b/src/d_netcmd.c index abc31949..1f75a3bf 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -3707,7 +3707,7 @@ static void Got_Removal(UINT8 **cp, INT32 playernum) } // Join password stuff -consvar_t cv_dummyjoinpassword = {"dummyjoinpassword", "", CV_HIDEN|CV_NOSHOWHELP, NULL, NULL, 0, NULL, NULL, 0, 0, NULL}; +consvar_t cv_dummyjoinpassword = {"dummyjoinpassword", "", CV_HIDEN|CV_NOSHOWHELP|CV_PASSWORD, NULL, NULL, 0, NULL, NULL, 0, 0, NULL}; #define NUMJOINCHALLENGES 32 static UINT8 joinpassmd5[MD5_LEN+1]; From 035ad5822c4c0aaa98795529f3d1ce5c5a9d2ad8 Mon Sep 17 00:00:00 2001 From: Alam Arias Date: Sat, 9 Mar 2019 18:17:38 -0500 Subject: [PATCH 20/33] c is only for chat_in --- src/hu_stuff.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/hu_stuff.c b/src/hu_stuff.c index bd8f7fd9..11a989f5 100644 --- a/src/hu_stuff.c +++ b/src/hu_stuff.c @@ -1130,8 +1130,6 @@ static INT16 typelines = 1; // number of drawfill lines we need when drawing the // boolean HU_Responder(event_t *ev) { - INT32 c=0; - if (ev->type != ev_keydown) return false; @@ -1157,8 +1155,6 @@ boolean HU_Responder(event_t *ev) return false; } - c = (INT32)ev->data1; - #ifndef NONET if (!chat_on) { @@ -1186,6 +1182,7 @@ boolean HU_Responder(event_t *ev) } else // if chat_on { + INT32 c = (INT32)ev->data1; // Ignore modifier keys // Note that we do this here so users can still set @@ -1201,8 +1198,6 @@ boolean HU_Responder(event_t *ev) && ev->data1 != gamecontrol[gc_talkkey][1])) return false; - c = (INT32)ev->data1; - // I know this looks very messy but this works. If it ain't broke, don't fix it! // shift LETTERS to uppercase if we have capslock or are holding shift if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) From 3e1570c59d2a3a9baad1f8b38ad8397c37f6ef97 Mon Sep 17 00:00:00 2001 From: fickleheart Date: Sat, 9 Mar 2019 22:17:16 -0600 Subject: [PATCH 21/33] Revert "Move HandleConnect to the same place as other packets" This reverts commit 6bba2f16c0c0c8dd657629e829760ecf75ce37a4. --- src/d_clisrv.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/d_clisrv.c b/src/d_clisrv.c index 08788613..6734b544 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -3944,10 +3944,6 @@ static void HandlePacketFromAwayNode(SINT8 node) Net_CloseConnection(node); break; - case PT_CLIENTJOIN: - if (server) - HandleConnect(node); - break; case PT_JOINCHALLENGE: if (server && serverrunning) { // But wait I thought I'm the server? @@ -4663,6 +4659,12 @@ FILESTAMP while (HGetPacket()) { node = (SINT8)doomcom->remotenode; + + if (netbuffer->packettype == PT_CLIENTJOIN && server) + { + HandleConnect(node); + continue; + } if (node == servernode && client && cl_mode != CL_SEARCHING) { if (netbuffer->packettype == PT_SERVERSHUTDOWN) From 386360ff43ba83d84e87d47010a79500dffbceb7 Mon Sep 17 00:00:00 2001 From: fickleheart Date: Sat, 9 Mar 2019 23:36:11 -0600 Subject: [PATCH 22/33] Properly close and reopen the client connection for password challenges --- src/d_clisrv.c | 33 +++++++++++++++++++++++++++------ 1 file changed, 27 insertions(+), 6 deletions(-) diff --git a/src/d_clisrv.c b/src/d_clisrv.c index 6734b544..b05babd6 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -1909,7 +1909,7 @@ void CL_UpdateServerList(boolean internetsearch, INT32 room) /** Called by CL_ServerConnectionTicker * * \param viams ??? - * \param asksent ??? + * \param asksent The last time we asked the server to join. We re-ask every second in case our request got lost in transmit. * \return False if the connection was aborted * \sa CL_ServerConnectionTicker * \sa CL_ConnectToServer @@ -2037,7 +2037,7 @@ static boolean CL_ServerConnectionSearchTicker(boolean viams, tic_t *asksent) * \param viams ??? * \param tmpsave The name of the gamestate file??? * \param oldtic Used for knowing when to poll events and redraw - * \param asksent ??? + * \param asksent The last time we asked the server to join. We re-ask every second in case our request got lost in transmit. * \return False if the connection was aborted * \sa CL_ServerConnectionSearchTicker * \sa CL_ConnectToServer @@ -2109,6 +2109,9 @@ static boolean CL_ServerConnectionTicker(boolean viams, const char *tmpsave, tic #endif case CL_CHALLENGE: + (*asksent) = I_GetTime() - NEWTICRATE + 2; // This is SUPPOSED to remove the delay from sending the password but it doesn't work... + break; + case CL_WAITJOINRESPONSE: case CL_WAITDOWNLOADFILESRESPONSE: case CL_CONNECTED: @@ -2226,10 +2229,26 @@ boolean CL_Responder(event_t *ev) } else if (ch == KEY_ENTER) { - // Done? - D_ComputeChallengeAnswer(cl_challengequestion, cl_challengepassword, cl_challengeanswer); - cl_mode = cl_needsdownload ? CL_ASKDOWNLOADFILES : CL_ASKJOIN; - cl_challengeattempted = 1; + // Done? Try to reconnect to the server... + if (!netgame && I_NetOpenSocket) + { + MSCloseUDPSocket(); // Tidy up before wiping the slate. + if (I_NetOpenSocket()) + { + netgame = true; + multiplayer = true; + +#ifndef NONET + SL_ClearServerList(servernode); +#endif + cl_mode = CL_SEARCHING; + + D_ComputeChallengeAnswer(cl_challengequestion, cl_challengepassword, cl_challengeanswer); + cl_challengeattempted = 1; + } + } + else + I_Error("haha that ain't it"); } return true; @@ -3956,6 +3975,8 @@ static void HandlePacketFromAwayNode(SINT8 node) cl_challengenum = netbuffer->u.joinchallenge.challengenum; memcpy(cl_challengequestion, netbuffer->u.joinchallenge.question, 16); + D_CloseConnection(); // Don't need to stay connected while challenging + cl_mode = CL_CHALLENGE; if (cl_challengeattempted == 2) From ce8150441035056f36b391e65ff6a128da285134 Mon Sep 17 00:00:00 2001 From: fickleheart Date: Sat, 9 Mar 2019 23:56:13 -0600 Subject: [PATCH 23/33] Try a partial disconnect instead --- src/d_clisrv.c | 26 ++++++++------------------ 1 file changed, 8 insertions(+), 18 deletions(-) diff --git a/src/d_clisrv.c b/src/d_clisrv.c index b05babd6..170c9645 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -2109,7 +2109,7 @@ static boolean CL_ServerConnectionTicker(boolean viams, const char *tmpsave, tic #endif case CL_CHALLENGE: - (*asksent) = I_GetTime() - NEWTICRATE + 2; // This is SUPPOSED to remove the delay from sending the password but it doesn't work... + (*asksent) = I_GetTime() - NEWTICRATE; // This is SUPPOSED to remove the delay from sending the password but it doesn't work... break; case CL_WAITJOINRESPONSE: @@ -2229,26 +2229,16 @@ boolean CL_Responder(event_t *ev) } else if (ch == KEY_ENTER) { - // Done? Try to reconnect to the server... - if (!netgame && I_NetOpenSocket) - { - MSCloseUDPSocket(); // Tidy up before wiping the slate. - if (I_NetOpenSocket()) - { - netgame = true; - multiplayer = true; + netgame = true; + multiplayer = true; #ifndef NONET - SL_ClearServerList(servernode); + SL_ClearServerList(servernode); #endif - cl_mode = CL_SEARCHING; + cl_mode = CL_SEARCHING; - D_ComputeChallengeAnswer(cl_challengequestion, cl_challengepassword, cl_challengeanswer); - cl_challengeattempted = 1; - } - } - else - I_Error("haha that ain't it"); + D_ComputeChallengeAnswer(cl_challengequestion, cl_challengepassword, cl_challengeanswer); + cl_challengeattempted = 1; } return true; @@ -3975,7 +3965,7 @@ static void HandlePacketFromAwayNode(SINT8 node) cl_challengenum = netbuffer->u.joinchallenge.challengenum; memcpy(cl_challengequestion, netbuffer->u.joinchallenge.question, 16); - D_CloseConnection(); // Don't need to stay connected while challenging + Net_CloseConnection(node|FORCECLOSE); // Don't need to stay connected while challenging cl_mode = CL_CHALLENGE; From bafa4cee7b3da60bdb1cad4ea4d9b37863418ac9 Mon Sep 17 00:00:00 2001 From: fickleheart Date: Sun, 10 Mar 2019 12:50:24 -0500 Subject: [PATCH 24/33] Improve stability when joining netgames maybe --- src/d_clisrv.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/d_clisrv.c b/src/d_clisrv.c index 170c9645..1da11e71 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -2084,14 +2084,20 @@ static boolean CL_ServerConnectionTicker(boolean viams, const char *tmpsave, tic CL_PrepareDownloadSaveGame(tmpsave); #endif if (CL_SendJoin()) + { + *asksent = I_GetTime(); cl_mode = CL_WAITJOINRESPONSE; + } break; case CL_ASKDOWNLOADFILES: cl_needsdownload = true; if (CL_SendJoin()) + { + *asksent = I_GetTime(); cl_mode = CL_WAITDOWNLOADFILESRESPONSE; + } break; @@ -2114,6 +2120,13 @@ static boolean CL_ServerConnectionTicker(boolean viams, const char *tmpsave, tic case CL_WAITJOINRESPONSE: case CL_WAITDOWNLOADFILESRESPONSE: + if (*asksent + NEWTICRATE < I_GetTime() && CL_SendJoin()) + { + *asksent = I_GetTime(); + } + + break; + case CL_CONNECTED: default: break; From 82f3d2cdb8c7f71d5b63f32c6fb5834cf6963a6c Mon Sep 17 00:00:00 2001 From: fickleheart Date: Sun, 10 Mar 2019 15:48:11 -0500 Subject: [PATCH 25/33] Skip password check if node is already in-game? idk --- 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 1da11e71..ca9e2084 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -3775,7 +3775,7 @@ static void HandleConnect(SINT8 node) boolean newnode = false; #endif - if (node != servernode && D_IsJoinPasswordOn()) + if (node != servernode && !nodeingame[node] && D_IsJoinPasswordOn()) { // Ensure node sent the correct password challenge boolean passed = false; From 0c6f3c58e6628fcde24a407d9205a01e4bbe414f Mon Sep 17 00:00:00 2001 From: fickleheart Date: Sun, 10 Mar 2019 16:06:46 -0500 Subject: [PATCH 26/33] Update packettypenames --- src/d_net.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/d_net.c b/src/d_net.c index 530ee6df..9f719967 100644 --- a/src/d_net.c +++ b/src/d_net.c @@ -821,10 +821,6 @@ static const char *packettypename[NUMPACKETTYPE] = "CLIENTMIS", "CLIENT2CMD", "CLIENT2MIS", - "CLIENT3CMD", - "CLIENT3MIS", - "CLIENT4CMD", - "CLIENT4MIS", "NODEKEEPALIVE", "NODEKEEPALIVEMIS", "SERVERTICS", @@ -841,6 +837,15 @@ static const char *packettypename[NUMPACKETTYPE] = "RESYNCHEND", "RESYNCHGET", + "CLIENT3CMD", + "CLIENT3MIS", + "CLIENT4CMD", + "CLIENT4MIS", + "BASICKEEPALIVE", + + "JOINCHALLENGE", + "DOWNLOADFILESOKAY", + "FILEFRAGMENT", "TEXTCMD", "TEXTCMD2", From 693da54d94481bf65a63f47bea19cf4d39829114 Mon Sep 17 00:00:00 2001 From: fickleheart Date: Sun, 10 Mar 2019 16:22:03 -0500 Subject: [PATCH 27/33] Properly close the connection on the server's side... --- 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 ca9e2084..be39f707 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -3789,7 +3789,7 @@ static void HandleConnect(SINT8 node) netbuffer->packettype = PT_JOINCHALLENGE; HSendPacket(node, true, 0, sizeof(joinchallenge_pak)); - //Net_CloseConnection(node); + Net_CloseConnection(node); return; } From f70163cfb9a3e253aab2e9bed07da810da8279d6 Mon Sep 17 00:00:00 2001 From: fickleheart Date: Sun, 10 Mar 2019 17:00:27 -0500 Subject: [PATCH 28/33] Show notice of a password-protected server on the join screen --- src/d_clisrv.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/d_clisrv.c b/src/d_clisrv.c index be39f707..4954a762 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -1179,6 +1179,8 @@ static void CV_LoadPlayerNames(UINT8 **p) } #ifdef CLIENT_LOADINGSCREEN +static UINT32 SL_SearchServer(INT32 node); + // // CL_DrawConnectionStatus // @@ -1212,12 +1214,28 @@ static inline void CL_DrawConnectionStatus(void) { char asterisks[33]; size_t sl = min(32, strlen(cl_challengepassword)); + UINT32 i; memset(asterisks, '*', sl); memset(asterisks+sl, 0, 33-sl); V_DrawString(BASEVIDWIDTH/2-128, BASEVIDHEIGHT-24, V_MONOSPACE|V_ALLOWLOWERCASE, asterisks); + i = SL_SearchServer(servernode); + + if (i == -1) + { + M_DrawTextBox(BASEVIDWIDTH/2-128-8, BASEVIDHEIGHT/2-8, 32, 1); + V_DrawCenteredString(BASEVIDWIDTH/2, BASEVIDHEIGHT/2, V_REDMAP, M_GetText("This server is password protected.")); + } + else + { + M_DrawTextBox(BASEVIDWIDTH/2-128-8, BASEVIDHEIGHT/2-8-8, 32, 3); + V_DrawCenteredString(BASEVIDWIDTH/2, BASEVIDHEIGHT/2-8, V_REDMAP, M_GetText("This server,")); + V_DrawCenteredString(BASEVIDWIDTH/2, BASEVIDHEIGHT/2, V_ALLOWLOWERCASE, serverlist[i].info.servername); + V_DrawCenteredString(BASEVIDWIDTH/2, BASEVIDHEIGHT/2+8, V_REDMAP, M_GetText("is password protected.")); + } + cltext = M_GetText(cl_challengeattempted ? "Incorrect password. Please try again." : "Please enter the server password."); } break; From 4a8d682b434b17bb1c8792fb8a25e88b3c097994 Mon Sep 17 00:00:00 2001 From: fickleheart Date: Sun, 10 Mar 2019 17:25:55 -0500 Subject: [PATCH 29/33] Draw a padlock on-screen! --- src/d_clisrv.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/d_clisrv.c b/src/d_clisrv.c index 4954a762..01304f38 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -1220,6 +1220,7 @@ static inline void CL_DrawConnectionStatus(void) memset(asterisks+sl, 0, 33-sl); V_DrawString(BASEVIDWIDTH/2-128, BASEVIDHEIGHT-24, V_MONOSPACE|V_ALLOWLOWERCASE, asterisks); + V_DrawFixedPatch((BASEVIDWIDTH/2) << FRACBITS, (BASEVIDHEIGHT/2) << FRACBITS, FRACUNIT, 0, W_CachePatchName("BSRVLOCK", PU_CACHE), NULL); i = SL_SearchServer(servernode); @@ -1230,10 +1231,10 @@ static inline void CL_DrawConnectionStatus(void) } else { - M_DrawTextBox(BASEVIDWIDTH/2-128-8, BASEVIDHEIGHT/2-8-8, 32, 3); - V_DrawCenteredString(BASEVIDWIDTH/2, BASEVIDHEIGHT/2-8, V_REDMAP, M_GetText("This server,")); - V_DrawCenteredString(BASEVIDWIDTH/2, BASEVIDHEIGHT/2, V_ALLOWLOWERCASE, serverlist[i].info.servername); - V_DrawCenteredString(BASEVIDWIDTH/2, BASEVIDHEIGHT/2+8, V_REDMAP, M_GetText("is password protected.")); + M_DrawTextBox(BASEVIDWIDTH/2-128-8, BASEVIDHEIGHT/2-8, 32, 3); + V_DrawCenteredString(BASEVIDWIDTH/2, BASEVIDHEIGHT/2, V_REDMAP, M_GetText("This server,")); + V_DrawCenteredString(BASEVIDWIDTH/2, BASEVIDHEIGHT/2+8, V_ALLOWLOWERCASE, serverlist[i].info.servername); + V_DrawCenteredString(BASEVIDWIDTH/2, BASEVIDHEIGHT/2+16, V_REDMAP, M_GetText("is password protected.")); } cltext = M_GetText(cl_challengeattempted ? "Incorrect password. Please try again." : "Please enter the server password."); @@ -2133,7 +2134,7 @@ static boolean CL_ServerConnectionTicker(boolean viams, const char *tmpsave, tic #endif case CL_CHALLENGE: - (*asksent) = I_GetTime() - NEWTICRATE; // This is SUPPOSED to remove the delay from sending the password but it doesn't work... + (*asksent) = I_GetTime() - NEWTICRATE; // Send password immediately upon entering break; case CL_WAITJOINRESPONSE: From 048ce8496fd2d5d72b04395a098904be2c41a3bc Mon Sep 17 00:00:00 2001 From: fickleheart Date: Sun, 10 Mar 2019 17:36:16 -0500 Subject: [PATCH 30/33] Make noises on the password entry screen --- src/d_clisrv.c | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/src/d_clisrv.c b/src/d_clisrv.c index 01304f38..98330c84 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -4001,11 +4001,23 @@ static void HandlePacketFromAwayNode(SINT8 node) cl_mode = CL_CHALLENGE; - if (cl_challengeattempted == 2) + switch (cl_challengeattempted) { - // We already sent a correct password, so throw it back up again. - D_ComputeChallengeAnswer(cl_challengequestion, cl_challengepassword, cl_challengeanswer); - cl_mode = CL_ASKJOIN; + case 2: + // We already sent a correct password, so throw it back up again. + D_ComputeChallengeAnswer(cl_challengequestion, cl_challengepassword, cl_challengeanswer); + cl_mode = CL_ASKJOIN; + break; + + case 1: + // We entered the wrong password! + S_StartSound(NULL, sfx_s26d); + break; + + default: + // First entry to the password screen. + S_StartSound(NULL, sfx_s224); + break; } } break; @@ -4064,6 +4076,9 @@ static void HandlePacketFromAwayNode(SINT8 node) break; } + if (cl_challengeattempted == 1) // Successful password noise. + S_StartSound(NULL, sfx_s221); + cl_challengeattempted = 2; CONS_Printf("trying to download\n"); if (CL_SendRequestFile()) @@ -4085,6 +4100,9 @@ static void HandlePacketFromAwayNode(SINT8 node) if (cl_mode != CL_WAITJOINRESPONSE) break; + if (cl_challengeattempted == 1) // Successful password noise. + S_StartSound(NULL, sfx_s221); + if (client) { maketic = gametic = neededtic = (tic_t)LONG(netbuffer->u.servercfg.gametic); From 0e586537271ddd2cd86300e68d81d2b5da1c2901 Mon Sep 17 00:00:00 2001 From: fickleheart Date: Sun, 10 Mar 2019 17:43:39 -0500 Subject: [PATCH 31/33] Make sure we don't write kartspeed beyond SV_SPEEDMASK --- 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 98330c84..0202ff6f 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -1364,7 +1364,7 @@ static void SV_SendServerInfo(INT32 node, tic_t servertime) netbuffer->u.serverinfo.cheatsenabled = CV_CheatsEnabled(); netbuffer->u.serverinfo.kartvars = (UINT8) ( - cv_kartspeed.value | + (cv_kartspeed.value & SV_SPEEDMASK) | (dedicated ? SV_DEDICATED : 0) | (D_IsJoinPasswordOn() ? SV_PASSWORD : 0) ); From c0ea78590025a618d82b8fbe1d962a3a1ee52a34 Mon Sep 17 00:00:00 2001 From: fickleheart Date: Sun, 10 Mar 2019 17:54:17 -0500 Subject: [PATCH 32/33] Remove unnecessary padding byte from stored challenge answers --- src/d_netcmd.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/d_netcmd.c b/src/d_netcmd.c index 2c6d6003..7c7f5690 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -3712,7 +3712,7 @@ consvar_t cv_dummyjoinpassword = {"dummyjoinpassword", "", CV_HIDEN|CV_NOSHOWHEL #define NUMJOINCHALLENGES 32 static UINT8 joinpassmd5[MD5_LEN+1]; boolean joinpasswordset = false; -static UINT8 joinpasschallenges[NUMJOINCHALLENGES][MD5_LEN+1]; +static UINT8 joinpasschallenges[NUMJOINCHALLENGES][MD5_LEN]; static tic_t joinpasschallengeson[NUMJOINCHALLENGES]; boolean D_IsJoinPasswordOn(void) @@ -3752,7 +3752,7 @@ boolean D_VerifyJoinPasswordChallenge(UINT8 num, UINT8 *answer) passed = true; // Wipe and reset the challenge so that it can't be tried against again, as a small measure against brute-force attacks. - memset(joinpasschallenges[num], 0x00, MD5_LEN+1); + memset(joinpasschallenges[num], 0x00, MD5_LEN); joinpasschallengeson[num] = 0; return passed; @@ -3787,7 +3787,7 @@ void D_MakeJoinPasswordChallenge(UINT8 *num, UINT8 *question) joinpasschallengeson[(*num)] = I_GetTime(); - memset(question, 0x00, MD5_LEN+1); + memset(question, 0x00, MD5_LEN); for (i = 0; i < MD5_LEN; i++) question[i] = M_RandomByte(); From c65ff70faf9530717dfe1dfafb281ec4ff3f2dd7 Mon Sep 17 00:00:00 2001 From: fickleheart Date: Sun, 10 Mar 2019 18:09:15 -0500 Subject: [PATCH 33/33] Deduplicate character shifting code --- src/console.c | 16 ++++++++++++++++ src/console.h | 2 ++ src/d_clisrv.c | 18 +----------------- src/hu_stuff.c | 13 +------------ 4 files changed, 20 insertions(+), 29 deletions(-) diff --git a/src/console.c b/src/console.c index 2b3ee0e2..44bb03a3 100644 --- a/src/console.c +++ b/src/console.c @@ -544,6 +544,22 @@ static void CON_MoveConsole(void) } } +INT32 CON_ShiftChar(INT32 ch) +{ + if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z')) + { + if (shiftdown ^ capslock) + ch = shiftxform[ch]; + } + else // if we're holding shift we should still shift non letter symbols + { + if (shiftdown) + ch = shiftxform[ch]; + } + + return ch; +} + // Clear time of console heads up messages // void CON_ClearHUD(void) diff --git a/src/console.h b/src/console.h index 98df6ee2..11621746 100644 --- a/src/console.h +++ b/src/console.h @@ -44,6 +44,8 @@ extern UINT8 *yellowmap, *purplemap, *greenmap, *bluemap, *graymap, *redmap, *or // Console bg color (auto updated to match) extern UINT8 *consolebgmap; +INT32 CON_ShiftChar(INT32 ch); + void CON_SetupBackColormap(void); void CON_ClearHUD(void); // clear heads up messages diff --git a/src/d_clisrv.c b/src/d_clisrv.c index 0202ff6f..5fe378e0 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -2228,24 +2228,8 @@ boolean CL_Responder(event_t *ev) len = strlen(cl_challengepassword); if (len < 64) { - - // shifting code stolen from lat by fickle, thx :) - - // I know this looks very messy but this works. If it ain't broke, don't fix it! - // shift LETTERS to uppercase if we have capslock or are holding shift - if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z')) - { - if (shiftdown ^ capslock) - ch = shiftxform[ch]; - } - else // if we're holding shift we should still shift non letter symbols - { - if (shiftdown) - ch = shiftxform[ch]; - } - cl_challengepassword[len+1] = 0; - cl_challengepassword[len] = ch; + cl_challengepassword[len] = CON_ShiftChar(ch); } cl_challengeattempted = 0; diff --git a/src/hu_stuff.c b/src/hu_stuff.c index a540e0a1..b4357073 100644 --- a/src/hu_stuff.c +++ b/src/hu_stuff.c @@ -1293,18 +1293,7 @@ boolean HU_Responder(event_t *ev) && ev->data1 != gamecontrol[gc_talkkey][1])) return false; - // I know this looks very messy but this works. If it ain't broke, don't fix it! - // shift LETTERS to uppercase if we have capslock or are holding shift - if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) - { - if (shiftdown ^ capslock) - c = shiftxform[c]; - } - else // if we're holding shift we should still shift non letter symbols - { - if (shiftdown) - c = shiftxform[c]; - } + c = CON_ShiftChar(c); // pasting. pasting is cool. chat is a bit limited, though :( if (((c == 'v' || c == 'V') && ctrldown) && !CHAT_MUTE)