From 4bd40d69e18b42035c8b5eaa9d472dfee9805a6f Mon Sep 17 00:00:00 2001 From: David Anderson Date: Thu, 4 Jan 2007 02:08:27 +0000 Subject: [PATCH] restructure of HandleSys admin permissions and interface removal of HandleSys helper functions removed useless BaseContext stuff from Engine put SourceMod specific stuff in BaseContext cleaned up broken Handle code --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40267 --- core/interfaces/IHandleSys.h | 181 +++++++++++---------- core/msvc8/sourcemod_mm.vcproj | 2 +- core/smn_filesystem.cpp | 19 ++- core/smn_handles.cpp | 7 +- core/systems/HandleSys.cpp | 278 +++++++++++++++++++++++---------- core/systems/HandleSys.h | 51 ++++-- core/systems/PluginSys.cpp | 34 ++-- core/systems/PluginSys.h | 3 +- core/systems/ShareSys.cpp | 37 +++-- core/vm/sp_vm_basecontext.cpp | 16 +- core/vm/sp_vm_basecontext.h | 7 + plugins/test.sma | 9 +- sourcepawn/include/sp_vm_api.h | 32 ++-- 13 files changed, 436 insertions(+), 240 deletions(-) diff --git a/core/interfaces/IHandleSys.h b/core/interfaces/IHandleSys.h index b0d71a38..6f105f1c 100644 --- a/core/interfaces/IHandleSys.h +++ b/core/interfaces/IHandleSys.h @@ -43,34 +43,72 @@ namespace SourceMod HandleError_Limit, /* The limited number of handles has been reached */ HandleError_Identity, /* The identity token was not usable */ HandleError_Owner, /* Owners do not match for this operation */ + HandleError_Version, /* Unrecognized security structure version */ + HandleError_Parameter, /* An invalid parameter was passed */ + HandleError_NoInherit, /* This type cannot be inherited */ }; + /** + * Access rights specific to a type + */ + enum HTypeAccessRight + { + HTypeAccess_Create = 0, /* Handles of this type can be created (DEFAULT=false) */ + HTypeAccess_Inherit, /* Sub-types can inherit this type (DEFAULT=false) */ + /* -------------- */ + HTypeAccess_TOTAL, /* Total number of type access rights */ + }; + + /** + * Access rights specific to a Handle. These rights are exclusive. + * For example, you do not need "read" access to delete or clone. + */ enum HandleAccessRight { - HandleAccess_Create, /* TYPE: Instances can be created by other objects (this makes it searchable) */ - HandleAccess_Read, /* HANDLES: Can be read by other objects */ - HandleAccess_IdentDelete, /* HANDLES: Can be deleted by other identities */ - HandleAccess_OwnerDelete, /* HANDLES: Can be deleted by other owners */ - HandleAccess_Inherit, /* TYPE: Can be inherited by new types */ - HandleAccess_Clone, /* HANDLES: Can be cloned */ + HandleAccess_Read, /* Can be read (DEFAULT=ident only) */ + HandleAccess_Delete, /* Can be deleted (DEFAULT=owner only) */ + HandleAccess_Clone, /* Can be cloned (DEFAULT=any) */ /* ------------- */ HandleAccess_TOTAL, /* Total number of access rights */ }; + #define HANDLE_RESTRICT_IDENTITY (1<<0) /* Access is restricted to the identity */ + #define HANDLE_RESTRICT_OWNER (1<<1) /* Access is restricted to the owner */ + + /** + * This is used to define per-type access rights. + */ + struct TypeAccess + { + TypeAccess() + { + hsVersion = SMINTERFACE_HANDLESYSTEM_VERSION; + } + unsigned int hsVersion; + IdentityToken_t *ident; + bool access[HTypeAccess_TOTAL]; + }; + + /** + * This is used to define per-Handle access rights. + */ + struct HandleAccess + { + HandleAccess() + { + hsVersion = SMINTERFACE_HANDLESYSTEM_VERSION; + } + unsigned int hsVersion; + unsigned int access[HandleAccess_TOTAL]; + }; + + /** + * This pair of tokens is used for identification. + */ struct HandleSecurity { - HandleSecurity() - { - owner = NULL; - access[HandleAccess_Create] = true; - access[HandleAccess_Read] = true; - access[HandleAccess_IdentDelete] = true; - access[HandleAccess_Inherit] = true; - access[HandleAccess_Clone] = true; - access[HandleAccess_OwnerDelete] = false; - } - IdentityToken_t *owner; /* Owner of the handle */ - bool access[HandleAccess_TOTAL]; /* World access rights */ + IdentityToken_t *pOwner; /* Owner of the Handle */ + IdentityToken_t *pIdentity; /* Owner of the Type */ }; class IHandleTypeDispatch @@ -99,17 +137,6 @@ namespace SourceMod return SMINTERFACE_HANDLESYSTEM_NAME; } public: - /** - * @brief Creates a new Handle type. - * NOTE: Handle names must be unique if not private. - * - * @param name Name of handle type (NULL or "" to be anonymous) - * @param dispatch Pointer to a valid IHandleTypeDispatch object. - * @return A new HandleType_t unique ID, or 0 on failure. - */ - virtual HandleType_t CreateType(const char *name, - IHandleTypeDispatch *dispatch) =0; - /** * @brief Creates a new Handle type. * NOTE: Currently, a child type may not have its own children. @@ -118,39 +145,30 @@ namespace SourceMod * @param name Name of handle type (NULL or "" to be anonymous) * @param dispatch Pointer to a valid IHandleTypeDispatch object. * @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. + * @param typeAccess Pointer to a TypeAccess object, NULL to use default + * or inherited permissions. Pointer can be temporary. + * @param hndlAccess Pointer to a HandleAccess object to define default + * default permissions on each Handle. NULL to use default + * permissions. + * @param ident Security token for any permissions. If typeAccess is NULL, this + * becomes the owning identity. + * @param err Optional pointer to store an error code. * @return A new HandleType_t unique ID, or 0 on failure. */ - virtual HandleType_t CreateTypeEx(const char *name, + virtual HandleType_t CreateType(const char *name, IHandleTypeDispatch *dispatch, HandleType_t parent, - const HandleSecurity *security, - IdentityToken_t *ident) =0; - - - /** - * @brief Creates a sub-type for a Handle. - * NOTE: Currently, a child type may not have its own children. - * NOTE: Handle names must be unique if not private. - * NOTE: This is a wrapper around the above. - * - * @param name Name of a handle. - * @param parent Parent handle type. - * @param dispatch Pointer to a valid IHandleTypeDispatch object. - * @return A new HandleType_t unique ID. - */ - virtual HandleType_t CreateChildType(const char *name, - HandleType_t parent, - IHandleTypeDispatch *dispatch) =0; + const TypeAccess *typeAccess, + const HandleAccess *hndlAccess, + IdentityToken_t *ident, + HandleError *err) =0; /** * @brief Removes a handle type. * NOTE: This removes all child types. * - * @param token Identity token. Removal fails if the token does not match. * @param type Type chain to remove. + * @param ident Identity token. Removal fails if the token does not match. * @return True on success, false on failure. */ virtual bool RemoveType(HandleType_t type, IdentityToken_t *ident) =0; @@ -169,29 +187,16 @@ namespace SourceMod * * @param type Type to use on the handle. * @param object Object to bind to the handle. - * @param owner Owner for the handle. NULL means anonymous (no owner). - * @param ident Identity token if any security rights are needed. + * @param owner Owner of the new Handle (may be NULL). + * @param ident Identity for type access if needed (may be NULL). + * @param err Optional pointer to store an error code. * @return A new Handle_t, or 0 on failure. */ virtual Handle_t CreateHandle(HandleType_t type, - void *object, - IdentityToken_t *owner, - IdentityToken_t *ident) =0; - - /** - * @brief Creates a new handle. - * NOTE: This is a wrapper around the above function. - * - * @param type Type to use on the handle. - * @param object Object to bind to the handle. - * @param pOwner Plugin context that will own this handle. NULL for none. - * @param ident Identity token if any security rights are needed. - * @return A new Handle_t. - */ - virtual Handle_t CreateScriptHandle(HandleType_t type, - void *object, - SourcePawn::IPluginContext *pOwner, - IdentityToken_t *ident) =0; + void *object, + IdentityToken_t *owner, + IdentityToken_t *ident, + HandleError *err) =0; /** * @brief Frees the memory associated with a handle and calls any destructors. @@ -199,34 +204,48 @@ namespace SourceMod * only perform any further action if the counter hits 0. * * @param type Handle_t identifier to destroy. - * @param owner Owner of handle (NULL for none). - * @param ident Identity token, for destroying secure handles (NULL for none). + * @param pSecurity Security information struct (may be NULL). * @return A HandleError error code. */ - virtual HandleError FreeHandle(Handle_t handle, IdentityToken_t *owner, IdentityToken_t *ident) =0; + virtual HandleError FreeHandle(Handle_t handle, const HandleSecurity *pSecurity) =0; /** * @brief Clones a handle by adding to its internal reference count. Its data, * type, and security permissions remain the same. * * @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 owner New owner of cloned handle. - * @param ident Security token, if needed. + * @param newhandle Stores the duplicated handle in the pointer (must not be NULL). + * @param newOwner New owner of cloned handle. + * @param pSecurity Security information struct (may be NULL). * @return A HandleError error code. */ - virtual HandleError CloneHandle(Handle_t handle, Handle_t *newhandle, IdentityToken_t *owner, IdentityToken_t *ident) =0; + virtual HandleError CloneHandle(Handle_t handle, + Handle_t *newhandle, + IdentityToken_t *newOwner, + const HandleSecurity *pSecurity) =0; /** * @brief Retrieves the contents of a handle. * * @param handle Handle_t from which to retrieve contents. * @param type Expected type to read as. 0 ignores typing rules. - * @param ident Identity token to validate as. + * @param pSecurity Security information struct (may be NULL). * @param object Optional 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, + const HandleSecurity *pSecurity, + void **object) =0; + + /** + * @brief Sets access permissions on one or more structures. + * + * @param pTypeAccess Optional TypeAccess buffer to initialize with the default values. + * @param pHandleAccess Optional HandleAccess buffer to initialize with the default values. + * @return True on success, false if version is unsupported. + */ + virtual bool InitAccessDefaults(TypeAccess *pTypeAccess, HandleAccess *pHandleAccess) =0; }; }; diff --git a/core/msvc8/sourcemod_mm.vcproj b/core/msvc8/sourcemod_mm.vcproj index a88b4467..ddef6937 100644 --- a/core/msvc8/sourcemod_mm.vcproj +++ b/core/msvc8/sourcemod_mm.vcproj @@ -41,7 +41,7 @@ Name="VCCLCompilerTool" Optimization="0" AdditionalIncludeDirectories="..\interfaces;..\;..\systems;..\..\sourcepawn\include" - PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;SOURCEMOD_MM_EXPORTS;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE" + PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;SOURCEMOD_MM_EXPORTS;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;SOURCEMOD_BUILD" MinimalRebuild="true" BasicRuntimeChecks="3" RuntimeLibrary="1" diff --git a/core/smn_filesystem.cpp b/core/smn_filesystem.cpp index 773c340f..75db63f2 100644 --- a/core/smn_filesystem.cpp +++ b/core/smn_filesystem.cpp @@ -12,13 +12,8 @@ class FileNatives : public: virtual void OnSourceModAllInitialized() { - HandleSecurity sec; - sec.owner = g_pCoreIdent; - sec.access[HandleAccess_Inherit] = false; - sec.access[HandleAccess_Create] = false; - - g_FileType = g_HandleSys.CreateTypeEx("File", this, 0, &sec, NULL); - g_DirType = g_HandleSys.CreateTypeEx("Directory", this, 0, &sec, NULL); + g_FileType = g_HandleSys.CreateType("File", this, 0, NULL, NULL, g_pCoreIdent, NULL); + g_DirType = g_HandleSys.CreateType("Directory", this, 0, NULL, NULL, g_pCoreIdent, NULL); } virtual void OnSourceModShutdown() { @@ -60,17 +55,21 @@ cell_t sm_OpenDirectory(IPluginContext *pContext, const cell_t *params) return 0; } - return g_HandleSys.CreateScriptHandle(g_DirType, pDir, pContext, g_pCoreIdent); + return g_HandleSys.CreateHandle(g_DirType, pDir, pContext->GetIdentity(), g_pCoreIdent, NULL); } cell_t sm_ReadDirEntry(IPluginContext *pContext, const cell_t *params) { Handle_t hndl = static_cast(params[1]); - IDirectory *pDir; HandleError herr; + HandleSecurity sec; int err; - if ((herr=g_HandleSys.ReadHandle(hndl, g_DirType, g_pCoreIdent, (void **)&pDir)) + + sec.pOwner = NULL; + sec.pIdentity = g_pCoreIdent; + + if ((herr=g_HandleSys.ReadHandle(hndl, g_DirType, &sec, (void **)&pDir)) != HandleError_None) { return pContext->ThrowNativeError("Invalid file handle %x (error %d)", hndl, herr); diff --git a/core/smn_handles.cpp b/core/smn_handles.cpp index 5f3e7b88..9d0105d9 100644 --- a/core/smn_handles.cpp +++ b/core/smn_handles.cpp @@ -24,7 +24,12 @@ static cell_t sm_CloseHandle(IPluginContext *pContext, const cell_t *params) /* :TODO: make this a little bit cleaner, eh? */ IPlugin *pPlugin = g_PluginSys.FindPluginByContext(pContext->GetContext()); - HandleError err = g_HandleSys.FreeHandle(hndl, pPlugin->GetIdentity(), NULL); + HandleSecurity sec; + + sec.pIdentity = NULL; + sec.pOwner = pContext->GetIdentity(); + + HandleError err = g_HandleSys.FreeHandle(hndl, &sec); if (err == HandleError_None) { diff --git a/core/systems/HandleSys.cpp b/core/systems/HandleSys.cpp index 90034a97..4c25ca7b 100644 --- a/core/systems/HandleSys.cpp +++ b/core/systems/HandleSys.cpp @@ -14,7 +14,7 @@ inline HandleType_t TypeParent(HandleType_t type) inline HandleError IdentityHandle(IdentityToken_t *token, unsigned int *index) { - return g_HandleSys.GetHandle(token->ident, g_ShareSys.GetIdentRoot(), &ignore_handle, index, HandleAccess_Read); + return g_HandleSys.GetHandle(token->ident, g_ShareSys.GetIdentRoot(), &ignore_handle, index); } HandleSystem::HandleSystem() @@ -39,24 +39,39 @@ HandleSystem::~HandleSystem() delete m_strtab; } -HandleType_t HandleSystem::CreateType(const char *name, IHandleTypeDispatch *dispatch) -{ - 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, NULL); -} - -HandleType_t HandleSystem::CreateTypeEx(const char *name, - IHandleTypeDispatch *dispatch, - HandleType_t parent, - const HandleSecurity *security, - IdentityToken_t *ident) +HandleType_t HandleSystem::CreateType(const char *name, + IHandleTypeDispatch *dispatch, + HandleType_t parent, + const TypeAccess *typeAccess, + const HandleAccess *hndlAccess, + IdentityToken_t *ident, + HandleError *err) { if (!dispatch) { + if (err) + { + *err = HandleError_Parameter; + } + return 0; + } + + if (typeAccess && typeAccess->hsVersion > SMINTERFACE_HANDLESYSTEM_VERSION) + { + if (err) + { + *err = HandleError_Version; + } + return 0; + } + + if (hndlAccess && hndlAccess->hsVersion > SMINTERFACE_HANDLESYSTEM_VERSION) + { + if (err) + { + *err = HandleError_Version; + } return 0; } @@ -67,34 +82,44 @@ HandleType_t HandleSystem::CreateTypeEx(const char *name, isChild = true; if (parent & HANDLESYS_SUBTYPE_MASK) { + if (err) + { + *err = HandleError_NoInherit; + } return 0; } if (parent >= HANDLESYS_TYPEARRAY_SIZE - || m_Types[parent].dispatch == NULL - || (m_Types[parent].sec.access[HandleAccess_Inherit] == false - && m_Types[parent].sec.owner != ident)) + || m_Types[parent].dispatch == NULL) { + if (err) + { + *err = HandleError_Parameter; + } + return 0; + } + if (m_Types[parent].typeSec.access[HTypeAccess_Inherit] == false + && (m_Types[parent].typeSec.ident != ident)) + { + if (err) + { + *err = HandleError_Access; + } return 0; } } - if (!security) + if (name && name[0] != '\0') { - if (isChild) + if (sm_trie_retrieve(m_TypeLookup, name, NULL)) { - security = &m_Types[parent].sec; - } else { - static HandleSecurity def_h; - security = &def_h; + if (err) + { + *err = HandleError_Parameter; + } + return 0; } } - if (security->access[HandleAccess_Create] - && sm_trie_retrieve(m_TypeLookup, name, NULL)) - { - return 0; - } - unsigned int index; if (isChild) @@ -102,6 +127,10 @@ HandleType_t HandleSystem::CreateTypeEx(const char *name, QHandleType *pParent = &m_Types[parent]; if (pParent->children >= HANDLESYS_MAX_SUBTYPES) { + if (err) + { + *err = HandleError_Limit; + } return 0; } index = 0; @@ -115,6 +144,10 @@ HandleType_t HandleSystem::CreateTypeEx(const char *name, } if (!index) { + if (err) + { + *err = HandleError_Limit; + } return 0; } pParent->children++; @@ -124,6 +157,10 @@ HandleType_t HandleSystem::CreateTypeEx(const char *name, /* Reserve another index */ if (m_TypeTail >= HANDLESYS_TYPEARRAY_SIZE) { + if (err) + { + *err = HandleError_Limit; + } return 0; } else { m_TypeTail += (HANDLESYS_MAX_SUBTYPES + 1); @@ -145,9 +182,24 @@ HandleType_t HandleSystem::CreateTypeEx(const char *name, } else { pType->nameIdx = -1; } - pType->sec = *security; + pType->opened = 0; + if (typeAccess) + { + pType->typeSec = *typeAccess; + } else { + InitAccessDefaults(&pType->typeSec, NULL); + pType->typeSec.ident = ident; + } + + if (hndlAccess) + { + pType->hndlSec = *hndlAccess; + } else { + InitAccessDefaults(NULL, &pType->hndlSec); + } + if (!isChild) { pType->children = 0; @@ -264,33 +316,46 @@ void HandleSystem::SetTypeSecurityOwner(HandleType_t type, IdentityToken_t *pTok return; } - m_Types[type].sec.owner = pToken; + m_Types[type].typeSec.ident = pToken; } -Handle_t HandleSystem::CreateHandle(HandleType_t type, void *object, IdentityToken_t *source, IdentityToken_t *ident) +Handle_t HandleSystem::CreateHandle(HandleType_t type, void *object, IdentityToken_t *owner, IdentityToken_t *ident, HandleError *err) { if (!type || type >= HANDLESYS_TYPEARRAY_SIZE || m_Types[type].dispatch == NULL) { + if (err) + { + *err = HandleError_Parameter; + } return 0; } - /* Check the security of this handle */ + /* Check to see if we're allowed to create this handle type */ QHandleType *pType = &m_Types[type]; - if (!pType->sec.access[HandleAccess_Create] - && pType->sec.owner != ident) + if (!pType->typeSec.access[HTypeAccess_Create] + && (!pType->typeSec.ident + || pType->typeSec.ident != ident)) { + if (err) + { + *err = HandleError_Access; + } return 0; } unsigned int index; Handle_t handle; QHandle *pHandle; - HandleError err; + HandleError _err; - if ((err=MakePrimHandle(type, &pHandle, &index, &handle, source)) != HandleError_None) + if ((_err=MakePrimHandle(type, &pHandle, &index, &handle, owner)) != HandleError_None) { + if (err) + { + *err = _err; + } return 0; } @@ -300,16 +365,6 @@ Handle_t HandleSystem::CreateHandle(HandleType_t type, void *object, IdentityTok return handle; } -Handle_t HandleSystem::CreateScriptHandle(HandleType_t type, - void *object, - IPluginContext *pContext, - IdentityToken_t *ident) -{ - IPlugin *pPlugin = g_PluginSys.FindPluginByContext(pContext->GetContext()); - - return CreateHandle(type, object, pPlugin->GetIdentity(), ident); -} - bool HandleSystem::TypeCheck(HandleType_t intype, HandleType_t outtype) { /* Check the type inheritance */ @@ -334,7 +389,6 @@ HandleError HandleSystem::GetHandle(Handle_t handle, IdentityToken_t *ident, QHandle **in_pHandle, unsigned int *in_index, - HandleAccessRight access, bool ignoreFree) { unsigned int serial = (handle >> 16); @@ -348,11 +402,6 @@ HandleError HandleSystem::GetHandle(Handle_t handle, QHandle *pHandle = &m_Handles[index]; QHandleType *pType = &m_Types[pHandle->type]; - if ((access != HandleAccess_TOTAL) - && (!pType->sec.access[access] && pType->sec.owner != ident)) - { - return HandleError_Access; - } if (!pHandle->set || (pHandle->set == HandleSet_Freed && !ignoreFree)) { @@ -374,13 +423,44 @@ 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) +bool HandleSystem::CheckAccess(QHandle *pHandle, HandleAccessRight right, const HandleSecurity *pSecurity) +{ + QHandleType *pType = &m_Types[pHandle->type]; + unsigned int access = pType->hndlSec.access[right]; + + /* Check if the type's identity matches */ + if (access & HANDLE_RESTRICT_IDENTITY) + { + IdentityToken_t *owner = pType->typeSec.ident; + if (!owner + || (!pSecurity || pSecurity->pIdentity != owner)) + { + return false; + } + } + + /* Check if the owner is allowed */ + if (access & HANDLE_RESTRICT_OWNER) + { + IdentityToken_t *owner = pHandle->owner; + if (owner + && (!pSecurity || pSecurity->pOwner != owner)) + { + return false; + } + } + + return true; +} + +HandleError HandleSystem::CloneHandle(Handle_t handle, Handle_t *newhandle, IdentityToken_t *newOwner, const HandleSecurity *pSecurity) { HandleError err; QHandle *pHandle; unsigned int index; + IdentityToken_t *ident = pSecurity ? pSecurity->pIdentity : NULL; - if ((err=GetHandle(handle, ident, &pHandle, &index, HandleAccess_Clone)) != HandleError_None) + if ((err=GetHandle(handle, ident, &pHandle, &index)) != HandleError_None) { return err; } @@ -391,49 +471,49 @@ HandleError HandleSystem::CloneHandle(Handle_t handle, Handle_t *out_newhandle, return HandleError_Identity; } - QHandleType *pType = &m_Types[pHandle->type]; + /* Check if the handle can be cloned */ + if (!CheckAccess(pHandle, HandleAccess_Clone, pSecurity)) + { + return HandleError_Access; + } /* Get a new Handle ID */ unsigned int new_index; QHandle *pNewHandle; Handle_t new_handle; - if ((err=MakePrimHandle(pHandle->type, &pNewHandle, &new_index, &new_handle, source)) != HandleError_None) + if ((err=MakePrimHandle(pHandle->type, &pNewHandle, &new_index, &new_handle, newOwner)) != HandleError_None) { return err; } - pNewHandle->clone = handle; + pNewHandle->clone = index; pHandle->refcount++; - if (out_newhandle) - { - *out_newhandle = new_handle; - } + *newhandle = new_handle; return HandleError_None; } -HandleError HandleSystem::FreeHandle(Handle_t handle, IdentityToken_t *pOwner, IdentityToken_t *ident) +HandleError HandleSystem::FreeHandle(Handle_t handle, const HandleSecurity *pSecurity) { unsigned int index; QHandle *pHandle; HandleError err; + IdentityToken_t *ident = pSecurity ? pSecurity->pIdentity : NULL; - if ((err=GetHandle(handle, ident, &pHandle, &index, HandleAccess_IdentDelete)) != HandleError_None) + if ((err=GetHandle(handle, ident, &pHandle, &index)) != HandleError_None) { return err; } - QHandleType *pType = &m_Types[pHandle->type]; - - if (pType->sec.access[HandleAccess_OwnerDelete] == false - && pHandle->owner - && pHandle->owner != pOwner) + if (!CheckAccess(pHandle, HandleAccess_Delete, pSecurity)) { return HandleError_Access; } + QHandleType *pType = &m_Types[pHandle->type]; + bool dofree = false; if (pHandle->clone) { @@ -441,9 +521,10 @@ HandleError HandleSystem::FreeHandle(Handle_t handle, IdentityToken_t *pOwner, I QHandle *pMaster; unsigned int master; - /* This call should not return an error, it'd be a corruption sign */ - err = GetHandle(pHandle->clone, ident, &pMaster, &master, HandleAccess_IdentDelete, true); - assert(err == HandleError_None); + /* Note that if we ever have per-handle security, we would need to re-check + * the access on this Handle. */ + master = pHandle->clone; + pMaster = &m_Handles[master]; /* Release the clone now */ ReleasePrimHandle(index); @@ -471,20 +552,23 @@ HandleError HandleSystem::FreeHandle(Handle_t handle, IdentityToken_t *pOwner, I return HandleError_None; } -HandleError HandleSystem::ReadHandle(Handle_t handle, - HandleType_t type, - IdentityToken_t *ident, - void **object) +HandleError HandleSystem::ReadHandle(Handle_t handle, HandleType_t type, const HandleSecurity *pSecurity, void **object) { unsigned int index; QHandle *pHandle; HandleError err; + IdentityToken_t *ident = pSecurity ? pSecurity->pIdentity : NULL; - if ((err=GetHandle(handle, ident, &pHandle, &index, HandleAccess_Read)) != HandleError_None) + if ((err=GetHandle(handle, ident, &pHandle, &index)) != HandleError_None) { return err; } + if (!CheckAccess(pHandle, HandleAccess_Read, pSecurity)) + { + return HandleError_Access; + } + /* Check the type inheritance */ if (pHandle->type & HANDLESYS_SUBTYPE_MASK) { @@ -505,8 +589,7 @@ HandleError HandleSystem::ReadHandle(Handle_t handle, /* if we're a clone, the rules change - object is ONLY in our reference */ if (pHandle->clone) { - /* :TODO: optimize this */ - return ReadHandle(pHandle->clone, pHandle->type, ident, object); + pHandle = &m_Handles[pHandle->clone]; } *object = pHandle->object; } @@ -579,7 +662,8 @@ bool HandleSystem::RemoveType(HandleType_t type, IdentityToken_t *ident) QHandleType *pType = &m_Types[type]; - if (pType->sec.owner && pType->sec.owner != ident) + if (pType->typeSec.ident + && pType->typeSec.ident != ident) { return false; } @@ -598,7 +682,7 @@ bool HandleSystem::RemoveType(HandleType_t type, IdentityToken_t *ident) childType = &m_Types[type + i]; if (childType->dispatch) { - RemoveType(type + i, childType->sec.owner); + RemoveType(type + i, childType->typeSec.ident); } } /* Link us into the free chain */ @@ -658,10 +742,38 @@ void HandleSystem::MarkHandleAsIdentity(Handle_t handle) QHandle *pHandle; unsigned int index; - if (GetHandle(handle, g_ShareSys.GetIdentRoot(), &pHandle, &index, HandleAccess_Read) != HandleError_None) + if (GetHandle(handle, g_ShareSys.GetIdentRoot(), &pHandle, &index) != HandleError_None) { return; } pHandle->set = HandleSet_Identity; } + +bool HandleSystem::InitAccessDefaults(TypeAccess *pTypeAccess, HandleAccess *pHandleAccess) +{ + if (pTypeAccess) + { + if (pTypeAccess->hsVersion > SMINTERFACE_HANDLESYSTEM_VERSION) + { + return false; + } + pTypeAccess->access[HTypeAccess_Create] = false; + pTypeAccess->access[HTypeAccess_Inherit] = false; + pTypeAccess->ident = NULL; + } + + if (pHandleAccess) + { + if (pHandleAccess->hsVersion > SMINTERFACE_HANDLESYSTEM_VERSION) + { + return false; + } + + pHandleAccess->access[HandleAccess_Clone] = 0; + pHandleAccess->access[HandleAccess_Delete] = HANDLE_RESTRICT_OWNER; + pHandleAccess->access[HandleAccess_Read] = HANDLE_RESTRICT_IDENTITY; + } + + return true; +} diff --git a/core/systems/HandleSys.h b/core/systems/HandleSys.h index 5f23cdf1..55c65dc4 100644 --- a/core/systems/HandleSys.h +++ b/core/systems/HandleSys.h @@ -48,7 +48,7 @@ struct QHandle 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 */ + unsigned int clone; /* If non-zero, this is our cloned parent index */ 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 */ @@ -64,7 +64,8 @@ struct QHandleType IHandleTypeDispatch *dispatch; unsigned int freeID; unsigned int children; - HandleSecurity sec; + TypeAccess typeSec; + HandleAccess hndlSec; unsigned int opened; int nameIdx; }; @@ -78,23 +79,38 @@ public: HandleSystem(); ~HandleSystem(); public: //IHandleSystem - HandleType_t CreateType(const char *name, IHandleTypeDispatch *dispatch); - HandleType_t CreateTypeEx(const char *name, - IHandleTypeDispatch *dispatch, - HandleType_t parent, - const HandleSecurity *security, - IdentityToken_t *ident); - HandleType_t CreateChildType(const char *name, HandleType_t parent, IHandleTypeDispatch *dispatch); + + HandleType_t CreateType(const char *name, + IHandleTypeDispatch *dispatch, + HandleType_t parent, + const TypeAccess *typeAccess, + const HandleAccess *hndlAccess, + IdentityToken_t *ident, + HandleError *err); + 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, IPluginContext *pContext, IdentityToken_t *ident); - HandleError FreeHandle(Handle_t handle, IdentityToken_t *owner, 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); + void *object, + IdentityToken_t *owner, + IdentityToken_t *ident, + HandleError *err); + HandleError FreeHandle(Handle_t handle, const HandleSecurity *pSecurity); + + HandleError CloneHandle(Handle_t handle, + Handle_t *newhandle, + IdentityToken_t *newOwner, + const HandleSecurity *pSecurity); + + HandleError ReadHandle(Handle_t handle, + HandleType_t type, + const HandleSecurity *pSecurity, + void **object); + + bool InitAccessDefaults(TypeAccess *pTypeAccess, HandleAccess *pHandleAccess); + bool TypeCheck(HandleType_t intype, HandleType_t outtype); protected: /** @@ -104,7 +120,6 @@ protected: IdentityToken_t *ident, QHandle **pHandle, unsigned int *index, - HandleAccessRight access, bool ignoreFree=false); /** @@ -133,6 +148,8 @@ protected: * This prevents it from being tampered with by outside stuff */ void MarkHandleAsIdentity(Handle_t handle); + + bool CheckAccess(QHandle *pHandle, HandleAccessRight right, const HandleSecurity *pSecurity); private: QHandle *m_Handles; QHandleType *m_Types; diff --git a/core/systems/PluginSys.cpp b/core/systems/PluginSys.cpp index 71d8f0d3..01a5db4a 100644 --- a/core/systems/PluginSys.cpp +++ b/core/systems/PluginSys.cpp @@ -32,7 +32,7 @@ CPlugin::~CPlugin() { if (m_ctx.base) { - g_pSourcePawn->FreeBaseContext(m_ctx.base); + delete m_ctx.base; m_ctx.base = NULL; } if (m_ctx.ctx) @@ -74,7 +74,11 @@ CPlugin::~CPlugin() if (m_handle) { - g_HandleSys.FreeHandle(m_handle, g_PluginSys.GetIdentity(), g_PluginSys.GetIdentity()); + HandleSecurity sec; + sec.pOwner = g_PluginSys.GetIdentity(); + sec.pIdentity = sec.pOwner; + + g_HandleSys.FreeHandle(m_handle, &sec); g_ShareSys.DestroyIdentity(m_ident); } } @@ -84,7 +88,8 @@ 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()); + m_handle = g_HandleSys.CreateHandle(g_PluginType, this, g_PluginSys.GetIdentity(), g_PluginSys.GetIdentity(), NULL); + m_ctx.base->SetIdentity(m_ident); } } @@ -188,7 +193,7 @@ bool CPlugin::FinishMyCompile(char *error, size_t maxlength) return false; } - m_ctx.base = g_pSourcePawn->CreateBaseContext(m_ctx.ctx); + m_ctx.base = new BaseContext(m_ctx.ctx); m_ctx.ctx->user[SM_CONTEXTVAR_MYSELF] = (void *)this; m_funcsnum = m_ctx.vm->FunctionCount(m_ctx.ctx); @@ -1113,15 +1118,13 @@ void CPluginManager::OnSourceModAllInitialized() { m_MyIdent = g_ShareSys.CreateCoreIdentity(); - HandleSecurity sec; + HandleAccess sec; + g_HandleSys.InitAccessDefaults(NULL, &sec); - sec.owner = m_MyIdent; /* :TODO: implement ShareSys */ - sec.access[HandleAccess_Create] = false; - sec.access[HandleAccess_IdentDelete] = false; - sec.access[HandleAccess_Inherit] = false; - sec.access[HandleAccess_Clone] = false; - - g_PluginType = g_HandleSys.CreateTypeEx("IPlugin", this, 0, &sec, NULL); + sec.access[HandleAccess_Delete] = HANDLE_RESTRICT_IDENTITY; + sec.access[HandleAccess_Clone] = HANDLE_RESTRICT_IDENTITY; + + g_PluginType = g_HandleSys.CreateType("Plugin", this, 0, NULL, &sec, m_MyIdent, NULL); g_PluginIdent = g_ShareSys.CreateIdentType("PLUGIN"); } @@ -1147,7 +1150,12 @@ IPlugin *CPluginManager::PluginFromHandle(Handle_t handle, HandleError *err) IPlugin *pPlugin; HandleError _err; - if ((_err=g_HandleSys.ReadHandle(handle, g_PluginType, m_MyIdent, (void **)&pPlugin)) != HandleError_None) + HandleSecurity sec; + + sec.pOwner = NULL; + sec.pIdentity = m_MyIdent; + + if ((_err=g_HandleSys.ReadHandle(handle, g_PluginType, &sec, (void **)&pPlugin)) != HandleError_None) { pPlugin = NULL; } diff --git a/core/systems/PluginSys.h b/core/systems/PluginSys.h index 904cd127..4f682973 100644 --- a/core/systems/PluginSys.h +++ b/core/systems/PluginSys.h @@ -7,6 +7,7 @@ #include #include #include "sm_globals.h" +#include "vm/sp_vm_basecontext.h" #include "CFunction.h" #include "PluginInfoDatabase.h" #include "sm_trie.h" @@ -67,7 +68,7 @@ struct ContextPair ContextPair() : base(NULL), ctx(NULL), co(NULL) { }; - IPluginContext *base; + BaseContext *base; sp_context_t *ctx; ICompilation *co; IVirtualMachine *vm; diff --git a/core/systems/ShareSys.cpp b/core/systems/ShareSys.cpp index 049ca6a2..784a69db 100644 --- a/core/systems/ShareSys.cpp +++ b/core/systems/ShareSys.cpp @@ -23,17 +23,16 @@ IdentityToken_t *ShareSystem::CreateCoreIdentity() void ShareSystem::OnSourceModStartup(bool late) { - HandleSecurity sec; + TypeAccess sec; - sec.owner = GetIdentRoot(); - sec.access[HandleAccess_Inherit] = false; - sec.access[HandleAccess_IdentDelete] = false; - - m_TypeRoot = g_HandleSys.CreateTypeEx("Identity", this, 0, &sec, NULL); - m_IfaceType = g_HandleSys.CreateTypeEx("Interface", this, 0, &sec, NULL); + g_HandleSys.InitAccessDefaults(&sec, NULL); + sec.ident = GetIdentRoot(); + + m_TypeRoot = g_HandleSys.CreateType("Identity", this, 0, &sec, NULL, NULL, NULL); + m_IfaceType = g_HandleSys.CreateType("Interface", this, 0, NULL, NULL, GetIdentRoot(), NULL); /* Initialize our static identity handle */ - m_IdentRoot.ident = g_HandleSys.CreateHandle(m_TypeRoot, NULL, NULL, NULL); + m_IdentRoot.ident = g_HandleSys.CreateHandle(m_TypeRoot, NULL, NULL, GetIdentRoot(), NULL); } void ShareSystem::OnSourceModShutdown() @@ -69,7 +68,7 @@ IdentityType_t ShareSystem::CreateIdentType(const char *name) return 0; } - return g_HandleSys.CreateTypeEx(name, this, m_TypeRoot, NULL, GetIdentRoot()); + return g_HandleSys.CreateType(name, this, m_TypeRoot, NULL, NULL, GetIdentRoot(), NULL); } void ShareSystem::OnHandleDestroy(HandleType_t type, void *object) @@ -86,7 +85,7 @@ IdentityToken_t *ShareSystem::CreateIdentity(IdentityType_t type) /* :TODO: Cache? */ IdentityToken_t *pToken = new IdentityToken_t; - pToken->ident = g_HandleSys.CreateHandle(type, NULL, NULL, GetIdentRoot()); + pToken->ident = g_HandleSys.CreateHandle(type, NULL, GetIdentRoot(), GetIdentRoot(), NULL); return pToken; } @@ -106,7 +105,7 @@ bool ShareSystem::AddInterface(SMInterface *iface, IdentityToken_t *token) if (token) { /* If we're an external object, we have to do this */ - info.handle = g_HandleSys.CreateHandle(m_IfaceType, iface, token, GetIdentRoot()); + info.handle = g_HandleSys.CreateHandle(m_IfaceType, iface, token, GetIdentRoot(), NULL); } else { info.handle = 0; } @@ -125,7 +124,12 @@ bool ShareSystem::RequestInterface(const char *iface_name, * HORRIBLE PERSON passed in a token that we don't recognize.... * Punish them. */ - if (!g_HandleSys.ReadHandle(token->ident, m_TypeRoot, GetIdentRoot(), NULL)) + HandleSecurity sec; + + sec.pIdentity = GetIdentRoot(); + sec.pOwner = NULL; + + if (!g_HandleSys.ReadHandle(token->ident, m_TypeRoot, &sec, NULL)) { return false; } @@ -162,7 +166,7 @@ bool ShareSystem::RequestInterface(const char *iface_name, if (iface_owner) { Handle_t newhandle; - if (g_HandleSys.CloneHandle(iface_handle, &newhandle, token, GetIdentRoot()) + if (g_HandleSys.CloneHandle(iface_handle, &newhandle, token, &sec) != HandleError_None) { return false; @@ -184,7 +188,12 @@ void ShareSystem::AddNatives(IdentityToken_t *token, const sp_nativeinfo_t *nati void ShareSystem::DestroyIdentity(IdentityToken_t *identity) { - g_HandleSys.FreeHandle(identity->ident, NULL, GetIdentRoot()); + HandleSecurity sec; + + sec.pOwner = GetIdentRoot(); + sec.pIdentity = GetIdentRoot(); + + g_HandleSys.FreeHandle(identity->ident, &sec); delete identity; } diff --git a/core/vm/sp_vm_basecontext.cpp b/core/vm/sp_vm_basecontext.cpp index d261292e..a1bf02f1 100644 --- a/core/vm/sp_vm_basecontext.cpp +++ b/core/vm/sp_vm_basecontext.cpp @@ -252,11 +252,9 @@ int BaseContext::HeapRelease(cell_t local_addr) int BaseContext::FindNativeByName(const char *name, uint32_t *index) { - int diff, high, low; - uint32_t mid; + int high; high = ctx->plugin->info.natives_num - 1; - low = 0; #if 0 while (low <= high) @@ -786,3 +784,15 @@ int BaseContext::LookupLine(ucell_t addr, uint32_t *line) return SP_ERROR_NONE; } + +#if defined SOURCEMOD_BUILD +SourceMod::IdentityToken_t *BaseContext::GetIdentity() +{ + return m_pToken; +} + +void BaseContext::SetIdentity(SourceMod::IdentityToken_t *token) +{ + m_pToken = token; +} +#endif diff --git a/core/vm/sp_vm_basecontext.h b/core/vm/sp_vm_basecontext.h index 44f7e6af..5b495509 100644 --- a/core/vm/sp_vm_basecontext.h +++ b/core/vm/sp_vm_basecontext.h @@ -44,6 +44,10 @@ namespace SourcePawn virtual int Execute(funcid_t funcid, cell_t *result); virtual void ThrowNativeErrorEx(int error, const char *msg, ...); virtual cell_t ThrowNativeError(const char *msg, ...); +#if defined SOURCEMOD_BUILD + virtual SourceMod::IdentityToken_t *GetIdentity(); + void SetIdentity(SourceMod::IdentityToken_t *token); +#endif public: //IPluginDebugInfo virtual int LookupFile(ucell_t addr, const char **filename); virtual int LookupFunction(ucell_t addr, const char **name); @@ -52,6 +56,9 @@ namespace SourcePawn void SetErrorMessage(const char *msg, va_list ap); private: sp_context_t *ctx; +#if defined SOURCEMOD_BUILD + SourceMod::IdentityToken_t *m_pToken; +#endif char m_MsgCache[1024]; bool m_CustomMsg; bool m_InExec; diff --git a/plugins/test.sma b/plugins/test.sma index 8143007f..30f93206 100644 --- a/plugins/test.sma +++ b/plugins/test.sma @@ -12,7 +12,7 @@ public Plugin:myinfo = native PrintStuff(const String:buffer[]); -public bool:AskPluginLoad(Handle:myself, bool:late, String:error[], err_max) +DoItAll() { new String:buffer[PLATFORM_MAX_PATH]; new FileType:type; @@ -24,7 +24,14 @@ public bool:AskPluginLoad(Handle:myself, bool:late, String:error[], err_max) Format(stuff, sizeof(stuff), "Type: %d Dir: %s", _:type, buffer) PrintStuff(stuff); } + new Handle:copy = CloneHandle(dir); + CloseHandle(copy); CloseHandle(dir); +} + +public bool:AskPluginLoad(Handle:myself, bool:late, String:error[], err_max) +{ + DoItAll(); return true; } diff --git a/sourcepawn/include/sp_vm_api.h b/sourcepawn/include/sp_vm_api.h index 16d5d1ee..f1421743 100644 --- a/sourcepawn/include/sp_vm_api.h +++ b/sourcepawn/include/sp_vm_api.h @@ -6,6 +6,13 @@ #define SOURCEPAWN_VM_API_VERSION 1 +#if defined SOURCEMOD_BUILD +namespace SourceMod +{ + struct IdentityToken_t; +}; +#endif + namespace SourcePawn { class IVirtualMachine; @@ -331,6 +338,16 @@ namespace SourcePawn * @return 0 for convenience. */ virtual cell_t ThrowNativeError(const char *msg, ...) =0; + +#if defined SOURCEMOD_BUILD + /** + * @brief Returns the identity token for this context. + * Note: This is a helper function for native calls and the Handle System. + * + * @return Identity token. + */ + virtual SourceMod::IdentityToken_t *GetIdentity() =0; +#endif }; @@ -448,21 +465,6 @@ namespace SourcePawn */ virtual int FreeFromMemory(sp_plugin_t *plugin) =0; - /** - * @brief Creates a new IContext from a context handle. - * - * @param ctx Context to use as a basis for the IPluginContext. - * @return New IPluginContext handle. - */ - virtual IPluginContext *CreateBaseContext(sp_context_t *ctx) =0; - - /** - * @brief Frees a base context. Does not free the sp_context_t it holds. - * - * @param ctx Context pointer to free. - */ - virtual void FreeBaseContext(IPluginContext *ctx) =0; - /** * @brief Allocates large blocks of temporary memory. *