diff --git a/src/console_cmds.cpp b/src/console_cmds.cpp index d74446be5a..3b797005cc 100644 --- a/src/console_cmds.cpp +++ b/src/console_cmds.cpp @@ -836,6 +836,7 @@ DEF_CONSOLE_CMD(ConRcon) if (argc == 0) { IConsolePrint(CC_HELP, "Remote control the server from another client. Usage: 'rcon '."); IConsolePrint(CC_HELP, "Remember to enclose the command in quotes, otherwise only the first parameter is sent."); + IConsolePrint(CC_HELP, "When your client's public key is in the 'authorized keys' for 'rcon', the password is not checked and may be '*'."); return true; } diff --git a/src/network/network_server.cpp b/src/network/network_server.cpp index 3a792504dd..6166376b11 100644 --- a/src/network/network_server.cpp +++ b/src/network/network_server.cpp @@ -60,6 +60,7 @@ template SocketList TCPListenHandlerSendEnableEncryption(); if (status != NETWORK_RECV_STATUS_OKAY) return status; + this->peer_public_key = this->authentication_handler->GetPeerPublicKey(); this->receive_encryption_handler = this->authentication_handler->CreateClientToServerEncryptionHandler(); this->send_encryption_handler = this->authentication_handler->CreateServerToClientEncryptionHandler(); this->authentication_handler = nullptr; @@ -1503,14 +1505,16 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::Receive_CLIENT_RCON(Packet &p) { if (this->status != STATUS_ACTIVE) return this->SendError(NETWORK_ERROR_NOT_EXPECTED); - if (_settings_client.network.rcon_password.empty()) return NETWORK_RECV_STATUS_OKAY; - Debug(net, 9, "client[{}] Receive_CLIENT_RCON()", this->client_id); std::string password = p.Recv_string(NETWORK_PASSWORD_LENGTH); std::string command = p.Recv_string(NETWORK_RCONCOMMAND_LENGTH); - if (_settings_client.network.rcon_password.compare(password) != 0) { + if (_rcon_authorized_key_handler.IsAllowed(this->peer_public_key)) { + /* We are allowed, nothing more to validate. */ + } else if (_settings_client.network.rcon_password.empty()) { + return NETWORK_RECV_STATUS_OKAY; + } else if (_settings_client.network.rcon_password.compare(password) != 0) { Debug(net, 1, "[rcon] Wrong password from client-id {}", this->client_id); return NETWORK_RECV_STATUS_OKAY; } diff --git a/src/network/network_server.h b/src/network/network_server.h index 47b8777578..d41ef4756c 100644 --- a/src/network/network_server.h +++ b/src/network/network_server.h @@ -24,6 +24,7 @@ extern NetworkClientSocketPool _networkclientsocket_pool; class ServerNetworkGameSocketHandler : public NetworkClientSocketPool::PoolItem<&_networkclientsocket_pool>, public NetworkGameSocketHandler, public TCPListenHandler { protected: std::unique_ptr authentication_handler; ///< The handler for the authentication. + std::string peer_public_key; ///< The public key of our client. NetworkRecvStatus Receive_CLIENT_JOIN(Packet &p) override; NetworkRecvStatus Receive_CLIENT_IDENTIFY(Packet &p) override; diff --git a/src/settings.cpp b/src/settings.cpp index 29e168bf19..88d96c0b48 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -138,6 +138,7 @@ private: "servers", "server_bind_addresses", "server_authorized_keys", + "rcon_authorized_keys", }; public: @@ -1287,6 +1288,7 @@ static void HandleSettingDescs(IniFile &generic_ini, IniFile &private_ini, IniFi proc_list(private_ini, "servers", _network_host_list); proc_list(private_ini, "bans", _network_ban_list); proc_list(private_ini, "server_authorized_keys", _settings_client.network.server_authorized_keys); + proc_list(private_ini, "rcon_authorized_keys", _settings_client.network.rcon_authorized_keys); } } diff --git a/src/settings_type.h b/src/settings_type.h index 9181e59dbe..17941ae0a4 100644 --- a/src/settings_type.h +++ b/src/settings_type.h @@ -315,6 +315,7 @@ struct NetworkSettings { std::string server_password; ///< password for joining this server std::vector server_authorized_keys; ///< Public keys of clients that are authorized to connect to the game. std::string rcon_password; ///< password for rconsole (server side) + std::vector rcon_authorized_keys; ///< Public keys of clients that are authorized to use the rconsole (server side). std::string admin_password; ///< password for the admin network std::string client_name; ///< name of the player (as client) std::string client_secret_key; ///< The secret key of the client for authorized key logins.