I needed to grant access to a file on Windows in a c++ program. I browsed around and copy/pasted code from MSDN and came up with the following. It has been working as far as I can tell.
But then today I stumbled across a warning in MSDN for the use of AddAccessAllowedAceEx, which says: "The caller must ensure that ACEs are added to the DACL in the correct order.". It then refers the reader to this: http://msdn.microsoft.com/en-us/library/windows/desktop/aa379298(v=vs.85).aspx
So, my request is for any seasoned Windows programmer to review my code below and tell me if I am going to have problems vis-a-vis ACE ordering within the DACL of the file I am modifying (which is passed in via szPath in my function). I will say that I simply added my new ACE to the end of the DACL. If this will be a problem, must I really read out all the ACE's from the DACL, inspect them and then add them back one at a time being sure to insert my new ACE in the correct position to respect the correct ordering?
char* whoOps::ACLAmigo::AddACEToDACL(char* szPath, char* szSecurityPrincipal, DWORD dwPermission)
{
ACL_SIZE_INFORMATION ACLInfo;
memset(&ACLInfo, 0, sizeof(ACL_SIZE_INFORMATION));
UCHAR BuffSid[256];
PSID pSID = (PSID)BuffSid;
int returnCode = ResolveSID(szSecurityPrincipal, pSID);
SE_OBJECT_TYPE SEObjType = SE_FILE_OBJECT;
PACL pOldDACL = NULL;
PSECURITY_DESCRIPTOR pSD = NULL;
SECURITY_INFORMATION ACLSecInfo = DACL_SECURITY_INFORMATION;
returnCode = GetNamedSecurityInfoA(szPath, SEObjType, ACLSecInfo, NULL, NULL, &pOldDACL, NULL, &pSD);
char* szReturn = NULL;
if (returnCode != ERROR_SUCCESS) {
szReturn = "GetNamedSecurityInfoA() failed.";
} else {
BOOL getACLResult = GetAclInformation(pOldDACL, &ACLInfo, sizeof(ACLInfo), AclSizeInformation);
if (!getACLResult) {
szReturn = "GetAclInformation() failed.";
} else {
DWORD cb = 0;
DWORD cbExtra = sizeof(ACCESS_ALLOWED_ACE) - sizeof(DWORD) + GetLengthSid(pSID);
cb = ACLInfo.AclBytesInUse + cbExtra;
PACL pNewDACL = static_cast<PACL>(HeapAlloc(GetProcessHeap(),0,cb));
BOOL initACLResult = InitializeAcl(pNewDACL, cb, ACL_REVISION);
if (!initACLResult) {
szReturn = "InitializeAcl() failed.";
} else {
for (DWORD i = 0; i < ACLInfo.AceCount; ++i) {
ACE_HEADER * pACE = 0;
GetAce(pOldDACL, i, reinterpret_cast<void**>(&pACE));
pACE->AceFlags = CONTAINER_INHERIT_ACE | OBJECT_INHERIT_ACE;
pACE->AceType = ACCESS_ALLOWED_ACE_TYPE;
AddAce(pNewDACL, ACL_REVISION, MAXDWORD, pACE, pACE->AceSize);
}
BOOL addACEResult = AddAccessAllowedAceEx(pNewDACL, ACL_REVISION, CONTAINER_INHERIT_ACE | OBJECT_INHERIT_ACE, dwPermission, pSID);
if (!addACEResult) {
szReturn = "AddAccessAllowedAceEx() failed.";
} else {
DWORD setSIResult = SetNamedSecurityInfoA(szPath, SEObjType, ACLSecInfo, NULL, NULL, pNewDACL, NULL);
if (!setSIResult) {
szReturn = "SetNamedSecurityInfoA() failed.";
} else {
szReturn = "AddACEToDACL() succesful.";
}
}
}
if (pNewDACL) HeapFree(GetProcessHeap(),0, pNewDACL);
}
if (pSD) LocalFree(pSD);
}
return szReturn;
}
ACE ordering is really important! Yes, best solution would be
This serie has a good amount of samples.