diff --git a/core/AdminCache.cpp b/core/AdminCache.cpp index 402d5444..2be1fc43 100644 --- a/core/AdminCache.cpp +++ b/core/AdminCache.cpp @@ -445,6 +445,7 @@ AdminId AdminCache::CreateAdmin(const char *name) pUser->auth.index = 0; pUser->immune_default = false; pUser->immune_global = false; + pUser->serialchange = 1; if (m_FirstUser == INVALID_ADMIN_ID) { @@ -843,6 +844,9 @@ bool AdminCache::InvalidateAdmin(AdminId id) pUser->next_user = m_FreeUserList; m_FreeUserList = id; + /* Unset serial change */ + pUser->serialchange = 0; + return true; } @@ -925,6 +929,8 @@ void AdminCache::InvalidateGroup(GroupId id) pOther = (AdminGroup *)m_pMemory->GetAddress(table[j]); pUser->eflags |= pOther->addflags; } + /* Mark as changed */ + pUser->serialchange++; /* Break now, duplicates aren't allowed */ break; } @@ -1172,6 +1178,8 @@ void AdminCache::SetAdminFlag(AdminId id, AdminFlag flag, bool enabled) pUser->flags &= ~bits; pUser->eflags &= ~bits; } + + pUser->serialchange++; } bool AdminCache::GetAdminFlag(AdminId id, AdminFlag flag, AccessMode mode) @@ -1238,6 +1246,8 @@ void AdminCache::SetAdminFlags(AdminId id, AccessMode mode, FlagBits bits) } else if (mode == Access_Effective) { pUser->eflags = bits; } + + pUser->serialchange++; } bool AdminCache::AdminInheritGroup(AdminId id, GroupId gid) @@ -1312,6 +1322,8 @@ bool AdminCache::AdminInheritGroup(AdminId id, GroupId gid) pUser->immune_global = true; } + pUser->serialchange++; + return true; } @@ -1551,3 +1563,36 @@ FlagBits AdminCache::ReadFlagString(const char *flags, const char **end) return bits; } + +unsigned int AdminCache::GetAdminSerialChange(AdminId id) +{ + AdminUser *pUser = (AdminUser *)m_pMemory->GetAddress(id); + if (!pUser || pUser->magic != USR_MAGIC_SET) + { + return 0; + } + + return pUser->serialchange; +} + +bool AdminCache::CanAdminUseCommand(int client, const char *cmd) +{ + FlagBits bits; + OverrideType otype = Override_Command; + + if (cmd[0] == '@') + { + otype = Override_CommandGroup; + cmd++; + } + + if (!g_ConCmds.LookForCommandAdminFlags(cmd, &bits)) + { + if (!GetCommandOverride(cmd, otype, &bits)) + { + bits = 0; + } + } + + return g_ConCmds.CheckCommandAccess(client, cmd, bits); +} diff --git a/core/AdminCache.h b/core/AdminCache.h index 620ec3eb..51eeae70 100644 --- a/core/AdminCache.h +++ b/core/AdminCache.h @@ -92,6 +92,7 @@ struct AdminUser UserAuth auth; /* Auth method for this user */ bool immune_global; /* Whether globally immune */ bool immune_default; /* Whether defaultly immune */ + unsigned int serialchange; /* Serial # for changes */ }; class AdminCache : @@ -154,6 +155,8 @@ public: //IAdminSystem bool FindFlag(const char *str, AdminFlag *pFlag); bool FindFlag(char c, AdminFlag *pAdmFlag); FlagBits ReadFlagString(const char *flags, const char **end); + unsigned int GetAdminSerialChange(AdminId id); + bool CanAdminUseCommand(int client, const char *cmd); public: bool IsValidAdmin(AdminId id); private: diff --git a/core/ConCmdManager.cpp b/core/ConCmdManager.cpp index 2a379007..ba34f4f7 100644 --- a/core/ConCmdManager.cpp +++ b/core/ConCmdManager.cpp @@ -323,7 +323,7 @@ void ConCmdManager::InternalDispatch() bool ConCmdManager::CheckCommandAccess(int client, const char *cmd, FlagBits cmdflags) { - if (cmdflags == 0) + if (cmdflags == 0 || client == 0) { return true; } @@ -520,6 +520,7 @@ bool ConCmdManager::AddAdminCommand(IPluginFunction *pFunction, /* Finally, add the hook */ pInfo->conhooks.push_back(pHook); pInfo->admin = *(pHook->pAdmin); + pInfo->is_admin_set = true; /* Now add to the plugin */ CmdList *pList; @@ -664,6 +665,7 @@ void ConCmdManager::UpdateAdminCmdFlags(const char *cmd, OverrideType type, Flag pInfo->admin = *(pHook->pAdmin); } } + pInfo->is_admin_set = true; } else if (type == Override_CommandGroup) { void *object; if (!sm_trie_retrieve(m_pCmdGrps, cmd, &object)) @@ -695,6 +697,7 @@ void ConCmdManager::UpdateAdminCmdFlags(const char *cmd, OverrideType type, Flag } } } + pInfo->is_admin_set = true; } } @@ -742,6 +745,20 @@ bool ConCmdManager::LookForSourceModCommand(const char *cmd) return pInfo->sourceMod && (pInfo->conhooks.size() > 0); } +bool ConCmdManager::LookForCommandAdminFlags(const char *cmd, FlagBits *pFlags) +{ + ConCmdInfo *pInfo; + + if (!sm_trie_retrieve(m_pCmds, cmd, (void **)&pInfo)) + { + return false; + } + + *pFlags = pInfo->admin.eflags; + + return pInfo->is_admin_set; +} + ConCmdInfo *ConCmdManager::AddOrFindCommand(const char *name, const char *description, int flags) { ConCmdInfo *pInfo; @@ -785,6 +802,7 @@ ConCmdInfo *ConCmdManager::AddOrFindCommand(const char *name, const char *descri } pInfo->pCmd = pCmd; + pInfo->is_admin_set = false; sm_trie_insert(m_pCmds, name, pInfo); AddToCmdList(pInfo); diff --git a/core/ConCmdManager.h b/core/ConCmdManager.h index 10dc54e7..162209e3 100644 --- a/core/ConCmdManager.h +++ b/core/ConCmdManager.h @@ -88,6 +88,7 @@ struct ConCmdInfo List srvhooks; /**< Hooks as a server command */ List conhooks; /**< Hooks as a console command */ AdminCmdInfo admin; /**< Admin info, if any */ + bool is_admin_set; /**< Whether or not admin info is set */ }; class ConCmdManager : @@ -118,6 +119,7 @@ public: ResultType DispatchClientCommand(int client, const char *cmd, int args, ResultType type); void UpdateAdminCmdFlags(const char *cmd, OverrideType type, FlagBits bits); bool LookForSourceModCommand(const char *cmd); + bool LookForCommandAdminFlags(const char *cmd, FlagBits *pFlags); bool CheckCommandAccess(int client, const char *cmd, FlagBits flags); private: void InternalDispatch(); diff --git a/public/IAdminSystem.h b/public/IAdminSystem.h index 4865926e..d5cb6c02 100644 --- a/public/IAdminSystem.h +++ b/public/IAdminSystem.h @@ -35,7 +35,7 @@ #include #define SMINTERFACE_ADMINSYS_NAME "IAdminSys" -#define SMINTERFACE_ADMINSYS_VERSION 2 +#define SMINTERFACE_ADMINSYS_VERSION 3 /** * @file IAdminSystem.h @@ -626,6 +626,27 @@ namespace SourceMod * @return FlagBits value of the flags. */ virtual FlagBits ReadFlagString(const char *flags, const char **end) =0; + + /** + * @brief Returns a "serial number" for an AdminId. If the serial + * number has changed for a given AdminId, it means the permissions + * have changed. + * + * @param id AdminId value. + * @return Serial number, or 0 on failure. + */ + virtual unsigned int GetAdminSerialChange(AdminId id) =0; + + /** + * @brief Checks whether an admin can use the given command name. + * + * If the command does not exist, this will return true. + * + * @param client Client index. + * @param cmd Command name. + * @return True on success, false on failure. + */ + virtual bool CanAdminUseCommand(int client, const char *cmd) =0; }; }