Question

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;

}

Was it helpful?

Solution

ACE ordering is really important! Yes, best solution would be

  1. read the content of the ACL before modifying
  2. programmatically inspect each element (ACE) in the Security Descriptor
  3. place your entry appropriatelly (denied before allow)

This serie has a good amount of samples.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top