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 次 |
| 最近记录: |