From 1c80875ea319756e6a46ec76ff572c7ec8d4f391 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Fri, 9 Feb 2007 01:08:59 +0000 Subject: [PATCH] initial import of binding user admin ids to players in game --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40464 --- core/AdminCache.cpp | 33 ++++++++ core/AdminCache.h | 4 + core/CPlayerManager.cpp | 55 +++++++++++++ core/CPlayerManager.h | 8 ++ core/smn_player.cpp | 150 ++++++++++++++++++++++++++++++++++ plugins/include/sourcemod.inc | 63 ++++++++++++++ public/IAdminSystem.h | 9 ++ public/IPlayerHelpers.h | 16 ++++ 8 files changed, 338 insertions(+) diff --git a/core/AdminCache.cpp b/core/AdminCache.cpp index 43580376..6537bc6b 100644 --- a/core/AdminCache.cpp +++ b/core/AdminCache.cpp @@ -16,6 +16,7 @@ #include "AdminCache.h" #include "ShareSys.h" #include "ForwardSys.h" +#include "CPlayerManager.h" AdminCache g_Admins; @@ -31,6 +32,7 @@ AdminCache::AdminCache() m_pCacheFwd = NULL; m_FirstGroup = -1; m_pAuthTables = sm_trie_create(); + m_InvalidatingAdmins = false; } AdminCache::~AdminCache() @@ -544,6 +546,11 @@ bool AdminCache::InvalidateAdmin(AdminId id) return false; } + if (!m_InvalidatingAdmins) + { + g_Players.ClearAdminId(id); + } + /* Unlink from the dbl link list */ if (id == m_FirstUser && id == m_LastUser) { @@ -738,6 +745,8 @@ void AdminCache::RegisterAuthIdentType(const char *name) void AdminCache::InvalidateAdminCache(bool unlink_admins) { + m_InvalidatingAdmins = true; + g_Players.ClearAllAdmins(); /* Wipe the identity cache first */ List::iterator iter; for (iter=m_AuthMethods.begin(); @@ -758,6 +767,7 @@ void AdminCache::InvalidateAdminCache(bool unlink_admins) m_LastUser = -1; m_FreeUserList = -1; } + m_InvalidatingAdmins = false; } void AdminCache::DumpAdminCache(AdminCachePart part, bool rebuild) @@ -950,6 +960,23 @@ FlagBits AdminCache::GetAdminFlags(AdminId id, AccessMode mode) return 0; } +void AdminCache::SetAdminFlags(AdminId id, AccessMode mode, FlagBits bits) +{ + AdminUser *pUser = (AdminUser *)m_pMemory->GetAddress(id); + if (!pUser || pUser->magic != USR_MAGIC_SET) + { + return; + } + + if (mode == Access_Real) + { + pUser->flags = bits; + pUser->eflags = bits; + } else if (mode == Access_Effective) { + pUser->eflags = bits; + } +} + bool AdminCache::AdminInheritGroup(AdminId id, GroupId gid) { AdminUser *pUser = (AdminUser *)m_pMemory->GetAddress(id); @@ -1025,6 +1052,12 @@ bool AdminCache::AdminInheritGroup(AdminId id, GroupId gid) return true; } +bool AdminCache::IsValidAdmin(AdminId id) +{ + AdminUser *pUser = (AdminUser *)m_pMemory->GetAddress(id); + return (pUser != NULL && pUser->magic == USR_MAGIC_SET); +} + unsigned int AdminCache::GetAdminGroupCount(AdminId id) { AdminUser *pUser = (AdminUser *)m_pMemory->GetAddress(id); diff --git a/core/AdminCache.h b/core/AdminCache.h index 11b452ea..9d4eaae9 100644 --- a/core/AdminCache.h +++ b/core/AdminCache.h @@ -131,6 +131,9 @@ public: //IAdminSystem unsigned int FlagBitsToArray(FlagBits bits, AdminFlag array[], unsigned int maxSize); bool CheckAdminFlags(AdminId id, FlagBits bits); bool CanAdminTarget(AdminId id, AdminId target); + void SetAdminFlags(AdminId id, AccessMode mode, FlagBits bits); +public: + bool IsValidAdmin(AdminId id); private: void _UnsetCommandOverride(const char *cmd); void _UnsetCommandGroupOverride(const char *group); @@ -155,6 +158,7 @@ public: int m_FirstUser; int m_LastUser; int m_FreeUserList; + bool m_InvalidatingAdmins; }; extern AdminCache g_Admins; diff --git a/core/CPlayerManager.cpp b/core/CPlayerManager.cpp index 53e240b6..e23a6783 100644 --- a/core/CPlayerManager.cpp +++ b/core/CPlayerManager.cpp @@ -14,6 +14,7 @@ #include "CPlayerManager.h" #include "ForwardSys.h" #include "ShareSys.h" +#include "AdminCache.h" CPlayerManager g_Players; @@ -383,6 +384,26 @@ IGamePlayer *CPlayerManager::GetGamePlayer(int client) return GetPlayerByIndex(client); } +void CPlayerManager::ClearAdminId(AdminId id) +{ + for (int i=1; i<=m_maxClients; i++) + { + if (m_Players[i].m_Admin == id) + { + m_Players[i].DumpAdmin(true); + } + } +} + +void CPlayerManager::ClearAllAdmins() +{ + for (int i=1; i<=m_maxClients; i++) + { + m_Players[i].DumpAdmin(true); + } +} + + /******************* *** PLAYER CODE *** *******************/ @@ -393,6 +414,8 @@ CPlayer::CPlayer() m_IsInGame = false; m_IsAuthorized = false; m_pEdict = NULL; + m_Admin = INVALID_ADMIN_ID; + m_TempAdmin = false; } void CPlayer::Initialize(const char *name, const char *ip, edict_t *pEntity) @@ -416,6 +439,7 @@ void CPlayer::Authorize(const char *steamid) void CPlayer::Disconnect() { + DumpAdmin(false); m_IsConnected = false; m_IsInGame = false; m_IsAuthorized = false; @@ -469,3 +493,34 @@ bool CPlayer::IsFakeClient() const { return (strcmp(m_AuthID.c_str(), "BOT") == 0); } + +void CPlayer::SetAdminId(AdminId id, bool temporary) +{ + if (!m_IsConnected) + { + return; + } + + DumpAdmin(false); + + m_Admin = id; + m_TempAdmin = temporary; +} + +AdminId CPlayer::GetAdminId() const +{ + return m_Admin; +} + +void CPlayer::DumpAdmin(bool deleting) +{ + if (m_Admin != INVALID_ADMIN_ID) + { + if (m_TempAdmin && !deleting) + { + g_Admins.InvalidateAdmin(m_Admin); + } + m_Admin = INVALID_ADMIN_ID; + m_TempAdmin = false; + } +} diff --git a/core/CPlayerManager.h b/core/CPlayerManager.h index 4ef1ace9..a621de88 100644 --- a/core/CPlayerManager.h +++ b/core/CPlayerManager.h @@ -19,6 +19,7 @@ #include "sourcemm_api.h" #include #include +#include #include #include #include @@ -39,12 +40,15 @@ public: bool IsConnected() const; bool IsAuthorized() const; bool IsFakeClient() const; + void SetAdminId(AdminId id, bool temporary); + AdminId GetAdminId() const; 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); private: bool m_IsConnected; bool m_IsInGame; @@ -52,6 +56,8 @@ private: String m_Name; String m_Ip; String m_AuthID; + AdminId m_Admin; + bool m_TempAdmin; edict_t *m_pEdict; }; @@ -68,6 +74,8 @@ public: //SMGlobalClass public: CPlayer *GetPlayerByIndex(int client) const; void RunAuthChecks(); + void ClearAdminId(AdminId id); + void ClearAllAdmins(); public: bool OnClientConnect(edict_t *pEntity, const char *pszName, const char *pszAddress, char *reject, int maxrejectlen); bool OnClientConnect_Post(edict_t *pEntity, const char *pszName, const char *pszAddress, char *reject, int maxrejectlen); diff --git a/core/smn_player.cpp b/core/smn_player.cpp index 804a0a17..fb271179 100644 --- a/core/smn_player.cpp +++ b/core/smn_player.cpp @@ -12,6 +12,7 @@ */ #include "CPlayerManager.h" +#include "AdminCache.h" #include "sm_stringutil.h" static cell_t sm_GetClientCount(IPluginContext *pCtx, const cell_t *params) @@ -230,6 +231,150 @@ static cell_t sm_PrintToConsole(IPluginContext *pCtx, const cell_t *params) return 1; } +static cell_t SetUserAdmin(IPluginContext *pContext, const cell_t *params) +{ + int client = params[1]; + CPlayer *pPlayer = g_Players.GetPlayerByIndex(client); + if (!pPlayer) + { + return pContext->ThrowNativeError("Invalid client index %d.", client); + } + if (!pPlayer->IsConnected()) + { + return pContext->ThrowNativeError("Client %d is not connected.", client); + } + if (!g_Admins.IsValidAdmin(params[2])) + { + return pContext->ThrowNativeError("AdminId %x is not valid.", params[2]); + } + + pPlayer->SetAdminId(params[2], params[3] ? true : false); + + return 1; +} + +static cell_t GetUserAdmin(IPluginContext *pContext, const cell_t *params) +{ + int client = params[1]; + CPlayer *pPlayer = g_Players.GetPlayerByIndex(client); + if (!pPlayer) + { + return pContext->ThrowNativeError("Invalid client index %d.", client); + } + if (!pPlayer->IsConnected()) + { + return pContext->ThrowNativeError("Client %d is not connected.", client); + } + + return pPlayer->GetAdminId(); +} + +static cell_t AddUserFlags(IPluginContext *pContext, const cell_t *params) +{ + int client = params[1]; + CPlayer *pPlayer = g_Players.GetPlayerByIndex(client); + if (!pPlayer) + { + return pContext->ThrowNativeError("Invalid client index %d.", client); + } + if (!pPlayer->IsConnected()) + { + return pContext->ThrowNativeError("Client %d is not connected.", client); + } + + AdminId id; + if ((id=pPlayer->GetAdminId()) == INVALID_ADMIN_ID) + { + id = g_Admins.CreateAdmin(NULL); + pPlayer->SetAdminId(id, true); + } + + cell_t *addr; + for (int i=2; i<=params[0]; i++) + { + pContext->LocalToPhysAddr(params[i], &addr); + g_Admins.SetAdminFlag(id, (AdminFlag)*addr, true); + } + + return 1; +} + +static cell_t RemoveUserFlags(IPluginContext *pContext, const cell_t *params) +{ + int client = params[1]; + CPlayer *pPlayer = g_Players.GetPlayerByIndex(client); + if (!pPlayer) + { + return pContext->ThrowNativeError("Invalid client index %d.", client); + } + if (!pPlayer->IsConnected()) + { + return pContext->ThrowNativeError("Client %d is not connected.", client); + } + + AdminId id; + if ((id=pPlayer->GetAdminId()) == INVALID_ADMIN_ID) + { + return 0; + } + + cell_t *addr; + for (int i=2; i<=params[0]; i++) + { + pContext->LocalToPhysAddr(params[i], &addr); + g_Admins.SetAdminFlag(id, (AdminFlag)*addr, false); + } + + return 1; +} + +static cell_t SetUserFlagBits(IPluginContext *pContext, const cell_t *params) +{ + int client = params[1]; + CPlayer *pPlayer = g_Players.GetPlayerByIndex(client); + if (!pPlayer) + { + return pContext->ThrowNativeError("Invalid client index %d.", client); + } + if (!pPlayer->IsConnected()) + { + return pContext->ThrowNativeError("Client %d is not connected.", client); + } + + AdminId id; + if ((id=pPlayer->GetAdminId()) == INVALID_ADMIN_ID) + { + id = g_Admins.CreateAdmin(NULL); + pPlayer->SetAdminId(id, true); + } + + g_Admins.SetAdminFlags(id, Access_Effective, params[2]); + + return 1; +} + +static cell_t GetUserFlagBits(IPluginContext *pContext, const cell_t *params) +{ + int client = params[1]; + CPlayer *pPlayer = g_Players.GetPlayerByIndex(client); + if (!pPlayer) + { + return pContext->ThrowNativeError("Invalid client index %d.", client); + } + if (!pPlayer->IsConnected()) + { + return pContext->ThrowNativeError("Client %d is not connected.", client); + } + + AdminId id; + if ((id=pPlayer->GetAdminId()) == INVALID_ADMIN_ID) + { + return 0; + } + + return g_Admins.GetAdminFlags(id, Access_Effective); +} + REGISTER_NATIVES(playernatives) { {"GetMaxClients", sm_GetMaxClients}, @@ -244,6 +389,11 @@ REGISTER_NATIVES(playernatives) {"PrintToServer", sm_PrintToServer}, {"PrintToConsole", sm_PrintToConsole}, {"GetClientInfo", sm_GetClientInfo}, + {"SetUserAdmin", SetUserAdmin}, + {"AddUserFlags", AddUserFlags}, + {"RemoveUserFlags", RemoveUserFlags}, + {"SetUserFlagBits", SetUserFlagBits}, + {"GetUserFlagBits", GetUserFlagBits}, {NULL, NULL} }; diff --git a/plugins/include/sourcemod.inc b/plugins/include/sourcemod.inc index 5cde54a1..131fd2e3 100644 --- a/plugins/include/sourcemod.inc +++ b/plugins/include/sourcemod.inc @@ -235,9 +235,72 @@ native bool:IsPlayerFakeClient(client); * @param value Buffer to store value. * @param maxlen Maximum length of valve (UTF-8 safe). * @return True on success, false otherwise. + * @error Invalid client index, or client not connected. */ native bool:GetClientInfo(client, const String:key[], String:value[], maxlen); +/** + * Sets a client's AdminId. + * + * @param client Player's index. + * @param id AdminId to set. INVALID_ADMIN_ID removes admin permissions. + * @param temp True if the id should be freed on disconnect. + * @noreturn + * @error Invalid client index, client not connected, or bogus AdminId. + */ +native SetUserAdmin(client, AdminId:id, bool:temp=false); + +/** + * Retrieves a client's AdminId. + * + * @param client Player's index. + * @return AdminId of the client, or INVALID_ADMIN_ID if none. + * @error Invalid client index, or client not connected. + */ +native AdminId:GetUserAdmin(client); + +/** + * Sets access flags on a client. If the client is not an admin, + * a temporary, anonymous AdminId is given. + * + * @param client Player's index. + * @param ... Flags to set on the client. + * @noreturn + * @error Invalid client index, or client not connected. + */ +native AddUserFlags(client, {AdminFlag}:...); + +/** + * Removes flags from a client. If the client is not an admin, + * this has no effect. + * + * @param client Player's index. + * @param ... Flags to remove from the client. + * @noreturn + * @error Invalid client index, or client not connected. + */ +native RemoveUserFlags(client, {AdminFlag}:...); + +/** + * Sets access flags on a client using bits instead of flags. If the + * client is not an admin, and flags not 0, a temporary, anonymous AdminId is given. + * + * @param client Player's index. + * @param flags Bitstring of flags to set on client. + * @noreturn + */ +native SetUserFlagBits(client, flags); + +/** + * Returns client access flags. If the client is not an admin, + * the result is always 0. + * + * @param client Player's index. + * @return Flags + * @error Invalid client index, or client not connected. + */ +native GetUserFlagBits(client); + /** * Sends a message to the server console. * diff --git a/public/IAdminSystem.h b/public/IAdminSystem.h index af5309ff..be93cbe9 100644 --- a/public/IAdminSystem.h +++ b/public/IAdminSystem.h @@ -444,6 +444,15 @@ namespace SourceMod */ virtual FlagBits GetAdminFlags(AdminId id, AccessMode mode) =0; + /** + * @brief Sets the bitstring of access flags on an admin. + * + * @param id AdminId index of the admin. + * @param mode Access mode to use (real affects both). + * @param bits Bitstring to set. + */ + virtual void SetAdminFlags(AdminId id, AccessMode mode, FlagBits bits) =0; + /** * @brief Adds a group to an admin's inherited group list. * Any flags the group has will be added to the admin's effective flags. diff --git a/public/IPlayerHelpers.h b/public/IPlayerHelpers.h index 5a4b9ded..3642409f 100644 --- a/public/IPlayerHelpers.h +++ b/public/IPlayerHelpers.h @@ -20,6 +20,7 @@ #define _INCLUDE_SOURCEMOD_INTERFACE_IPLAYERHELPERS_H_ #include +#include #define SMINTERFACE_PLAYERMANAGER_NAME "IPlayerManager" #define SMINTERFACE_PLAYERMANAGER_VERSION 1 @@ -92,6 +93,21 @@ namespace SourceMod * @return True if a fake client, false otherwise. */ virtual bool IsFakeClient() const =0; + + /** + * @brief Returns the client's AdminId, if any. + * + * @return AdminId, or INVALID_ADMIN_ID if none. + */ + virtual AdminId GetAdminId() const =0; + + /** + * @brief Sets the client's AdminId. + * + * @param id AdminId to set. + * @param temp If true, the id will be invalidated on disconnect. + */ + virtual void SetAdminId(AdminId id, bool temp) =0; }; /**