Modifying Existing DACLs of an Object Program Example
The following example adds an ACE to the DACL of an existing object. The AccessMode parameter, a member of the EXPLICIT_ACCESS structure determines the type of new ACE and how the new ACE is combined with any existing ACEs for the specified trustee. You can use the GRANT_ACCESS, SET_ACCESS, DENY_ACCESS, or REVOKE_ACCESS flags in the AccessMode parameter. Similar code can be used to work with a SACL. Specify SACL_SECURITY_INFORMATION in the GetNamedSecurityInfo() and SetNamedSecurityInfo() functions to get and set the SACL for the object. Use the SET_AUDIT_SUCCESS, SET_AUDIT_FAILURE, and REVOKE_ACCESS flags in the AccessMode parameter. This code example can be used to add an object-specific ACE to the DACL of a directory service object. To specify the GUIDs in an object-specific ACE, set the TrusteeForm parameter to TRUSTEE_IS_OBJECTS_AND_NAME or TRUSTEE_IS_OBJECTS_AND_SID and set the pszTrustee parameter to be a pointer to an OBJECTS_AND_NAME or OBJECTS_AND_SID structure. This example uses the GetNamedSecurityInfo() function to get the existing DACL. Then it fills an EXPLICIT_ACCESS structure with information about an ACE and uses the SetEntriesInAcl() function to merge the new ACE with any existing ACEs in the DACL. Finally, the example calls the SetNamedSecurityInfo() function to attach the new DACL to the security descriptor of the object. The following figures are the NewDACLDir directory property pages before the program been run.
Create a new empty Win32 console application project. Give a suitable project name and change the project location if needed.
Then, add the source file and give it a suitable name.
Next, add the following source code.
// Modifying DACL of an object. In ACL there are ACEs...
// Here we are going to add deny standard right
// access for Administrators group. This Win XP machine is
// logged in by user named Mike spoon who is a member of Administrators group
#include <windows.h>
#include <aclapi.h>
#include <stdio.h>
// Clean up the allocated resources
void Cleanup(PSECURITY_DESCRIPTOR pSD, PACL pNewDACL)
{
if(pSD != NULL)
LocalFree((HLOCAL) pSD);
else
wprintf(LpSD freed up\n);
if(pNewDACL != NULL)
LocalFree((HLOCAL) pNewDACL);
else
wprintf(LpNewDACL freed up\n);
}
int wmain(int argc, WCHAR **argv)
{
// Name of object, here we will add ACE for a directory
// the directory is already created
LPTSTR pszObjName = L\\\\?\\C:\\NewDACLDir;
// Type of object, file or directory. Here we test on directory
SE_OBJECT_TYPE ObjectType = SE_FILE_OBJECT;
// Access mask for new ACE equal to 0x001F0000 flags (bit 0 till 15)
DWORD dwAccessRights = STANDARD_RIGHTS_ALL;
// Type of ACE, Access denied ACE
ACCESS_MODE AccessMode = DENY_ACCESS;
// Inheritance flags for new the ACE. The OBJECT_INHERIT_ACE and
// CONTAINER_INHERIT_ACE flags are
// not propagated to an inherited ACE.
DWORD dwInheritance = NO_PROPAGATE_INHERIT_ACE;
// format of trustee structure, the trustee is name
TRUSTEE_FORM TrusteeForm = TRUSTEE_IS_NAME;
// Trustee for new ACE. This just for fun...When you run once, only one
// element will take effect. By changing the first array element we
// can change to other trustee and re run the program....
// Other than Mike spoon, they are all well known trustees
// Take note the localization issues
WCHAR pszTrustee[4][15] = {LAdministrators, LSystem, LUsers, LMike spoon};
// Result
DWORD dwRes = 0;
// Existing and new DACL pointers...
PACL pOldDACL = NULL, pNewDACL = NULL;
// Security descriptor
PSECURITY_DESCRIPTOR pSD = NULL;
SecureZeroMemory(&pSD, sizeof(PSECURITY_DESCRIPTOR));
// EXPLICIT_ACCESS structure. For more than one entries,
// declare an array of the EXPLICIT_ACCESS structure
EXPLICIT_ACCESS ea;
// Verify the object name validity
if(pszObjName == NULL)
{
wprintf(LThe object name is invalid!\n);
return ERROR_INVALID_PARAMETER;
}
else
wprintf(LThe object name is valid, \%s\\n, pszObjName);
// Verify that our new trustee strings is OK
for(int i = 0; i <= 3; i++)
wprintf(LTest pointer #%d: %s\n, i, pszTrustee[i]);
// Get a pointer to the existing DACL.
dwRes = GetNamedSecurityInfo(pszObjName, ObjectType,
DACL_SECURITY_INFORMATION,
NULL,
NULL,
&pOldDACL,
NULL,
&pSD);
// Verify
if(dwRes != ERROR_SUCCESS)
{
wprintf(LGetNamedSecurityInfo() failed, error %u\n, dwRes);
Cleanup(pSD, pNewDACL);
}
else
wprintf(LGetNamedSecurityInfo() is OK\n);
// Initialize an EXPLICIT_ACCESS structure for the new ACE.
// For more entries, declare an array of the EXPLICIT_ACCESS structure
SecureZeroMemory(&ea, sizeof(EXPLICIT_ACCESS));
ea.grfAccessPermissions = dwAccessRights;
ea.grfAccessMode = AccessMode;
ea.grfInheritance= dwInheritance;
ea.Trustee.TrusteeForm = TrusteeForm;
// Test for Administrators group, a new trustee for the ACE
// For other trustees, you can try changing
// the array index to 1, 2 and 3 and rerun, see the effect
ea.Trustee.ptstrName = (LPTSTR)(pszTrustee[0]);
// Create a new ACL that merges the new ACE into the existing DACL.
dwRes = SetEntriesInAcl(1, &ea, pOldDACL, &pNewDACL);
// Verify
if(dwRes != ERROR_SUCCESS)
{
wprintf(LSetEntriesInAcl() failed, error %u\n, dwRes);
Cleanup(pSD, pNewDACL);
}
else
wprintf(LSetEntriesInAcl() working fine!\n);
// Attach the new ACL as the object's DACL.
dwRes = SetNamedSecurityInfo(pszObjName, ObjectType,
DACL_SECURITY_INFORMATION,
NULL,
NULL,
pNewDACL,
NULL);
if(dwRes != ERROR_SUCCESS)
{
wprintf(LSetNamedSecurityInfo() failed, error %u\n, dwRes);
Cleanup(pSD, pNewDACL);
}
wprintf(LSetNamedSecurityInfo() is OK\n);
return 0;
}
Build and run the project. The following screenshot is a sample output.
Then verify through the C:\NewDACLDir directory property pages again.
Under the Permission for Administrators group, the Special Permissions is ticked for the Deny permission. Keep in mind that Deny overrides the Allow permission. The following figure also confirmed that our new ACE for the Deny is not inherited.
Remember that, DENY overwrites ALLOW permission. For this case because Mike spoon is a member of the Administrators group, however he cannot delete or open the C:\\NewDACLDir directory. We have to log off and login again as other Administrators group user or create another user that is a member of Administrators or take the object’s ownership or just edit the permission entries (shown at the end of this section). When we try to delete the folder, the following message was displayed. Well, it funny isn’t it? A user of Administrators group cannot delete/open his/her own folder.
It is same when we want to open the folder, it is not accessible.
So, whatever it is, please don’t mess up your machine. The following steps show how to re-enable the Full Control for Administrators group.