diff --git a/src/engine/console.h b/src/engine/console.h index 3d6794c07..1e5f874c5 100644 --- a/src/engine/console.h +++ b/src/engine/console.h @@ -19,6 +19,7 @@ public: ACCESS_LEVEL_ADMIN=0, ACCESS_LEVEL_MOD, + ACCESS_LEVEL_HELPER, ACCESS_LEVEL_USER, TEMPCMD_NAME_LENGTH=32, diff --git a/src/engine/server/server.cpp b/src/engine/server/server.cpp index 1a2db2570..e44f25b20 100644 --- a/src/engine/server/server.cpp +++ b/src/engine/server/server.cpp @@ -910,7 +910,7 @@ void CServer::UpdateClientRconCommands() if(m_aClients[ClientID].m_State != CClient::STATE_EMPTY && m_aClients[ClientID].m_Authed) { - int ConsoleAccessLevel = m_aClients[ClientID].m_Authed == AUTHED_ADMIN ? IConsole::ACCESS_LEVEL_ADMIN : IConsole::ACCESS_LEVEL_MOD; + int ConsoleAccessLevel = m_aClients[ClientID].m_Authed == AUTHED_ADMIN ? IConsole::ACCESS_LEVEL_ADMIN : m_aClients[ClientID].m_Authed == AUTHED_MOD ? IConsole::ACCESS_LEVEL_MOD : IConsole::ACCESS_LEVEL_HELPER; for(int i = 0; i < MAX_RCONCMD_SEND && m_aClients[ClientID].m_pRconCmdToSend; ++i) { SendRconCmdAdd(m_aClients[ClientID].m_pRconCmdToSend, ClientID); @@ -1134,7 +1134,7 @@ void CServer::ProcessClientPacket(CNetChunk *pPacket) 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 : m_aClients[ClientID].m_Authed == AUTHED_MOD ? IConsole::ACCESS_LEVEL_MOD : IConsole::ACCESS_LEVEL_USER); + Console()->SetAccessLevel(m_aClients[ClientID].m_Authed == AUTHED_ADMIN ? IConsole::ACCESS_LEVEL_ADMIN : m_aClients[ClientID].m_Authed == AUTHED_MOD ? IConsole::ACCESS_LEVEL_MOD : m_aClients[ClientID].m_Authed == AUTHED_HELPER ? IConsole::ACCESS_LEVEL_HELPER : IConsole::ACCESS_LEVEL_USER); Console()->ExecuteLineFlag(pCmd, CFGFLAG_SERVER, ClientID); Console()->SetAccessLevel(IConsole::ACCESS_LEVEL_ADMIN); m_RconClientID = IServer::RCON_CID_SERV; @@ -1151,7 +1151,7 @@ void CServer::ProcessClientPacket(CNetChunk *pPacket) if((pPacket->m_Flags&NET_CHUNKFLAG_VITAL) != 0 && Unpacker.Error() == 0) { - if(g_Config.m_SvRconPassword[0] == 0 && g_Config.m_SvRconModPassword[0] == 0) + if(g_Config.m_SvRconPassword[0] == 0 && g_Config.m_SvRconModPassword[0] == 0 && g_Config.m_SvRconHelperPassword[0] == 0) { SendRconLine(ClientID, "No rcon password set on server. Set sv_rcon_password and/or sv_rcon_mod_password to enable the remote console."); } @@ -1201,6 +1201,29 @@ void CServer::ProcessClientPacket(CNetChunk *pPacket) GameServer()->OnSetAuthed(ClientID, AUTHED_MOD); } } + else if(g_Config.m_SvRconHelperPassword[0] && str_comp(pPw, g_Config.m_SvRconHelperPassword) == 0) + { + m_aClients[ClientID].m_LastAuthed = AUTHED_HELPER; + if(m_aClients[ClientID].m_Authed != AUTHED_HELPER) + { + CMsgPacker Msg(NETMSG_RCON_AUTH_STATUS); + Msg.AddInt(1); //authed + Msg.AddInt(1); //cmdlist + SendMsgEx(&Msg, MSGFLAG_VITAL, ClientID, true); + + m_aClients[ClientID].m_Authed = AUTHED_HELPER; + int SendRconCmds = Unpacker.GetInt(); + if(Unpacker.Error() == 0 && SendRconCmds) + m_aClients[ClientID].m_pRconCmdToSend = Console()->FirstCommandInfo(IConsole::ACCESS_LEVEL_HELPER, CFGFLAG_SERVER); + SendRconLine(ClientID, "Helper authentication successful. Limited remote console access granted."); + char aBuf[256]; + str_format(aBuf, sizeof(aBuf), "ClientID=%d authed (helper)", ClientID); + Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "server", aBuf); + + // DDRace + GameServer()->OnSetAuthed(ClientID, AUTHED_HELPER); + } + } else if(g_Config.m_SvRconMaxTries) { m_aClients[ClientID].m_AuthTries++; @@ -1776,7 +1799,8 @@ void CServer::ConStatus(IConsole::IResult *pResult, void *pUser) if(pThis->m_aClients[i].m_State == CClient::STATE_INGAME) { const char *pAuthStr = pThis->m_aClients[i].m_Authed == CServer::AUTHED_ADMIN ? "(Admin)" : - pThis->m_aClients[i].m_Authed == CServer::AUTHED_MOD ? "(Mod)" : ""; + pThis->m_aClients[i].m_Authed == CServer::AUTHED_MOD ? "(Mod)" : + pThis->m_aClients[i].m_Authed == CServer::AUTHED_HELPER ? "(Helper)" : ""; str_format(aBuf, sizeof(aBuf), "id=%d addr=%s name='%s' score=%d client=%d secure=%s %s", i, aAddrStr, pThis->m_aClients[i].m_aName, pThis->m_aClients[i].m_Score, ((CGameContext *)(pThis->GameServer()))->m_apPlayers[i]->m_ClientVersion, pThis->m_NetServer.HasSecurityToken(i) ? "yes":"no", pAuthStr); } @@ -1921,7 +1945,7 @@ void CServer::ConchainMaxclientsperipUpdate(IConsole::IResult *pResult, void *pU ((CServer *)pUserData)->m_NetServer.SetMaxClientsPerIP(pResult->GetInteger(0)); } -void CServer::ConchainModCommandUpdate(IConsole::IResult *pResult, void *pUserData, IConsole::FCommandCallback pfnCallback, void *pCallbackUserData) +void CServer::ConchainCommandAccessUpdate(IConsole::IResult *pResult, void *pUserData, IConsole::FCommandCallback pfnCallback, void *pCallbackUserData) { if(pResult->NumArguments() == 2) { @@ -1935,11 +1959,13 @@ void CServer::ConchainModCommandUpdate(IConsole::IResult *pResult, void *pUserDa { for(int i = 0; i < MAX_CLIENTS; ++i) { - if(pThis->m_aClients[i].m_State == CServer::CClient::STATE_EMPTY || pThis->m_aClients[i].m_Authed != CServer::AUTHED_MOD || - (pThis->m_aClients[i].m_pRconCmdToSend && str_comp(pResult->GetString(0), pThis->m_aClients[i].m_pRconCmdToSend->m_pName) >= 0)) + if(pThis->m_aClients[i].m_State == CServer::CClient::STATE_EMPTY || + (pInfo->GetAccessLevel() > AUTHED_ADMIN - pThis->m_aClients[i].m_Authed && AUTHED_ADMIN - pThis->m_aClients[i].m_Authed < OldAccessLevel) || + (pInfo->GetAccessLevel() < AUTHED_ADMIN - pThis->m_aClients[i].m_Authed && AUTHED_ADMIN - pThis->m_aClients[i].m_Authed > OldAccessLevel) || + (pThis->m_aClients[i].m_pRconCmdToSend && str_comp(pResult->GetString(0), pThis->m_aClients[i].m_pRconCmdToSend->m_pName) >= 0)) continue; - if(OldAccessLevel == IConsole::ACCESS_LEVEL_ADMIN) + if(OldAccessLevel < pInfo->GetAccessLevel()) pThis->SendRconCmdAdd(pInfo, i); else pThis->SendRconCmdRem(pInfo, i); @@ -2022,6 +2048,37 @@ void CServer::ConchainRconModPasswordChange(IConsole::IResult *pResult, void *pU } } +void CServer::ConchainRconHelperPasswordChange(IConsole::IResult *pResult, void *pUserData, IConsole::FCommandCallback pfnCallback, void *pCallbackUserData) +{ + pfnCallback(pResult, pCallbackUserData); + if(pResult->NumArguments() == 1) + { + CServer *pServer = (CServer *)pUserData; + for(int i = 0; i < MAX_CLIENTS; i++) + { + if(pServer->m_aClients[i].m_State == CServer::CClient::STATE_EMPTY) + continue; + if(pServer->m_aClients[i].m_Authed == AUTHED_HELPER) + { + CMsgPacker Msg(NETMSG_RCON_AUTH_STATUS); + Msg.AddInt(0); //authed + Msg.AddInt(0); //cmdlist + pServer->SendMsgEx(&Msg, MSGFLAG_VITAL, i, true); + + pServer->m_aClients[i].m_Authed = AUTHED_NO; + pServer->m_aClients[i].m_LastAuthed = AUTHED_NO; + pServer->m_aClients[i].m_AuthTries = 0; + pServer->m_aClients[i].m_pRconCmdToSend = 0; + + pServer->SendRconLine(i, "Logged out by password change."); + char aBuf[64]; + str_format(aBuf, sizeof(aBuf), "ClientID=%d logged out by password change", i); + pServer->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "server", aBuf); + } + } + } +} + void CServer::RegisterCommands() { m_pConsole = Kernel()->RequestInterface(); @@ -2044,11 +2101,12 @@ void CServer::RegisterCommands() Console()->Chain("password", ConchainSpecialInfoupdate, this); Console()->Chain("sv_max_clients_per_ip", ConchainMaxclientsperipUpdate, this); - Console()->Chain("mod_command", ConchainModCommandUpdate, this); + Console()->Chain("access_level", ConchainCommandAccessUpdate, this); Console()->Chain("console_output_level", ConchainConsoleOutputLevelUpdate, this); Console()->Chain("sv_rcon_password", ConchainRconPasswordChange, this); Console()->Chain("sv_rcon_mod_password", ConchainRconModPasswordChange, this); + Console()->Chain("sv_rcon_helper_password", ConchainRconHelperPasswordChange, this); // register console commands in sub parts m_ServerBan.InitServerBan(Console(), Storage(), this); diff --git a/src/engine/server/server.h b/src/engine/server/server.h index 01f86930f..c45e8134a 100644 --- a/src/engine/server/server.h +++ b/src/engine/server/server.h @@ -83,6 +83,7 @@ public: enum { AUTHED_NO=0, + AUTHED_HELPER, AUTHED_MOD, AUTHED_ADMIN, @@ -263,10 +264,11 @@ public: static void ConLogout(IConsole::IResult *pResult, void *pUser); static void ConchainSpecialInfoupdate(IConsole::IResult *pResult, void *pUserData, IConsole::FCommandCallback pfnCallback, void *pCallbackUserData); static void ConchainMaxclientsperipUpdate(IConsole::IResult *pResult, void *pUserData, IConsole::FCommandCallback pfnCallback, void *pCallbackUserData); - static void ConchainModCommandUpdate(IConsole::IResult *pResult, void *pUserData, IConsole::FCommandCallback pfnCallback, void *pCallbackUserData); + static void ConchainCommandAccessUpdate(IConsole::IResult *pResult, void *pUserData, IConsole::FCommandCallback pfnCallback, void *pCallbackUserData); static void ConchainConsoleOutputLevelUpdate(IConsole::IResult *pResult, void *pUserData, IConsole::FCommandCallback pfnCallback, void *pCallbackUserData); static void ConchainRconPasswordChange(IConsole::IResult *pResult, void *pUserData, IConsole::FCommandCallback pfnCallback, void *pCallbackUserData); static void ConchainRconModPasswordChange(IConsole::IResult *pResult, void *pUserData, IConsole::FCommandCallback pfnCallback, void *pCallbackUserData); + static void ConchainRconHelperPasswordChange(IConsole::IResult *pResult, void *pUserData, IConsole::FCommandCallback pfnCallback, void *pCallbackUserData); void RegisterCommands(); diff --git a/src/engine/shared/config_variables.h b/src/engine/shared/config_variables.h index df156c9a1..50beb5316 100644 --- a/src/engine/shared/config_variables.h +++ b/src/engine/shared/config_variables.h @@ -141,6 +141,7 @@ MACRO_CONFIG_INT(SvHighBandwidth, sv_high_bandwidth, 0, 0, 1, CFGFLAG_SERVER, "U 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 (full access)") MACRO_CONFIG_STR(SvRconModPassword, sv_rcon_mod_password, 32, "", CFGFLAG_SERVER, "Remote console password for moderators (limited access)") +MACRO_CONFIG_STR(SvRconHelperPassword, sv_rcon_helper_password, 32, "", CFGFLAG_SERVER, "Remote console password for helpers (limited access)") MACRO_CONFIG_INT(SvRconMaxTries, sv_rcon_max_tries, 30, 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") MACRO_CONFIG_INT(SvAutoDemoRecord, sv_auto_demo_record, 0, 0, 1, CFGFLAG_SERVER, "Automatically record demos") diff --git a/src/engine/shared/console.cpp b/src/engine/shared/console.cpp index 42a64b443..a5859ad31 100644 --- a/src/engine/shared/console.cpp +++ b/src/engine/shared/console.cpp @@ -514,7 +514,7 @@ void CConsole::Con_Exec(IResult *pResult, void *pUserData) ((CConsole*)pUserData)->ExecuteFile(pResult->GetString(0)); } -void CConsole::ConModCommandAccess(IResult *pResult, void *pUser) +void CConsole::ConCommandAccess(IResult *pResult, void *pUser) { CConsole* pConsole = static_cast(pUser); char aBuf[128]; @@ -526,12 +526,16 @@ void CConsole::ConModCommandAccess(IResult *pResult, void *pUser) pCommand->SetAccessLevel(pResult->GetInteger(1)); str_format(aBuf, sizeof(aBuf), "moderator access for '%s' is now %s", pResult->GetString(0), pCommand->GetAccessLevel() ? "enabled" : "disabled"); pConsole->Print(OUTPUT_LEVEL_STANDARD, "console", aBuf); + str_format(aBuf, sizeof(aBuf), "helper access for '%s' is now %s", pResult->GetString(0), pCommand->GetAccessLevel() >= ACCESS_LEVEL_HELPER ? "enabled" : "disabled"); + pConsole->Print(OUTPUT_LEVEL_STANDARD, "console", aBuf); str_format(aBuf, sizeof(aBuf), "user access for '%s' is now %s", pResult->GetString(0), pCommand->GetAccessLevel() >= ACCESS_LEVEL_USER ? "enabled" : "disabled"); } else { str_format(aBuf, sizeof(aBuf), "moderator access for '%s' is %s", pResult->GetString(0), pCommand->GetAccessLevel() ? "enabled" : "disabled"); pConsole->Print(OUTPUT_LEVEL_STANDARD, "console", aBuf); + str_format(aBuf, sizeof(aBuf), "helper access for '%s' is %s", pResult->GetString(0), pCommand->GetAccessLevel() >= ACCESS_LEVEL_HELPER ? "enabled" : "disabled"); + pConsole->Print(OUTPUT_LEVEL_STANDARD, "console", aBuf); str_format(aBuf, sizeof(aBuf), "user access for '%s' is %s", pResult->GetString(0), pCommand->GetAccessLevel() >= ACCESS_LEVEL_USER ? "enabled" : "disabled"); } } @@ -576,6 +580,41 @@ void CConsole::ConModCommandStatus(IResult *pResult, void *pUser) pConsole->Print(OUTPUT_LEVEL_STANDARD, "console", aBuf); } +void CConsole::ConHelperCommandStatus(IResult *pResult, void *pUser) +{ + CConsole* pConsole = static_cast(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->GetAccessLevel() >= ACCESS_LEVEL_HELPER) + { + 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; @@ -753,8 +792,9 @@ CConsole::CConsole(int FlagMask) Register("toggle", "sii", CFGFLAG_SERVER|CFGFLAG_CLIENT, ConToggle, this, "Toggle config value"); Register("+toggle", "sii", CFGFLAG_CLIENT, ConToggleStroke, this, "Toggle config value via keypress"); - Register("mod_command", "s?i", CFGFLAG_SERVER, ConModCommandAccess, this, "Specify command accessibility for moderators"); + Register("access_level", "s?i", CFGFLAG_SERVER, ConCommandAccess, this, "Specify command accessibility (admin = 0, moderator = 1, helper = 2, all = 3)"); Register("mod_status", "", CFGFLAG_SERVER, ConModCommandStatus, this, "List all commands which are accessible for moderators"); + Register("helper_status", "", CFGFLAG_SERVER, ConHelperCommandStatus, this, "List all commands which are accessible for helpers"); Register("user_status", "", CFGFLAG_SERVER, ConUserCommandStatus, this, "List all commands which are accessible for users"); Register("cmdlist", "", CFGFLAG_SERVER|CFGFLAG_CHAT, ConUserCommandStatus, this, "List all commands which are accessible for users"); diff --git a/src/engine/shared/console.h b/src/engine/shared/console.h index 18825c8d8..76918670c 100644 --- a/src/engine/shared/console.h +++ b/src/engine/shared/console.h @@ -56,8 +56,9 @@ class CConsole : public IConsole static void Con_Exec(IResult *pResult, void *pUserData); static void ConToggle(IResult *pResult, void *pUser); static void ConToggleStroke(IResult *pResult, void *pUser); - static void ConModCommandAccess(IResult *pResult, void *pUser); + static void ConCommandAccess(IResult *pResult, void *pUser); static void ConModCommandStatus(IConsole::IResult *pResult, void *pUser); + static void ConHelperCommandStatus(IConsole::IResult *pResult, void *pUser); void ExecuteFileRecurse(const char *pFilename); void ExecuteLineStroked(int Stroke, const char *pStr, int ClientID = -1); diff --git a/src/game/server/gamecontext.cpp b/src/game/server/gamecontext.cpp index 688c8f977..3e74207f0 100644 --- a/src/game/server/gamecontext.cpp +++ b/src/game/server/gamecontext.cpp @@ -1096,7 +1096,7 @@ void CGameContext::OnMessage(int MsgID, CUnpacker *pUnpacker, int ClientID) Console()->SetFlagMask(CFGFLAG_CHAT); if (pPlayer->m_Authed) - Console()->SetAccessLevel(pPlayer->m_Authed == CServer::AUTHED_ADMIN ? IConsole::ACCESS_LEVEL_ADMIN : IConsole::ACCESS_LEVEL_MOD); + Console()->SetAccessLevel(pPlayer->m_Authed == CServer::AUTHED_ADMIN ? IConsole::ACCESS_LEVEL_ADMIN : pPlayer->m_Authed == CServer::AUTHED_MOD ? IConsole::ACCESS_LEVEL_MOD : IConsole::ACCESS_LEVEL_HELPER); else Console()->SetAccessLevel(IConsole::ACCESS_LEVEL_USER); Console()->SetPrintOutputLevel(m_ChatPrintCBIndex, 0);