diff options
| author | oy <Tom_Adams@web.de> | 2011-07-05 21:54:10 +0200 |
|---|---|---|
| committer | oy <Tom_Adams@web.de> | 2011-07-05 21:54:10 +0200 |
| commit | 1ae474689d564e1feba9924842f05e06600d83a1 (patch) | |
| tree | baac3e231cc2a1e1d35ea7d2a8c109e23fd8b8af /src | |
| parent | 5008b5f8a52a2692e5396cd67bf3ad13332e074b (diff) | |
| download | zcatch-1ae474689d564e1feba9924842f05e06600d83a1.tar.gz zcatch-1ae474689d564e1feba9924842f05e06600d83a1.zip | |
added moderator support for the remote console. #518
Diffstat (limited to 'src')
| -rw-r--r-- | src/engine/console.h | 7 | ||||
| -rw-r--r-- | src/engine/server/server.cpp | 58 | ||||
| -rw-r--r-- | src/engine/server/server.h | 8 | ||||
| -rw-r--r-- | src/engine/shared/config_variables.h | 3 | ||||
| -rw-r--r-- | src/engine/shared/console.cpp | 129 | ||||
| -rw-r--r-- | src/engine/shared/console.h | 6 |
6 files changed, 172 insertions, 39 deletions
diff --git a/src/engine/console.h b/src/engine/console.h index f8ec67b0..e650ac47 100644 --- a/src/engine/console.h +++ b/src/engine/console.h @@ -14,7 +14,10 @@ public: { OUTPUT_LEVEL_STANDARD=0, OUTPUT_LEVEL_ADDINFO, - OUTPUT_LEVEL_DEBUG + OUTPUT_LEVEL_DEBUG, + + ACCESS_LEVEL_ADMIN=0, + ACCESS_LEVEL_MOD, }; // TODO: rework this interface to reduce the amount of virtual calls @@ -62,6 +65,8 @@ public: virtual void RegisterPrintCallback(FPrintCallback pfnPrintCallback, void *pUserData) = 0; virtual void Print(int Level, const char *pFrom, const char *pStr) = 0; + + virtual void SetAccessLevel(int AccessLevel) = 0; }; extern IConsole *CreateConsole(int FlagMask); diff --git a/src/engine/server/server.cpp b/src/engine/server/server.cpp index 0e43e73f..14467b2b 100644 --- a/src/engine/server/server.cpp +++ b/src/engine/server/server.cpp @@ -1,6 +1,7 @@ /* (c) Magnus Auvinen. See licence.txt in the root of the distribution for more information. */ /* If you are missing that file, acquire a complete release at teeworlds.com. */ +#include <base/math.h> #include <base/system.h> #include <engine/config.h> @@ -181,6 +182,7 @@ CServer::CServer() : m_DemoRecorder(&m_SnapshotDelta) m_MapReload = 0; m_RconClientID = -1; + m_RconAuthLevel = AUTHED_ADMIN; Init(); } @@ -280,6 +282,11 @@ void CServer::Kick(int ClientID, const char *pReason) Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "server", "you can't kick yourself"); return; } + else if(m_aClients[ClientID].m_Authed > m_RconAuthLevel) + { + Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "server", "kick command denied"); + return; + } m_NetServer.Drop(ClientID, pReason); } @@ -571,7 +578,7 @@ int CServer::NewClientCallback(int ClientID, void *pUser) pThis->m_aClients[ClientID].m_aName[0] = 0; pThis->m_aClients[ClientID].m_aClan[0] = 0; pThis->m_aClients[ClientID].m_Country = -1; - pThis->m_aClients[ClientID].m_Authed = 0; + pThis->m_aClients[ClientID].m_Authed = AUTHED_NO; pThis->m_aClients[ClientID].m_AuthTries = 0; pThis->m_aClients[ClientID].Reset(); return 0; @@ -596,7 +603,7 @@ int CServer::DelClientCallback(int ClientID, const char *pReason, void *pUser) pThis->m_aClients[ClientID].m_aName[0] = 0; pThis->m_aClients[ClientID].m_aClan[0] = 0; pThis->m_aClients[ClientID].m_Country = -1; - pThis->m_aClients[ClientID].m_Authed = 0; + pThis->m_aClients[ClientID].m_Authed = AUTHED_NO; pThis->m_aClients[ClientID].m_AuthTries = 0; pThis->m_aClients[ClientID].m_Snapshots.PurgeAll(); return 0; @@ -635,7 +642,7 @@ void CServer::SendRconLineAuthed(const char *pLine, void *pUser) for(i = 0; i < MAX_CLIENTS; i++) { - if(pThis->m_aClients[i].m_State != CClient::STATE_EMPTY && pThis->m_aClients[i].m_Authed) + if(pThis->m_aClients[i].m_State != CClient::STATE_EMPTY && pThis->m_aClients[i].m_Authed >= pThis->m_RconAuthLevel) pThis->SendRconLine(i, pLine); } @@ -813,8 +820,12 @@ void CServer::ProcessClientPacket(CNetChunk *pPacket) str_format(aBuf, sizeof(aBuf), "ClientID=%d rcon='%s'", ClientID, pCmd); Console()->Print(IConsole::OUTPUT_LEVEL_ADDINFO, "server", aBuf); m_RconClientID = ClientID; + m_RconAuthLevel = m_aClients[ClientID].m_Authed; + Console()->SetAccessLevel(m_aClients[ClientID].m_Authed == AUTHED_ADMIN ? IConsole::ACCESS_LEVEL_ADMIN : IConsole::ACCESS_LEVEL_MOD); Console()->ExecuteLine(pCmd); + Console()->SetAccessLevel(IConsole::ACCESS_LEVEL_ADMIN); m_RconClientID = -1; + m_RconAuthLevel = AUTHED_ADMIN; } } else if(Msg == NETMSG_RCON_AUTH) @@ -825,9 +836,9 @@ void CServer::ProcessClientPacket(CNetChunk *pPacket) if(Unpacker.Error() == 0) { - if(g_Config.m_SvRconPassword[0] == 0) + if(g_Config.m_SvRconPassword[0] == 0 && g_Config.m_SvRconModPassword[0]) { - SendRconLine(ClientID, "No rcon password set on server. Set sv_rcon_password to enable the remote console."); + SendRconLine(ClientID, "No rcon password set on server. Set sv_rcon_password and/or sv_rcon_mod_password to enable the remote console."); } else if(str_comp(pPw, g_Config.m_SvRconPassword) == 0) { @@ -835,10 +846,22 @@ void CServer::ProcessClientPacket(CNetChunk *pPacket) Msg.AddInt(1); SendMsgEx(&Msg, MSGFLAG_VITAL, ClientID, true); - m_aClients[ClientID].m_Authed = 1; - SendRconLine(ClientID, "Authentication successful. Remote console access granted."); + m_aClients[ClientID].m_Authed = AUTHED_ADMIN; + SendRconLine(ClientID, "Admin authentication successful. Full remote console access granted."); + char aBuf[256]; + str_format(aBuf, sizeof(aBuf), "ClientID=%d authed (admin)", ClientID); + Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "server", aBuf); + } + else if(str_comp(pPw, g_Config.m_SvRconModPassword) == 0) + { + CMsgPacker Msg(NETMSG_RCON_AUTH_STATUS); + Msg.AddInt(1); + SendMsgEx(&Msg, MSGFLAG_VITAL, ClientID, true); + + m_aClients[ClientID].m_Authed = AUTHED_MOD; + SendRconLine(ClientID, "Moderator authentication successful. Limited remote console access granted."); char aBuf[256]; - str_format(aBuf, sizeof(aBuf), "ClientID=%d authed", ClientID); + str_format(aBuf, sizeof(aBuf), "ClientID=%d authed (moderator)", ClientID); Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "server", aBuf); } else if(g_Config.m_SvRconMaxTries) @@ -1308,6 +1331,20 @@ void CServer::ConBan(IConsole::IResult *pResult, void *pUser) pServer->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "server", "you can't ban yourself"); return; } + + for(int i = 0; i < MAX_CLIENTS; ++i) + { + if(i == pServer->m_RconClientID) + continue; + + AddrCheck = pServer->m_NetServer.ClientAddr(i); + AddrCheck.port = 0; + if(net_addr_comp(&Addr, &AddrCheck) == 0 && pServer->m_aClients[i].m_Authed > pServer->m_RconAuthLevel) + { + pServer->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "server", "ban command denied"); + return; + } + } } pServer->BanAdd(Addr, Minutes*60, pReason); } @@ -1325,6 +1362,11 @@ void CServer::ConBan(IConsole::IResult *pResult, void *pUser) pServer->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "server", "you can't ban yourself"); return; } + else if(pServer->m_aClients[ClientID].m_Authed > pServer->m_RconAuthLevel) + { + pServer->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "server", "ban command denied"); + return; + } Addr = pServer->m_NetServer.ClientAddr(ClientID); pServer->BanAdd(Addr, Minutes*60, pReason); diff --git a/src/engine/server/server.h b/src/engine/server/server.h index be36a856..72c82d4d 100644 --- a/src/engine/server/server.h +++ b/src/engine/server/server.h @@ -49,6 +49,13 @@ public: class IConsole *Console() { return m_pConsole; } class IStorage *Storage() { return m_pStorage; } + enum + { + AUTHED_NO=0, + AUTHED_MOD, + AUTHED_ADMIN, + }; + class CClient { public: @@ -110,6 +117,7 @@ public: int m_RunServer; int m_MapReload; int m_RconClientID; + int m_RconAuthLevel; int64 m_Lastheartbeat; //static NETADDR4 master_server; diff --git a/src/engine/shared/config_variables.h b/src/engine/shared/config_variables.h index 31a8128a..213ebf26 100644 --- a/src/engine/shared/config_variables.h +++ b/src/engine/shared/config_variables.h @@ -82,7 +82,8 @@ MACRO_CONFIG_INT(SvMaxClients, sv_max_clients, 8, 1, MAX_CLIENTS, CFGFLAG_SERVER MACRO_CONFIG_INT(SvMaxClientsPerIP, sv_max_clients_per_ip, 4, 1, MAX_CLIENTS, CFGFLAG_SERVER, "Maximum number of clients with the same IP that can connect to the server") MACRO_CONFIG_INT(SvHighBandwidth, sv_high_bandwidth, 0, 0, 1, CFGFLAG_SERVER, "Use high bandwidth mode. Doubles the bandwidth required for the server. LAN use only") MACRO_CONFIG_INT(SvRegister, sv_register, 1, 0, 1, CFGFLAG_SERVER, "Register server with master server for public listing") -MACRO_CONFIG_STR(SvRconPassword, sv_rcon_password, 32, "", CFGFLAG_SERVER, "Remote console password") +MACRO_CONFIG_STR(SvRconPassword, sv_rcon_password, 32, "", CFGFLAG_SERVER, "Remote console password (full access)") +MACRO_CONFIG_STR(SvRconModPassword, sv_rcon_mod_password, 32, "", CFGFLAG_SERVER, "Remote console password for moderators (limited access)") MACRO_CONFIG_INT(SvRconMaxTries, sv_rcon_max_tries, 3, 0, 100, CFGFLAG_SERVER, "Maximum number of tries for remote console authentication") MACRO_CONFIG_INT(SvRconBantime, sv_rcon_bantime, 5, 0, 1440, CFGFLAG_SERVER, "The time a client gets banned if remote console authentication fails. 0 makes it just use kick") diff --git a/src/engine/shared/console.cpp b/src/engine/shared/console.cpp index 3fd73543..588abd61 100644 --- a/src/engine/shared/console.cpp +++ b/src/engine/shared/console.cpp @@ -1,11 +1,15 @@ /* (c) Magnus Auvinen. See licence.txt in the root of the distribution for more information. */ /* If you are missing that file, acquire a complete release at teeworlds.com. */ #include <new> + +#include <base/math.h> #include <base/system.h> -#include <engine/shared/protocol.h> + #include <engine/storage.h> -#include "console.h" +#include <engine/shared/protocol.h> + #include "config.h" +#include "console.h" #include "linereader.h" const char *CConsole::CResult::GetString(unsigned Index) @@ -247,38 +251,47 @@ void CConsole::ExecuteLineStroked(int Stroke, const char *pStr) if(ParseStart(&Result, pStr, (pEnd-pStr) + 1) != 0) return; - if (!*Result.m_pCommand) + if(!*Result.m_pCommand) return; CCommand *pCommand = FindCommand(Result.m_pCommand, m_FlagMask); if(pCommand) { - int IsStrokeCommand = 0; - if(Result.m_pCommand[0] == '+') - { - // insert the stroke direction token - Result.AddArgument(m_paStrokeStr[Stroke]); - IsStrokeCommand = 1; - } - - if(Stroke || IsStrokeCommand) + if(pCommand->m_AccessLevel >= m_AccessLevel) { - if(ParseArgs(&Result, pCommand->m_pParams)) + int IsStrokeCommand = 0; + if(Result.m_pCommand[0] == '+') { - char aBuf[256]; - str_format(aBuf, sizeof(aBuf), "Invalid arguments... Usage: %s %s", pCommand->m_pName, pCommand->m_pParams); - Print(OUTPUT_LEVEL_STANDARD, "Console", aBuf); + // insert the stroke direction token + Result.AddArgument(m_paStrokeStr[Stroke]); + IsStrokeCommand = 1; } - else if(m_StoreCommands && pCommand->m_Flags&CFGFLAG_STORE) + + if(Stroke || IsStrokeCommand) { - m_ExecutionQueue.AddEntry(); - m_ExecutionQueue.m_pLast->m_pfnCommandCallback = pCommand->m_pfnCallback; - m_ExecutionQueue.m_pLast->m_pCommandUserData = pCommand->m_pUserData; - m_ExecutionQueue.m_pLast->m_Result = Result; + if(ParseArgs(&Result, pCommand->m_pParams)) + { + char aBuf[256]; + str_format(aBuf, sizeof(aBuf), "Invalid arguments... Usage: %s %s", pCommand->m_pName, pCommand->m_pParams); + Print(OUTPUT_LEVEL_STANDARD, "Console", aBuf); + } + else if(m_StoreCommands && pCommand->m_Flags&CFGFLAG_STORE) + { + m_ExecutionQueue.AddEntry(); + m_ExecutionQueue.m_pLast->m_pfnCommandCallback = pCommand->m_pfnCallback; + m_ExecutionQueue.m_pLast->m_pCommandUserData = pCommand->m_pUserData; + m_ExecutionQueue.m_pLast->m_Result = Result; + } + else + pCommand->m_pfnCallback(&Result, pCommand->m_pUserData); } - else - pCommand->m_pfnCallback(&Result, pCommand->m_pUserData); + } + else if(Stroke) + { + char aBuf[256]; + str_format(aBuf, sizeof(aBuf), "Access for command %s denied.", Result.m_pCommand); + Print(OUTPUT_LEVEL_STANDARD, "Console", aBuf); } } else if(Stroke) @@ -294,8 +307,7 @@ void CConsole::ExecuteLineStroked(int Stroke, const char *pStr) void CConsole::PossibleCommands(const char *pStr, int FlagMask, FPossibleCallback pfnCallback, void *pUser) { - CCommand *pCommand; - for(pCommand = m_pFirstCommand; pCommand; pCommand = pCommand->m_pNext) + for(CCommand *pCommand = m_pFirstCommand; pCommand; pCommand = pCommand->m_pNext) { if(pCommand->m_Flags&FlagMask) { @@ -307,8 +319,7 @@ void CConsole::PossibleCommands(const char *pStr, int FlagMask, FPossibleCallbac CConsole::CCommand *CConsole::FindCommand(const char *pName, int FlagMask) { - CCommand *pCommand; - for (pCommand = m_pFirstCommand; pCommand; pCommand = pCommand->m_pNext) + for(CCommand *pCommand = m_pFirstCommand; pCommand; pCommand = pCommand->m_pNext) { if(pCommand->m_Flags&FlagMask) { @@ -383,6 +394,62 @@ void CConsole::Con_Exec(IResult *pResult, void *pUserData) ((CConsole*)pUserData)->ExecuteFile(pResult->GetString(0)); } +void CConsole::ConModCommandAccess(IResult *pResult, void *pUser) +{ + CConsole* pConsole = static_cast<CConsole *>(pUser); + char aBuf[128]; + CCommand *pCommand = pConsole->FindCommand(pResult->GetString(0), CFGFLAG_SERVER); + if(pCommand) + { + if(pResult->NumArguments() == 2) + { + pCommand->m_AccessLevel = clamp(pResult->GetInteger(1), (int)(ACCESS_LEVEL_ADMIN), (int)(ACCESS_LEVEL_MOD)); + str_format(aBuf, sizeof(aBuf), "moderator access for '%s' is now %s", pResult->GetString(0), pCommand->m_AccessLevel ? "enabled" : "disabled"); + } + else + str_format(aBuf, sizeof(aBuf), "moderator access for '%s' is %s", pResult->GetString(0), pCommand->m_AccessLevel ? "enabled" : "disabled"); + } + else + str_format(aBuf, sizeof(aBuf), "No such command: '%s'.", pResult->GetString(0)); + + pConsole->Print(OUTPUT_LEVEL_STANDARD, "Console", aBuf); +} + +void CConsole::ConModCommandStatus(IResult *pResult, void *pUser) +{ + CConsole* pConsole = static_cast<CConsole *>(pUser); + char aBuf[240]; + mem_zero(aBuf, sizeof(aBuf)); + int Used = 0; + + for(CCommand *pCommand = pConsole->m_pFirstCommand; pCommand; pCommand = pCommand->m_pNext) + { + if(pCommand->m_Flags&pConsole->m_FlagMask && pCommand->m_AccessLevel == ACCESS_LEVEL_MOD) + { + int Length = str_length(pCommand->m_pName); + if(Used + Length + 2 < (int)(sizeof(aBuf))) + { + if(Used > 0) + { + Used += 2; + str_append(aBuf, ", ", sizeof(aBuf)); + } + str_append(aBuf, pCommand->m_pName, sizeof(aBuf)); + Used += Length; + } + else + { + pConsole->Print(OUTPUT_LEVEL_STANDARD, "Console", aBuf); + mem_zero(aBuf, sizeof(aBuf)); + str_copy(aBuf, pCommand->m_pName, sizeof(aBuf)); + Used = Length; + } + } + } + if(Used > 0) + pConsole->Print(OUTPUT_LEVEL_STANDARD, "Console", aBuf); +} + struct CIntVariableData { IConsole *m_pConsole; @@ -463,6 +530,7 @@ static void StrVariableCommand(IConsole::IResult *pResult, void *pUserData) CConsole::CConsole(int FlagMask) { m_FlagMask = FlagMask; + m_AccessLevel = ACCESS_LEVEL_ADMIN; m_StoreCommands = true; m_paStrokeStr[0] = "0"; m_paStrokeStr[1] = "1"; @@ -478,6 +546,9 @@ CConsole::CConsole(int FlagMask) Register("echo", "r", CFGFLAG_SERVER|CFGFLAG_CLIENT, Con_Echo, this, "Echo the text"); Register("exec", "r", CFGFLAG_SERVER|CFGFLAG_CLIENT, Con_Exec, this, "Execute the specified file"); + Register("mod_command", "s?i", CFGFLAG_SERVER, ConModCommandAccess, this, "Specify command accessibility for moderators"); + Register("mod_status", "", CFGFLAG_SERVER, ConModCommandStatus, this, "List all commands which are accessible for moderators"); + // TODO: this should disappear #define MACRO_CONFIG_INT(Name,ScriptName,Def,Min,Max,Flags,Desc) \ { \ @@ -524,14 +595,14 @@ void CConsole::ParseArguments(int NumArgs, const char **ppArguments) void CConsole::Register(const char *pName, const char *pParams, int Flags, FCommandCallback pfnFunc, void *pUser, const char *pHelp) { - CCommand *pCommand = (CCommand *)mem_alloc(sizeof(CCommand), sizeof(void*)); + CCommand *pCommand = new(mem_alloc(sizeof(CCommand), sizeof(void*))) CCommand; pCommand->m_pfnCallback = pfnFunc; pCommand->m_pUserData = pUser; pCommand->m_pHelp = pHelp; pCommand->m_pName = pName; pCommand->m_pParams = pParams; pCommand->m_Flags = Flags; - + pCommand->m_AccessLevel = ACCESS_LEVEL_ADMIN; pCommand->m_pNext = m_pFirstCommand; m_pFirstCommand = pCommand; diff --git a/src/engine/shared/console.h b/src/engine/shared/console.h index 0866d8e3..14c48581 100644 --- a/src/engine/shared/console.h +++ b/src/engine/shared/console.h @@ -13,6 +13,7 @@ class CConsole : public IConsole public: CCommand *m_pNext; int m_Flags; + int m_AccessLevel; FCommandCallback m_pfnCallback; void *m_pUserData; }; @@ -41,10 +42,13 @@ class CConsole : public IConsole CExecFile *m_pFirstExec; class IStorage *m_pStorage; + int m_AccessLevel; static void Con_Chain(IResult *pResult, void *pUserData); static void Con_Echo(IResult *pResult, void *pUserData); static void Con_Exec(IResult *pResult, void *pUserData); + static void ConModCommandAccess(IResult *pResult, void *pUser); + static void ConModCommandStatus(IConsole::IResult *pResult, void *pUser); void ExecuteFileRecurse(const char *pFilename); void ExecuteLineStroked(int Stroke, const char *pStr); @@ -153,6 +157,8 @@ public: virtual void RegisterPrintCallback(FPrintCallback pfnPrintCallback, void *pUserData); virtual void Print(int Level, const char *pFrom, const char *pStr); + + void SetAccessLevel(int AccessLevel) { m_AccessLevel = clamp(AccessLevel, (int)(ACCESS_LEVEL_ADMIN), (int)(ACCESS_LEVEL_MOD)); } }; #endif |