Last active
December 29, 2023 08:13
-
-
Save asmichi/daa11b2bf86855f6dde8b6228ca7a8b8 to your computer and use it in GitHub Desktop.
Create a security descriptor with an explicit ACL using Win32 APIs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#define WIN32_LEAN_AND_MEAN | |
#define NOMINMAX | |
#include <Windows.h> | |
#include <AclAPI.h> | |
#include <psapi.h> | |
#include <sddl.h> | |
#include <cassert> | |
#include <cstdio> | |
#include <memory> | |
// Additional References: | |
// - https://learn.microsoft.com/en-us/windows/win32/api/securitybaseapi/nf-securitybaseapi-initializeacl | |
// - https://learn.microsoft.com/en-us/windows/win32/secauthz/taking-object-ownership-in-c-- (trailing hypens are parts of the URI) | |
// - https://learn.microsoft.com/en-us/windows/win32/secauthz/creating-a-security-descriptor-for-a-new-object-in-c-- | |
// Creates a file named "new_file_with_explicit_security" with the security descriptor of "O:<CurrentUserSID>D:(A;;FA;;;<CurrentUserSID>)". | |
// | |
// NOTE: This code leaks on error. Employ RAII for actual code, for example. | |
int wmain(int argc, wchar_t* argv[]) | |
{ | |
DWORD error{}; | |
DWORD dw{}; | |
// | |
// Obtain the user of the current process token. | |
// | |
DWORD tokenUserLength; | |
if (!GetTokenInformation(GetCurrentProcessToken(), TokenUser, nullptr, 0, &tokenUserLength) && GetLastError() != ERROR_INSUFFICIENT_BUFFER) | |
{ | |
std::printf("error: GetTokenInformation failed: %d\n", GetLastError()); | |
return 1; | |
} | |
auto tokenUserBuf = std::make_unique<std::byte[]>(tokenUserLength); | |
if (!GetTokenInformation(GetCurrentProcessToken(), TokenUser, tokenUserBuf.get(), tokenUserLength, &dw)) | |
{ | |
std::printf("error: GetTokenInformation failed: %d\n", GetLastError()); | |
return 1; | |
} | |
const TOKEN_USER* pTokenUser = reinterpret_cast<TOKEN_USER*>(tokenUserBuf.get()); | |
// There are currently no attributes defined for user security identifiers (SIDs). | |
// https://learn.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-token_user | |
assert(pTokenUser->User.Attributes == 0); | |
// | |
// Print the user | |
// | |
LPWSTR sidString{}; | |
if (!ConvertSidToStringSidW(pTokenUser->User.Sid, &sidString)) | |
{ | |
std::printf("error: ConvertSidToStringSidW failed: %d\n", GetLastError()); | |
return 1; | |
} | |
std::printf("User of the current process token: %ls\n", sidString); | |
LocalFree(sidString); | |
sidString = nullptr; | |
// | |
// Create an ACL that has one ACCESS_ALLOWED_ACE granting full control to the current user (and not others). | |
// | |
// https://learn.microsoft.com/en-us/windows/win32/api/aclapi/nf-aclapi-setentriesinaclw | |
// https://learn.microsoft.com/en-us/windows/win32/api/accctrl/ns-accctrl-explicit_access_w | |
// https://learn.microsoft.com/en-us/windows/win32/api/accctrl/ns-accctrl-trustee_w | |
// | |
PACL pAcl{}; | |
EXPLICIT_ACCESSW ea{}; | |
ea.grfAccessPermissions = FILE_ALL_ACCESS; | |
ea.grfAccessMode = SET_ACCESS; | |
ea.grfInheritance = NO_INHERITANCE; | |
ea.Trustee.TrusteeForm = TRUSTEE_IS_SID; | |
ea.Trustee.TrusteeType = TRUSTEE_IS_USER; | |
ea.Trustee.ptstrName = reinterpret_cast<LPWCH>(pTokenUser->User.Sid); | |
if ((error = SetEntriesInAclW(1, &ea, nullptr, &pAcl) != ERROR_SUCCESS)) | |
{ | |
std::printf("error: SetEntriesInAclW failed: %d\n", error); | |
return 1; | |
} | |
// | |
// Create the security descriptor | |
// | |
SECURITY_DESCRIPTOR sd{}; | |
static_assert(sizeof(sd) >= SECURITY_DESCRIPTOR_MIN_LENGTH); | |
if (!InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION)) | |
{ | |
std::printf("error: InitializeSecurityDescriptor failed: %d\n", GetLastError()); | |
return 1; | |
} | |
if (!SetSecurityDescriptorDacl(&sd, TRUE, pAcl, FALSE)) | |
{ | |
std::printf("error: SetSecurityDescriptorDacl failed: %d\n", GetLastError()); | |
return 1; | |
} | |
if (!SetSecurityDescriptorOwner(&sd, pTokenUser->User.Sid, FALSE)) | |
{ | |
std::printf("error: SetSecurityDescriptorOwner failed: %d\n", GetLastError()); | |
return 1; | |
} | |
// NOTE: We may also want SetSecurityDescriptorControl | |
// | |
// Print the SDDL representation of the security descriptor | |
// | |
LPWSTR sdString{}; | |
if (!ConvertSecurityDescriptorToStringSecurityDescriptorW( | |
&sd, | |
SDDL_REVISION_1, | |
OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION | SACL_SECURITY_INFORMATION, | |
&sdString, | |
nullptr)) | |
{ | |
std::printf("error: ConvertSecurityDescriptorToStringSecurityDescriptorW failed: %d\n", GetLastError()); | |
return 1; | |
} | |
std::printf("Created security descriptor: %ls\n", sdString); | |
LocalFree(sdString); | |
sdString = nullptr; | |
// | |
// Create a file named "new_file_with_explicit_security" with the security descriptor | |
// | |
SECURITY_ATTRIBUTES sa{}; | |
sa.nLength = sizeof(sa); | |
sa.bInheritHandle = FALSE; | |
sa.lpSecurityDescriptor = &sd; | |
HANDLE hFile = CreateFileW( | |
L"new_file_with_explicit_security", | |
GENERIC_READ | GENERIC_WRITE, | |
0, | |
&sa, | |
CREATE_ALWAYS, | |
FILE_ATTRIBUTE_NORMAL, | |
nullptr); | |
if (hFile == INVALID_HANDLE_VALUE) | |
{ | |
std::printf("error: CreateFileW failed: %d\n", GetLastError()); | |
return 1; | |
} | |
CloseHandle(hFile); | |
LocalFree(pAcl); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment