Control Access and Object Access

Overview

Windows implements a robust security model that controls who can access system objects and what actions they can perform. This page covers the core concepts of Access Control Lists (ACLs), access tokens, and object-specific permissions in the Win32 API.

Key Concepts

Access Control Lists (ACLs)

ACLs consist of Access Control Entries (ACEs) that define allow or deny permissions for users and groups. Two types exist:

  • DACL – Discretionary ACL, controls access to an object.
  • SACL – System ACL, used for auditing.

Example of a DACL in C++:

C++
#include <windows.h>
SECURITY_DESCRIPTOR sd;
InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION);
EXPLICIT_ACCESS ea = {0};
ea.grfAccessPermissions = GENERIC_READ | GENERIC_WRITE;
ea.grfAccessMode = SET_ACCESS;
ea.grfInheritance = SUB_CONTAINERS_AND_OBJECTS_INHERIT;
ea.Trustee.TrusteeForm = TRUSTEE_IS_NAME;
ea.Trustee.TrusteeType = TRUSTEE_IS_USER;
ea.Trustee.ptstrName = L"DOMAIN\\User";
SetEntriesInAcl(1, &ea, NULL, &sd);
Access Tokens

An access token represents the security context of a process or thread. It contains the user SID, group SIDs, privileges, and the default DACL.

Retrieving the current token:

C++
HANDLE token;
OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &token);
TOKEN_GROUPS *groups;
DWORD size;
GetTokenInformation(token, TokenGroups, NULL, 0, &size);
groups = (TOKEN_GROUPS*)malloc(size);
GetTokenInformation(token, TokenGroups, groups, size, &size);
Impersonation

Impersonation allows a thread to adopt a different security context temporarily. Commonly used in server applications.

Example of impersonation with a client token:

C++
HANDLE clientToken;
ImpersonateLoggedOnUser(clientToken);
// Perform actions as the client
RevertToSelf();

Practical Example – Securing a File

Below is a complete snippet that creates a file with a custom DACL granting read/write access to a specific user while denying delete rights.

C++
#include <windows.h>
#include <aclapi.h>

int main() {
    WCHAR *filename = L"C:\\SecureFolder\\demo.txt";
    HANDLE hFile = CreateFileW(filename, GENERIC_WRITE, 0, NULL,
                               CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
    if (hFile == INVALID_HANDLE_VALUE) return 1;

    PSID userSid = NULL;
    SID_IDENTIFIER_AUTHORITY ntauthority = SECURITY_NT_AUTHORITY;
    AllocateAndInitializeSid(&ntauthority, 1,
        SECURITY_BUILTIN_DOMAIN_RID,
        DOMAIN_ALIAS_RID_USERS, 0,0,0,0,0,0, &userSid);

    EXPLICIT_ACCESS ea[2];
    ZeroMemory(&ea, sizeof(ea));
    ea[0].grfAccessPermissions = FILE_GENERIC_READ | FILE_GENERIC_WRITE;
    ea[0].grfAccessMode = SET_ACCESS;
    ea[0].grfInheritance = SUB_CONTAINERS_AND_OBJECTS_INHERIT;
    ea[0].Trustee.TrusteeForm = TRUSTEE_IS_SID;
    ea[0].Trustee.TrusteeType = TRUSTEE_IS_USER;
    ea[0].Trustee.ptstrName = (LPWSTR)userSid;

    ea[1].grfAccessPermissions = DELETE;
    ea[1].grfAccessMode = DENY_ACCESS;
    ea[1].grfInheritance = SUB_CONTAINERS_AND_OBJECTS_INHERIT;
    ea[1].Trustee = ea[0].Trustee;

    PACL acl = NULL;
    SetEntriesInAcl(2, ea, NULL, &acl);

    PSECURITY_DESCRIPTOR sd = (PSECURITY_DESCRIPTOR)LocalAlloc(LPTR, SECURITY_DESCRIPTOR_MIN_LENGTH);
    InitializeSecurityDescriptor(sd, SECURITY_DESCRIPTOR_REVISION);
    SetSecurityDescriptorDacl(sd, TRUE, acl, FALSE);
    SetSecurityInfo(hFile, SE_FILE_OBJECT, DACL_SECURITY_INFORMATION,
                    NULL, NULL, acl, NULL);
    CloseHandle(hFile);
    FreeSid(userSid);
    LocalFree(sd);
    LocalFree(acl);
    return 0;
}