about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/engine/console.h3
-rw-r--r--src/engine/server/server.cpp119
-rw-r--r--src/engine/server/server.h11
-rw-r--r--src/engine/shared/console.cpp4
-rw-r--r--src/engine/shared/console.h2
5 files changed, 130 insertions, 9 deletions
diff --git a/src/engine/console.h b/src/engine/console.h
index 8951d2d1..44c40c16 100644
--- a/src/engine/console.h
+++ b/src/engine/console.h
@@ -18,6 +18,7 @@ public:
 		OUTPUT_LEVEL_DEBUG,
 
 		ACCESS_LEVEL_ADMIN=0,
+		ACCESS_LEVEL_SUBADMIN,
 		ACCESS_LEVEL_MOD,
 
 		TEMPCMD_NAME_LENGTH=32,
@@ -69,7 +70,7 @@ public:
 	virtual void PossibleCommands(const char *pStr, int FlagMask, bool Temp, FPossibleCallback pfnCallback, void *pUser) = 0;
 	virtual void ParseArguments(int NumArgs, const char **ppArguments) = 0;
 
-	virtual void Register(const char *pName, const char *pParams, int Flags, FCommandCallback pfnFunc, void *pUser, const char *pHelp) = 0;
+	virtual void Register(const char *pName, const char *pParams, int Flags, FCommandCallback pfnFunc, void *pUser, const char *pHelp, int accessLevel = ACCESS_LEVEL_SUBADMIN) = 0;
 	virtual void RegisterTemp(const char *pName, const char *pParams, int Flags, const char *pHelp) = 0;
 	virtual void DeregisterTemp(const char *pName) = 0;
 	virtual void DeregisterTempAll() = 0;
diff --git a/src/engine/server/server.cpp b/src/engine/server/server.cpp
index 2ad7fbf0..0aa8fde4 100644
--- a/src/engine/server/server.cpp
+++ b/src/engine/server/server.cpp
@@ -31,6 +31,10 @@
 #include "register.h"
 #include "server.h"
 
+#include <string.h>
+#include <string>
+#include <map>
+
 #if defined(CONF_FAMILY_WINDOWS)
 	#define _WIN32_WINNT 0x0501
 	#define WIN32_LEAN_AND_MEAN
@@ -869,7 +873,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 : (AUTHED_SUBADMIN ? IConsole::ACCESS_LEVEL_SUBADMIN : IConsole::ACCESS_LEVEL_MOD);
 		for(int i = 0; i < MAX_RCONCMD_SEND && m_aClients[ClientID].m_pRconCmdToSend; ++i)
 		{
 			SendRconCmdAdd(m_aClients[ClientID].m_pRconCmdToSend, ClientID);
@@ -1050,7 +1054,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 : IConsole::ACCESS_LEVEL_MOD);
+				Console()->SetAccessLevel(m_aClients[ClientID].m_Authed == AUTHED_ADMIN ? IConsole::ACCESS_LEVEL_ADMIN : (m_aClients[ClientID].m_Authed == AUTHED_SUBADMIN ? IConsole::ACCESS_LEVEL_SUBADMIN : IConsole::ACCESS_LEVEL_MOD));
 				Console()->ExecuteLineFlag(pCmd, CFGFLAG_SERVER);
 				Console()->SetAccessLevel(IConsole::ACCESS_LEVEL_ADMIN);
 				m_RconClientID = IServer::RCON_CID_SERV;
@@ -1062,12 +1066,23 @@ void CServer::ProcessClientPacket(CNetChunk *pPacket)
 			const char *pPw;
 			Unpacker.GetString(); // login name, not used
 			pPw = Unpacker.GetString(CUnpacker::SANITIZE_CC);
-
+			
+			// try matching username:password login
+			const char *delimiter = strchr(pPw, ':');
+			std::string username, password;
+			loginiterator loginit;
+			bool loginWithUsername = (delimiter != NULL);
+			if(loginWithUsername)
+			{
+				username.assign(pPw, delimiter - pPw);
+				password.assign(delimiter + 1);
+			}
+			
 			if(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 && logins.empty())
 				{
-					SendRconLine(ClientID, "No rcon password set on server. Set sv_rcon_password and/or sv_rcon_mod_password to enable the remote console.");
+					SendRconLine(ClientID, "No rcon password set on server. Set sv_rcon_password and/or sv_rcon_mod_password or add logins using add_login to enable the remote console.");
 				}
 				else if(g_Config.m_SvRconPassword[0] && str_comp(pPw, g_Config.m_SvRconPassword) == 0)
 				{
@@ -1075,7 +1090,7 @@ void CServer::ProcessClientPacket(CNetChunk *pPacket)
 					Msg.AddInt(1);	//authed
 					Msg.AddInt(1);	//cmdlist
 					SendMsgEx(&Msg, MSGFLAG_VITAL, ClientID, true);
-
+					
 					m_aClients[ClientID].m_Authed = AUTHED_ADMIN;
 					int SendRconCmds = Unpacker.GetInt();
 					if(Unpacker.Error() == 0 && SendRconCmds)
@@ -1102,6 +1117,28 @@ void CServer::ProcessClientPacket(CNetChunk *pPacket)
 					str_format(aBuf, sizeof(aBuf), "ClientID=%d authed (moderator)", ClientID);
 					Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "server", aBuf);
 				}
