title: Windows DACL permissions
body: <p>I am trying to modify permissions using Windows permissions API. 
  I have a standalone use case code as below, I first revoke all the access and then grant read and write ones.</p>
  
  <pre><code>#include &lt;fstream&gt;
  #include &lt;iostream&gt;
  #include &lt;aclapi.h&gt;
  #include &lt;windows.h&gt;
  #include &lt;string&gt;
  using namespace std;
  #include &lt;memory&gt;
  
  
  bool CanAccessFolder(LPCTSTR folderName, DWORD genericAccessRights,DWORD&amp; grantedRights)
  {
      bool bRet = false;
      DWORD length = 0;
      if (!::GetFileSecurity(folderName, OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION
          | DACL_SECURITY_INFORMATION, NULL, NULL, &amp;length) &amp;&amp;
          ERROR_INSUFFICIENT_BUFFER == ::GetLastError()) {
          PSECURITY_DESCRIPTOR security = static_cast&lt; PSECURITY_DESCRIPTOR &gt;(::malloc(length));
          if (security &amp;&amp; ::GetFileSecurity(folderName, OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION
              | DACL_SECURITY_INFORMATION, security, length, &amp;length)) {
              HANDLE hToken = NULL;
              if (::OpenProcessToken(::GetCurrentProcess(), TOKEN_IMPERSONATE | TOKEN_QUERY |
                  TOKEN_DUPLICATE | STANDARD_RIGHTS_READ, &amp;hToken)) {
                  HANDLE hImpersonatedToken = NULL;
                  if (::DuplicateToken(hToken, SecurityImpersonation, &amp;hImpersonatedToken)) {
                      GENERIC_MAPPING mapping = { 0xFFFFFFFF };
                      PRIVILEGE_SET privileges = { 0 };
                      DWORD grantedAccess = 0, privilegesLength = sizeof(privileges);
                      BOOL result = FALSE;
  
                      mapping.GenericRead = FILE_GENERIC_READ;
                      mapping.GenericWrite = FILE_GENERIC_WRITE;
                      mapping.GenericExecute = FILE_GENERIC_EXECUTE;
                      mapping.GenericAll = FILE_ALL_ACCESS;
  
                      ::MapGenericMask(&amp;genericAccessRights, &amp;mapping);
                      if (::AccessCheck(security, hImpersonatedToken, genericAccessRights,
                          &amp;mapping, &amp;privileges, &amp;privilegesLength, &amp;grantedAccess, &amp;result)) 
                      {
                          bRet = (result == TRUE);
                          grantedRights = grantedAccess;
                      }
                      ::CloseHandle(hImpersonatedToken);
                  }
                  ::CloseHandle(hToken);
              }
              ::free(security);
          }
      }
  
      return bRet;
  }
   void printMasks(DWORD Mask)
   {
       // This evaluation of the ACCESS_MASK is an example.
       // Applications should evaluate the ACCESS_MASK as necessary.
      std::wcout &lt;&lt; "Effective Allowed Access Mask :  "&lt;&lt; Mask &lt;&lt; std::hex &lt;&lt; std::endl;
       if (((Mask &amp; GENERIC_ALL) == GENERIC_ALL)
           || ((Mask &amp; FILE_ALL_ACCESS) == FILE_ALL_ACCESS))
       {
           wprintf_s(L"Full Control\n");
           //return;
       }
       if (((Mask &amp; GENERIC_READ) == GENERIC_READ)
           || ((Mask &amp; FILE_GENERIC_READ) == FILE_GENERIC_READ))
           wprintf_s(L"Read\n");
       if (((Mask &amp; GENERIC_WRITE) == GENERIC_WRITE)
           || ((Mask &amp; FILE_GENERIC_WRITE) == FILE_GENERIC_WRITE))
           wprintf_s(L"Write\n");
       if (((Mask &amp; GENERIC_EXECUTE) == GENERIC_EXECUTE)
           || ((Mask &amp; FILE_GENERIC_EXECUTE) == FILE_GENERIC_EXECUTE))
           wprintf_s(L"Execute\n");
   }
  
   DWORD AddAceToObjectsSecurityDescriptor(
       LPTSTR pszObjName,          // name of object
       SE_OBJECT_TYPE ObjectType,  // type of object     
       DWORD dwAccessRights,       // access mask for new ACE
       ACCESS_MODE AccessMode,     // type of ACE
       DWORD dwInheritance         // inheritance flags for new ACE
   )
   {
       DWORD dwRes = 0;
       PACL pOldDACL = NULL, pNewDACL = NULL;
       PSECURITY_DESCRIPTOR pSD = NULL;
       EXPLICIT_ACCESS ea;
  
       if (NULL == pszObjName)
           return ERROR_INVALID_PARAMETER;
  
       // Get a pointer to the existing DACL.
  
       dwRes = GetNamedSecurityInfo(pszObjName, ObjectType,
           DACL_SECURITY_INFORMATION,
           NULL, NULL, &amp;pOldDACL, NULL, &amp;pSD);
  
       if (ERROR_SUCCESS != dwRes) {
           printf("GetNamedSecurityInfo Error %u\n", dwRes);
           goto Cleanup;
       }
  
  
       // Initialize an EXPLICIT_ACCESS structure for the new ACE. 
  
       ZeroMemory(&amp;ea, sizeof(EXPLICIT_ACCESS));
       ea.grfAccessPermissions = dwAccessRights;
       ea.grfAccessMode = AccessMode;
       ea.grfInheritance = dwInheritance;
       ea.Trustee.TrusteeForm = TRUSTEE_IS_NAME;
       ea.Trustee.ptstrName = L"CURRENT_USER";
       ea.Trustee.TrusteeType = TRUSTEE_IS_USER;
       // Create a new ACL that merges the new ACE
       // into the existing DACL.
  
       dwRes = SetEntriesInAcl(1, &amp;ea, pOldDACL, &amp;pNewDACL);
       if (ERROR_SUCCESS != dwRes) {
           printf("SetEntriesInAcl Error %u\n", dwRes);
           goto Cleanup;
       }
  
       // Attach the new ACL as the object's DACL.
  
       dwRes = SetNamedSecurityInfo(pszObjName, ObjectType,
           DACL_SECURITY_INFORMATION,
           NULL, NULL, pNewDACL, NULL);
       if (ERROR_SUCCESS != dwRes) {
           printf("SetNamedSecurityInfo Error %u\n", dwRes);
           goto Cleanup;
       }
  
   Cleanup:
  
       if (pSD != NULL)
           LocalFree((HLOCAL)pSD);
       if (pNewDACL != NULL)
           LocalFree((HLOCAL)pNewDACL);
  
       return dwRes;
   }
  
   int main()
   {
       DWORD access_mask = FILE_GENERIC_READ | FILE_GENERIC_WRITE | FILE_GENERIC_EXECUTE | FILE_ALL_ACCESS;
       DWORD grant = 0;
  
       std::cout &lt;&lt; "Before modification \n";
  
       bool b = CanAccessFolder(L"C:\\Deny\\file.txt", access_mask, grant);
  
       printMasks(grant);
  
       std::cout &lt;&lt; "After removing access \n";
  
       DWORD dwres = AddAceToObjectsSecurityDescriptor(
           L"C:\\Deny\\file.txt",
           SE_FILE_OBJECT,
           FILE_ALL_ACCESS,
           DENY_ACCESS,
           NO_INHERITANCE);
  
       if (dwres == ERROR_SUCCESS)
       {
           grant = 0;
           bool b = CanAccessFolder(L"C:\\Deny\\file.txt", access_mask, grant);
           printMasks(grant);
       }
       else
       {
           std::cout &lt;&lt; "Error   :   " &lt;&lt; GetLastError() &lt;&lt; '\n';
       }
       HANDLE hFile = CreateFileW(L"C:\\Deny\\file.txt",               // file name 
           GENERIC_READ,          // open for reading 
           0,                     // do not share 
           NULL,                  // default security 
           OPEN_EXISTING,         // existing file only 
           FILE_ATTRIBUTE_NORMAL, // normal file 
           NULL);                 // no template 
       if (hFile == INVALID_HANDLE_VALUE)
       {
           std::cout &lt;&lt; "CreateFileW1 Error  :  " &lt;&lt; GetLastError() &lt;&lt; '\n';
       }
  
   // ?????????????????????? GRANT ACCESS ?????????????????????????????????
  
       std::cout &lt;&lt; "After granting access \n";
       DWORD dwres1 = AddAceToObjectsSecurityDescriptor(
           L"C:\\Deny\\file.txt",
           SE_FILE_OBJECT,
           FILE_GENERIC_READ | FILE_GENERIC_WRITE,
           GRANT_ACCESS,
           NO_INHERITANCE);
  
       if (dwres1 == ERROR_SUCCESS)
       {
           grant = 0;
           bool b = CanAccessFolder(L"C:\\Deny\\file.txt", access_mask, grant);
           printMasks(grant);
       }
       else
       {
           std::cout &lt;&lt; "Error   :   " &lt;&lt; GetLastError() &lt;&lt; '\n';
       }
       HANDLE hFile1 = CreateFileW(L"C:\\Deny\\file.txt",               // file name 
           GENERIC_READ,          // open for reading 
           0,                     // do not share 
           NULL,                  // default security 
           OPEN_EXISTING,         // existing file only 
           FILE_ATTRIBUTE_NORMAL, // normal file 
           NULL);                 // no template 
       if (hFile1 == INVALID_HANDLE_VALUE)
       {
           std::cout &lt;&lt; "CreateFileW2 Error  :  " &lt;&lt; GetLastError() &lt;&lt; '\n';
       }
  
       return 0;
   }
  </code></pre>
  
  <p>I get the output for this code as below</p>
  
  <pre><code>Before modification
  Effective Allowed Access Mask :  2032127
  Full Control
  Read
  Write
  Execute
  After removing access
  Effective Allowed Access Mask :  0
  CreateFileW1 Error  :  5
  After granting access
  Effective Allowed Access Mask :  0
  </code></pre>
  
  <p>After granting permissions I can access the file "file.txt", I can open it/write to it (e.g. CreateFileW passes)</p>
  
  <p>What I dont understand is the mystery behind the permission bits, which is displayed as <code>0</code> even though I have granted the permissions <code>FILE_GENERIC_READ | FILE_GENERIC_WRITE</code> to the <code>CURRENT_USER</code> trustee. </p>
  
  <p>I also checked the DAC List using <code>icacls</code> and it gave me following output</p>
  
  <pre><code>C:\&gt;icacls C:\Deny\file.txt
  C:\Deny\file.txt DOMAIN\user:(DENY)(D,WDAC,WO,X,DC)
                   DOMAIN\user:(R,W)
                   NT AUTHORITY\Authenticated Users:(I)(F)
                   DOMAIN\user:(I)(F)
                   BUILTIN\Users:(I)(F)
                   BUILTIN\Administrators:(I)(F)
                   NT AUTHORITY\SYSTEM:(I)(F)
  </code></pre>
  
  <p>This tells me that my <code>GRANT</code> permissions ACE got pushed below the <code>DENY</code> one and this is a <a href="https://blogs.msdn.microsoft.com/oldnewthing/20070608-00/?p=26503" rel="nofollow noreferrer">well documented behavior</a>. </p>
  
  <p>Is this why I am getting the flag value as <code>0</code> ?</p>
  
  <p>Is there any way/API/function that can get me the correct flags i.e. which can tell that <code>FILE_GENERIC_READ</code> and <code>FILE_GENERIC_WRITE</code> are set ? </p>