ahm*_*md0 2 c++ permissions winapi acl
我对某事很好奇。我正在用 C++ 编写一段代码,需要扫描特定文件夹的子文件夹的 ACL 权限,并找到与第一个文件夹的 ACL 权限不同的那些。为此,我使用FindFirstFile和FindNextFile递归检查文件夹中的所有文件夹,然后通过在找到的每个子文件夹上调用GetNamedSecurityInfo来检查 ACL 权限。
这种方法有效,只是它的运行速度很慢,尤其是在扫描网络共享时。我知道名为accesschk的工具可以做同样的事情,但是当我在同一个文件夹(带-dsqvli
开关)上递归运行它时,它返回结果的方式比我上面描述的过程更快。
所以我想知道如何加快这个 ACL 权限查找过程?
我的第一个想法是在 ACE 上使用继承,我只是不确定如何实现它......
编辑 2:感谢@arx 的建议。这个 ACL/ACE 的东西记录很差。他在下面发布的代码对我有用。请注意,由于@arx 在他的帖子中概述的原因,我用于检查 ACL 继承的原始代码没有产生可靠的结果。
评论中的一些进一步信息:
该应用程序确定正在检查其访问权限的用户的 SID。
调用GetNamedSecurityInfo
每个目录后,应用程序GetEffectiveRightsFromAcl
使用用户的 SID 进行调用。大多数时间是后者调用。
GetEffectiveRightsFromAcl
根据用户的 SID 和用户所属的任何组的 SID 检查 ACL。这可能很慢,因为确定用户组需要往返域控制器。
有两种可能的修复方法和一个死胡同:
模拟 GetEffectiveRightsFromAcl
在循环外,确定用户的 SID 和用户组的 SID。(待办事项:检查嵌套组是否自动处理,或者是否必须递归解析。)
要确定 ACL 的有效权限:
处理完所有 ACE 后,您的权限掩码就会保存答案。
跳过继承的 ACL
在许多目录层次结构中,大多数或所有文件和目录将从其父目录继承其权限。但是,这无济于事。继承的 ACL 可能对父级无效,因此子级的有效权限与父级的有效权限不匹配。因此,即使 ACL 是继承的,仍然需要对其进行检查。
缓存 GetEffectiveRightsFromAcl 的结果
只需创建一个从 ACL 到有效权限掩码的映射。为此,您需要一种比较 ACL 的方法。您不能只使用 memcmp 比较整个 ACL,因为 ACL.AclSize 包括额外填充的大小。相反,比较 ACE 的数量,如果它们相同,则使用 memcmp 比较各个 ACE。
我在我的Program Files
目录上试过这个。扫描整个目录结构需要 6 次调用GetEffectiveRightsFromAcl
. 剩余的 2,708 个目录是从缓存中解析的,因此速度要快得多。
下面实现了一个缓存版本的GetEffectiveRightsFromAcl
. 请注意,缺少错误处理,并且它永远不会释放它放入映射中的 PACL。
// Compare two access-control lists.
// Return <0 if acl1<acl2, 0 if acl1==acl2 and >0 if acl1>acl2.
// The ordering is arbitrary but consistent.
int aclcmp(PACL acl1, PACL acl2)
{
// First compare by number of ACEs
int c = acl1->AceCount - acl2->AceCount;
if (c)
return c;
// We have the same number of ACEs, so compare each ACE
int aceCount = acl1->AceCount;
for (int aceIndex = 0; aceIndex != aceCount; ++aceIndex)
{
// Get the ACEs
PACE_HEADER ace1;
PACE_HEADER ace2;
GetAce(acl1, aceIndex, (LPVOID*)&ace1);
GetAce(acl2, aceIndex, (LPVOID*)&ace2);
// Compare the ACE sizes
c = ace1->AceSize - ace2->AceSize;
if (c)
return c;
// Compare the ACE content
c = memcmp(ace1, ace2, ace1->AceSize);
if (c)
return c;
}
return 0;
}
// Less-than operator for pointers to ACLs
class ComparePAcl
{
public:
bool operator()(const PACL& acl1, const PACL& acl2) const
{
return aclcmp(acl1, acl2) < 0;
}
};
// Map from pointers-to-ACLs to access masks
typedef std::map<PACL, ACCESS_MASK, ComparePAcl> AclToAccessMask;
AclToAccessMask aclToAccessMask;
// Just to check how the cache performs
DWORD foundCount = 0;
DWORD notFoundCount = 0;
// Same as GetEffectiveRightsFromAcl but caches results.
// Note that this must be called with the same trustee to get meaningful results.
DWORD CachedGetEffectiveRightsFromAcl(PACL pacl, PTRUSTEE pTrustee, PACCESS_MASK pAccessRights)
{
AclToAccessMask::const_iterator it = aclToAccessMask.find(pacl);
if (it != aclToAccessMask.end())
{
// The ACL is in the cache
++foundCount;
*pAccessRights = it->second;
}
else
{
// The ACL is not in the cache
++notFoundCount;
DWORD rc = GetEffectiveRightsFromAcl(pacl, pTrustee, pAccessRights);
if (rc != ERROR_SUCCESS)
return rc;
// TODO: Clean up copies of ACLs afterwards
PACL aclcopy = (PACL)malloc(pacl->AclSize);
memcpy(aclcopy, pacl, pacl->AclSize);
aclToAccessMask.insert(AclToAccessMask::value_type(aclcopy, *pAccessRights));
}
return ERROR_SUCCESS;
}
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
1279 次 |
最近记录: |