+				else if(loginWithUsername
+					&& !logins.empty()
+					&& (loginit = logins.find(username)) != logins.end()
+					&& loginit->second == password)
+				{
+					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_SUBADMIN;
+					m_aClients[ClientID].m_SubAdminAuthName = loginit->first;
+					
+					int SendRconCmds = Unpacker.GetInt();
+					if(Unpacker.Error() == 0 && SendRconCmds)
+						m_aClients[ClientID].m_pRconCmdToSend = Console()->FirstCommandInfo(IConsole::ACCESS_LEVEL_SUBADMIN, CFGFLAG_SERVER);
+					SendRconLine(ClientID, "Subadmin authentication successful. Limited remote console access granted.");
+					char aBuf[256];
+					str_format(aBuf, sizeof(aBuf), "ClientID=%d authed (subadmin:%s)", ClientID, loginit->first.c_str());
+					Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "server", aBuf);
+					IncreaseLoggedInAdmins();
+				}
 				else if(g_Config.m_SvRconMaxTries)
 				{
 					m_aClients[ClientID].m_AuthTries++;
@@ -1703,6 +1740,70 @@ void CServer::ConVotebans(IConsole::IResult *pResult, void *pUser)
 	pThis->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "Server", aBuf);
 }
 
+void CServer::ConAddLogin(IConsole::IResult *pResult, void *pUser)
+{
+	CServer* pThis = static_cast<CServer *>(pUser);
+	char aBuf[128];
+	std::string username(pResult->GetString(0)),
+		password(pResult->GetString(1));
+	
+	// insert if doesn't exist
+	if(pThis->logins.find(username) == pThis->logins.end())
+	{
+		pThis->logins[username] = password;
+		
+		str_format(aBuf, sizeof(aBuf), "Added login for '%s'.", username.c_str());
+		pThis->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "Server", aBuf);
+	}
+	else
+	{
+		pThis->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "Server", "Did not overwrite existing login.");
+	}
+}
+
+void CServer::ConRemoveLogin(IConsole::IResult *pResult, void *pUser)
+{
+	CServer* pThis = static_cast<CServer *>(pUser);
+	char aBuf[128];
+	loginiterator loginit;
+	std::string username(pResult->GetString(0));
+	
+	// delete if exists
+	if((loginit = pThis->logins.find(username)) != pThis->logins.end())
+	{
+		// check if someone is logged in with this login
+		for(int i = 0; i < MAX_CLIENTS; i++)
+		{
+			if(pThis->m_aClients[i].m_State != CClient::STATE_EMPTY && pThis->m_aClients[i].m_Authed == CServer::AUTHED_SUBADMIN && pThis->m_aClients[i].m_SubAdminAuthName == loginit->first)
+			{
+				CMsgPacker Msg(NETMSG_RCON_AUTH_STATUS);
+				Msg.AddInt(0);
+				Msg.AddInt(0);
+				pThis->SendMsgEx(&Msg, MSGFLAG_VITAL, i, true);
+
+				pThis->m_aClients[i].m_Authed = AUTHED_NO;
+				pThis->m_aClients[i].m_AuthTries = 0;
+				pThis->m_aClients[i].m_pRconCmdToSend = 0;
+				pThis->SendRconLine(i, "You were logged out.");
+				char aBuf[32];
+				str_format(aBuf, sizeof(aBuf), "ClientID=%d logged out", i);
+				pThis->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "server", aBuf);
+				pThis->DecreaseLoggedInAdmins();
+			}
+		}
+		
+		// finally delete
+		pThis->logins.erase(loginit);
+		
+		str_format(aBuf, sizeof(aBuf), "Removed login '%s'.", username.c_str());
+		pThis->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "Server", aBuf);
+	}
+	else
+	{
+		pThis->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "Server", "No login with that username.");
+	}
+}
+
 void CServer::ConKick(IConsole::IResult *pResult, void *pUser)
 {
 	if(pResult->NumArguments() > 1)
@@ -1728,7 +1829,10 @@ void CServer::ConStatus(IConsole::IResult *pResult, void *pUser)
 			net_addr_str(pThis->m_NetServer.ClientAddr(i), aAddrStr, sizeof(aAddrStr), true);
 			if(pThis->m_aClients[i].m_State == CClient::STATE_INGAME)
 			{
+				char bBuf[32];
+				str_format(bBuf, sizeof(bBuf), "(Subadmin:%s)", pThis->m_aClients[i].m_SubAdminAuthName.c_str());
 				const char *pAuthStr = pThis->m_aClients[i].m_Authed == CServer::AUTHED_ADMIN ? "(Admin)" :
+										pThis->m_aClients[i].m_Authed == CServer::AUTHED_SUBADMIN ? bBuf :
 										pThis->m_aClients[i].m_Authed == CServer::AUTHED_MOD ? "(Mod)" : "";
 				const char *pAimBotStr = pThis->GameServer()->IsClientAimBot(i) ? "[aimbot]" : "";
 				str_format(aBuf, sizeof(aBuf), "id=%d addr=%s name='%s' score=%d %s %s", i, aAddrStr,
@@ -1907,6 +2011,9 @@ void CServer::RegisterCommands()
 	Console()->Register("unvoteban", "i", CFGFLAG_SERVER, ConUnvoteban, this, "Remove voteban by index in list votebans");
 	Console()->Register("unvoteban_client", "i", CFGFLAG_SERVER, ConUnvotebanClient, this, "Remove voteban by player id");
 	Console()->Register("votebans", "", CFGFLAG_SERVER, ConVotebans, this, "Show all votebans");
+	
+	Console()->Register("add_login", "ss", CFGFLAG_SERVER, ConAddLogin, this, "Add a subadmin login. The rcon password will be user:pass with no additional spaces.", IConsole::ACCESS_LEVEL_ADMIN);
+	Console()->Register("remove_login", "s", CFGFLAG_SERVER, ConRemoveLogin, this, "Remove a subadmin login", IConsole::ACCESS_LEVEL_ADMIN);
 
 	// 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 ebbcc82c..1958c4e6 100644
--- a/src/engine/server/server.h
+++ b/src/engine/server/server.h
@@ -6,6 +6,9 @@
 
 #include <engine/server.h>
 
+#include <string>
+#include <map>
+
 
 class CSnapIDPool
 {
@@ -84,6 +87,7 @@ public:
 	{
 		AUTHED_NO=0,
 		AUTHED_MOD,
+		AUTHED_SUBADMIN,
 		AUTHED_ADMIN,
 
 		MAX_RCONCMD_SEND=16,
@@ -132,6 +136,7 @@ public:
 		int m_Score;
 		int m_Authed;
 		int m_AuthTries;
+		std::string m_SubAdminAuthName;
 
 		const IConsole::CCommandInfo *m_pRconCmdToSend;
 
@@ -280,8 +285,14 @@ public:
 	static void ConUnvoteban(IConsole::IResult *pResult, void *pUser);
 	static void ConUnvotebanClient(IConsole::IResult *pResult, void *pUser);
 	static void ConVotebans(IConsole::IResult *pResult, void *pUser);
+	static void ConAddLogin(IConsole::IResult *pResult, void *pUser);
+	static void ConRemoveLogin(IConsole::IResult *pResult, void *pUser);
 	
 	virtual int GetNumLoggedInAdmins() { return m_numLoggedInAdmins; }
+	
+	// logins
+	typedef std::map<std::string,std::string>::iterator loginiterator;
+	std::map<std::string,std::string> logins;
 };
 
 #endif
diff --git a/src/engine/shared/console.cpp b/src/engine/shared/console.cpp
index 399f5323..dcace5b8 100644
--- a/src/engine/shared/console.cpp
+++ b/src/engine/shared/console.cpp
@@ -738,7 +738,7 @@ void CConsole::AddCommandSorted(CCommand *pCommand)
 }
 
 void CConsole::Register(const char *pName, const char *pParams,
-	int Flags, FCommandCallback pfnFunc, void *pUser, const char *pHelp)
+	int Flags, FCommandCallback pfnFunc, void *pUser, const char *pHelp, int accessLevel)
 {
 	CCommand *pCommand = FindCommand(pName, Flags);
 	bool DoAdd = false;
@@ -756,6 +756,8 @@ void CConsole::Register(const char *pName, const char *pParams,
 
 	pCommand->m_Flags = Flags;
 	pCommand->m_Temp = false;
+	
+	pCommand->SetAccessLevel(accessLevel);
 
 	if(DoAdd)
 		AddCommandSorted(pCommand);
diff --git a/src/engine/shared/console.h b/src/engine/shared/console.h
index bbe267d4..a3d65eb3 100644
--- a/src/engine/shared/console.h
+++ b/src/engine/shared/console.h
@@ -163,7 +163,7 @@ public:
 	virtual void PossibleCommands(const char *pStr, int FlagMask, bool Temp, FPossibleCallback pfnCallback, void *pUser);
 
 	virtual void ParseArguments(int NumArgs, const char **ppArguments);
-	virtual void Register(const char *pName, const char *pParams, int Flags, FCommandCallback pfnFunc, void *pUser, const char *pHelp);
+	virtual void Register(const char *pName, const char *pParams, int Flags, FCommandCallback pfnFunc, void *pUser, const char *pHelp, int accessLevel = ACCESS_LEVEL_SUBADMIN);
 	virtual void RegisterTemp(const char *pName, const char *pParams, int Flags, const char *pHelp);
 	virtual void DeregisterTemp(const char *pName);
 	virtual void DeregisterTempAll();