From 48d71cae26367d35dd430f9f605670a7b1d09963 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Tue, 24 Jul 2007 20:11:47 +0000 Subject: [PATCH] finished a(nother) rewrite of how players authenticate. name-based authentication has been added and passwords work fully now. --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%401167 --- configs/admins_simple.ini | 7 +- core/PlayerManager.cpp | 226 +++++++++++++++++++++++++++++++++----- core/PlayerManager.h | 12 +- 3 files changed, 210 insertions(+), 35 deletions(-) diff --git a/configs/admins_simple.ini b/configs/admins_simple.ini index e6f5d980..21bd61d1 100644 --- a/configs/admins_simple.ini +++ b/configs/admins_simple.ini @@ -22,9 +22,10 @@ // // setinfo "KEY" "PASSWORD" // -// Where KEY is the "pw_auth" setting in your sourcemod.cfg file, and "PASSWORD" -// is their password. This must be done before the authentication matches on the -// server. +// Where KEY is the "PassInfoVar" setting in your core.cfg file, and "PASSWORD" +// is their password. With name based authentication, this must be done before +// changing names or connecting. Otherwise, SourceMod will automatically detect +// the password being set. // //////////////////////////////// // Examples: diff --git a/core/PlayerManager.cpp b/core/PlayerManager.cpp index 2f7062df..d11ab7b2 100644 --- a/core/PlayerManager.cpp +++ b/core/PlayerManager.cpp @@ -21,6 +21,9 @@ #include "MenuStyle_Radio.h" #include "sm_stringutil.h" #include "CoreConfig.h" +#include +#include +#include "TimerSys.h" PlayerManager g_Players; bool g_OnMapStarted = false; @@ -32,6 +35,25 @@ SH_DECL_HOOK1_void(IServerGameClients, ClientCommand, SH_NOATTRIB, 0, edict_t *) SH_DECL_HOOK1_void(IServerGameClients, ClientSettingsChanged, SH_NOATTRIB, 0, edict_t *); SH_DECL_HOOK3_void(IServerGameDLL, ServerActivate, SH_NOATTRIB, 0, edict_t *, int, int); +class KickPlayerTimer : public ITimedEvent +{ +public: + ResultType OnTimer(ITimer *pTimer, void *pData) + { + int userid = (int)pData; + int client = g_Players.GetClientOfUserId(userid); + if (client) + { + CPlayer *player = g_Players.GetPlayerByIndex(client); + player->Kick("Your name is reserved by SourceMod; set your password to use it."); + } + return Pl_Stop; + } + void OnTimerEnd(ITimer *pTimer, void *pData) + { + } +} s_KickPlayerTimer; + PlayerManager::PlayerManager() { m_AuthQueue = NULL; @@ -159,6 +181,31 @@ bool PlayerManager::CheckSetAdmin(int index, CPlayer *pPlayer, AdminId id) return true; } +bool PlayerManager::CheckSetAdminName(int index, CPlayer *pPlayer, AdminId id) +{ + const char *password = g_Admins.GetAdminPassword(id); + if (password == NULL) + { + return false; + } + + if (m_PassInfoVar.size() < 1) + { + return false; + } + + /* Whoa... the user needs a password! */ + const char *given = engine->GetClientConVarValue(index, m_PassInfoVar.c_str()); + if (!given || strcmp(given, password) != 0) + { + return false; + } + + pPlayer->SetAdminId(id, false); + + return true; +} + void PlayerManager::RunAuthChecks() { CPlayer *pPlayer; @@ -172,24 +219,13 @@ void PlayerManager::RunAuthChecks() && (strcmp(authstr, "STEAM_ID_PENDING") != 0)) { /* Set authorization */ - pPlayer->m_AuthID.assign(authstr); - pPlayer->m_IsAuthorized = true; + pPlayer->Authorize(authstr); /* Mark as removed from queue */ unsigned int client = m_AuthQueue[i]; m_AuthQueue[i] = 0; removed++; - /* Do admin lookups */ - if (pPlayer->GetAdminId() == INVALID_ADMIN_ID) - { - AdminId id = g_Admins.FindAdminByIdentity("steam", authstr); - if (id != INVALID_ADMIN_ID) - { - CheckSetAdmin(client, pPlayer, id); - } - } - /* Send to extensions */ List::iterator iter; IClientListener *pListener; @@ -211,6 +247,11 @@ void PlayerManager::RunAuthChecks() m_clauth->PushString(authstr); m_clauth->Execute(NULL); } + + if (pPlayer->IsConnected()) + { + pPlayer->Authorize_Post(); + } } } @@ -303,23 +344,6 @@ bool PlayerManager::OnClientConnect_Post(edict_t *pEntity, const char *pszName, } } - if (pPlayer->IsConnected()) - { - /* Do an ip based lookup */ - char ip[24], *ptr; - strncopy(ip, pszAddress, sizeof(ip)); - if ((ptr = strchr(ip, ':')) != NULL) - { - *ptr = '\0'; - } - - AdminId id = g_Admins.FindAdminByIdentity("ip", ip); - if (id != INVALID_ADMIN_ID) - { - CheckSetAdmin(client, pPlayer, id); - } - } - return true; } @@ -370,6 +394,15 @@ void PlayerManager::OnClientPutInServer(edict_t *pEntity, const char *playername m_clauth->PushCell(client); m_clauth->PushString(authid); m_clauth->Execute(NULL); + if (!pPlayer->IsConnected()) + { + return; + } + } + pPlayer->Authorize_Post(); + if (!pPlayer->IsConnected()) + { + return; } } @@ -524,7 +557,46 @@ void PlayerManager::OnClientSettingsChanged(edict_t *pEntity) m_clinfochanged->PushCell(engine->IndexOfEdict(pEntity)); m_clinfochanged->Execute(&res, NULL); - m_Players[client].SetName(engine->GetClientConVarValue(client, "name")); + + IPlayerInfo *info = m_Players[client].GetPlayerInfo(); + const char *new_name = info ? info->GetName() : engine->GetClientConVarValue(client, "name"); + const char *old_name = m_Players[client].m_Name.c_str(); + + if (strcmp(old_name, new_name) != 0) + { + AdminId id = g_Admins.FindAdminByIdentity("name", new_name); + if (id != INVALID_ADMIN_ID && m_Players[client].GetAdminId() != id) + { + if (!CheckSetAdminName(client, &m_Players[client], id)) + { + m_Players[client].Kick("Your name is reserved by SourceMod; set your password to use it."); + RETURN_META(MRES_IGNORED); + } + } else if ((id = g_Admins.FindAdminByIdentity("name", old_name)) != INVALID_ADMIN_ID) { + if (id == m_Players[client].GetAdminId()) + { + /* This player is changing their name; force them to drop admin privileges! */ + m_Players[client].SetAdminId(INVALID_ADMIN_ID, false); + } + } + m_Players[client].SetName(new_name); + } + + if (m_PassInfoVar.size() > 0) + { + /* Try for a password change */ + const char *old_pass = m_Players[client].m_LastPassword.c_str(); + const char *new_pass = engine->GetClientConVarValue(client, m_PassInfoVar.c_str()); + if (strcmp(old_pass, new_pass) != 0) + { + m_Players[client].m_LastPassword.assign(new_pass); + if (m_Players[client].IsInGame() && m_Players[client].IsAuthorized()) + { + /* If there is already an admin id assigned, this will just bail out. */ + m_Players[client].DoBasicAdminChecks(); + } + } + } } int PlayerManager::GetMaxClients() @@ -631,6 +703,10 @@ void PlayerManager::ClearAllAdmins() } } +const char *PlayerManager::GetPassInfoVar() +{ + return m_PassInfoVar.c_str(); +} /******************* *** PLAYER CODE *** @@ -645,6 +721,7 @@ CPlayer::CPlayer() m_Admin = INVALID_ADMIN_ID; m_TempAdmin = false; m_Info = NULL; + m_LastPassword.clear(); } void CPlayer::Initialize(const char *name, const char *ip, edict_t *pEntity) @@ -653,15 +730,48 @@ void CPlayer::Initialize(const char *name, const char *ip, edict_t *pEntity) m_Name.assign(name); m_Ip.assign(ip); m_pEdict = pEntity; + + char ip2[24], *ptr; + strncopy(ip2, ip, sizeof(ip2)); + if ((ptr = strchr(ip2, ':')) != NULL) + { + *ptr = '\0'; + } + m_IpNoPort.assign(ip2); } void CPlayer::Connect() { + if (m_IsInGame) + { + return; + } + m_IsInGame = true; + + const char *var = g_Players.GetPassInfoVar(); + int client = engine->IndexOfEdict(m_pEdict); + if (var[0] != '\0') + { + const char *pass = engine->GetClientConVarValue(client, var); + m_LastPassword.assign(pass ? pass : ""); + } else { + m_LastPassword.assign(""); + } + + if (m_IsAuthorized) + { + DoBasicAdminChecks(); + } } void CPlayer::Authorize(const char *steamid) { + if (m_IsAuthorized) + { + return; + } + m_IsAuthorized = true; m_AuthID.assign(steamid); } @@ -759,3 +869,59 @@ void CPlayer::DumpAdmin(bool deleting) m_TempAdmin = false; } } + +void CPlayer::Kick(const char *str) +{ + int client = engine->IndexOfEdict(m_pEdict); + INetChannel *pNetChan = static_cast(engine->GetPlayerNetInfo(client)); + IClient *pClient = static_cast(pNetChan->GetMsgHandler()); + pClient->Disconnect("%s", str); +} + +void CPlayer::Authorize_Post() +{ + if (m_IsInGame) + { + DoBasicAdminChecks(); + } +} + +void CPlayer::DoBasicAdminChecks() +{ + if (GetAdminId() != INVALID_ADMIN_ID) + { + return; + } + + /* First check the name */ + AdminId id; + int client = engine->IndexOfEdict(m_pEdict); + + if ((id = g_Admins.FindAdminByIdentity("name", GetName())) != INVALID_ADMIN_ID) + { + if (!g_Players.CheckSetAdminName(client, this, id)) + { + int userid = engine->GetPlayerUserId(m_pEdict); + g_Timers.CreateTimer(&s_KickPlayerTimer, 0.1f, (void *)userid, 0); + } + return; + } + + /* Check IP */ + if ((id = g_Admins.FindAdminByIdentity("ip", m_IpNoPort.c_str())) != INVALID_ADMIN_ID) + { + if (g_Players.CheckSetAdmin(client, this, id)) + { + return; + } + } + + /* Check IP address */ + if ((id = g_Admins.FindAdminByIdentity("steam", m_AuthID.c_str())) != INVALID_ADMIN_ID) + { + if (g_Players.CheckSetAdmin(client, this, id)) + { + return; + } + } +} diff --git a/core/PlayerManager.h b/core/PlayerManager.h index 2b5141fa..60756c55 100644 --- a/core/PlayerManager.h +++ b/core/PlayerManager.h @@ -43,26 +43,31 @@ public: bool IsFakeClient(); void SetAdminId(AdminId id, bool temporary); AdminId GetAdminId(); + void Kick(const char *str); public: IPlayerInfo *GetPlayerInfo(); private: void Initialize(const char *name, const char *ip, edict_t *pEntity); void Connect(); - void Authorize(const char *steamid); void Disconnect(); void SetName(const char *name); void DumpAdmin(bool deleting); + void Authorize(const char *auth); + void Authorize_Post(); + void DoBasicAdminChecks(); private: bool m_IsConnected; bool m_IsInGame; bool m_IsAuthorized; String m_Name; String m_Ip; + String m_IpNoPort; String m_AuthID; AdminId m_Admin; bool m_TempAdmin; edict_t *m_pEdict; IPlayerInfo *m_Info; + String m_LastPassword; }; class PlayerManager : @@ -90,6 +95,7 @@ public: void OnClientDisconnect_Post(edict_t *pEntity); void OnClientCommand(edict_t *pEntity); void OnClientSettingsChanged(edict_t *pEntity); + //void OnClientSettingsChanged_Pre(edict_t *pEntity); public: //IPlayerManager void AddClientListener(IClientListener *listener); void RemoveClientListener(IClientListener *listener); @@ -107,9 +113,11 @@ public: { return m_PlayerCount; } + bool CheckSetAdmin(int index, CPlayer *pPlayer, AdminId id); + bool CheckSetAdminName(int index, CPlayer *pPlayer, AdminId id); + const char *GetPassInfoVar(); private: void OnServerActivate(edict_t *pEdictList, int edictCount, int clientMax); - bool CheckSetAdmin(int index, CPlayer *pPlayer, AdminId id); private: List m_hooks; IForward *m_clconnect;