diff --git a/core/interfaces/IHandleSys.h b/core/interfaces/IHandleSys.h index 08d0d71e..d2b2c297 100644 --- a/core/interfaces/IHandleSys.h +++ b/core/interfaces/IHandleSys.h @@ -7,6 +7,8 @@ #define SMINTERFACE_HANDLESYSTEM_NAME "IHandleSys" #define SMINTERFACE_HANDLESYSTEM_VERSION 1 +#define DEFAULT_IDENTITY NULL + namespace SourceMod { /** @@ -37,6 +39,7 @@ namespace SourceMod HandleError_Index, /* generic internal indexing error */ HandleError_Access, /* No access permitted to free this handle */ HandleError_Limit, /* The limited number of handles has been reached */ + HandleError_Identity, /* The identity token was not usable */ }; enum HandleAccessRight @@ -54,14 +57,14 @@ namespace SourceMod { HandleSecurity() { - owner = 0; + owner = NULL; access[HandleAccess_Create] = true; access[HandleAccess_Read] = true; access[HandleAccess_Delete] = true; access[HandleAccess_Inherit] = true; access[HandleAccess_Clone] = true; } - IdentityToken_t owner; /* Owner of the handle */ + IdentityToken_t *owner; /* Owner of the handle */ bool access[HandleAccess_TOTAL]; /* World access rights */ }; @@ -112,12 +115,14 @@ namespace SourceMod * @param parent Parent handle to inherit from, 0 for none. * @param security Pointer to a temporary HandleSecurity object, NULL to use default * or inherited permissions. + * @param ident Security token for any permissions. * @return A new HandleType_t unique ID. */ virtual HandleType_t CreateTypeEx(const char *name, IHandleTypeDispatch *dispatch, HandleType_t parent, - const HandleSecurity *security) =0; + const HandleSecurity *security, + IdentityToken_t *ident) =0; /** @@ -143,7 +148,7 @@ namespace SourceMod * @param type Type chain to remove. * @return True on success, false on failure. */ - virtual bool RemoveType(HandleType_t type, IdentityToken_t ident) =0; + virtual bool RemoveType(HandleType_t type, IdentityToken_t *ident) =0; /** * @brief Finds a handle type by name. @@ -159,14 +164,14 @@ namespace SourceMod * * @param type Type to use on the handle. * @param object Object to bind to the handle. - * @param source Identity token for object using this handle (for example, a script). + * @param owner Owner for the handle. * @param ident Identity token if any security rights are needed. * @return A new Handle_t, or 0 on failure. */ virtual Handle_t CreateHandle(HandleType_t type, void *object, - IdentityToken_t source, - IdentityToken_t ident) =0; + IdentityToken_t *owner, + IdentityToken_t *ident) =0; /** * @brief Creates a new handle. @@ -181,7 +186,7 @@ namespace SourceMod virtual Handle_t CreateScriptHandle(HandleType_t type, void *object, sp_context_t *ctx, - IdentityToken_t ident) =0; + IdentityToken_t *ident) =0; /** * @brief Frees the memory associated with a handle and calls any destructors. @@ -192,7 +197,7 @@ namespace SourceMod * @param ident Identity token, for destroying secure handles (0 for none). * @return A HandleError error code. */ - virtual HandleError FreeHandle(Handle_t handle, IdentityToken_t ident) =0; + virtual HandleError FreeHandle(Handle_t handle, IdentityToken_t *ident) =0; /** * @brief Clones a handle by adding to its internal reference count. Its data, @@ -200,11 +205,11 @@ namespace SourceMod * * @param handle Handle to duplicate. Any non-free handle target is valid. * @param newhandle If non-NULL, stores the duplicated handle in the pointer. - * @param source New source of cloned handle. + * @param owner New owner of cloned handle. * @param ident Security token, if needed. * @return A HandleError error code. */ - virtual HandleError CloneHandle(Handle_t handle, Handle_t *newhandle, IdentityToken_t source, IdentityToken_t ident) =0; + virtual HandleError CloneHandle(Handle_t handle, Handle_t *newhandle, IdentityToken_t *owner, IdentityToken_t *ident) =0; /** * @brief Retrieves the contents of a handle. @@ -215,7 +220,7 @@ namespace SourceMod * @param object Address to store object in. * @return HandleError error code. */ - virtual HandleError ReadHandle(Handle_t handle, HandleType_t type, IdentityToken_t ident, void **object) =0; + virtual HandleError ReadHandle(Handle_t handle, HandleType_t type, IdentityToken_t *ident, void **object) =0; }; }; diff --git a/core/interfaces/IPluginSys.h b/core/interfaces/IPluginSys.h index 037cc33b..dca8e2db 100644 --- a/core/interfaces/IPluginSys.h +++ b/core/interfaces/IPluginSys.h @@ -147,7 +147,7 @@ namespace SourceMod /** * @brief Returns a plugin's identity token. */ - virtual IdentityToken_t GetIdentity() =0; + virtual IdentityToken_t *GetIdentity() =0; }; diff --git a/core/interfaces/IShareSys.h b/core/interfaces/IShareSys.h index 156d0470..d4f6db0f 100644 --- a/core/interfaces/IShareSys.h +++ b/core/interfaces/IShareSys.h @@ -3,11 +3,13 @@ #include -#define DEFAULT_IDENTITY 0 +#define NO_IDENTITY 0 namespace SourceMod { - typedef unsigned int IdentityToken_t; + struct IdentityToken_t; + typedef unsigned int HandleType_t; + typedef HandleType_t IdentityType_t; /** * @brief Defines the base functionality required by a shared interface. */ @@ -49,12 +51,13 @@ namespace SourceMod { public: /** - * @brief Adds an interface to the global interface system + * @brief Adds an interface to the global interface system. * * @param iface Interface pointer (must be unique). * @param token Parent token of the module/interface. + * @return True on success, false otherwise. */ - virtual bool AddInterface(SMInterface *iface, IdentityToken_t token) =0; + virtual bool AddInterface(SMInterface *iface, IdentityToken_t *token) =0; /** * @brief Requests an interface from the global interface system. @@ -67,8 +70,8 @@ namespace SourceMod */ virtual bool RequestInterface(const char *iface_name, unsigned int iface_vers, - IdentityToken_t token, - void **pIface) =0; + IdentityToken_t *token, + SMInterface **pIface) =0; /** * @brief Adds a list of natives to the global native pool. @@ -76,7 +79,54 @@ namespace SourceMod * @param token Identity token of parent object. * @param natives Array of natives to add, NULL terminated. */ - virtual void AddNatives(IdentityToken_t token, const sp_nativeinfo_t *natives[]) =0; + virtual void AddNatives(IdentityToken_t *token, const sp_nativeinfo_t *natives[]) =0; + + /** + * @brief Creates a new identity type. + * NOTE: Module authors should never need to use this. Due to the current implementation, + * there is a hardcoded limit of 15 types. Core uses up a few, so think carefully! + * + * @param name String containing type name. Must not be empty or NULL. + * @return A new HandleType_t identifier, or 0 on failure. + */ + virtual IdentityType_t CreateIdentType(const char *name) =0; + + /** + * @brief Finds an identity type by name. + * DEFAULT IDENTITY TYPES: + * "PLUGIN" - An IPlugin object. + * "MODULE" - An IModule object. + * "CORE" - An SMGlobalClass or other singleton. + * + * @param name String containing type name to search for. + * @return A HandleType_t identifier if found, 0 otherwise. + */ + virtual IdentityType_t FindIdentType(const char *name) =0; + + /** + * @brief Creates a new identity token. This token is guaranteed to be unique + * amongst all other open identities. + * + * @param type Identity type. + * @return A new IdentityToken_t identifier. + */ + virtual IdentityToken_t *CreateIdentity(IdentityType_t type) =0; + + /** + * @brief Destroys an identity type. Note that this will delete any identities + * that are under this type. + * + * @param type Identity type. + */ + virtual void DestroyIdentType(IdentityType_t type) =0; + + /** + * @brief Destroys an identity token. Any handles being owned by this token, or + * any handles being + * + * @param identity Identity to remove. + */ + virtual void DestroyIdentity(IdentityToken_t *identity) =0; }; }; diff --git a/core/sm_globals.h b/core/sm_globals.h index a69a3abf..8426b0bd 100644 --- a/core/sm_globals.h +++ b/core/sm_globals.h @@ -13,6 +13,40 @@ using namespace SourcePawn; using namespace SourceMod; +/** + * @brief Any class deriving from this will be automatically initiated/shutdown by SourceMod + */ +class SMGlobalClass +{ + friend class SourceModBase; +public: + SMGlobalClass(); +public: + /** + * @brief Called when SourceMod is initially loading + */ + virtual void OnSourceModStartup(bool late) + { + } + + /** + * @brief Called after all global classes have initialized + */ + virtual void OnSourceModAllInitialized() + { + } + + /** + * @brief Called when SourceMod is shutting down + */ + virtual void OnSourceModShutdown() + { + } +private: + SMGlobalClass *m_pGlobalClassNext; + static SMGlobalClass *head; +}; + extern ISourcePawnEngine *g_pSourcePawn; extern IVirtualMachine *g_pVM; diff --git a/core/sourcemod.h b/core/sourcemod.h index 238531c4..0405cefd 100644 --- a/core/sourcemod.h +++ b/core/sourcemod.h @@ -52,40 +52,6 @@ private: bool m_IsLateLoadInMap; }; -/** - * @brief Any class deriving from this will be automatically initiated/shutdown by SourceMod - */ -class SMGlobalClass -{ - friend class SourceModBase; -public: - SMGlobalClass(); -public: - /** - * @brief Called when SourceMod is initially loading - */ - virtual void OnSourceModStartup(bool late) - { - } - - /** - * @brief Called after all global classes have initialized - */ - virtual void OnSourceModAllInitialized() - { - } - - /** - * @brief Called when SourceMod is shutting down - */ - virtual void OnSourceModShutdown() - { - } -private: - SMGlobalClass *m_pGlobalClassNext; - static SMGlobalClass *head; -}; - extern SourceModBase g_SourceMod; #endif //_INCLUDE_SOURCEMOD_GLOBALHEADER_H_ diff --git a/core/systems/HandleSys.cpp b/core/systems/HandleSys.cpp index 35ef4a62..be91460a 100644 --- a/core/systems/HandleSys.cpp +++ b/core/systems/HandleSys.cpp @@ -1,9 +1,22 @@ #include "HandleSys.h" +#include "ShareSys.h" #include "PluginSys.h" #include HandleSystem g_HandleSys; +QHandle *ignore_handle; + +inline HandleType_t TypeParent(HandleType_t type) +{ + return (type & ~HANDLESYS_SUBTYPE_MASK); +} + +inline HandleError IdentityHandle(IdentityToken_t *token, unsigned int *index) +{ + return g_HandleSys.GetHandle(token->ident, g_ShareSys.GetIdentRoot(), &ignore_handle, index, HandleAccess_Read); +} + HandleSystem::HandleSystem() { m_Handles = new QHandle[HANDLESYS_MAX_HANDLES + 1]; @@ -28,18 +41,19 @@ HandleSystem::~HandleSystem() HandleType_t HandleSystem::CreateType(const char *name, IHandleTypeDispatch *dispatch) { - return CreateTypeEx(name, dispatch, 0, NULL); + return CreateTypeEx(name, dispatch, 0, NULL, NULL); } HandleType_t HandleSystem::CreateChildType(const char *name, HandleType_t parent, IHandleTypeDispatch *dispatch) { - return CreateTypeEx(name, dispatch, parent, NULL); + return CreateTypeEx(name, dispatch, parent, NULL, NULL); } HandleType_t HandleSystem::CreateTypeEx(const char *name, IHandleTypeDispatch *dispatch, HandleType_t parent, - const HandleSecurity *security) + const HandleSecurity *security, + IdentityToken_t *ident) { if (!dispatch) { @@ -56,8 +70,9 @@ HandleType_t HandleSystem::CreateTypeEx(const char *name, return 0; } if (parent >= HANDLESYS_TYPEARRAY_SIZE - || m_Types[parent].dispatch != NULL - || m_Types[parent].sec.access[HandleAccess_Inherit] == false) + || m_Types[parent].dispatch == NULL + || (m_Types[parent].sec.access[HandleAccess_Inherit] == false + && m_Types[parent].sec.owner != ident)) { return 0; } @@ -163,8 +178,16 @@ bool HandleSystem::FindHandleType(const char *name, HandleType_t *type) HandleError HandleSystem::MakePrimHandle(HandleType_t type, QHandle **in_pHandle, unsigned int *in_index, - Handle_t *in_handle) + Handle_t *in_handle, + IdentityToken_t *owner) { + unsigned int owner_index = 0; + + if (owner && (IdentityHandle(owner, &owner_index) != HandleError_None)) + { + return HandleError_Identity; + } + unsigned int handle; if (m_FreeHandles == 0) { @@ -187,10 +210,12 @@ HandleError HandleSystem::MakePrimHandle(HandleType_t type, } /* Set essential information */ - pHandle->set = true; + pHandle->set = HandleSet_Used;; pHandle->refcount = 1; pHandle->type = type; pHandle->serial = m_HSerial; + pHandle->owner = owner; + pHandle->ch_next = 0; /* Create the hash value */ Handle_t hash = pHandle->serial; @@ -205,10 +230,44 @@ HandleError HandleSystem::MakePrimHandle(HandleType_t type, *in_index = handle; *in_handle = hash; + /* Decode the identity token */ + if (owner) + { + QHandle *pIdentity = &m_Handles[owner_index]; + if (pIdentity->ch_prev == 0) + { + pIdentity->ch_prev = handle; + pIdentity->ch_next = handle; + pHandle->ch_prev = 0; + } else { + /* Link previous node to us (forward) */ + m_Handles[pIdentity->ch_next].ch_next = handle; + /* Link us to previous node (backwards) */ + pHandle->ch_prev = pIdentity->ch_next; + /* Set new tail */ + pIdentity->ch_next = handle; + } + pIdentity->refcount++; + } else { + pHandle->ch_prev = 0; + } + return HandleError_None; } -Handle_t HandleSystem::CreateHandle(HandleType_t type, void *object, IdentityToken_t source, IdentityToken_t ident) +void HandleSystem::SetTypeSecurityOwner(HandleType_t type, IdentityToken_t *pToken) +{ + if (!type + || type >= HANDLESYS_TYPEARRAY_SIZE + || m_Types[type].dispatch == NULL) + { + return; + } + + m_Types[type].sec.owner = pToken; +} + +Handle_t HandleSystem::CreateHandle(HandleType_t type, void *object, IdentityToken_t *source, IdentityToken_t *ident) { if (!type || type >= HANDLESYS_TYPEARRAY_SIZE @@ -230,12 +289,11 @@ Handle_t HandleSystem::CreateHandle(HandleType_t type, void *object, IdentityTok QHandle *pHandle; HandleError err; - if ((err=MakePrimHandle(type, &pHandle, &index, &handle)) != HandleError_None) + if ((err=MakePrimHandle(type, &pHandle, &index, &handle, source)) != HandleError_None) { return 0; } - pHandle->source = source; pHandle->object = object; pHandle->clone = 0; @@ -245,15 +303,35 @@ Handle_t HandleSystem::CreateHandle(HandleType_t type, void *object, IdentityTok Handle_t HandleSystem::CreateScriptHandle(HandleType_t type, void *object, sp_context_t *ctx, - IdentityToken_t ident) + IdentityToken_t *ident) { IPlugin *pPlugin = g_PluginSys.FindPluginByContext(ctx); return CreateHandle(type, object, pPlugin->GetIdentity(), ident); } +bool HandleSystem::TypeCheck(HandleType_t intype, HandleType_t outtype) +{ + /* Check the type inheritance */ + if (intype & HANDLESYS_SUBTYPE_MASK) + { + if (intype != outtype + && (TypeParent(intype) != TypeParent(outtype))) + { + return false; + } + } else { + if (intype != outtype) + { + return false; + } + } + + return true; +} + HandleError HandleSystem::GetHandle(Handle_t handle, - IdentityToken_t ident, + IdentityToken_t *ident, QHandle **in_pHandle, unsigned int *in_index, HandleAccessRight access) @@ -277,6 +355,11 @@ HandleError HandleSystem::GetHandle(Handle_t handle, if (!pHandle->set) { return HandleError_Freed; + } else if (pHandle->set == HandleSet_Identity + && ident != g_ShareSys.GetIdentRoot()) + { + /* Only IdentityHandle() can read this! */ + return HandleError_Identity; } if (pHandle->serial != serial) { @@ -289,7 +372,7 @@ HandleError HandleSystem::GetHandle(Handle_t handle, return HandleError_None; } -HandleError HandleSystem::CloneHandle(Handle_t handle, Handle_t *out_newhandle, IdentityToken_t source, IdentityToken_t ident) +HandleError HandleSystem::CloneHandle(Handle_t handle, Handle_t *out_newhandle, IdentityToken_t *source, IdentityToken_t *ident) { HandleError err; QHandle *pHandle; @@ -307,13 +390,12 @@ HandleError HandleSystem::CloneHandle(Handle_t handle, Handle_t *out_newhandle, QHandle *pNewHandle; Handle_t new_handle; - if ((err=MakePrimHandle(pHandle->type, &pNewHandle, &new_index, &new_handle)) != HandleError_None) + if ((err=MakePrimHandle(pHandle->type, &pNewHandle, &new_index, &new_handle, source)) != HandleError_None) { return err; } pNewHandle->clone = index; - pNewHandle->source = source; if (out_newhandle) { @@ -323,7 +405,7 @@ HandleError HandleSystem::CloneHandle(Handle_t handle, Handle_t *out_newhandle, return HandleError_None; } -HandleError HandleSystem::FreeHandle(Handle_t handle, IdentityToken_t ident) +HandleError HandleSystem::FreeHandle(Handle_t handle, IdentityToken_t *ident) { unsigned int index; QHandle *pHandle; @@ -361,14 +443,9 @@ HandleError HandleSystem::FreeHandle(Handle_t handle, IdentityToken_t ident) return HandleError_None; } -inline HandleType_t TypeParent(HandleType_t type) -{ - return (type & ~HANDLESYS_SUBTYPE_MASK); -} - HandleError HandleSystem::ReadHandle(Handle_t handle, HandleType_t type, - IdentityToken_t ident, + IdentityToken_t *ident, void **object) { unsigned int index; @@ -412,12 +489,59 @@ void HandleSystem::ReleasePrimHandle(unsigned int index) { QHandle *pHandle = &m_Handles[index]; - pHandle->set = false; + pHandle->set = HandleSet_None; m_Types[pHandle->type].opened--; m_Handles[++m_FreeHandles].freeID = index; + + /* Unlink us if necessary */ + if (pHandle->owner) + { + unsigned int ident_index; + if (IdentityHandle(pHandle->owner, &ident_index) != HandleError_None) + { + /* Uh-oh! */ + assert(pHandle->owner == 0); + return; + } + /* Note that since 0 is an invalid handle, if any of these links are 0, + * the data can still be set. + */ + QHandle *pIdentity = &m_Handles[ident_index]; + + /* Unlink case: We're the head AND tail node */ + if (index == pIdentity->ch_prev && index == pIdentity->ch_next) + { + pIdentity->ch_prev = 0; + pIdentity->ch_next = 0; + } + /* Unlink case: We're the head node */ + else if (index == pIdentity->ch_prev) { + /* Link us to the next in the chain */ + pIdentity->ch_prev = pHandle->ch_next; + /* Patch up the previous link */ + m_Handles[pHandle->ch_next].ch_prev = 0; + } + /* Unlink case: We're the tail node */ + else if (index == pIdentity->ch_next) { + /* Link us to the previous in the chain */ + pIdentity->ch_next = pHandle->ch_prev; + /* Patch up the next link */ + m_Handles[pHandle->ch_prev].ch_next = 0; + } + /* Unlink case: We're in the middle! */ + else { + /* Patch the forward reference */ + m_Handles[pHandle->ch_next].ch_prev = pHandle->ch_prev; + /* Patch the backward reference */ + m_Handles[pHandle->ch_prev].ch_next = pHandle->ch_next; + } + + /* Lastly, decrease the reference count */ + pIdentity->refcount--; + } } -bool HandleSystem::RemoveType(HandleType_t type, IdentityToken_t ident) +bool HandleSystem::RemoveType(HandleType_t type, IdentityToken_t *ident) { if (type == 0 || type >= HANDLESYS_TYPEARRAY_SIZE) { @@ -499,3 +623,16 @@ bool HandleSystem::RemoveType(HandleType_t type, IdentityToken_t ident) return true; } + +void HandleSystem::MarkHandleAsIdentity(Handle_t handle) +{ + QHandle *pHandle; + unsigned int index; + + if (GetHandle(handle, g_ShareSys.GetIdentRoot(), &pHandle, &index, HandleAccess_Read) != HandleError_None) + { + return; + } + + pHandle->set = HandleSet_Identity; +} diff --git a/core/systems/HandleSys.h b/core/systems/HandleSys.h index 755de11f..ec88d6ca 100644 --- a/core/systems/HandleSys.h +++ b/core/systems/HandleSys.h @@ -16,16 +16,46 @@ #define HANDLESYS_SERIAL_MASK 0xFFFF0000 #define HANDLESYS_HANDLE_MASK 0x0000FFFF +/** + * The QHandle is a nasty structure that compacts the handle system into a big vector. + * The members of the vector each encapsulate one Handle, however, they also act as nodes + * in an inlined linked list and an inlined vector. + * + * The first of these lists is the 'freeID' list. Each node from 1 to N (where N + * is the number of free nodes) has a 'freeID' that specifies a free Handle ID. This + * is a quick hack to get around allocating a second base vector. + * + * The second vector is the identity linked list. An identity has its own handle, so + * these handles are used as sentinel nodes for index linking. They point to the first and last + * index into the handle array. Each subsequent Handle who is owned by that indentity is mapped into + * that list. This lets owning identities be unloaded in O(n) time. + * + * Eventually, there may be a third list for type chains. + */ + +enum HandleSet +{ + HandleSet_None = 0, + HandleSet_Used, + HandleSet_Identity +}; + struct QHandle { HandleType_t type; /* Handle type */ void *object; /* Unmaintained object pointer */ - unsigned int freeID; /* ID of a free handle in the free handle chain */ - IdentityToken_t source; /* Identity of object which owns this */ + IdentityToken_t *owner; /* Identity of object which owns this */ unsigned int serial; /* Serial no. for sanity checking */ unsigned int refcount; /* Reference count for safe destruction */ Handle_t clone; /* If non-zero, this is our cloned parent */ - bool set; /* Whether or not this handle is set */ + HandleSet set; /* Information about the handle's state */ + /* The following variables are unrelated to the Handle array, and used + * as an inlined chain of information */ + unsigned int freeID; /* ID of a free handle in the free handle chain */ + /* Indexes into the handle array for owner membership. + * For identity roots, these are treated as the head/tail. */ + unsigned int ch_prev; /* chained previous handle or HEAD */ + unsigned int ch_next; /* chained next handle or TAIL */ }; struct QHandleType @@ -41,6 +71,8 @@ struct QHandleType class HandleSystem : public IHandleSys { + friend HandleError IdentityHandle(IdentityToken_t *token, unsigned int *index); + friend class ShareSystem; public: HandleSystem(); ~HandleSystem(); @@ -49,24 +81,26 @@ public: //IHandleSystem HandleType_t CreateTypeEx(const char *name, IHandleTypeDispatch *dispatch, HandleType_t parent, - const HandleSecurity *security); + const HandleSecurity *security, + IdentityToken_t *ident); HandleType_t CreateChildType(const char *name, HandleType_t parent, IHandleTypeDispatch *dispatch); - bool RemoveType(HandleType_t type, IdentityToken_t ident); + bool RemoveType(HandleType_t type, IdentityToken_t *ident); bool FindHandleType(const char *name, HandleType_t *type); Handle_t CreateHandle(HandleType_t type, void *object, - IdentityToken_t source, - IdentityToken_t ident); - Handle_t CreateScriptHandle(HandleType_t type, void *object, sp_context_t *ctx, IdentityToken_t ident); - HandleError FreeHandle(Handle_t handle, IdentityToken_t ident); - HandleError CloneHandle(Handle_t handle, Handle_t *newhandle, IdentityToken_t source, IdentityToken_t ident); - HandleError ReadHandle(Handle_t handle, HandleType_t type, IdentityToken_t ident, void **object); -private: + IdentityToken_t *source, + IdentityToken_t *ident); + Handle_t CreateScriptHandle(HandleType_t type, void *object, sp_context_t *ctx, IdentityToken_t *ident); + HandleError FreeHandle(Handle_t handle, IdentityToken_t *ident); + HandleError CloneHandle(Handle_t handle, Handle_t *newhandle, IdentityToken_t *source, IdentityToken_t *ident); + HandleError ReadHandle(Handle_t handle, HandleType_t type, IdentityToken_t *ident, void **object); + bool TypeCheck(HandleType_t intype, HandleType_t outtype); +protected: /** * Decodes a handle with sanity and security checking. */ HandleError GetHandle(Handle_t handle, - IdentityToken_t ident, + IdentityToken_t *ident, QHandle **pHandle, unsigned int *index, HandleAccessRight access); @@ -75,12 +109,28 @@ private: * Creates a basic handle and sets its reference count to 1. * Does not do any type or security checking. */ - HandleError MakePrimHandle(HandleType_t type, QHandle **pHandle, unsigned int *index, HandleType_t *handle); + HandleError MakePrimHandle(HandleType_t type, + QHandle **pHandle, + unsigned int *index, + HandleType_t *handle, + IdentityToken_t *owner); /** - * Frees a primitive handle. Does no object freeing, only reference count and bookkeepping. + * Frees a primitive handle. Does no object freeing, only reference count, bookkeepping, + * and linked list maintenance. */ void ReleasePrimHandle(unsigned int index); + + /** + * Sets the security owner of a type + */ + void SetTypeSecurityOwner(HandleType_t type, IdentityToken_t *pToken); + + /** + * Marks a handle as an identity. + * This prevents it from being tampered with by outside stuff + */ + void MarkHandleAsIdentity(Handle_t handle); private: QHandle *m_Handles; QHandleType *m_Types; diff --git a/core/systems/PluginSys.cpp b/core/systems/PluginSys.cpp index ce10f096..6524fac4 100644 --- a/core/systems/PluginSys.cpp +++ b/core/systems/PluginSys.cpp @@ -1,5 +1,6 @@ #include #include "PluginSys.h" +#include "ShareSys.h" #include "LibrarySys.h" #include "HandleSys.h" #include "sourcemm_api.h" @@ -8,6 +9,7 @@ CPluginManager g_PluginSys; HandleType_t g_PluginType = 0; +IdentityType_t g_PluginIdent = 0; CPlugin::CPlugin(const char *file) { @@ -22,8 +24,8 @@ CPlugin::CPlugin(const char *file) m_pub_funcs = NULL; m_errormsg[256] = '\0'; snprintf(m_filename, sizeof(m_filename), "%s", file); - /* :TODO: ShareSys token */ - m_handle = g_HandleSys.CreateHandle(g_PluginType, this, DEFAULT_IDENTITY, 1); + m_handle = 0; + m_ident = NULL; } CPlugin::~CPlugin() @@ -70,7 +72,20 @@ CPlugin::~CPlugin() m_plugin = NULL; } - g_HandleSys.FreeHandle(m_handle, g_PluginType); + if (m_handle) + { + g_HandleSys.FreeHandle(m_handle, g_PluginSys.GetIdentity()); + g_ShareSys.DestroyIdentity(m_ident); + } +} + +void CPlugin::InitIdentity() +{ + if (!m_handle) + { + m_ident = g_ShareSys.CreateIdentity(g_PluginIdent); + m_handle = g_HandleSys.CreateHandle(g_PluginType, this, g_PluginSys.GetIdentity(), g_PluginSys.GetIdentity()); + } } CPlugin *CPlugin::CreatePlugin(const char *file, char *error, size_t maxlength) @@ -447,9 +462,9 @@ bool CPlugin::SetPauseState(bool paused) return true; } -IdentityToken_t CPlugin::GetIdentity() +IdentityToken_t *CPlugin::GetIdentity() { - return 0; + return m_ident; } /******************* @@ -499,6 +514,7 @@ CPluginManager::CPluginManager() { m_LoadLookup = sm_trie_create(); m_AllPluginsLoaded = false; + m_MyIdent = NULL; } CPluginManager::~CPluginManager() @@ -661,6 +677,7 @@ void CPluginManager::LoadAutoPlugin(const char *file) if (pPlugin->GetStatus() == Plugin_Created) { AddCoreNativesToPlugin(pPlugin); + pPlugin->InitIdentity(); pPlugin->Call_AskPluginLoad(NULL, 0); } @@ -712,6 +729,8 @@ IPlugin *CPluginManager::LoadPlugin(const char *path, bool debug, PluginType typ AddCoreNativesToPlugin(pPlugin); + pPlugin->InitIdentity(); + /* Finally, ask the plugin if it wants to be loaded */ if (!pPlugin->Call_AskPluginLoad(error, err_max)) { @@ -1092,20 +1111,25 @@ bool CPluginManager::IsLateLoadTime() void CPluginManager::OnSourceModAllInitialized() { + m_MyIdent = g_ShareSys.CreateCoreIdentity(); + HandleSecurity sec; - sec.owner = 1; /* :TODO: implement ShareSys */ + sec.owner = m_MyIdent; /* :TODO: implement ShareSys */ sec.access[HandleAccess_Create] = false; sec.access[HandleAccess_Delete] = false; sec.access[HandleAccess_Inherit] = false; sec.access[HandleAccess_Clone] = false; - g_PluginType = g_HandleSys.CreateTypeEx("IPlugin", this, 0, &sec); + g_PluginType = g_HandleSys.CreateTypeEx("IPlugin", this, 0, &sec, NULL); + g_PluginIdent = g_ShareSys.CreateIdentType("PLUGIN"); } void CPluginManager::OnSourceModShutdown() { - g_HandleSys.RemoveType(g_PluginType, 1); + g_HandleSys.RemoveType(g_PluginType, m_MyIdent); + g_ShareSys.DestroyIdentType(g_PluginIdent); + g_ShareSys.DestroyIdentity(m_MyIdent); } void CPluginManager::OnHandleDestroy(HandleType_t type, void *object) diff --git a/core/systems/PluginSys.h b/core/systems/PluginSys.h index b6e3769f..6f58880a 100644 --- a/core/systems/PluginSys.h +++ b/core/systems/PluginSys.h @@ -93,7 +93,7 @@ public: virtual const sp_plugin_t *GetPluginStructure() const; virtual IPluginFunction *GetFunctionByName(const char *public_name); virtual IPluginFunction *GetFunctionById(funcid_t func_id); - virtual IdentityToken_t GetIdentity(); + virtual IdentityToken_t *GetIdentity(); public: /** * Creates a plugin object with default values. @@ -114,11 +114,17 @@ public: */ bool FinishMyCompile(char *error, size_t maxlength); void CancelMyCompile(); + /** * Sets an error state on the plugin */ void SetErrorState(PluginStatus status, const char *error_fmt, ...); + /** + * Initializes the plugin's identity information + */ + void InitIdentity(); + /** * Calls the OnPluginLoad function, and sets any failed states if necessary. * NOTE: Valid pre-states are: Plugin_Created @@ -151,6 +157,7 @@ private: CFunction **m_pub_funcs; char m_errormsg[256]; time_t m_LastAccess; + IdentityToken_t *m_ident; Handle_t m_handle; }; @@ -262,6 +269,10 @@ protected: void ReleaseIterator(CPluginIterator *iter); CFunction *GetFunctionFromPool(funcid_t f, CPlugin *plugin); void ReleaseFunctionToPool(CFunction *func); + inline IdentityToken_t *GetIdentity() + { + return m_MyIdent; + } private: List m_listeners; List m_plugins; @@ -271,6 +282,7 @@ private: CPluginInfoDatabase m_PluginInfo; Trie *m_LoadLookup; bool m_AllPluginsLoaded; + IdentityToken_t *m_MyIdent; }; extern CPluginManager g_PluginSys; diff --git a/core/systems/ShareSys.cpp b/core/systems/ShareSys.cpp new file mode 100644 index 00000000..073a5e6b --- /dev/null +++ b/core/systems/ShareSys.cpp @@ -0,0 +1,195 @@ +#include "ShareSys.h" +#include "HandleSys.h" + +ShareSystem g_ShareSys; + +ShareSystem::ShareSystem() +{ + m_IdentRoot.ident = 0; + m_TypeRoot = 0; + m_IfaceType = 0; + m_CoreType = 0; +} + +IdentityToken_t *ShareSystem::CreateCoreIdentity() +{ + if (!m_CoreType) + { + m_CoreType = CreateIdentType("CORE"); + } + + return CreateIdentity(m_CoreType); +} + +void ShareSystem::OnSourceModStartup(bool late) +{ + HandleSecurity sec; + + sec.owner = GetIdentRoot(); + sec.access[HandleAccess_Inherit] = false; + sec.access[HandleAccess_Delete] = false; + + m_TypeRoot = g_HandleSys.CreateTypeEx("Identity", this, 0, &sec, NULL); + m_IfaceType = g_HandleSys.CreateTypeEx("Interface", this, 0, &sec, NULL); + + /* Initialize our static identity handle */ + m_IdentRoot.ident = g_HandleSys.CreateHandle(m_TypeRoot, NULL, NULL, NULL); +} + +void ShareSystem::OnSourceModShutdown() +{ + if (m_CoreType) + { + g_HandleSys.RemoveType(m_CoreType, GetIdentRoot()); + } + + g_HandleSys.RemoveType(m_IfaceType, GetIdentRoot()); + g_HandleSys.RemoveType(m_TypeRoot, GetIdentRoot()); +} + +IdentityType_t ShareSystem::FindIdentType(const char *name) +{ + HandleType_t type; + + if (g_HandleSys.FindHandleType(name, &type)) + { + if (g_HandleSys.TypeCheck(type, m_TypeRoot)) + { + return type; + } + } + + return 0; +} + +IdentityType_t ShareSystem::CreateIdentType(const char *name) +{ + if (!m_TypeRoot) + { + return 0; + } + + return g_HandleSys.CreateTypeEx(name, this, m_TypeRoot, NULL, GetIdentRoot()); +} + +void ShareSystem::OnHandleDestroy(HandleType_t type, void *object) +{ + /* We don't care here */ +} + +IdentityToken_t *ShareSystem::CreateIdentity(IdentityType_t type) +{ + if (!m_TypeRoot) + { + return 0; + } + + /* :TODO: Cache? */ + IdentityToken_t *pToken = new IdentityToken_t; + pToken->ident = g_HandleSys.CreateHandle(type, NULL, NULL, GetIdentRoot()); + + return pToken; +} + +bool ShareSystem::AddInterface(SMInterface *iface, IdentityToken_t *token) +{ + if (!iface) + { + return false; + } + + IfaceInfo info; + + info.iface = iface; + info.token = token; + + if (token) + { + /* If we're an external object, we have to do this */ + info.handle = g_HandleSys.CreateHandle(m_IfaceType, iface, token, GetIdentRoot()); + } else { + info.handle = 0; + } + + m_Interfaces.push_back(info); + + return true; +} + +bool ShareSystem::RequestInterface(const char *iface_name, + unsigned int iface_vers, + IdentityToken_t *token, + SMInterface **pIface) +{ + /* If Some yahoo.... SOME HOOLIGAN... some NO GOOD DIRTY + * HORRIBLE PERSON passed in a token that we don't recognize.... + * Punish them. + */ + if (!g_HandleSys.ReadHandle(token->ident, m_TypeRoot, GetIdentRoot(), NULL)) + { + return false; + } + + /* See if the interface exists */ + List::iterator iter; + SMInterface *iface; + IdentityToken_t *iface_owner; + Handle_t iface_handle; + bool found = false; + for (iter=m_Interfaces.begin(); iter!=m_Interfaces.end(); iter++) + { + IfaceInfo &info = (*iter); + iface = info.iface; + if (strcmp(iface->GetInterfaceName(), iface_name) == 0) + { + if (iface->GetInterfaceVersion() == iface_vers + || iface->IsVersionCompatible(iface_vers)) + { + iface_owner = info.token; + iface_handle = info.handle; + found = true; + break; + } + } + } + + if (!found) + { + return false; + } + + /* If something external owns this, we need to track it. */ + if (iface_owner) + { + Handle_t newhandle; + if (g_HandleSys.CloneHandle(iface_handle, &newhandle, token, GetIdentRoot()) + != HandleError_None) + { + return false; + } + /** + * Now we can deny module loads based on dependencies. + */ + } + + /* :TODO: finish */ + + return NULL; +} + +void ShareSystem::AddNatives(IdentityToken_t *token, const sp_nativeinfo_t *natives[]) +{ + /* :TODO: implement */ +} + +void ShareSystem::DestroyIdentity(IdentityToken_t *identity) +{ + g_HandleSys.FreeHandle(identity->ident, GetIdentRoot()); + delete identity; +} + +void ShareSystem::DestroyIdentType(IdentityType_t type) +{ + g_HandleSys.RemoveType(type, GetIdentRoot()); +} + diff --git a/core/systems/ShareSys.h b/core/systems/ShareSys.h new file mode 100644 index 00000000..c8b8aecf --- /dev/null +++ b/core/systems/ShareSys.h @@ -0,0 +1,69 @@ +#ifndef _INCLUDE_SOURCEMOD_SHARESYSTEM_H_ +#define _INCLUDE_SOURCEMOD_SHARESYSTEM_H_ + +#include +#include +#include +#include "sm_globals.h" +#include "sourcemod.h" + +using namespace SourceHook; + +namespace SourceMod +{ + struct IdentityToken_t + { + Handle_t ident; + }; +}; + +struct IfaceInfo +{ + SMInterface *iface; + IdentityToken_t *token; + Handle_t handle; +}; + +class ShareSystem : + public IShareSys, + public SMGlobalClass, + public IHandleTypeDispatch +{ +public: + ShareSystem(); +public: //IShareSys + bool AddInterface(SMInterface *iface, IdentityToken_t *token); + bool RequestInterface(const char *iface_name, + unsigned int iface_vers, + IdentityToken_t *token, + SMInterface **pIface); + void AddNatives(IdentityToken_t *token, const sp_nativeinfo_t *natives[]); + IdentityType_t CreateIdentType(const char *name); + IdentityType_t FindIdentType(const char *name); + IdentityToken_t *CreateIdentity(IdentityType_t type); + void DestroyIdentType(IdentityType_t type); + void DestroyIdentity(IdentityToken_t *identity); +public: //SMGlobalClass + /* Pre-empt in case anything tries to register idents early */ + void OnSourceModStartup(bool late); + void OnSourceModShutdown(); +public: //IHandleTypeDispatch + void OnHandleDestroy(HandleType_t type, void *object); +public: + IdentityToken_t *CreateCoreIdentity(); +public: + inline IdentityToken_t *GetIdentRoot() + { + return &m_IdentRoot; + } +private: + List m_Interfaces; + HandleType_t m_TypeRoot; + IdentityToken_t m_IdentRoot; + HandleType_t m_IfaceType; + IdentityType_t m_CoreType; +}; + +extern ShareSystem g_ShareSys; + +#endif //_INCLUDE_SOURCEMOD_SHARESYSTEM_H_