Let's assume that we have a parent_folder
folder on our Windows desktop, inside of which we have created a test.txt
file.
This file has FILE_EXECUTE
permissions by default after creation. As far as I understand, this file inherits these permissions from the parent parent_folder
folder because we did not explicitly set these permissions for this file. Inheritance is also confirmed by the fact that ACE_HEADER::AceFlags
of this file contains the INHERITED_ACE
flag (proof is below).
#include <aclapi.h>
#include <windows.h>
#include <stdio.h>
#include <iostream>
#include <sddl.h>
int main()
{
wchar_t objectName[] = L"C:\\Users\\Username\\Desktop\\parent_folder\\test.txt";
wchar_t trusteeSID[] = L"S-1-5-21-#-#-#-#";
PSID pSid;
if (!ConvertStringSidToSid(trusteeSID, &pSid)) {
std::cout << "ConvertStringSidToSid failed\n";
return 0;
}
PACL pOldDACL = NULL;
PSECURITY_DESCRIPTOR pSD = NULL;
DWORD dwRes = GetNamedSecurityInfo(objectName, SE_FILE_OBJECT,
DACL_SECURITY_INFORMATION,
NULL, NULL, &pOldDACL, NULL, &pSD);
if (ERROR_SUCCESS != dwRes) {
printf("GetNamedSecurityInfo Error %u\n", dwRes);
return EXIT_FAILURE;
}
for (WORD i = 0; i < pOldDACL->AceCount; i++)
{
PACE_HEADER header;
GetAce(pOldDACL, i, (PVOID*)&header);
auto ace = (ACCESS_DENIED_ACE*)header;
if (EqualSid((PSID)&ace->SidStart, pSid) != 0)
{
if ((header->AceFlags & INHERITED_ACE) == INHERITED_ACE)
{
std::cout << "This ACE is inherited\n";
if ((ace->Mask & FILE_EXECUTE) == FILE_EXECUTE)
{
std::cout << "FILE_EXECUTE rights exists\n";
}
std::cout << "Ace type: " << (header->AceType == ACCESS_ALLOWED_ACE_TYPE) << std::endl;
}
}
}
}
Now if I Deny FILE_EXECUTE
on parent_folder
, test.txt
still has FILE_EXECUTE
flag. My question is why does this happen, since we have Deny FILE_EXECUTE
on the parent folder? I do Deny FILE_EXECUTE
for the parent_folder like this:
#include <aclapi.h>
#include <windows.h>
#include <stdio.h>
#include <iostream>
DWORD AddAceToObjectsSecurityDescriptor(
LPTSTR pszObjName, // name of object
SE_OBJECT_TYPE ObjectType, // type of object
LPTSTR pszTrustee, // trustee for new ACE
TRUSTEE_FORM TrusteeForm, // format of trustee structure
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, &pOldDACL, NULL, &pSD);
if (ERROR_SUCCESS != dwRes) {
printf("GetNamedSecurityInfo Error %u\n", dwRes);
goto Cleanup;
}
// Initialize an EXPLICIT_ACCESS structure for the new ACE.
ZeroMemory(&ea, sizeof(EXPLICIT_ACCESS));
ea.grfAccessPermissions = dwAccessRights;
ea.grfAccessMode = AccessMode;
ea.grfInheritance = dwInheritance;
ea.Trustee.TrusteeForm = TrusteeForm;
ea.Trustee.ptstrName = pszTrustee;
// Create a new ACL that merges the new ACE
// into the existing DACL.
dwRes = SetEntriesInAcl(1, &ea, pOldDACL, &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;
}
#include <sddl.h>
int main()
{
wchar_t objectName[] = L"C:\\Users\\Username\\Desktop\\parent_folder";
wchar_t trusteeSID[] = L"S-1-5-21-#-#-#-#";
PSID pSid;
if (!ConvertStringSidToSid(trusteeSID, &pSid)) {
std::cout << "ConvertStringSidToSid failed\n";
return 0;
}
AddAceToObjectsSecurityDescriptor(objectName, SE_FILE_OBJECT, (PWSTR)pSid, TRUSTEE_IS_SID, FILE_EXECUTE, DENY_ACCESS, NO_INHERITANCE);
}
Even though I Deny FILE_EXECUTE
for the parent folder, I still get an inherited ACE with FILE_EXECUTE
permission for the file test.txt
. Where does this permission come from if we took it away from the parent folder and by the way, what does FILE_EXECUTE
for folders? Can folders be executable?