Setting File Permissions on Windows With C

Edit 2018-01-19

In my original article I have naively supposed that the group names are not localized. This is false. Always use the Well Known Security IDs when manipulating permissions on Windows.


I’ve spent good part of my morning trying to find a way how to set permissions to a particular group.

Finally while digging though Stack Overflow I have found this question which lead to another because of deprecation errors.

My final version of the code to add file read and write permissions to the group Users is this:

#include <Windows.h>
#include <AccCtrl.h>
#include <Aclapi.h>

const char* fileName = "C:/path/to/your_file.txt";

DWORD result = 0;

PACL pDACL = NULL;
PACL pOldDACL = NULL;
PSECURITY_DESCRIPTOR pSD = NULL;
EXPLICIT_ACCESS ea;
PSID pUsersSID = NULL;

const auto cleanup = [pDACL, pOldDACL, pSD, pUsersSID](){
  if (pOldDACL) LocalFree(pOldDACL);
  if (pDACL) LocalFree(pDACL);
  if (pSD) LocalFree(pSD);
  if (pUsersSID) FreeSid(pUsersSID);
};

result = GetNamedSecurityInfo(static_cast<LPTSTR>(fileName), SE_FILE_OBJECT, DACL_SECURITY_INFORMATION, NULL, NULL, &pOldDACL, NULL, &pSD);
if (result != ERROR_SUCCESS) {
  std::cerr << "Failed to get the security info [" << result << "]" << std::endl;
  cleanup();
  return EReturnCode_Error;
}

ZeroMemory(&ea, sizeof(EXPLICIT_ACCESS));

SID_IDENTIFIER_AUTHORITY SIDAuthNT = {SECURITY_NT_AUTHORITY};
if (!AllocateAndInitializeSid(&SIDAuthNT, 2, SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_USERS, 0, 0, 0, 0, 0, 0, &pUsersSID)) {
  std::cerr << "Failed to allocate SID" << std::endl;
  cleanup();
  return EReturnCode_Error;
}

ea.grfAccessPermissions = FILE_GENERIC_WRITE | FILE_GENERIC_READ;
ea.grfAccessMode = SET_ACCESS;
ea.grfInheritance = CONTAINER_INHERIT_ACE | OBJECT_INHERIT_ACE;
ea.Trustee.TrusteeForm = TRUSTEE_IS_SID;
ea.Trustee.TrusteeType = TRUSTEE_IS_WELL_KNOWN_GROUP;
ea.Trustee.ptstrName = reinterpret_cast<LPTSTR>(pUsersSID);

result = SetEntriesInAcl(1, &ea, pOldDACL, &pDACL);
if (result != ERROR_SUCCESS) {
  std::cerr << "Failed to set entries in the access control list [" << result << "]" << std::endl;
  cleanup();
  return EReturnCode_Error;
}

result = SetNamedSecurityInfo(static_cast<LPTSTR>(fileName), SE_FILE_OBJECT, DACL_SECURITY_INFORMATION, NULL, NULL, pDACL, NULL);
if (result != ERROR_SUCCESS) {
  std::cerr << "Failed to set the security info [" << result << "]" << std::endl;
  cleanup();
  return EReturnCode_Error;
}

cleanup();

Note: You will also need to link your program with Advapi32.lib.


My original code follows, do not use this:

const char* fileName = "C:/path/to/your_file.txt";
PACL pDACL = NULL;    
PACL pOldDACL = NULL;
PSECURITY_DESCRIPTOR pSD = NULL;
EXPLICIT_ACCESS ea;

GetNamedSecurityInfo(static_cast<LPTSTR>(fileName), SE_FILE_OBJECT, 
                     DACL_SECURITY_INFORMATION, NULL, NULL, 
                     &pOldDACL, NULL, &pSD);

ZeroMemory(&ea, sizeof(EXPLICIT_ACCESS));

char groupUsersName[6] = {"USERS"};
ea.grfAccessPermissions = FILE_GENERIC_WRITE | FILE_GENERIC_READ;
ea.grfAccessMode = SET_ACCESS;
ea.grfInheritance = CONTAINER_INHERIT_ACE | OBJECT_INHERIT_ACE;
ea.Trustee.TrusteeForm = TRUSTEE_IS_NAME;
ea.Trustee.TrusteeType = TRUSTEE_IS_GROUP;
ea.Trustee.ptstrName = groupUsersName;

SetEntriesInAcl(1, &ea, pOldDACL, &pDACL);

SetNamedSecurityInfo(static_cast<LPTSTR>(fileName), SE_FILE_OBJECT, 
                     DACL_SECURITY_INFORMATION, NULL, NULL, pDACL, NULL);