From 17c054a650e913b328946212ff7f118ae059b77b Mon Sep 17 00:00:00 2001 From: Jonathan G Rennison Date: Tue, 20 Aug 2019 20:04:34 +0100 Subject: [PATCH] Use password hash for network server and rcon passwords --- src/network/network_client.cpp | 28 +++++++++++++++++++--------- src/network/network_server.cpp | 10 ++++++++-- src/network/network_server.h | 2 ++ 3 files changed, 29 insertions(+), 11 deletions(-) diff --git a/src/network/network_client.cpp b/src/network/network_client.cpp index f35c13bc06..67d33abb59 100644 --- a/src/network/network_client.cpp +++ b/src/network/network_client.cpp @@ -325,8 +325,12 @@ ClientNetworkGameSocketHandler * ClientNetworkGameSocketHandler::my_client = nul 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 uint32 _company_password_game_seed; +/** One bit of 'entropy' used to generate a salt for the server passwords. */ +static uint32 _server_password_game_seed; +/** One bit of 'entropy' used to generate a salt for the rcon passwords. */ +static uint32 _rcon_password_game_seed; +/** One bit of 'entropy' used to generate a salt for the settings passwords. */ static char _password_server_id[NETWORK_SERVER_ID_LENGTH]; /** Maximum number of companies of the currently joined server. */ @@ -394,7 +398,7 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::SendNewGRFsOk() NetworkRecvStatus ClientNetworkGameSocketHandler::SendGamePassword(const char *password) { Packet *p = new Packet(PACKET_CLIENT_GAME_PASSWORD); - p->Send_string(password); + p->Send_string(GenerateCompanyPasswordHash(password, _password_server_id, _server_password_game_seed)); my_client->SendPacket(p); return NETWORK_RECV_STATUS_OKAY; } @@ -406,7 +410,7 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::SendGamePassword(const char *p NetworkRecvStatus ClientNetworkGameSocketHandler::SendCompanyPassword(const char *password) { Packet *p = new Packet(PACKET_CLIENT_COMPANY_PASSWORD); - p->Send_string(GenerateCompanyPasswordHash(password, _password_server_id, _password_game_seed)); + p->Send_string(GenerateCompanyPasswordHash(password, _password_server_id, _company_password_game_seed)); my_client->SendPacket(p); return NETWORK_RECV_STATUS_OKAY; } @@ -504,7 +508,7 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::SendSetPassword(const char *pa { Packet *p = new Packet(PACKET_CLIENT_SET_PASSWORD); - p->Send_string(GenerateCompanyPasswordHash(password, _password_server_id, _password_game_seed)); + p->Send_string(GenerateCompanyPasswordHash(password, _password_server_id, _company_password_game_seed)); my_client->SendPacket(p); return NETWORK_RECV_STATUS_OKAY; } @@ -541,7 +545,7 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::SendQuit() NetworkRecvStatus ClientNetworkGameSocketHandler::SendRCon(const char *pass, const char *command) { Packet *p = new Packet(PACKET_CLIENT_RCON); - p->Send_string(pass); + p->Send_string(GenerateCompanyPasswordHash(pass, _password_server_id, _rcon_password_game_seed)); p->Send_string(command); my_client->SendPacket(p); return NETWORK_RECV_STATUS_OKAY; @@ -556,7 +560,7 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::SendMove(CompanyID company, co { Packet *p = new Packet(PACKET_CLIENT_MOVE); p->Send_uint8(company); - p->Send_string(GenerateCompanyPasswordHash(password, _password_server_id, _password_game_seed)); + p->Send_string(GenerateCompanyPasswordHash(password, _password_server_id, _company_password_game_seed)); my_client->SendPacket(p); return NETWORK_RECV_STATUS_OKAY; } @@ -773,6 +777,10 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_NEED_GAME_PASSW if (this->status < STATUS_JOIN || this->status >= STATUS_AUTH_GAME) return NETWORK_RECV_STATUS_MALFORMED_PACKET; this->status = STATUS_AUTH_GAME; + _server_password_game_seed = p->Recv_uint32(); + p->Recv_string(_password_server_id, sizeof(_password_server_id)); + if (this->HasClientQuit()) return NETWORK_RECV_STATUS_MALFORMED_PACKET; + const char *password = _network_join_server_password; if (!StrEmpty(password)) { return SendGamePassword(password); @@ -788,7 +796,7 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_NEED_COMPANY_PA if (this->status < STATUS_JOIN || this->status >= STATUS_AUTH_COMPANY) return NETWORK_RECV_STATUS_MALFORMED_PACKET; this->status = STATUS_AUTH_COMPANY; - _password_game_seed = p->Recv_uint32(); + _company_password_game_seed = p->Recv_uint32(); p->Recv_string(_password_server_id, sizeof(_password_server_id)); if (this->HasClientQuit()) return NETWORK_RECV_STATUS_MALFORMED_PACKET; @@ -810,7 +818,9 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_WELCOME(Packet _network_own_client_id = (ClientID)p->Recv_uint32(); /* Initialize the password hash salting variables, even if they were previously. */ - _password_game_seed = p->Recv_uint32(); + _company_password_game_seed = p->Recv_uint32(); + _server_password_game_seed = p->Recv_uint32(); + _rcon_password_game_seed = p->Recv_uint32(); p->Recv_string(_password_server_id, sizeof(_password_server_id)); /* Start receiving the map */ diff --git a/src/network/network_server.cpp b/src/network/network_server.cpp index 0ff9f53e95..1297a9c536 100644 --- a/src/network/network_server.cpp +++ b/src/network/network_server.cpp @@ -216,6 +216,8 @@ ServerNetworkGameSocketHandler::ServerNetworkGameSocketHandler(SOCKET s) : Netwo this->status = STATUS_INACTIVE; this->client_id = _network_client_id++; this->receive_limit = _settings_client.network.bytes_per_frame_burst; + this->server_hash_bits = InteractiveRandom(); + this->rcon_hash_bits = InteractiveRandom(); /* The Socket and Info pools need to be the same in size. After all, * each Socket will be associated with at most one Info object. As @@ -492,6 +494,8 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::SendNeedGamePassword() this->last_frame = this->last_frame_server = _frame_counter; Packet *p = new Packet(PACKET_SERVER_NEED_GAME_PASSWORD); + p->Send_uint32(_settings_game.game_creation.generation_seed ^ this->server_hash_bits); + p->Send_string(_settings_client.network.network_id); this->SendPacket(p); return NETWORK_RECV_STATUS_OKAY; } @@ -531,6 +535,8 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::SendWelcome() p = new Packet(PACKET_SERVER_WELCOME); p->Send_uint32(this->client_id); p->Send_uint32(_settings_game.game_creation.generation_seed); + p->Send_uint32(_settings_game.game_creation.generation_seed ^ this->server_hash_bits); + p->Send_uint32(_settings_game.game_creation.generation_seed ^ this->rcon_hash_bits); p->Send_string(_settings_client.network.network_id); this->SendPacket(p); @@ -972,7 +978,7 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::Receive_CLIENT_GAME_PASSWORD(P /* Check game password. Allow joining if we cleared the password meanwhile */ if (!StrEmpty(_settings_client.network.server_password) && - strcmp(password, _settings_client.network.server_password) != 0) { + strcmp(password, GenerateCompanyPasswordHash(_settings_client.network.server_password, _settings_client.network.network_id, _settings_game.game_creation.generation_seed ^ this->server_hash_bits)) != 0) { /* Password is invalid */ return this->SendError(NETWORK_ERROR_WRONG_PASSWORD); } @@ -1481,7 +1487,7 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::Receive_CLIENT_RCON(Packet *p) p->Recv_string(pass, sizeof(pass)); p->Recv_string(command, sizeof(command)); - if (strcmp(pass, _settings_client.network.rcon_password) != 0) { + if (strcmp(pass, GenerateCompanyPasswordHash(_settings_client.network.rcon_password, _settings_client.network.network_id, _settings_game.game_creation.generation_seed ^ this->rcon_hash_bits)) != 0) { DEBUG(net, 0, "[rcon] wrong password from client-id %d", this->client_id); return NETWORK_RECV_STATUS_OKAY; } diff --git a/src/network/network_server.h b/src/network/network_server.h index 89de84d06b..2ea4441bd4 100644 --- a/src/network/network_server.h +++ b/src/network/network_server.h @@ -72,6 +72,8 @@ public: ClientStatus status; ///< Status of this client CommandQueue outgoing_queue; ///< The command-queue awaiting delivery int receive_limit; ///< Amount of bytes that we can receive at this moment + uint32 server_hash_bits; ///< Server password hash entropy bits + uint32 rcon_hash_bits; ///< Rcon password hash entropy bits struct PacketWriter *savegame; ///< Writer used to write the savegame. NetworkAddress client_address; ///< IP-address of the client (so he can be banned)