New auth system for rcon

This commit is contained in:
Learath2 2017-03-02 18:16:29 +03:00
parent acb1ada28c
commit b7cbaedea0
6 changed files with 546 additions and 52 deletions

View file

@ -2146,6 +2146,49 @@ void str_hex(char *dst, int dst_size, const void *data, int data_size)
}
}
static int hexval(char x)
{
switch (x)
{
case '0': return 0;
case '1': return 1;
case '2': return 2;
case '3': return 3;
case '4': return 4;
case '5': return 5;
case '6': return 6;
case '7': return 7;
case '8': return 8;
case '9': return 9;
case 'a':
case 'A': return 10;
case 'b':
case 'B': return 11;
case 'c':
case 'C': return 12;
case 'd':
case 'D': return 13;
case 'e':
case 'E': return 14;
case 'f':
case 'F': return 15;
default: return -1;
}
}
static unsigned char byteval(const char *byte)
{
return hexval(byte[0]) * 16 + hexval(byte[1]);
}
void str_hex_decode(unsigned char *dst, int dst_size, const char *src)
{
int len = str_length(src)/2;
int i = 0;
for(; i < len && dst_size; i++, dst_size--)
*dst++ = byteval(src + i * 2);
}
void str_timestamp_ex(time_t time_data, char *buffer, int buffer_size, const char *format)
{
struct tm *time_info;

View file

@ -1016,6 +1016,17 @@ const char *str_find(const char *haystack, const char *needle);
*/
void str_hex(char *dst, int dst_size, const void *data, int data_size);
/*
Function: str_hex_decode
Takes a hex string and returns a byte array.
Parameters:
dst - Buffer for the byte array
dst_size - size of the buffer
data - String to decode
data_size - Size of the data
*/
void str_hex_decode(unsigned char *dst, int dst_size, const char *src);
/*
Function: str_timestamp
Copies a time stamp in the format year-month-day_hour-minute-second to the string.

View file

@ -0,0 +1,162 @@
#include <engine/external/md5/md5.h>
#include <engine/shared/config.h>
#include "authmanager.h"
#define ADMIN_IDENT "default_admin"
#define MOD_IDENT "default_mod"
#define HELPER_IDENT "default_helper"
CAuthManager::CAuthManager()
{
m_aDefault[0] = -1;
m_aDefault[1] = -1;
m_aDefault[2] = -1;
}
void CAuthManager::Init()
{
if(g_Config.m_SvRconPassword[0])
AddAdminKey(g_Config.m_SvRconPassword);
if(g_Config.m_SvRconModPassword[0])
AddModKey(g_Config.m_SvRconModPassword);
if (g_Config.m_SvRconHelperPassword[0])
AddHelperKey(g_Config.m_SvRconHelperPassword);
}
int CAuthManager::AddKeyHash(const char *pIdent, const unsigned char *pHash, const unsigned char *pSalt, int AuthLevel)
{
CKey Key;
str_copy(Key.m_aIdent, pIdent, sizeof Key.m_aIdent);
mem_copy(Key.m_aPw, pHash, MD5_BYTES);
mem_copy(Key.m_aSalt, pSalt, SALT_BYTES);
Key.m_Level = AuthLevel;
return m_aKeys.add(Key);
}
int CAuthManager::AddKey(const char *pIdent, const char *pPw, int AuthLevel)
{
md5_state_t ctx;
unsigned char aHash[MD5_BYTES];
unsigned char aSalt[SALT_BYTES];
//Generate random salt
secure_random_fill(aSalt, SALT_BYTES);
//Hash the password and the salt
md5_init(&ctx);
md5_append(&ctx, (unsigned char *)pPw, str_length(pPw));
md5_append(&ctx, aSalt, SALT_BYTES);
md5_finish(&ctx, aHash);
return AddKeyHash(pIdent, aHash, aSalt, AuthLevel);
}
void CAuthManager::RemoveKey(int Slot)
{
m_aKeys.remove_index_fast(Slot);
}
int CAuthManager::FindKey(const char *pIdent)
{
for(int i = 0; i < m_aKeys.size(); i++)
if(!str_comp(m_aKeys[i].m_aIdent, pIdent))
return i;
return -1;
}
bool CAuthManager::CheckKey(int Slot, const char *pPw)
{
if(Slot < 0 || Slot > m_aKeys.size())
return false;
md5_state_t ctx;
unsigned char aHash[MD5_BYTES];
//Hash the password and the salt
md5_init(&ctx);
md5_append(&ctx, (unsigned char*)pPw, str_length(pPw));
md5_append(&ctx, m_aKeys[Slot].m_aSalt, SALT_BYTES);
md5_finish(&ctx, aHash);
return !mem_comp(m_aKeys[Slot].m_aPw, aHash, MD5_BYTES);
}
int CAuthManager::DefaultKey(int AuthLevel)
{
if(AuthLevel < 0 || AuthLevel > AUTHED_ADMIN)
return -1;
return m_aDefault[AUTHED_ADMIN - AuthLevel];
}
int CAuthManager::KeyLevel(int Slot)
{
if(Slot < 0 || Slot > m_aKeys.size())
return AUTHED_NO;
return m_aKeys[Slot].m_Level;
}
const char *CAuthManager::KeyIdent(int Slot)
{
if(Slot < 0 || Slot > m_aKeys.size())
return 0;
return m_aKeys[Slot].m_aIdent;
}
void CAuthManager::UpdateKeyHash(int Slot, const unsigned char *pHash, const unsigned char *pSalt, int AuthLevel)
{
if(Slot < 0 || Slot > m_aKeys.size())
return;
CKey *pKey = &m_aKeys[Slot];
mem_copy(pKey->m_aPw, pHash, MD5_BYTES);
mem_copy(pKey->m_aSalt, pSalt, SALT_BYTES);
pKey->m_Level = AuthLevel;
}
void CAuthManager::UpdateKey(int Slot, const char *pPw, int AuthLevel)
{
if(Slot < 0 || Slot > m_aKeys.size())
return;
md5_state_t ctx;
unsigned char aHash[MD5_BYTES];
unsigned char aSalt[SALT_BYTES];
//Generate random salt
secure_random_fill(aSalt, SALT_BYTES);
//Hash the password and the salt
md5_init(&ctx);
md5_append(&ctx, (unsigned char *)pPw, str_length(pPw));
md5_append(&ctx, aSalt, SALT_BYTES);
md5_finish(&ctx, aHash);
UpdateKeyHash(Slot, aHash, aSalt, AuthLevel);
}
void CAuthManager::ListKeys(FListCallback pfnListCallback, void *pUser)
{
for(int i = 0; i < m_aKeys.size(); i++)
pfnListCallback(m_aKeys[i].m_aIdent, m_aKeys[i].m_Level, pUser);
}
void CAuthManager::AddAdminKey(const char *pPw)
{
m_aDefault[0] = AddKey(ADMIN_IDENT, pPw, AUTHED_ADMIN);
}
void CAuthManager::AddModKey(const char *pPw)
{
m_aDefault[1] = AddKey(MOD_IDENT, pPw, AUTHED_MOD);
}
void CAuthManager::AddHelperKey(const char *pPw)
{
m_aDefault[2] = AddKey(HELPER_IDENT, pPw, AUTHED_HELPER);
}

View file

@ -0,0 +1,50 @@
#ifndef ENGINE_SERVER_AUTH_MANAGER_H
#define ENGINE_SERVER_AUTH_MANAGER_H
#include <base/tl/array.h>
#define MD5_BYTES 16
#define SALT_BYTES 8
class CAuthManager
{
private:
enum { //:(
AUTHED_NO = 0,
AUTHED_HELPER,
AUTHED_MOD,
AUTHED_ADMIN
};
struct CKey
{
char m_aIdent[64];
unsigned char m_aPw[MD5_BYTES];
unsigned char m_aSalt[SALT_BYTES];
int m_Level;
};
array<CKey> m_aKeys;
int m_aDefault[3];
public:
typedef void (*FListCallback)(const char *pIdent, int Level, void *pUser);
CAuthManager();
void Init();
int AddKeyHash(const char *pIdent, const unsigned char *pHash, const unsigned char *pSalt, int AuthLevel);
int AddKey(const char *pIdent, const char *pPw, int AuthLevel);
void RemoveKey(int Slot);
int FindKey(const char *pIdent);
bool CheckKey(int Slot, const char *pPw);
int DefaultKey(int AuthLevel);
int KeyLevel(int Slot);
const char *KeyIdent(int Slot);
void UpdateKeyHash(int Slot, const unsigned char *pHash, const unsigned char *pSalt, int AuthLevel);
void UpdateKey(int Slot, const char *pPw, int AuthLevel);
void ListKeys(FListCallback pfnListCallbac, void *pUser);
void AddAdminKey(const char *pPw);
void AddModKey(const char *pPw);
void AddHelperKey(const char *pPw);
};
#endif //ENGINE_SERVER_AUTH_MANAGER_H

View file

@ -468,6 +468,7 @@ int CServer::Init()
m_aClients[i].m_Snapshots.Init();
m_aClients[i].m_Traffic = 0;
m_aClients[i].m_TrafficSince = 0;
m_aClients[i].m_AuthKey = -1;
}
m_CurrentGameTick = 0;
@ -770,6 +771,7 @@ int CServer::ClientRejoinCallback(int ClientID, void *pUser)
CServer *pThis = (CServer *)pUser;
pThis->m_aClients[ClientID].m_Authed = AUTHED_NO;
pThis->m_aClients[ClientID].m_AuthKey = 0;
pThis->m_aClients[ClientID].m_pRconCmdToSend = 0;
pThis->m_aClients[ClientID].Reset();
@ -792,6 +794,7 @@ int CServer::NewClientNoAuthCallback(int ClientID, bool Reset, void *pUser)
pThis->m_aClients[ClientID].m_aClan[0] = 0;
pThis->m_aClients[ClientID].m_Country = -1;
pThis->m_aClients[ClientID].m_Authed = AUTHED_NO;
pThis->m_aClients[ClientID].m_AuthKey = 0;
pThis->m_aClients[ClientID].m_AuthTries = 0;
pThis->m_aClients[ClientID].m_pRconCmdToSend = 0;
pThis->m_aClients[ClientID].Reset();
@ -811,6 +814,7 @@ int CServer::NewClientCallback(int ClientID, void *pUser)
pThis->m_aClients[ClientID].m_aClan[0] = 0;
pThis->m_aClients[ClientID].m_Country = -1;
pThis->m_aClients[ClientID].m_Authed = AUTHED_NO;
pThis->m_aClients[ClientID].m_AuthKey = 0;
pThis->m_aClients[ClientID].m_AuthTries = 0;
pThis->m_aClients[ClientID].m_pRconCmdToSend = 0;
pThis->m_aClients[ClientID].m_Traffic = 0;
@ -860,6 +864,7 @@ int CServer::DelClientCallback(int ClientID, const char *pReason, void *pUser)
pThis->m_aClients[ClientID].m_aClan[0] = 0;
pThis->m_aClients[ClientID].m_Country = -1;
pThis->m_aClients[ClientID].m_Authed = AUTHED_NO;
pThis->m_aClients[ClientID].m_AuthKey = 0;
pThis->m_aClients[ClientID].m_AuthTries = 0;
pThis->m_aClients[ClientID].m_pRconCmdToSend = 0;
pThis->m_aClients[ClientID].m_Traffic = 0;
@ -1188,9 +1193,8 @@ void CServer::ProcessClientPacket(CNetChunk *pPacket)
}
else if(Msg == NETMSG_RCON_AUTH)
{
const char *pPw;
Unpacker.GetString(); // login name, not used
pPw = Unpacker.GetString(CUnpacker::SANITIZE_CC);
const char *pName = Unpacker.GetString(CUnpacker::SANITIZE_CC); // login name, now used
const char *pPw = Unpacker.GetString(CUnpacker::SANITIZE_CC);
if(!str_utf8_check(pPw))
{
return;
@ -1199,17 +1203,23 @@ void CServer::ProcessClientPacket(CNetChunk *pPacket)
if((pPacket->m_Flags&NET_CHUNKFLAG_VITAL) != 0 && Unpacker.Error() == 0)
{
int AuthLevel = -1;
int KeySlot = -1;
if(g_Config.m_SvRconPassword[0] == 0 && g_Config.m_SvRconModPassword[0] == 0 && g_Config.m_SvRconHelperPassword[0] == 0)
if(!pName[0])
{
SendRconLine(ClientID, "No rcon password set on server. Set sv_rcon_password and/or sv_rcon_mod_password to enable the remote console.");
if(m_AuthManager.CheckKey((KeySlot = m_AuthManager.DefaultKey(AUTHED_ADMIN)), pPw))
AuthLevel = AUTHED_ADMIN;
else if(m_AuthManager.CheckKey((KeySlot = m_AuthManager.DefaultKey(AUTHED_MOD)), pPw))
AuthLevel = AUTHED_MOD;
else if(m_AuthManager.CheckKey((KeySlot = m_AuthManager.DefaultKey(AUTHED_HELPER)), pPw))
AuthLevel = AUTHED_HELPER;
}
else
{
KeySlot = m_AuthManager.FindKey(pName);
if(m_AuthManager.CheckKey(KeySlot, pPw))
AuthLevel = m_AuthManager.KeyLevel(KeySlot);
}
else if(g_Config.m_SvRconPassword[0] && str_comp(pPw, g_Config.m_SvRconPassword) == 0)
AuthLevel = AUTHED_ADMIN;
else if(g_Config.m_SvRconModPassword[0] && str_comp(pPw, g_Config.m_SvRconModPassword) == 0)
AuthLevel = AUTHED_MOD;
else if(g_Config.m_SvRconHelperPassword[0] && str_comp(pPw, g_Config.m_SvRconHelperPassword) == 0)
AuthLevel = AUTHED_HELPER;
if(AuthLevel != -1)
{
@ -1220,31 +1230,33 @@ void CServer::ProcessClientPacket(CNetChunk *pPacket)
Msg.AddInt(1); //cmdlist
SendMsgEx(&Msg, MSGFLAG_VITAL, ClientID, true);
m_aClients[ClientID].m_Authed = AuthLevel;
m_aClients[ClientID].m_Authed = AuthLevel; //Keeping m_Authed around is unwise...
m_aClients[ClientID].m_AuthKey = KeySlot;
int SendRconCmds = Unpacker.GetInt();
if(Unpacker.Error() == 0 && SendRconCmds)
// AUTHED_ADMIN - AuthLevel gets the proper IConsole::ACCESS_LEVEL_<x>
m_aClients[ClientID].m_pRconCmdToSend = Console()->FirstCommandInfo(AUTHED_ADMIN - AuthLevel, CFGFLAG_SERVER);
char aBuf[256];
const char *pIdent = m_AuthManager.KeyIdent(KeySlot);
switch (AuthLevel)
{
case AUTHED_ADMIN:
{
SendRconLine(ClientID, "Admin authentication successful. Full remote console access granted.");
str_format(aBuf, sizeof(aBuf), "ClientID=%d authed (admin)", ClientID);
str_format(aBuf, sizeof(aBuf), "ClientID=%d authed with key=%s (admin)", ClientID, pIdent);
break;
}
case AUTHED_MOD:
{
SendRconLine(ClientID, "Moderator authentication successful. Limited remote console access granted.");
str_format(aBuf, sizeof(aBuf), "ClientID=%d authed (moderator)", ClientID);
str_format(aBuf, sizeof(aBuf), "ClientID=%d authed with key=%s (moderator)", ClientID, pIdent);
break;
}
case AUTHED_HELPER:
{
SendRconLine(ClientID, "Helper authentication successful. Limited remote console access granted.");
str_format(aBuf, sizeof(aBuf), "ClientID=%d authed (helper)", ClientID);
str_format(aBuf, sizeof(aBuf), "ClientID=%d authed with key=%s (helper)", ClientID, pIdent);
break;
}
}
@ -1593,6 +1605,8 @@ void CServer::InitRegister(CNetServer *pNetServer, IEngineMasterServer *pMasterS
int CServer::Run()
{
m_AuthManager.Init();
//
m_PrintCBIndex = Console()->RegisterPrintCallback(g_Config.m_ConsoleOutputLevel, SendRconLineAuthed, this);
@ -1944,6 +1958,178 @@ void CServer::ConDnsblStatus(IConsole::IResult *pResult, void *pUser)
}
}
static int GetAuthLevel(const char *pLevel)
{
int Level = -1;
if(!str_comp_nocase(pLevel, "admin"))
Level = CServer::AUTHED_ADMIN;
else if(!str_comp_nocase_num(pLevel, "mod", 3))
Level = CServer::AUTHED_MOD;
else if(!str_comp_nocase(pLevel, "helper"))
Level = CServer::AUTHED_HELPER;
return Level;
}
void CServer::ConAuthAdd(IConsole::IResult *pResult, void *pUser)
{
CServer *pThis = (CServer *)pUser;
CAuthManager *pManager = &pThis->m_AuthManager;
const char *pIdent = pResult->GetString(0);
const char *pLevel = pResult->GetString(1);
const char *pPw = pResult->GetString(2);
int KeySlot = pManager->FindKey(pIdent);
if(KeySlot != -1)
{
pThis->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "auth", "ident already exists");
return;
}
int Level = GetAuthLevel(pLevel);
if(Level == -1)
{
pThis->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "auth", "level can be one of {\"admin\", \"mod(erator)\", \"helper\"}");
return;
}
pManager->AddKey(pIdent, pPw, Level);
pThis->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "auth", "key added");
}
void CServer::ConAuthAddHashed(IConsole::IResult *pResult, void *pUser)
{
CServer *pThis = (CServer *)pUser;
CAuthManager *pManager = &pThis->m_AuthManager;
const char *pIdent = pResult->GetString(0);
const char *pLevel = pResult->GetString(1);
const char *pPw = pResult->GetString(2);
const char *pSalt = pResult->GetString(3);
int KeySlot = pManager->FindKey(pIdent);
if(KeySlot != -1){
pThis->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "auth", "ident already exists");
return;
}
int Level = GetAuthLevel(pLevel);
if(Level == -1)
{
pThis->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "auth", "level can be one of {\"admin\", \"mod(erator)\", \"helper\"}");
return;
}
unsigned char aHash[MD5_BYTES];
unsigned char aSalt[SALT_BYTES];
str_hex_decode(aHash, sizeof aHash, pPw);
str_hex_decode(aSalt, sizeof aSalt, pSalt);
pManager->AddKeyHash(pIdent, aHash, aSalt, Level);
pThis->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "auth", "key added");
}
void CServer::ConAuthUpdate(IConsole::IResult *pResult, void *pUser)
{
CServer *pThis = (CServer *)pUser;
CAuthManager *pManager = &pThis->m_AuthManager;
const char *pIdent = pResult->GetString(0);
const char *pLevel = pResult->GetString(1);
const char *pPw = pResult->GetString(2);
int KeySlot = pManager->FindKey(pIdent);
if(KeySlot == -1){
pThis->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "auth", "ident couldn't be found");
return;
}
int Level = GetAuthLevel(pLevel);
if(Level == -1)
{
pThis->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "auth", "level can be one of {\"admin\", \"mod(erator)\", \"helper\"}");
return;
}
pManager->UpdateKey(KeySlot, pPw, Level);
pThis->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "auth", "key updated");
}
void CServer::ConAuthUpdateHashed(IConsole::IResult *pResult, void *pUser)
{
CServer *pThis = (CServer *)pUser;
CAuthManager *pManager = &pThis->m_AuthManager;
const char *pIdent = pResult->GetString(0);
const char *pLevel = pResult->GetString(1);
const char *pPw = pResult->GetString(2);
const char *pSalt = pResult->GetString(3);
int KeySlot = pManager->FindKey(pIdent);
if(KeySlot == -1){
pThis->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "auth", "ident couldn't be found");
return;
}
int Level = GetAuthLevel(pLevel);
if(Level == -1)
{
pThis->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "auth", "level can be one of {\"admin\", \"mod(erator)\", \"helper\"}");
return;
}
unsigned char aHash[MD5_BYTES];
unsigned char aSalt[SALT_BYTES];
str_hex_decode(aHash, sizeof aHash, pPw);
str_hex_decode(aSalt, sizeof aSalt, pSalt);
pManager->UpdateKeyHash(KeySlot, aHash, aSalt, Level);
pThis->LogoutKey(KeySlot, "key update");
pThis->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "auth", "key updated");
}
void CServer::ConAuthRemove(IConsole::IResult *pResult, void *pUser)
{
CServer *pThis = (CServer *)pUser;
CAuthManager *pManager = &pThis->m_AuthManager;
const char *pIdent = pResult->GetString(0);
int KeySlot = pManager->FindKey(pIdent);
if(KeySlot == -1){
pThis->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "auth", "ident couldn't be found");
return;
}
pManager->RemoveKey(KeySlot);
pThis->LogoutKey(KeySlot, "key removal");
pThis->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "auth", "key removed, all users logged out");
}
static void ListKeysCallback(const char *pIdent, int Level, void *pUser)
{
static const char lstring[][10] = {"helper", "moderator", "admin"};
char aBuf[256];
str_format(aBuf, sizeof aBuf, "%s %s", pIdent, lstring[Level - 1]);
((CServer *)pUser)->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "auth", aBuf);
}
void CServer::ConAuthList(IConsole::IResult *pResult, void *pUser)
{
CServer *pThis = (CServer *)pUser;
CAuthManager *pManager = &pThis->m_AuthManager;
pManager->ListKeys(ListKeysCallback, pThis);
}
void CServer::ConShutdown(IConsole::IResult *pResult, void *pUser)
{
((CServer *)pUser)->m_RunServer = 0;
@ -2048,18 +2234,7 @@ void CServer::ConLogout(IConsole::IResult *pResult, void *pUser)
if(pServer->m_RconClientID >= 0 && pServer->m_RconClientID < MAX_CLIENTS &&
pServer->m_aClients[pServer->m_RconClientID].m_State != CServer::CClient::STATE_EMPTY)
{
CMsgPacker Msg(NETMSG_RCON_AUTH_STATUS);
Msg.AddInt(0); //authed
Msg.AddInt(0); //cmdlist
pServer->SendMsgEx(&Msg, MSGFLAG_VITAL, pServer->m_RconClientID, true);
pServer->m_aClients[pServer->m_RconClientID].m_Authed = AUTHED_NO;
pServer->m_aClients[pServer->m_RconClientID].m_AuthTries = 0;
pServer->m_aClients[pServer->m_RconClientID].m_pRconCmdToSend = 0;
pServer->SendRconLine(pServer->m_RconClientID, "Logout successful.");
char aBuf[32];
str_format(aBuf, sizeof(aBuf), "ClientID=%d logged out", pServer->m_RconClientID);
pServer->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "server", aBuf);
pServer->LogoutClient(pServer->m_RconClientID, "");
}
}
@ -2199,29 +2374,38 @@ void CServer::ConchainConsoleOutputLevelUpdate(IConsole::IResult *pResult, void
}
}
void CServer::LogoutByAuthLevel(int AuthLevel) // AUTHED_<x>
void CServer::LogoutClient(int ClientID, const char *pReason)
{
CMsgPacker Msg(NETMSG_RCON_AUTH_STATUS);
Msg.AddInt(0); //authed
Msg.AddInt(0); //cmdlist
SendMsgEx(&Msg, MSGFLAG_VITAL, ClientID, true);
m_aClients[ClientID].m_AuthTries = 0;
m_aClients[ClientID].m_pRconCmdToSend = 0;
char aBuf[64];
if(*pReason){
str_format(aBuf, sizeof aBuf, "Logged out by %s.", pReason);
SendRconLine(ClientID, aBuf);
str_format(aBuf, sizeof aBuf, "ClientID=%d with key=%s logged out by %s", ClientID, m_AuthManager.KeyIdent(m_aClients[ClientID].m_AuthKey), pReason);
}
else{
SendRconLine(ClientID, "Logout successful.");
str_format(aBuf, sizeof aBuf, "ClientID=%d with key=%s logged out", ClientID, m_AuthManager.KeyIdent(m_aClients[ClientID].m_AuthKey));
}
m_aClients[ClientID].m_Authed = AUTHED_NO;
m_aClients[ClientID].m_AuthKey = -1;
Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "server", aBuf);
}
void CServer::LogoutKey(int Key, const char *pReason)
{
for(int i = 0; i < MAX_CLIENTS; i++)
{
if(m_aClients[i].m_State == CServer::CClient::STATE_EMPTY)
continue;
if(m_aClients[i].m_Authed == AuthLevel)
{
CMsgPacker Msg(NETMSG_RCON_AUTH_STATUS);
Msg.AddInt(0); //authed
Msg.AddInt(0); //cmdlist
SendMsgEx(&Msg, MSGFLAG_VITAL, i, true);
m_aClients[i].m_Authed = AUTHED_NO;
m_aClients[i].m_AuthTries = 0;
m_aClients[i].m_pRconCmdToSend = 0;
SendRconLine(i, "Logged out by password change.");
char aBuf[64];
str_format(aBuf, sizeof(aBuf), "ClientID=%d logged out by password change", i);
Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "server", aBuf);
}
}
if(m_aClients[i].m_AuthKey == Key)
LogoutClient(i, pReason);
}
void CServer::ConchainRconPasswordChange(IConsole::IResult *pResult, void *pUserData, IConsole::FCommandCallback pfnCallback, void *pCallbackUserData)
@ -2230,7 +2414,14 @@ void CServer::ConchainRconPasswordChange(IConsole::IResult *pResult, void *pUser
if(pResult->NumArguments() == 1)
{
CServer *pServer = (CServer *)pUserData;
pServer->LogoutByAuthLevel(AUTHED_ADMIN);
CAuthManager *pManager = &pServer->m_AuthManager;
int KeySlot = pManager->DefaultKey(AUTHED_ADMIN);
if(KeySlot == -1)
pManager->AddAdminKey(pResult->GetString(0));//Shouldn't happen
pManager->UpdateKey(KeySlot, pResult->GetString(0), AUTHED_ADMIN);
pServer->LogoutKey(KeySlot, "key update");
}
}
@ -2240,7 +2431,16 @@ void CServer::ConchainRconModPasswordChange(IConsole::IResult *pResult, void *pU
if(pResult->NumArguments() == 1)
{
CServer *pServer = (CServer *)pUserData;
pServer->LogoutByAuthLevel(AUTHED_MOD);
CAuthManager *pManager = &pServer->m_AuthManager;
int KeySlot = pManager->DefaultKey(AUTHED_MOD);
if(KeySlot == -1)
pManager->AddModKey(pResult->GetString(0));
else
{
pManager->UpdateKey(KeySlot, pResult->GetString(0), AUTHED_MOD);
pServer->LogoutKey(KeySlot, "key update");
}
}
}
@ -2250,7 +2450,16 @@ void CServer::ConchainRconHelperPasswordChange(IConsole::IResult *pResult, void
if(pResult->NumArguments() == 1)
{
CServer *pServer = (CServer *)pUserData;
pServer->LogoutByAuthLevel(AUTHED_HELPER);
CAuthManager *pManager = &pServer->m_AuthManager;
int KeySlot = pManager->DefaultKey(AUTHED_HELPER);
if(KeySlot == -1)
pManager->AddHelperKey(pResult->GetString(0));
else
{
pManager->UpdateKey(KeySlot, pResult->GetString(0), AUTHED_HELPER);
pServer->LogoutKey(KeySlot, "key update");
}
}
}
@ -2281,6 +2490,13 @@ void CServer::RegisterCommands()
Console()->Register("dnsbl_status", "", CFGFLAG_SERVER, ConDnsblStatus, this, "List blacklisted players");
Console()->Register("auth_add", "s[ident] s[level] s[pw]", CFGFLAG_SERVER, ConAuthAdd, this, "add a rcon key.");
Console()->Register("auth_add_p", "s[ident] s[level] s[hash] s[salt]", CFGFLAG_SERVER, ConAuthAddHashed, this, "add a prehashed rcon key.");
Console()->Register("auth_change", "s[ident] s[level] s[pw]", CFGFLAG_SERVER, ConAuthUpdate, this, "update a rcon key.");
Console()->Register("auth_change_p", "s[ident] s[level] s[hash] s[salt]", CFGFLAG_SERVER, ConAuthUpdateHashed, this, "update a rcon key with prehashed data.");
Console()->Register("auth_remove", "s[ident]", CFGFLAG_SERVER, ConAuthRemove, this, "remove a rcon key.");
Console()->Register("auth_list", "", CFGFLAG_SERVER, ConAuthList, this, "list all rcon keys.");
Console()->Chain("sv_name", ConchainSpecialInfoupdate, this);
Console()->Chain("password", ConchainSpecialInfoupdate, this);

View file

@ -19,6 +19,8 @@
#include <engine/shared/fifo.h>
#include <engine/shared/netban.h>
#include "authmanager.h"
#if defined (CONF_SQL)
#include "sql_connector.h"
#include "sql_server.h"
@ -153,6 +155,7 @@ public:
int m_Country;
int m_Score;
int m_Authed;
int m_AuthKey;
int m_AuthTries;
int m_NextMapChunk;
@ -206,6 +209,7 @@ public:
CDemoRecorder m_aDemoRecorder[MAX_CLIENTS+1];
CRegister m_Register;
CMapChecker m_MapChecker;
CAuthManager m_AuthManager;
int m_RconRestrict;
@ -296,6 +300,13 @@ public:
static void ConLogout(IConsole::IResult *pResult, void *pUser);
static void ConDnsblStatus(IConsole::IResult *pResult, void *pUser);
static void ConAuthAdd(IConsole::IResult *pResult, void *pUser);
static void ConAuthAddHashed(IConsole::IResult *pResult, void *pUser);
static void ConAuthUpdate(IConsole::IResult *pResult, void *pUser);
static void ConAuthUpdateHashed(IConsole::IResult *pResult, void *pUser);
static void ConAuthRemove(IConsole::IResult *pResult, void *pUser);
static void ConAuthList(IConsole::IResult *pResult, void *pUser);
#if defined (CONF_SQL)
// console commands for sqlmasters
static void ConAddSqlServer(IConsole::IResult *pResult, void *pUserData);
@ -309,7 +320,8 @@ public:
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);
void LogoutByAuthLevel(int AuthLevel);
void LogoutClient(int ClientID, const char *pReason);
void LogoutKey(int Key, const char *pReason);
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);