GetExplicitEntriesFromAcl() Win32 API 函数的对应物是啥?

Posted

技术标签:

【中文标题】GetExplicitEntriesFromAcl() Win32 API 函数的对应物是啥?【英文标题】:What is the counterpart to the GetExplicitEntriesFromAcl() Win32 API function?GetExplicitEntriesFromAcl() Win32 API 函数的对应物是什么? 【发布时间】:2016-02-05 15:00:55 【问题描述】:

GetExplicitEntriesFromAcl Win32 API 函数允许检索文件 ACL 的显式条目。但是当我更改一些条目时,使用SetEntriesInAcl 将结果转换为新的ACL,最后使用SetSecurityInfo 将ACL 应用回文件,所有继承的条目似乎都丢失了,只剩下(更改的)显式条目。

是否有一个对应函数“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;

【问题讨论】:

没有这样的功能,因为 ACE 的顺序很重要,并且系统无法猜测您希望现有继承的 ACE 出现的顺序,相对于您正在设置的显式条目。您需要指定所有 ACE,以便知道顺序。 Raymond 的观察在技术上是正确的(最好的那种!),但在这种情况下可能会产生误导。默认情况下,SetSecurityInfo 会将继承自父级的 ACE 添加到您指定的 ACL(使用首选顺序),但如果文件已被移动,则可能与最初继承的 ACE 不同。 ... 所以您需要检查父目录是否具有您希望应用于文件的可继承 ACE,并且您没有指定 PROTECTED_DACL_SECURITY_INFORMATION 标志。如果这仍然不起作用,请显示您的代码,因为它对我来说非常有效。 @HarryJohnston:在我的测试中,继承的 ACE 仅由 SetSecurityInfo 在处理目录时添加,而不是在处理文件时添加。 您是否检查过相关权限在父目录上是否标记为 (OI) 以及 (CI)? 【参考方案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;

【讨论】:

【参考方案2】:

以下代码似乎可以工作,但使用 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;

【讨论】:

以上是关于GetExplicitEntriesFromAcl() Win32 API 函数的对应物是啥?的主要内容,如果未能解决你的问题,请参考以下文章