From 92802a10c2bc0d9456b1b75ffdea992c25619350 Mon Sep 17 00:00:00 2001 From: divverent Date: Fri, 2 Oct 2009 09:22:33 +0000 Subject: [PATCH] sorry for this 100% untested change... making srcon use the new challenge-based protocol (but rcon_secure 1 and rcon still uses the time-based one as that's faster and more reliable). git-svn-id: svn://svn.icculus.org/twilight/trunk/darkplaces@9279 d7cf8633-e32d-0410-b094-e92efae38249 --- client.h | 6 ++++++ host_cmd.c | 15 ++++++++++++--- netconn.c | 24 ++++++++++++++++++++++++ 3 files changed, 42 insertions(+), 3 deletions(-) diff --git a/client.h b/client.h index f6a8a4d6..acab743a 100644 --- a/client.h +++ b/client.h @@ -581,6 +581,12 @@ typedef struct client_static_s // (kept outside client_state_t because it's used between levels) protocolversion_t protocol; +#define MAX_RCONS 64 + int rcon_trying; + lhnetaddress_t rcon_addresses[MAX_RCONS]; + char rcon_commands[MAX_RCONS][MAX_INPUTLINE]; + int rcon_ringpos; + // connection information // 0 to SIGNONS int signon; diff --git a/host_cmd.c b/host_cmd.c index dc84be9d..895bb2d2 100644 --- a/host_cmd.c +++ b/host_cmd.c @@ -33,7 +33,7 @@ cvar_t sv_adminnick = {CVAR_SAVE, "sv_adminnick", "", "nick name to use for admi cvar_t sv_status_privacy = {CVAR_SAVE, "sv_status_privacy", "0", "do not show IP addresses in 'status' replies to clients"}; cvar_t sv_status_show_qcstatus = {CVAR_SAVE, "sv_status_show_qcstatus", "0", "show the 'qcstatus' field in status replies, not the 'frags' field. Turn this on if your mod uses this field, and the 'frags' field on the other hand has no meaningful value."}; cvar_t rcon_password = {CVAR_PRIVATE, "rcon_password", "", "password to authenticate rcon commands; NOTE: changing rcon_secure clears rcon_password, so set rcon_secure always before rcon_password"}; -cvar_t rcon_secure = {CVAR_NQUSERINFOHACK, "rcon_secure", "0", "force secure rcon authentication; NOTE: changing rcon_secure clears rcon_password, so set rcon_secure always before rcon_password"}; +cvar_t rcon_secure = {CVAR_NQUSERINFOHACK, "rcon_secure", "0", "force secure rcon authentication (1 = time based, 2 = challenge based); NOTE: changing rcon_secure clears rcon_password, so set rcon_secure always before rcon_password"}; cvar_t rcon_address = {0, "rcon_address", "", "server address to send rcon commands to (when not connected to a server)"}; cvar_t team = {CVAR_USERINFO | CVAR_SAVE, "team", "none", "QW team (4 character limit, example: blue)"}; cvar_t skin = {CVAR_USERINFO | CVAR_SAVE, "skin", "", "QW player skin name (example: base)"}; @@ -2436,10 +2436,19 @@ void Host_Rcon_f (void) // credit: taken from QuakeWorld LHNETADDRESS_FromString(&to, rcon_address.string, sv_netport.integer); } mysocket = NetConn_ChooseClientSocketForAddress(&to); - if (mysocket) + if (mysocket && Cmd_Args()[0]) { // simply put together the rcon packet and send it - if(Cmd_Argv(0)[0] == 's' || rcon_secure.integer) + if(Cmd_Argv(0)[0] == 's' || rcon_secure.integer > 1) + { + if(!cls.rcon_commands[cls.rcon_ringpos][0]) + ++cls.rcon_trying; + strlcpy(cls.rcon_commands[cls.rcon_ringpos], Cmd_Args(), sizeof(cls.rcon_commands[cls.rcon_ringpos])); + cls.rcon_addresses[cls.rcon_ringpos] = to; + cls.rcon_ringpos = (cls.rcon_ringpos) % 64; + NetConn_WriteString(mysocket, "\377\377\377\377getchallenge", &to); + } + else if(rcon_secure.integer) { char buf[1500]; char argbuf[1500]; diff --git a/netconn.c b/netconn.c index 80355210..1dfb0cc0 100755 --- a/netconn.c +++ b/netconn.c @@ -1554,6 +1554,30 @@ static int NetConn_ClientParsePacket(lhnetsocket_t *mysocket, unsigned char *dat Com_HexDumpToConsole(data, length); } + if (length > 10 && !memcmp(string, "challenge ", 10) && cls.rcon_trying) + { + int i; + for (i = 0;i < MAX_RCONS;i++) + if(cls.rcon_commands[i][0]) + if (!LHNETADDRESS_Compare(peeraddress, &cls.rcon_addresses[i])) + break; + if (i < MAX_RCONS) + { + char buf[1500]; + char argbuf[1500]; + dpsnprintf(argbuf, sizeof(argbuf), "%s %s", string + 10, cls.rcon_commands[i]); + memcpy(buf, "\377\377\377\377srcon HMAC-MD4 CHALLENGE ", 29); + if(HMAC_MDFOUR_16BYTES((unsigned char *) (buf + 29), (unsigned char *) argbuf, strlen(argbuf), (unsigned char *) rcon_password.string, strlen(rcon_password.string))) + { + buf[45] = ' '; + strlcpy(buf + 46, argbuf, sizeof(buf) - 46); + NetConn_Write(mysocket, buf, 46 + strlen(buf + 46), peeraddress); + cls.rcon_commands[i][0] = 0; + --cls.rcon_trying; + return true; // we used up the challenge, so we can't use this oen for connecting now anyway + } + } + } if (length > 10 && !memcmp(string, "challenge ", 10) && cls.connect_trying) { // darkplaces or quake3 -- 2.39.2