Creating a Security Descriptor from Scratch for a New Object, a Registry key Code Example
The following example creates a security descriptor for a new registry key using the following steps. Similar code can be used to create a security descriptor for other object types.
The example fills an array of EXPLICIT_ACCESS structures with the information for two ACEs. One ACE allows read access to everyone; the other ACE allows full access to administrators. The EXPLICIT_ACCESS array is passed to the SetEntriesInAcl() function to create a DACL for the security descriptor. After allocating memory for the security descriptor, the example calls the InitializeSecurityDescriptor() and SetSecurityDescriptorDacl() functions to initialize the security descriptor and attach the DACL. The security descriptor is then stored in a SECURITY_ATTRIBUTES structure and passed to the RegCreateKeyEx() function, which attaches the security descriptor to the newly created key.
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 a security descriptor for a new object, a registry key...
#include <windows.h>
#include <stdio.h>
#include <aclapi.h>
// Buffer clean up routine
void Cleanup(PSID pEveryoneSID, PSID pAdminSID, PACL pACL, PSECURITY_DESCRIPTOR pSD, HKEY hkSub)
{
if(pEveryoneSID)
FreeSid(pEveryoneSID);
if(pAdminSID)
FreeSid(pAdminSID);
if(pACL)
LocalFree(pACL);
if(pSD)
LocalFree(pSD);
if(hkSub)
RegCloseKey(hkSub);
}
int wmain(int argc, WCHAR **argv)
{
DWORD dwRes, dwDisposition;
PSID pEveryoneSID = NULL, pAdminSID = NULL;
PACL pACL = NULL;
PSECURITY_DESCRIPTOR pSD = {0};
// An array of EXPLICIT_ACCESS structure
EXPLICIT_ACCESS ea[2];
SID_IDENTIFIER_AUTHORITY SIDAuthWorld = SECURITY_WORLD_SID_AUTHORITY;
SID_IDENTIFIER_AUTHORITY SIDAuthNT = SECURITY_NT_AUTHORITY;
SECURITY_ATTRIBUTES sa = {0};
LONG lRes;
HKEY hkSub = NULL;
// Create a well-known SID for the Everyone group.
if(!AllocateAndInitializeSid(&SIDAuthWorld, 1, SECURITY_WORLD_RID, 0, 0, 0, 0, 0, 0, 0, &pEveryoneSID))
{
wprintf(LAllocateAndInitializeSid() failed, error %u\n, GetLastError());
Cleanup(pEveryoneSID, pAdminSID, pACL, pSD, hkSub);
}
else
wprintf(LSID for the Everyone group was allocated and initialized!\n);
// Initialize an EXPLICIT_ACCESS structure for an ACE.
// The ACE will allow Everyone read access to the key.
ZeroMemory(&ea, 2 * sizeof(EXPLICIT_ACCESS));
ea[0].grfAccessPermissions = KEY_READ;
ea[0].grfAccessMode = SET_ACCESS;
ea[0].grfInheritance= NO_INHERITANCE;
ea[0].Trustee.TrusteeForm = TRUSTEE_IS_SID;
ea[0].Trustee.TrusteeType = TRUSTEE_IS_WELL_KNOWN_GROUP;
ea[0].Trustee.ptstrName = (LPTSTR) pEveryoneSID;
// Create a SID for the BUILTIN\Administrators group.
if(!AllocateAndInitializeSid(&SIDAuthNT, 2, SECURITY_BUILTIN_DOMAIN_RID,
DOMAIN_ALIAS_RID_ADMINS,
0, 0, 0, 0, 0, 0,
&pAdminSID))
{
wprintf(LAllocateAndInitializeSid() failed, error %u\n, GetLastError());
Cleanup(pEveryoneSID, pAdminSID, pACL, pSD, hkSub);
}
else
wprintf(LSID for the BUILTIN\\Administrators group was allocated and initialized!\n);
// Initialize an EXPLICIT_ACCESS structure for an ACE.
// The ACE will allow the Administrators group full access to the key.
ea[1].grfAccessPermissions = KEY_ALL_ACCESS;
ea[1].grfAccessMode = SET_ACCESS;
ea[1].grfInheritance= NO_INHERITANCE;
ea[1].Trustee.TrusteeForm = TRUSTEE_IS_SID;
ea[1].Trustee.TrusteeType = TRUSTEE_IS_GROUP;
ea[1].Trustee.ptstrName = (LPTSTR) pAdminSID;
// Create a new ACL that contains the new ACEs.
dwRes = SetEntriesInAcl(2, ea, NULL, &pACL);
if(dwRes != ERROR_SUCCESS)
{
wprintf(LSetEntriesInAcl() failed, error %u\n, GetLastError());
Cleanup(pEveryoneSID, pAdminSID, pACL, pSD, hkSub);
}
else
wprintf(LSetEntriesInAcl() for the Administrators group is OK\n);
// Initialize a security descriptor.
pSD = (PSECURITY_DESCRIPTOR) LocalAlloc(LPTR, SECURITY_DESCRIPTOR_MIN_LENGTH);
if(pSD == NULL)
{
wprintf(LLocalAlloc() for pSD failed, error %u\n, GetLastError());
Cleanup(pEveryoneSID, pAdminSID, pACL, pSD, hkSub);
}
else
wprintf(LLocalAlloc() for pSD is OK!\n);
if(!InitializeSecurityDescriptor(pSD, SECURITY_DESCRIPTOR_REVISION))
{
wprintf(LInitializeSecurityDescriptor() failed, error %u\n, GetLastError());
Cleanup(pEveryoneSID, pAdminSID, pACL, pSD, hkSub);
}
else
wprintf(LInitializeSecurityDescriptor() is pretty fine!\n);
// Add the ACL to the security descriptor.
if(!SetSecurityDescriptorDacl(pSD,
TRUE, // bDaclPresent flag
pACL,
FALSE)) // not a default DACL
{
wprintf(LSetSecurityDescriptorDacl() failed, error %u\n, GetLastError());
Cleanup(pEveryoneSID, pAdminSID, pACL, pSD, hkSub);
}
else
wprintf(LSetSecurityDescriptorDacl() is OK!\n);
// Initialize a security attributes structure.
sa.nLength = sizeof (SECURITY_ATTRIBUTES);
sa.lpSecurityDescriptor = pSD;
sa.bInheritHandle = FALSE;
// Use the security attributes to set the security descriptor
// when you create a registry key.
lRes = RegCreateKeyEx(
HKEY_CURRENT_USER, // handle to an open key
LMyTestRegKey, // name of the subkey
0, // Reserved
L, // class or object type of this key, may be ignored
0, // Options
KEY_READ | KEY_WRITE, // Access right for the key
&sa, // Pointer to security attribute structure,
// can be inherited or not. NULL is not inherited
&hkSub, // variable that receives a handle to the opened or created key
&dwDisposition); // variable that receives:
// REG_CREATED_NEW_KEY - create new key (non-exist)
// REG_OPENED_EXISTING_KEY - just open the existing key (already exist)
// If successful
if(lRes == 0)
{
wprintf(LThe value of the \'dwDisposition\': %u\n, dwDisposition);
wprintf(LHKEY_CURRENT_USER\\MyTestRegKey successfully created.\n);
}
else
wprintf(LCreating and opening HKEY_CURRENT_USER\\MyTestRegKey was failed, error %u.\n, GetLastError());
return 0;
}
Build and run the project. The following screenshot is a sample output.
Then, let verify the result using the regedt32/regedit registry tool.
Don’t forget to delete the registry key that has been created.