Inheritable ACE doesn't inherit (code included)

clintp_at_gmail.com
Date: 05/03/05

  • Next message: Karl Levinson, mvp: "Re: Administration Password"
    Date: 3 May 2005 12:44:55 -0700
    
    

    I've got a function that I'm using to create an inheritable ACE. I
    want to grant permission on a directory, and have it be inherited by
    its children.

    The function was largely stolen from MSDN, and it almost works. If I
    go into Explorer and pull up the directory, everyhing looks fine -- all
    of the correct switches are set, etc... If I look at the children --
    no permissions are inherited.

    Doing it manually using Explorer's Security tab works fine.

    And, in fact, if I take the "broken" ACL on the directory and modify it
    in any way using the Security tab and apply the changes... voila, it
    gets inherited by its children.

    The function follows.

    PS: in the if(){} block below, I'm sure that AddAccessAllowedAceEx is
    being called. I've dumped the ACE using another tool and the flag bits
    look the same in the header whether this function adjusts the
    permissions, or the Security tab does it. I'm completely lost.

    BOOL AddAccessRights(TCHAR *lpszFileName, TCHAR *lpszAccountName, DWORD
    dwAccessMask)
    {
            // SID variables.
            LPVOID pUserSID = NULL;

            // File SD variables.
            PSECURITY_DESCRIPTOR pFileSD = NULL;
            DWORD cbFileSD = 0;

            // New SD variables.
            SECURITY_DESCRIPTOR newSD;

            // ACL variables.
            PACL pACL = NULL;
            BOOL fDaclPresent;
            BOOL fDaclDefaulted;
            ACL_SIZE_INFORMATION AclInfo;

            // New ACL variables.
            PACL pNewACL = NULL;
            DWORD cbNewACL = 0;

            // Temporary ACE.
            LPVOID pTempAce = NULL;
            UINT CurrentAceIndex = 0;

            UINT newAceIndex = 0;

            // Assume function will fail.
            BOOL fResult = FALSE;

            SetSecurityDescriptorControlFnPtr _SetSecurityDescriptorControl;
            AddAccessAllowedAceExFnPtr _AddAccessAllowedAceEx;

            SECURITY_INFORMATION secInfo = DACL_SECURITY_INFORMATION;

            //
            // STEP 1: Get SID of the account name specified.
            //
            if (! (pUserSID = GetUserSid(lpszAccountName)))
            {
                    fResult = 1;
                    goto EXITFUNC;
            }

            //
            // STEP 2: Get security descriptor (SD) of the file specified.
            //
            if (! GetFileSecurity(lpszFileName, secInfo, pFileSD, 0, &cbFileSD))
            {
                    if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
                    {
                            err_msg();
                            fResult = 2;
                            goto EXITFUNC;
                    }
            }

            if (! (pFileSD = malloc(cbFileSD)))
            {
                    fResult = -1;
                    goto EXITFUNC;
            }

            if (! GetFileSecurity(lpszFileName, secInfo, pFileSD, cbFileSD,
    &cbFileSD))
            {
                    err_msg();
                    fResult = 2;
                    goto EXITFUNC;
            }

            //
            // STEP 3: Initialize new SD.
            //
            if (!InitializeSecurityDescriptor(&newSD,
    SECURITY_DESCRIPTOR_REVISION))
            {
                    err_msg();
                    fResult = 3;
                    goto EXITFUNC;
            }

            //
            // STEP 4: Get DACL from the old SD.
            //
            if (!GetSecurityDescriptorDacl(pFileSD, &fDaclPresent, &pACL,
    &fDaclDefaulted))
            {
                    err_msg();
                    fResult = 4;
                    goto EXITFUNC;
            }

            //
            // STEP 5: Get size information for DACL.
            //
            AclInfo.AceCount = 0; // Assume NULL DACL.
            AclInfo.AclBytesFree = 0;
            AclInfo.AclBytesInUse = sizeof(ACL);

            if (pACL == NULL)
                    fDaclPresent = FALSE;

            // If not NULL DACL, gather size information from DACL.
            if (fDaclPresent)
            {
                    if (!GetAclInformation(pACL, &AclInfo, sizeof(ACL_SIZE_INFORMATION),
    AclSizeInformation))
                    {
                            err_msg();
                            fResult = 5;
                            goto EXITFUNC;
                    }
            }

            //
            // STEP 6: Compute size needed for the new ACL.
            //
            cbNewACL = AclInfo.AclBytesInUse + sizeof(ACCESS_ALLOWED_ACE) +
    GetLengthSid(pUserSID) - sizeof(DWORD);

            //
            // STEP 7: Allocate memory for new ACL.
            //
            if (! (pNewACL = (PACL) malloc(cbNewACL)))
            {
                    fResult = -1;
                    goto EXITFUNC;
            }

            //
            // STEP 8: Initialize the new ACL.
            //
            if (!InitializeAcl(pNewACL, cbNewACL, ACL_REVISION2))
            {
                    err_msg();
                    fResult = 6;
                    goto EXITFUNC;
            }

            //
            // STEP 9 If DACL is present, copy all the ACEs from the old DACL
            // to the new DACL.
            //
            // The following code assumes that the old DACL is
            // already in Windows 2000 preferred order. To conform
            // to the new Windows 2000 preferred order, first we will
            // copy all non-inherited ACEs from the old DACL to the
            // new DACL, irrespective of the ACE type.
            //
            newAceIndex = 0;

            if (fDaclPresent && AclInfo.AceCount)
            {
                    for (CurrentAceIndex = 0; CurrentAceIndex < AclInfo.AceCount;
    CurrentAceIndex++)
                    {
                            //
                            // STEP 10: Get an ACE.
                            //
                            if (!GetAce(pACL, CurrentAceIndex, &pTempAce))
                            {
                                    err_msg();
                                    fResult = 7;
                                    goto EXITFUNC;
                            }

                            //
                            // STEP 11: Check if it is a non-inherited ACE.
                            // If it is an inherited ACE, break from the loop so
                            // that the new access allowed non-inherited ACE can
                            // be added in the correct position, immediately after
                            // all non-inherited ACEs.
                            //
                            if (((ACCESS_ALLOWED_ACE *)pTempAce)->Header.AceFlags &
    INHERITED_ACE)
                                    break;

                            //
                            // STEP 12: Skip adding the ACE, if the SID matches
                            // with the account specified, as we are going to
                            // add an access allowed ACE with a different access
                            // mask.
                            //
                            if (EqualSid(pUserSID, &(((ACCESS_ALLOWED_ACE
    *)pTempAce)->SidStart)))
                                    continue;

                            //
                            // STEP 13: Add the ACE to the new ACL.
                            //
                            if (!AddAce(pNewACL, ACL_REVISION, MAXDWORD, pTempAce,
    ((PACE_HEADER) pTempAce)->AceSize))
                            {
                                    err_msg();
                                    fResult = 7;
                                    goto EXITFUNC;
                            }

                            newAceIndex++;
                    }
            }

            //
            // STEP 14: Add the access-allowed ACE to the new DACL.
            // The new ACE added here will be in the correct position,
            // immediately after all existing non-inherited ACEs.
            //
            _AddAccessAllowedAceEx =
    (AddAccessAllowedAceExFnPtr)GetProcAddress(GetModuleHandle(TEXT("advapi32.dll")),"AddAccessAllowedAceEx");
            if (_AddAccessAllowedAceEx)
            {
                    fprintf(stderr, "new API\n");
                    if (!_AddAccessAllowedAceEx(pNewACL, ACL_REVISION2,
    CONTAINER_INHERIT_ACE | OBJECT_INHERIT_ACE, dwAccessMask, pUserSID))
                    {
                            err_msg();
                            fResult = 8;
                            goto EXITFUNC;
                    }
            }
            else
            {
                    if (!AddAccessAllowedAce(pNewACL, ACL_REVISION2, dwAccessMask,
    pUserSID))
                    {
                            err_msg();
                            fResult = 8;
                            goto EXITFUNC;
                    }
            }

            //
            // STEP 15: To conform to the new Windows 2000 preferred order,
            // we will now copy the rest of inherited ACEs from the
            // old DACL to the new DACL.
            //
            if (fDaclPresent && AclInfo.AceCount)
            {
                    for (; CurrentAceIndex < AclInfo.AceCount; CurrentAceIndex++)
                    {
                            //
                            // STEP 16: Get an ACE.
                            //
                            if (!GetAce(pACL, CurrentAceIndex, &pTempAce))
                            {
                                    err_msg();
                                    fResult = 8;
                                    goto EXITFUNC;
                            }

                            //
                            // STEP 17: Add the ACE to the new ACL.
                            //
                            if (!AddAce(pNewACL, ACL_REVISION, MAXDWORD, pTempAce,
    ((PACE_HEADER) pTempAce)->AceSize))
                            {
                                    err_msg();
                                    fResult = 9;
                                    goto EXITFUNC;
                            }
                    }
            }

            //
            // STEP 18: Set the new DACL to the new SD.
            //
            if (!SetSecurityDescriptorDacl(&newSD, TRUE, pNewACL, FALSE))
            {
                    err_msg();
                    fResult = 10;
                    goto EXITFUNC;
            }

            //
            // STEP 19: Copy the old security descriptor control flags
            // regarding DACL automatic inheritance for Windows 2000 or
            // later where SetSecurityDescriptorControl() API is available
            // in advapi32.dll.
            //
            _SetSecurityDescriptorControl =
    (SetSecurityDescriptorControlFnPtr)GetProcAddress(GetModuleHandle(TEXT("advapi32.dll")),"SetSecurityDescriptorControl");
            if (_SetSecurityDescriptorControl)
            {
                    SECURITY_DESCRIPTOR_CONTROL controlBitsOfInterest = 0;
                    SECURITY_DESCRIPTOR_CONTROL controlBitsToSet = 0;
                    SECURITY_DESCRIPTOR_CONTROL oldControlBits = 0;
                    DWORD dwRevision = 0;

                    if (!GetSecurityDescriptorControl(pFileSD, &oldControlBits,
    &dwRevision))
                    {
                            err_msg();
                            fResult = 10;
                            goto EXITFUNC;
                    }

                    if (oldControlBits & SE_DACL_AUTO_INHERITED)
                    {
                            controlBitsOfInterest = SE_DACL_AUTO_INHERIT_REQ |
    SE_DACL_AUTO_INHERITED;
                            controlBitsToSet = controlBitsOfInterest;
                    }
                    else if (oldControlBits & SE_DACL_PROTECTED)
                    {
                            controlBitsOfInterest = SE_DACL_PROTECTED;
                            controlBitsToSet = controlBitsOfInterest;
                    }

                    if (controlBitsOfInterest)
                    {
                            if (!_SetSecurityDescriptorControl(&newSD, controlBitsOfInterest,
    controlBitsToSet))
                            {
                                    err_msg();
                                    fResult = 11;
                                    goto EXITFUNC;
                            }
                    }
            }

            //
            // STEP 20: Set the new SD to the File.
            //
            if (!SetFileSecurity(lpszFileName, secInfo, &newSD))
            {
                    err_msg();
                    fResult = 12;
                    goto EXITFUNC;
            }

            fResult = 0;

    EXITFUNC:
            //
            // STEP 21: Free allocated memory
            //
            if (pFileSD) free(pFileSD);
            if (pNewACL) free(pNewACL);

            return fResult;
    }


  • Next message: Karl Levinson, mvp: "Re: Administration Password"

    Relevant Pages

    • Re: Inheritable ACE doesnt inherit (code included)
      ... > I've got a function that I'm using to create an inheritable ACE. ... two kinds of inheritable ACL sets on ... > Doing it manually using Explorer's Security tab works fine. ... > permissions, or the Security tab does it. ...
      (microsoft.public.win2000.security)
    • Re: Inheritable ACE doesnt inherit (code included)
      ... did matches what Explorer does, it hides a lot of the detail. ... how to do it with other permissions. ... > Doing it manually using Explorer's Security tab works fine. ... > CONTAINER_INHERIT_ACE | OBJECT_INHERIT_ACE, dwAccessMask, pUserSID)) ...
      (microsoft.public.win2000.security)
    • Re: receiving access denied message on all folders in logical pa
      ... In order to access the security tab in XP Home edition you're ... ownership. ... >> Administrator account (e.g. it may be called Administrator, ... >> Review the listed permissions configuration and adjust as ...
      (microsoft.public.windowsxp.security_admin)
    • Re: Help--Excel files that cannot be accessed...
      ... > Yes, XP Home does not normally have the security tab, and it will also not ... Remove "SPAM" without the quotes ... >> Spybot S & D: ... >>> It sounds like a permissions problem. ...
      (microsoft.public.windowsxp.general)
    • Re: Computer componet of GP not being applied
      ... Enterprise Admins: everything but full control ... That is quite possibly related to groups and permissions. ... > click Properties and then look at the Security tab. ...
      (microsoft.public.windows.group_policy)