Hello there,
in case you find this useful, here is a small patch to slightly improve
the security by proposing an alternative to sending a clear-text
password over the network.
This small patch introduces the possibility to avoid sending a
clear-text password over the network by using a MD5 hash instead; the
provided code uses this facility with the 'rconPassword'.
The compatibility with legacy clients or servers is also maintained, ie
a MD5-enabled server still allows legacy clients to send a clear-text
'rconPassword' and vice-versa.
Basically, the patch introduces a new function, Com_MD5String(), which
take a string with an optionnal prefix and returns the calculated MD5
hash. A new cvar, 'sv_MD5', is added in the server and propagated
through the server infostring to let any clients know about the MD5
availibility.
To avoid sending the password by itself (either in plain-text or its MD5
counterpart), the MD5 hash is created using the 'rconPassword' prefixed
by the client's current challenge; 2 clients on the same server will
then send 2 different MD5 hashes.
Have a nice day
ps: please, add a notice on the ioq3 ML web page to state that only
members of this ML are allowed to posts to this ML
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 \
_______________________________________________
ioquake3 mailing list
ioquake3@lists.ioquake.org
http://lists.ioquake.org/listinfo.cgi/ioquake3-ioquake.org
By sending this message I agree to love ioquake3 and libsdl.