Permalink
Browse files

Extend ACL to allow ModifyOtherObjects only on a single resource

  • Loading branch information...
botder committed Aug 28, 2018
1 parent 938aaff commit 6614d9ca56d7a9d64c486831715fd6342763ba2b
@@ -743,7 +743,15 @@ uint GetWeaponPropertyFlagBit(eWeaponProperty weaponProperty)
//
// Set error if pThisResource does not have permission to modify pOtherResource
//
void CheckCanModifyOtherResource(CScriptArgReader& argStream, CResource* pThisResource, CResource* pOtherResource, CResource* pOtherResource2)
void CheckCanModifyOtherResource(CScriptArgReader& argStream, CResource* pThisResource, CResource* pOtherResource)
{
// No operation on the client
}
//
// Set error if pThisResource does not have permission to modify every resource in resourceList
//
void CheckCanModifyOtherResources(CScriptArgReader& argStream, CResource* pThisResource, std::initializer_list<CResource*> resourceList)
{
// No operation on the client
}
@@ -475,7 +475,12 @@ void MixedReadMaterialString(CScriptArgReader& argStream, CClientMaterial*& pMat
bool ReadMatrix(lua_State* luaVM, uint uiArgIndex, CMatrix& outMatrix);
bool MinClientReqCheck(CScriptArgReader& argStream, const char* szVersionReq, const char* szReason = nullptr);
void ReadPregFlags(CScriptArgReader& argStream, pcrecpp::RE_Options& pOptions);
void CheckCanModifyOtherResource(CScriptArgReader& argStream, CResource* pThisResource, CResource* pOtherResource, CResource* pOtherResource2 = nullptr);
//
// Resource access helpers
//
void CheckCanModifyOtherResource(CScriptArgReader& argStream, CResource* pThisResource, CResource* pOtherResource);
void CheckCanModifyOtherResources(CScriptArgReader& argStream, CResource* pThisResource, std::initializer_list<CResource*> resourceList);
void CheckCanAccessOtherResourceFile(CScriptArgReader& argStream, CResource* pThisResource, CResource* pOtherResource, const SString& strAbsPath,
bool* pbReadOnly = nullptr);
@@ -19,6 +19,7 @@
#include <ctime>
#include <sstream>
#include <mutex>
#include <unordered_set>
// Forward declarations
class CAclRightName;
@@ -496,34 +496,84 @@ uint GetWeaponPropertyFlagBit(eWeaponProperty weaponProperty)
return uiFlagBit;
}
//
// Returns the permission level of pThisResource to modify pOtherResource
//
eResourceModifyScope GetResourceModifyScope(CResource* pThisResource, CResource* pOtherResource)
{
if (pThisResource == pOtherResource)
return eResourceModifyScope::SINGLE_RESOURCE;
CAccessControlListManager* const pACLManager = g_pGame->GetACLManager();
const SString& strResourceName = pThisResource->GetName();
// Check if resource has right to modify any resource
if (pACLManager->CanObjectUseRight(strResourceName.c_str(), CAccessControlListGroupObject::OBJECT_TYPE_RESOURCE, "ModifyOtherObjects", CAccessControlListRight::RIGHT_TYPE_GENERAL, false))
return eResourceModifyScope::EVERY_RESOURCE;
// Check if resource has right to modify only pOtherResource
const SString strRightName("ModifyOtherObjects.%s", pOtherResource->GetName().c_str());
if (pACLManager->CanObjectUseRight(strResourceName.c_str(), CAccessControlListGroupObject::OBJECT_TYPE_RESOURCE, strRightName.c_str(), CAccessControlListRight::RIGHT_TYPE_GENERAL, false))
return eResourceModifyScope::SINGLE_RESOURCE;
return eResourceModifyScope::NONE;
}
//
// Set error if pThisResource does not have permission to modify pOtherResource
//
void CheckCanModifyOtherResource(CScriptArgReader& argStream, CResource* pThisResource, CResource* pOtherResource, CResource* pOtherResource2)
void CheckCanModifyOtherResource(CScriptArgReader& argStream, CResource* pThisResource, CResource* pOtherResource)
{
if (GetResourceModifyScope(pThisResource, pOtherResource) == eResourceModifyScope::NONE)
argStream.SetCustomError(SString("ModifyOtherObjects in ACL denied resource %s to access %s", pThisResource->GetName().c_str(), pOtherResource->GetName().c_str()), "Access denied");
}
//
// Set error if pThisResource does not have permission to modify every resource in resourceList
//
void CheckCanModifyOtherResources(CScriptArgReader& argStream, CResource* pThisResource, std::initializer_list<CResource*> resourceList)
{
// Check if other object is different and right is denied
if ((pThisResource != pOtherResource || (pOtherResource2 != nullptr && pThisResource != pOtherResource2)) &&
(g_pGame->GetACLManager()->CanObjectUseRight(pThisResource->GetName(), CAccessControlListGroupObject::OBJECT_TYPE_RESOURCE, "ModifyOtherObjects",
CAccessControlListRight::RIGHT_TYPE_GENERAL, false) == false))
// std::unordered_set only allows unique values and resourceList can contain duplicates
std::unordered_set<CResource*> setNoPermissionResources;
for (CResource* pOtherResource : resourceList)
{
SString strWho;
if (pThisResource != pOtherResource)
strWho += pOtherResource->GetName();
if (pOtherResource2 != nullptr && pThisResource != pOtherResource2 && pOtherResource != pOtherResource2)
{
if (!strWho.empty())
strWho += " and ";
strWho += pOtherResource2->GetName();
}
argStream.SetCustomError(SString("ModifyOtherObjects in ACL denied resource %s to access %s", *pThisResource->GetName(), *strWho), "Access denied");
eResourceModifyScope modifyScope = GetResourceModifyScope(pThisResource, pOtherResource);
if (modifyScope == eResourceModifyScope::SINGLE_RESOURCE)
continue;
if (modifyScope == eResourceModifyScope::EVERY_RESOURCE)
return;
setNoPermissionResources.emplace(pOtherResource);
}
if (setNoPermissionResources.empty())
return;
std::stringstream ssResourceNames;
size_t remainingElements = setNoPermissionResources.size();
for (CResource* pResource : setNoPermissionResources)
{
ssResourceNames << pResource->GetName();
if (remainingElements > 1)
ssResourceNames << ", ";
--remainingElements;
}
argStream.SetCustomError(SString("ModifyOtherObjects in ACL denied resource %s to access %s", pThisResource->GetName().c_str(), ssResourceNames.str().c_str()), "Access denied");
}
//
// Set error if resource file access is blocked due to reasons
//
void CheckCanAccessOtherResourceFile(CScriptArgReader& argStream, CResource* pThisResource, CResource* pOtherResource, const SString& strAbsPath,
bool* pbReadOnly)
bool* pbReadOnly)
{
if (!g_pGame->GetConfig()->IsDatabaseCredentialsProtectionEnabled())
return;
@@ -451,9 +451,22 @@ bool StringToBool(const SString& strText);
void MinServerReqCheck(CScriptArgReader& argStream, const char* szVersionReq, const char* szReason);
void ReadPregFlags(CScriptArgReader& argStream, pcrecpp::RE_Options& pOptions);
bool ReadMatrix(lua_State* luaVM, uint uiArgIndex, CMatrix& outMatrix);
void CheckCanModifyOtherResource(CScriptArgReader& argStream, CResource* pThisResource, CResource* pOtherResource, CResource* pOtherResource2 = nullptr);
void CheckCanAccessOtherResourceFile(CScriptArgReader& argStream, CResource* pThisResource, CResource* pOtherResource, const SString& strAbsPath,
bool* pbReadOnly = nullptr);
//
// Resource access helpers
//
enum class eResourceModifyScope
{
NONE,
SINGLE_RESOURCE,
EVERY_RESOURCE,
};
eResourceModifyScope GetResourceModifyScope(CResource* pThisResource, CResource* pOtherResource);
void CheckCanModifyOtherResource(CScriptArgReader& argStream, CResource* pThisResource, CResource* pOtherResource);
void CheckCanModifyOtherResources(CScriptArgReader& argStream, CResource* pThisResource, std::initializer_list<CResource*> resourceList);
void CheckCanAccessOtherResourceFile(CScriptArgReader& argStream, CResource* pThisResource, CResource* pOtherResource, const SString& strAbsPath,
bool* pbReadOnly = nullptr);
//
// Other misc helpers
@@ -430,7 +430,7 @@ int CLuaFileDefs::fileCopy(lua_State* luaVM)
if (CResourceManager::ParseResourcePathInput(strInputSrcPath, pSrcResource, &strSrcAbsPath) &&
CResourceManager::ParseResourcePathInput(strInputDestPath, pDestResource, &strDestAbsPath))
{
CheckCanModifyOtherResource(argStream, pThisResource, pSrcResource, pDestResource);
CheckCanModifyOtherResources(argStream, pThisResource, { pSrcResource, pDestResource });
CheckCanAccessOtherResourceFile(argStream, pThisResource, pSrcResource, strSrcAbsPath);
CheckCanAccessOtherResourceFile(argStream, pThisResource, pDestResource, strDestAbsPath);
if (!argStream.HasErrors())
@@ -521,7 +521,7 @@ int CLuaFileDefs::fileRename(lua_State* luaVM)
if (CResourceManager::ParseResourcePathInput(strInputSrcPath, pSrcResource, &strSrcAbsPath) &&
CResourceManager::ParseResourcePathInput(strInputDestPath, pDestResource, &strDestAbsPath))
{
CheckCanModifyOtherResource(argStream, pThisResource, pSrcResource, pDestResource);
CheckCanModifyOtherResources(argStream, pThisResource, { pSrcResource, pDestResource });
CheckCanAccessOtherResourceFile(argStream, pThisResource, pSrcResource, strSrcAbsPath);
CheckCanAccessOtherResourceFile(argStream, pThisResource, pDestResource, strDestAbsPath);
if (!argStream.HasErrors())

0 comments on commit 6614d9c

Please sign in to comment.