Index: code/server/server.h =================================================================== --- code/server/server.h (révision 1803) +++ code/server/server.h (copie de travail) @@ -282,6 +282,7 @@ extern cvar_t *sv_lanForceRate; extern cvar_t *sv_strictAuth; extern cvar_t *sv_banFile; +extern cvar_t *sv_MD5; // uZu - let clients know about MD5 availibility extern serverBan_t serverBans[SERVER_MAXBANS]; extern int serverBansCount; Index: code/server/sv_init.c =================================================================== --- code/server/sv_init.c (révision 1803) +++ code/server/sv_init.c (copie de travail) @@ -644,6 +644,9 @@ sv_minPing = Cvar_Get ("sv_minPing", "0", CVAR_ARCHIVE | CVAR_SERVERINFO ); sv_maxPing = Cvar_Get ("sv_maxPing", "0", CVAR_ARCHIVE | CVAR_SERVERINFO ); sv_floodProtect = Cvar_Get ("sv_floodProtect", "1", CVAR_ARCHIVE | CVAR_SERVERINFO ); + // uZu - let clients know about MD5 availibility + sv_MD5 = Cvar_Get ("sv_MD5", "1", CVAR_SERVERINFO | CVAR_ROM); + // !uZu // systeminfo Cvar_Get ("sv_cheats", "1", CVAR_SYSTEMINFO | CVAR_ROM ); Index: code/server/sv_main.c =================================================================== --- code/server/sv_main.c (révision 1803) +++ code/server/sv_main.c (copie de travail) @@ -58,6 +58,7 @@ cvar_t *sv_lanForceRate; // dedicated 1 (LAN) server forces local client rates to 99999 (bug #491) cvar_t *sv_strictAuth; cvar_t *sv_banFile; +cvar_t *sv_MD5; // uZu - let clients know about MD5 availibility serverBan_t serverBans[SERVER_MAXBANS]; int serverBansCount = 0; @@ -660,6 +661,10 @@ Info_SetValueForKey( infostring, "game", gamedir ); } + // uZu - let clients know about MD5 availibility + Info_SetValueForKey( infostring, "sv_MD5", va("%i", sv_MD5->integer) ); + // !uZu + NET_OutOfBandPrint( NS_SERVER, from, "infoResponse\n%s", infostring ); } @@ -690,6 +695,11 @@ #define SV_OUTPUTBUF_LENGTH (1024 - 16) char sv_outputbuf[SV_OUTPUTBUF_LENGTH]; char *cmd_aux; + // uZu - use the current client's challenge as MD5 hash prefix + challenge_t *challenge; + char challenge_str[12]; + int i; + // !uZu // Prevent using rcon as an amplifier and make dictionary attacks impractical if ( SVC_RateLimitAddress( from, 10, 1000 ) ) { @@ -698,8 +708,22 @@ return; } + // uZu - avoid clear text password but support legacy clients + challenge = &svs.challenges[0]; + for (i = 0 ; i < MAX_CHALLENGES ; i++, challenge++) { + if ( challenge->connected && NET_CompareAdr(from, challenge->adr) ) { + // found the current client's challenge + break; + } + } + Com_sprintf( challenge_str, sizeof(challenge_str), "%d", challenge->challenge ); + // !uZu + if ( !strlen( sv_rconPassword->string ) || - strcmp (Cmd_Argv(1), sv_rconPassword->string) ) { + // uZu - first check the MD5 hash + (strcmp (Cmd_Argv(1), Com_MD5String(sv_rconPassword->string, challenge_str, sizeof(challenge_str))) && + // !uZu + strcmp (Cmd_Argv(1), sv_rconPassword->string)) ) { static leakyBucket_t bucket; // Make DoS via rcon impractical Index: code/qcommon/md5.c =================================================================== --- code/qcommon/md5.c (révision 1803) +++ code/qcommon/md5.c (copie de travail) @@ -308,3 +308,27 @@ } return final; } + +// uZu - create and returns the MD5 hash of a string +char *Com_MD5String( const char *string, const char *prefix, int prefix_len ) +{ + MD5_CTX md5; + static char final[33] = {""}; + unsigned char digest[16] = {""}; + int i; + + MD5Init(&md5); + + if (prefix_len && *prefix) + MD5Update(&md5 , (unsigned char *)prefix, prefix_len); + + MD5Update(&md5, (unsigned char *)string, sizeof(string)); + MD5Final(&md5, digest); + final[0] = '\0'; + for(i = 0; i < 16; i++) { + Q_strcat(final, sizeof(final), va("%02X", digest[i])); + } + return final; +} +// !uZu + Index: code/qcommon/qcommon.h =================================================================== --- code/qcommon/qcommon.h (révision 1803) +++ code/qcommon/qcommon.h (copie de travail) @@ -803,6 +803,9 @@ int Com_Milliseconds( void ); // will be journaled properly unsigned Com_BlockChecksum( const void *buffer, int length ); char *Com_MD5File(const char *filename, int length, const char *prefix, int prefix_len); +// uZu create and returns the MD5 hash of a string +char *Com_MD5String(const char *string, const char *prefix, int prefix_len); +// !uZu int Com_Filter(char *filter, char *name, int casesensitive); int Com_FilterPath(char *filter, char *name, int casesensitive); int Com_RealTime(qtime_t *qtime); Index: code/client/cl_main.c =================================================================== --- code/client/cl_main.c (révision 1803) +++ code/client/cl_main.c (copie de travail) @@ -1606,7 +1606,14 @@ void CL_Rcon_f( void ) { char message[MAX_RCON_MESSAGE]; netadr_t to; + // uZu - to know if a server has MD5 support + const char *serverInfo; + char challenge_str[12]; + serverInfo = cl.gameState.stringData + + cl.gameState.stringOffsets[ CS_SERVERINFO ]; + // !uZu + if ( !rcon_client_password->string ) { Com_Printf ("You must set 'rconpassword' before\n" "issuing an rcon command.\n"); @@ -1621,7 +1628,13 @@ Q_strcat (message, MAX_RCON_MESSAGE, "rcon "); - Q_strcat (message, MAX_RCON_MESSAGE, rcon_client_password->string); + // uZu - if server has MD5 support, send the MD5 hash of the + // current challenge+password instead of the clear-text password + Com_sprintf( challenge_str, sizeof(challenge_str), "%d", clc.challenge ); + Q_strcat (message, MAX_RCON_MESSAGE, strlen(Info_ValueForKey(serverInfo, "sv_MD5")) ? + Com_MD5String(rcon_client_password->string, challenge_str, sizeof(challenge_str)) : + rcon_client_password->string); + // !uZu Q_strcat (message, MAX_RCON_MESSAGE, " "); // https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=543 Index: Makefile =================================================================== --- Makefile (révision 1803) +++ Makefile (copie de travail) @@ -1634,6 +1634,7 @@ $(B)/ded/cvar.o \ $(B)/ded/files.o \ $(B)/ded/md4.o \ + $(B)/ded/md5.o \ $(B)/ded/msg.o \ $(B)/ded/net_chan.o \ $(B)/ded/net_ip.o \