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

时间:2016-02-05 15:00:56

标签: c winapi acl

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

是否有对应的函数“SetExplicitEntriesInAcl”只替换ACL结构中的显式条目并保持继承的条目不变?

编辑1:代码示例

我正在使用类似于以下行的代码进行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;
}

2 个答案:

答案 0 :(得分:1)

Given the information in the latest edit, I can now replicate your problem. It only occurs in the case when you are removing all of the explicit entries from the DACL.

It turns out there's a nasty (and undocumented, so far as I can see) catch in SetEntriesInAcl: if you pass it a zero-length array, it silently returns NULL as the new ACL rather than returning an empty ACL as you might reasonably expect.

The documentation for SetSecurityInfo explains what happens in this case:

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.

That implicitly removes the inherited permissions (which are redundant anyway).

One way to fix the problem:

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;

答案 1 :(得分: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;
}