diff --git a/src/console.cpp b/src/console.cpp index ab131b135e..c7a1ffd749 100644 --- a/src/console.cpp +++ b/src/console.cpp @@ -13,6 +13,7 @@ #include "console_internal.h" #include "network/network.h" #include "network/network_func.h" +#include "network/network_admin.h" #include "debug.h" #include "console_func.h" #include "settings_type.h" @@ -38,6 +39,7 @@ void IConsoleInit() _iconsole_output_file = NULL; #ifdef ENABLE_NETWORK /* Initialize network only variables */ _redirect_console_to_client = INVALID_CLIENT_ID; + _redirect_console_to_admin = INVALID_ADMIN_ID; #endif IConsoleGUIInit(); @@ -96,6 +98,11 @@ void IConsolePrint(ConsoleColour colour_code, const char *string) NetworkServerSendRcon(_redirect_console_to_client, colour_code, string); return; } + + if (_redirect_console_to_admin != INVALID_ADMIN_ID) { + NetworkServerSendAdminRcon(_redirect_console_to_admin, colour_code, string); + return; + } #endif /* Create a copy of the string, strip if of colours and invalid diff --git a/src/console_cmds.cpp b/src/console_cmds.cpp index c047340dd9..8f976b48f8 100644 --- a/src/console_cmds.cpp +++ b/src/console_cmds.cpp @@ -18,6 +18,7 @@ #include "network/network.h" #include "network/network_func.h" #include "network/network_base.h" +#include "network/network_admin.h" #include "command_func.h" #include "settings_func.h" #include "fios.h" @@ -1416,7 +1417,8 @@ DEF_CONSOLE_CMD(ConSay) if (!_network_server) { NetworkClientSendChat(NETWORK_ACTION_CHAT, DESTTYPE_BROADCAST, 0 /* param does not matter */, argv[1]); } else { - NetworkServerSendChat(NETWORK_ACTION_CHAT, DESTTYPE_BROADCAST, 0, argv[1], CLIENT_ID_SERVER); + bool from_admin = (_redirect_console_to_admin < INVALID_ADMIN_ID); + NetworkServerSendChat(NETWORK_ACTION_CHAT, DESTTYPE_BROADCAST, 0, argv[1], CLIENT_ID_SERVER, from_admin); } return true; @@ -1473,7 +1475,8 @@ DEF_CONSOLE_CMD(ConSayCompany) if (!_network_server) { NetworkClientSendChat(NETWORK_ACTION_CHAT_COMPANY, DESTTYPE_TEAM, company_id, argv[2]); } else { - NetworkServerSendChat(NETWORK_ACTION_CHAT_COMPANY, DESTTYPE_TEAM, company_id, argv[2], CLIENT_ID_SERVER); + bool from_admin = (_redirect_console_to_admin < INVALID_ADMIN_ID); + NetworkServerSendChat(NETWORK_ACTION_CHAT_COMPANY, DESTTYPE_TEAM, company_id, argv[2], CLIENT_ID_SERVER, from_admin); } return true; @@ -1492,7 +1495,8 @@ DEF_CONSOLE_CMD(ConSayClient) if (!_network_server) { NetworkClientSendChat(NETWORK_ACTION_CHAT_CLIENT, DESTTYPE_CLIENT, atoi(argv[1]), argv[2]); } else { - NetworkServerSendChat(NETWORK_ACTION_CHAT_CLIENT, DESTTYPE_CLIENT, atoi(argv[1]), argv[2], CLIENT_ID_SERVER); + bool from_admin = (_redirect_console_to_admin < INVALID_ADMIN_ID); + NetworkServerSendChat(NETWORK_ACTION_CHAT_CLIENT, DESTTYPE_CLIENT, atoi(argv[1]), argv[2], CLIENT_ID_SERVER, from_admin); } return true; diff --git a/src/network/core/tcp_admin.cpp b/src/network/core/tcp_admin.cpp index b2da7475fe..9de27d1834 100644 --- a/src/network/core/tcp_admin.cpp +++ b/src/network/core/tcp_admin.cpp @@ -55,6 +55,7 @@ NetworkRecvStatus NetworkAdminSocketHandler::HandlePacket(Packet *p) ADMIN_COMMAND(ADMIN_PACKET_ADMIN_UPDATE_FREQUENCY) ADMIN_COMMAND(ADMIN_PACKET_ADMIN_POLL) ADMIN_COMMAND(ADMIN_PACKET_ADMIN_CHAT) + ADMIN_COMMAND(ADMIN_PACKET_ADMIN_RCON) ADMIN_COMMAND(ADMIN_PACKET_SERVER_FULL) ADMIN_COMMAND(ADMIN_PACKET_SERVER_BANNED) @@ -77,6 +78,7 @@ NetworkRecvStatus NetworkAdminSocketHandler::HandlePacket(Packet *p) ADMIN_COMMAND(ADMIN_PACKET_SERVER_COMPANY_ECONOMY) ADMIN_COMMAND(ADMIN_PACKET_SERVER_COMPANY_STATS) ADMIN_COMMAND(ADMIN_PACKET_SERVER_CHAT) + ADMIN_COMMAND(ADMIN_PACKET_SERVER_RCON) default: if (this->HasClientQuit()) { @@ -127,6 +129,7 @@ DEFINE_UNAVAILABLE_ADMIN_RECEIVE_COMMAND(ADMIN_PACKET_ADMIN_QUIT) DEFINE_UNAVAILABLE_ADMIN_RECEIVE_COMMAND(ADMIN_PACKET_ADMIN_UPDATE_FREQUENCY) DEFINE_UNAVAILABLE_ADMIN_RECEIVE_COMMAND(ADMIN_PACKET_ADMIN_POLL) DEFINE_UNAVAILABLE_ADMIN_RECEIVE_COMMAND(ADMIN_PACKET_ADMIN_CHAT) +DEFINE_UNAVAILABLE_ADMIN_RECEIVE_COMMAND(ADMIN_PACKET_ADMIN_RCON) DEFINE_UNAVAILABLE_ADMIN_RECEIVE_COMMAND(ADMIN_PACKET_SERVER_FULL) DEFINE_UNAVAILABLE_ADMIN_RECEIVE_COMMAND(ADMIN_PACKET_SERVER_BANNED) @@ -149,5 +152,6 @@ DEFINE_UNAVAILABLE_ADMIN_RECEIVE_COMMAND(ADMIN_PACKET_SERVER_COMPANY_REMOVE) DEFINE_UNAVAILABLE_ADMIN_RECEIVE_COMMAND(ADMIN_PACKET_SERVER_COMPANY_ECONOMY) DEFINE_UNAVAILABLE_ADMIN_RECEIVE_COMMAND(ADMIN_PACKET_SERVER_COMPANY_STATS) DEFINE_UNAVAILABLE_ADMIN_RECEIVE_COMMAND(ADMIN_PACKET_SERVER_CHAT) +DEFINE_UNAVAILABLE_ADMIN_RECEIVE_COMMAND(ADMIN_PACKET_SERVER_RCON) #endif /* ENABLE_NETWORK */ diff --git a/src/network/core/tcp_admin.h b/src/network/core/tcp_admin.h index e73d0202e3..d4b0d746cf 100644 --- a/src/network/core/tcp_admin.h +++ b/src/network/core/tcp_admin.h @@ -31,6 +31,7 @@ enum PacketAdminType { ADMIN_PACKET_ADMIN_UPDATE_FREQUENCY, ///< The admin tells the server the update frequency of a particular piece of information. ADMIN_PACKET_ADMIN_POLL, ///< The admin explicitly polls for a piece of information. ADMIN_PACKET_ADMIN_CHAT, ///< The admin sends a chat message to be distributed. + ADMIN_PACKET_ADMIN_RCON, ///< The admin sends a remote console command. ADMIN_PACKET_SERVER_FULL = 100, ///< The server tells the admin it cannot accept the admin. ADMIN_PACKET_SERVER_BANNED, ///< The server tells the admin it is banned. @@ -53,6 +54,7 @@ enum PacketAdminType { ADMIN_PACKET_SERVER_COMPANY_ECONOMY, ///< The server gives the admin some economy related company information. ADMIN_PACKET_SERVER_COMPANY_STATS, ///< The server gives the admin some statistics about a company. ADMIN_PACKET_SERVER_CHAT, ///< The server received a chat message and relays it. + ADMIN_PACKET_SERVER_RCON, ///< The server's reply to a remove console command. INVALID_ADMIN_PACKET = 0xFF, ///< An invalid marker for admin packets. }; @@ -142,6 +144,12 @@ protected: */ DECLARE_ADMIN_RECEIVE_COMMAND(ADMIN_PACKET_ADMIN_CHAT); + /** + * Execute a command on the servers console: + * string Command to be executed. + */ + DECLARE_ADMIN_RECEIVE_COMMAND(ADMIN_PACKET_ADMIN_RCON); + /** * The server is full (connection gets closed). */ @@ -316,6 +324,13 @@ protected: */ DECLARE_ADMIN_RECEIVE_COMMAND(ADMIN_PACKET_SERVER_CHAT); + /** + * Result of an rcon command: + * uint16 Colour as it would be used on the server or a client. + * string Output of the executed command. + */ + DECLARE_ADMIN_RECEIVE_COMMAND(ADMIN_PACKET_SERVER_RCON); + NetworkRecvStatus HandlePacket(Packet *p); public: NetworkRecvStatus CloseConnection(bool error = true); diff --git a/src/network/network_admin.cpp b/src/network/network_admin.cpp index 565976c701..081d59e124 100644 --- a/src/network/network_admin.cpp +++ b/src/network/network_admin.cpp @@ -28,6 +28,9 @@ /* This file handles all the admin network commands. */ +/** Redirection of the (remote) console to the admin. */ +AdminIndex _redirect_console_to_admin = INVALID_ADMIN_ID; + /** The amount of admins connected. */ byte _network_admins_connected = 0; @@ -67,6 +70,7 @@ ServerNetworkAdminSocketHandler::~ServerNetworkAdminSocketHandler() { _network_admins_connected--; DEBUG(net, 1, "[admin] '%s' (%s) has disconnected", this->admin_name, this->admin_version); + if (_redirect_console_to_admin == this->index) _redirect_console_to_admin = INVALID_ADMIN_ID; } /** @@ -399,6 +403,33 @@ NetworkRecvStatus ServerNetworkAdminSocketHandler::SendChat(NetworkAction action return NETWORK_RECV_STATUS_OKAY; } +NetworkRecvStatus ServerNetworkAdminSocketHandler::SendRcon(uint16 colour, const char *result) +{ + Packet *p = new Packet(ADMIN_PACKET_SERVER_RCON); + + p->Send_uint16(colour); + p->Send_string(result); + this->Send_Packet(p); + + return NETWORK_RECV_STATUS_OKAY; +} + +DEF_ADMIN_RECEIVE_COMMAND(Server, ADMIN_PACKET_ADMIN_RCON) +{ + if (this->status == ADMIN_STATUS_INACTIVE) return this->SendError(NETWORK_ERROR_NOT_EXPECTED); + + char command[NETWORK_RCONCOMMAND_LENGTH]; + + p->Recv_string(command, sizeof(command)); + + DEBUG(net, 2, "[admin] Rcon command from '%s' (%s): '%s'", this->admin_name, this->admin_version, command); + + _redirect_console_to_admin = this->index; + IConsoleCmdExec(command); + _redirect_console_to_admin = INVALID_ADMIN_ID; + return NETWORK_RECV_STATUS_OKAY; +} + /*********** * Receiving functions ************/ @@ -671,6 +702,17 @@ void NetworkAdminChat(NetworkAction action, DestType desttype, ClientID client_i } } +/** + * Pass the rcon reply to the admin. + * @param admin_index The admin to give the reply. + * @param colour_code The colour of the string. + * @param string The string to show. + */ +void NetworkServerSendAdminRcon(AdminIndex admin_index, ConsoleColour colour_code, const char *string) +{ + ServerNetworkAdminSocketHandler::Get(admin_index)->SendRcon(colour_code, string); +} + /** * Send a Welcome packet to all connected admins */ diff --git a/src/network/network_admin.h b/src/network/network_admin.h index 7174a191ad..a2a177b900 100644 --- a/src/network/network_admin.h +++ b/src/network/network_admin.h @@ -18,6 +18,8 @@ #include "core/tcp_listen.h" #include "core/tcp_admin.h" +extern AdminIndex _redirect_console_to_admin; + class ServerNetworkAdminSocketHandler; typedef Pool NetworkAdminSocketPool; extern NetworkAdminSocketPool _networkadminsocket_pool; @@ -30,6 +32,7 @@ protected: DECLARE_ADMIN_RECEIVE_COMMAND(ADMIN_PACKET_ADMIN_UPDATE_FREQUENCY); DECLARE_ADMIN_RECEIVE_COMMAND(ADMIN_PACKET_ADMIN_POLL); DECLARE_ADMIN_RECEIVE_COMMAND(ADMIN_PACKET_ADMIN_CHAT); + DECLARE_ADMIN_RECEIVE_COMMAND(ADMIN_PACKET_ADMIN_RCON); NetworkRecvStatus SendProtocol(); public: @@ -59,6 +62,7 @@ public: NetworkRecvStatus SendCompanyStats(); NetworkRecvStatus SendChat(NetworkAction action, DestType desttype, ClientID client_id, const char *msg, int64 data); + NetworkRecvStatus SendRcon(uint16 colour, const char *command); static void Send(); static void AcceptConnection(SOCKET s, const NetworkAddress &address); @@ -88,6 +92,7 @@ void NetworkAdminCompanyRemove(CompanyID company_id, AdminCompanyRemoveReason bc void NetworkAdminChat(NetworkAction action, DestType desttype, ClientID client_id, const char *msg, int64 data = 0, bool from_admin = false); void NetworkAdminUpdate(AdminUpdateFrequency freq); +void NetworkServerSendAdminRcon(AdminIndex admin_index, ConsoleColour colour_code, const char *string); #endif /* ENABLE_NETWORK */ #endif /* NETWORK_ADMIN_H */