GetExplicitEntriesFromAcl() Win32 API 函数的对应项是什么?
What is the counterpart to the GetExplicitEntriesFromAcl() Win32 API function?
GetExplicitEntriesFromAcl
Win32 API function allows to retrieve the explicit entries of a file ACL. But when I change some entries, convert the result into a new ACL using SetEntriesInAcl
and finally apply the ACL back to the file with SetSecurityInfo
所有继承的条目似乎都丢失了,只剩下(更改的)显式条目。
是否有对应函数"SetExplicitEntriesInAcl"只替换ACL结构中的显式条目并保持继承的条目完整?
Edit1:代码示例
我正在使用类似于以下行的代码来更新 ACL:
int RemoveAclAccessRights( HANDLE hFile, PSID SidPtr,
DWORD AccessRights, ACCESS_MODE AccessMode )
{
PACL OldAcl = NULL, NewAcl = NULL;
PSECURITY_DESCRIPTOR SecDesc = NULL;
PEXPLICIT_ACCESS EntryList = NULL, EntryItem;
ULONG EntryCount, EntryIndex;
int r;
// Get a pointer to the existing DACL
r = GetSecurityInfo(hFile, SE_FILE_OBJECT, DACL_SECURITY_INFORMATION,
NULL, NULL, &OldAcl, NULL, &SecDesc);
if ( r != ERROR_SUCCESS )
goto _CleanUp;
r = GetExplicitEntriesFromAcl(OldAcl, &EntryCount, &EntryItem);
if ( r != ERROR_SUCCESS )
goto _CleanUp;
EntryList = EntryItem;
EntryIndex = 0;
while ( EntryIndex < EntryCount ) {
// ... update access entry ...
EntryIndex++;
EntryItem++;
}
// Create a new ACL from the explicit entries of the existing DACL
r = SetEntriesInAcl(EntryCount, EntryList, NULL, &NewAcl);
if ( r != ERROR_SUCCESS )
goto _CleanUp;
// Attach the new ACL as the object's DACL
r = SetSecurityInfo(hFile, SE_FILE_OBJECT, DACL_SECURITY_INFORMATION,
NULL, NULL, NewAcl, NULL);
_CleanUp:
LocalFree(NewAcl);
LocalFree(EntryList);
LocalFree(SecDesc);
return r;
}
Edit2:文件和父目录的ACL
文件 icacls
的输出:
> icacls TestAcl01.txt
TestAcl01.txt VORDEFINIERT\Gäste:(R)
VORDEFINIERT\Administratoren:(I)(F)
NT-AUTORITÄT\SYSTEM:(I)(F)
NT-AUTORITÄT\Authentifizierte Benutzer:(I)(M)
VORDEFINIERT\Benutzer:(I)(RX)
icacls
在父目录上的输出:
> icacls .
. VORDEFINIERT\Administratoren:(I)(F)
VORDEFINIERT\Administratoren:(I)(OI)(CI)(IO)(F)
NT-AUTORITÄT\SYSTEM:(I)(F)
NT-AUTORITÄT\SYSTEM:(I)(OI)(CI)(IO)(F)
NT-AUTORITÄT\Authentifizierte Benutzer:(I)(M)
NT-AUTORITÄT\Authentifizierte Benutzer:(I)(OI)(CI)(IO)(M)
VORDEFINIERT\Benutzer:(I)(RX)
VORDEFINIERT\Benutzer:(I)(OI)(CI)(IO)(GR,GE)
该文件有一个显式条目"VORDEFINIERT\Gäste:(R)" (SID "S-1-5-32-546")。其他条目继承自父目录。
在上面的 while 循环中,如果显式条目与 SID 匹配,我将尝试使用类似
的代码删除该显式条目
if ( (EntryItem->Trustee.TrusteeForm == TRUSTEE_IS_SID) && EqualSid(EntryItem->Trustee.ptstrName, SidPtr) ) {
if ( EntryIndex < (EntryCount-1) )
MoveMemory(&EntryList[EntryIndex], &EntryList[EntryIndex+1], (EntryCount-EntryIndex-1)*sizeof(EntryList[0]));
EntryCount--;
continue;
}
以下代码似乎有效,但使用 GetAclInformation
和 GetAce
而不是 GetExplicitEntriesFromAcl
,后者需要指针类型检查,因此不太方便:
int UpdateAclAccessRights( HANDLE hFile, PSID SidPtr,
DWORD AccessRights, ACCESS_MODE AccessMode )
{
PACL DiscAcl = NULL;
PSECURITY_DESCRIPTOR SecDesc = NULL;
ACL_SIZE_INFORMATION AclSizeInfo;
PACCESS_ALLOWED_ACE AceItem;
int AceIndex;
int r;
// Get a pointer to the existing DACL
r = GetSecurityInfo(hFile, SE_FILE_OBJECT, DACL_SECURITY_INFORMATION,
NULL, NULL, &DiscAcl, NULL, &SecDesc);
if ( r != ERROR_SUCCESS )
goto _CleanUp;
ZeroMemory(&AclSizeInfo, sizeof(AclSizeInfo));
if (!GetAclInformation(DiscAcl, &AclSizeInfo, sizeof(AclSizeInfo), AclSizeInformation))
goto _CleanUp;
for (AceIndex = AclSizeInfo.AceCount-1; AceIndex >= 0; AceIndex--) {
if (!GetAce(DiscAcl, AceIndex, &((void*)AceItem)))
continue;
if ( (AceItem->Header.AceType != ACCESS_ALLOWED_ACE_TYPE) &&
(AceItem->Header.AceType != ACCESS_DENIED_ACE_TYPE) )
continue; // entry pointer structure does not match AceItem
if ( (AceItem->Header.AceFlags && INHERITED_ACE) > 0 )
continue; // not an explicit entry
// ... update/delete access entry in case it matches SidPtr ...
}
// Attach updated ACL to the file object
r = SetSecurityInfo(hFile, SE_FILE_OBJECT, DACL_SECURITY_INFORMATION,
NULL, NULL, DiscAcl, NULL);
_CleanUp:
LocalFree(SecDesc);
return r;
}
根据最新编辑中的信息,我现在可以重现您的问题。它只发生在您从 DACL 中删除所有显式条目的情况下。
事实证明 SetEntriesInAcl 中有一个令人讨厌的(并且据我所知没有记录):如果你传递一个零长度数组,它会默默地 returns NULL
作为新的 ACL,而不是像您合理期望的那样返回一个空的 ACL。
SetSecurityInfo 的文档解释了这种情况下发生的情况:
If the value of the SecurityInfo parameter includes the DACL_SECURITY_INFORMATION flag and the value of this parameter is set to NULL, full access to the object is granted to everyone.
这会隐式删除继承的权限(无论如何都是多余的)。
解决问题的一种方法:
ACL empty_acl;
if (!InitializeAcl(&empty_acl, sizeof(empty_acl), ACL_REVISION))
goto _CleanUp;
// Create a new ACL from the explicit entries of the existing DACL
r = SetEntriesInAcl(EntryCount, EntryList, &empty_acl, &NewAcl);
if ( r != ERROR_SUCCESS )
goto _CleanUp;
GetExplicitEntriesFromAcl
Win32 API function allows to retrieve the explicit entries of a file ACL. But when I change some entries, convert the result into a new ACL using SetEntriesInAcl
and finally apply the ACL back to the file with SetSecurityInfo
所有继承的条目似乎都丢失了,只剩下(更改的)显式条目。
是否有对应函数"SetExplicitEntriesInAcl"只替换ACL结构中的显式条目并保持继承的条目完整?
Edit1:代码示例
我正在使用类似于以下行的代码来更新 ACL:
int RemoveAclAccessRights( HANDLE hFile, PSID SidPtr,
DWORD AccessRights, ACCESS_MODE AccessMode )
{
PACL OldAcl = NULL, NewAcl = NULL;
PSECURITY_DESCRIPTOR SecDesc = NULL;
PEXPLICIT_ACCESS EntryList = NULL, EntryItem;
ULONG EntryCount, EntryIndex;
int r;
// Get a pointer to the existing DACL
r = GetSecurityInfo(hFile, SE_FILE_OBJECT, DACL_SECURITY_INFORMATION,
NULL, NULL, &OldAcl, NULL, &SecDesc);
if ( r != ERROR_SUCCESS )
goto _CleanUp;
r = GetExplicitEntriesFromAcl(OldAcl, &EntryCount, &EntryItem);
if ( r != ERROR_SUCCESS )
goto _CleanUp;
EntryList = EntryItem;
EntryIndex = 0;
while ( EntryIndex < EntryCount ) {
// ... update access entry ...
EntryIndex++;
EntryItem++;
}
// Create a new ACL from the explicit entries of the existing DACL
r = SetEntriesInAcl(EntryCount, EntryList, NULL, &NewAcl);
if ( r != ERROR_SUCCESS )
goto _CleanUp;
// Attach the new ACL as the object's DACL
r = SetSecurityInfo(hFile, SE_FILE_OBJECT, DACL_SECURITY_INFORMATION,
NULL, NULL, NewAcl, NULL);
_CleanUp:
LocalFree(NewAcl);
LocalFree(EntryList);
LocalFree(SecDesc);
return r;
}
Edit2:文件和父目录的ACL
文件 icacls
的输出:
> icacls TestAcl01.txt
TestAcl01.txt VORDEFINIERT\Gäste:(R)
VORDEFINIERT\Administratoren:(I)(F)
NT-AUTORITÄT\SYSTEM:(I)(F)
NT-AUTORITÄT\Authentifizierte Benutzer:(I)(M)
VORDEFINIERT\Benutzer:(I)(RX)
icacls
在父目录上的输出:
> icacls .
. VORDEFINIERT\Administratoren:(I)(F)
VORDEFINIERT\Administratoren:(I)(OI)(CI)(IO)(F)
NT-AUTORITÄT\SYSTEM:(I)(F)
NT-AUTORITÄT\SYSTEM:(I)(OI)(CI)(IO)(F)
NT-AUTORITÄT\Authentifizierte Benutzer:(I)(M)
NT-AUTORITÄT\Authentifizierte Benutzer:(I)(OI)(CI)(IO)(M)
VORDEFINIERT\Benutzer:(I)(RX)
VORDEFINIERT\Benutzer:(I)(OI)(CI)(IO)(GR,GE)
该文件有一个显式条目"VORDEFINIERT\Gäste:(R)" (SID "S-1-5-32-546")。其他条目继承自父目录。
在上面的 while 循环中,如果显式条目与 SID 匹配,我将尝试使用类似
的代码删除该显式条目if ( (EntryItem->Trustee.TrusteeForm == TRUSTEE_IS_SID) && EqualSid(EntryItem->Trustee.ptstrName, SidPtr) ) {
if ( EntryIndex < (EntryCount-1) )
MoveMemory(&EntryList[EntryIndex], &EntryList[EntryIndex+1], (EntryCount-EntryIndex-1)*sizeof(EntryList[0]));
EntryCount--;
continue;
}
以下代码似乎有效,但使用 GetAclInformation
和 GetAce
而不是 GetExplicitEntriesFromAcl
,后者需要指针类型检查,因此不太方便:
int UpdateAclAccessRights( HANDLE hFile, PSID SidPtr,
DWORD AccessRights, ACCESS_MODE AccessMode )
{
PACL DiscAcl = NULL;
PSECURITY_DESCRIPTOR SecDesc = NULL;
ACL_SIZE_INFORMATION AclSizeInfo;
PACCESS_ALLOWED_ACE AceItem;
int AceIndex;
int r;
// Get a pointer to the existing DACL
r = GetSecurityInfo(hFile, SE_FILE_OBJECT, DACL_SECURITY_INFORMATION,
NULL, NULL, &DiscAcl, NULL, &SecDesc);
if ( r != ERROR_SUCCESS )
goto _CleanUp;
ZeroMemory(&AclSizeInfo, sizeof(AclSizeInfo));
if (!GetAclInformation(DiscAcl, &AclSizeInfo, sizeof(AclSizeInfo), AclSizeInformation))
goto _CleanUp;
for (AceIndex = AclSizeInfo.AceCount-1; AceIndex >= 0; AceIndex--) {
if (!GetAce(DiscAcl, AceIndex, &((void*)AceItem)))
continue;
if ( (AceItem->Header.AceType != ACCESS_ALLOWED_ACE_TYPE) &&
(AceItem->Header.AceType != ACCESS_DENIED_ACE_TYPE) )
continue; // entry pointer structure does not match AceItem
if ( (AceItem->Header.AceFlags && INHERITED_ACE) > 0 )
continue; // not an explicit entry
// ... update/delete access entry in case it matches SidPtr ...
}
// Attach updated ACL to the file object
r = SetSecurityInfo(hFile, SE_FILE_OBJECT, DACL_SECURITY_INFORMATION,
NULL, NULL, DiscAcl, NULL);
_CleanUp:
LocalFree(SecDesc);
return r;
}
根据最新编辑中的信息,我现在可以重现您的问题。它只发生在您从 DACL 中删除所有显式条目的情况下。
事实证明 SetEntriesInAcl 中有一个令人讨厌的(并且据我所知没有记录):如果你传递一个零长度数组,它会默默地 returns NULL
作为新的 ACL,而不是像您合理期望的那样返回一个空的 ACL。
SetSecurityInfo 的文档解释了这种情况下发生的情况:
If the value of the SecurityInfo parameter includes the DACL_SECURITY_INFORMATION flag and the value of this parameter is set to NULL, full access to the object is granted to everyone.
这会隐式删除继承的权限(无论如何都是多余的)。
解决问题的一种方法:
ACL empty_acl;
if (!InitializeAcl(&empty_acl, sizeof(empty_acl), ACL_REVISION))
goto _CleanUp;
// Create a new ACL from the explicit entries of the existing DACL
r = SetEntriesInAcl(EntryCount, EntryList, &empty_acl, &NewAcl);
if ( r != ERROR_SUCCESS )
goto _CleanUp;