summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/console_cmds.cpp7
-rw-r--r--src/network/core/config.h2
-rw-r--r--src/network/network_client.cpp69
-rw-r--r--src/network/network_server.cpp4
4 files changed, 77 insertions, 5 deletions
diff --git a/src/console_cmds.cpp b/src/console_cmds.cpp
index af5feb4fb..96b6a9735 100644
--- a/src/console_cmds.cpp
+++ b/src/console_cmds.cpp
@@ -1326,6 +1326,8 @@ DEF_CONSOLE_HOOK(ConHookRconPW)
return true;
}
+extern void HashCurrentCompanyPassword();
+
/* Also use from within player_gui to change the password graphically */
bool NetworkChangeCompanyPassword(byte argc, char *argv[])
{
@@ -1346,8 +1348,11 @@ bool NetworkChangeCompanyPassword(byte argc, char *argv[])
ttd_strlcpy(_network_player_info[_local_player].password, argv[0], sizeof(_network_player_info[_local_player].password));
- if (!_network_server)
+ if (!_network_server) {
SEND_COMMAND(PACKET_CLIENT_SET_PASSWORD)(_network_player_info[_local_player].password);
+ } else {
+ HashCurrentCompanyPassword();
+ }
IConsolePrintF(_icolour_warn, "'company_pw' changed to: %s", _network_player_info[_local_player].password);
diff --git a/src/network/core/config.h b/src/network/core/config.h
index 6fcbf7da2..f2f21c59d 100644
--- a/src/network/core/config.h
+++ b/src/network/core/config.h
@@ -29,7 +29,7 @@ enum {
NETWORK_HOSTNAME_LENGTH = 80, ///< The maximum length of the host name, in bytes including '\0'
NETWORK_UNIQUE_ID_LENGTH = 33, ///< The maximum length of the unique id of the clients, in bytes including '\0'
NETWORK_REVISION_LENGTH = 15, ///< The maximum length of the revision, in bytes including '\0'
- NETWORK_PASSWORD_LENGTH = 20, ///< The maximum length of the password, in bytes including '\0'
+ NETWORK_PASSWORD_LENGTH = 33, ///< The maximum length of the password, in bytes including '\0' (must be >= NETWORK_UNIQUE_ID_LENGTH)
NETWORK_PLAYERS_LENGTH = 200, ///< The maximum length for the list of players that controls a company, in bytes including '\0'
NETWORK_CLIENT_NAME_LENGTH = 25, ///< The maximum length of a player, in bytes including '\0'
NETWORK_RCONCOMMAND_LENGTH = 500, ///< The maximum length of a rconsole command, in bytes including '\0'
diff --git a/src/network/network_client.cpp b/src/network/network_client.cpp
index d7f7a7ee8..7c27e0b46 100644
--- a/src/network/network_client.cpp
+++ b/src/network/network_client.cpp
@@ -23,6 +23,7 @@
#include "../ai/ai.h"
#include "../helpers.hpp"
#include "../fileio.h"
+#include "../md5.h"
// This file handles all the client-commands
@@ -32,6 +33,59 @@
static uint32 last_ack_frame;
+/** One bit of 'entropy' used to generate a salt for the company passwords. */
+static uint32 _password_game_seed;
+/** The other bit of 'entropy' used to generate a salt for the company passwords. */
+static char _password_server_unique_id[NETWORK_UNIQUE_ID_LENGTH];
+
+/** Make sure the unique ID length is the same as a md5 hash. */
+assert_compile(NETWORK_UNIQUE_ID_LENGTH == 16 * 2 + 1);
+
+/**
+ * Generates a hashed password for the company name.
+ * @param password the password to 'encrypt'.
+ * @return the hashed password.
+ */
+static const char *GenerateCompanyPasswordHash(const char *password)
+{
+ if (StrEmpty(password)) return password;
+
+ char salted_password[NETWORK_UNIQUE_ID_LENGTH];
+
+ memset(salted_password, 0, sizeof(salted_password));
+ snprintf(salted_password, sizeof(salted_password), "%s", password);
+ /* Add the game seed and the server's unique ID as the salt. */
+ for (uint i = 0; i < NETWORK_UNIQUE_ID_LENGTH; i++) salted_password[i] ^= _password_server_unique_id[i] ^ (_password_game_seed >> i);
+
+ md5_state_t state;
+ md5_byte_t digest[16];
+ static char hashed_password[NETWORK_UNIQUE_ID_LENGTH];
+
+ /* Generate the MD5 hash */
+ md5_init(&state);
+ md5_append(&state, (const md5_byte_t*)salted_password, sizeof(salted_password));
+ md5_finish(&state, digest);
+
+ for (int di = 0; di < 16; di++) sprintf(hashed_password + di * 2, "%02x", digest[di]);
+
+ return hashed_password;
+}
+
+/**
+ * Hash the current company password; used when the server 'player' sets his/her password.
+ */
+void HashCurrentCompanyPassword()
+{
+ if (StrEmpty(_network_player_info[_local_player].password)) return;
+
+ _password_game_seed = _patches.generation_seed;
+ snprintf(_password_server_unique_id, sizeof(_password_server_unique_id), _network_unique_id);
+
+ const char *new_pw = GenerateCompanyPasswordHash(_network_player_info[_local_player].password);
+ snprintf(_network_player_info[_local_player].password, sizeof(_network_player_info[_local_player].password), new_pw);
+}
+
+
// **********
// Sending functions
// DEF_CLIENT_SEND_COMMAND has no parameters
@@ -103,7 +157,7 @@ DEF_CLIENT_SEND_COMMAND_PARAM(PACKET_CLIENT_PASSWORD)(NetworkPasswordType type,
//
Packet *p = NetworkSend_Init(PACKET_CLIENT_PASSWORD);
p->Send_uint8 (type);
- p->Send_string(password);
+ p->Send_string(type == NETWORK_GAME_PASSWORD ? password : GenerateCompanyPasswordHash(password));
MY_CLIENT->Send_Packet(p);
}
@@ -224,7 +278,7 @@ DEF_CLIENT_SEND_COMMAND_PARAM(PACKET_CLIENT_SET_PASSWORD)(const char *password)
//
Packet *p = NetworkSend_Init(PACKET_CLIENT_SET_PASSWORD);
- p->Send_string(password);
+ p->Send_string(GenerateCompanyPasswordHash(password));
MY_CLIENT->Send_Packet(p);
}
@@ -458,8 +512,13 @@ DEF_CLIENT_RECEIVE_COMMAND(PACKET_SERVER_NEED_PASSWORD)
NetworkPasswordType type = (NetworkPasswordType)p->Recv_uint8();
switch (type) {
- case NETWORK_GAME_PASSWORD:
case NETWORK_COMPANY_PASSWORD:
+ /* Initialize the password hash salting variables. */
+ _password_game_seed = p->Recv_uint32();
+ p->Recv_string(_password_server_unique_id, sizeof(_password_server_unique_id));
+ if (MY_CLIENT->has_quit) return NETWORK_RECV_STATUS_MALFORMED_PACKET;
+
+ case NETWORK_GAME_PASSWORD:
ShowNetworkNeedPassword(type);
return NETWORK_RECV_STATUS_OKAY;
@@ -471,6 +530,10 @@ DEF_CLIENT_RECEIVE_COMMAND(PACKET_SERVER_WELCOME)
{
_network_own_client_index = p->Recv_uint16();
+ /* Initialize the password hash salting variables, even if they were previously. */
+ _password_game_seed = p->Recv_uint32();
+ p->Recv_string(_password_server_unique_id, sizeof(_password_server_unique_id));
+
// Start receiving the map
SEND_COMMAND(PACKET_CLIENT_GETMAP)();
return NETWORK_RECV_STATUS_OKAY;
diff --git a/src/network/network_server.cpp b/src/network/network_server.cpp
index 0c484d516..1c10996db 100644
--- a/src/network/network_server.cpp
+++ b/src/network/network_server.cpp
@@ -224,6 +224,8 @@ DEF_SERVER_SEND_COMMAND_PARAM(PACKET_SERVER_NEED_PASSWORD)(NetworkTCPSocketHandl
Packet *p = NetworkSend_Init(PACKET_SERVER_NEED_PASSWORD);
p->Send_uint8(type);
+ p->Send_uint32(_patches.generation_seed);
+ p->Send_string(_network_unique_id);
cs->Send_Packet(p);
}
@@ -247,6 +249,8 @@ DEF_SERVER_SEND_COMMAND(PACKET_SERVER_WELCOME)
p = NetworkSend_Init(PACKET_SERVER_WELCOME);
p->Send_uint16(cs->index);
+ p->Send_uint32(_patches.generation_seed);
+ p->Send_string(_network_unique_id);
cs->Send_Packet(p);
// Transmit info about all the active clients