diff --git a/src/network/network.cpp b/src/network/network.cpp index 1a193d4bbb..d139ca01c1 100644 --- a/src/network/network.cpp +++ b/src/network/network.cpp @@ -37,6 +37,7 @@ #include "../error.h" #include "../core/checksum_func.hpp" #include "../string_func_extra.h" +#include "../3rdparty/randombytes/randombytes.h" #include #include @@ -62,6 +63,7 @@ bool _network_dedicated; ///< are we a dedicated server? bool _is_network_server; ///< Does this client wants to be a network-server? bool _network_settings_access; ///< Can this client change server settings? NetworkCompanyState *_network_company_states = nullptr; ///< Statistics about some companies. +std::string _network_company_server_id; ///< Server ID string used for company passwords ClientID _network_own_client_id; ///< Our client identifier. ClientID _redirect_console_to_client; ///< If not invalid, redirect the console output to a client. uint8 _network_reconnect; ///< Reconnect timeout @@ -634,6 +636,7 @@ void NetworkClose(bool close_admins) delete[] _network_company_states; _network_company_states = nullptr; + _network_company_server_id.clear(); InitializeNetworkPools(close_admins); } @@ -917,6 +920,7 @@ bool NetworkServerStart() NetworkUDPServerListen(); _network_company_states = new NetworkCompanyState[MAX_COMPANIES]; + _network_company_server_id = NetworkGenerateRandomKeyString(); _network_server = true; _networking = true; _frame_counter = 0; @@ -1257,6 +1261,26 @@ static void NetworkGenerateServerId() _settings_client.network.network_id = hex_output; } +std::string NetworkGenerateRandomKeyString() +{ + uint8 key[16]; + char hex_output[16 * 2 + 1]; + + if (randombytes(key, 16) < 0) { + /* Fallback poor-quality random */ + DEBUG(misc, 0, "High quality random source unavailable"); + for (int i = 0; i < 16; i++) { + key[i] = (uint8)InteractiveRandom(); + } + } + + for (int i = 0; i < 16; ++i) { + seprintf(hex_output + i * 2, lastof(hex_output), "%02x", key[i]); + } + + return std::string(hex_output); +} + class TCPNetworkDebugConnecter : TCPConnecter { private: std::string connection_string; diff --git a/src/network/network_client.cpp b/src/network/network_client.cpp index 6b95cc209b..e299732580 100644 --- a/src/network/network_client.cpp +++ b/src/network/network_client.cpp @@ -374,8 +374,10 @@ static uint32 _server_password_game_seed; static uint32 _rcon_password_game_seed; /** One bit of 'entropy' used to generate a salt for the settings passwords. */ static uint32 _settings_password_game_seed; -/** The other bit of 'entropy' used to generate a salt for the company, server, rcon, and settings passwords. */ +/** The other bit of 'entropy' used to generate a salt for the server, rcon, and settings passwords. */ static std::string _password_server_id; +/** The other bit of 'entropy' used to generate a salt for the company passwords. */ +static std::string _company_password_server_id; /** Maximum number of companies of the currently joined server. */ static uint8 _network_server_max_companies; @@ -437,7 +439,7 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::SendGamePassword(const std::st NetworkRecvStatus ClientNetworkGameSocketHandler::SendCompanyPassword(const std::string &password) { Packet *p = new Packet(PACKET_CLIENT_COMPANY_PASSWORD, SHRT_MAX); - p->Send_string(GenerateCompanyPasswordHash(password, _password_server_id, _company_password_game_seed)); + p->Send_string(GenerateCompanyPasswordHash(password, _company_password_server_id, _company_password_game_seed)); my_client->SendPacket(p); return NETWORK_RECV_STATUS_OKAY; } @@ -571,7 +573,7 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::SendSetPassword(const std::str { Packet *p = new Packet(PACKET_CLIENT_SET_PASSWORD, SHRT_MAX); - p->Send_string(GenerateCompanyPasswordHash(password, _password_server_id, _company_password_game_seed)); + p->Send_string(GenerateCompanyPasswordHash(password, _company_password_server_id, _company_password_game_seed)); my_client->SendPacket(p); return NETWORK_RECV_STATUS_OKAY; } @@ -623,7 +625,7 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::SendMove(CompanyID company, co { Packet *p = new Packet(PACKET_CLIENT_MOVE, SHRT_MAX); p->Send_uint8(company); - p->Send_string(GenerateCompanyPasswordHash(password, _password_server_id, _company_password_game_seed)); + p->Send_string(GenerateCompanyPasswordHash(password, _company_password_server_id, _company_password_game_seed)); my_client->SendPacket(p); return NETWORK_RECV_STATUS_OKAY; } @@ -828,7 +830,7 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_NEED_COMPANY_PA this->status = STATUS_AUTH_COMPANY; _company_password_game_seed = p->Recv_uint32(); - _password_server_id = p->Recv_string(NETWORK_SERVER_ID_LENGTH); + _company_password_server_id = p->Recv_string(NETWORK_SERVER_ID_LENGTH); if (this->HasClientQuit()) return NETWORK_RECV_STATUS_MALFORMED_PACKET; if (!_network_join.company_password.empty()) { @@ -853,6 +855,7 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_WELCOME(Packet _rcon_password_game_seed = p->Recv_uint32(); _settings_password_game_seed = p->Recv_uint32(); _password_server_id = p->Recv_string(NETWORK_SERVER_ID_LENGTH); + _company_password_server_id = p->Recv_string(NETWORK_SERVER_ID_LENGTH); /* Start receiving the map */ return SendGetMap(); diff --git a/src/network/network_func.h b/src/network/network_func.h index 7089ff35ea..c643cb24bc 100644 --- a/src/network/network_func.h +++ b/src/network/network_func.h @@ -25,6 +25,7 @@ #include "../string_type.h" extern NetworkCompanyState *_network_company_states; +extern std::string _network_company_server_id; extern ClientID _network_own_client_id; extern ClientID _redirect_console_to_client; diff --git a/src/network/network_internal.h b/src/network/network_internal.h index fc4b6a83ae..436fe610fe 100644 --- a/src/network/network_internal.h +++ b/src/network/network_internal.h @@ -131,6 +131,7 @@ uint NetworkCalculateLag(const NetworkClientSocket *cs); StringID GetNetworkErrorMsg(NetworkErrorCode err); bool NetworkMakeClientNameUnique(std::string &new_name); std::string GenerateCompanyPasswordHash(const std::string &password, const std::string &password_server_id, uint32 password_game_seed); +std::string NetworkGenerateRandomKeyString(); std::string_view ParseCompanyFromConnectionString(const std::string &connection_string, CompanyID *company_id); NetworkAddress ParseConnectionString(const std::string &connection_string, uint16 default_port); diff --git a/src/network/network_server.cpp b/src/network/network_server.cpp index 0423f1584a..68aced0372 100644 --- a/src/network/network_server.cpp +++ b/src/network/network_server.cpp @@ -490,7 +490,7 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::SendNeedCompanyPassword() Packet *p = new Packet(PACKET_SERVER_NEED_COMPANY_PASSWORD, SHRT_MAX); p->Send_uint32(_settings_game.game_creation.generation_seed); - p->Send_string(_settings_client.network.network_id); + p->Send_string(_network_company_server_id); this->SendPacket(p); return NETWORK_RECV_STATUS_OKAY; } @@ -516,6 +516,7 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::SendWelcome() p->Send_uint32(_settings_game.game_creation.generation_seed ^ this->rcon_hash_bits); p->Send_uint32(_settings_game.game_creation.generation_seed ^ this->settings_hash_bits); p->Send_string(_settings_client.network.network_id); + p->Send_string(_network_company_server_id); this->SendPacket(p); /* Transmit info about all the active clients */ @@ -1825,7 +1826,7 @@ void NetworkServerSetCompanyPassword(CompanyID company_id, const std::string &pa if (already_hashed) { _network_company_states[company_id].password = password; } else { - _network_company_states[company_id].password = GenerateCompanyPasswordHash(password, _settings_client.network.network_id, _settings_game.game_creation.generation_seed); + _network_company_states[company_id].password = GenerateCompanyPasswordHash(password, _network_company_server_id, _settings_game.game_creation.generation_seed); } NetworkServerUpdateCompanyPassworded(company_id, !_network_company_states[company_id].password.empty());