From c66632776f27e5617f89e922910a1e908c8e8148 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Mon, 29 Jan 2007 04:19:14 +0000 Subject: [PATCH] initial import of finished admin api --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40410 --- core/AdminCache.cpp | 456 +++++++++++++++++++++++++++++++++++++++++- core/AdminCache.h | 55 +++++ core/sm_memtable.h | 2 + public/IAdminSystem.h | 155 ++++++++++++++ 4 files changed, 657 insertions(+), 11 deletions(-) diff --git a/core/AdminCache.cpp b/core/AdminCache.cpp index 79d4a254..0f05e49f 100644 --- a/core/AdminCache.cpp +++ b/core/AdminCache.cpp @@ -26,8 +26,10 @@ AdminCache::AdminCache() m_pStrings = new BaseStringTable(1024); m_pMemory = m_pStrings->GetMemTable(); m_FreeGroupList = m_FirstGroup = m_LastGroup = INVALID_GROUP_ID; + m_FreeUserList = m_FirstUser = m_LastUser = INVALID_ADMIN_ID; m_pGroups = sm_trie_create(); m_pCacheFwd = NULL; + m_FirstGroup = -1; } AdminCache::~AdminCache() @@ -52,6 +54,13 @@ AdminCache::~AdminCache() delete m_pStrings; } +void AdminCache::OnSourceModStartup(bool late) +{ + RegisterAuthIdentType("steam"); + RegisterAuthIdentType("name"); + RegisterAuthIdentType("ip"); +} + void AdminCache::OnSourceModAllInitialized() { m_pCacheFwd = g_Forwards.CreateForward("OnRebuildAdminCache", ET_Ignore, 1, NULL, Param_Cell); @@ -196,6 +205,51 @@ void AdminCache::DumpCommandOverrideCache(OverrideType type) } } +AdminId AdminCache::CreateAdmin(const char *name) +{ + AdminId id; + AdminUser *pUser; + + if (m_FreeUserList != INVALID_ADMIN_ID) + { + pUser = (AdminUser *)m_pMemory->GetAddress(m_FreeUserList); + assert(pUser->magic == USR_MAGIC_UNSET); + id = m_FreeUserList; + m_FreeUserList = pUser->next_user; + } else { + id = m_pMemory->CreateMem(sizeof(AdminUser), (void **)&pUser); + pUser->grp_size = 0; + pUser->grp_table = -1; + pUser->auth_size = 0; + pUser->auth_table = -1; + } + + memset(pUser->flags, 0, sizeof(pUser->flags)); + memset(pUser->eflags, 0, sizeof(pUser->flags)); + pUser->grp_count = 0; + pUser->auth_count = 0; + pUser->password = -1; + pUser->magic = USR_MAGIC_SET; + + if (m_FirstUser == INVALID_ADMIN_ID) + { + m_FirstUser = id; + m_LastUser = id; + } else { + AdminUser *pPrev = (AdminUser *)m_pMemory->GetAddress(m_LastUser); + pPrev->next_user = id; + pUser->prev_user = m_LastUser; + m_LastUser = id; + } + + if (name && name[0] != '\0') + { + pUser->nameidx = m_pStrings->AddString(name); + } + + return id; +} + GroupId AdminCache::AddGroup(const char *group_name) { if (sm_trie_retrieve(m_pGroups, group_name, NULL)) @@ -222,7 +276,6 @@ GroupId AdminCache::AddGroup(const char *group_name) pGroup->next_grp = INVALID_GROUP_ID; pGroup->pCmdGrpTable = NULL; pGroup->pCmdTable = NULL; - pGroup->nameidx = m_pStrings->AddString(group_name); memset(pGroup->addflags, 0, sizeof(AdminFlag) * AdminFlags_TOTAL); if (m_FirstGroup == INVALID_GROUP_ID) @@ -238,6 +291,8 @@ GroupId AdminCache::AddGroup(const char *group_name) m_LastGroup = id; } + pGroup->nameidx = m_pStrings->AddString(group_name); + sm_trie_insert(m_pGroups, group_name, (void *)id); return id; @@ -498,6 +553,80 @@ bool AdminCache::GetGroupCommandOverride(GroupId id, const char *name, OverrideT return true; } +Trie *AdminCache::GetMethodByIndex(unsigned int index) +{ + List::iterator iter; + for (iter=m_AuthMethods.begin(); + iter!=m_AuthMethods.end(); + iter++) + { + if (index-- == 0) + { + return (*iter).table; + } + } + + return NULL; +} + +bool AdminCache::InvalidateAdmin(AdminId id) +{ + AdminUser *pUser = (AdminUser *)m_pMemory->GetAddress(id); + AdminUser *pOther; + if (!pUser || pUser->magic != USR_MAGIC_SET) + { + return false; + } + + /* Unlink from the dbl link list */ + if (id == m_FirstUser && id == m_LastUser) + { + m_FirstUser = INVALID_ADMIN_ID; + m_LastUser = INVALID_ADMIN_ID; + } else if (id == m_FirstUser) { + m_FirstUser = pUser->next_user; + pOther = (AdminUser *)m_pMemory->GetAddress(m_FirstUser); + pOther->prev_user = INVALID_ADMIN_ID; + } else if (id == m_LastUser) { + m_LastUser = pUser->prev_user; + pOther = (AdminUser *)m_pMemory->GetAddress(m_LastUser); + pOther->next_user = INVALID_ADMIN_ID; + } else { + pOther = (AdminUser *)m_pMemory->GetAddress(pUser->prev_user); + pOther->next_user = pUser->next_user; + pOther = (AdminUser *)m_pMemory->GetAddress(pUser->next_user); + pOther->prev_user = pUser->prev_user; + } + + /* Unlink from auth tables */ + if (pUser->auth_count > 0) + { + UserAuth *pAuth = (UserAuth *)m_pMemory->GetAddress(pUser->auth_table); + Trie *pTrie; + for (unsigned int i=0; iauth_count; i++) + { + pTrie = GetMethodByIndex(pAuth[i].index); + if (!pTrie) + { + continue; + } + sm_trie_delete(pTrie, m_pStrings->GetString(pAuth->identidx)); + } + } + + /* Clear table counts */ + pUser->grp_count = 0; + pUser->auth_count = 0; + + /* Link into free list */ + pUser->magic = USR_MAGIC_UNSET; + pUser->next_user = m_FreeUserList; + m_FreeUserList = id; + + return true; +} + + void AdminCache::InvalidateGroup(GroupId id) { AdminGroup *pGroup = (AdminGroup *)m_pMemory->GetAddress(id); @@ -548,7 +677,44 @@ void AdminCache::InvalidateGroup(GroupId id) pGroup->next_grp = m_FreeGroupList; m_FreeGroupList = id; - /* :TODO: remove this group from any users */ + int idx = m_FirstUser; + AdminUser *pUser; + int *table; + while (idx != INVALID_ADMIN_ID) + { + pUser = (AdminUser *)m_pMemory->GetAddress(idx); + if (pUser->grp_count > 0) + { + table = (int *)m_pMemory->GetAddress(pUser->grp_table); + for (unsigned int i=0; igrp_count; i++) + { + if (table[i] == id) + { + /* We have to remove this entry */ + for (unsigned int j=i+1; jgrp_count; j++) + { + /* Move everything down by one */ + table[j-1] = table[j]; + } + /* Decrease count */ + pUser->grp_count--; + /* Recalculate effective flags */ + memset(pUser->eflags, 0, sizeof(pUser->eflags)); + for (unsigned int j=0; jgrp_count; j++) + { + pOther = (AdminGroup *)m_pMemory->GetAddress(table[j]); + for (unsigned int k=0; keflags[k] = (pUser->flags[k] || pOther->addflags[k]); + } + } + /* Break now, duplicates aren't allowed */ + break; + } + } + } + idx = pUser->next_user; + } } void AdminCache::InvalidateGroupCache() @@ -580,7 +746,7 @@ void AdminCache::InvalidateGroupCache() m_FirstGroup = INVALID_GROUP_ID; m_LastGroup = INVALID_GROUP_ID; - /* :TODO: dump the admin cache */ + InvalidateAdminCache(false); /* Reset the memory table */ m_pMemory->Reset(); @@ -596,6 +762,41 @@ void AdminCache::RemoveAdminListener(IAdminListener *pListener) m_hooks.remove(pListener); } +void AdminCache::RegisterAuthIdentType(const char *name) +{ + if (sm_trie_retrieve(m_pAuthTables, name, NULL)) + { + return; + } + + Trie *pAuth = sm_trie_create(); + + AuthMethod method; + method.name.assign(name); + method.table = pAuth; + + m_AuthMethods.push_back(method); + + sm_trie_insert(m_pAuthTables, name, pAuth); +} + +void AdminCache::InvalidateAdminCache(bool unlink_admins) +{ + /* Wipe the identity cache first */ + List::iterator iter; + for (iter=m_AuthMethods.begin(); + iter!=m_AuthMethods.end(); + iter++) + { + sm_trie_clear((*iter).table); + } + + while (m_FirstUser != INVALID_ADMIN_ID) + { + InvalidateAdmin(m_FirstUser); + } +} + void AdminCache::DumpAdminCache(int cache_flags, bool rebuild) { if (cache_flags & ADMIN_CACHE_OVERRIDES) @@ -604,19 +805,19 @@ void AdminCache::DumpAdminCache(int cache_flags, bool rebuild) DumpCommandOverrideCache(Override_CommandGroup); } - if ((cache_flags & ADMIN_CACHE_ADMINS) || - (cache_flags & ADMIN_CACHE_GROUPS)) - { - /* Make sure the flag is set */ - cache_flags |= ADMIN_CACHE_ADMINS; - /* :TODO: Dump admin cache */ - } - + /* This will auto-invalidate the admin cache */ if (cache_flags & ADMIN_CACHE_GROUPS) { InvalidateGroupCache(); } + /* If we only requested an admin rebuild, re-use the internal memory */ + if ((cache_flags & ADMIN_CACHE_ADMINS) && + !(cache_flags & ADMIN_CACHE_GROUPS)) + { + InvalidateAdminCache(true); + } + if (rebuild) { List::iterator iter; @@ -631,3 +832,236 @@ void AdminCache::DumpAdminCache(int cache_flags, bool rebuild) m_pCacheFwd->Execute(&result); } } + +const char *AdminCache::GetAdminName(AdminId id) +{ + AdminUser *pUser = (AdminUser *)m_pMemory->GetAddress(id); + if (!pUser || pUser->magic != USR_MAGIC_SET) + { + return NULL; + } + + return m_pStrings->GetString(pUser->nameidx); +} + +bool AdminCache::BindAdminIdentity(AdminId id, const char *auth, const char *ident) +{ + AdminUser *pUser = (AdminUser *)m_pMemory->GetAddress(id); + if (!pUser || pUser->magic != USR_MAGIC_SET) + { + return false; + } + + Trie *pTable; + if (!sm_trie_retrieve(m_pAuthTables, auth, (void **)&pTable)) + { + return false; + } + + if (sm_trie_retrieve(pTable, ident, NULL)) + { + return false; + } + + return sm_trie_insert(pTable, ident, (void **)id); +} + +AdminId AdminCache::FindAdminByIdentity(const char *auth, const char *identity) +{ + Trie *pTable; + if (!sm_trie_retrieve(m_pAuthTables, auth, (void **)&pTable)) + { + return INVALID_ADMIN_ID; + } + + void *object; + if (!sm_trie_retrieve(pTable, identity, &object)) + { + return INVALID_ADMIN_ID; + } + + return (AdminId)object; +} + +void AdminCache::SetAdminFlag(AdminId id, AdminFlag flag, bool enabled) +{ + AdminUser *pUser = (AdminUser *)m_pMemory->GetAddress(id); + if (!pUser || pUser->magic != USR_MAGIC_SET) + { + return; + } + + if (flag < Admin_None + || flag >= AdminFlags_TOTAL) + { + return; + } + + pUser->flags[enabled] = false; +} + +bool AdminCache::GetAdminFlag(AdminId id, AdminFlag flag, AccessMode mode) +{ + AdminUser *pUser = (AdminUser *)m_pMemory->GetAddress(id); + if (!pUser || pUser->magic != USR_MAGIC_SET) + { + return false; + } + + if (flag < Admin_None + || flag >= AdminFlags_TOTAL) + { + return false; + } + + if (mode == Access_Real) + { + return pUser->flags[flag]; + } else if (mode == Access_Effective) { + return (pUser->flags[flag] || pUser->eflags[flag]); + } + + return false; +} + +unsigned int AdminCache::GetAdminFlags(AdminId id, bool flags[], unsigned int total, AccessMode mode) +{ + AdminUser *pUser = (AdminUser *)m_pMemory->GetAddress(id); + if (!pUser || pUser->magic != USR_MAGIC_SET) + { + return 0; + } + + unsigned int i = 0; + if (mode == Access_Real) + { + for (i=0; iflags[i]; + } + } else if (mode == Access_Effective) { + for (i=0; iflags[i] || pUser->eflags[i]); + } + } + + return i; +} + +bool AdminCache::AdminInheritGroup(AdminId id, GroupId gid) +{ + AdminUser *pUser = (AdminUser *)m_pMemory->GetAddress(id); + if (!pUser || pUser->magic != USR_MAGIC_SET) + { + return false; + } + + AdminGroup *pGroup = (AdminGroup *)m_pMemory->GetAddress(gid); + if (!pGroup || pGroup->magic != USR_MAGIC_SET) + { + return false; + } + + int *table; + if (pUser->grp_count + 1 > pUser->grp_size) + { + int new_size = 0; + int tblidx; + + if (pUser->grp_size == 0) + { + new_size = 2; + } else { + new_size = pUser->grp_size * 2; + } + + /* Create and refresh pointers */ + tblidx = m_pMemory->CreateMem(new_size * sizeof(int), (void **)&table); + pUser = (AdminUser *)m_pMemory->GetAddress(id); + pGroup = (AdminGroup *)m_pMemory->GetAddress(gid); + + /* Copy old data if necessary */ + if (pUser->grp_table != -1) + { + int *old_table = (int *)m_pMemory->GetAddress(pUser->grp_table); + memcpy(table, old_table, sizeof(int) * pUser->grp_count); + } + pUser->grp_table = tblidx; + pUser->grp_size = new_size; + } else { + table = (int *)m_pMemory->GetAddress(pUser->grp_table); + } + + for (unsigned int i=0; igrp_count; i++) + { + if (table[i] == gid) + { + return false; + } + } + + table[pUser->grp_count] = gid; + pUser->grp_count++; + + /* Compute new effective flags */ + for (unsigned int i=Admin_None; + ieflags[i]) + { + pUser->eflags[i] = pGroup->addflags[i]; + } + } + + return true; +} + +unsigned int AdminCache::GetAdminGroupCount(AdminId id) +{ + AdminUser *pUser = (AdminUser *)m_pMemory->GetAddress(id); + if (!pUser || pUser->magic != USR_MAGIC_SET) + { + return 0; + } + + return pUser->grp_count; +} + +GroupId AdminCache::GetAdminGroup(AdminId id, unsigned int index, const char **name) +{ + AdminUser *pUser = (AdminUser *)m_pMemory->GetAddress(id); + if (!pUser || pUser->magic != USR_MAGIC_SET || index >= pUser->grp_count) + { + return INVALID_GROUP_ID; + } + + int *table = (int *)m_pMemory->GetAddress(pUser->grp_table); + + return table[index]; +} + +const char *AdminCache::GetAdminPassword(AdminId id) +{ + AdminUser *pUser = (AdminUser *)m_pMemory->GetAddress(id); + if (!pUser || pUser->magic != USR_MAGIC_SET) + { + return NULL; + } + + return m_pStrings->GetString(pUser->password); +} + +void AdminCache::SetAdminPassword(AdminId id, const char *password) +{ + AdminUser *pUser = (AdminUser *)m_pMemory->GetAddress(id); + if (!pUser || pUser->magic != USR_MAGIC_SET) + { + return; + } + + pUser->password = m_pStrings->AddString(password); +} + diff --git a/core/AdminCache.h b/core/AdminCache.h index a4bb38d0..07681a14 100644 --- a/core/AdminCache.h +++ b/core/AdminCache.h @@ -17,6 +17,7 @@ #include "sm_memtable.h" #include #include +#include #include #include "sm_globals.h" #include @@ -25,6 +26,8 @@ using namespace SourceHook; #define GRP_MAGIC_SET 0xDEADFADE #define GRP_MAGIC_UNSET 0xFACEFACE +#define USR_MAGIC_SET 0xDEADFACE +#define USR_MAGIC_UNSET 0xFADEDEAD struct AdminGroup { @@ -44,6 +47,35 @@ struct AdminGroup bool addflags[AdminFlags_TOTAL]; /* Additive flags */ }; +struct AuthMethod +{ + String name; + Trie *table; +}; + +struct UserAuth +{ + unsigned int index; /* Index into auth table */ + int identidx; /* Index into the string table */ +}; + +struct AdminUser +{ + int magic; /* Magic flag, for memory validation */ + bool flags[AdminFlags_TOTAL]; /* Base flags */ + bool eflags[AdminFlags_TOTAL]; /* Effective flags */ + int nameidx; /* Name index */ + int password; /* Password index */ + unsigned int grp_count; /* Number of groups */ + unsigned int grp_size; /* Size of groups table */ + int grp_table; /* Group table itself */ + int next_user; /* Next user in ze list */ + int prev_user; /* Prev user in the list */ + unsigned int auth_count; /* Number of auth methods */ + unsigned int auth_size; /* Size of auth table */ + int auth_table; /* Auth table itself */ +}; + class AdminCache : public IAdminSystem, public SMGlobalClass @@ -52,6 +84,7 @@ public: AdminCache(); ~AdminCache(); public: //SMGlobalClass + void OnSourceModStartup(bool late); void OnSourceModAllInitialized(); void OnSourceModShutdown(); public: //IAdminSystem @@ -76,6 +109,21 @@ public: //IAdminSystem void DumpAdminCache(int cache_flags, bool rebuild); void AddAdminListener(IAdminListener *pListener); void RemoveAdminListener(IAdminListener *pListener); + /** User stuff */ + void RegisterAuthIdentType(const char *name); + AdminId CreateAdmin(const char *name); + const char *GetAdminName(AdminId id); + bool BindAdminIdentity(AdminId id, const char *auth, const char *ident); + virtual void SetAdminFlag(AdminId id, AdminFlag flag, bool enabled); + bool GetAdminFlag(AdminId id, AdminFlag flag, AccessMode mode); + unsigned int GetAdminFlags(AdminId id, bool flags[], unsigned int total, AccessMode mode); + bool AdminInheritGroup(AdminId id, GroupId gid); + unsigned int GetAdminGroupCount(AdminId id); + GroupId GetAdminGroup(AdminId id, unsigned int index, const char **name); + void SetAdminPassword(AdminId id, const char *password); + const char *GetAdminPassword(AdminId id); + AdminId FindAdminByIdentity(const char *auth, const char *identity); + bool InvalidateAdmin(AdminId id); private: void _AddCommandOverride(const char *cmd, AdminFlag flag); void _AddCommandGroupOverride(const char *group, AdminFlag flag); @@ -84,7 +132,9 @@ private: void _UnsetCommandOverride(const char *cmd); void _UnsetCommandGroupOverride(const char *group); void InvalidateGroupCache(); + void InvalidateAdminCache(bool unlink_admins); void DumpCommandOverrideCache(OverrideType type); + Trie *GetMethodByIndex(unsigned int index); public: BaseStringTable *m_pStrings; BaseMemTable *m_pMemory; @@ -95,7 +145,12 @@ public: int m_FreeGroupList; Trie *m_pGroups; List m_hooks; + List m_AuthMethods; + Trie *m_pAuthTables; IForward *m_pCacheFwd; + int m_FirstUser; + int m_LastUser; + int m_FreeUserList; }; extern AdminCache g_Admins; diff --git a/core/sm_memtable.h b/core/sm_memtable.h index 043e2618..e77eeb88 100644 --- a/core/sm_memtable.h +++ b/core/sm_memtable.h @@ -39,6 +39,8 @@ public: * begin at the first index again. */ void Reset(); + + private: unsigned char *membase; unsigned int size; diff --git a/public/IAdminSystem.h b/public/IAdminSystem.h index ceb4188c..83e7b646 100644 --- a/public/IAdminSystem.h +++ b/public/IAdminSystem.h @@ -43,6 +43,8 @@ * 3] An override table - insertion and retrieval only. * Individual groups can be invalidated entirely. It should be considered an expensive * operation, since each admin needs to be patched up to not reference the group. + * + * For more information, see the SourceMod Development wiki. */ namespace SourceMod @@ -98,11 +100,25 @@ namespace SourceMod Immunity_Global, /**< Immune from everyone (except root admins) */ }; + /** + * @brief Defines user access modes. + */ + enum AccessMode + { + Access_Real, /**< Access the user has inherently */ + Access_Effective, /**< Access the user has from their groups */ + }; + /** * @brief Represents an index to one group. */ typedef int GroupId; + /** + * @brief Represents an index to one user entry. + */ + typedef int AdminId; + #define ADMIN_CACHE_OVERRIDES (1<<0) #define ADMIN_CACHE_ADMINS (1<<1) #define ADMIN_CACHE_GROUPS ((1<<2)|ADMIN_CACHE_ADMINS) @@ -112,6 +128,11 @@ namespace SourceMod */ #define INVALID_GROUP_ID -1 + /** + * @brief Represents an invalid/nonexistant user or an erroneous operation. + */ + #define INVALID_ADMIN_ID -1 + /** * @brief Provides callbacks for admin cache operations. */ @@ -315,6 +336,140 @@ namespace SourceMod * @param pListener Pointer to an IAdminListener to remove. */ virtual void RemoveAdminListener(IAdminListener *pListener) =0; + + /** + * @brief Registers an authentication identity type. + * Note: Default types are "steam," "name," and "ip." + * + * @param name String containing the type name. + */ + virtual void RegisterAuthIdentType(const char *name) =0; + + /** + * @brief Creates a new user entry. + * + * @param name Name for this entry (does not have to be unique). + * Specify NULL for an anonymous admin. + * @return A new AdminId index. + */ + virtual AdminId CreateAdmin(const char *name) =0; + + /** + * @brief Gets an admin's user name. + * + * @param id AdminId index for this admin. + * @return A string containing the admin's name, or NULL + * if the admin was created anonymously. + */ + virtual const char *GetAdminName(AdminId id) =0; + + /** + * @brief Binds a user entry to a particular auth method. + * This bind must be unique. + * + * @param id AdminId index of the admin. + * @param auth Auth method to use. + * @param ident Identity string to bind to. + * @return True on success, false if auth method was not found, + * id was invalid, or ident was already taken. + */ + virtual bool BindAdminIdentity(AdminId id, const char *auth, const char *ident) =0; + + /** + * @brief Sets whether or not a flag is enabled on an admin. + * + * @param id AdminId index of the admin. + * @param flag Admin flag to use. + * @param enabled True to enable, false to disable. + */ + virtual void SetAdminFlag(AdminId id, AdminFlag flag, bool enabled) =0; + + /** + * @brief Returns whether or not a flag is enabled on an admin. + * + * @param id AdminId index of the admin. + * @param flag Admin flag to use. + * @param mode Access mode to check. + * @return True if enabled, false otherwise. + */ + virtual bool GetAdminFlag(AdminId id, AdminFlag flag, AccessMode mode) =0; + + /** + * @brief Returns a bitarray of flags enabled on an admin. + * + * @param id AdminId index of the admin. + * @param flag Array to store flag bits in. + * @param total Maximum size of the flag array. + * @param mode Access mode to use. + * @return Number of flags written to the array. + */ + virtual unsigned int GetAdminFlags(AdminId id, + bool flags[], + unsigned int total, + AccessMode mode) =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. + * + * @param id AdminId index of the admin. + * @param gid GroupId index of the group. + * @return True on success, false on invalid input or duplicate membership. + */ + virtual bool AdminInheritGroup(AdminId id, GroupId gid) =0; + + /** + * @brief Returns the number of groups this admin is a member of. + * + * @param id AdminId index of the admin. + * @return Number of groups this admin is a member of. + */ + virtual unsigned int GetAdminGroupCount(AdminId id) =0; + + /** + * @brief Returns group information from an admin. + * + * @param id AdminId index of the admin. + * @param index Group number to retrieve, from 0 to N-1, where N + * is the value of GetAdminGroupCount(id). + * @param name Optional pointer to store the group's name. + * @return A GroupId index and a name pointer, or + * INVALID_GROUP_ID and NULL if an error occurred. + */ + virtual GroupId GetAdminGroup(AdminId id, unsigned int index, const char **name) =0; + + /** + * @brief Sets a password on an admin. + * + * @param id AdminId index of the admin. + * @param passwd String containing the password. + */ + virtual void SetAdminPassword(AdminId id, const char *password) =0; + + /** + * @brief Gets an admin's password. + * + * @param id AdminId index of the admin. + * @return Password of the admin, or NULL if none. + */ + virtual const char *GetAdminPassword(AdminId id) =0; + + /** + * @brief Attempts to find an admin by an auth method and an identity. + * + * @param auth Auth method to try. + * @param identity Identity string to look up. + * @return An AdminId index if found, INVALID_ADMIN_ID otherwise. + */ + virtual AdminId FindAdminByIdentity(const char *auth, const char *identity) =0; + + /** + * @brief Invalidates an admin from the cache so its resources can be re-used. + * + * @param id AdminId index to invalidate. + * @return True on success, false otherwise. + */ + virtual bool InvalidateAdmin(AdminId id) =0; }; };