GetExplicitEntriesFromAcl() Win32 API函数的对应函数是什么?

4
The Win32 API function GetExplicitEntriesFromAcl can be used to retrieve explicit entries from a file ACL related to IT technology. However, after making changes to some entries and converting the result into a new ACL using SetEntriesInAcl, applying the ACL back to the file with SetSecurityInfo results in the loss of all inherited entries, leaving only the changed explicit entries.
Is there an equivalent function "SetExplicitEntriesInAcl" that only replaces the explicit entries within an ACL structure while keeping the inherited entries intact?
Edit1: Code Sample The following lines of code are being used for updating the 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;
}

编辑2:文件和父目录的访问控制列表

icacls 命令输出的文件ACL:

> 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;
}

2
没有这样的功能,因为ACE的顺序很重要,系统无法猜测您希望现有继承的ACE相对于您设置的显式条目发生的顺序。您需要指定所有的ACE,以便知道顺序。 - Raymond Chen
2
Raymond的观察在技术上是正确的(最好的那种!),但在这种情况下可能会导致误解。默认情况下,SetSecurityInfo将从父项添加继承的ACE到指定的ACL中(使用首选顺序),但如果文件已被移动,则可能与其最初具有的继承的ACE不同。 - Harry Johnston
所以您需要检查父目录是否具有您期望应用于文件的可继承ACE,并且您没有指定PROTECTED_DACL_SECURITY_INFORMATION标志。如果仍然无法工作,请展示您的代码,因为它对我来说完美地运行。 - Harry Johnston
@HarryJohnston: 在我的测试中,只有在处理目录时,通过SetSecurityInfo继承的ACE才会被添加,而在处理文件时不会添加。 - blerontin
你的代码看起来和我的一模一样,而我的代码完美地运行了。我能想到的唯一可能是:(1)在省略部分的代码中有些东西破坏了它——如果你不修改显式条目数组,它是否正常工作?(2)你以不足够的访问权限打开了文件。(3)你正在处理的特定权限使其表现不同。你能发布你正在使用的父目录和文件的icacls输出吗?(4)你使用的Windows版本是什么? - Harry Johnston
显示剩余3条评论
2个回答

1
根据最新的编辑信息,我现在可以复制您的问题。只有在从DACL中删除所有显式条目的情况下才会出现此问题。
原来SetEntriesInAcl中有一个令人讨厌的(并且据我所见未经记录)陷阱:如果您传递一个零长度的数组,则它会静默地返回NULL作为新的ACL,而不是像您可能合理地期望的那样返回一个空的ACL。 SetSecurityInfo的文档解释了此情况的发生:
“如果SecurityInfo参数的值包括DACL_SECURITY_INFORMATION标志,并且将该参数的值设置为NULL,则授予每个人对对象的完全访问权限。”
这隐含地删除了继承的权限(这些权限无论如何都是多余的)。
解决问题的一种方法:
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;

0
以下代码似乎可以工作,但使用的是GetAclInformationGetAce而不是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;
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接