Creating DACL and SACL with the Privilege Program Example
The following program example try to create an ACL that contains both the DACL and SACL For the SACL we need to enable the SeSecurityPrivilege privilege by using the AdjustTokenPrivileges().
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.
// Creating an ACL-DACL & SACL, need the required privilege for SACL
// The following #define must be the 1st statement
// #define _WIN32_WINNT 0x0500
#include <windows.h>
#include <sddl.h>
#include <stdio.h>
// ********** Enabling the privilege ***************
BOOL SetPrivilege(
HANDLE hToken, // access token handle
LPCTSTR lpszPrivilege, // name of privilege to enable/disable
BOOL bEnablePrivilege // to enable (or disable privilege)
)
{
TOKEN_PRIVILEGES tp;
LUID luid;
if(!LookupPrivilegeValue(
NULL, // lookup privilege on local system
lpszPrivilege, // privilege to lookup
&luid)) // receives LUID of privilege
{
wprintf(LLookupPrivilegeValue() failed, error: %u\n, GetLastError());
return FALSE;
}
else
wprintf(LLookupPrivilegeValue() is OK, %s found!\n, lpszPrivilege);
// the number of entries in the Privileges array
tp.PrivilegeCount = 1;
// an array of LUID_AND_ATTRIBUTES structures
tp.Privileges[0].Luid = luid;
// If TRUE
if(bEnablePrivilege)
{
tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
wprintf(LPrivilege was enabled!\n);
}
else
{
tp.Privileges[0].Attributes = 0;
wprintf(LPrivilege was disabled!\n);
}
// Enable the privilege (or disable all privileges)
if(!AdjustTokenPrivileges(
hToken,
FALSE, // If TRUE, function disables all privileges,
// if FALSE the function modifies privileges based on the tp
&tp,
sizeof(TOKEN_PRIVILEGES),
(PTOKEN_PRIVILEGES) NULL,
(PDWORD) NULL))
{
wprintf(LAdjustTokenPrivileges() failed, error: %u\n, GetLastError());
return FALSE;
}
else
wprintf(LAdjustTokenPrivileges() is OK!\n);
return TRUE;
}
//********************** Create the ACL *****************
// CreateMyACL() routine.
// The return value is FALSE if the address to the structure is NULL.
// Otherwise, this function returns the value from the
// ConvertStringSecurityDescriptorToSecurityDescriptor function.
BOOL CreateMyACL(SECURITY_ATTRIBUTES * pSA)
{
// Define the SDDL for the DACL & SACL.
WCHAR * szSD = LD: // DACL
L(D;OICI;GRLOFR;;;AN) // Deny Anonymous some rights
L(A;;RPWPCCDCLCRCWOWDSDSW;;;SY) // Allow System some rights
L(A;OICI;GACCFA;;;LA) // Allow Built-in Administrator some rights
L(A;OICI;GACCFA;;;S-1-5-11) // Allow Authenticated user some rights
LS: // SACL
L(OU;SAFA;RPWPCCDCLCRCWOWDSDSW;;;S-1-5-18) // Object audit success/fail, Local systems, using a SID string
L(OU;SAFA;GACCFA;;;AU) // Object audit success/fail, Authenticated users
L(OU;SAFA;GAWPFW;;;LA); // Object audit success/fail, Built-in Administrator
// Verify
if(pSA == NULL)
{
wprintf(LSECURITY_ATTRIBUTES wasn\'t passed properly...\n);
return FALSE;
}
else
wprintf(LSECURITY_ATTRIBUTES was passed properly...\n);
// Do some verification
wprintf(LThe ACE strings:\n%s \n, szSD);
// Convert to security descriptor binary and return
return ConvertStringSecurityDescriptorToSecurityDescriptor(
szSD, // The ACE strings
SDDL_REVISION_1, // Standard revision level
&(pSA->lpSecurityDescriptor), // Pointer to the converted security descriptor
NULL); // The size in byte the converted security descriptor
}
//************ main *******************
int wmain(int argc, WCHAR **argv)
{
WCHAR DirName[] = L\\\\?\\C:\\AnotherTestDirectory;
SECURITY_ATTRIBUTES sa;
LPCTSTR lpszPrivilege = LSeSecurityPrivilege;
// Initially we try to enable
BOOL bEnablePrivilege = TRUE;
// Handle to the running process that is this program
HANDLE hToken;
BOOL bTestRetVal = FALSE;
//*************** Get the handle to the process ****************
// Open a handle to the access token for the calling process.
// That is this running program
if(!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hToken))
{
wprintf(LOpenProcessToken() failed, error %u\n, GetLastError());
return FALSE;
}
else
wprintf(LOpenProcessToken() is OK, got the handle!\n);
//************ Enabling privilege ******************
// Call the user defined SetPrivilege() function to enable privilege
wprintf(LEnabling the privilege...\n);
bTestRetVal = SetPrivilege(hToken, lpszPrivilege, bEnablePrivilege);
// Verify
wprintf(LThe SetPrivilage() return value: %d\n\n, bTestRetVal);
//*************** End enabling privilege *********************
// The SECURITY_ATTRIBUTE structure size
sa.nLength = sizeof(SECURITY_ATTRIBUTES);
// The return handle not inherited
sa.bInheritHandle = FALSE;
// Call CreateMyACL() function to set the DACL and SACL,
// is set in the SECURITY_ATTRIBUTES lpSecurityDescriptor member
if(!CreateMyACL(&sa))
{
// Error encountered; generate message and just exit.
wprintf(LCreateMyACL() failed, error %u.\n, GetLastError());
exit(1);
}
else
wprintf(LCreateMyACL() is OK.\n);
// Use the updated SECURITY_ATTRIBUTES to specify security attributes
// for securable objects. This example uses security attributes
// during creation of a new director
if(CreateDirectory(DirName, &sa) == 0)
{
// Error encountered; generate message and just exit
wprintf(LCreateDirectory() failed, error %d!\n, GetLastError());
exit(1);
}
else
wprintf(LCreateDirectory() - %s was created successfully!\n\n, DirName);
//************* Disable the privilege ****************
wprintf(LDisabling the privilege...\n);
bEnablePrivilege = FALSE;
SetPrivilege(hToken, lpszPrivilege, bEnablePrivilege);
// Verify
wprintf(LThe SetPrivilage() return value: %d\n\n, bTestRetVal);
//************* End disabling the privilege ****************
//************ Clean up ********************
// Release the memory allocated for the SECURITY_DESCRIPTOR
// This means release back the used memory to the system
if(LocalFree(sa.lpSecurityDescriptor) != NULL)
{
// Error encountered; generate message and just exit
wprintf(LLocalFree() failed, error %u.\n, GetLastError());
exit(1);
}
else
wprintf(LLocalFree() - buffer was freed-up!\n);
return 0;
}
Build and run the project. The following screenshot is a sample output.
Let verify through the folder's property page.
Without enabling the required privilege, the CreateDirectory() will fail because we don’t have privilege to create SACL for auditing. In order to test this, delete the created, C:\AnotherTestDirectory directory and comment out the following code portion:
...
/*
//************ Enabling privilege ******************
// Call the user defined SetPrivilege() function to enable privilege
wprintf(LEnabling the privilege...\n);
bTestRetVal = SetPrivilege(hToken, lpszPrivilege, bEnablePrivilege);
// Verify
wprintf(LThe SetPrivilage() return value: %d\n\n, bTestRetVal);
//*************** End enabling privilege *********************
*/
...
Re-run the program, the following output should be expected.
The 1314 (0x522 - ERROR_PRIVILEGE_NOT_HELD) error constant means a required privilege is not held by the client. The attributes of a privilege can be a combination of the following values.
Value |
Meaning |
SE_PRIVILEGE_ENABLED |
The privilege is enabled. |
SE_PRIVILEGE_ENABLED_BY_DEFAULT |
The privilege is enabled by default. |
SE_PRIVILEGE_REMOVED |
Used to remove a privilege. |
SE_PRIVILEGE_USED_FOR_ACCESS |
The privilege was used to gain access to an object or service. This flag is used to identify the relevant privileges in a set passed by a client application that may contain unnecessary privileges. |